The source code moved from the SPIN with license changed to Flora 1.1
[apps/native/home/homescreen-efl.git] / src / data_model.c
1 /*
2  * Copyright 2012  Samsung Electronics Co., Ltd
3  *
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
7  *
8  * http://floralicense.org/license/
9  *
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.
15  */
16
17 #include <alloca.h>
18 #include "homescreen-efl.h"
19 #include "data_model.h"
20 #include "db/db.h"
21 #include "app_icon.h"
22 #include "app_item.h"
23 #include "app_grid.h"
24 #include "folder_panel.h"
25 #include "all_apps.h"
26 #include "livebox/livebox_widget.h"
27 #include "popup.h"
28
29 static struct {
30         Tree_node_t *data;
31         Tree_node_t *all_apps;
32         Tree_node_t *home;
33 } s_info = {
34         .data = NULL,
35         .all_apps = NULL,
36         .home = NULL,
37 };
38
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);
54
55 static Eina_Bool __data_model_reattach_children(const void *container, void *node, void *fdata);
56
57 HAPI Tree_node_t *data_model_get_data(void)
58 {
59         return s_info.data;
60 }
61
62 HAPI Tree_node_t *data_model_get_all_apps(void)
63 {
64         return s_info.all_apps;
65 }
66
67 HAPI Tree_node_t *data_model_get_home(void)
68 {
69         return s_info.home;
70 }
71
72
73 HAPI void data_model_load_app_mgr(void)
74 {
75         Eina_List *livebox_list = NULL;
76         Eina_List *apps = NULL;
77         Eina_List *it = 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;
82
83         LOGD("LOADING DATA MODEL FROM APP MGR");
84         db_create_tables();
85
86         if (!tree_node_new(&s_info.data)) {
87                 LOGE("app_mgr_load -> tree_node_new failure1");
88                 return;
89         }
90
91         s_info.data->data = app_item_create(APP_ITEM_ROOT, -1, "ROOT", NULL, NULL, "ROOT", NULL, false, 0, 0, 0, 0, NULL);
92
93         if (!tree_node_new(&s_info.all_apps)) {
94                 LOGE("app_mgr_load -> tree_node_new failure2");
95                 return;
96         }
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);
99
100         if (!tree_node_new(&s_info.home)) {
101                 LOGE("app_mgr_load -> tree_node_new failure2");
102                 return;
103         }
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);
106
107
108         apps = app_mgr_get_apps();
109
110         EINA_LIST_FOREACH(apps, it, app_mgr_item) {
111                 if (!tree_node_new(&item)) {
112                         LOGE("app_mgr_load -> tree_node_new failure2");
113                         return;
114                 }
115                 item->data = app_item_create(
116                                 APP_ITEM_ICON,
117                                 -1,
118                                 app_mgr_item->label,
119                                 app_mgr_item->icon,
120                                 app_mgr_item->exec,
121                                 app_mgr_item->appid,
122                                 NULL,
123                                 app_mgr_item->removable,
124                                 0,
125                                 0,
126                                 0,
127                                 0,
128                                 NULL);
129
130                 if (!item->data) {
131                         LOGE("app_mgr_load -> app_item-create failure");
132                         tree_node_free(item, NULL, NULL, NULL);
133                         continue;
134                 }
135
136                 if (!__data_model_append_item(s_info.all_apps, item, APPS_PAGE))
137                         tree_node_free(item, NULL, NULL, NULL);
138         }
139
140         livebox_list = livebox_widget_get_list();
141         if (!livebox_list) {
142                 LOGW(" livebox_list == NULL");
143
144                 page = data_model_add_widget_page();
145                 if (!page) {
146                         LOGE("page == NULL");
147                         return;
148                 }
149
150                 return;
151         }
152
153         widget = eina_list_nth(livebox_list, 0);
154         if (!widget) {
155                 LOGE("widget == NULL");
156                 return;
157         }
158
159         __add_default_widget(widget);
160
161
162         widget = eina_list_nth(livebox_list, 1);
163         if (!widget) {
164                 LOGE("widget == NULL");
165                 return;
166         }
167
168         __add_default_widget(widget);
169
170         app_mgr_free_apps(apps);
171
172         /*by default model is being sorted:*/
173         data_model_sort(__data_model_set_lexical_compare_function);
174 }
175
176 HAPI Eina_Bool data_model_load_db(void)
177 {
178         Eina_List *apps_db = NULL;
179         Eina_List *apps_mgr = NULL;
180         Eina_List *it = NULL;
181         db_item_t *db_item = NULL;
182
183         LOGD("LOADING DATA MODEL FROM DB");
184
185         db_get_apps(&apps_db);
186
187         if (apps_db == NULL || eina_list_count(apps_db) == 0)
188                 return EINA_FALSE;
189
190         EINA_LIST_FOREACH(apps_db, it, db_item) {
191                 switch (db_item->type) {
192                 case APP_ITEM_ROOT:
193                         if (!s_info.data) {
194                                 __data_model_load_item(NULL, &s_info.data, db_item, apps_db);
195                         } else {
196                                 LOGE("DB corrupted s_info.data != NULL");
197                         }
198                 break;
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);
202                         } else {
203                                 LOGE("DB corrupted s_info.all_apps != NULL");
204                         }
205                 break;
206                 case APP_ITEM_HOME:
207                         if (!s_info.home) {
208                                 __data_model_load_item(s_info.data, &s_info.home, db_item, apps_db);
209                         } else {
210                                 LOGE("DB corrupted s_info.home != NULL");
211                         }
212                 break;
213                 default:
214                         LOGW("Unknown type");
215                 }
216         }
217         db_free_apps(apps_db);
218
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);
222
223         if (!s_info.home) {
224                 LOGE("s_info.home == NULL");
225
226                 if (!tree_node_new(&s_info.home)) {
227                         LOGE("app_mgr_load -> tree_node_new failure2");
228                         return EINA_FALSE;
229                 }
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);
232         }
233
234         if (s_info.home->count == 0) {
235                 LOGE("s_info.home == s_info.home->count");
236                 data_model_add_widget_page();
237         }
238
239         home_screen_print_tree();
240
241         /*by default model is being sorted:*/
242         data_model_sort(__data_model_set_lexical_compare_function);
243         return EINA_TRUE;
244 }
245
246 HAPI void data_model_free(void)
247 {
248         __data_model_free_subtree(s_info.data);
249 }
250
251 HAPI Tree_node_t *data_model_create_folder(app_item_t *new_folder_data)
252 {
253         Tree_node_t *folder = NULL, *new_page = NULL;
254
255         if (new_folder_data) {
256                 tree_node_new(&folder);
257                 if (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);
262                         if (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);
266                                 } else {
267                                         tree_node_free(new_page, NULL, NULL, NULL);
268                                 }
269                         }
270                 }
271         }
272
273         return folder;
274 }
275
276 HAPI void data_model_append_node_to_folder(Tree_node_t *folder, Tree_node_t *node)
277 {
278         if (!node || !folder)
279                 return;
280         tree_node_detatch(node);
281         __data_model_append_item(folder, node, FOLDER_APPS_PAGE);
282 }
283
284 HAPI void data_model_free_empty_pages(Tree_node_t *folder_or_some_other_root)
285 {
286         Tree_node_t *empty_page = NULL;
287
288         if (!folder_or_some_other_root)
289                 folder_or_some_other_root = data_model_get_all_apps();
290
291         do {
292                 empty_page = NULL;
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);
296 }
297
298 HAPI void data_model_delete_folder(Tree_node_t *node)
299 {
300         Tree_node_t *page = NULL, *it = NULL, *it_tmp_next = NULL;
301
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);
308         }
309
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);
314 }
315
316 HAPI Tree_node_t *data_model_install_application(app_mgr_item_t *app_mgr_item)
317 {
318         Tree_node_t *item = NULL;
319
320         tree_node_new(&item);
321         item->data = app_item_create(
322                         APP_ITEM_ICON,
323                         -1,
324                         app_mgr_item->label,
325                         app_mgr_item->icon,
326                         app_mgr_item->exec,
327                         app_mgr_item->appid,
328                         NULL,
329                         app_mgr_item->removable,
330                         0,
331                         0,
332                         0,
333                         0,
334                         NULL);
335
336         if (!item->data) {
337                 tree_node_free(item, NULL, NULL, NULL);
338                 return NULL;
339         }
340
341         __data_model_append_item(s_info.all_apps, item, APPS_PAGE);
342
343         return item;
344 }
345
346 HAPI void data_model_uninstall_application(Tree_node_t *node)
347 {
348         tree_node_detatch(node);
349
350         /*this will free memory since application node is always empty:*/
351         __data_model_remove_empty(node);
352 }
353
354 HAPI void data_model_check_all_apps(Tree_node_t *node, bool checked)
355 {
356         LOGI("");
357         tree_in_depth_browse(node, __data_model_check_cb, &checked);
358 }
359
360 HAPI int data_model_get_app_check_state(void)
361 {
362         LOGI("");
363         int count = 0;
364         tree_in_depth_browse(s_info.all_apps, __data_model_check_count_cb, &count);
365         return count;
366 }
367
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)
370 {
371         if (!node || !destinations_parent) {
372                 LOGE("item_reposition INVALID usage: %d %d %d", node, destinations_parent, destination);
373                 return;
374         }
375
376         if (node == destination)
377                 return;
378
379         tree_node_detatch(node);
380
381         if (destination)
382                 /*append relatively to sibling:*/
383                 side == REPOSITION_SIDE_TO_RIGHT ? tree_node_append_relative(node, destination) : tree_node_prepend_relative(node, destination);
384         else
385                 /*append to page:*/
386                 side == REPOSITION_SIDE_TO_RIGHT ? tree_node_append(destinations_parent, node) : tree_node_prepend(destinations_parent, node);
387
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);
391
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);
395                         break;
396                 } else {/*there is a next page, so lets prepend*/
397                         destinations_parent = destinations_parent->next;
398                         tree_node_prepend(destinations_parent, node);
399                 }
400         }
401 }
402
403 HAPI void data_model_iterate(Tree_node_t *node, tree_browse_cb_t func_cb, void *data)
404 {
405         if (!node)
406                 tree_in_depth_browse(s_info.all_apps, func_cb, data);
407         else
408                 tree_in_depth_browse(node, func_cb, data);
409 }
410
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)
412 {
413         Tree_node_t *page = NULL, *item = NULL;
414
415         if (!node)
416                 node = s_info.all_apps;
417
418         /*for each page:*/
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);
422                         continue;
423                 }
424                 if (page_func)
425                         page_func(NULL, page, data);
426                 /*for each item in page:*/
427                 if (item_func) {
428                         for (item = page->first; item; item = item->next) {
429                                 item_func(page, item, data);
430                                 LOGI("[%s]", item->data->label);
431                         }
432                 }
433         }
434 }
435
436 HAPI void data_model_update_item(Tree_node_t *node)
437 {
438         if (!node) {
439                 LOGE("node == NULL");
440                 return;
441         }
442
443         tree_node_update(node);
444 }
445
446 HAPI void data_model_set_view_mode(homescreen_view_t view)
447 {
448         tree_in_depth_browse(s_info.all_apps, __data_model_set_set_cb, &view);
449 }
450
451 HAPI void data_model_detach_from_folder(Tree_node_t *folder_node, Tree_node_t *node)
452 {
453         if (!folder_node || !node) {
454                 LOGE("[INVALID_PARAMS]");
455                 return;
456         }
457
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);
461 }
462
463
464 /* -----=========================== widget ===================================*/
465
466 HAPI Tree_node_t *data_model_add_widget_page()
467 {
468         Tree_node_t *item = NULL;
469
470         if (!tree_node_new(&item)) {
471                 LOGE(" app_mgr_load -> tree_node_new failure2");
472                 return NULL;
473         }
474
475         item->data = app_item_create(APP_ITEM_PAGE, -1, "WIDGET_PAGE", NULL, NULL, "WIDGET_PAGE", NULL, false, 0, 0, 0, 0, NULL);
476         if (!item->data) {
477                 tree_node_free(item, NULL, NULL, NULL);
478                 return NULL;
479         }
480
481         tree_node_append(s_info.home, item);
482
483         return item;
484 }
485
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)
487 {
488         Tree_node_t *item = NULL;
489
490         if (!tree_node_new(&item)) {
491                 LOGE(" app_mgr_load -> tree_node_new failure2");
492                 return NULL;
493         }
494
495         item->data = app_item_create(APP_ITEM_WIDGET, -1,
496                         NULL,
497                         NULL,
498                         NULL,
499                         widget_id,
500                         NULL,
501                         false,
502                         col,
503                         row,
504                         col_span,
505                         row_span,
506                         content_info);
507
508         if (!item->data) {
509                 tree_node_free(item, NULL, NULL, NULL);
510                 return NULL;
511         }
512
513         tree_node_append(page, item);
514
515         return item;
516 }
517
518 HAPI void data_model_reposition_widget(Tree_node_t *page_node, Tree_node_t *obj_node)
519 {
520         tree_node_detatch(obj_node);
521         tree_node_append(page_node, obj_node);
522 }
523
524 HAPI void data_model_insert_after(Tree_node_t *prev_node, Tree_node_t *item_node)
525 {
526         tree_node_detatch(item_node);
527
528         if (prev_node) {
529                 tree_node_append_relative(item_node, prev_node);
530         } else {
531                 tree_node_prepend(s_info.home, item_node);
532         }
533 }
534
535 HAPI void data_model_del_item(Tree_node_t *node)
536 {
537         tree_node_detatch(node);
538         __data_model_free_subtree(node);
539 }
540
541 HAPI void data_model_resize_widget(Tree_node_t *item_node, int col, int row, int col_span, int row_span)
542 {
543         if (!item_node) {
544                 LOGE("item_node == NULL");
545                 return;
546         }
547
548         if (!item_node->data) {
549                 LOGE("item_node->data == NULL");
550                 return;
551         }
552
553         app_item_geometry_update(item_node->data, col, row, col_span, row_span);
554         tree_node_update(item_node);
555 }
556
557 HAPI void data_model_update_content_info(Tree_node_t *item_node, const char *content_info)
558 {
559         if (!item_node) {
560                 LOGE("item_node == NULL");
561                 return;
562         }
563
564         if (!item_node->data) {
565                 LOGE("item_node->data == NULL");
566                 return;
567         }
568
569         app_item_update_content_info(item_node->data, content_info);
570         tree_node_update(item_node);
571 }
572
573 /*===================================== widget ===============================*/
574
575 HAPI void data_model_sort(Eina_Compare_Cb sort_compare_function)
576 {
577         Eina_Inarray *sorted_children = NULL;
578         Tree_node_t *page = NULL, *it = NULL;
579
580         if (!sort_compare_function)
581                 sort_compare_function = __data_model_set_lexical_compare_function;
582
583         if (!s_info.all_apps)
584                 return;
585
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);
590
591         /*Second we have to sort all items in all folders:
592         find 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);
599                         }
600                 }
601         }
602 }
603
604 static bool __data_model_get_empty_page(Tree_node_t *nothing, Tree_node_t *page, void *data)
605 {
606         Tree_node_t **empty_page = (Tree_node_t **)data;
607
608         if (page->count == 0) {
609                 *empty_page = page;
610                 return false;
611         }
612
613         return true;
614 }
615
616 static void __data_model_load_item(Tree_node_t *parent, Tree_node_t **item, db_item_t* db_item, Eina_List* apps_db)
617 {
618         if (!tree_node_new(item)) {
619                 LOGE("*item == NULL");
620                 return;
621         }
622
623         (*item)->data = app_item_create(db_item->type,
624                         db_item->id,
625                         NULL,
626                         NULL, NULL,
627                         db_item->appid,
628                         NULL,
629                         false,
630                         db_item->x,
631                         db_item->y,
632                         db_item->w,
633                         db_item->h,
634                         db_item->content_info);
635
636         if (parent) {
637                 if (!tree_node_append(parent, *item)) {
638                         LOGE("failed to append home to data");
639                         __data_model_free_subtree(*item);
640                         return;
641                 }
642
643                 __data_model_convert_db_list_to_tree(*item, db_item->first_id, apps_db);
644         }
645 }
646
647
648 static bool __data_model_append_item(Tree_node_t *parent, Tree_node_t *node, int container_limit)
649 {
650         Tree_node_t *page = NULL;
651
652         if (!parent || !node)
653                 return false;
654
655         page = parent->last;
656         if (!page || page->count >= container_limit) {
657                 if (!tree_node_new(&page))
658                         return false;
659                 page->data = app_item_create(APP_ITEM_PAGE, -1, "PAGE", NULL, NULL, "PAGE", NULL, false, 0, 0, 0, 0, NULL);
660                 if (!page->data) {
661                         tree_node_free(page, NULL, NULL, NULL);
662                         return NULL;
663                 }
664
665                 if (!tree_node_append(parent, page)) {
666                         data_model_del_item(page);
667                         return false;
668                 }
669         }
670
671         return tree_node_append(page, node);
672 }
673
674 static void __data_model_convert_db_list_to_tree(Tree_node_t *parent, int id, Eina_List *list)
675 {
676         Eina_List *it = NULL;
677         db_item_t *db_item = NULL;
678         Tree_node_t *node = NULL;
679
680         if (id == -1)
681                 return;
682
683         EINA_LIST_FOREACH(list, it, db_item) {
684                 if (db_item->id == id)
685                         break;
686         }
687
688         if (!db_item)
689                 return;
690
691         tree_node_new(&node);
692         node->data = app_item_create(db_item->type,
693                         db_item->id,
694                         "",
695                         "",
696                         "",
697                         db_item->appid,
698                         NULL,
699                         db_item->type == APP_ITEM_FOLDER,
700                         db_item->x,
701                         db_item->y,
702                         db_item->w,
703                         db_item->h,
704                         db_item->content_info);
705
706         if (!node->data) {
707                 tree_node_free(node, NULL, NULL, NULL);
708                 return;
709         }
710
711         tree_node_append(parent, node);
712
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);
715 }
716
717 static bool __data_model_update_tree_cb(Tree_node_t *parent, Tree_node_t *node, void *data)
718 {
719         if (node->data->type == APP_ITEM_ICON) {
720                 Eina_List *it;
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)))
724                                 break;
725                 }
726
727                 if (app_mgr) {
728                         node->data->label = strdup(app_mgr->label);
729                         node->data->icon = strdup(app_mgr->icon);
730                         node->data->exec = strdup(app_mgr->exec);
731
732                         node->data->removable = app_mgr->removable;
733                 }
734         } else if (node->data->type == APP_ITEM_FOLDER) {
735                 node->data->label = strdup(node->data->appid);
736         }
737         return true;
738 }
739
740 static bool __data_model_check_cb(Tree_node_t *parent, Tree_node_t *node, void *data)
741 {
742         if (node->data->type == APP_ITEM_ICON)
743                 node->data->is_checked = *(bool *)data;
744
745         return true;
746 }
747
748 static bool __data_model_check_count_cb(Tree_node_t *parent, Tree_node_t *node, void *data)
749 {
750         if (node && node->data && node->data->is_checked) {
751                 LOGI("%s", node->data->label);
752                 ++*(int *)data;
753         }
754         return true;
755 }
756
757 static bool __data_model_set_set_cb(Tree_node_t *parent, Tree_node_t *node, void *data)
758 {
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);
762                 } else {
763                         app_icon_set_view_mode(node->data->layout, *(homescreen_view_t *)data, false);
764                 }
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);
767         }
768         return true;
769 }
770
771 /*
772 static void _data_model_full_page_reorder(Tree_node_t *node)
773 {
774         if (node->parent->count > APPS_PAGE)
775         {
776                 Tree_node_t *parent = node->parent;
777                 Tree_node_t *last = parent->last;
778                 tree_node_detatch(last);
779
780                 last->data->grid_item = app_grid_insert_item_relative(parent->next->data->layout, last->data->layout, parent->next->first->data->grid_item);
781
782                 //TODO check if next exist
783                 tree_node_prepend(parent->next, last);
784                 _data_model_full_page_reorder(last);
785         }
786 }
787 */
788
789 static void __data_model_remove_empty(Tree_node_t *node)
790 {
791         if (!node || !node->data)
792                 return;
793
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);
798         }
799 }
800
801 static Eina_Bool __data_model_reattach_children(const void *container, void *node, void *fdata)
802 {
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;
806
807         if (parent->data->type == APP_ITEM_ALL_APPS_ROOT)
808                 page_size_limit = APPS_PAGE;
809
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);
814                         place_found = true;
815                         LOGI("reattach_children %s found place in %s", child->data->label, parent->data->label);
816                         break;
817                 }
818         }
819
820         /*sanity check:*/
821         if (!place_found) {
822                 LOGE("reattach_children %s could not find place", child->data->label);
823                 __data_model_append_item(parent, child, page_size_limit);
824         }
825         return EINA_TRUE;
826 }
827
828 static Eina_Inarray *__data_model_sort_children(const Tree_node_t *const root, unsigned int size_hint, Eina_Compare_Cb sort_compare_function)
829 {
830         Eina_Inarray *array = NULL;
831         Tree_node_t *page = NULL, *it = NULL, *it_tmp = NULL;
832
833         if (!root || !root->data ||
834                 !(root->data->type == APP_ITEM_FOLDER ||
835                         root->data->type == APP_ITEM_ALL_APPS_ROOT)
836         )
837                 return NULL;
838         /*now we know this is root or folder for sure, so it contains pages:*/
839
840         array = eina_inarray_new(sizeof(Tree_node_t *), size_hint);
841
842         if (!array) {
843                 LOGE("sort_children: allocation error");
844                 return NULL;
845         }
846
847         /*for each "page":*/
848         for (page = root->first; page; page = page->next) {
849                 /*sanity check:*/
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);
852                         return array;
853                 }
854
855                 /*for each node in "page":*/
856                 for (it = page->first; it; it = it_tmp) {
857                         it_tmp = it->next;
858                         tree_node_detatch(it);
859
860                         if (eina_inarray_insert_sorted(array, &it, sort_compare_function) < 0) {
861                                 LOGE("sort_children: item insertion error");
862                                 return array;
863                         }
864                 }
865         }
866
867         return array;
868 }
869
870 static void __data_model_free_subtree(Tree_node_t *root_node)
871 {
872         Tree_node_t *first_child = NULL, *last_child = NULL, *child_tmp = NULL;
873         int children_count = 0;
874
875         if (!root_node) {
876                 LOGE("root_node == NULL");
877                 return;
878         }
879
880         tree_node_free(root_node, &first_child, &last_child, &children_count);
881
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);
884                 return;
885         }
886
887         while (children_count-- > 0) {
888                 child_tmp = first_child->next;
889                 __data_model_free_subtree(first_child);
890                 first_child = child_tmp;
891         }
892 }
893
894 static int __data_model_set_lexical_compare_function(const void *data1, const void *data2)
895 {
896         char *l_upper = NULL, *r_upper = NULL;
897         Tree_node_t *l = *((Tree_node_t **)data1), *r = *((Tree_node_t **)data2);
898         int res = 0;
899
900         if (!l || !l->data || !l->data->label)
901                 return 1;
902
903         if (!r || !r->data || !r->data->label)
904                 return -1;
905
906         l_upper = (char *)alloca(NAME_MAX*sizeof(char));
907         r_upper = (char *)alloca(NAME_MAX*sizeof(char));
908
909         strncpy(l_upper, l->data->label, NAME_MAX - sizeof('\0'));
910         strncpy(r_upper, r->data->label, NAME_MAX - sizeof('\0'));
911
912         eina_str_toupper(&l_upper);
913         eina_str_toupper(&r_upper);
914
915         return !(res = strcoll(l_upper, r_upper)) ? 1 : res;
916 }
917
918 static void __add_default_widget(widget_info_t *widget)
919 {
920         Tree_node_t *item = NULL;
921
922         Tree_node_t *page = data_model_add_widget_page();
923         if (!page) {
924                 LOGE("item == NULL");
925                 return;
926         }
927
928         item = data_model_add_widget(page, widget->widget_id, 0, 0, widget->width,
929                         widget->height, NULL);
930         if (!item) {
931                 LOGE("item == NULL");
932                 return;
933         }
934
935         LOGD("Widget: %s with size (%d, %d) added", widget->widget_id,
936                         widget->width, widget->height);
937 }