Don't fetch url. Only fetch just when we need it (to play the files).
[clutter-grilo-player:cgp.git] / src / cgp-plugins-model.c
1 #include "config.h"
2 #include <grilo.h>
3 #include <cgp-plugins-model.h>
4
5 static void on_source_added (GrlPluginRegistry *registry, 
6                              GrlMediaPlugin *plugin, 
7                              CgpPluginsModel *self);
8 static void cgp_plugins_model_dispose (GObject *self);
9 static void cgp_plugins_model_set_property (GObject *gobject,
10                                             guint prop_id,
11                                             const GValue *value,
12                                             GParamSpec *pspec);
13 static void cgp_plugins_model_get_property (GObject *gobject,
14                                             guint prop_id,
15                                             GValue *value,
16                                             GParamSpec *pspec);
17 static void set_container (CgpPluginsModel *model,
18                            GObject *container);
19 static void on_media_source_browse (GrlMediaSource *source,
20                                     guint browse_id,
21                                     GrlMedia *media,
22                                     guint remaining,
23                                     CgpPluginsModel *self,
24                                     const GError *error);
25
26 enum {
27         PROP_0,
28         PROP_SOURCE,
29         PROP_CONTAINER,
30         PROP_SEARCH
31 };
32
33 const gchar *cgp_plugins_model_column_names[] = {
34         "uri",
35         "name",
36         "type",
37         "instance"
38 };
39
40 GType cgp_plugins_model_column_types[] = {
41         G_TYPE_STRING,
42         G_TYPE_STRING,
43         G_TYPE_INT,
44         G_TYPE_OBJECT
45 };
46
47 G_DEFINE_TYPE (CgpPluginsModel,
48                cgp_plugins_model,
49                CLUTTER_TYPE_LIST_MODEL);
50
51 typedef struct _CgpPluginsModelPrivate CgpPluginsModelPrivate;
52 struct _CgpPluginsModelPrivate {
53         GObject *source;
54         GObject *container;
55         gchar *search_string;
56         guint op_id;
57 };
58
59 #define CGP_PLUGINS_MODEL_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
60                                                                           CGP_TYPE_PLUGINS_MODEL, \
61                                                                           CgpPluginsModelPrivate))
62
63 static void
64 on_source_added (GrlPluginRegistry *registry, GrlMediaPlugin *plugin, CgpPluginsModel *self)
65 {
66         if (GRL_IS_MEDIA_SOURCE (plugin)) {
67                 clutter_model_append (CLUTTER_MODEL (self), 
68                                       CGP_PLUGINS_MODEL_COLUMN_ID, grl_media_plugin_get_id (plugin),
69                                       CGP_PLUGINS_MODEL_COLUMN_NAME, grl_media_plugin_get_name (plugin),
70                                       CGP_PLUGINS_MODEL_COLUMN_TYPE, CGP_PLUGINS_MODEL_TYPE_SOURCE,
71                                       CGP_PLUGINS_MODEL_COLUMN_INSTANCE, plugin,
72                                       -1);
73         }
74 }
75
76 static gboolean
77 foreach_remove_plugin (ClutterModel *model,
78                        ClutterModelIter *iter,
79                        GrlMediaPlugin *plugin)
80 {
81         gchar *id;
82         gboolean match;
83
84         clutter_model_iter_get (iter, CGP_PLUGINS_MODEL_COLUMN_ID, &id, -1);
85         match = g_strcmp0 (id, grl_media_plugin_get_id (plugin)) == 0;
86         if (match) {
87                 clutter_model_remove (model, clutter_model_iter_get_row (iter));
88         }
89         g_free (id);
90         return !match;
91 }
92
93 static void
94 on_source_removed (GrlPluginRegistry *registry, GrlMediaPlugin *plugin, CgpPluginsModel *self)
95 {
96         clutter_model_foreach (CLUTTER_MODEL (self), (ClutterModelForeachFunc) foreach_remove_plugin, plugin);
97 }
98
99 static void
100 cgp_plugins_model_class_init (CgpPluginsModelClass *klass)
101 {
102         GObjectClass *gobject_class;
103         GParamSpec *pspec;
104
105         gobject_class = (GObjectClass*) klass;
106
107         gobject_class->dispose = cgp_plugins_model_dispose;
108         gobject_class->set_property = cgp_plugins_model_set_property;
109         gobject_class->get_property = cgp_plugins_model_get_property;
110
111         pspec = g_param_spec_object ("source",
112                                      "Source",
113                                      "Media source",
114                                      GRL_TYPE_MEDIA_SOURCE,
115                                      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READABLE | G_PARAM_WRITABLE);
116         g_object_class_install_property (gobject_class, PROP_SOURCE, pspec);
117
118         pspec = g_param_spec_object ("container",
119                                      "Container",
120                                      "Container of the shown items",
121                                      G_TYPE_OBJECT,
122                                      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READABLE | G_PARAM_WRITABLE);
123         g_object_class_install_property (gobject_class, PROP_CONTAINER, pspec);
124
125         pspec = g_param_spec_string ("search",
126                                      "Search string",
127                                      "String to search",
128                                      NULL, 
129                                      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READABLE | G_PARAM_WRITABLE);
130         g_object_class_install_property (gobject_class, PROP_SEARCH, pspec);
131
132         g_type_class_add_private (gobject_class, sizeof(CgpPluginsModelPrivate));
133 }
134
135 static void
136 cgp_plugins_model_dispose (GObject *self)
137 {
138         CgpPluginsModelPrivate *priv;
139
140         priv = CGP_PLUGINS_MODEL_GET_PRIVATE (self);
141
142         if (priv->op_id) {
143                 grl_media_source_cancel (GRL_MEDIA_SOURCE (priv->source), priv->op_id);
144                 priv->op_id = 0;
145         }
146         if (priv->source) {
147                 g_object_unref (priv->source);
148                 priv->source = NULL;
149         }
150         if (priv->container) {
151                 if (GRL_IS_PLUGIN_REGISTRY (priv->container)) {
152                         g_signal_handlers_disconnect_by_func (priv->container, G_CALLBACK (on_source_added), self);
153                         g_signal_handlers_disconnect_by_func (priv->container, G_CALLBACK (on_source_removed), self);
154                 }
155                 g_object_unref (priv->container);
156                 priv->container = NULL;
157         }
158
159         G_OBJECT_CLASS (cgp_plugins_model_parent_class)->dispose (G_OBJECT (self));
160 }
161
162 static void
163 cgp_plugins_model_set_property (GObject *gobject,
164                                 guint prop_id,
165                                 const GValue *value,
166                                 GParamSpec *pspec)
167 {
168         CgpPluginsModelPrivate *priv;
169
170         priv = CGP_PLUGINS_MODEL_GET_PRIVATE (gobject);
171         switch (prop_id) {
172         case PROP_SOURCE:
173                 priv->source = g_value_dup_object (value);
174                 break;
175         case PROP_CONTAINER:
176                 set_container (CGP_PLUGINS_MODEL (gobject), g_value_get_object (value));
177                 break;
178         case PROP_SEARCH:
179                 priv->search_string = g_value_dup_string (value);
180                 break;
181         default:
182                 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
183                 break;
184         }
185 }
186
187 static void
188 cgp_plugins_model_get_property (GObject *gobject,
189                                 guint prop_id,
190                                 GValue *value,
191                                 GParamSpec *pspec)
192 {
193         CgpPluginsModelPrivate *priv;
194
195         priv = CGP_PLUGINS_MODEL_GET_PRIVATE (gobject);
196         switch (prop_id) {
197         case PROP_SOURCE:
198                 g_value_set_object (value, priv->source);
199                 break;
200         case PROP_CONTAINER:
201                 g_value_set_object (value, priv->container);
202                 break;
203         case PROP_SEARCH:
204                 g_value_set_string (value, priv->search_string);
205                 break;
206         default:
207                 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
208                 break;
209         }
210 }
211
212 static void
213 set_container (CgpPluginsModel *self, GObject *container)
214 {
215         CgpPluginsModelPrivate *priv;
216
217         priv = CGP_PLUGINS_MODEL_GET_PRIVATE (self);
218         priv->container = g_object_ref (container);
219         if (GRL_IS_PLUGIN_REGISTRY (container)) {
220                 GrlMediaPlugin **sources, **current;
221
222                 sources = grl_plugin_registry_get_sources (GRL_PLUGIN_REGISTRY (priv->container), FALSE);
223                 for (current = sources; current != NULL && *current != NULL; current++) {
224                         if (GRL_IS_MEDIA_SOURCE (*current)) {
225                                 clutter_model_append (CLUTTER_MODEL (self), 
226                                                       CGP_PLUGINS_MODEL_COLUMN_ID, grl_media_plugin_get_id (*current),
227                                                       CGP_PLUGINS_MODEL_COLUMN_NAME, grl_media_plugin_get_name (*current),
228                                                       CGP_PLUGINS_MODEL_COLUMN_TYPE, CGP_PLUGINS_MODEL_TYPE_SOURCE,
229                                                       CGP_PLUGINS_MODEL_COLUMN_INSTANCE, *current,
230                                                       -1);
231                         }
232                 }
233
234                 g_signal_connect (priv->container, "source-added", G_CALLBACK (on_source_added), self);
235                 g_signal_connect (priv->container, "source-removed", G_CALLBACK (on_source_added), self);
236                 
237         } else if (GRL_IS_MEDIA_SOURCE (container)) {
238                 if (priv->search_string) {
239                         priv->op_id = grl_media_source_search (GRL_MEDIA_SOURCE (container), priv->search_string, 
240                                                                grl_metadata_key_list_new (GRL_METADATA_KEY_ID,
241                                                                                           GRL_METADATA_KEY_TITLE,
242                                                                                           NULL),
243                                                                0, 100, GRL_RESOLVE_FAST_ONLY,
244                                                                (GrlMediaSourceResultCb) on_media_source_browse,
245                                                                self);
246                 } else {
247                         priv->op_id = grl_media_source_browse (GRL_MEDIA_SOURCE (container), NULL, 
248                                                                grl_metadata_key_list_new (GRL_METADATA_KEY_ID,
249                                                                                           GRL_METADATA_KEY_TITLE,
250                                                                                           NULL),
251                                                                0, 100, GRL_RESOLVE_FAST_ONLY,
252                                                                (GrlMediaSourceResultCb) on_media_source_browse,
253                                                                self);
254                 }
255         } else if (GRL_IS_MEDIA_BOX (container)) {
256                 priv->op_id = grl_media_source_browse (GRL_MEDIA_SOURCE (priv->source), GRL_MEDIA (container),
257                                                        grl_metadata_key_list_new (GRL_METADATA_KEY_ID,
258                                                                                   GRL_METADATA_KEY_TITLE,
259                                                                                   NULL),
260                                                        0, 100, GRL_RESOLVE_IDLE_RELAY,
261                                                        (GrlMediaSourceResultCb) on_media_source_browse,
262                                                        self);
263                 g_warning ("NOT IMPLEMENTED");
264         }
265 }
266
267 static gint
268 model_sort_func (ClutterModel *model,
269                  const GValue *a,
270                  const GValue *b,
271                  gpointer notused)
272 {
273         const gchar *a_str, *b_str;
274         
275         a_str = g_value_get_string (a);
276         b_str = g_value_get_string (b);
277
278         return g_strcmp0 (a_str, b_str);
279 }
280
281 static void
282 cgp_plugins_model_init (CgpPluginsModel *self)
283 {
284         CgpPluginsModelPrivate *priv;
285         priv = CGP_PLUGINS_MODEL_GET_PRIVATE (self);
286
287         priv->op_id = 0;
288         priv->source = NULL;
289
290         clutter_model_set_names (CLUTTER_MODEL (self), CGP_PLUGINS_MODEL_N_COLUMNS, cgp_plugins_model_column_names);
291         clutter_model_set_types (CLUTTER_MODEL (self), CGP_PLUGINS_MODEL_N_COLUMNS, cgp_plugins_model_column_types);
292
293         clutter_model_set_sort (CLUTTER_MODEL (self), CGP_PLUGINS_MODEL_COLUMN_NAME,
294                                 model_sort_func, NULL, NULL);
295 }
296
297 ClutterModel *
298 cgp_plugins_model_new_from_registry (GrlPluginRegistry *registry)
299 {
300         return g_object_new (CGP_TYPE_PLUGINS_MODEL, "container", registry, NULL);
301 }
302
303 ClutterModel *
304 cgp_plugins_model_new_from_source (GrlMediaSource *source, const gchar *search_string)
305 {
306         return g_object_new (CGP_TYPE_PLUGINS_MODEL, "search", search_string, "source", source, "container", source, NULL);
307 }
308
309 ClutterModel *
310 cgp_plugins_model_new_from_media_box (GrlMediaSource *source, GrlMediaBox *media_box)
311 {
312         return g_object_new (CGP_TYPE_PLUGINS_MODEL, "source", source, "container", media_box, NULL);
313 }
314
315 GObject *
316 cgp_plugins_model_get_item (CgpPluginsModel *self, const gchar *id)
317 {
318         CgpPluginsModelPrivate *priv;
319         ClutterModelIter *iter;
320         GObject *result = NULL;
321
322         priv = CGP_PLUGINS_MODEL_GET_PRIVATE (self);
323         iter = clutter_model_get_first_iter (CLUTTER_MODEL (self));
324         while (!result && !clutter_model_iter_is_last (iter)) {
325                 gchar *iter_id;
326                 GObject *instance;
327
328                 clutter_model_iter_get (iter, CGP_PLUGINS_MODEL_COLUMN_ID, &iter_id, CGP_PLUGINS_MODEL_COLUMN_INSTANCE, &instance, -1);
329                 if (g_strcmp0 (id, iter_id) == 0) {
330                         result = g_object_ref (instance);
331                 }
332                 g_object_unref (instance);
333                 g_free (iter_id);
334                 clutter_model_iter_next (iter);
335         }
336
337         return result;
338 }
339
340 static void
341 on_media_source_browse (GrlMediaSource *source,
342                         guint browse_id,
343                         GrlMedia *media,
344                         guint remaining,
345                         CgpPluginsModel *self,
346                         const GError *error)
347 {
348         CgpPluginsModelPrivate *priv;
349
350         priv = CGP_PLUGINS_MODEL_GET_PRIVATE (self);
351
352         if (error) {
353                 g_warning ("There was an error browsing");
354                 return;
355         }
356
357         clutter_model_append (CLUTTER_MODEL (self), 
358                               CGP_PLUGINS_MODEL_COLUMN_ID, grl_media_get_id (media),
359                               CGP_PLUGINS_MODEL_COLUMN_NAME, grl_media_get_title (media),
360                               CGP_PLUGINS_MODEL_COLUMN_TYPE, GRL_IS_MEDIA_BOX (media)?CGP_PLUGINS_MODEL_TYPE_MEDIA_BOX:CGP_PLUGINS_MODEL_TYPE_MEDIA,
361                               CGP_PLUGINS_MODEL_COLUMN_INSTANCE, media,
362                               -1);
363
364         if (remaining == 0) {
365                 priv->op_id = 0;
366         }
367 }
368
369 GrlMediaSource *
370 cgp_plugins_model_get_source (CgpPluginsModel *self)
371 {
372         CgpPluginsModelPrivate *priv;
373
374         priv = CGP_PLUGINS_MODEL_GET_PRIVATE (self);
375
376         return GRL_MEDIA_SOURCE (priv->source);
377 }