Apply IActivatedListener for gengrid / genlist.
[profile/tv/apps/native/musicplayer.git] / src / views / album-layout.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
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 <Eina.h>
19 #include <utilX.h>
20 #include <AppCommon.h>
21 #include <InputHandler.h>
22 #include <SortMgr.h>
23 #include <Sort.h>
24 #include "dbg.h"
25 #include "i18n.h"
26 #include "define.h"
27 #include "album_info.h"
28 #include "song_info.h"
29 #include "music-controller.h"
30 #include "LayoutMgr.h"
31 #include "common.h"
32 #include "common-ui.h"
33 #include "BaseView.h"
34 #include "BaseLayout.h"
35 #include "ExtBaseLayout.h"
36 #include "ViewMgr.h"
37 #include "album-layout.h"
38 #include "album-songs-layout.h"
39 #include "base-view.h"
40
41 #define GENGRID_ITEM_SIZE_W (263+20)
42 #define GENGRID_ITEM_SIZE_H (359+20)
43
44
45 enum EObjectType {
46         ALBUM_LAYOUT,
47         ALBUM_GENGRID,
48 };
49
50 struct SAlbumItemInfo {
51         CAlbumInfo *alinfo;
52         Elm_Object_Item *item;
53 };
54
55 struct SCallback {
56         void(*cbHandleEmptyStatus)(void *cookie, bool emptyStatus);
57         void *cookie;
58 };
59
60 struct SAlbumLayout {
61         Evas_Object *win;
62         Evas_Object *base;
63         Evas_Object *grid;
64         Elm_Object_Item *focused_item;
65         Eina_List *alblist;
66         Eina_List *it_infolist;
67         Elm_Gengrid_Item_Class *item_class;
68         CMusicController *mhandle;
69         CLayoutMgr *lmgr;
70         CViewMgr *vmgr;
71         SContentInfo *ctxtinfo;
72         char *album_id;
73         CAlbumSongsLayout *layoutAlbumSongs;
74         SCallback callback;
75         CAlbumLayout* parent;
76
77         SAlbumLayout() {
78                 memset(this, 0, sizeof(SAlbumLayout));
79         }
80         
81         ~SAlbumLayout() {
82         }
83 };
84
85
86 char *CAlbumLayout::sm_CbGetGridItemText(void *data, Evas_Object *obj, const char *part)
87 {
88         SAlbumItemInfo *itinfo = (SAlbumItemInfo *)data;
89         CAlbumInfo *alinfo = NULL;
90         char *txt = NULL;
91
92         if (!itinfo || !obj)
93                 return NULL;
94
95         alinfo = itinfo->alinfo;
96         txt = NULL;
97
98         if (!strcmp(part, "elm.text"))
99                 txt = alinfo->Name();
100         else if (!strcmp(part, "elm.text1"))
101                 txt = alinfo->Artist();
102
103         if (txt)
104                 return strdup(txt);
105
106         return NULL;
107 }
108
109
110 Evas_Object *CAlbumLayout::sm_CbGetGridItemContent(void *data, Evas_Object *obj, const char *part)
111 {
112         SAlbumItemInfo *itinfo = (SAlbumItemInfo *)data;
113         CAlbumInfo *alinfo = NULL;
114         char *path = NULL;
115         Evas_Object *img = NULL;
116         char buf[MAX_LENGTH];
117
118         if (!itinfo || !obj)
119                 return NULL;
120
121         alinfo = itinfo->alinfo;
122
123         if (!strcmp(part, "elm.swallow.icon")) {
124                 img = elm_image_add(obj);
125                 if (!img)
126                         return NULL;
127
128                 path = alinfo->ThumbnailPath();
129                 if (!path) {
130                         snprintf(buf, sizeof(buf), "%s/%s", IMAGEDIR,
131                                 MUSIC_IMAGE_DEFAULT_THUMB_126);
132                         elm_image_file_set(img, buf, "NULL");
133                         elm_image_no_scale_set(img, EINA_TRUE);
134                 }
135                 else {
136                         elm_image_file_set(img, path, "NULL");
137                         elm_image_aspect_fixed_set(img, EINA_FALSE);
138                 }
139                 return img;
140         }
141
142         return NULL;
143 }
144
145
146 void CAlbumLayout::sm_CbRemoveGridItem(void *data, Evas_Object *obj)
147 {
148         free(data);
149 }
150
151
152 void CAlbumLayout::sm_CbCtxtUpdate(void *dt, enum EActionType type, int lid)
153 {
154         CAlbumLayout *root = (CAlbumLayout*)dt;
155
156         if (root)
157                 root->m_OnCtxtUpdate(type, lid);
158 }
159
160
161 void CAlbumLayout::m_OnCtxtUpdate(EActionType type, int lid)
162 {
163         Eina_List *list = NULL;
164         CSongInfo *sinfo = NULL;
165         EAddType mode;
166
167         if (!m->ctxtinfo || !m->ctxtinfo->context)
168                 return;
169
170         if (type == ACTION_TYPE_ADDNEXT)
171                 mode = ADD_TYPE_NEXT;
172         else
173                 mode = ADD_TYPE_END;
174
175         m->mhandle->MediaGetList(LIST_TYPE_ALBUM_SONG,
176                 m->ctxtinfo->context, &list);
177         if (type ==  ACTION_TYPE_ADDTO) {
178                 if (!m->mhandle->MediaAddsongsPlaylist(lid, list))
179                         _ERR(" Adding songs to playlist failed ");
180                 else
181                         _create_message_box(m->base, MUSIC_TEXT_ADDTO_MSG);
182
183                 return;
184         }
185
186         m->mhandle->UpdatePlaylist(list, mode);
187         sinfo = (CSongInfo *)eina_list_data_get(list);
188         eina_list_free(list);
189
190         if (type == ACTION_TYPE_PLAY) {
191                 m->mhandle->Stop();
192                 m->mhandle->SetCurrentSong(sinfo->Id());
193         }
194
195         _update_playback_view((EAddType)type, m->parent->Layout(), m->focused_item);
196 }
197
198
199 void CAlbumLayout::sm_CbCtxtClose(void *dt)
200 {
201         CAlbumLayout *root = (CAlbumLayout*)dt;
202
203         if (root)
204                 root->m_OnCtxtClose();
205 }
206
207
208 void CAlbumLayout::m_OnCtxtClose(void)
209 {
210         m->vmgr->PopView();
211         m->vmgr->PushView(MUSIC_BASE_VIEW, NULL);
212         elm_object_item_focus_set(m->focused_item, EINA_TRUE);
213 }
214
215
216 void CAlbumLayout::sm_CbItemSelect(void *data, Elm_Object_Item *it, const char *emission, const char *source)
217 {
218         CAlbumLayout *root = (CAlbumLayout*)data;
219
220         if (root)
221                 root->m_OnItemSelect(it, emission, source);
222 }
223
224
225 void CAlbumLayout::m_OnItemSelect(Elm_Object_Item *it, const char *emission, const char *source)
226 {
227         SAlbumItemInfo *itinfo;
228
229         itinfo = m_FindItemInfo(m->it_infolist, it);
230         if (!itinfo) {
231                 _ERR(" no item info found ");
232                 return;
233         }
234
235         m->mhandle->SetCurrentAlbum(itinfo->alinfo);
236
237         m_ShowAlbumSongs();
238 }
239
240
241 SAlbumItemInfo *CAlbumLayout::m_FindItemInfo(Eina_List *list, Elm_Object_Item *item)
242 {
243         Eina_List *l = NULL;
244         SAlbumItemInfo *itinfo = NULL;
245         void *obj = NULL;
246
247         if (!list || !item)
248                 return NULL;
249
250         EINA_LIST_FOREACH(list, l, obj) {
251                 itinfo = (SAlbumItemInfo *)obj;
252                 if (itinfo->item == item)
253                         return itinfo;
254         }
255
256         return NULL;
257 }
258
259
260 SAlbumItemInfo *CAlbumLayout::m_FindItemInfoById(Eina_List *list, int alid)
261 {
262         Eina_List *l = NULL;
263         SAlbumItemInfo *itinfo = NULL;
264         void *obj = NULL;
265         int id;
266
267         if (!list)
268                 return NULL;
269
270         EINA_LIST_FOREACH(list, l, obj) {
271                 itinfo = (SAlbumItemInfo *)obj;
272                 if (!itinfo->alinfo)
273                         continue;
274                 id = itinfo->alinfo->AlbumId();
275                 if (alid == id) {
276                         return itinfo;
277                 }
278         }
279
280         return NULL;
281 }
282
283
284 void CAlbumLayout::m_ShowAlbumSongs(void)
285 {
286         elm_object_part_content_unset(m->base, MUSIC_PART_CONTENT);
287
288         bool emptyStatus = m->layoutAlbumSongs->EmptyStatus();
289
290         if (emptyStatus == false) {
291                 elm_object_part_content_set(m->base, MUSIC_PART_CONTENT, m->layoutAlbumSongs->Layout());
292                 m->lmgr->Show(MUSIC_ALBUM_SONGS_LAYOUT);
293         }
294
295         if (m->callback.cbHandleEmptyStatus != NULL) {
296                 m->callback.cbHandleEmptyStatus(m->callback.cookie, emptyStatus);
297         }
298 }
299
300
301 void CAlbumLayout::m_RemoveAlbumList(Eina_List *list)
302 {
303         eina_list_free(list);
304 }
305
306
307 void CAlbumLayout::m_CreateAlbumGrid(void)
308 {
309         Evas_Object *grid;
310         Elm_Gengrid_Item_Class *grid_item;
311
312         grid = elm_gengrid_add(Layout());
313         if (!grid)
314                 return;
315
316         evas_object_size_hint_weight_set(grid,
317                 EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
318         elm_gengrid_align_set(grid, 0, 0);
319         elm_object_part_content_set(Layout(), MUSIC_PART_ALBUM_GRID, grid);
320         Connect(grid, ALBUM_GENGRID, TYPE_MOUSE_MOVE | TYPE_KEY_DOWN | TYPE_REALIZED | TYPE_UNREALIZED | TYPE_ACTIVATED);
321         elm_gengrid_item_size_set(grid,
322                 elm_config_scale_get() * GENGRID_ITEM_SIZE_W,
323                 elm_config_scale_get() * GENGRID_ITEM_SIZE_H);
324
325         m->grid = grid;
326
327         grid_item = elm_gengrid_item_class_new();
328         if (!grid_item) {
329                 evas_object_del(grid);
330                 _ERR(" elm_genlist_item_class_new failed ");
331                 return;
332         }
333
334         grid_item->item_style = MUSIC_STYLE_ALBUM_GRID;
335         grid_item->func.text_get = sm_CbGetGridItemText;
336         grid_item->func.content_get = sm_CbGetGridItemContent;
337         grid_item->func.state_get = NULL;
338         grid_item->func.del = sm_CbRemoveGridItem;
339         m->item_class = grid_item;
340
341         m_UpdateAlbumGrid(false);
342 }
343
344
345 void CAlbumLayout::m_EmptyAlbumGrid(bool sort_flag)
346 {
347         if (m->grid)
348                 elm_gengrid_clear(m->grid);
349
350         if (!sort_flag) {
351                 m_RemoveAlbumList(m->alblist);
352                 m->alblist = NULL;
353         }
354
355         eina_list_free(m->it_infolist);
356         m->it_infolist = NULL;
357 }
358
359
360 void CAlbumLayout::m_SortAlbumGrid(void)
361 {
362         int sortType;
363         const char *sortFuncId[] = {
364                 SORT_BY_NAME_AZ,
365                 SORT_BY_NAME_ZA,
366         };
367
368         sortType = m->mhandle->SortType();
369
370         m->alblist = CSort::Sort(m->alblist, sortFuncId[sortType]);
371 }
372
373
374 void CAlbumLayout::m_UpdateAlbumGrid(bool sort_flag)
375 {
376         bool r;
377         CAlbumInfo *alinfo;
378         void *obj;
379         Eina_List *l;
380         SAlbumItemInfo *itinfo;
381         Elm_Object_Item *item;
382
383         /* Remove existing albumgrid and prepare afresh */
384         m_EmptyAlbumGrid(sort_flag);
385
386         if (!sort_flag) {
387                 r = m->mhandle->MediaGetList(LIST_TYPE_ALBUM, NULL, &(m->alblist));
388                 if (r == false ||
389                         eina_list_count(m->alblist) == 0) {
390                         _ERR(" Fetching album list from media failed ");
391                         m->parent->SetEmptyStatus(true);
392                         return;
393                 }
394         }
395
396         m_SortAlbumGrid();
397
398         EINA_LIST_FOREACH(m->alblist, l, obj) {
399                 alinfo = (CAlbumInfo *)obj;
400                 itinfo = (SAlbumItemInfo *)calloc(1, sizeof(*itinfo));
401                 if (!itinfo)
402                         return;
403
404                 itinfo->alinfo = alinfo;
405                 item = elm_gengrid_item_append(m->grid, m->item_class, itinfo, NULL, NULL);
406                 itinfo->item = item;
407                 m->it_infolist = eina_list_append(m->it_infolist, itinfo);
408         }
409 }
410
411
412 bool CAlbumLayout::Create(CLayoutMgr *mgr, const char *albumId)
413 {
414         ASSERT(!m);
415
416         Evas_Object *base = NULL;
417         Evas_Object *win = NULL;
418         Evas_Object *layout = NULL;
419         CMusicController *mhandle = NULL;
420         CViewMgr *vmgr = NULL;
421
422         m = new SAlbumLayout;
423         if (!m) {
424                 _ERR(" albumlayout data allocation failed ");
425                 return false;
426         }
427
428         vmgr = CViewMgr::GetInstance();
429         if (!vmgr) {
430                 _ERR(" get viewmgr failed ");
431                 delete m;
432                 m = NULL;
433                 return false;
434         }
435
436         base = mgr->Base();
437         if (!base) {
438                 _ERR(" get base failed ");
439                 delete m;
440                 m = NULL;
441                 return false;
442         }
443
444         win = vmgr->Window();
445         if (!win) {
446                 _ERR(" vimewmgr get win failed ");
447                 delete m;
448                 m = NULL;
449                 return false;
450         }
451
452         mhandle = CMusicController::GetInstance();
453         if (!mhandle) {
454                 _ERR(" music controller get music instance failed ");
455                 delete m;
456                 m = NULL;
457                 return false;
458         }
459
460         layout = _add_base(base, MUSIC_ALBUM_LAYOUT);
461         if (!layout) {
462                 _ERR(" get layout failed ");
463                 delete m;
464                 m = NULL;
465                 return false;
466         }
467
468         bool r = CExtBaseLayout::Create(layout);
469         if (!r) {
470                 _ERR(" CBaseLayout creation failed ");
471                 evas_object_del(layout);
472                 delete m;
473                 m = NULL;
474                 return false;
475         }
476
477         if (albumId) {
478                 m->album_id = new char[strlen(albumId) + 1];
479                 strcpy(m->album_id, albumId);
480         }
481         else {
482                 m->album_id = NULL;
483         }
484
485         m->win = win;
486         m->base = base;
487         m->vmgr = vmgr;
488         m->mhandle = mhandle;
489         m->lmgr = mgr;
490         m->callback.cbHandleEmptyStatus = NULL;
491         m->callback.cookie = NULL;
492         m->parent = this;
493
494         m->layoutAlbumSongs = new CAlbumSongsLayout(MUSIC_ALBUM_SONGS_LAYOUT);
495         m->layoutAlbumSongs->Create(m->lmgr);
496         m->lmgr->AddLayout(m->layoutAlbumSongs);
497
498         m_CreateAlbumGrid();
499
500         Connect(layout, ALBUM_LAYOUT, TYPE_KEY_DOWN);
501
502         SParcel parcel;
503         parcel.ctxtInfo = NULL;
504         parcel.updateType = E_LAYOUT_UPDATE;
505         parcel.layoutId = MUSIC_ALBUM_LAYOUT;
506         parcel.keyEvent = NULL;
507         m->vmgr->UpdateView((const char *)MUSIC_BASE_VIEW, &parcel);
508
509         return true;
510 }
511
512 void CAlbumLayout::Destroy(void)
513 {
514         ASSERT(m);
515
516         m->lmgr->RemoveLayout(m->layoutAlbumSongs);
517         m->layoutAlbumSongs->Destroy();
518         delete m->layoutAlbumSongs;
519
520         m_EmptyAlbumGrid(false);
521         CExtBaseLayout::Destroy();
522         evas_object_del(Layout());
523
524         free(m->ctxtinfo);
525         delete[] m->album_id;
526         delete m;
527         m = NULL;
528 }
529
530
531 void CAlbumLayout::t_OnShow(void)
532 {
533         ASSERT(m);
534
535         SAlbumItemInfo *itinfo = NULL;
536
537         m_UpdateAlbumGrid(false);
538
539         SParcel parcel;
540         parcel.ctxtInfo = NULL;
541         parcel.updateType = E_LAYOUT_UPDATE;
542         parcel.layoutId = MUSIC_ALBUM_LAYOUT;
543         parcel.keyEvent = NULL;
544         m->vmgr->UpdateView((const char *)MUSIC_BASE_VIEW, &parcel);
545
546         evas_object_show(Layout());
547
548         if (m->album_id) {
549                 itinfo = m_FindItemInfoById(m->it_infolist,
550                         atoi(m->album_id));
551                 if (itinfo) {
552                         m->mhandle->SetCurrentAlbum(itinfo->alinfo);
553                         m_ShowAlbumSongs();
554                         return;
555                 }
556                 delete[] m->album_id;
557                 m->album_id = NULL;
558         }
559 }
560
561
562 void CAlbumLayout::Update(bool focusFlag)
563 {
564         ASSERT(m);
565
566         CAlbumInfo *alinfo = NULL;
567         SAlbumItemInfo *itinfo = NULL;
568         int id;
569
570         if (!focusFlag) {
571                 m_UpdateAlbumGrid(true);
572                 return;
573         }
574
575         alinfo = m->mhandle->CurrentAlbum();
576         if (alinfo) {
577                 id = alinfo->AlbumId();
578                 itinfo = m_FindItemInfoById(m->it_infolist, id);
579                 if (itinfo) {
580                         m->mhandle->SetCurrentAlbum(NULL);
581                         elm_gengrid_item_show(itinfo->item,
582                                 ELM_GENGRID_ITEM_SCROLLTO_IN);
583                         elm_object_item_focus_set(itinfo->item, EINA_TRUE);
584                         return;
585                 }
586         }
587
588         elm_object_focus_set(m->grid, EINA_TRUE);
589 }
590
591
592 void CAlbumLayout::SetEmptyStatusHandleCallback(void(*handleEmptyStatusCb)(void *cookie, bool emptyStatus), void *cookie)
593 {
594         ASSERT(m);
595
596         m->callback.cbHandleEmptyStatus = handleEmptyStatusCb;
597         m->callback.cookie = cookie;
598 }
599
600
601 void CAlbumLayout::OnKeyDown(int id, Evas *e, Evas_Object *obj, Evas_Event_Key_Down *ev)
602 {
603         switch (id) {
604         case ALBUM_LAYOUT:
605                 if (!strcmp(ev->keyname, KEY_BACK)) {
606                         SParcel parcel;
607                         parcel.ctxtInfo = NULL;
608                         parcel.updateType = E_FOCUS_UPDATE;
609                         parcel.layoutId = NULL;
610                         parcel.keyEvent = NULL;
611                         m->vmgr->UpdateView((const char *)MUSIC_BASE_VIEW, &parcel);
612                 }
613                 break;
614
615         case ALBUM_GENGRID:
616                 {
617                         Elm_Object_Item *it = NULL;
618                         SContentInfo *ctxtinfo = NULL;
619                         SAlbumItemInfo *itinfo = NULL;
620
621                         if (strcmp(ev->keyname, KEY_MENU))
622                                 return;
623
624                         it = elm_object_focused_item_get(obj);
625                         if (!it) {
626                                 _ERR(" unable to get focused item ");
627                                 return;
628                         }
629                         m->focused_item = it;
630
631                         if (m->ctxtinfo) {
632                                 free(m->ctxtinfo);
633                                 m->ctxtinfo = NULL;
634                         }
635
636                         ctxtinfo = (SContentInfo *)calloc(1, sizeof(*ctxtinfo));
637                         if (!ctxtinfo)
638                                 return;
639
640                         itinfo = m_FindItemInfo(m->it_infolist, it);
641                         if (!itinfo) {
642                                 free(ctxtinfo);
643                                 return;
644                         }
645
646                         ctxtinfo->type = CONTEXT_TYPE_ALBUM;
647                         ctxtinfo->context = itinfo->alinfo;
648                         ctxtinfo->cbdata = this;
649                         ctxtinfo->update = sm_CbCtxtUpdate;
650                         ctxtinfo->close = sm_CbCtxtClose;
651
652                         m->ctxtinfo = ctxtinfo;
653
654                         SParcel parcel;
655                         parcel.ctxtInfo = ctxtinfo;
656                         if (!m->vmgr->PushView(MUSIC_CONTEXT_VIEW, &parcel))
657                                 _ERR("viewmgr push view MUSIC_CONTEXT_VIEW failed");
658                 }
659                 break;
660
661         default:
662                 break;
663         }
664 }
665
666
667 void CAlbumLayout::OnMouseMove(int id, Evas *e, Evas_Object *obj, Evas_Event_Mouse_Move *ev)
668 {
669         Elm_Object_Item *item;
670
671         item = elm_gengrid_at_xy_item_get(obj, ev->cur.canvas.x,
672                 ev->cur.canvas.y, NULL, NULL);
673         if (!item)
674                 return;
675
676         if (!elm_object_item_focus_get(item))
677                 elm_object_item_focus_set(item, EINA_TRUE);
678 }
679
680
681 void CAlbumLayout::OnRealized(int id, Evas_Object *obj, Elm_Object_Item *item)
682 {
683         switch (id) {
684         case ALBUM_GENGRID:
685                 {
686                         elm_object_item_signal_callback_add(item,
687                         MUSIC_SIGNAL_BTN_CLICKED, MUSIC_BASE_VIEW,
688                         sm_CbItemSelect, this);
689                 }
690                 break;
691
692         default:
693                 break;
694         }
695 }
696
697
698 void CAlbumLayout::OnUnrealized(int id, Evas_Object *obj, Elm_Object_Item *item)
699 {
700         switch (id) {
701         case ALBUM_GENGRID:
702                 {
703                         elm_object_item_signal_callback_del(item,
704                         MUSIC_SIGNAL_BTN_CLICKED, MUSIC_BASE_VIEW,
705                         sm_CbItemSelect);
706                 }
707                 break;
708
709         default:
710                 break;
711         }
712 }
713
714
715 void CAlbumLayout::OnActivated(int id, Evas_Object *obj, Elm_Object_Item *item)
716 {
717         switch (id) {
718         case ALBUM_GENGRID:
719                 m_OnItemSelect(item, NULL, NULL);
720                 break;
721
722         default:
723                 break;
724         }
725 }