apply FSL(Flora Software License)
[apps/core/preloaded/message-app.git] / composer / src / ui-composer / msg-ui-composer-common.c
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 #include <Elementary.h>
18 #include <utilX.h>
19 #include <Ecore_X.h>
20
21 #include <devman_haptic.h>
22 #include "msg-ui-composer-common.h"
23 #include "msg-ui-composer-body.h"
24 #include "msg-ui-composer-recipient.h"
25 #include "msg-ui-composer-popup.h"
26 #include "msg-ui-composer-data.h"
27 #include "msg-ui-composer-bubble.h"
28 #include "msg-ui-composer-main.h"
29
30 /* vib feedback apply when message type change*/
31 static bool bVibrating;
32 static int dev_handle;
33
34 char *msg_ui_composer_edj_get(MSG_COMPOSER_VIEW_DATA_S *cd)
35 {
36         if (cd->current_theme == MSG_UI_THEME_WHITE)
37                 return MSGC_UI_WHITE_EDJ;
38
39         return MSGC_UI_DEFAULT_EDJ;     /*black*/
40 }
41
42 Evas_Object *msg_ui_composer_load_edj(Evas_Object *parent, const char *edj_file, const char *group)
43 {
44         Evas_Object *layout;
45         layout = elm_layout_add(parent);
46
47         elm_layout_file_set(layout, edj_file, group);
48         return layout;
49 }
50
51 Evas_Object *msg_ui_composer_layout_create(Evas_Object *parent, bool indicator)
52 {
53         D_ENTER;
54         D_MSG_RETVM_IF(parent == NULL, NULL, "parent object  == NULL");
55
56         Evas_Object *layout;
57
58         layout = elm_layout_add(parent);
59         if (layout == NULL) {
60                 D_EMSG("[ASSERT] elm_layout_add failed!!");
61                 return NULL;
62         }
63
64         if (indicator == true)
65                 elm_layout_theme_set(layout, "layout", "application", "default");
66         else
67                 elm_layout_theme_set(layout, "layout", "application", "noindicator");
68
69         evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
70         evas_object_size_hint_align_set(layout, EVAS_HINT_FILL, EVAS_HINT_FILL);
71         evas_object_show(layout);
72         D_LEAVE;
73         return layout;
74 }
75
76 Evas_Object *msg_ui_composer_conformant_create(Evas_Object *parent_win, Evas_Object *inner)
77 {
78         D_ENTER;
79         Evas_Object *conform;
80         D_MSG_RETVM_IF(!parent_win, NULL,"Inputted Paremeter Window is Invalid");
81         D_MSG_RETVM_IF(!inner, NULL,"Inputted Paremeter Content is Invalid");
82
83         conform = elm_conformant_add(parent_win);
84         D_MSG_RETVM_IF(!conform, NULL,"Fail to Create conformant object");
85
86         elm_win_conformant_set(parent_win, EINA_TRUE);
87         evas_object_size_hint_weight_set(conform, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
88         evas_object_size_hint_align_set(conform, EVAS_HINT_FILL, EVAS_HINT_FILL);
89         elm_win_resize_object_add(parent_win, conform);
90         evas_object_show(conform);
91
92         elm_object_content_set(conform, inner);
93         D_LEAVE;
94         return conform;
95 }
96
97 Evas_Object *msg_ui_composer_bg_create(Evas_Object *parent)
98 {
99         D_MSG_RETVM_IF(parent == NULL, NULL, "parent object  == NULL");
100     Evas_Object *bg = elm_bg_add(parent);
101     evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
102     evas_object_show(bg);
103     return bg;
104 }
105
106 int64 msg_composer_get_file_size(const char *path)
107 {
108         return ecore_file_size(path);
109 }
110
111 char *msg_common_get_file_ext(const char *a_pszfile_name)
112 {
113         if (a_pszfile_name != NULL) {
114                 int nlen = strlen(a_pszfile_name);
115                 char *psztemp = (char *)a_pszfile_name + nlen;
116
117                 while (nlen--) {
118                         psztemp--;
119                         if (*psztemp == '.') {
120                                 psztemp++;
121                                 break;
122                         }
123                 }
124                 return psztemp;
125         }
126
127         return NULL;
128 }
129
130 void msg_ui_composer_clear(MSG_COMPOSER_VIEW_DATA_S *cd)
131 {
132         D_ENTER;
133         D_MSG_RETM_IF(cd == NULL, "Composer Data is NULL");
134
135         /*Clear recipient */
136         if (cd->recipient)
137                 msg_ui_composer_recipient_clear(cd->recipient);
138
139         msg_ui_composer_body_clear(cd);
140
141         D_LEAVE;
142 }
143
144 Eina_Bool msg_ui_composer_last_focus_load(void *data)
145 {
146         D_ENTER;
147         MSG_COMPOSER_VIEW_DATA_S *cd = (MSG_COMPOSER_VIEW_DATA_S *)data;
148         if(!cd) return EINA_FALSE;
149
150         if (cd->last_focus_entry == NULL) {
151                 D_MSG("NO ENTRY FOCUS");
152                 return EINA_FALSE;
153         }
154
155         elm_object_focus_set(cd->last_focus_entry, EINA_TRUE);
156         D_MSG("### Focused Entry Load = %p",cd->last_focus_entry);
157         D_LEAVE;
158         return EINA_FALSE;
159 }
160
161 void msg_ui_composer_last_focused_entry_set(void *data, Evas_Object *entry)
162 {
163         MSG_COMPOSER_VIEW_DATA_S *cd;
164         cd = (MSG_COMPOSER_VIEW_DATA_S *)data;
165         cd->last_focus_entry = entry;
166 }
167
168 Evas_Object *msg_ui_composer_last_focused_entry_get(void *data)
169 {
170         MSG_COMPOSER_VIEW_DATA_S *cd;
171         cd = (MSG_COMPOSER_VIEW_DATA_S *)data;
172         if (!cd) return NULL;
173
174         return cd->last_focus_entry;
175 }
176
177 Evas_Object *msg_ui_composer_last_body_entry_get(void *data)
178 {
179         D_ENTER;
180
181         MSG_COMPOSER_VIEW_DATA_S *cd = (MSG_COMPOSER_VIEW_DATA_S *)data;
182
183         MSG_COMPOSER_BODY_PAGE_S *page_data = eina_list_nth(cd->body_data.page_list, cd->current_edit_entry);
184         D_MSG("cd->current_edit_entry = %d", cd->current_edit_entry);
185
186         if (page_data && page_data->entry) {
187                 return page_data->entry;
188         } else {
189                 D_MSG("No Entry Saved");
190                 return NULL;
191         }
192
193         D_LEAVE;
194         return NULL;
195 }
196
197 void bundle_send_to_result(void *data, char *key, char *val)
198 {
199         D_ENTER;
200         D_MSG("key = %s, val = %s", key, val);
201
202         MSG_COMPOSER_VIEW_DATA_S *cd = (MSG_COMPOSER_VIEW_DATA_S *)data;
203
204         bundle *b;
205         b = bundle_create();
206         bundle_add(b, key, val);
207
208         ug_send_result(cd->ug, b);
209
210         bundle_free(b);
211
212         D_LEAVE;
213 }
214
215 int msg_ui_composer_thread_id_get(MSG_HANDLE_T msg_handle, const char *recipient)
216 {
217         char tmp_recipient[DEF_BUF_LEN] = {0,};
218         MSG_ERROR_T err = MSG_SUCCESS;
219         MSG_SORT_RULE_S sortRule = {0, };
220         MSG_THREAD_VIEW_LIST_S peerList = {0,};
221         int row;
222         char thread_addr_r[DEF_THREAD_ADDR_LEN] = {0};
223
224         sortRule.sortType = MSG_SORT_BY_THREAD_DATE;
225         sortRule.bAscending = false;
226
227         strncpy(tmp_recipient, recipient, sizeof(tmp_recipient)-1);
228         D_MSG("recipient = %s:%s, tmp recipient = %s", recipient, strdup(recipient), tmp_recipient);
229         g_strreverse(tmp_recipient);
230         D_MSG("tmp_recipient = %s", tmp_recipient);
231         err = msg_get_thread_view_list(msg_handle, &sortRule, &peerList);
232         for (row = 0; row < peerList.nCount; row++) {
233                 if (strlen(msg_thread_view_get_address(peerList.msgThreadInfo[row]))) {
234                         strncpy(thread_addr_r, msg_thread_view_get_address(peerList.msgThreadInfo[row]), strlen(msg_thread_view_get_address(peerList.msgThreadInfo[row])));
235                         g_strreverse(thread_addr_r);
236                         if (g_ascii_strncasecmp(thread_addr_r, tmp_recipient, COMPARE_STRING_NUM) == 0) {
237                                 D_MSG("FIND THREAD ADDRESS = %s", msg_thread_view_get_address(peerList.msgThreadInfo[row]));
238                                 break;
239                         }
240                 }
241         }
242
243         if (row >= peerList.nCount) {
244                 msg_release_thread_view_list(&peerList);
245                 D_MSG("CANNOT FIND THREAD");
246                 return 0;
247         }
248
249         int retid = msg_thread_view_get_thread_id(peerList.msgThreadInfo[row]);
250         msg_release_thread_view_list(&peerList);
251         return retid;
252 }
253
254 char *msg_ui_composer_thread_recipient_get(MSG_HANDLE_T msg_handle, int inp_tid)
255 {
256         MSG_ERROR_T err = MSG_SUCCESS;
257         MSG_SORT_RULE_S sortRule = {0, };
258         MSG_THREAD_VIEW_LIST_S peerList = {0,};
259         int row;
260         char *ret_recipient = NULL;
261         sortRule.sortType = MSG_SORT_BY_THREAD_DATE;
262         sortRule.bAscending = false;
263
264         err = msg_get_thread_view_list(msg_handle, &sortRule, &peerList);
265         for (row = 0; row < peerList.nCount; row++) {
266                 if (inp_tid == msg_thread_view_get_thread_id(peerList.msgThreadInfo[row])) {
267                         ret_recipient = strdup(msg_thread_view_get_address(peerList.msgThreadInfo[row]));
268                         break;
269                 }
270         }
271
272         msg_release_thread_view_list(&peerList);
273         return ret_recipient;
274 }
275
276 bool msg_ui_composer_common_is_send_possible(MSG_COMPOSER_VIEW_DATA_S *cd)
277 {
278         D_ENTER;
279
280         if (!cd) {
281                 MSG_UI_DEBUG(MSG_UI_LEVEL_ASSERT, "[ASSERT] composer data is NULL");
282                 return false;
283         }
284
285         MSG_COMPOSER_BODY_S *body_data = &cd->body_data;
286         MSG_COMPOSER_BODY_PAGE_S *page_data = NULL;
287
288         if (cd->msg_type == COMPOSER_MSG_TYPE_SMS) {
289                 page_data = (MSG_COMPOSER_BODY_PAGE_S *)eina_list_nth(body_data->page_list, 0);
290                 if(page_data) {
291                         char *body_text = elm_entry_markup_to_utf8(elm_entry_entry_get(page_data->entry));
292                         if (body_text) {
293                                 if (strlen(body_text) > 0) {
294                                         g_free(body_text);
295                                         return true;
296                                 }
297                                 g_free(body_text);
298                         }
299                 }
300         } else {
301                 MSG_UI_DEBUG(MSG_UI_LEVEL_ASSERT, "[ASSERT] invalid message type");
302                 return false;
303         }
304
305         D_LEAVE;
306         return false;
307 }
308
309 static gboolean __msg_ui_composer_vib_timeout_cb(gpointer data)
310 {
311         D_ENTER;
312
313         int ret = 0;
314
315         if (bVibrating == true) {
316                 ret = device_haptic_stop_play(dev_handle);
317
318                 if (ret != 0) {
319                         MSG_UI_DEBUG(MSG_UI_LEVEL_ASSERT, "[ASSERT] Fail to stop haptic : [%d]", ret);
320                 }
321
322                 ret = device_haptic_close(dev_handle);
323
324                 if (ret != 0) {
325                         MSG_UI_DEBUG(MSG_UI_LEVEL_ASSERT, "[ASSERT] Fail to close haptic : [%d]", ret);
326                 }
327
328                 bVibrating = false;
329         }
330
331         D_LEAVE;
332
333         return FALSE;
334 }
335
336 void msg_ui_composer_common_play_vibration()
337 {
338         D_ENTER;
339
340         int ret = 0;
341         int vibPattern = EFFCTVIBE_NOTIFICATION;
342
343         bVibrating = true;
344         dev_handle = device_haptic_open(DEV_IDX_0, 0);
345
346         g_timeout_add(150, __msg_ui_composer_vib_timeout_cb, NULL);
347
348         ret = device_haptic_play_pattern(dev_handle, vibPattern, 1, HAPTIC_FEEDBACK_LEVEL_5);
349
350         if (ret != 0) {
351                 MSG_UI_DEBUG(MSG_UI_LEVEL_ASSERT, "[ASSERT] Fail to play haptic : [%d]", ret);
352         }
353
354         D_LEAVE;
355 }
356
357 void msg_composer_entry_filter_remove_markup(void *data, Evas_Object *entry, char **text)
358 {
359         D_ENTER;
360         D_MSG_RETM_IF(text == NULL || *text == NULL, "New Text is NULL");
361
362         char *preedit_str = NULL;
363         char *utf8_text = NULL;
364         char *convert_text = NULL;
365         D_MSG("text %s", *text);
366         /* Check preeditting text and return if it exist*/
367         preedit_str = strstr(*text, "<preedit_sel>");
368         if (preedit_str) return;
369
370         /* convert from markup text to utf8 text from entry */
371         utf8_text  = elm_entry_markup_to_utf8(*text);
372         if (utf8_text) {
373
374                 /* If the string contains "Carrage return ('\n'), it should be changed "<br>" to show properly*/
375                 convert_text = elm_entry_utf8_to_markup(utf8_text);
376                 if(convert_text) {
377                         free(*text);
378                         *text = strdup(convert_text);
379                         free(convert_text);
380                 }
381                 free(utf8_text);
382         }
383
384         D_LEAVE;
385 }
386
387 int msg_ui_composer_convert_UTF8ToUCS2(unsigned char *pDestText, int maxLength, const char *pSrcText, int srcTextLen)
388 {
389         D_ENTER;
390         int textLen = 0;
391         unsigned char *unicodeTemp = (unsigned char*)pDestText;
392
393         int ucs2Length = 0;
394         int remainedBuffer = maxLength;
395
396         if(maxLength == 0 || pSrcText == NULL || pDestText ==  NULL)
397         {
398                 MSG_UI_DEBUG(MSG_UI_LEVEL_ASSERT,"[ASSERT]UTF8 to UCS2 Failed as text length is NULL \n");
399                 return -1;
400         }
401
402         // null terminated string
403         if (srcTextLen == -1) {
404                 textLen = strlen((char*)pSrcText);
405                 srcTextLen = textLen;
406         } else {
407                 textLen = srcTextLen;
408         }
409
410         GIConv cd;
411         int err=0;
412
413         cd = g_iconv_open("UCS-2BE", "UTF8");
414
415         if (cd > 0)
416         {
417                 err = g_iconv(cd, (char**)&pSrcText, (gsize*)&textLen, (char**)&unicodeTemp, (gsize*)&remainedBuffer);
418         }
419
420         ucs2Length = maxLength - remainedBuffer;
421
422         g_iconv_close(cd);
423
424         D_LEAVE;
425         return ucs2Length;
426 }
427
428 void msg_ui_composer_common_tickernoti(MSG_COMPOSER_VIEW_DATA_S *cd, COMPOSER_TICKERNOTI_TYPE_E tickertype)
429 {
430         char popup_msg[DEF_BUF_LEN_L] = {0,};
431         MSGC_NOTIFY_ORIENT orient;
432         Evas_Object *parent_notify;
433
434         D_MSG_RETM_IF(cd == NULL, "Composer Data is Invalid");
435
436         if (tickertype == COMPOSER_TICKERNOTI_COUNT_MAX) {
437                 snprintf(popup_msg, sizeof(popup_msg)-1, MSGC_STR_NOTI_RECIPIENT_MAX, COMPOSER_RECIPIENT_COUNT_MAX);
438                 parent_notify = cd->recipient->bx_main;
439                 orient = MSGC_NOTIFY_ORIENT_BOTTOM;
440         } else if (tickertype == COMPOSER_TICKERNOTI_DUP_RECP) {
441                 snprintf(popup_msg, sizeof(popup_msg)-1, MSGC_STR_NOTI_RECIPIENT_DUP);
442                 parent_notify = cd->recipient->bx_main;
443                 orient = MSGC_NOTIFY_ORIENT_BOTTOM;
444         } else if (tickertype == COMPOSER_TICKERNOTI_INVALID_RECP) {
445                 snprintf(popup_msg, sizeof(popup_msg)-1, MSGC_STR_NOTI_RECIPIENT_INVALID);
446                 parent_notify = cd->recipient->bx_main;
447                 orient = MSGC_NOTIFY_ORIENT_BOTTOM;
448         } else if (tickertype == COMPOSER_TICKERNOTI_CHANGED_SMS) {
449                 snprintf(popup_msg, sizeof(popup_msg)-1, MSGC_STR_NOTI_CHANGE_SMS);
450                 parent_notify = cd->ly_body;
451                 orient = MSGC_NOTIFY_ORIENT_BOTTOM;
452         } else {
453                 return;
454         }
455
456         if (cd->noti) {
457                 evas_object_del(cd->noti);
458         }
459
460         cd->noti = msg_ui_composer_notify_show(parent_notify, popup_msg, COMPOSER_STATUS_POPUP_DEFAULT_TIME, orient, false);
461 }
462
463 void msg_ui_composer_entry_imf_state_cb(void * data, Ecore_IMF_Context *ctx, int value)
464 {
465         D_ENTER;
466
467         MSG_COMPOSER_VIEW_DATA_S *cd = (MSG_COMPOSER_VIEW_DATA_S *)data;
468
469         D_MSG_RETM_IF(cd == NULL, "Composer Data is Invalid");
470         D_MSG_RETM_IF(ctx == NULL, "Ecore_IMF_Context is Invalid");
471
472         if (value == ECORE_IMF_INPUT_PANEL_STATE_SHOW) {
473                 D_MSG("Imf status SHOW");
474                 edje_object_signal_emit(_EDJ(cd->ly_body), "body_contract","*");
475         } else if (value == ECORE_IMF_INPUT_PANEL_STATE_HIDE) {
476                 D_MSG("Imf status HIDE");
477
478                 if (msg_ui_composer_common_is_send_possible(cd) == false) {
479                         D_MSG("body_EXPAND and send button HIDE ");
480                         edje_object_signal_emit(_EDJ(cd->ly_body), "body_expand","*");
481                 }
482         } else {
483                 D_EMSG("imf status INVALID");
484         }
485
486         D_LEAVE;
487 }
488
489 void msg_ui_composer_evas_object_delete_cb(void *data, Evas * e, Evas_Object *obj, void *event_info)
490 {
491         D_ENTER;
492         if (!data || !obj)
493                 return;
494
495         D_PRINT("delete = %s[%p]", (char *)data, obj);
496         D_LEAVE;
497 }