Elm entry: Fixed 'Paste' to only show if there clipboard isn't empty.
[framework/uifw/elementary.git] / src / lib / elm_cnp_helper.c
index 39b6239..96b3b07 100644 (file)
@@ -12,7 +12,6 @@
 
 //#define DEBUGON 1
 
-
 #ifdef DEBUGON
 # define cnp_debug(x...) fprintf(stderr, __FILE__": " x)
 #else
@@ -143,7 +142,6 @@ static char *mark_up(const char *start, int inlen, int *lenp);
 static Evas_Object *image_provider(void *images, Evas_Object *entry, const char *item);
 static void entry_deleted(void *images, Evas *e, Evas_Object *entry, void *unused);
 
-
 static Eina_Bool targets_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
 static Eina_Bool text_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
 static Eina_Bool html_converter(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize);
@@ -165,17 +163,19 @@ static int vcard_receive(Cnp_Selection *sed, Ecore_X_Event_Selection_Notify *not
 static Paste_Image *pasteimage_alloc(const char *file, int pathlen);
 static Eina_Bool pasteimage_append(Paste_Image *pi, Evas_Object *entry);
 static void pasteimage_free(Paste_Image *pi);
+static void entry_insert_filter(Evas_Object* entry, char* str);
 
 /* Optimisation: Turn this into a 256 byte table:
  *     then can lookup in one index, not N checks */
 static const Escape escapes[] = {
-       { "<br>",   '\n' },
-       { "<\t>",   '\t' },
-       { "gt;",    '>'  },
-       { "lt;",    '<'  },
-       { "amp;",   '&'  },
-       { "quot;",  '\'' },
-       { "dquot;", '"'  }
+  { "<br>",   '\n' },
+  { "<ps>",   '\n' },
+  { "<\t>",   '\t' },
+  { "gt;",    '>'  },
+  { "lt;",    '<'  },
+  { "amp;",   '&'  },
+  { "quot;",  '\'' },
+  { "dquot;", '"'  }
 };
 #define N_ESCAPES ((int)(sizeof(escapes) / sizeof(escapes[0])))
 
@@ -190,7 +190,7 @@ static Cnp_Atom atoms[CNP_N_ATOMS] = {
      },
      [CNP_ATOM_XELM] =  {
           "application/x-elementary-markup",
-          ELM_SEL_FORMAT_TEXT | ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
+          ELM_SEL_FORMAT_MARKUP | ELM_SEL_FORMAT_HTML,
           edje_converter,
           NULL,
           notify_handler_edje,
@@ -407,7 +407,6 @@ static Ecore_Event_Handler *handler_status = NULL;
 /* Stringshared, so I can just compare pointers later */
 static const char *text_uri;
 
-
 /* For convert EFL to HTML */
 
 #define TAGPOS_START    0x00000001
@@ -429,6 +428,7 @@ TagTable _EFLtoHTMLConvertTable[] = {
        {"underline", "del", 0},
        {"strikethrough", "ins", 0},
        {"br", "br", 1},
+       {"ps", "br", 1},
        {"b", "b", 1},
        {"item", "img", 1}
 };
@@ -515,7 +515,11 @@ static PTagNode
 _new_tag_node(char *tag, char *tag_str, char* str, char *pos_in_ori_str)
 {
    PTagNode newNode = calloc(1, sizeof(TagNode));
+   if (tag)
+     eina_str_tolower(&tag);
    newNode->tag = tag;
+   if (tag_str)
+     eina_str_tolower(&tag_str);
    newNode->tag_str = tag_str;
    newNode->str = str;
    newNode->pos_in_ori_str = pos_in_ori_str;
@@ -768,7 +772,12 @@ _get_tag_value(const char *tag_str, const char *tag_name)
              char *valueEnd = strchr(value, '\0');
 
              int i;
-             for (i = 0; i < spCnt; i++)
+             int start = 0;
+             if ((!strncmp(tag_str, "<item", 5) && !strcmp(tag_name, "href")) // EFL img tag
+               || (!strncmp(tag_str, "<img", 4) && !strcmp(tag_name, "src"))) // HTML img tag
+               start = 1;
+
+             for (i = start; i < spCnt; i++)
                {
                   if (spArray[i] && spArray[i] < valueEnd)
                     valueEnd = spArray[i];
@@ -814,8 +823,7 @@ _set_EFL_item_data(PItemTagData data, const char *tag_str)
         if (path)
           {
              char *modify = malloc(sizeof(char) * (strlen(value) + 1));
-             strncpy(modify, "file://", 7);
-             modify[7] = '\0';
+             strncpy(modify, "file://", 8);
              path += 7;
              while (path[1] && path[0] && path[1] == '/' && path[0] == '/')
                {
@@ -896,8 +904,7 @@ _set_HTML_img_data(PItemTagData data, const char *tag_str)
         if (path)
           {
              char *modify = malloc(sizeof(char) * (strlen(value) + 1));
-             strncpy(modify, "file://", 7);
-             modify[7] = '\0';
+             strncpy(modify, "file://", 8);
              path += 7;
              while (path[1] && path[0] && path[1] == '/' && path[0] == '/')
                {
@@ -1033,9 +1040,10 @@ _convert_to_html(Eina_List* nodes)
                          }
                        switch(trail->tagPosType)
                          {
+                            /* closed tag does not need in HTML
                           case TAGPOS_ALONE:
                              eina_strbuf_append(html, " />");
-                             break;
+                             break;*/
                           default:
                              eina_strbuf_append(html, ">");
                              break;
@@ -1149,9 +1157,11 @@ _convert_to_edje(Eina_List* nodes)
                          }
                        switch(trail->tagPosType)
                          {
+                            /* not support in efl
                           case TAGPOS_ALONE:
                              eina_strbuf_append(html, " />");
                              break;
+                             */
                           default:
                              eina_strbuf_append(html, ">");
                              break;
@@ -1169,12 +1179,28 @@ _convert_to_edje(Eina_List* nodes)
    return ret;
 
 }
+
+Eina_Bool
+elm_selection_selection_has_owner(void)
+{
+#ifdef HAVE_ELEMENTARY_X
+   return !!ecore_x_selection_owner_get(clipboard_atom);
+#else
+   return EINA_FALSE;
+#endif
+}
+
 Eina_Bool
 elm_selection_set(Elm_Sel_Type selection, Evas_Object *widget, Elm_Sel_Format format, const char *selbuf)
 {
 #ifdef HAVE_ELEMENTARY_X
+   Evas_Object *top = elm_widget_top_get(widget);
+   Ecore_X_Window xwin;
    Cnp_Selection *sel;
 
+   if (top) xwin = elm_win_xwindow_get(top);
+   else xwin = elm_win_xwindow_get(widget);
+   if (!xwin) return EINA_FALSE;
    if ((unsigned int)selection >= (unsigned int)ELM_SEL_MAX) return EINA_FALSE;
    if (!_elm_cnp_init_count) _elm_cnp_init();
    if ((!selbuf) && (format != ELM_SEL_FORMAT_IMAGE))
@@ -1185,7 +1211,7 @@ elm_selection_set(Elm_Sel_Type selection, Evas_Object *widget, Elm_Sel_Format fo
    sel->active = 1;
    sel->widget = widget;
 
-   sel->set(elm_win_xwindow_get(widget),&selection,sizeof(Elm_Sel_Type));
+   sel->set(xwin, &selection, sizeof(Elm_Sel_Type));
    sel->format = format;
    sel->selbuf = selbuf ? strdup(selbuf) : NULL;
 
@@ -1355,6 +1381,8 @@ targets_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void
    Cnp_Selection *sel;
 
    if (!data_ret) return EINA_FALSE;
+   if (!data || (*((unsigned int *)data) >= ELM_SEL_MAX))
+     return EINA_FALSE;
 
    sel = selections + *((int *)data);
 
@@ -1398,6 +1426,28 @@ vcard_send(char *target __UNUSED__, void *data __UNUSED__, int size __UNUSED__,
 
    return EINA_TRUE;
 }
+
+static Eina_Bool
+is_uri_type_data(Cnp_Selection *sel __UNUSED__, Ecore_X_Event_Selection_Notify *notify)
+{
+   Ecore_X_Selection_Data *data;
+   char *p;
+
+   data = notify->data;
+   cnp_debug("data->format is %d %p %p\n", data->format, notify, data);
+   if (data->content == ECORE_X_SELECTION_CONTENT_FILES) return EINA_TRUE;
+   else p = (char *)data->data;
+
+   if (!p) return EINA_TRUE;
+   cnp_debug("Got %s\n", p);
+   if (strncmp(p, "file://", 7))
+     {
+        if (*p != '/') return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
 /*
  * Callback to handle a targets response on a selection request:
  * So pick the format we'd like; and then request it.
@@ -1407,6 +1457,7 @@ notify_handler_targets(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notif
 {
    Ecore_X_Selection_Data_Targets *targets;
    Ecore_X_Atom *atomlist;
+   Evas_Object *top;
    int i, j;
 
    targets = notify->data;
@@ -1420,6 +1471,13 @@ notify_handler_targets(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notif
           {
              if ((atoms[j].atom == atomlist[i]) && (atoms[j].notify))
                {
+#if 0
+                  if ((j == CNP_ATOM_text_uri) ||
+                      (j == CNP_ATOM_text_urilist))
+                    {
+                      if(!is_uri_type_data(sel, notify)) continue;
+                    }
+#endif
                   cnp_debug("Atom %s matches\n",atoms[j].name);
                   goto done;
                }
@@ -1430,8 +1488,10 @@ notify_handler_targets(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notif
    return ECORE_CALLBACK_PASS_ON;
 
 done:
-   cnp_debug("Sending request for %s\n",atoms[j].name);
-   sel->request(elm_win_xwindow_get(sel->requestwidget), atoms[j].name);
+   top = elm_widget_top_get(sel->requestwidget);
+   if (!top) top = sel->requestwidget;
+   cnp_debug("Sending request for %s\n", atoms[j].name);
+   sel->request(elm_win_xwindow_get(top), atoms[j].name);
 
    return ECORE_CALLBACK_PASS_ON;
 }
@@ -1474,6 +1534,69 @@ found:
    return 0;
 }
 
+static void
+entry_insert_filter(Evas_Object* entry, char* str)
+{
+   if (!entry || !str)
+     return;
+
+   char *insertStr = str;
+   // if entry has text only set then remove item tags
+   if (elm_entry_cnp_textonly_get(entry))
+     {
+        while (EINA_TRUE)
+          {
+             char *startTag = NULL;
+             char *endTag = NULL;
+
+             startTag = strstr(insertStr, "<item");
+             if (!startTag)
+               startTag = strstr(insertStr, "</item");
+             if (startTag)
+               endTag = strstr(startTag, ">");
+             else
+               break;
+             if (!endTag || startTag > endTag)
+               {
+                  cnp_debug("Broken tag: %s\n", str);
+                  break;
+               }
+
+             size_t sindex = startTag - insertStr;
+             size_t eindex = endTag - insertStr + 1;
+
+             Eina_Strbuf *buf = eina_strbuf_new();
+             if (buf)
+               {
+                  eina_strbuf_append(buf, insertStr);
+                  eina_strbuf_remove(buf, sindex, eindex);
+                  insertStr = eina_strbuf_string_steal(buf);
+                  eina_strbuf_free(buf);
+               }
+          }
+     }
+   cnp_debug("remove item tag: %s\n", insertStr);
+
+   // if entry has single line set then remove <br> & <ps> tags
+   if (elm_entry_single_line_get(entry))
+     {
+        Eina_Strbuf *buf = eina_strbuf_new();
+        if (buf)
+          {
+             eina_strbuf_append(buf, insertStr);
+             eina_strbuf_replace_all(buf, "<br>", "");
+             eina_strbuf_replace_all(buf, "<ps>", "");
+             insertStr = eina_strbuf_string_steal(buf);
+             eina_strbuf_free(buf);
+          }
+     }
+   cnp_debug("remove break tag: %s\n", insertStr);
+
+   elm_entry_entry_insert(entry, insertStr);
+
+   if (insertStr != str)
+     free(insertStr);
+}
 
 static int
 notify_handler_text(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
@@ -1486,8 +1609,8 @@ notify_handler_text(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
    if (sel->datacb)
      {
         Elm_Selection_Data ddata;
-        
-        str = mark_up((char *)data->data, data->length, NULL);
+
+        str = strdup(data->data);
         ddata.x = ddata.y = 0;
         ddata.format = ELM_SEL_FORMAT_TEXT;
         ddata.data = str;
@@ -1496,11 +1619,12 @@ notify_handler_text(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
         free(str);
         return 0;
      }
-   
+
    cnp_debug("Notify handler text %d %d %p\n", data->format,data->length, data->data);
    str = mark_up((char *)data->data, data->length, NULL);
    cnp_debug("String is %s (from %s)\n", str, data->data);
-   elm_entry_entry_insert(sel->requestwidget, str);
+   entry_insert_filter(sel->requestwidget, str);
+   //elm_entry_entry_insert(sel->requestwidget, str);
    free(str);
    return 0;
 }
@@ -1515,7 +1639,7 @@ notify_handler_uri(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
    Ecore_X_Selection_Data *data;
    Ecore_X_Selection_Data_Files *files;
    Paste_Image *pi;
-   char *p;
+   char *p, *stripstr;
 
    data = notify->data;
    cnp_debug("data->format is %d %p %p\n", data->format, notify, data);
@@ -1529,11 +1653,11 @@ notify_handler_uri(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
              cnp_debug("more then one file: Bailing\n");
              return 0;
           }
-        p = files->files[0];
+        stripstr = p = strdup(files->files[0]);
      }
    else
      {
-        p = (char *)data->data;
+        stripstr = p = strndup((char *)data->data, data->length);
      }
 
    if (!p)
@@ -1545,18 +1669,23 @@ notify_handler_uri(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
    if (sel->datacb)
      {
         Elm_Selection_Data ddata;
-        
+
         ddata.x = ddata.y = 0;
         ddata.format = ELM_SEL_FORMAT_MARKUP;
         ddata.data = p;
         ddata.len = data->length;
         sel->datacb(sel->udata, sel->widget, &ddata);
+        free(p);
         return 0;
      }
    if (strncmp(p, "file://", 7))
      {
         /* Try and continue if it looks sane */
-        if (*p != '/') return 0;
+        if (*p != '/')
+          {
+             free(p);
+             return 0;
+          }
      }
    else
      {
@@ -1575,6 +1704,7 @@ notify_handler_uri(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
         pasteimage_append(pi, sel->requestwidget);
         savedtypes.pi = NULL;
      }
+   free(stripstr);
    return 0;
 }
 
@@ -1694,12 +1824,14 @@ notify_handler_edje(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
         sel->datacb(sel->udata, sel->widget, &ddata);
      }
    else
-     elm_entry_entry_insert(sel->requestwidget, stripstr);
+     entry_insert_filter(sel->requestwidget, stripstr);
+     //elm_entry_entry_insert(sel->requestwidget, stripstr);
 
    cnp_debug("String is %s (%d bytes)\n", stripstr, data->length);
    free(stripstr);
    return 0;
 }
+
 /**
  *    Warning: Generic text/html can';t handle it sanely.
  *    Firefox sends ucs2 (i think).
@@ -1728,7 +1860,8 @@ notify_handler_html(Cnp_Selection *sel, Ecore_X_Event_Selection_Notify *notify)
         sel->datacb(sel->udata, sel->widget, &ddata);
      }
    else
-     elm_entry_entry_insert(sel->requestwidget, stripstr);
+     entry_insert_filter(sel->requestwidget, stripstr);
+     //elm_entry_entry_insert(sel->requestwidget, stripstr);
 
    cnp_debug("String is %s (%d bytes)\n", stripstr, data->length);
    free(stripstr);
@@ -1776,7 +1909,12 @@ edje_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **
    if (size_ret) *size_ret = strlen(sel->selbuf);*/
    char *edje = NULL;
 
-   if (data_ret && (sel->format & ELM_SEL_FORMAT_HTML))
+   if (data_ret && (sel->format == ELM_SEL_FORMAT_TEXT))
+     {
+        if (sel->selbuf && sel->selbuf[0] != '\0')
+          edje = mark_up(sel->selbuf, strlen(sel->selbuf), NULL);
+     }
+   else if (data_ret && ((sel->format & ELM_SEL_FORMAT_HTML)))
      {
         Eina_List *nodeList = NULL;
         Eina_List *trail;
@@ -1811,14 +1949,20 @@ edje_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **
         if (edje)
           *data_ret = edje;
         else
-          *data_ret = strdup(sel->selbuf);
+           if (sel->selbuf)
+             *data_ret = strdup(sel->selbuf);
+           else
+             *data_ret = strdup("");
      }
    if (size_ret)
      {
         if (edje)
           *size_ret = strlen(edje);
         else
-          *size_ret = strlen(sel->selbuf);
+          if (sel->selbuf)
+            *size_ret = strlen(sel->selbuf);
+          else
+            *size_ret = 0;
      }
 
    return EINA_TRUE;
@@ -1832,13 +1976,25 @@ html_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **
    sel = selections + *(int *)data;
 
    char *html = NULL;
-   if (data_ret && (sel->format & ELM_SEL_FORMAT_MARKUP))
+   char *convert_target = sel->selbuf;
+   Eina_Bool convert_edje = EINA_FALSE;
+
+   if (data_ret && (sel->format == ELM_SEL_FORMAT_TEXT))
+     {
+        if (sel->selbuf && sel->selbuf[0] != '\0')
+          {
+             convert_target = mark_up(sel->selbuf, strlen(sel->selbuf), NULL);
+             convert_edje = EINA_TRUE;
+          }
+     }
+
+   if (data_ret && ((sel->format & ELM_SEL_FORMAT_MARKUP) || convert_edje))
      {
         Eina_List *nodeList = NULL;
         Eina_List *trail;
         PTagNode nodeData;
 
-        nodeData = _get_start_node(sel->selbuf);
+        nodeData = _get_start_node(convert_target);
 
         while (nodeData)
           {
@@ -1866,7 +2022,10 @@ html_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **
         if (html)
           *data_ret = html;
         else
-          *data_ret = strdup(sel->selbuf);
+          if (sel->selbuf)
+            *data_ret = strdup(sel->selbuf);
+          else
+            *data_ret = strdup("");
      }
 
    if (size_ret)
@@ -1874,8 +2033,13 @@ html_converter(char *target __UNUSED__, void *data, int size __UNUSED__, void **
         if (html)
           *size_ret = strlen(html);
         else
-          *size_ret = strlen(sel->selbuf);
+          if (sel->selbuf)
+            *size_ret = strlen(sel->selbuf);
+          else
+            *size_ret = 0;
      }
+   if (convert_target != sel->selbuf)
+     free(convert_target);
 
    return EINA_TRUE;
 }
@@ -1998,6 +2162,7 @@ pasteimage_append(Paste_Image *pi, Evas_Object *entry)
 
    if (!pi) return EINA_FALSE;
    if (!entry) return EINA_FALSE;
+   if (elm_entry_cnp_textonly_get(entry)) return EINA_FALSE;
 
    pasteimage_provider_set(entry);
 
@@ -2097,7 +2262,7 @@ mark_up(const char *start, int inlen, int *lenp)
    q = ret = malloc(l + 1);
 
    /* Second pass: Change characters */
-   for (p = start; *p; )
+   for (p = start; ((!endp) || (p < endp)) && (*p); )
      {
         for (i = 0; i < N_ESCAPES; i++)
           {
@@ -2144,6 +2309,7 @@ _dnd_enter(void *data __UNUSED__, int etype __UNUSED__, void *ev)
              /* Request it, so we know what it is */
              cnp_debug("Sending uri request\n");
              savedtypes.textreq = 1;
+             if (savedtypes.pi) pasteimage_free(savedtypes.pi);
              savedtypes.pi = NULL; /* FIXME: Free? */
              ecore_x_selection_xdnd_request(enter->win, text_uri);
           }
@@ -2252,6 +2418,9 @@ found:
                   cnp_debug("Insert %s\n", (char *)ddata.data);
                   dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
                   ecore_x_dnd_send_finished();
+
+                  if (savedtypes.pi) pasteimage_free(savedtypes.pi);
+                  savedtypes.pi = NULL;
                   return EINA_TRUE;
                }
              else if (dropable->types & ELM_SEL_FORMAT_IMAGE)
@@ -2262,7 +2431,7 @@ found:
                   dropable->dropcb(dropable->cbdata, dropable->obj, &ddata);
                   ecore_x_dnd_send_finished();
 
-                  pasteimage_free(savedtypes.pi);
+                  if (savedtypes.pi) pasteimage_free(savedtypes.pi);
                   savedtypes.pi = NULL;
 
                   return EINA_TRUE;
@@ -2553,7 +2722,6 @@ elm_cnp_tempfile_create(int size)
 
    tmppath = getenv("TMP");
    if (!tmppath) tmppath = P_tmpdir;
-   if (!tmppath) tmppath = "/tmp";
    len = snprintf(NULL, 0, "%s/%sXXXXXX", tmppath, "elmcnpitem-");
    if (len < 0)
      {
@@ -2610,6 +2778,8 @@ elm_cnp_tempfile_create(int size)
         return info;
      }
 
+   eina_mmap_safety_enabled_set(EINA_TRUE);
+
    info->map = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, info->fd, 0);
    if (info->map == MAP_FAILED)
      {