419b3e3a1c2688d85f8937cc78c7759db22ef70b
[framework/uifw/elementary.git] / src / modules / ctxpopup_copypasteUI / copypaste.c
1 #include <Elementary.h>
2 #include "elm_module_priv.h"
3 #include "elm_priv.h"
4 #include <appsvc/appsvc.h>
5 #include "cbhm_helper.h"
6
7 #define MULTI_(id) dgettext("sys_string", #id)
8 #define S_SELECT MULTI_(IDS_COM_SK_SELECT)
9 #define S_SELECT_ALL MULTI_(IDS_COM_BODY_SELECT_ALL)
10 #define S_COPY MULTI_(IDS_COM_BODY_COPY)
11 #define S_CUT MULTI_(IDS_COM_BODY_CUT)
12 #define S_PASTE MULTI_(IDS_COM_BODY_PASTE)
13 #define S_CLIPBOARD MULTI_(IDS_COM_BODY_CLIPBOARD)
14
15
16 Elm_Entry_Extension_data *ext_mod;
17 static int _mod_hook_count = 0;
18
19 typedef struct _Elm_Entry_Context_Menu_Item Elm_Entry_Context_Menu_Item;
20 struct _Elm_Entry_Context_Menu_Item
21 {
22    Evas_Object *obj;
23    const char *label;
24    const char *icon_file;
25    const char *icon_group;
26    Elm_Icon_Type icon_type;
27    Evas_Smart_Cb func;
28    void *data;
29 };
30
31 static char *
32 _remove_tags(const char *str)
33 {
34    char *ret;
35    if (!str)
36      return NULL;
37
38    Eina_Strbuf *buf = eina_strbuf_new();
39    if (!buf)
40      return NULL;
41
42    if (!eina_strbuf_append(buf, str))
43      return NULL;
44
45    eina_strbuf_replace_all(buf, "<br>", " ");
46    eina_strbuf_replace_all(buf, "<br/>", " ");
47    eina_strbuf_replace_all(buf, "<ps>", " ");
48    eina_strbuf_replace_all(buf, "<ps/>", " ");
49
50    while (EINA_TRUE)
51      {
52         const char *temp = eina_strbuf_string_get(buf);
53
54         char *startTag = NULL;
55         char *endTag = NULL;
56
57         startTag = strstr(temp, "<");
58         if (startTag)
59           endTag = strstr(startTag, ">");
60         else
61           break;
62         if (!endTag || startTag > endTag)
63           break;
64
65         size_t sindex = startTag - temp;
66         size_t eindex = endTag - temp + 1;
67         if (!eina_strbuf_remove(buf, sindex, eindex))
68           break;
69      }
70    ret = eina_strbuf_string_steal(buf);
71    eina_strbuf_free(buf);
72    return ret;
73 }
74
75 static void _ctxpopup_hide(Evas_Object *popup);
76 static void _ctxpopup_position(Evas_Object *obj);
77 static void
78 _entry_move(void *data, Evas *e, Evas_Object *obj, void *event_info)
79 {
80    if (evas_pointer_button_down_mask_get(e))
81      _ctxpopup_hide(ext_mod->popup);
82    else
83      _ctxpopup_position(data);
84 }
85
86 static void
87 _ctxpopup_hide(Evas_Object *popup)
88 {
89    evas_object_hide(popup);
90    evas_object_event_callback_del(ext_mod->caller, EVAS_CALLBACK_MOVE, _entry_move);
91    ext_mod->caller = NULL;
92 }
93
94 static void
95 _ctxpopup_position(Evas_Object *obj)
96 {
97    if(!ext_mod) return;
98
99    Evas_Coord cx, cy, cw, ch, x, y, w, h;
100    if (!edje_object_part_text_selection_geometry_get(ext_mod->ent, "elm.text", &x, &y, &w, &h))
101      {
102         evas_object_geometry_get(ext_mod->ent, &x, &y, NULL, NULL);
103         edje_object_part_text_cursor_geometry_get(ext_mod->ent, "elm.text",
104                                                   &cx, &cy, &cw, &ch);
105         evas_object_size_hint_min_get(ext_mod->popup, &w, &h);
106         if (cw < w)
107           {
108              cx += (cw - w) / 2;
109              cw = w;
110           }
111         if (ch < h)
112           {
113              cy += (ch - h) / 2;
114              ch = h;
115           }
116         evas_object_move(ext_mod->popup, x + cx, y + cy);
117         evas_object_resize(ext_mod->popup, cw, ch);
118      }
119    else
120      {
121         if (ext_mod->viewport_rect.x != -1 || ext_mod->viewport_rect.y != -1
122             || ext_mod->viewport_rect.w != -1 || ext_mod->viewport_rect.h != -1)
123           {
124              Evas_Coord vx, vy, vw, vh, x2, y2;
125              x2 = x + w;
126              y2 = y + h;
127              vx = ext_mod->viewport_rect.x;
128              vy = ext_mod->viewport_rect.y;
129              vw = ext_mod->viewport_rect.w;
130              vh = ext_mod->viewport_rect.h;
131
132              if (x < vx) x = vx;
133              if (y < vy) y = vy;
134              if (x2 > vx + vw) x2 = vx + vw;
135              if (y2 > vy + vh) y2 = vy + vh;
136              w = x2 - x;
137              h = y2 - y;
138           }
139         else
140           {
141              Evas_Coord sw, sh, x2, y2;
142              x2 = x + w;
143              y2 = y + h;
144              ecore_x_window_size_get(ecore_x_window_root_first_get(), &sw, &sh);
145
146              if (x < 0) x = 0;
147              if (y < 0) y = 0;
148              if (x2 > sw) x2 = sw;
149              if (y2 > sh) y2 = sh;
150              w = x2 - x;
151              h = y2 - y;
152           }
153         cx = x + (w / 2);
154         cy = y + (h / 2);
155         evas_object_move(ext_mod->popup, cx, cy);
156      }
157 }
158
159 static void
160 _select_all(void *data, Evas_Object *obj, void *event_info)
161 {
162    if(!ext_mod) return;
163
164    ext_mod->selectall(data,obj,event_info);
165    _ctxpopup_hide(obj);
166 }
167
168 static void
169 _select(void *data, Evas_Object *obj, void *event_info)
170 {
171    if(!ext_mod) return;
172
173    ext_mod->select(data,obj,event_info);
174    _ctxpopup_hide(obj);
175 }
176
177 static void
178 _paste(void *data, Evas_Object *obj, void *event_info)
179 {
180    if(!ext_mod) return;
181
182    ext_mod->paste(data,obj,event_info);
183    _ctxpopup_hide(obj);
184 }
185
186 static void
187 _cut(void *data, Evas_Object *obj, void *event_info)
188 {
189    if(!ext_mod) return;
190
191    ext_mod->cut(data,obj,event_info);
192    _ctxpopup_hide(obj);
193    elm_object_scroll_freeze_pop(ext_mod->popup);
194 }
195
196 static void
197 _copy(void *data, Evas_Object *obj, void *event_info)
198 {
199    if(!ext_mod) return;
200
201    ext_mod->copy(data,obj,event_info);
202    _ctxpopup_hide(obj);
203    elm_object_scroll_freeze_pop(ext_mod->popup);
204 }
205
206 static void
207 _cancel(void *data, Evas_Object *obj, void *event_info)
208 {
209    if(!ext_mod) return;
210
211    ext_mod->cancel(data,obj,event_info);
212    _ctxpopup_hide(obj);
213    elm_object_scroll_freeze_pop(ext_mod->popup);
214 }
215
216 static void
217 _search_menu(void *data, Evas_Object *obj, void *event_info)
218 {
219    if(!ext_mod) return;
220
221    int ret;
222    bundle *b = bundle_create();
223    if (!b)
224      {
225         //printf("bundle_create() failed\n");
226         return;
227      }
228
229    appsvc_set_operation(b, APPSVC_OPERATION_SEARCH);
230    if (ext_mod->selmode)
231      {
232         const char *selection = elm_entry_selection_get(ext_mod->caller);
233         if (selection)
234           {
235              char *str = _remove_tags(selection);
236              if (str)
237                {
238                   appsvc_add_data(b, APPSVC_DATA_KEYWORD, str);
239                   free(str);
240                }
241              else
242                appsvc_add_data(b, APPSVC_DATA_KEYWORD, selection);
243           }
244      }
245    appsvc_run_service(b, 0, NULL, NULL);
246    bundle_free(b);
247    _ctxpopup_hide(obj);
248 }
249
250 static void
251 _clipboard_menu(void *data, Evas_Object *obj, void *event_info)
252 {
253    if(!ext_mod) return;
254
255    // start for cbhm
256 #ifdef HAVE_ELEMENTARY_X
257    ecore_x_selection_secondary_set(elm_win_xwindow_get(obj), "",1);
258 #endif
259    ext_mod->cnpinit(data,obj,event_info);
260    if (ext_mod->cnp_mode != ELM_CNP_MODE_MARKUP)
261      _cbhm_msg_send(obj, "show0");
262    else
263      _cbhm_msg_send(obj, "show1");
264    _ctxpopup_hide(obj);
265    // end for cbhm
266 }
267
268 static void
269 _item_clicked(void *data, Evas_Object *obj, void *event_info)
270 {
271    Elm_Entry_Context_Menu_Item *it = data;
272    Evas_Object *obj2 = it->obj;
273
274    if (it->func) it->func(it->data, obj2, NULL);
275    _ctxpopup_hide(obj);
276 }
277
278 static void
279 _ctxpopup_dismissed_cb(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__)
280 {
281    if (!ext_mod) return;
282
283    elm_object_scroll_freeze_pop(ext_mod->popup);
284 }
285
286 // module api funcs needed
287 EAPI int
288 elm_modapi_init(void *m)
289 {
290    return 1; // succeed always
291 }
292
293 EAPI int
294 elm_modapi_shutdown(void *m)
295 {
296    return 1; // succeed always
297 }
298
299 // module funcs for the specific module type
300 EAPI void
301 obj_hook(Evas_Object *obj)
302 {
303    _mod_hook_count++;
304    //if(_mod_hook_count > 1) return;
305
306    if(!ext_mod)
307      {
308         ext_mod = ELM_NEW(Elm_Entry_Extension_data);
309         elm_entry_extension_module_data_get(obj,ext_mod);
310      }
311 }
312
313 EAPI void
314 obj_unhook(Evas_Object *obj)
315 {
316    _mod_hook_count--;
317    if(_mod_hook_count > 0) return;
318
319    if(ext_mod)
320      {
321         free(ext_mod);
322         ext_mod = NULL;
323      }
324 }
325
326 EAPI void
327 obj_longpress(Evas_Object *obj)
328 {
329    if(!ext_mod) return;
330
331    Evas_Object *top;
332    const Eina_List *l;
333    const Elm_Entry_Context_Menu_Item *it;
334    const char *context_menu_orientation;
335    char buf[255];
336    Evas_Object* icon;
337    Elm_Object_Item *added_item = NULL;
338
339    /*update*/
340    elm_entry_extension_module_data_get(obj,ext_mod);
341    if (ext_mod->context_menu)
342      {
343 #ifdef HAVE_ELEMENTARY_X
344         int cbhm_count = _cbhm_item_count_get(obj);
345 #endif
346         if (ext_mod->popup) evas_object_del(ext_mod->popup);
347         //else elm_widget_scroll_freeze_push(obj);
348         top = elm_widget_top_get(obj);
349         if(top)
350           {
351              ext_mod->popup = elm_ctxpopup_add(top);
352              elm_object_focus_allow_set(ext_mod->popup, EINA_FALSE);
353              evas_object_smart_callback_add(ext_mod->popup, "dismissed", _ctxpopup_dismissed_cb, NULL);
354           }
355         /*currently below theme not used,when guideline comes a new theme can be created if required*/
356         elm_object_style_set(ext_mod->popup,"extended/entry");
357         context_menu_orientation = edje_object_data_get
358            (ext_mod->ent, "context_menu_orientation");
359         if ((context_menu_orientation) &&
360             (!strcmp(context_menu_orientation, "horizontal")))
361           elm_ctxpopup_horizontal_set(ext_mod->popup, EINA_TRUE);
362
363         elm_widget_sub_object_add(obj, ext_mod->popup);
364         if (!ext_mod->selmode)
365           {
366              if (!ext_mod->password)
367                {
368                   if (!elm_entry_is_empty(obj))
369                     {
370                        added_item = elm_ctxpopup_item_append(ext_mod->popup, S_SELECT, NULL, _select, obj );
371                        added_item = elm_ctxpopup_item_append(ext_mod->popup, S_SELECT_ALL, NULL, _select_all, obj );
372                     }
373                }
374
375 #ifdef HAVE_ELEMENTARY_X
376              if (cbhm_count)
377 #else
378              if (1) // need way to detect if someone has a selection
379 #endif
380                {
381                   if (ext_mod->editable)
382                     added_item = elm_ctxpopup_item_append(ext_mod->popup, S_PASTE, NULL, _paste, obj );
383                }
384              //elm_ctxpopup_item_append(wd->ctxpopup, NULL, "Selectall",_select_all, obj );
385              // start for cbhm
386 #ifdef HAVE_ELEMENTARY_X
387              if ((!ext_mod->password) && (ext_mod->editable) && (cbhm_count))
388 #else
389              if ((!ext_mod->password) && (ext_mod->editable))
390 #endif
391                {
392                   added_item = elm_ctxpopup_item_append(ext_mod->popup, S_CLIPBOARD, NULL, _clipboard_menu, obj);  // Clipboard
393                   //elm_ctxpopup_item_append(ext_mod->popup, "More", NULL, _clipboard_menu, obj );
394                }
395              // end for cbhm
396              icon = elm_icon_add(ext_mod->popup);
397              snprintf(buf, sizeof(buf), "%s/images/copy&paste_icon_search.png", PACKAGE_DATA_DIR);
398              elm_icon_file_set(icon, buf, NULL);
399              added_item = elm_ctxpopup_item_append(ext_mod->popup, NULL, icon, _search_menu, obj);  // Search
400           }
401         else
402           {
403              if (!ext_mod->password)
404                {
405                   if (ext_mod->have_selection)
406                     {
407                        added_item = elm_ctxpopup_item_append(ext_mod->popup, S_COPY, NULL, _copy, obj );
408                        if (ext_mod->editable)
409                          added_item = elm_ctxpopup_item_append(ext_mod->popup, S_CUT, NULL, _cut, obj );
410 #ifdef HAVE_ELEMENTARY_X
411                        if (ext_mod->editable && cbhm_count)
412 #else
413                        if (ext_mod->editable)
414 #endif
415                          added_item = elm_ctxpopup_item_append(ext_mod->popup, S_PASTE, NULL, _paste, obj );
416                     }
417                   else
418                     {
419                        _cancel(obj,ext_mod->popup,NULL);
420                        if (!elm_entry_is_empty(obj))
421                          {
422                             added_item = elm_ctxpopup_item_append(ext_mod->popup, S_SELECT, NULL, _select, obj );
423                             added_item = elm_ctxpopup_item_append(ext_mod->popup, S_SELECT_ALL, NULL, _select_all, obj );
424                          }
425 #ifdef HAVE_ELEMENTARY_X
426                        if (cbhm_count)
427 #else
428                        if (1) // need way to detect if someone has a selection
429 #endif
430                          {
431                             if (ext_mod->editable)
432                               added_item = elm_ctxpopup_item_append(ext_mod->popup, S_PASTE, NULL, _paste, obj );
433                          }
434                     }
435                   // start for cbhm
436 #ifdef HAVE_ELEMENTARY_X
437                   if (ext_mod->editable && cbhm_count)
438 #else
439                   if (ext_mod->editable)
440 #endif
441                     {
442                        added_item = elm_ctxpopup_item_append(ext_mod->popup, S_CLIPBOARD, NULL, _clipboard_menu, obj);  // Clipboard
443                        //elm_ctxpopup_item_append(ext_mod->popup, "More", NULL, _clipboard_menu, obj );
444                     }
445                   // end for cbhm
446                   icon = elm_icon_add(ext_mod->popup);
447                   snprintf(buf, sizeof(buf), "%s/images/copy&paste_icon_search.png", PACKAGE_DATA_DIR);
448                   elm_icon_file_set(icon, buf, NULL);
449                   added_item = elm_ctxpopup_item_append(ext_mod->popup, NULL, icon, _search_menu, obj);  // Search
450                }
451           }
452         EINA_LIST_FOREACH(ext_mod->items, l, it)
453           {
454              added_item = elm_ctxpopup_item_append(ext_mod->popup, it->label, NULL, _item_clicked, it );
455           }
456         if (ext_mod->popup && added_item)
457           {
458              elm_object_scroll_freeze_push(ext_mod->popup);
459              _ctxpopup_position(obj);
460              evas_object_show(ext_mod->popup);
461              ext_mod->caller = obj;
462              evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _entry_move, ext_mod->popup);
463           }
464         else
465           ext_mod->caller = NULL;
466      }
467 }
468
469 EAPI void
470 obj_mouseup(Evas_Object *obj)
471 {
472    if (!obj || !ext_mod)
473      return;
474 }
475
476
477 EAPI void
478 obj_hidemenu(Evas_Object *obj)
479 {
480    if (!obj || !ext_mod || obj != ext_mod->caller)
481      return;
482
483    _ctxpopup_hide(ext_mod->popup);
484    // if (ext_mod->popup) evas_object_del(ext_mod->popup);
485 }