Initial Import
[profile/ivi/clutter-toys.git] / attic / aaina / sources / aaina-source-flickr.c
1 /*
2 * Authored By Neil Jagdish Patel <njp@o-hand.com>
3  *
4  * Copyright (C) 2007 OpenedHand
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include <libaaina/aaina-photo.h>
23 #include <libnflick/nflick-photo-search-worker.h>
24 #include <libnflick/nflick-info-worker.h>
25 #include <libnflick/nflick.h>
26 #include "aaina-source-flickr.h"
27
28 G_DEFINE_TYPE (AainaSourceFlickr, aaina_source_flickr, AAINA_TYPE_SOURCE);
29
30 #define AAINA_SOURCE_FLICKR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
31         AAINA_TYPE_SOURCE_FLICKR, \
32         AainaSourceFlickrPrivate))
33
34 #define CHECK_TIMEOUT 60000
35 #define MAX_PHOTOS 100
36
37 struct _AainaSourceFlickrPrivate
38 {
39   AainaLibrary *library;
40   gchar        *tags;
41
42   /* table of already downloaded photos */
43   GHashTable   *table;
44
45   /* Queue of photos to download */
46   GQueue       *queue;
47   gboolean      running;
48   NFlickWorker *pix_worker;
49
50   AainaPhoto   *current;
51
52   NFlickWorker *worker;
53
54   /* Queue of photos to add to library */
55   GQueue       *add_queue;
56   gboolean      add_running;
57 };
58
59 static GQuark   worker_quark = 0;
60
61 static gboolean get_photos (AainaSourceFlickr *source);
62 static gboolean get_pixbuf (AainaSourceFlickr *source);
63
64
65 static gboolean
66 on_info_thread_abort (AainaPhoto *photo)
67 {
68   g_print ("abort\n");
69   return FALSE;
70 }
71
72 static gboolean
73 on_info_thread_error (AainaPhoto *photo)
74 {
75   NFlickWorker *worker;
76   worker = (NFlickWorker*)g_object_get_qdata (G_OBJECT (photo), worker_quark);
77   gchar *error = NULL;
78
79   g_object_get (G_OBJECT (worker), "error", &error, NULL);
80   if (error)
81   {
82     g_warning ("%s\n", error);
83   }
84   else
85     g_print ("error\n");
86   g_object_unref (G_OBJECT (worker)); 
87   
88   return FALSE;
89 }
90
91 static gboolean
92 on_info_thread_ok (AainaPhoto *photo)
93 {
94   NFlickWorker *worker;
95   gchar *rotation = NULL;
96   gint rot;
97   gchar *realname = NULL;
98   gchar *desc = NULL;
99
100   worker = (NFlickWorker*)g_object_get_qdata (G_OBJECT (photo), worker_quark);
101     
102   nflick_info_worker_get ((NFlickInfoWorker*)worker,
103                           &rotation,
104                           &realname,
105                           &desc);
106   /* find the rotation */
107   rot = atoi (rotation);
108   
109   if (!realname)
110     g_object_get (G_OBJECT (photo), "author", &realname, NULL);
111   g_object_set (G_OBJECT (photo),
112                 "rotation", rot,
113                 "author", realname,
114                 "desc", desc,
115                 NULL);
116
117   g_object_unref (G_OBJECT (worker));  
118   return FALSE;
119 }
120
121 static void
122 manage_queue (AainaSourceFlickr *source)
123 {
124   AainaSourceFlickrPrivate *priv;
125   
126   g_return_if_fail (AAINA_IS_SOURCE_FLICKR (source));
127   priv = source->priv;
128
129   /* Now we do the work for the next one */
130   if (g_queue_get_length (priv->queue))
131   {
132     priv->current = AAINA_PHOTO (g_queue_pop_head (priv->queue));
133     g_timeout_add (100, (GSourceFunc)get_pixbuf, (gpointer)source);
134
135     priv->running = TRUE;
136     aaina_library_set_pending (priv->library, TRUE);
137   }
138   else
139   {
140     priv->running = FALSE;
141     aaina_library_set_pending (priv->library, FALSE);
142   }
143
144 }
145
146 static gboolean
147 on_pixbuf_thread_abort (AainaSourceFlickr *source)
148 {
149   g_print ("abort\n");
150   manage_queue (source);
151
152   return FALSE;
153 }
154
155 static gboolean
156 on_pixbuf_thread_error (AainaSourceFlickr *source)
157 {
158   AainaSourceFlickrPrivate *priv;
159   gchar *error = NULL;
160
161   g_return_val_if_fail (AAINA_IS_SOURCE_FLICKR (source), FALSE);
162   priv = source->priv;
163
164   g_object_get (G_OBJECT (priv->pix_worker), "error", &error, NULL);
165   if (error)
166   {
167     g_warning ("%s\n", error);
168   }
169   else
170     g_print ("error\n");
171
172   manage_queue (source);
173   return FALSE;
174 }
175
176 static gboolean
177 add_to_library (AainaSourceFlickr *source)
178 {
179   AainaSourceFlickrPrivate *priv;
180   AainaPhoto *photo = NULL;
181
182   g_return_val_if_fail (AAINA_IS_SOURCE (source), FALSE);
183   priv = source->priv;
184
185   if (aaina_library_is_full (priv->library))
186   {
187     aaina_library_set_pending (priv->library, TRUE);
188     return TRUE;
189   }
190   photo = AAINA_PHOTO (g_queue_pop_head (priv->add_queue));
191
192   if (photo)
193   {
194     aaina_library_append_photo (priv->library, (gpointer)photo);
195     return TRUE;
196   }
197   else
198   {
199     aaina_library_set_pending (priv->library, FALSE);
200     priv->add_running = FALSE;
201     return FALSE;
202   }
203 }
204
205 static gboolean
206 on_pixbuf_thread_ok (AainaSourceFlickr *source)
207 {
208
209   AainaSourceFlickrPrivate *priv;
210   GdkPixbuf *pixbuf;
211   
212   g_return_val_if_fail (AAINA_IS_SOURCE_FLICKR (source), FALSE);
213   priv = source->priv;
214
215   g_object_get (G_OBJECT (priv->pix_worker), "pixbuf", &pixbuf, NULL);
216
217   /* Set the current photo's pixbuf and add it to the library */
218   if (pixbuf)
219   {
220     aaina_photo_set_pixbuf (priv->current, pixbuf);
221
222     if (priv->add_running || aaina_library_is_full (priv->library))
223     {
224       g_queue_push_tail (priv->add_queue, (gpointer)priv->current);
225
226       if (!priv->add_running)
227       {
228         g_timeout_add (1000, (GSourceFunc)add_to_library, (gpointer)source);
229         priv->add_running = TRUE;
230         aaina_library_set_pending (priv->library, TRUE);
231       }
232     }
233     else
234       aaina_library_append_photo (priv->library, priv->current);
235
236     priv->current = NULL;
237   }
238  
239   manage_queue (source);
240
241   static gint i = 0;
242   i++;
243   return FALSE;
244 }
245
246 static gboolean
247 get_pixbuf (AainaSourceFlickr *source)
248 {
249
250   AainaSourceFlickrPrivate *priv;
251   NFlickWorker *worker;
252   AainaPhoto *photo;
253   gchar *id;
254
255   g_return_val_if_fail (AAINA_IS_SOURCE_FLICKR (source), FALSE);
256   priv = source->priv;
257
258   if (priv->current == NULL)
259     return FALSE;
260
261   photo = priv->current;
262   g_object_get (G_OBJECT (photo), "id", &id, NULL);
263
264   worker = (NFlickWorker*)nflick_show_worker_new (id,
265                                                   CLUTTER_STAGE_WIDTH ()/2,
266                                                   CLUTTER_STAGE_HEIGHT ()/2,
267                                                   " ");
268   if (G_IS_OBJECT (priv->pix_worker))
269     g_object_unref (G_OBJECT (priv->pix_worker));
270   priv->pix_worker = worker;
271
272   nflick_worker_set_custom_data (worker, source);
273   nflick_worker_set_aborted_idle (worker, 
274                                   (NFlickWorkerIdleFunc)on_pixbuf_thread_abort);
275   nflick_worker_set_error_idle (worker, 
276                                 (NFlickWorkerIdleFunc)on_pixbuf_thread_error);
277   nflick_worker_set_ok_idle (worker,
278                              (NFlickWorkerIdleFunc)on_pixbuf_thread_ok);
279   
280   nflick_worker_start (worker);  
281
282
283   worker = (NFlickWorker*)nflick_info_worker_new (id, 22, 22, " ");
284   nflick_worker_start (worker);
285
286   priv->running = TRUE;
287   
288   nflick_worker_set_custom_data (worker, photo);
289   nflick_worker_set_aborted_idle (worker, 
290                                   (NFlickWorkerIdleFunc)on_info_thread_abort);
291   nflick_worker_set_error_idle (worker, 
292                                 (NFlickWorkerIdleFunc)on_info_thread_error);
293   nflick_worker_set_ok_idle (worker,
294                              (NFlickWorkerIdleFunc)on_info_thread_ok);
295
296   g_object_set_qdata (G_OBJECT (photo), worker_quark, (gpointer)worker);
297
298
299   return FALSE;
300 }
301
302
303 static gboolean
304 on_thread_abort (AainaSourceFlickr *source)
305 {
306   g_print ("abort\n");
307   return FALSE;
308 }
309
310 static gboolean
311 on_thread_error (AainaSourceFlickr *source)
312 {
313   g_print ("error\n");
314   return FALSE;
315 }
316
317 static gboolean
318 on_thread_ok (AainaSourceFlickr *source)
319 {
320   AainaSourceFlickrPrivate *priv;
321   GList *list = NULL, *l;
322
323   g_return_val_if_fail (AAINA_IS_SOURCE_FLICKR (source), FALSE);
324   priv = source->priv;
325
326   /* Grab the list of photos from the worker */
327   list = nflick_photo_search_worker_take_list (NFLICK_PHOTO_SEARCH_WORKER 
328                                                                 (priv->worker));
329   for (l = list; l != NULL; l = l->next)
330   {
331     FlickrPhoto *photo = (FlickrPhoto*)l->data;
332     ClutterActor *aphoto = NULL;
333     gpointer res;
334
335     if (!photo)
336       continue;
337
338     /* If the photo is already present, return */
339     if (g_hash_table_lookup (priv->table, photo->id) != NULL)
340       continue;
341     
342     /* Insert into the hash table */
343     g_hash_table_insert (priv->table, 
344                          g_strdup (photo->id), 
345                          GINT_TO_POINTER (1));
346
347     /* Create a aaina photo objec, but don't add it to the library yet */
348     aphoto = aaina_photo_new ();
349     g_object_set (G_OBJECT (aphoto),
350                   "id", photo->id,
351                   "title", photo->title, 
352                   "author", photo->user,
353                   NULL);
354     
355     /* Add the photo to the download queue */
356     g_queue_push_tail (priv->queue, (gpointer)aphoto);
357
358     /* Free the the photo struct and its data */
359     g_free (photo->id);
360     g_free (photo->title);
361     g_free (photo->user);
362     g_free (photo);
363     l->data = NULL;
364   }
365
366   g_list_free (list);
367
368   g_timeout_add (CHECK_TIMEOUT, (GSourceFunc)get_photos, (gpointer)source);
369   if (!priv->running)
370   {
371     priv->current = AAINA_PHOTO (g_queue_pop_head (priv->queue));
372     g_timeout_add (200, (GSourceFunc)get_pixbuf, (gpointer)source);
373   }
374   return FALSE;
375 }
376
377 static gboolean
378 get_photos (AainaSourceFlickr *source)
379 {
380   NFlickWorker *worker;
381   NFlickWorkerStatus *status;
382
383   worker = (NFlickWorker*)nflick_photo_search_worker_new (source->priv->tags,
384                                                           " ");
385   if (G_IS_OBJECT (source->priv->worker))
386     g_object_unref (G_OBJECT (source->priv->worker));
387
388   source->priv->worker = worker;
389   
390   nflick_worker_set_custom_data (worker, source);
391   nflick_worker_set_aborted_idle (worker, 
392                                   (NFlickWorkerIdleFunc)on_thread_abort);
393   nflick_worker_set_error_idle (worker, 
394                                 (NFlickWorkerIdleFunc)on_thread_error);
395   nflick_worker_set_ok_idle (worker,
396                              (NFlickWorkerIdleFunc)on_thread_ok);
397
398   nflick_worker_start (worker);
399
400   return FALSE;
401 }
402
403 /* GObject stuff */
404 static void
405 aaina_source_flickr_class_init (AainaSourceFlickrClass *klass)
406 {
407   GObjectClass    *gobject_class = G_OBJECT_CLASS (klass);
408   
409   g_type_class_add_private (gobject_class, sizeof (AainaSourceFlickrPrivate));
410
411 }
412
413
414 static void
415 aaina_source_flickr_init (AainaSourceFlickr *source_flickr)
416 {
417   AainaSourceFlickrPrivate *priv;
418
419   priv = source_flickr->priv = AAINA_SOURCE_FLICKR_GET_PRIVATE (source_flickr);
420
421   priv->table = g_hash_table_new ((GHashFunc)g_str_hash, 
422                                   (GEqualFunc)g_str_equal);
423
424   priv->queue = g_queue_new ();
425   priv->running = FALSE;
426
427   priv->add_queue = g_queue_new ();
428   priv->add_running = FALSE;
429
430   worker_quark = g_quark_from_string ("aaina.flickr.worker");
431 }
432
433 AainaSource*
434 aaina_source_flickr_new (AainaLibrary *library, const gchar *tags)
435 {
436   AainaSourceFlickr         *source_flickr;
437
438   source_flickr = g_object_new (AAINA_TYPE_SOURCE_FLICKR, 
439                                    NULL);
440
441   source_flickr->priv->tags = g_strdup (tags);
442   source_flickr->priv->library = library;
443   get_photos (source_flickr);
444
445   return AAINA_SOURCE (source_flickr);
446 }
447