apply FSL(Flora Software License)
[profile/ivi/download-provider.git] / src / download-provider-viewItem.cpp
1 /*
2  * Copyright 2012  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.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.tizenopensource.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 /**
18  * @file        download-provider-viewItem.cpp
19  * @author      Jungki Kwak (jungki.kwak@samsung.com)
20  * @brief       item data class for download view
21  */
22 #include "download-provider-viewItem.h"
23 #include "download-provider-items.h"
24 #include "download-provider-view.h"
25
26 ViewItem::ViewItem(Item *item)
27         : m_item(item)
28         , m_glItem(NULL)
29         , m_progressBar(NULL)
30         , m_checkedBtn(NULL)
31         , m_checked(EINA_FALSE)
32         , m_isRetryCase(false)
33         , m_dateGroupType(DATETIME::DATE_TYPE_NONE)
34 {
35         // FIXME need to makes exchange subject?? not yet, but keep it in mind!
36         if (item) {
37                 m_aptr_observer = auto_ptr<Observer>(
38                         new Observer(updateCB, this, "viewItemObserver"));
39                 item->subscribe(m_aptr_observer.get());
40         }
41
42         dldGenlistStyle.item_style = "3text.3icon";
43         dldGenlistStyle.func.text_get = getGenlistLabelCB;
44         dldGenlistStyle.func.content_get = getGenlistIconCB;
45         dldGenlistStyle.func.state_get = NULL;
46         dldGenlistStyle.func.del = NULL;
47         dldGenlistStyle.decorate_all_item_style = "edit_default";
48
49         dldHistoryGenlistStyle.item_style = "3text.1icon.2";
50         dldHistoryGenlistStyle.func.text_get = getGenlistLabelCB;
51         dldHistoryGenlistStyle.func.content_get = getGenlistIconCB;
52         dldHistoryGenlistStyle.func.state_get = NULL;
53         dldHistoryGenlistStyle.func.del = NULL;
54         dldHistoryGenlistStyle.decorate_all_item_style = "edit_default";
55
56         dldGenlistSlideStyle.item_style = "3text.1icon.2";
57         dldGenlistSlideStyle.func.text_get = getGenlistLabelCB;
58         dldGenlistSlideStyle.func.content_get= getGenlistIconCB;
59         dldGenlistSlideStyle.func.state_get = NULL;
60         dldGenlistSlideStyle.func.del = NULL;
61         dldGenlistSlideStyle.decorate_all_item_style = "edit_default";
62
63 }
64
65 ViewItem::~ViewItem()
66 {
67         DP_LOGD_FUNC();
68 }
69
70 void ViewItem::create(Item *item)
71 {
72         ViewItem *newViewItem = new ViewItem(item);
73
74         DownloadView &view = DownloadView::getInstance();
75         view.attachViewItem(newViewItem);
76 }
77
78 void ViewItem::destroy()
79 {
80         DP_LOGD("ViewItem::destroy");
81         /* After item is destory,
82            view item also will be destroyed through event system */
83         if (m_item)
84                 m_item->destroy();
85 }
86
87 void ViewItem::updateCB(void *data)
88 {
89         if (data)
90                 static_cast<ViewItem*>(data)->updateFromItem();
91 }
92
93 void ViewItem::updateFromItem()
94 {
95         DownloadView &view = DownloadView::getInstance();
96         DP_LOGD("ViewItem::updateFromItem() ITEM::[%d]", state());
97         if (state() == ITEM::DESTROY) {
98                 int tempType = 0;
99                 DP_LOGD("ViewItem::updateFromItem() ITEM::DESTROY");
100                 if (m_item)
101                         m_item->deSubscribe(m_aptr_observer.get());
102                 m_aptr_observer->clear();
103                 elm_object_item_del(m_glItem);
104                 m_glItem = NULL;
105                 tempType = dateGroupType();
106                 view.detachViewItem(this);
107                 view.handleGenlistGroupItem(tempType);
108                 return;
109         }
110
111         if (state() == ITEM::WAITING_USER_RESPONSE) {
112                 string buf;
113                 buf.append("Name : ");
114                 buf.append(m_item->contentName());
115                 buf.append("<br>");
116                 buf.append("Size : ");
117                 buf.append(getHumanFriendlyBytesStr(fileSize(), false));
118                 buf.append("<br>");
119                 buf.append("Vendor : ");
120                 buf.append(m_item->vendorName());
121                 buf.append("<br>");
122                 if (m_item->isMidletInstalled()) {
123                         buf.append("<br>");
124                         buf.append(S_("IDS_COM_POP_ALREDY_EXISTS"));
125                         buf.append("<br>");
126                         buf.append("Want to update?");
127                 }
128                 view.showOMAPopup(buf, this);
129                 return;
130         }
131
132         if (state() == ITEM::DOWNLOADING) {
133                 if (fileSize() > 0 && m_progressBar) {
134                         double percentageProgress = 0.0;
135                         percentageProgress = (double)(receivedFileSize()) /
136                                 (double)(fileSize());
137                         DP_LOGD("progress value[%.2f]",percentageProgress);
138                         elm_progressbar_value_set(m_progressBar, percentageProgress);
139                 }
140                 elm_genlist_item_fields_update(m_glItem,"elm.text.2",
141                         ELM_GENLIST_ITEM_FIELD_TEXT);
142         } else if (m_isRetryCase && state() == ITEM::RECEIVING_DOWNLOAD_INFO) {
143                 elm_genlist_item_item_class_update(m_glItem, &dldGenlistStyle);
144         } else if (!isFinished()) {
145                 elm_genlist_item_update(m_glItem);
146         } else {/* finished state */
147                 if (state() == ITEM::FINISH_DOWNLOAD)
148                         elm_genlist_item_item_class_update(m_glItem, &dldHistoryGenlistStyle);
149                 else
150                         elm_genlist_item_item_class_update(m_glItem, &dldGenlistSlideStyle);
151                 if (view.isGenlistEditMode())
152                         elm_object_item_disabled_set(m_glItem, EINA_FALSE);
153         }
154 }
155
156 char *ViewItem::getGenlistLabelCB(void *data, Evas_Object *obj, const char *part)
157 {
158 //      DP_LOGD_FUNC();
159
160         if(!data || !obj || !part)
161                 return NULL;
162
163         ViewItem *item = static_cast<ViewItem *>(data);
164         return item->getGenlistLabel(obj, part);
165 }
166
167 char *ViewItem::getGenlistLabel(Evas_Object *obj,       const char *part)
168 {
169         DP_LOGD("ViewItem::getListLabel:part[%s]", part);
170
171         if (strncmp(part, "elm.text.1", strlen("elm.text.1")) == 0) {
172                 return strdup(getTitle());
173         } else if (strncmp(part, "elm.text.2", strlen("elm.text.2")) == 0) {
174                 return strdup(getMessage());
175         } else if (strncmp(part, "elm.text.3", strlen("elm.text.3")) == 0) {
176                 if (!isFinished()) {
177                         return NULL;
178                 } else {
179                         string outBuf;
180                         DateUtil &inst = DateUtil::getInstance();
181                         double udateTime = finishedTime() * 1000;
182                         if (dateGroupType() == DATETIME::DATE_TYPE_PREVIOUS 
183                                 || dateGroupType() == DATETIME::DATE_TYPE_LATER)
184                                 inst.getDateStr(LOCALE_STYLE::SHORT_DATE, udateTime, outBuf);
185                         else
186                                 inst.getDateStr(LOCALE_STYLE::TIME, udateTime, outBuf);
187                         return strdup(outBuf.c_str());
188                 }
189         } else {
190                 DP_LOGD("No Implementation");
191                 return NULL;
192         }
193 }
194
195 Evas_Object *ViewItem::getGenlistIconCB(void *data, Evas_Object *obj,
196         const char *part)
197 {
198 //      DP_LOGD_FUNC();
199         if(!data || !obj || !part) {
200                 DP_LOGE("parameter is NULL");
201                 return NULL;
202         }
203
204         ViewItem *item = static_cast<ViewItem *>(data);
205         return item->getGenlistIcon(obj, part);
206 }
207
208 Evas_Object *ViewItem::getGenlistIcon(Evas_Object *obj, const char *part)
209 {
210         //DP_LOGD("ViewItem::getGenlistIcon:part[%s]state[%s]", part, stateStr());
211
212         if (elm_genlist_decorate_mode_get(obj) && isFinished()) {
213                 if (strncmp(part,"elm.edit.icon.1", strlen("elm.edit.icon.1")) == 0) {
214                         Evas_Object *checkBtn = elm_check_add(obj);
215                         elm_check_state_pointer_set(checkBtn, &m_checked);
216                         evas_object_smart_callback_add(checkBtn, "changed", checkChangedCB,
217                                 this);
218                         m_checkedBtn = checkBtn;
219                         return checkBtn;
220                 } else if (strncmp(part,"elm.edit.icon.2", strlen("elm.edit.icon.2")) ==
221                         0) {
222                         return NULL;
223                 }
224
225         }
226         /* elm.icon.2 should be checked prior to elm.icon */
227         if (strncmp(part,"elm.icon.2", strlen("elm.icon.2")) == 0) {
228                 if (state() == ITEM::RECEIVING_DOWNLOAD_INFO || 
229                         state() == ITEM::PREPARE_TO_RETRY ||
230                         state() == ITEM::DOWNLOADING ||
231                         isPreparingDownload())
232                         return createCancelBtn(obj);
233                 else
234                         return NULL;
235         } else if (strncmp(part,"elm.icon.1", strlen("elm.icon.1")) == 0 ||
236                 strncmp(part, "elm.icon", strlen("elm.icon")) == 0) {
237 //      if (strncmp(part,"elm.icon.1", strlen("elm.icon.1")) == 0) {
238                 Evas_Object *icon = elm_icon_add(obj);
239                 elm_icon_file_set(icon, getIconPath(), NULL);
240                 evas_object_size_hint_aspect_set(icon, EVAS_ASPECT_CONTROL_VERTICAL,1,1);
241                 return icon;
242         } else if (strcmp(part,"elm.swallow.progress") == 0) {
243                 return createProgressBar(obj);
244         } else {
245                 DP_LOGE("Cannot enter here");
246                 return NULL;
247         }
248 }
249
250 void ViewItem::checkChangedCB(void *data, Evas_Object *obj,
251         void *event_info)
252 {
253         DownloadView &view = DownloadView::getInstance();
254         DP_LOGD_FUNC();
255         //ViewItem *item = static_cast<ViewItem *>(data);
256         //DP_LOGD("checked[%d] viewItem[%p]",(bool)(item->checkedValue()),item);
257         view.handleCheckedState();
258 }
259
260 void ViewItem::clickedDeleteButton()
261 {
262         DP_LOGD("ViewItem::clickedDeleteButton()");
263         m_item->deleteFromDB();
264         destroy();
265 }
266
267 void ViewItem::clickedCancelButton()
268 {
269         DP_LOG("ViewItem::clickedCancelButton()");
270         requestCancel();
271 }
272
273 void ViewItem::requestCancel()
274 {
275         if (m_item) {
276                 m_item->cancel();
277         }
278 }
279
280 void ViewItem::clickedRetryButton()
281 {
282         DP_LOG_FUNC();
283         retryViewItem();
284 }
285
286 void ViewItem::clickedGenlistItem()
287 {
288         DownloadView &view = DownloadView::getInstance();
289         DP_LOG_FUNC();
290         if (!m_item) {
291                 DP_LOGE("m_item is NULL");
292                 return;
293         }
294         if (view.isGenlistEditMode()) {
295                 m_checked = !m_checked;
296                 if (m_checkedBtn)
297                         elm_genlist_item_fields_update(genlistItem(),"elm.edit.icon.1",
298                                 ELM_GENLIST_ITEM_FIELD_CONTENT);
299                 else
300                         DP_LOGE("m_checkedBtn is NULL");
301                 view.handleCheckedState();
302         } else if (state() == ITEM::FINISH_DOWNLOAD) {
303                 bool ret = m_item->play();
304                 if (ret == false) {
305                         string desc = __("IDS_BR_POP_UNABLE_TO_OPEN_FILE");
306                         view.showErrPopup(desc);
307                 }
308         } else if (isFinishedWithErr()) {
309                 retryViewItem();
310         }
311         elm_genlist_item_selected_set(genlistItem(), EINA_FALSE);
312 }
313
314 Elm_Genlist_Item_Class *ViewItem::elmGenlistStyle()
315 {
316         /* Change the genlist style class in case of download history item */
317         if (state() == ITEM::FINISH_DOWNLOAD)
318                 return &dldHistoryGenlistStyle;
319         else if (isFinishedWithErr())
320                  return &dldGenlistSlideStyle;
321         else
322                 return &dldGenlistStyle;
323 }
324
325 const char *ViewItem::getMessage()
326 {
327         DP_LOGD("ViewItem state() ITEM::[%d]", state());
328         const char *buff = NULL;
329         switch(state()) {
330         case ITEM::IDLE:
331         case ITEM::REQUESTING:
332         case ITEM::PREPARE_TO_RETRY:
333         case ITEM::WAITING_USER_RESPONSE:
334         case ITEM::RECEIVING_DOWNLOAD_INFO:
335         /* Do not display string and show only the progress bar */
336 //              buff = __("Check for download");
337                 buff = "";
338                 break;
339         case ITEM::DOWNLOADING:
340                 buff = getHumanFriendlyBytesStr(receivedFileSize(), true);
341 //              DP_LOGD("%s", buff);
342                 break;
343         case ITEM::CANCEL:
344                 buff = S_("IDS_COM_POP_CANCELLED");
345                 break;
346         case ITEM::FAIL_TO_DOWNLOAD:
347                 buff = getErrMsg();
348                 break;
349         case ITEM::REGISTERING_TO_SYSTEM:
350                 buff = S_("IDS_COM_POP_INSTALLING_ING");
351                 break;
352         case ITEM::ACTIVATING:
353                 buff = S_("IDS_COM_POP_ACTIVATING");
354                 break;
355         case ITEM::NOTIFYING_TO_SERVER:
356                 buff =  __("IDS_BR_BODY_NOTIFYING_ING");
357                 break;
358         case ITEM::PROCESSING_DOMAIN:
359                 buff = S_("IDS_COM_POP_PROCESSING");
360                 break;
361         case ITEM::FINISH_PROCESSING_DOMAIN:
362                 buff = __("IDS_BR_BODY_PROCESSING_COMPLETED");
363                 break;
364         case ITEM::FINISH_DOWNLOAD:
365                 buff =  __("IDS_EMAIL_BODY_COMPLETE");
366                 break;
367         default:
368                 buff = "";
369                 break;
370         }
371         return buff;
372 }
373
374 const char *ViewItem::getHumanFriendlyBytesStr(unsigned long int bytes,
375         bool progressOption)
376 {
377         double doubleTypeBytes = 0.0;
378         const char *unitStr[4] = {"B", "KB", "MB", "GB"};
379         int unit = 0;
380         unsigned long int unitBytes = bytes;
381
382         /* using bit operation to avoid floating point arithmetic */
383         for (unit=0; (unitBytes > 1024 && unit < 4) ; unit++) {
384                 unitBytes = unitBytes >> 10;
385         }
386
387         unitBytes = 1 << (10*unit);
388         doubleTypeBytes = ((double)bytes / (double)(unitBytes));
389         // FIXME following code should be broken into another function, but leave it now to save function call time.s
390         char str[32] = {0};
391         if (progressOption && fileSize() != 0) {
392                 /* using fixed point arithmetic to avoid floating point arithmetic */
393                 const int fixed_point = 6;
394                 unsigned long long int receivedBytes = receivedFileSize() << fixed_point;
395                 unsigned long long int result = (receivedBytes*100) / fileSize();
396                 unsigned long long int result_int = result >> fixed_point;
397                 unsigned long long int result_fraction = result &
398                         ~(0xFFFFFFFF << fixed_point);
399                 if (unit == 0)
400                         snprintf(str, sizeof(str), "%lu %s / %llu.%.2llu %%",
401                                 bytes, unitStr[unit], result_int, result_fraction);
402                 else
403                         snprintf(str, sizeof(str), "%.2f %s / %llu.%.2llu %%",
404                                 doubleTypeBytes, unitStr[unit], result_int, result_fraction);
405         } else {
406                 if (unit == 0)
407                         snprintf(str, sizeof(str), "%lu %s", bytes, unitStr[unit]);
408                 else
409                         snprintf(str, sizeof(str), "%.2f %s", doubleTypeBytes, unitStr[unit]);
410         }
411         return string(str).c_str();
412 }
413
414 unsigned long int ViewItem::receivedFileSize()
415 {
416         if (m_item)
417                 return m_item->receivedFileSize();
418
419         return 0;
420 }
421
422 unsigned long int ViewItem::fileSize()
423 {
424         if (m_item)
425                 return m_item->fileSize();
426
427         return 0;
428 }
429
430 const char *ViewItem::getTitle()
431 {
432         const char *title = NULL;
433         if (m_item)
434                 title = m_item->title().c_str();
435
436         if (!title)
437                 return S_("IDS_COM_BODY_NO_NAME");
438
439         return title;
440 }
441
442 Evas_Object *ViewItem::createProgressBar(Evas_Object *parent)
443 {
444         Evas_Object *progress = NULL;
445         if (!parent) {
446                 DP_LOGE("parent is NULL");
447                 return NULL;
448         }
449         progress = elm_progressbar_add(parent);
450         setProgressBar(progress);
451         if (isFinished()) {
452                 DP_LOGE("Cannot enter here. finished item has othere genlist style");
453                 return NULL;
454         }
455
456         if (fileSize() == 0 || isPreparingDownload()) {
457                 //DP_LOGD("Pending style::progressBar[%p]",progress);
458                 elm_object_style_set(progress, "pending_list");
459                 elm_progressbar_horizontal_set(progress, EINA_TRUE);
460                 evas_object_size_hint_align_set(progress, EVAS_HINT_FILL, EVAS_HINT_FILL);
461                 evas_object_size_hint_weight_set(progress, EVAS_HINT_EXPAND,
462                         EVAS_HINT_EXPAND);
463                 elm_progressbar_pulse(progress, EINA_TRUE);
464         } else {
465                 //DP_LOGD("List style::progressBar[%p] fileSize[%d] state[%d]",progress, fileSize(),state());
466                 elm_object_style_set(progress, "list_progress");
467                 elm_progressbar_horizontal_set(progress, EINA_TRUE);
468
469                 if (isCompletedDownload())
470                         elm_progressbar_value_set(progress, 1.0);
471                 /* When realized event is happened, the progress is created.
472                    This is needed for that case */
473                 else if (state() == ITEM::DOWNLOADING) {
474                         double percentageProgress = 0.0;
475                         percentageProgress = (double)(receivedFileSize()) /
476                                 (double)(fileSize());
477                         elm_progressbar_value_set(progress, percentageProgress);
478                 }
479         }
480         evas_object_show(progress);
481         return progress;
482 }
483
484 void ViewItem::updateCheckedBtn()
485 {
486         if (m_checkedBtn)
487                 elm_check_state_pointer_set(m_checkedBtn,&m_checked);
488 }
489
490 void ViewItem::deleteBtnClickedCB(void *data, Evas_Object *obj, void *event_info)
491 {
492         DP_LOGD_FUNC();
493         if (!data) {
494                 DP_LOGE("data is NULL");
495                 return;
496         }
497         ViewItem *viewItem = static_cast<ViewItem *>(data);
498         viewItem->clickedDeleteButton();
499 }
500
501 void ViewItem::retryBtnClickedCB(void *data, Evas_Object *obj, void *event_info)
502 {
503         DP_LOGD_FUNC();
504         if (!data) {
505                 DP_LOGE("data is NULL");
506                 return;
507         }
508         ViewItem *viewItem = static_cast<ViewItem *>(data);
509         viewItem->clickedRetryButton();
510 }
511
512 Evas_Object *ViewItem::createCancelBtn(Evas_Object *parent)
513 {
514         DP_LOGD_FUNC();
515         Evas_Object *button = elm_button_add(parent);
516         elm_object_part_content_set(parent, "btn_style1", button);
517         elm_object_style_set(button, "style1/auto_expand");
518         evas_object_size_hint_aspect_set(button, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
519         elm_object_text_set(button, S_("IDS_COM_SK_CANCEL"));
520         evas_object_propagate_events_set(button, EINA_FALSE);
521         evas_object_smart_callback_add(button,"clicked", cancelBtnClickedCB, this);
522         return button;
523 }
524
525 void ViewItem::cancelBtnClickedCB(void *data, Evas_Object *obj, void *event_info)
526 {
527         DP_LOGD_FUNC();
528         if (!data) {
529                 DP_LOGE("data is NULL");
530                 return;
531         }
532         ViewItem *viewItem = static_cast<ViewItem *>(data);
533         viewItem->clickedCancelButton();
534 }
535
536 void ViewItem::extractDateGroupType()
537 {
538         DP_LOGD_FUNC();
539         /* History Item */
540         //DP_LOGD("state[%s],finishedTime[%ld]",stateStr(),finishedTime());
541         if (isFinished() && finishedTime() > 0) {
542                 int diffDay = 0;
543                 DateUtil &inst = DateUtil::getInstance();
544                 double nowTime = inst.nowTime();
545                 double finishTime = finishedTime();
546                 diffDay = inst.getDiffDays((time_t)nowTime, (time_t)finishTime);
547                 if (diffDay == 0)
548                         m_dateGroupType = DATETIME::DATE_TYPE_TODAY;
549                 else if (diffDay == 1)
550                         m_dateGroupType = DATETIME::DATE_TYPE_YESTERDAY;
551                 else if (diffDay > 1)
552                         m_dateGroupType = DATETIME::DATE_TYPE_PREVIOUS;
553                 else 
554                         m_dateGroupType = DATETIME::DATE_TYPE_LATER;
555                 return;
556         }
557         /* Item which is added now or retrying item */
558         m_dateGroupType = DATETIME::DATE_TYPE_TODAY;
559 }
560
561
562 void ViewItem::retryViewItem(void)
563 {
564         DownloadView &view = DownloadView::getInstance();
565         DP_LOGD_FUNC();
566         if (m_item) {
567                 m_isRetryCase = true;
568                 m_item->clearForRetry();
569                 if (!m_item->retry()) {
570                         DownloadView &view = DownloadView::getInstance();
571                         string desc = S_("IDS_COM_POP_FAILED");
572                         view.showErrPopup(desc);
573                         m_item->deleteFromDB();
574                         m_item->destroy();
575                         return;
576                 }
577                 /* Move a item to Today group, if it is not included to Today group */
578                 view.moveRetryItem(this);
579         }
580 }