summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuilherme Lepsch <lepsch@expertisesolutions.com.br>2015-03-24 17:50:11 -0300
committerFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2015-09-03 23:06:06 -0300
commit7ea7beffb105a25a586dc6669231da36a160b156 (patch)
tree083ddcf1997d735fc749658712c6c385834731e5
parent01ef11eb56f73af38ba8a3e7f6a5fc2b31a7f53d (diff)
elm_prefs: EFL Data Model integrationdevs/felipealmeida/elm_prefs
-rw-r--r--src/examples/Makefile.am3
-rw-r--r--src/examples/prefs_example_04.c84
-rw-r--r--src/examples/prefs_example_04.epc49
-rw-r--r--src/lib/Elementary.h.in1
-rw-r--r--src/lib/elm_prefs.c436
-rw-r--r--src/lib/elm_prefs.eo55
-rw-r--r--src/lib/elm_prefs.h1
-rw-r--r--src/lib/elm_widget_prefs.h4
8 files changed, 538 insertions, 95 deletions
diff --git a/src/examples/Makefile.am b/src/examples/Makefile.am
index bf969e385..87a004284 100644
--- a/src/examples/Makefile.am
+++ b/src/examples/Makefile.am
@@ -114,6 +114,7 @@ photocam_example_01.c \
114prefs_example_01.c \ 114prefs_example_01.c \
115prefs_example_02.c \ 115prefs_example_02.c \
116prefs_example_03.c \ 116prefs_example_03.c \
117prefs_example_04.c \
117popup_example_01.c \ 118popup_example_01.c \
118popup_example_02.c \ 119popup_example_02.c \
119popup_example_03.c \ 120popup_example_03.c \
@@ -195,6 +196,7 @@ files_DATA += \
195 prefs_example_02.epb \ 196 prefs_example_02.epb \
196 prefs_example_03.epb \ 197 prefs_example_03.epb \
197 prefs_example_03.edj \ 198 prefs_example_03.edj \
199 prefs_example_04.epb \
198 theme_example.edj \ 200 theme_example.edj \
199 layout_example.edj\ 201 layout_example.edj\
200 codegen_example.edj \ 202 codegen_example.edj \
@@ -292,6 +294,7 @@ photocam_example_01 \
292prefs_example_01 \ 294prefs_example_01 \
293prefs_example_02 \ 295prefs_example_02 \
294prefs_example_03 \ 296prefs_example_03 \
297prefs_example_04 \
295popup_example_01 \ 298popup_example_01 \
296popup_example_02 \ 299popup_example_02 \
297popup_example_03 \ 300popup_example_03 \
diff --git a/src/examples/prefs_example_04.c b/src/examples/prefs_example_04.c
new file mode 100644
index 000000000..94a3a23b9
--- /dev/null
+++ b/src/examples/prefs_example_04.c
@@ -0,0 +1,84 @@
1//Compile with:
2//gcc -o prefs_example_04 prefs_example_04.c -g `pkg-config --cflags --libs elementary`
3
4#ifdef HAVE_CONFIG_H
5#include <elementary_config.h>
6#endif
7
8#include <Elementary.h>
9#include <Efl.h>
10#include <Eio.h>
11#include <eio_model.eo.h>
12
13static void
14_page_saved_cb(void *data, Evas_Object *obj, void *event_info)
15{
16 const char *page = event_info;
17
18 printf("page %s was saved!\n", page);
19}
20
21static void
22_page_loaded_cb(void *data, Evas_Object *obj, void *event_info)
23{
24 const char *page = event_info;
25
26 printf("page %s was loaded!\n", page);
27}
28
29static void
30_item_changed_cb(void *data, Evas_Object *obj, void *event_info)
31{
32 const char *item = event_info;
33
34 printf("item %s was changed!\n", item);
35}
36
37static Eina_Bool
38_filter_cb(void *data EINA_UNUSED,
39 Eio_File *handler EINA_UNUSED,
40 const Eina_File_Direct_Info *info)
41{
42 if (info->type == EINA_FILE_DIR &&
43 info->path[info->name_start] != '.')
44 return EINA_TRUE;
45
46 return EINA_FALSE;
47}
48
49EAPI_MAIN int
50elm_main(int argc, char **argv)
51{
52 Evas_Object *win, *prefs;
53
54 win = elm_win_util_standard_add("prefs", "Prefs Example 04");
55 elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
56 elm_win_autodel_set(win, EINA_TRUE);
57
58 prefs = elm_prefs_add(win);
59 evas_object_size_hint_weight_set(prefs, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
60 elm_win_resize_object_add(win, prefs);
61 evas_object_show(prefs);
62
63 evas_object_smart_callback_add(prefs, "page,saved", _page_saved_cb, NULL);
64 evas_object_smart_callback_add(prefs, "page,loaded", _page_loaded_cb, NULL);
65 evas_object_smart_callback_add(prefs, "item,changed", _item_changed_cb, win);
66
67 Efl_Model_Base *model = eo_add(EIO_MODEL_CLASS, NULL, eio_model_path_set("test"));
68 eo_do(model, eio_model_children_filter_set(_filter_cb, NULL));
69 eo_do(model, efl_model_load());
70
71 elm_prefs_file_set(prefs, "prefs_example_04.epb", NULL);
72 eo_do(prefs, elm_obj_prefs_property_connect("path", "main:text"),
73 elm_obj_prefs_model_set(model));
74
75 evas_object_resize(win, 320, 320);
76 evas_object_show(win);
77
78 elm_run();
79
80 eo_unref(model);
81
82 return 0;
83}
84ELM_MAIN()
diff --git a/src/examples/prefs_example_04.epc b/src/examples/prefs_example_04.epc
new file mode 100644
index 000000000..881861904
--- /dev/null
+++ b/src/examples/prefs_example_04.epc
@@ -0,0 +1,49 @@
1collection
2{
3 page
4 {
5 name: "main";
6 version: 1;
7 title: "Preferences Widget";
8 subtitle: "Example 01";
9 widget: "elm/vertical_box";
10
11 items {
12
13 item {
14 name: "label";
15 type: LABEL;
16 label: "Filename";
17 }
18
19 item {
20 name: "text";
21 type: TEXT;
22 editable: 1;
23
24 text {
25 placeholder: "test";
26 default: "test";
27 deny: "/";
28 }
29 }
30
31 item {
32 name: "sep";
33 type: SEPARATOR;
34 }
35
36 item {
37 name: "save";
38 type: SAVE;
39 label: "Save";
40 }
41
42 item {
43 name: "reset";
44 type: RESET;
45 label: "Reset";
46 }
47 }
48 }
49}
diff --git a/src/lib/Elementary.h.in b/src/lib/Elementary.h.in
index af3f1229f..cc93cf475 100644
--- a/src/lib/Elementary.h.in
+++ b/src/lib/Elementary.h.in
@@ -84,6 +84,7 @@
84#include <Efreet_Mime.h> 84#include <Efreet_Mime.h>
85#include <Efreet_Trash.h> 85#include <Efreet_Trash.h>
86#include <Ethumb_Client.h> 86#include <Ethumb_Client.h>
87#include <Eo.h>
87 88
88#ifdef ELM_ELOCATION 89#ifdef ELM_ELOCATION
89#include <Elocation.h> 90#include <Elocation.h>
diff --git a/src/lib/elm_prefs.c b/src/lib/elm_prefs.c
index 5b22fd416..c2dac4147 100644
--- a/src/lib/elm_prefs.c
+++ b/src/lib/elm_prefs.c
@@ -10,7 +10,7 @@
10#include "elm_widget_prefs.h" 10#include "elm_widget_prefs.h"
11#include "elm_prefs_edd.x" 11#include "elm_prefs_edd.x"
12 12
13#include "Eo.h" 13#include <Eo.h>
14 14
15#define MY_CLASS ELM_PREFS_CLASS 15#define MY_CLASS ELM_PREFS_CLASS
16 16
@@ -40,10 +40,14 @@ static Eina_Hash *_elm_prefs_item_widgets_map = NULL;
40static Eina_Hash *_elm_prefs_item_type_widgets_map = NULL; 40static Eina_Hash *_elm_prefs_item_type_widgets_map = NULL;
41static const Elm_Prefs_Item_Iface *_elm_prefs_item_default_widget = NULL; 41static const Elm_Prefs_Item_Iface *_elm_prefs_item_default_widget = NULL;
42 42
43static void _elm_prefs_values_get_default(Elm_Prefs_Page_Node *, 43static void _elm_prefs_values_get_default(Elm_Prefs_Page_Node *, Eina_Bool);
44 Eina_Bool); 44static Eina_Bool _prefs_item_widget_value_from_self(Elm_Prefs_Item_Node *, Eina_Bool);
45static Eina_Bool _prefs_item_widget_value_from_self(Elm_Prefs_Item_Node *, 45static Eina_Bool _elm_prefs_value_get(Elm_Prefs_Data *, const char *, Eina_Value *);
46 Eina_Bool); 46static Eina_Bool _elm_prefs_value_set(Elm_Prefs_Data *, const char *, const Elm_Prefs_Item_Type, const Eina_Value *);
47static void _elm_prefs_value_restore(Elm_Prefs_Data *, Elm_Prefs_Item_Node *, const char *);
48static Eina_Bool _elm_prefs_item_changed(Eo *, Elm_Prefs_Data *, const char *);
49static void _elm_prefs_values_get_user(Elm_Prefs_Data *, Elm_Prefs_Page_Node *);
50static void _elm_prefs_values_fetch(Eo *, Elm_Prefs_Data *, Eina_Bool);
47 51
48EOLIAN static void 52EOLIAN static void
49_elm_prefs_evas_object_smart_add(Eo *obj, Elm_Prefs_Data *_pd EINA_UNUSED) 53_elm_prefs_evas_object_smart_add(Eo *obj, Elm_Prefs_Data *_pd EINA_UNUSED)
@@ -245,19 +249,10 @@ _prefs_item_widget_value_from_data(Elm_Prefs_Data *sd,
245 if (!_prefs_data_types_match(t, it->type)) 249 if (!_prefs_data_types_match(t, it->type))
246 { 250 {
247 if (!_prefs_data_type_fix(it, value)) return EINA_FALSE; 251 if (!_prefs_data_type_fix(it, value)) return EINA_FALSE;
248 else
249 {
250 Eina_Bool v_set;
251
252 sd->changing_from_ui = EINA_TRUE;
253 252
254 v_set = elm_prefs_data_value_set(sd->prefs_data, 253 // write-back the type fix only if prefs_data
255 buf, it->type, value); 254 if (sd->prefs_data && !_elm_prefs_value_set(sd, buf, it->type, value))
256 255 return EINA_FALSE;
257 sd->changing_from_ui = EINA_FALSE;
258
259 if (!v_set) return EINA_FALSE;
260 }
261 } 256 }
262 257
263 if (!it->available) 258 if (!it->available)
@@ -362,35 +357,121 @@ _elm_prefs_item_list_node_by_name(Elm_Prefs_Data *sd,
362static void 357static void
363_prefs_data_item_changed_cb(void *cb_data, 358_prefs_data_item_changed_cb(void *cb_data,
364 Elm_Prefs_Data_Event_Type type EINA_UNUSED, 359 Elm_Prefs_Data_Event_Type type EINA_UNUSED,
365 Elm_Prefs_Data *prefs_data, 360 Elm_Prefs_Data *prefs_data EINA_UNUSED,
366 void *event_info) 361 void *event_info)
367{ 362{
368 Elm_Prefs_Data_Event_Changed *evt = event_info; 363 Elm_Prefs_Data_Event_Changed *evt = event_info;
369 Eo *obj = cb_data; 364 Eo *obj = cb_data;
370 Elm_Prefs_Item_Node *it;
371 Eina_Value value;
372 365
373 ELM_PREFS_DATA_GET(obj, sd); 366 ELM_PREFS_DATA_GET(obj, sd);
374 if (sd->changing_from_ui) return; 367 if (sd->changing_from_ui) return;
375 368
376 it = _elm_prefs_item_node_by_name(sd, evt->key); 369 if (_elm_prefs_item_changed(obj, sd, evt->key))
377 if (!it) return; 370 _elm_prefs_mark_as_dirty(obj);
371}
372
373static Eina_Bool
374_elm_prefs_item_changed(Eo *obj,
375 Elm_Prefs_Data *sd,
376 const char *key)
377{
378 Elm_Prefs_Item_Node *item = _elm_prefs_item_node_by_name(sd, key);
379 if (!item) return EINA_FALSE;
378 380
379 if (elm_prefs_data_value_get(prefs_data, evt->key, NULL, &value)) 381 if (sd->pending_change && strcmp(sd->pending_change, key) == 0)
380 { 382 {
381 if (!_prefs_item_widget_value_from_data(sd, it, &value)) goto end; 383 free(sd->pending_change);
384 sd->pending_change = NULL;
385 return EINA_FALSE;
386 }
382 387
383 _elm_prefs_item_changed_report(obj, it); 388 Eina_Value value;
384 _elm_prefs_mark_as_dirty(obj); 389 if (!_elm_prefs_value_get(sd, key, &value))
390 {
391 ERR("failed to fetch value from data after changed event: %s", key);
392 return EINA_FALSE;
385 } 393 }
386 else
387 ERR("failed to fetch value from data after changed event");
388 394
389end: 395 Eina_Bool changed = _prefs_item_widget_value_from_data(sd, item, &value);
396 if (changed)
397 _elm_prefs_item_changed_report(obj, item);
398
390 eina_value_flush(&value); 399 eina_value_flush(&value);
391 return; 400 return changed;
401}
402
403static Eina_Bool
404_elm_prefs_properties_changed(Eo *obj,
405 Elm_Prefs_Data *sd,
406 const Eina_Array *properties)
407{
408 if (!properties) return EINA_FALSE;
409
410 Eina_Bool changed = EINA_FALSE;
411
412 size_t i;
413 const char *property;
414 Eina_Array_Iterator it;
415 EINA_ARRAY_ITER_NEXT(properties, i, property, it)
416 {
417 const char *key = eina_hash_find(sd->property_to_key, property);
418 if (!key)
419 key = property;
420 changed = _elm_prefs_item_changed(obj, sd, key) || changed;
421 }
422
423 return changed;
424}
425
426static Eina_Bool
427_model_property_changed_cb(void *data,
428 Eo *model EINA_UNUSED,
429 const Eo_Event_Description *desc EINA_UNUSED,
430 void *event_info)
431{
432 const Efl_Model_Property_Event *evt = (Efl_Model_Property_Event*)event_info;
433 Eo *obj = (Eo*)data;
434
435 ELM_PREFS_DATA_GET(obj, sd);
436
437 Eina_Bool changed = _elm_prefs_properties_changed
438 (obj, sd, evt->changed_properties);
439 changed = _elm_prefs_properties_changed
440 (obj, sd, evt->invalidated_properties) || changed;
441 if (changed)
442 _elm_prefs_mark_as_dirty(obj);
443
444 return EO_CALLBACK_CONTINUE;
445}
446
447static Eina_Bool
448_model_load_status_change_cb(void *data,
449 Eo *model EINA_UNUSED,
450 const Eo_Event_Description *desc EINA_UNUSED,
451 void *event_info)
452{
453 const Efl_Model_Load *load = (Efl_Model_Load*)event_info;
454 Eo *obj = (Eo*)data;
455 ELM_PREFS_DATA_GET(obj, sd);
456
457 if ((load->status & EFL_MODEL_LOAD_STATUS_ERROR) && sd->pending_change)
458 {
459 Elm_Prefs_Item_Node *item = _elm_prefs_item_node_by_name(sd, sd->pending_change);
460 if (item)
461 _elm_prefs_value_restore(sd, item, sd->pending_change);
462
463 free(sd->pending_change);
464 sd->pending_change = NULL;
465 return EO_CALLBACK_CONTINUE;
466 }
467
468 Eina_Bool reset_values = !(load->status & EFL_MODEL_LOAD_STATUS_LOADED_PROPERTIES);
469 _elm_prefs_values_fetch(obj, sd, reset_values);
470
471 return EO_CALLBACK_CONTINUE;
392} 472}
393 473
474
394static void 475static void
395_prefs_data_autosaved_cb(void *cb_data, 476_prefs_data_autosaved_cb(void *cb_data,
396 Elm_Prefs_Data_Event_Type type EINA_UNUSED, 477 Elm_Prefs_Data_Event_Type type EINA_UNUSED,
@@ -446,6 +527,29 @@ _elm_prefs_data_cbs_del(Eo *obj)
446 "prefs data handle"); 527 "prefs data handle");
447} 528}
448 529
530static Eina_Bool
531_elm_prefs_model_cbs_add(Eo *obj, Efl_Model_Base *model)
532{
533 eo_do(model, eo_event_callback_add(EFL_MODEL_BASE_EVENT_PROPERTIES_CHANGED,
534 _model_property_changed_cb, obj));
535 eo_do(model, eo_event_callback_add(EFL_MODEL_BASE_EVENT_LOAD_STATUS,
536 _model_load_status_change_cb, obj));
537 return EINA_TRUE;
538}
539
540static void
541_elm_prefs_model_cbs_del(Eo *obj)
542{
543 ELM_PREFS_DATA_GET(obj, sd);
544
545 if (!sd->model) return;
546
547 eo_do(sd->model, eo_event_callback_del(EFL_MODEL_BASE_EVENT_PROPERTIES_CHANGED,
548 _model_property_changed_cb, obj));
549 eo_do(sd->model, eo_event_callback_del(EFL_MODEL_BASE_EVENT_LOAD_STATUS,
550 _model_load_status_change_cb, obj));
551}
552
449EOLIAN static void 553EOLIAN static void
450_elm_prefs_evas_object_smart_del(Eo *obj, Elm_Prefs_Data *sd) 554_elm_prefs_evas_object_smart_del(Eo *obj, Elm_Prefs_Data *sd)
451{ 555{
@@ -454,17 +558,24 @@ _elm_prefs_evas_object_smart_del(Eo *obj, Elm_Prefs_Data *sd)
454 if (sd->saving_poller) ecore_poller_del(sd->saving_poller); 558 if (sd->saving_poller) ecore_poller_del(sd->saving_poller);
455 559
456 _elm_prefs_data_cbs_del(obj); 560 _elm_prefs_data_cbs_del(obj);
561 _elm_prefs_model_cbs_del(obj);
457 562
458 if (sd->root) 563 if (sd->root)
459 { 564 {
460 elm_prefs_data_version_set(sd->prefs_data, sd->root->version); 565 if (sd->prefs_data)
461 566 {
462 _elm_prefs_save(obj); 567 elm_prefs_data_version_set(sd->prefs_data, sd->root->version);
568 _elm_prefs_save(obj);
569 }
463 570
464 _root_node_free(sd); 571 _root_node_free(sd);
465 } 572 }
466 573
574 eina_hash_free(sd->key_to_property);
575 eina_hash_free(sd->property_to_key);
576 free(sd->pending_change);
467 if (sd->prefs_data) elm_prefs_data_unref(sd->prefs_data); 577 if (sd->prefs_data) elm_prefs_data_unref(sd->prefs_data);
578 if (sd->model) eo_unref(sd->model);
468 579
469 eina_stringshare_del(sd->file); 580 eina_stringshare_del(sd->file);
470 eina_stringshare_del(sd->page); 581 eina_stringshare_del(sd->page);
@@ -512,14 +623,16 @@ elm_prefs_add(Evas_Object *parent)
512 return obj; 623 return obj;
513} 624}
514 625
515EOLIAN static Eo * 626EOLIAN static Eo*
516_elm_prefs_eo_base_constructor(Eo *obj, Elm_Prefs_Data *_pd EINA_UNUSED) 627_elm_prefs_eo_base_constructor(Eo *obj, Elm_Prefs_Data *pd)
517{ 628{
518 obj = eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor()); 629 obj = eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
519 eo_do(obj, 630 eo_do(obj,
520 evas_obj_type_set(MY_CLASS_NAME_LEGACY), 631 evas_obj_type_set(MY_CLASS_NAME_LEGACY),
521 evas_obj_smart_callbacks_descriptions_set(_elm_prefs_smart_callbacks), 632 evas_obj_smart_callbacks_descriptions_set(_elm_prefs_smart_callbacks),
522 elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_REDUNDANT_OBJECT)); 633 elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_REDUNDANT_OBJECT));
634 pd->key_to_property = eina_hash_string_superfast_new(free);
635 pd->property_to_key = eina_hash_string_superfast_new(free);
523 636
524 return obj; 637 return obj;
525} 638}
@@ -583,30 +696,12 @@ _item_changed_cb(Evas_Object *it_obj)
583 if (it->w_impl->value_validate && 696 if (it->w_impl->value_validate &&
584 !it->w_impl->value_validate(it->w_obj)) 697 !it->w_impl->value_validate(it->w_obj))
585 { 698 {
586 if (sd->prefs_data) 699 _elm_prefs_value_restore(sd, it, buf);
587 {
588 Eina_Value value;
589
590 // Restoring to the last valid value.
591 if (!elm_prefs_data_value_get(sd->prefs_data, buf, NULL, &value))
592 goto restore_fail;
593 if (!it->w_impl->value_set(it->w_obj, &value))
594 {
595 eina_value_flush(&value);
596 goto restore_fail;
597 }
598 }
599 else
600 {
601 if (!_prefs_item_widget_value_from_self(it, EINA_FALSE))
602 goto restore_fail;
603 }
604
605 return; 700 return;
606 } 701 }
607 702
608end: 703end:
609 if (sd->prefs_data) 704 if (sd->prefs_data || sd->model)
610 { 705 {
611 Eina_Value value; 706 Eina_Value value;
612 707
@@ -614,22 +709,14 @@ end:
614 ERR("failed to fetch value from widget of item %s", buf); 709 ERR("failed to fetch value from widget of item %s", buf);
615 else 710 else
616 { 711 {
617 sd->changing_from_ui = EINA_TRUE; 712 _elm_prefs_value_set(sd, buf, it->type, &value);
618 elm_prefs_data_value_set(sd->prefs_data, buf, it->type, &value);
619 eina_value_flush(&value); 713 eina_value_flush(&value);
620 sd->changing_from_ui = EINA_FALSE;
621 } 714 }
622 } 715 }
623 716
624 if (!sd->values_fetching) _elm_prefs_item_changed_report(it->prefs, it); 717 if (!sd->values_fetching) _elm_prefs_item_changed_report(it->prefs, it);
625 718
626 _elm_prefs_mark_as_dirty(it->prefs); 719 _elm_prefs_mark_as_dirty(it->prefs);
627
628 return;
629
630restore_fail:
631 ERR("failed to restore the last valid value from widget of item %s",
632 buf);
633} 720}
634 721
635static Eina_Bool 722static Eina_Bool
@@ -1061,26 +1148,18 @@ _elm_prefs_values_get_user(Elm_Prefs_Data *sd,
1061 1148
1062 EINA_LIST_FOREACH(p->items, l, it) 1149 EINA_LIST_FOREACH(p->items, l, it)
1063 { 1150 {
1064 Eina_Bool get_err = EINA_FALSE, set_err = EINA_FALSE;
1065
1066 if (it->type == ELM_PREFS_TYPE_PAGE) 1151 if (it->type == ELM_PREFS_TYPE_PAGE)
1067 { 1152 {
1068 Elm_Prefs_Page_Node *subp = it->subpage; 1153 Elm_Prefs_Page_Node *subp = it->subpage;
1069 1154
1070 if (!elm_prefs_data_value_get 1155 if (!_elm_prefs_value_get(sd, subp->name, &value))
1071 (sd->prefs_data, subp->name, NULL, &value))
1072 { 1156 {
1073 INF("failed to fetch value for item %s on user data, " 1157 INF("failed to fetch value for item %s on user data, "
1074 "writing UI value back on it", it->name); 1158 "writing UI value back on it", it->name);
1075 1159
1076 if (eina_value_setup(&value, EINA_VALUE_TYPE_STRINGSHARE) && 1160 if (eina_value_setup(&value, EINA_VALUE_TYPE_STRINGSHARE) &&
1077 eina_value_set(&value, subp->name)) 1161 eina_value_set(&value, subp->name))
1078 { 1162 _elm_prefs_value_set(sd, subp->name, it->type, &value);
1079 sd->changing_from_ui = EINA_TRUE;
1080 elm_prefs_data_value_set
1081 (sd->prefs_data, subp->name, it->type, &value);
1082 sd->changing_from_ui = EINA_FALSE;
1083 }
1084 } 1163 }
1085 1164
1086 _elm_prefs_values_get_user(sd, subp); 1165 _elm_prefs_values_get_user(sd, subp);
@@ -1094,11 +1173,15 @@ _elm_prefs_values_get_user(Elm_Prefs_Data *sd,
1094 1173
1095 snprintf(buf, sizeof(buf), "%s:%s", p->name, it->name); 1174 snprintf(buf, sizeof(buf), "%s:%s", p->name, it->name);
1096 1175
1097 if (!elm_prefs_data_value_get(sd->prefs_data, buf, NULL, &value)) 1176 Eina_Bool get_err = EINA_FALSE, set_err = EINA_FALSE;
1177 if (!_elm_prefs_value_get(sd, buf, &value))
1098 get_err = EINA_TRUE; 1178 get_err = EINA_TRUE;
1099 else if (!_prefs_item_widget_value_from_data(sd, it, &value)) 1179 else if (!_prefs_item_widget_value_from_data(sd, it, &value))
1100 set_err = EINA_TRUE; 1180 set_err = EINA_TRUE;
1101 1181
1182 if (!get_err)
1183 eina_value_flush(&value);
1184
1102 if (get_err || set_err) 1185 if (get_err || set_err)
1103 { 1186 {
1104 if (get_err) 1187 if (get_err)
@@ -1113,15 +1196,11 @@ _elm_prefs_values_get_user(Elm_Prefs_Data *sd,
1113 it->name); 1196 it->name);
1114 else 1197 else
1115 { 1198 {
1116 sd->changing_from_ui = EINA_TRUE; 1199 _elm_prefs_value_set(sd, buf, it->type, &value);
1117 elm_prefs_data_value_set 1200 eina_value_flush(&value);
1118 (sd->prefs_data, buf, it->type, &value);
1119 sd->changing_from_ui = EINA_FALSE;
1120 } 1201 }
1121 } 1202 }
1122 } 1203 }
1123
1124 eina_value_flush(&value);
1125 } 1204 }
1126} 1205}
1127 1206
@@ -1193,6 +1272,12 @@ _elm_prefs_data_set(Eo *obj, Elm_Prefs_Data *sd, Elm_Prefs_Data *prefs_data)
1193{ 1272{
1194 if (!sd->root) return EINA_FALSE; 1273 if (!sd->root) return EINA_FALSE;
1195 1274
1275 if (sd->model)
1276 {
1277 Eina_Bool ret = eo_do_ret(obj, ret, elm_obj_prefs_model_set(NULL));
1278 if (!ret) return EINA_FALSE;
1279 }
1280
1196 if (prefs_data && !_elm_prefs_data_cbs_add(obj, prefs_data)) 1281 if (prefs_data && !_elm_prefs_data_cbs_add(obj, prefs_data))
1197 return EINA_FALSE; 1282 return EINA_FALSE;
1198 1283
@@ -1205,23 +1290,14 @@ _elm_prefs_data_set(Eo *obj, Elm_Prefs_Data *sd, Elm_Prefs_Data *prefs_data)
1205 1290
1206 sd->prefs_data = prefs_data; 1291 sd->prefs_data = prefs_data;
1207 1292
1208 if (!sd->prefs_data) 1293 Eina_Bool reset_values = EINA_TRUE;
1294 if (sd->prefs_data)
1209 { 1295 {
1210 INF("resetting prefs to default values"); 1296 elm_prefs_data_ref(sd->prefs_data);
1211 _elm_prefs_values_get_default(sd->root, EINA_FALSE); 1297 reset_values = EINA_FALSE;
1212
1213 goto end;
1214 } 1298 }
1215 1299
1216 elm_prefs_data_ref(sd->prefs_data); 1300 _elm_prefs_values_fetch(obj, sd, reset_values);
1217
1218 sd->values_fetching = EINA_TRUE;
1219 _elm_prefs_values_get_user(sd, sd->root);
1220 sd->values_fetching = EINA_FALSE;
1221
1222end:
1223 eo_do(obj, eo_event_callback_call
1224 (ELM_PREFS_EVENT_PAGE_CHANGED, (char *)sd->root->name));
1225 1301
1226 return EINA_TRUE; 1302 return EINA_TRUE;
1227} 1303}
@@ -1233,6 +1309,50 @@ _elm_prefs_data_get(Eo *obj EINA_UNUSED, Elm_Prefs_Data *sd)
1233 else return sd->prefs_data; 1309 else return sd->prefs_data;
1234} 1310}
1235 1311
1312EOLIAN static Eina_Bool
1313_elm_prefs_model_set(Eo *obj, Elm_Prefs_Data *sd, Efl_Model_Base *model)
1314{
1315 if (!sd->root) return EINA_FALSE;
1316
1317 if (sd->prefs_data)
1318 {
1319 Eina_Bool ret = eo_do_ret(obj, ret, elm_obj_prefs_data_set(NULL));
1320 if (!ret) return EINA_FALSE;
1321 }
1322
1323 if (model && !_elm_prefs_model_cbs_add(obj, model))
1324 return EINA_FALSE;
1325
1326 if (sd->model)
1327 {
1328 _elm_prefs_model_cbs_del(obj);
1329 eo_unref(sd->model);
1330 }
1331
1332 sd->model = model;
1333
1334 Eina_Bool reset_values = EINA_TRUE;
1335 if (sd->model)
1336 {
1337 eo_ref(sd->model);
1338 Efl_Model_Load_Status status;
1339 eo_do(sd->model, status = efl_model_load_status_get());
1340 reset_values = !(status & EFL_MODEL_LOAD_STATUS_LOADED_PROPERTIES);
1341 }
1342
1343 _elm_prefs_values_fetch(obj, sd, reset_values);
1344 return EINA_TRUE;
1345}
1346
1347EOLIAN static Efl_Model_Base*
1348_elm_prefs_model_get(const Eo *obj EINA_UNUSED, Elm_Prefs_Data *sd)
1349{
1350 if (!sd->root)
1351 return NULL;
1352
1353 return sd->model;
1354}
1355
1236EOLIAN static void 1356EOLIAN static void
1237_elm_prefs_autosave_set(Eo *obj, Elm_Prefs_Data *_pd EINA_UNUSED, Eina_Bool autosave) 1357_elm_prefs_autosave_set(Eo *obj, Elm_Prefs_Data *_pd EINA_UNUSED, Eina_Bool autosave)
1238{ 1358{
@@ -1890,4 +2010,130 @@ elm_prefs_file_get(const Eo *obj, const char **file, const char **page)
1890 return EINA_TRUE; 2010 return EINA_TRUE;
1891} 2011}
1892 2012
2013static Eina_Bool
2014_elm_prefs_value_get(Elm_Prefs_Data *sd, const char *key, Eina_Value *value)
2015{
2016 const char *property = eina_hash_find(sd->key_to_property, key);
2017 if (!property)
2018 property = key;
2019
2020 if (sd->prefs_data)
2021 return elm_prefs_data_value_get(sd->prefs_data, property, NULL, value);
2022
2023 if (sd->model)
2024 {
2025 Efl_Model_Load_Status status;
2026 const Eina_Value *prop_value;
2027 eo_do(sd->model, status = efl_model_property_get(property, &prop_value));
2028 if (EFL_MODEL_LOAD_STATUS_ERROR == status || !prop_value)
2029 return EINA_FALSE;
2030
2031 return eina_value_copy(prop_value, value);
2032 }
2033
2034 return EINA_FALSE;
2035}
2036
2037static Eina_Bool
2038_elm_prefs_value_set(Elm_Prefs_Data *sd,
2039 const char *key,
2040 const Elm_Prefs_Item_Type type,
2041 const Eina_Value *value)
2042{
2043 const char *property = eina_hash_find(sd->key_to_property, key);
2044 if (!property)
2045 property = key;
2046
2047
2048 Eina_Bool result = EINA_FALSE;
2049 if (sd->prefs_data)
2050 {
2051 sd->changing_from_ui = EINA_TRUE;
2052 result = elm_prefs_data_value_set(sd->prefs_data, property, type, value);
2053 sd->changing_from_ui = EINA_FALSE;
2054 }
2055 else
2056 if (sd->model)
2057 {
2058 sd->pending_change = strdup(key);
2059
2060 // TODO: Convert the value
2061 Efl_Model_Load_Status status;
2062 eo_do(sd->model, status = efl_model_property_set(property, value));
2063 result = EFL_MODEL_LOAD_STATUS_ERROR != status;
2064
2065 if (!result)
2066 {
2067 free(sd->pending_change);
2068 sd->pending_change = NULL;
2069 }
2070 }
2071
2072 return result;
2073}
2074
2075static void
2076_elm_prefs_value_restore(Elm_Prefs_Data *sd,
2077 Elm_Prefs_Item_Node *it,
2078 const char *key)
2079{
2080 if (sd->prefs_data || sd->model)
2081 {
2082 Eina_Value value;
2083
2084 // Restoring to the last valid value.
2085 if (!_elm_prefs_value_get(sd, key, &value))
2086 goto on_error;
2087
2088 Eina_Bool ret = it->w_impl->value_set(it->w_obj, &value);
2089 eina_value_flush(&value);
2090 if (!ret) goto on_error;
2091 }
2092 else
2093 {
2094 if (!_prefs_item_widget_value_from_self(it, EINA_FALSE))
2095 goto on_error;
2096 }
2097
2098 return;
2099
2100on_error:
2101 ERR("failed to restore the last valid value from widget of item %s", key);
2102}
2103
2104static void
2105_elm_prefs_property_connect(Eo *obj EINA_UNUSED,
2106 Elm_Prefs_Data *sd,
2107 const char *property,
2108 const char *part)
2109{
2110 EINA_SAFETY_ON_NULL_RETURN(sd);
2111 EINA_SAFETY_ON_NULL_RETURN(property);
2112 EINA_SAFETY_ON_NULL_RETURN(part);
2113
2114 free(eina_hash_set(sd->key_to_property, part, strdup(property)));
2115 free(eina_hash_set(sd->property_to_key, property, strdup(part)));
2116}
2117
2118static void
2119_elm_prefs_values_fetch(Eo *obj, Elm_Prefs_Data *sd, Eina_Bool reset_values)
2120{
2121 if (reset_values)
2122 {
2123 INF("resetting prefs to default values");
2124 _elm_prefs_values_get_default(sd->root, EINA_FALSE);
2125 }
2126 else
2127 {
2128 elm_prefs_data_ref(sd->prefs_data);
2129
2130 sd->values_fetching = EINA_TRUE;
2131 _elm_prefs_values_get_user(sd, sd->root);
2132 sd->values_fetching = EINA_FALSE;
2133 }
2134
2135 eo_do(obj, eo_event_callback_call
2136 (ELM_PREFS_EVENT_PAGE_CHANGED, (char *)sd->root->name));
2137}
2138
1893#include "elm_prefs.eo.c" 2139#include "elm_prefs.eo.c"
diff --git a/src/lib/elm_prefs.eo b/src/lib/elm_prefs.eo
index fa507a907..80da1dc0b 100644
--- a/src/lib/elm_prefs.eo
+++ b/src/lib/elm_prefs.eo
@@ -60,6 +60,61 @@ class Elm.Prefs (Elm.Widget, Efl.File)
60 autosave: bool; [[$true to save automatically, $false otherwise.]] 60 autosave: bool; [[$true to save automatically, $false otherwise.]]
61 } 61 }
62 } 62 }
63 model_set {
64 [[Set user model for a given prefs widget
65
66 Once a prefs widget is created, after elm_prefs_file_set() is
67 issued on it, all of its UI elements will get default values, when
68 declared on that file. To fetch an user's own, personal set of
69 those values, one gets to pair a <b>model</b> handle to the
70 prefs widget. This is what this call is intended for.
71
72 Model property values from $model model with names matching the ones
73 present on the file passed on elm_prefs_file_set() to $model obj will
74 have their values applied to the respective UI elements of the
75 widget.
76
77 When $model obj dies, the values of the elements declared on its
78 .epb file (the one set on elm_prefs_file_set()) marked as permanent
79 <b>will be written back</b> to $model model, if it is writable.
80 One is also able to make this writing event to take place
81 automatically after each UI element modification by using
82 elm_prefs_autosave_set().
83
84 Note: $model obj will keep a reference of its own for $model model,
85 but you should still unreference it by yourself, after the widget
86 is gone.
87
88 see elm_prefs_model_get()
89
90 @since 1.16]]
91
92 return: bool; [[$true, on success, $false otherwise]]
93 params {
94 @in model: Efl.Model.Base*; [[A valid model handle]]
95 }
96 legacy: null;
97 }
98 model_get @const {
99 [[Get user model for a given prefs widget
100
101 see elm_prefs_model_set() for more details
102
103 @since 1.16]]
104
105 return: Efl.Model.Base *; [[A pointer to the user model of a given prefs widget on success.]]
106 legacy: null;
107 }
108 property_connect {
109 [[Connect property
110
111 @since 1.16]]
112 params {
113 @in property: const(char)*; [[Property name]]
114 @in part: const(char)*; [[Prefs page:item layout part]]
115 }
116 legacy: null;
117 }
63 reset { 118 reset {
64 [[Reset the values of a given prefs widget to a previous state. 119 [[Reset the values of a given prefs widget to a previous state.
65 120
diff --git a/src/lib/elm_prefs.h b/src/lib/elm_prefs.h
index 466065850..a43f73f41 100644
--- a/src/lib/elm_prefs.h
+++ b/src/lib/elm_prefs.h
@@ -71,6 +71,7 @@
71 * @li @ref prefs_example_01 71 * @li @ref prefs_example_01
72 * @li @ref prefs_example_02 72 * @li @ref prefs_example_02
73 * @li @ref prefs_example_03 73 * @li @ref prefs_example_03
74 * @li @ref prefs_example_04
74 */ 75 */
75 76
76#include "elm_prefs_common.h" 77#include "elm_prefs_common.h"
diff --git a/src/lib/elm_widget_prefs.h b/src/lib/elm_widget_prefs.h
index 728ef3d6c..77960d93d 100644
--- a/src/lib/elm_widget_prefs.h
+++ b/src/lib/elm_widget_prefs.h
@@ -75,7 +75,11 @@ struct _Elm_Prefs_Data
75{ 75{
76 Elm_Prefs_Page_Node *root; 76 Elm_Prefs_Page_Node *root;
77 77
78 Eina_Hash *key_to_property;
79 Eina_Hash *property_to_key;
78 Elm_Prefs_Data *prefs_data; 80 Elm_Prefs_Data *prefs_data;
81 Efl_Model_Base *model;
82 char *pending_change;
79 const char *file; 83 const char *file;
80 const char *page; 84 const char *page;
81 85