elm_image: add support for url.
authorCedric Bail <cedric.bail@samsung.com>
Fri, 9 Aug 2013 12:12:29 +0000 (21:12 +0900)
committerCedric Bail <cedric.bail@samsung.com>
Fri, 9 Aug 2013 12:13:15 +0000 (21:13 +0900)
ChangeLog
NEWS
src/bin/test.c
src/bin/test_image.c
src/lib/Makefile.am
src/lib/elm_image.c
src/lib/elm_image_common.h
src/lib/elm_priv.h
src/lib/elm_url.c [new file with mode: 0644]
src/lib/elm_widget_image.h

index 052bd6c73eb71b8aa51328e11c13acc9479b936a..00d6f9a3576bccff0f7912e349371ae6b0bff0d0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
 
         * Fix elm to use key not keyname (otherwise xmodmap and friends
         don't work).
+
+2013-08-09  Cedric Bail
+
+       * Add support for URL in Elm_Image.
diff --git a/NEWS b/NEWS
index ab0d98276f81314ca59e579e2544b43018fc0ac2..d639c3c462b2cd5ecc56e2a5ff20bf2bb2706ed1 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -124,6 +124,7 @@ Improvements:
    * Move cursor when mouse moves with longpress.
    * Show magnifier when selection handlers are pressed or moved.
    * Change the method to calculate a distance which be scrolled from linear to sine curve.
+   * Add support for URL in Elm_Image.
 
 Fixes:
    * Now elm_datetime_field_limit_set() can set year limits wihtout problems.
index 0e2c712155cea7f772de62d1c20c7e4372921536..8e0fddff432e1c391ba1fd41447768a4330a716f 100644 (file)
@@ -204,6 +204,7 @@ void test_datetime(void *data, Evas_Object *obj, void *event_info);
 void test_popup(void *data, Evas_Object *obj, void *event_info);
 void test_dayselector(void *data, Evas_Object *obj, void *event_info);
 void test_image(void *data, Evas_Object *obj, void *event_info);
+void test_remote_image(void *data, Evas_Object *obj, void *event_info);
 void test_external_button(void *data, Evas_Object *obj, void *event_info);
 void test_external_slider(void *data, Evas_Object *obj, void *event_info);
 void test_external_scroller(void *data, Evas_Object *obj, void *event_info);
@@ -528,6 +529,7 @@ add_tests:
    ADD_TEST(NULL, "Images", "Photo", test_photo);
    ADD_TEST(NULL, "Images", "Thumb", test_thumb);
    ADD_TEST(NULL, "Images", "Image", test_image);
+   ADD_TEST(NULL, "Images", "Image Remote", test_remote_image);
    ADD_TEST(NULL, "Images", "Slideshow", test_slideshow);
 #ifdef HAVE_EMOTION
    ADD_TEST(NULL, "Images", "Video", test_video);
index 4809a6423cfe40ab76cf77d1acacdfab3649ea4c..253dda1464716644c3c41a0b7e14380ab189d2de 100644 (file)
@@ -83,4 +83,54 @@ test_image(void *data __UNUSED__, Evas_Object *obj  __UNUSED__, void *event_info
    evas_object_resize(win, 320, 480);
    evas_object_show(win);
 }
+
+void
+test_remote_image(void *data __UNUSED__, Evas_Object *obj  __UNUSED__, void *event_info __UNUSED__)
+{
+   Evas_Object *win, *box, *im, *rd, *rdg = NULL;
+   int i;
+
+   win = elm_win_util_standard_add("image test", "Image Test");
+   elm_win_autodel_set(win, EINA_TRUE);
+
+   box = elm_box_add(win);
+   evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(win, box);
+   evas_object_show(box);
+
+   im = elm_image_add(win);
+   elm_image_file_set(im, "http://31.media.tumblr.com/29f1ecd4f98aaff73fb21f479b450d4c/tumblr_mqsxdciQmB1rrju89o1_1280.jpg", NULL);
+   elm_image_resizable_set(im, EINA_TRUE, EINA_TRUE);
+   evas_object_size_hint_weight_set(im, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(im, EVAS_HINT_FILL, EVAS_HINT_FILL);
+
+   elm_box_pack_end(box, im);
+   evas_object_show(im);
+
+   evas_object_data_set(win, "im", im);
+
+   for (i = 0; images_orient[i].name; ++i)
+     {
+        rd = elm_radio_add(win);
+        evas_object_size_hint_align_set(rd, EVAS_HINT_FILL, EVAS_HINT_FILL);
+        evas_object_size_hint_weight_set(rd, EVAS_HINT_EXPAND, 0.0);
+        elm_radio_state_value_set(rd, images_orient[i].orient);
+        elm_object_text_set(rd, images_orient[i].name);
+        elm_box_pack_end(box, rd);
+        evas_object_show(rd);
+        evas_object_smart_callback_add(rd, "changed", my_im_ch, win);
+        if (!rdg)
+          {
+             rdg = rd;
+             evas_object_data_set(win, "rdg", rdg);
+          }
+        else
+          {
+             elm_radio_group_add(rd, rdg);
+          }
+     }
+
+   evas_object_resize(win, 320, 480);
+   evas_object_show(win);
+}
 #endif
index 559a459b7d69042410dfdc02b4fc1dc49896c2ad..e87794b46a6753d191a9295ca045332c7586476e 100644 (file)
@@ -463,6 +463,7 @@ elm_thumb.c \
 elm_toolbar.c \
 elm_transit.c \
 elm_util.c \
+elm_url.c \
 elm_video.c \
 elm_web.c \
 elm_web2.c \
index da0ca256b9db737db0fd44af17d6dbf95d016a2c..5e3a0c7c7b7bd5fdec30e05941a0206ae5354f29 100644 (file)
@@ -16,9 +16,17 @@ EAPI Eo_Op ELM_OBJ_IMAGE_BASE_ID = EO_NOOP;
 
 static const char SIG_DND[] = "drop";
 static const char SIG_CLICKED[] = "clicked";
+static const char SIG_DOWNLOAD_START[] = "download,start";
+static const char SIG_DOWNLOAD_PROGRESS[] = "download,progress";
+static const char SIG_DOWNLOAD_DONE[] = "download,done";
+static const char SIG_DOWNLOAD_ERROR[] = "download,error";
 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
    {SIG_DND, ""},
    {SIG_CLICKED, ""},
+   {SIG_DOWNLOAD_START, ""},
+   {SIG_DOWNLOAD_PROGRESS, ""},
+   {SIG_DOWNLOAD_DONE, ""},
+   {SIG_DOWNLOAD_ERROR, ""},
    {NULL, NULL}
 };
 
@@ -183,6 +191,7 @@ _elm_image_internal_sizing_eval(Evas_Object *obj, Elm_Image_Smart_Data *sd)
 static Eina_Bool
 _elm_image_edje_file_set(Evas_Object *obj,
                          const char *file,
+                         Eina_File *f,
                          const char *group)
 {
    Evas_Object *pclip;
@@ -207,7 +216,16 @@ _elm_image_edje_file_set(Evas_Object *obj,
      }
 
    sd->edje = EINA_TRUE;
-   if (!edje_object_file_set(sd->img, file, group))
+   if (f)
+     {
+        if (!edje_object_mmap_set(sd->img, f, group))
+          {
+             ERR("failed to set edje file '%s', group '%s': %s", file, group,
+                 edje_load_error_str(edje_object_load_error_get(sd->img)));
+             return EINA_FALSE;
+          }
+     }
+   else if (!edje_object_file_set(sd->img, file, group))
      {
         ERR("failed to set edje file '%s', group '%s': %s", file, group,
             edje_load_error_str(edje_object_load_error_get(sd->img)));
@@ -480,6 +498,9 @@ _elm_image_smart_del(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
    if (sd->anim_timer) ecore_timer_del(sd->anim_timer);
    if (sd->img) evas_object_del(sd->img);
    if (sd->prev_img) evas_object_del(sd->prev_img);
+   if (sd->remote) elm_url_cancel(sd->remote);
+   free(sd->remote_data);
+   eina_stringshare_del(sd->key);
 
    eo_do_super(obj, MY_CLASS, evas_obj_smart_del());
 }
@@ -810,26 +831,24 @@ elm_image_file_set(Evas_Object *obj,
 }
 
 static void
-_elm_image_smart_file_set(Eo *obj, void *_pd, va_list *list)
+_elm_image_smart_internal_file_set(Eo *obj, Elm_Image_Smart_Data *sd,
+                                   const char *file, Eina_File *f, const char *key, Eina_Bool *ret)
 {
-   const char *file = va_arg(*list, const char *);
-   const char *key = va_arg(*list, const char *);
-   Eina_Bool *ret = va_arg(*list, Eina_Bool *);
-
    Evas_Coord w, h;
 
-   Elm_Image_Smart_Data *sd = _pd;
-
    if (eina_str_has_extension(file, ".edj"))
      {
-        Eina_Bool int_ret = _elm_image_edje_file_set(obj, file, key);
+        Eina_Bool int_ret = _elm_image_edje_file_set(obj, file, f, key);
         if (ret) *ret = int_ret;
         return;
      }
 
    _elm_image_file_set_do(obj);
 
-   evas_object_image_file_set(sd->img, file, key);
+   if (f)
+     evas_object_image_mmap_set(sd->img, f, key);
+   else
+     evas_object_image_file_set(sd->img, file, key);
 
    sd->preloading = EINA_TRUE;
    evas_object_hide(sd->img);
@@ -849,6 +868,108 @@ _elm_image_smart_file_set(Eo *obj, void *_pd, va_list *list)
    _elm_image_internal_sizing_eval(obj, sd);
 
    if (ret) *ret = EINA_TRUE;
+}                                  
+
+static void
+_elm_image_smart_download_done(void *data, Elm_Url *url EINA_UNUSED, Eina_Binbuf *download)
+{
+   Eo *obj = data;
+   Elm_Image_Smart_Data *sd = eo_data_scope_get(obj, MY_CLASS);
+   Eina_File *f;
+   size_t length;
+   Eina_Bool ret = EINA_FALSE;
+
+   if (sd->remote_data) free(sd->remote_data);
+   length = eina_binbuf_length_get(download);
+   sd->remote_data = eina_binbuf_string_steal(download);
+   f = eina_file_virtualize(elm_url_get(url),
+                            sd->remote_data, length,
+                            EINA_FALSE);
+   _elm_image_smart_internal_file_set(obj, sd, elm_url_get(url), f, sd->key, &ret);
+   eina_file_close(f);
+
+   if (!ret)
+     {
+        Elm_Image_Error err = { 0, EINA_TRUE };
+
+        free(sd->remote_data);
+        sd->remote_data = NULL;
+        evas_object_smart_callback_call(obj, SIG_DOWNLOAD_ERROR, &err);
+     }
+   else
+     {
+        evas_object_smart_callback_call(obj, SIG_DOWNLOAD_DONE, NULL);
+     }
+
+   sd->remote = NULL;
+   eina_stringshare_del(sd->key);
+   sd->key = NULL;
+}
+
+static void
+_elm_image_smart_download_cancel(void *data, Elm_Url *url EINA_UNUSED, int error)
+{
+   Eo *obj = data;
+   Elm_Image_Smart_Data *sd = eo_data_scope_get(obj, MY_CLASS);
+   Elm_Image_Error err = { error, EINA_FALSE };
+
+   evas_object_smart_callback_call(obj, SIG_DOWNLOAD_ERROR, &err);
+
+   sd->remote = NULL;
+   eina_stringshare_del(sd->key);
+   sd->key = NULL;
+}
+
+static void
+_elm_image_smart_download_progress(void *data, Elm_Url *url EINA_UNUSED, double now, double total)
+{
+   Eo *obj = data;
+   Elm_Image_Progress progress;
+
+   progress.now = now;
+   progress.total = total;
+   evas_object_smart_callback_call(obj, SIG_DOWNLOAD_PROGRESS, &progress);
+}
+
+static const char *remote_uri[] = {
+  "http://", "https://", "ftp://"
+};
+
+static void
+_elm_image_smart_file_set(Eo *obj, void *_pd, va_list *list)
+{
+   const char *file = va_arg(*list, const char *);
+   const char *key = va_arg(*list, const char *);
+   Eina_Bool *ret = va_arg(*list, Eina_Bool *);
+
+   Elm_Image_Smart_Data *sd = _pd;
+
+   unsigned int i;
+
+   if (sd->remote) elm_url_cancel(sd->remote);
+   sd->remote = NULL;
+
+   for (i = 0; i < sizeof (remote_uri) / sizeof (remote_uri[0]); ++i)
+     if (strncmp(remote_uri[i], file, strlen(remote_uri[i])) == 0)
+       {
+          // Found a remote target !
+          evas_object_hide(sd->img);
+          sd->remote = elm_url_download(file,
+                                        _elm_image_smart_download_done,
+                                        _elm_image_smart_download_cancel,
+                                        _elm_image_smart_download_progress,
+                                        obj);
+          if (sd->remote)
+            {
+               evas_object_smart_callback_call(obj, SIG_DOWNLOAD_START, NULL);
+               eina_stringshare_replace(&sd->key, key);
+               if (ret) *ret = EINA_TRUE;
+               return ;
+            }
+          break;
+       }
+
+   _elm_image_smart_internal_file_set(obj, sd, file, NULL, key, ret);
 }
 
 EAPI void
index 7651927c7b8ddc3bd200346f852f92846926e8a8..6de250cbb3c4f834e3969f11881fa691b104b81b 100644 (file)
@@ -19,4 +19,27 @@ typedef enum
    ELM_IMAGE_FLIP_TRANSVERSE = 7 /**< flip the image along the y = x line (top-left to bottom-right) */
 } Elm_Image_Orient;
 
+/**
+ * Structure associated with smart callback 'download,progress'.
+ * @since 1.8
+ */
+typedef struct _Elm_Image_Progress Elm_Image_Progress;
+
+struct _Elm_Image_Progress
+{
+   double now;
+   double total;
+};
+
+
+/**
+ * Structre associated with smart callback 'download,error'
+ * @since 1.8
+ */
+typedef struct _Elm_Image_Error Elm_Image_Error;
+struct _Elm_Image_Error
+{
+   int status;
 
+   Eina_Bool open_error;
+};
index 212e2ef7f24c5b5c4f4bcc53d8d4f6f592e81a73..6d78e8ab94ef548dc328fc9a56f6302b8b5f9d95 100644 (file)
@@ -450,6 +450,18 @@ void                *_elm_icon_signal_callback_del(Evas_Object *obj,
                                                    Edje_Signal_Cb func_cb);
 /* end of DEPRECATED */
 
+
+/* Elm helper to download content */
+typedef struct _Elm_Url Elm_Url;
+
+typedef void (*Elm_Url_Done)(void *data, Elm_Url *url, Eina_Binbuf *download);
+typedef void (*Elm_Url_Cancel)(void *data, Elm_Url *url, int error);
+typedef void (*Elm_Url_Progress)(void *data, Elm_Url *url, double now, double total);
+
+Elm_Url *elm_url_download(const char *url, Elm_Url_Done done_cb, Elm_Url_Cancel cancel_cb, Elm_Url_Progress progress_cb, const void *data);
+void elm_url_cancel(Elm_Url *r);
+const char *elm_url_get(Elm_Url *r);
+
 extern char *_elm_appname;
 extern Elm_Config *_elm_config;
 extern const char *_elm_data_dir;
diff --git a/src/lib/elm_url.c b/src/lib/elm_url.c
new file mode 100644 (file)
index 0000000..2d74561
--- /dev/null
@@ -0,0 +1,147 @@
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#include <Elementary.h>
+#include "elm_priv.h"
+
+struct _Elm_Url
+{
+   const char *url;
+
+   struct {
+      Elm_Url_Done done;
+      Elm_Url_Cancel cancel;
+      Elm_Url_Progress progress;
+   } cb;
+
+   const void *data;
+
+   Ecore_Con_Url *target;
+   Eina_Binbuf *download;
+
+   struct {
+      Ecore_Event_Handler *progress;
+      Ecore_Event_Handler *done;
+      Ecore_Event_Handler *data;
+   } handler;
+};
+
+static void
+_elm_url_free(Elm_Url *r)
+{
+   ecore_con_url_free(r->target);
+   eina_binbuf_free(r->download);
+   ecore_event_handler_del(r->handler.progress);
+   ecore_event_handler_del(r->handler.done);
+   ecore_event_handler_del(r->handler.data);
+   eina_stringshare_del(r->url);
+   free(r);
+}
+
+static Eina_Bool
+_elm_url_progress(void *data, int type EINA_UNUSED, void *event)
+{
+   Ecore_Con_Event_Url_Progress *url_progress = event;
+   Elm_Url *r = data;
+
+   if (url_progress->url_con != r->target) return EINA_TRUE;
+
+   r->cb.progress((void*) r->data, r, url_progress->down.now, url_progress->down.total);
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_elm_url_done(void *data, int type EINA_UNUSED, void *event)
+{
+   Ecore_Con_Event_Url_Complete *url_complete = event;
+   Elm_Url *r = data;
+
+   if (url_complete->url_con != r->target) return EINA_TRUE;
+
+   if (url_complete->status == 200)
+     {
+        r->cb.done((void*) r->data, r, r->download);
+     }
+   else
+     {
+        r->cb.cancel((void*) r->data, r, url_complete->status);
+     }
+
+   _elm_url_free(r);
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_elm_url_data(void *data, int type EINA_UNUSED, void *event)
+{
+   Ecore_Con_Event_Url_Data *url_data = event;
+   Elm_Url *r = data;
+
+   if (url_data->url_con != r->target) return EINA_TRUE;
+
+   eina_binbuf_append_length(r->download, url_data->data, url_data->size);
+     
+   return EINA_TRUE;
+}
+
+Elm_Url *
+elm_url_download(const char *url, Elm_Url_Done done_cb, Elm_Url_Cancel cancel_cb, Elm_Url_Progress progress_cb, const void *data)
+{
+   Ecore_Con_Url *target;
+   Elm_Url *r;
+
+   ecore_con_url_init();
+
+   target = ecore_con_url_new(url);
+   if (!target) goto on_error;
+
+   if (getenv("http_proxy")) ecore_con_url_proxy_set(target, getenv("http_proxy"));
+   if (getenv("https_proxy")) ecore_con_url_proxy_set(target, getenv("https_proxy"));
+   if (getenv("ftp_proxy")) ecore_con_url_proxy_set(target, getenv("ftp_proxy"));
+
+   r = malloc(sizeof (Elm_Url));
+   if (!r) goto on_error;
+
+   r->url = eina_stringshare_add(url);
+   r->cb.done = done_cb;
+   r->cb.cancel = cancel_cb;
+   r->cb.progress = progress_cb;
+   r->data = data;
+
+   r->download = eina_binbuf_new();
+   r->target = target;
+   r->handler.progress = ecore_event_handler_add(ECORE_CON_EVENT_URL_PROGRESS, _elm_url_progress, r);
+   r->handler.done = ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, _elm_url_done, r);
+   r->handler.data = ecore_event_handler_add(ECORE_CON_EVENT_URL_DATA, _elm_url_data, r);
+
+   if (!ecore_con_url_get(r->target))
+     {
+       _elm_url_free(r);
+       cancel_cb((void*) data, NULL, -1);
+       return NULL;
+     }
+
+   return r;
+
+ on_error:
+   ecore_con_url_shutdown();
+
+   cancel_cb((void*) data, NULL, -1);
+   return NULL;
+}
+
+void
+elm_url_cancel(Elm_Url *r)
+{
+   r->cb.cancel((void*) r->data, r, 0);
+   _elm_url_free(r);
+}
+
+const char *
+elm_url_get(Elm_Url *r)
+{
+   return r->url;
+}
index cb4b11e8b9c9fc3ef4b0922e47a0e7c3562f27d9..16ec392398cd85b92574ab304fa85a5606e5c2df 100644 (file)
@@ -33,6 +33,10 @@ struct _Elm_Image_Smart_Data
    Evas_Object          *prev_img;
    Ecore_Timer          *anim_timer;
 
+   Elm_Url              *remote;
+   const char           *key;
+   void                 *remote_data;
+
    double                scale;
    double                frame_duration;