2 * Copyright 2012 Samsung Electronics Co., Ltd
4 * Licensed under the Flora License, Version 1.1 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://floralicense.org/license/
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include "homescreen-efl.h"
19 #include "data_model.h"
24 #include "folder_panel.h"
26 #include "livebox/livebox_widget.h"
31 Tree_node_t *all_apps;
39 static bool __data_model_get_empty_page(Tree_node_t *nothing, Tree_node_t *page, void *data);
40 static void __data_model_load_item(Tree_node_t *parent, Tree_node_t **item, db_item_t* db_item, Eina_List* apps_db);
41 static void __data_model_free_subtree(Tree_node_t *root_node);
42 static bool __data_model_append_item(Tree_node_t *parent, Tree_node_t *node, int container_limit);
43 static void __data_model_convert_db_list_to_tree(Tree_node_t *parent, int id, Eina_List *list);
44 static bool __data_model_update_tree_cb(Tree_node_t *parent, Tree_node_t *node, void *data);
45 static bool __data_model_check_cb(Tree_node_t *parent, Tree_node_t *node, void *data);
46 static bool __data_model_check_count_cb(Tree_node_t *parent, Tree_node_t *node, void *data);
47 static bool __data_model_set_set_cb(Tree_node_t *parent, Tree_node_t *node, void *data);
48 static void __data_model_remove_empty(Tree_node_t *node);
49 static int __data_model_set_lexical_compare_function(const void *data1, const void *data2);
50 static Eina_Inarray *__data_model_sort_children(const Tree_node_t *const root,
51 unsigned int size_hint,
52 Eina_Compare_Cb sort_compare_function);
53 static void __add_default_widget(widget_info_t *widget);
55 static Eina_Bool __data_model_reattach_children(const void *container, void *node, void *fdata);
57 HAPI Tree_node_t *data_model_get_data(void)
62 HAPI Tree_node_t *data_model_get_all_apps(void)
64 return s_info.all_apps;
67 HAPI Tree_node_t *data_model_get_home(void)
73 HAPI void data_model_load_app_mgr(void)
75 Eina_List *livebox_list = NULL;
76 Eina_List *apps = NULL;
78 app_mgr_item_t *app_mgr_item = NULL;
79 Tree_node_t *page = NULL;
80 Tree_node_t *item = NULL;
81 widget_info_t *widget = NULL;
83 LOGD("LOADING DATA MODEL FROM APP MGR");
86 if (!tree_node_new(&s_info.data)) {
87 LOGE("app_mgr_load -> tree_node_new failure1");
91 s_info.data->data = app_item_create(APP_ITEM_ROOT, -1, "ROOT", NULL, NULL, "ROOT", NULL, false, 0, 0, 0, 0, NULL);
93 if (!tree_node_new(&s_info.all_apps)) {
94 LOGE("app_mgr_load -> tree_node_new failure2");
97 s_info.all_apps->data = app_item_create(APP_ITEM_ALL_APPS_ROOT, -1, "ALL APPS", NULL, NULL, "ALL APPS", NULL, false, 0, 0, 0, 0, NULL);
98 tree_node_append(s_info.data, s_info.all_apps);
100 if (!tree_node_new(&s_info.home)) {
101 LOGE("app_mgr_load -> tree_node_new failure2");
104 s_info.home->data = app_item_create(APP_ITEM_HOME, -1, "HOME", NULL, NULL, "HOME", NULL, false, 0, 0, 0, 0, NULL);
105 tree_node_append(s_info.data, s_info.home);
108 apps = app_mgr_get_apps();
110 EINA_LIST_FOREACH(apps, it, app_mgr_item) {
111 if (!tree_node_new(&item)) {
112 LOGE("app_mgr_load -> tree_node_new failure2");
115 item->data = app_item_create(
123 app_mgr_item->removable,
131 LOGE("app_mgr_load -> app_item-create failure");
132 tree_node_free(item, NULL, NULL, NULL);
136 if (!__data_model_append_item(s_info.all_apps, item, APPS_PAGE))
137 tree_node_free(item, NULL, NULL, NULL);
140 livebox_list = livebox_widget_get_list();
142 LOGW(" livebox_list == NULL");
144 page = data_model_add_widget_page();
146 LOGE("page == NULL");
153 widget = eina_list_nth(livebox_list, 0);
155 LOGE("widget == NULL");
159 __add_default_widget(widget);
162 widget = eina_list_nth(livebox_list, 1);
164 LOGE("widget == NULL");
168 __add_default_widget(widget);
170 app_mgr_free_apps(apps);
172 /*by default model is being sorted:*/
173 data_model_sort(__data_model_set_lexical_compare_function);
176 HAPI Eina_Bool data_model_load_db(void)
178 Eina_List *apps_db = NULL;
179 Eina_List *apps_mgr = NULL;
180 Eina_List *it = NULL;
181 db_item_t *db_item = NULL;
183 LOGD("LOADING DATA MODEL FROM DB");
185 db_get_apps(&apps_db);
187 if (apps_db == NULL || eina_list_count(apps_db) == 0)
190 EINA_LIST_FOREACH(apps_db, it, db_item) {
191 switch (db_item->type) {
194 __data_model_load_item(NULL, &s_info.data, db_item, apps_db);
196 LOGE("DB corrupted s_info.data != NULL");
199 case APP_ITEM_ALL_APPS_ROOT:
200 if (!s_info.all_apps) {
201 __data_model_load_item(s_info.data, &s_info.all_apps, db_item, apps_db);
203 LOGE("DB corrupted s_info.all_apps != NULL");
208 __data_model_load_item(s_info.data, &s_info.home, db_item, apps_db);
210 LOGE("DB corrupted s_info.home != NULL");
214 LOGW("Unknown type");
217 db_free_apps(apps_db);
219 apps_mgr = app_mgr_get_apps();
220 tree_in_depth_browse(s_info.all_apps, __data_model_update_tree_cb, apps_mgr);
221 app_mgr_free_apps(apps_mgr);
224 LOGE("s_info.home == NULL");
226 if (!tree_node_new(&s_info.home)) {
227 LOGE("app_mgr_load -> tree_node_new failure2");
230 s_info.home->data = app_item_create(APP_ITEM_HOME, -1, "HOME", NULL, NULL, "HOME", NULL, false, 0, 0, 0, 0, NULL);
231 tree_node_append(s_info.data, s_info.home);
234 if (s_info.home->count == 0) {
235 LOGE("s_info.home == s_info.home->count");
236 data_model_add_widget_page();
239 home_screen_print_tree();
241 /*by default model is being sorted:*/
242 data_model_sort(__data_model_set_lexical_compare_function);
246 HAPI void data_model_free(void)
248 __data_model_free_subtree(s_info.data);
251 HAPI Tree_node_t *data_model_create_folder(app_item_t *new_folder_data)
253 Tree_node_t *folder = NULL, *new_page = NULL;
255 if (new_folder_data) {
256 tree_node_new(&folder);
258 folder->data = new_folder_data;
259 __data_model_append_item(s_info.all_apps, folder, APPS_PAGE);
260 /*also give it one initial page:*/
261 tree_node_new(&new_page);
263 new_page->data = app_item_create(APP_ITEM_PAGE, -1, NULL, NULL, NULL, "PAGE", NULL, false, 0, 0, 0, 0, NULL);
264 if (new_page->data) {
265 tree_node_append(folder, new_page);
267 tree_node_free(new_page, NULL, NULL, NULL);
276 HAPI void data_model_append_node_to_folder(Tree_node_t *folder, Tree_node_t *node)
278 if (!node || !folder)
280 tree_node_detatch(node);
281 __data_model_append_item(folder, node, FOLDER_APPS_PAGE);
284 HAPI void data_model_free_empty_pages(Tree_node_t *folder_or_some_other_root)
286 Tree_node_t *empty_page = NULL;
288 if (!folder_or_some_other_root)
289 folder_or_some_other_root = data_model_get_all_apps();
293 data_model_iterate_pages(folder_or_some_other_root, __data_model_get_empty_page, NULL, &empty_page);
294 __data_model_free_subtree(empty_page);
295 } while (empty_page);
298 HAPI void data_model_delete_folder(Tree_node_t *node)
300 Tree_node_t *page = NULL, *it = NULL, *it_tmp_next = NULL;
302 /*attach child elements to the last page:*/
303 TREE_NODE_FOREACH(node, page)
304 for (it = page->first; it; it = it_tmp_next) {
305 it_tmp_next = it->next;
306 tree_node_detatch(it);
307 tree_node_append(s_info.all_apps->last, it);
310 /*out from the tree:*/
311 tree_node_detatch(node);
312 /*folder with empty pages subtree can be deleted:*/
313 __data_model_free_subtree(node);
316 HAPI Tree_node_t *data_model_install_application(app_mgr_item_t *app_mgr_item)
318 Tree_node_t *item = NULL;
320 tree_node_new(&item);
321 item->data = app_item_create(
329 app_mgr_item->removable,
337 tree_node_free(item, NULL, NULL, NULL);
341 __data_model_append_item(s_info.all_apps, item, APPS_PAGE);
346 HAPI void data_model_uninstall_application(Tree_node_t *node)
348 tree_node_detatch(node);
350 /*this will free memory since application node is always empty:*/
351 __data_model_remove_empty(node);
354 HAPI void data_model_check_all_apps(Tree_node_t *node, bool checked)
357 tree_in_depth_browse(node, __data_model_check_cb, &checked);
360 HAPI int data_model_get_app_check_state(void)
364 tree_in_depth_browse(s_info.all_apps, __data_model_check_count_cb, &count);
368 HAPI void data_model_reposition_item(Tree_node_t *node, Tree_node_t *destinations_parent, Tree_node_t *destination,
369 reposition_side_t side, int page_limit)
371 if (!node || !destinations_parent) {
372 LOGE("item_reposition INVALID usage: %d %d %d", node, destinations_parent, destination);
376 if (node == destination)
379 tree_node_detatch(node);
382 /*append relatively to sibling:*/
383 side == REPOSITION_SIDE_TO_RIGHT ? tree_node_append_relative(node, destination) : tree_node_prepend_relative(node, destination);
386 side == REPOSITION_SIDE_TO_RIGHT ? tree_node_append(destinations_parent, node) : tree_node_prepend(destinations_parent, node);
388 /*now, it may be that we have more items than we can on this page...*/
389 while (destinations_parent->count > page_limit) {
390 tree_node_detatch(node = destinations_parent->last);
392 /*next page (create, or prepend):*/
393 if (!destinations_parent->next) { /*there seems to be no pages left, create one:*/
394 __data_model_append_item(destinations_parent->parent, node, page_limit);
396 } else {/*there is a next page, so lets prepend*/
397 destinations_parent = destinations_parent->next;
398 tree_node_prepend(destinations_parent, node);
403 HAPI void data_model_iterate(Tree_node_t *node, tree_browse_cb_t func_cb, void *data)
406 tree_in_depth_browse(s_info.all_apps, func_cb, data);
408 tree_in_depth_browse(node, func_cb, data);
411 HAPI void data_model_iterate_pages(Tree_node_t *node, tree_browse_cb_t page_func, tree_browse_cb_t item_func, void *data)
413 Tree_node_t *page = NULL, *item = NULL;
416 node = s_info.all_apps;
419 for (page = node->first; page; page = page->next) {
420 if (!page->data || page->data->type != APP_ITEM_PAGE) {
421 LOGE("Model unstable [or node != root], skipping: %d %d", page->data, page->data ? page->data->type : -1);
425 page_func(NULL, page, data);
426 /*for each item in page:*/
428 for (item = page->first; item; item = item->next) {
429 item_func(page, item, data);
430 LOGI("[%s]", item->data->label);
436 HAPI void data_model_update_item(Tree_node_t *node)
439 LOGE("node == NULL");
443 tree_node_update(node);
446 HAPI void data_model_set_view_mode(homescreen_view_t view)
448 tree_in_depth_browse(s_info.all_apps, __data_model_set_set_cb, &view);
451 HAPI void data_model_detach_from_folder(Tree_node_t *folder_node, Tree_node_t *node)
453 if (!folder_node || !node) {
454 LOGE("[INVALID_PARAMS]");
458 data_model_reposition_item(node, s_info.all_apps->last, NULL,
459 REPOSITION_SIDE_TO_RIGHT, APPS_PAGE);
460 data_model_sort(__data_model_set_lexical_compare_function);
464 /* -----=========================== widget ===================================*/
466 HAPI Tree_node_t *data_model_add_widget_page()
468 Tree_node_t *item = NULL;
470 if (!tree_node_new(&item)) {
471 LOGE(" app_mgr_load -> tree_node_new failure2");
475 item->data = app_item_create(APP_ITEM_PAGE, -1, "WIDGET_PAGE", NULL, NULL, "WIDGET_PAGE", NULL, false, 0, 0, 0, 0, NULL);
477 tree_node_free(item, NULL, NULL, NULL);
481 tree_node_append(s_info.home, item);
486 HAPI Tree_node_t *data_model_add_widget(Tree_node_t *page, const char *widget_id, int col, int row, int col_span, int row_span, const char *content_info)
488 Tree_node_t *item = NULL;
490 if (!tree_node_new(&item)) {
491 LOGE(" app_mgr_load -> tree_node_new failure2");
495 item->data = app_item_create(APP_ITEM_WIDGET, -1,
509 tree_node_free(item, NULL, NULL, NULL);
513 tree_node_append(page, item);
518 HAPI void data_model_reposition_widget(Tree_node_t *page_node, Tree_node_t *obj_node)
520 tree_node_detatch(obj_node);
521 tree_node_append(page_node, obj_node);
524 HAPI void data_model_insert_after(Tree_node_t *prev_node, Tree_node_t *item_node)
526 tree_node_detatch(item_node);
529 tree_node_append_relative(item_node, prev_node);
531 tree_node_prepend(s_info.home, item_node);
535 HAPI void data_model_del_item(Tree_node_t *node)
537 tree_node_detatch(node);
538 __data_model_free_subtree(node);
541 HAPI void data_model_resize_widget(Tree_node_t *item_node, int col, int row, int col_span, int row_span)
544 LOGE("item_node == NULL");
548 if (!item_node->data) {
549 LOGE("item_node->data == NULL");
553 app_item_geometry_update(item_node->data, col, row, col_span, row_span);
554 tree_node_update(item_node);
557 HAPI void data_model_update_content_info(Tree_node_t *item_node, const char *content_info)
560 LOGE("item_node == NULL");
564 if (!item_node->data) {
565 LOGE("item_node->data == NULL");
569 app_item_update_content_info(item_node->data, content_info);
570 tree_node_update(item_node);
573 /*===================================== widget ===============================*/
575 HAPI void data_model_sort(Eina_Compare_Cb sort_compare_function)
577 Eina_Inarray *sorted_children = NULL;
578 Tree_node_t *page = NULL, *it = NULL;
580 if (!sort_compare_function)
581 sort_compare_function = __data_model_set_lexical_compare_function;
583 if (!s_info.all_apps)
586 /*First we have to sort top level applications and folders:*/
587 sorted_children = __data_model_sort_children(s_info.all_apps, s_info.all_apps->count*APPS_PAGE, sort_compare_function);
588 eina_inarray_foreach(sorted_children, __data_model_reattach_children, s_info.all_apps);
589 eina_inarray_free(sorted_children);
591 /*Second we have to sort all items in all folders:
593 for (page = s_info.all_apps->first; page; page = page->next) {
594 for (it = page->first; it; it = it->next) {
595 if (it->data && it->data->type == APP_ITEM_FOLDER) {
596 sorted_children = __data_model_sort_children(it, it->count*FOLDER_APPS_PAGE, sort_compare_function);
597 eina_inarray_foreach(sorted_children, __data_model_reattach_children, it);
598 eina_inarray_free(sorted_children);
604 static bool __data_model_get_empty_page(Tree_node_t *nothing, Tree_node_t *page, void *data)
606 Tree_node_t **empty_page = (Tree_node_t **)data;
608 if (page->count == 0) {
616 static void __data_model_load_item(Tree_node_t *parent, Tree_node_t **item, db_item_t* db_item, Eina_List* apps_db)
618 if (!tree_node_new(item)) {
619 LOGE("*item == NULL");
623 (*item)->data = app_item_create(db_item->type,
634 db_item->content_info);
637 if (!tree_node_append(parent, *item)) {
638 LOGE("failed to append home to data");
639 __data_model_free_subtree(*item);
643 __data_model_convert_db_list_to_tree(*item, db_item->first_id, apps_db);
648 static bool __data_model_append_item(Tree_node_t *parent, Tree_node_t *node, int container_limit)
650 Tree_node_t *page = NULL;
652 if (!parent || !node)
656 if (!page || page->count >= container_limit) {
657 if (!tree_node_new(&page))
659 page->data = app_item_create(APP_ITEM_PAGE, -1, "PAGE", NULL, NULL, "PAGE", NULL, false, 0, 0, 0, 0, NULL);
661 tree_node_free(page, NULL, NULL, NULL);
665 if (!tree_node_append(parent, page)) {
666 data_model_del_item(page);
671 return tree_node_append(page, node);
674 static void __data_model_convert_db_list_to_tree(Tree_node_t *parent, int id, Eina_List *list)
676 Eina_List *it = NULL;
677 db_item_t *db_item = NULL;
678 Tree_node_t *node = NULL;
683 EINA_LIST_FOREACH(list, it, db_item) {
684 if (db_item->id == id)
691 tree_node_new(&node);
692 node->data = app_item_create(db_item->type,
699 db_item->type == APP_ITEM_FOLDER,
704 db_item->content_info);
707 tree_node_free(node, NULL, NULL, NULL);
711 tree_node_append(parent, node);
713 __data_model_convert_db_list_to_tree(parent, db_item->next_id, list);
714 __data_model_convert_db_list_to_tree(node, db_item->first_id, list);
717 static bool __data_model_update_tree_cb(Tree_node_t *parent, Tree_node_t *node, void *data)
719 if (node->data->type == APP_ITEM_ICON) {
721 app_mgr_item_t *app_mgr;
722 EINA_LIST_FOREACH((Eina_List *)data, it, app_mgr) {
723 if (!strncmp(app_mgr->appid, node->data->appid, strlen(node->data->appid)))
728 node->data->label = strdup(app_mgr->label);
729 node->data->icon = strdup(app_mgr->icon);
730 node->data->exec = strdup(app_mgr->exec);
732 node->data->removable = app_mgr->removable;
734 } else if (node->data->type == APP_ITEM_FOLDER) {
735 node->data->label = strdup(node->data->appid);
740 static bool __data_model_check_cb(Tree_node_t *parent, Tree_node_t *node, void *data)
742 if (node->data->type == APP_ITEM_ICON)
743 node->data->is_checked = *(bool *)data;
748 static bool __data_model_check_count_cb(Tree_node_t *parent, Tree_node_t *node, void *data)
750 if (node && node->data && node->data->is_checked) {
751 LOGI("%s", node->data->label);
757 static bool __data_model_set_set_cb(Tree_node_t *parent, Tree_node_t *node, void *data)
759 if (node->data->type == APP_ITEM_ICON || node->data->type == APP_ITEM_FOLDER) {
760 if (node->parent->parent && node->parent->parent->data->type == APP_ITEM_FOLDER) {
761 app_icon_set_view_mode(node->data->layout, *(homescreen_view_t *)data, true);
763 app_icon_set_view_mode(node->data->layout, *(homescreen_view_t *)data, false);
765 } else if (node->data->type == APP_ITEM_PAGE && node->parent->data->type == APP_ITEM_ALL_APPS_ROOT) {
766 app_grid_set_view_mode(node->data->layout, *(homescreen_view_t *)data);
772 static void _data_model_full_page_reorder(Tree_node_t *node)
774 if (node->parent->count > APPS_PAGE)
776 Tree_node_t *parent = node->parent;
777 Tree_node_t *last = parent->last;
778 tree_node_detatch(last);
780 last->data->grid_item = app_grid_insert_item_relative(parent->next->data->layout, last->data->layout, parent->next->first->data->grid_item);
782 //TODO check if next exist
783 tree_node_prepend(parent->next, last);
784 _data_model_full_page_reorder(last);
789 static void __data_model_remove_empty(Tree_node_t *node)
791 if (!node || !node->data)
794 if ((node->data->type == APP_ITEM_PAGE || node->data->type == APP_ITEM_FOLDER) && node->count == 0) {
795 app_item_free(node->data);
796 /*since it's empty, we pass NULLs:*/
797 tree_node_free(node, NULL, NULL, NULL);
801 static Eina_Bool __data_model_reattach_children(const void *container, void *node, void *fdata)
803 unsigned int page_size_limit = FOLDER_APPS_PAGE;
804 bool place_found = false;
805 Tree_node_t *parent = (Tree_node_t *)fdata, *child = *((Tree_node_t **)node), *page = NULL;
807 if (parent->data->type == APP_ITEM_ALL_APPS_ROOT)
808 page_size_limit = APPS_PAGE;
810 /*now find first free page:*/
811 for (page = parent->first; page; page = page->next) {
812 if (page->count < page_size_limit) {
813 tree_node_append(page, child);
815 LOGI("reattach_children %s found place in %s", child->data->label, parent->data->label);
822 LOGE("reattach_children %s could not find place", child->data->label);
823 __data_model_append_item(parent, child, page_size_limit);
828 static Eina_Inarray *__data_model_sort_children(const Tree_node_t *const root, unsigned int size_hint, Eina_Compare_Cb sort_compare_function)
830 Eina_Inarray *array = NULL;
831 Tree_node_t *page = NULL, *it = NULL, *it_tmp = NULL;
833 if (!root || !root->data ||
834 !(root->data->type == APP_ITEM_FOLDER ||
835 root->data->type == APP_ITEM_ALL_APPS_ROOT)
838 /*now we know this is root or folder for sure, so it contains pages:*/
840 array = eina_inarray_new(sizeof(Tree_node_t *), size_hint);
843 LOGE("sort_children: allocation error");
848 for (page = root->first; page; page = page->next) {
850 if (!page->data || page->data->type != APP_ITEM_PAGE) {
851 LOGE("sort_children problem: data: %d type: %d", page->data, page->data ? page->data->type : -1);
855 /*for each node in "page":*/
856 for (it = page->first; it; it = it_tmp) {
858 tree_node_detatch(it);
860 if (eina_inarray_insert_sorted(array, &it, sort_compare_function) < 0) {
861 LOGE("sort_children: item insertion error");
870 static void __data_model_free_subtree(Tree_node_t *root_node)
872 Tree_node_t *first_child = NULL, *last_child = NULL, *child_tmp = NULL;
873 int children_count = 0;
876 LOGE("root_node == NULL");
880 tree_node_free(root_node, &first_child, &last_child, &children_count);
882 if ((!first_child || !last_child) && children_count > 0) {
883 LOGE("Node has %d children but pointers are first: %d, last: %d", children_count, first_child, last_child);
887 while (children_count-- > 0) {
888 child_tmp = first_child->next;
889 __data_model_free_subtree(first_child);
890 first_child = child_tmp;
894 static int __data_model_set_lexical_compare_function(const void *data1, const void *data2)
896 char *l_upper = NULL, *r_upper = NULL;
897 Tree_node_t *l = *((Tree_node_t **)data1), *r = *((Tree_node_t **)data2);
900 if (!l || !l->data || !l->data->label)
903 if (!r || !r->data || !r->data->label)
906 l_upper = (char *)alloca(NAME_MAX*sizeof(char));
907 r_upper = (char *)alloca(NAME_MAX*sizeof(char));
909 strncpy(l_upper, l->data->label, NAME_MAX - sizeof('\0'));
910 strncpy(r_upper, r->data->label, NAME_MAX - sizeof('\0'));
912 eina_str_toupper(&l_upper);
913 eina_str_toupper(&r_upper);
915 return !(res = strcoll(l_upper, r_upper)) ? 1 : res;
918 static void __add_default_widget(widget_info_t *widget)
920 Tree_node_t *item = NULL;
922 Tree_node_t *page = data_model_add_widget_page();
924 LOGE("item == NULL");
928 item = data_model_add_widget(page, widget->widget_id, 0, 0, widget->width,
929 widget->height, NULL);
931 LOGE("item == NULL");
935 LOGD("Widget: %s with size (%d, %d) added", widget->widget_id,
936 widget->width, widget->height);