Refactored TabUI service
[profile/tv/apps/web/browser.git] / services / TabUI / TabUI.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (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://www.apache.org/licenses/LICENSE-2.0
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 <Elementary.h>
18 #include <boost/concept_check.hpp>
19 #include <vector>
20 #include <string>
21 #include <string.h>
22 #include <AbstractMainWindow.h>
23
24 #include "TabUI.h"
25 #include "ServiceManager.h"
26 #include "BrowserLogger.h"
27 #include "Tools/EflTools.h"
28 #include "../Tools/BrowserImage.h"
29
30
31 namespace tizen_browser{
32 namespace base_ui{
33
34 EXPORT_SERVICE(TabUI, "org.tizen.browser.tabui")
35
36 typedef struct _TabItemData
37 {
38     std::shared_ptr<tizen_browser::basic_webengine::TabContent> item;
39     std::shared_ptr<tizen_browser::base_ui::TabUI> tabUI;
40 } TabItemData;
41
42 struct ItemData
43 {
44     tizen_browser::base_ui::TabUI* tabUI;
45     Elm_Object_Item * e_item;
46 };
47
48 TabUI::TabUI()
49     : m_tab_layout(nullptr)
50     , m_genListActionBar(nullptr)
51     , m_itemClassActionBar(nullptr)
52     , m_genListTop(nullptr)
53     , m_itemClassTop(nullptr)
54     , m_gengrid(nullptr)
55     , m_parent(nullptr)
56     , m_item_class(nullptr)
57 {
58     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
59     m_edjFilePath = EDJE_DIR;
60     m_edjFilePath.append("TabUI/TabUI.edj");
61 }
62
63 TabUI::~TabUI()
64 {
65
66 }
67
68 void TabUI::show(Evas_Object* parent)
69 {
70     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
71     //m_parent = p;
72     elm_theme_extension_add(nullptr, m_edjFilePath.c_str());
73     m_tab_layout = elm_layout_add(parent);
74     elm_layout_file_set(m_tab_layout, m_edjFilePath.c_str(), "tab-layout");
75     evas_object_size_hint_weight_set(m_tab_layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
76     evas_object_size_hint_align_set(m_tab_layout, EVAS_HINT_FILL, EVAS_HINT_FILL);
77     evas_object_show(m_tab_layout);
78
79     showActionBar();
80     showTopButtons();
81
82     m_gengrid = elm_gengrid_add(m_tab_layout);
83     elm_object_part_content_set(m_tab_layout, "tab_gengird", m_gengrid);
84
85     evas_object_smart_callback_add(m_gengrid, "item,focused", focusItem, nullptr);
86     evas_object_smart_callback_add(m_gengrid, "item,unfocused", unFocusItem, nullptr);
87     evas_object_smart_callback_add(m_gengrid, "activated", _itemSelected, this);
88
89     if (!m_item_class) {
90         m_item_class = elm_gengrid_item_class_new();
91         m_item_class->item_style = "tab_item";
92         m_item_class->func.text_get = _grid_text_get;
93         m_item_class->func.content_get =  _tab_grid_content_get;
94         m_item_class->func.state_get = nullptr;
95         m_item_class->func.del = nullptr;
96     }
97
98     M_ASSERT(m_parent);
99     elm_gengrid_align_set(m_gengrid, 0, 0);
100     elm_gengrid_select_mode_set(m_gengrid, ELM_OBJECT_SELECT_MODE_ALWAYS);
101     elm_gengrid_multi_select_set(m_gengrid, EINA_FALSE);
102     elm_gengrid_horizontal_set(m_gengrid, EINA_FALSE);
103     elm_gengrid_highlight_mode_set(m_gengrid, EINA_TRUE);
104     elm_scroller_policy_set(m_gengrid, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
105     elm_scroller_page_size_set(m_gengrid, 0, 327);
106
107     evas_object_size_hint_weight_set(m_gengrid, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
108     evas_object_size_hint_align_set(m_gengrid, EVAS_HINT_FILL, EVAS_HINT_FILL);
109
110     double efl_scale = elm_config_scale_get() / elm_app_base_scale_get();
111     elm_gengrid_item_size_set(m_gengrid, 364 * efl_scale, 320 * efl_scale);
112 }
113
114
115 void TabUI::showActionBar()
116 {
117     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
118     elm_theme_extension_add(nullptr, m_edjFilePath.c_str());
119     m_genListActionBar = elm_genlist_add(m_tab_layout);
120     elm_object_part_content_set(m_tab_layout, "action_bar_genlist", m_genListActionBar);
121     elm_genlist_homogeneous_set(m_genListActionBar, EINA_FALSE);
122     elm_genlist_multi_select_set(m_genListActionBar, EINA_FALSE);
123     elm_genlist_select_mode_set(m_genListActionBar, ELM_OBJECT_SELECT_MODE_ALWAYS);
124     elm_genlist_mode_set(m_genListActionBar, ELM_LIST_LIMIT);
125     elm_genlist_decorate_mode_set(m_genListActionBar, EINA_TRUE);
126     evas_object_size_hint_weight_set(m_genListActionBar, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
127
128 //  evas_object_smart_callback_add(m_genList, "item,focused", focusItem, this);
129 //  evas_object_smart_callback_add(m_genList, "item,unfocused", unFocusItem, nullptr);*/
130
131     m_itemClassActionBar = elm_genlist_item_class_new();
132     m_itemClassActionBar->item_style = "action_bar_items";
133     m_itemClassActionBar->func.text_get = nullptr; // &listTopItemTextGet;
134     m_itemClassActionBar->func.content_get = &listActionBarContentGet;
135     m_itemClassActionBar->func.state_get = nullptr;
136     m_itemClassActionBar->func.del = nullptr;
137
138     ItemData *id = new ItemData;
139     id->tabUI = this;
140     Elm_Object_Item* elmItem = elm_genlist_item_append(m_genListActionBar,    //genlist
141                                                        m_itemClassActionBar,  //item Class
142                                                        id,
143                                                        nullptr,               //parent item
144                                                        ELM_GENLIST_ITEM_NONE, //item type
145                                                        nullptr,
146                                                        nullptr                //data passed to above function
147                                                       );
148     id->e_item = elmItem;
149
150     ItemData *id2 = new ItemData;
151     id2->tabUI = this;
152     Elm_Object_Item* elmItem2 = elm_genlist_item_append(m_genListActionBar,    //genlist
153                                                         m_itemClassActionBar,  //item Class
154                                                         id2,
155                                                         nullptr,               //parent item
156                                                         ELM_GENLIST_ITEM_NONE, //item type
157                                                         nullptr,
158                                                         nullptr                //data passed to above function
159                                                        );
160     id2->e_item = elmItem2;
161
162     ItemData *id3 = new ItemData;
163     id3->tabUI = this;
164     Elm_Object_Item* elmItem3 = elm_genlist_item_append(m_genListActionBar  ,  //genlist
165                                                         m_itemClassActionBar,  //item Class
166                                                         id3,
167                                                         nullptr,               //parent item
168                                                         ELM_GENLIST_ITEM_NONE, //item type
169                                                         nullptr,
170                                                         nullptr                //data passed to above function
171                                                        );
172     id3->e_item = elmItem3;
173
174     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
175 }
176
177 Evas_Object* TabUI::listActionBarContentGet(void* data, Evas_Object* obj , const char* part)
178 {
179     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
180     if (obj && part) {
181         const char *part_name1 = "newtab_click";
182         static const int part_name1_len = strlen(part_name1);
183         const char *part_name2 = "newincognitotab_clic";
184         static const int part_name2_len = strlen(part_name2);
185         const char *part_name3 = "closetabs_click";
186         static const int part_name3_len = strlen(part_name3);
187         const char *part_name4 = "close_click";
188         static const int part_name4_len = strlen(part_name4);
189
190         if (!strncmp(part_name1, part, part_name1_len)) {
191             Evas_Object *newtabButton = elm_button_add(obj);
192             elm_object_style_set(newtabButton, "tab_button");
193             evas_object_smart_callback_add(newtabButton, "clicked", tizen_browser::base_ui::TabUI::_newtab_clicked, data);
194             return newtabButton;
195         }
196         if (!strncmp(part_name2, part, part_name2_len)) {
197             Evas_Object *newincognitotabButton = elm_button_add(obj);
198             elm_object_style_set(newincognitotabButton, "tab_button");
199             evas_object_smart_callback_add(newincognitotabButton, "clicked", tizen_browser::base_ui::TabUI::_newincognitotab_clicked, data);
200             return newincognitotabButton;
201         }
202         if (!strncmp(part_name3, part, part_name3_len)) {
203             Evas_Object *closetabsButton = elm_button_add(obj);
204             elm_object_style_set(closetabsButton, "tab_button");
205             evas_object_smart_callback_add(closetabsButton, "clicked", tizen_browser::base_ui::TabUI::_closetabs_clicked, data);
206             return closetabsButton;
207         }
208         if (!strncmp(part_name4, part, part_name4_len)) {
209             Evas_Object *close_click = elm_button_add(obj);
210             elm_object_style_set(close_click, "tab_button");
211             evas_object_smart_callback_add(close_click, "clicked", TabUI::close_clicked_cb, data);
212             return close_click;
213         }
214     }
215     return nullptr;
216 }
217
218 void TabUI::close_clicked_cb(void* data, Evas_Object*, void*)
219 {
220     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
221     if (data) {
222         ItemData * id = static_cast<ItemData*>(data);
223         id->tabUI->closeTabUIClicked(std::string());
224         id->tabUI->clearItems();
225     }
226 }
227
228 void TabUI::hide()
229 {
230     evas_object_hide(elm_layout_content_get(m_tab_layout, "action_bar_genlist"));
231     evas_object_hide(elm_layout_content_get(m_tab_layout, "top_bar_genlist"));
232     evas_object_hide(elm_layout_content_get(m_tab_layout, "tab_gengird"));
233     evas_object_hide(m_tab_layout);
234 }
235
236 void TabUI::showTopButtons()
237 {
238     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
239     elm_theme_extension_add(nullptr, m_edjFilePath.c_str());
240     m_genListTop = elm_genlist_add(m_tab_layout);
241     elm_object_part_content_set(m_tab_layout, "top_bar_genlist", m_genListTop);
242     elm_genlist_homogeneous_set(m_genListTop, EINA_FALSE);
243     elm_genlist_multi_select_set(m_genListTop, EINA_FALSE);
244     elm_genlist_select_mode_set(m_genListTop, ELM_OBJECT_SELECT_MODE_ALWAYS);
245     elm_genlist_mode_set(m_genListTop, ELM_LIST_LIMIT);
246     elm_genlist_decorate_mode_set(m_genListTop, EINA_TRUE);
247     evas_object_size_hint_weight_set(m_genListTop, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
248
249 //  evas_object_smart_callback_add(m_genList, "item,focused", focusItem, this);
250 //  evas_object_smart_callback_add(m_genList, "item,unfocused", unFocusItem, nullptr);
251
252     m_itemClassTop = elm_genlist_item_class_new();
253     m_itemClassTop->item_style = "top_buttons";
254     m_itemClassTop->func.text_get = nullptr;
255     m_itemClassTop->func.content_get = &listTopButtonItemsContentGet;
256     m_itemClassTop->func.state_get = nullptr;
257     m_itemClassTop->func.del = nullptr;
258
259     ItemData *id = new ItemData;
260     id->tabUI = this;
261     Elm_Object_Item *elmItem = elm_genlist_item_append(m_genListTop,          //genlist
262                                                        m_itemClassTop,        //item Class
263                                                        id,
264                                                        nullptr,               //parent item
265                                                        ELM_GENLIST_ITEM_NONE, //item type
266                                                        nullptr,
267                                                        nullptr                //data passed to above function
268                                                       );
269     id->e_item = elmItem;
270     ItemData *id2 = new ItemData;
271     id2->tabUI = this;
272     Elm_Object_Item *elmItem2 = elm_genlist_item_append(m_genListTop,          //genlist
273                                                         m_itemClassTop,        //item Class
274                                                         id2,
275                                                         nullptr,               //parent item
276                                                         ELM_GENLIST_ITEM_NONE, //item type
277                                                         nullptr,
278                                                         nullptr                //data passed to above function
279                                                        );
280     id2->e_item = elmItem2;
281
282     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
283 }
284
285 Evas_Object* TabUI::listTopButtonItemsContentGet(void* data, Evas_Object* obj , const char* part)
286 {
287     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
288     if (data && obj && part) {
289         const char *part_name1 = "openedtabs_button";
290         static const int part_name1_len = strlen(part_name1);
291         const char *part_name2 = "onotherdevices_button";
292         static const int part_name2_len = strlen(part_name2);
293
294         if (!strncmp(part_name1, part, part_name1_len)) {
295             Evas_Object *openedtabsButton = elm_button_add(obj);
296             elm_object_style_set(openedtabsButton, "tab_button");
297             evas_object_smart_callback_add(openedtabsButton, "clicked", tizen_browser::base_ui::TabUI::_openedtabs_clicked, data);
298             return openedtabsButton;
299         }
300         if (!strncmp(part_name2, part, part_name2_len)) {
301             Evas_Object *onotherdevicesButton = elm_button_add(obj);
302             elm_object_style_set(onotherdevicesButton, "tab_button");
303             evas_object_smart_callback_add(onotherdevicesButton, "clicked", tizen_browser::base_ui::TabUI::_onotherdevices_clicked, data);
304             return onotherdevicesButton;
305         }
306     }
307     return nullptr;
308 }
309
310 void TabUI::_newtab_clicked(void * data, Evas_Object*, void*)
311 {
312     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
313     if (data) {
314         ItemData* itemData = static_cast<ItemData*>(data);
315         itemData->tabUI->clearItems();
316         itemData->tabUI->newTabClicked(std::string());
317     }
318
319 }
320 void TabUI::_openedtabs_clicked(void*, Evas_Object*, void*)
321 {
322         BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
323 }
324
325 void TabUI::_onotherdevices_clicked(void*, Evas_Object*, void*)
326 {
327         BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
328 }
329
330 void TabUI::_newincognitotab_clicked(void* data, Evas_Object*, void*)
331 {
332     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
333     if (data) {
334         ItemData* itemData = static_cast<ItemData*>(data);
335         itemData->tabUI->clearItems();
336         itemData->tabUI->newIncognitoTabClicked(std::string());
337     }
338 }
339
340 void TabUI::_closetabs_clicked(void* data, Evas_Object*, void*)
341 {
342     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
343     if (data) {
344         ItemData* itemData = static_cast<ItemData*>(data);
345         itemData->tabUI->closeTabsClicked(std::string());
346     }
347 }
348
349 void TabUI::addTabItem(std::shared_ptr<tizen_browser::basic_webengine::TabContent> hi)
350 {
351     BROWSER_LOGD("%s:%d %s", __FILE__, __LINE__, __func__);
352     if (m_map_tab_views.size() >= 10)
353         return;
354     TabItemData *itemData = new TabItemData();
355     itemData->item = hi;
356     itemData->tabUI = std::shared_ptr<tizen_browser::base_ui::TabUI>(this);
357     Elm_Object_Item* tabView = elm_gengrid_item_append(m_gengrid, m_item_class, itemData, nullptr, this);
358     m_map_tab_views.insert(std::pair<std::string,Elm_Object_Item*>(hi->getTitle(),tabView));
359
360     // unselect by default
361     elm_gengrid_item_selected_set(tabView, EINA_FALSE);
362     setEmptyGengrid(false);
363 }
364
365 void TabUI::addTabItems(std::vector<std::shared_ptr<tizen_browser::basic_webengine::TabContent>>items)
366 {
367     BROWSER_LOGD("%s:%d %s", __FILE__, __LINE__, __func__);
368     //limiting number of added items to 10
369     auto eit = std::min(items.end(), items.begin() + 10);
370     for (auto it = items.begin(); it != eit; ++it) {
371         addTabItem(*it);
372     }
373 }
374
375 char* TabUI::_grid_text_get(void *data, Evas_Object*, const char *part)
376 {
377     BROWSER_LOGD("%s:%d %s", __FILE__, __LINE__, __func__);
378     if (data && part) {
379         TabItemData *itemData = static_cast<TabItemData*>(data);
380         const char *part_name1 = "tab_title";
381         static const int part_name1_len = strlen(part_name1);
382         const char *part_name2 = "tab_url";
383         static const int part_name2_len = strlen(part_name2);
384
385         if (!strncmp(part_name1, part, part_name1_len)) {
386             return strdup(itemData->item->getTitle().c_str());
387         }
388         if (!strncmp(part_name2, part, part_name2_len)) {
389             //return strdup(itemData->item->getUrl().c_str());
390             return strdup("");
391         }
392     }
393     return strdup("");
394 }
395
396 Evas_Object * TabUI::_tab_grid_content_get(void *data, Evas_Object *obj, const char *part)
397 {
398     BROWSER_LOGD("%s:%d %s part=%s", __FILE__, __LINE__, __func__, part);
399     if (data && obj && part) {
400         TabItemData *itemData = static_cast<TabItemData*>(data);
401         const char *part_name1 = "tab_thumbnail";
402         static const int part_name1_len = strlen(part_name1);
403         const char *part_name2 = "tab_thumbButton";
404         static const int part_name2_len = strlen(part_name2);
405
406         if (!strncmp(part_name2, part, part_name2_len)) {
407             Evas_Object *thumbButton = elm_button_add(obj);
408             elm_object_style_set(thumbButton, "tab_thumbButton");
409             evas_object_smart_callback_add(thumbButton, "clicked", tizen_browser::base_ui::TabUI::_thumbSelected, data);
410             return thumbButton;
411         }
412         if (!strncmp(part_name1, part, part_name1_len)) {
413             if (itemData->item->getThumbnail()) {
414                 return tizen_browser::tools::EflTools::getEvasImage(itemData->item->getThumbnail(), itemData->tabUI->m_parent);
415             }
416         }
417     }
418     return nullptr;
419 }
420
421 void TabUI::_itemSelected(void*, Evas_Object*, void*)
422 {
423     BROWSER_LOGD("%s:%d %s", __FILE__, __LINE__, __func__);
424 //  self->historyClicked(itemData->item);
425 }
426
427 void TabUI::_thumbSelected(void *data, Evas_Object*, void*)
428 {
429     BROWSER_LOGD("%s:%d %s", __FILE__, __LINE__, __func__);
430     if (data) {
431         TabItemData *itemData = static_cast<TabItemData*>(data);
432         itemData->tabUI->clearItems();
433         itemData->tabUI->tabClicked(itemData->item->getId());
434     }
435 }
436
437 void TabUI::clearItems()
438 {
439     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
440     hide();
441     elm_gengrid_clear(m_gengrid);
442     elm_genlist_clear(m_genListActionBar);
443     elm_genlist_clear(m_genListTop);
444     m_map_tab_views.clear();
445 }
446
447 Evas_Object* TabUI::createNoHistoryLabel()
448 {
449     Evas_Object *label = elm_label_add(m_parent);
450     elm_object_text_set(label, "No favorite websites.");
451     evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
452     evas_object_size_hint_align_set(label, EVAS_HINT_FILL, EVAS_HINT_FILL);
453     return label;
454 }
455
456 void TabUI::setEmptyGengrid(bool setEmpty)
457 {
458     if (setEmpty) {
459         elm_object_part_content_set(m_gengrid, "elm.swallow.empty", createNoHistoryLabel());
460     } else {
461         elm_object_part_content_set(m_gengrid, "elm.swallow.empty", nullptr);
462     }
463 }
464
465 void TabUI::focusItem(void*, Evas_Object*, void* event_info)
466 {
467     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
468     if (event_info) {
469         Elm_Object_Item *item = static_cast<Elm_Object_Item*>(event_info);
470         elm_object_item_signal_emit( item, "mouse,in", "over2");
471
472         // selected manually
473         elm_gengrid_item_selected_set(item, EINA_TRUE);
474     }
475 }
476
477 void TabUI::unFocusItem(void*, Evas_Object*, void* event_info)
478 {
479     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
480     if (event_info) {
481         Elm_Object_Item *item = static_cast<Elm_Object_Item*>(event_info);
482         elm_object_item_signal_emit( item, "mouse,out", "over2");
483
484         // unselected manually
485         elm_gengrid_item_selected_set(item, EINA_FALSE);
486     }
487 }
488
489 }
490 }