Macro qtTrIdx() replaced by tr() and QT_TRANSLATE_NOOP()
[mafwsubrenderer] / mafw-gst-subtitles-renderer / libmafw-gst-renderer / mafw-playlist-iterator.c
1 /*
2  * This file is a part of MAFW
3  *
4  * Copyright (C) 2007, 2008, 2009 Nokia Corporation, all rights reserved.
5  *
6  * Contact: Visa Smolander <visa.smolander@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24
25 #include "mafw-playlist-iterator.h"
26 #include "mafw-gst-renderer-marshal.h"
27
28 #undef  G_LOG_DOMAIN
29 #define G_LOG_DOMAIN "mafw-gst-renderer-playlist-iterator"
30
31 struct _MafwPlaylistIteratorPrivate {
32         MafwPlaylist *playlist;
33         gint current_index;
34         gchar *current_objectid;
35         gint size;
36 };
37
38 typedef gboolean (*movement_function) (MafwPlaylist *playlist,
39                                        guint *index,
40                                        gchar **objectid,
41                                        GError **error);
42
43 enum {
44         PLAYLIST_CHANGED = 0,
45         LAST_SIGNAL,
46 };
47
48 static guint mafw_playlist_iterator_signals[LAST_SIGNAL];
49
50 G_DEFINE_TYPE(MafwPlaylistIterator, mafw_playlist_iterator, G_TYPE_OBJECT);
51
52 static void
53 mafw_playlist_iterator_dispose(GObject *object)
54 {
55         MafwPlaylistIterator *iterator = (MafwPlaylistIterator *) object;
56
57         g_return_if_fail(MAFW_IS_PLAYLIST_ITERATOR(iterator));
58
59         mafw_playlist_iterator_invalidate(iterator);
60
61         G_OBJECT_CLASS(mafw_playlist_iterator_parent_class)->dispose(object);
62 }
63
64 static void
65 mafw_playlist_iterator_class_init(MafwPlaylistIteratorClass *klass)
66 {
67         GObjectClass *gclass = NULL;
68
69         gclass = G_OBJECT_CLASS(klass);
70         g_return_if_fail(gclass != NULL);
71
72         g_type_class_add_private(klass, sizeof(MafwPlaylistIteratorPrivate));
73
74         gclass->dispose = mafw_playlist_iterator_dispose;
75
76         mafw_playlist_iterator_signals[PLAYLIST_CHANGED] =
77             g_signal_new("playlist-changed",
78                          G_TYPE_FROM_CLASS(klass),
79                          G_SIGNAL_RUN_FIRST,
80                          G_STRUCT_OFFSET(MafwPlaylistIteratorClass, playlist_changed),
81                          NULL,
82                          NULL,
83                          mafw_gst_renderer_marshal_VOID__BOOLEAN_UINT_INT_STRING,
84                          G_TYPE_NONE,
85                          4,
86                          G_TYPE_BOOLEAN,
87                          G_TYPE_UINT, G_TYPE_INT, G_TYPE_STRING);
88 }
89
90 static void
91 mafw_playlist_iterator_init(MafwPlaylistIterator *self)
92 {
93         self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
94                                                  MAFW_TYPE_PLAYLIST_ITERATOR,
95                                                  MafwPlaylistIteratorPrivate);
96 }
97
98 static void
99 mafw_playlist_iterator_set_data(MafwPlaylistIterator *iterator, gint index,
100                                  gchar *objectid)
101 {
102         g_assert(mafw_playlist_iterator_is_valid(iterator));
103
104         g_free(iterator->priv->current_objectid);
105         iterator->priv->current_index = index;
106         iterator->priv->current_objectid = objectid;
107 }
108
109 static MafwPlaylistIteratorMovementResult
110 mafw_playlist_iterator_move_to_next_in_direction(MafwPlaylistIterator *iterator,
111                                                   movement_function get_next_in_direction,
112                                                   GError **error)
113 {
114         gint index;
115         gchar *objectid = NULL;
116         GError *new_error = NULL;
117         gboolean playlist_movement_result = FALSE;
118         MafwPlaylistIteratorMovementResult iterator_movement_result =
119                 MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_OK;
120
121         g_return_val_if_fail(mafw_playlist_iterator_is_valid(iterator),
122                              MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_INVALID);
123
124         index = iterator->priv->current_index;
125
126         playlist_movement_result =
127                 get_next_in_direction (iterator->priv->playlist,
128                                        (guint *) &index,
129                                        &objectid, &new_error);
130
131         if (new_error != NULL) {
132                 g_propagate_error(error, new_error);
133                 iterator_movement_result =
134                         MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_ERROR;
135         } else if (playlist_movement_result) {
136                 mafw_playlist_iterator_set_data(iterator, index, objectid);
137         } else {
138                 iterator_movement_result =
139                         MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_LIMIT;
140         }
141
142         return iterator_movement_result;
143 }
144
145 static void
146 mafw_playlist_iterator_playlist_contents_changed_handler(MafwPlaylist *playlist,
147                                                           guint from,
148                                                           guint nremove,
149                                                           guint nreplace,
150                                                           gpointer user_data)
151 {
152         gint play_index;
153         gboolean clip_changed = FALSE;
154         GError *error = NULL;
155         MafwPlaylistIterator *iterator = (MafwPlaylistIterator*) user_data;
156
157         g_return_if_fail(MAFW_IS_PLAYLIST(playlist));
158         g_return_if_fail(MAFW_IS_PLAYLIST_ITERATOR(iterator));
159
160         if (iterator->priv->playlist == NULL) {
161                 g_critical("Got playlist:contents-changed but renderer has no" \
162                            "playlist assigned!. Skipping...");
163                 return;
164         }
165
166         play_index = iterator->priv->current_index;
167         iterator->priv->size += nreplace;
168
169         if (nremove > 0) {
170                 /* Items have been removed from the playlist */
171                 iterator->priv->size -= nremove;
172                 if ((play_index >= from) &&
173                     (play_index < from + nremove)) {
174                         /* The current index has been removed */
175                         guint pls_size =
176                                 mafw_playlist_iterator_get_size(iterator,
177                                                                  &error);
178                         if (error == NULL) {
179                                 /* Is the current index invalid now? If not,
180                                    set current item to the last in the playlist,
181                                    otherwise the keep the index and update the
182                                    media */
183                                 if (pls_size == 0) {
184                                         mafw_playlist_iterator_set_data(iterator, -1, NULL);
185                                 } else if (play_index >= pls_size) {
186                                         mafw_playlist_iterator_move_to_index(iterator,
187                                                                               pls_size - 1,
188                                                                               &error);
189                                 } else {
190                                         mafw_playlist_iterator_update(iterator,
191                                                                        &error);
192                                 }
193
194                                 clip_changed = TRUE;
195                         }
196                 } else if (from < play_index) {
197                         /* The current index has been moved towards
198                            the head of the playlist */
199                         play_index -= nremove;
200                         if (play_index < 0) {
201                                 play_index = 0;
202                         }
203                         mafw_playlist_iterator_move_to_index(iterator,
204                                                               play_index,
205                                                               &error);
206                 }
207         } else if (nremove == 0) {
208                 /* Items have been inserted in the playlist */
209                 if (play_index == -1) {
210                         /* First item has been added to an empty playlist */
211                         mafw_playlist_iterator_reset(iterator,
212                                                       &error);
213                         clip_changed = TRUE;
214                 } else if (play_index >= from) {
215                         /* The current item has been moved towards the
216                            tail of the playlist */
217                         mafw_playlist_iterator_move_to_index(iterator,
218                                                               play_index + nreplace,
219                                                               &error);
220                 }
221         }
222
223         if (error != NULL) {
224                 g_critical("playlist::contents-changed handler failed "
225                            "with \"%s\"", error->message);
226                 g_signal_emit(iterator,
227                               mafw_playlist_iterator_signals[PLAYLIST_CHANGED],
228                               0, FALSE, error->domain, error->code, error->message);
229                 g_error_free (error);
230         } else {
231                 g_signal_emit(iterator,
232                               mafw_playlist_iterator_signals[PLAYLIST_CHANGED],
233                               0, clip_changed, 0, 0, NULL);
234         }
235 }
236
237 static void
238 mafw_playlist_iterator_playlist_item_moved_handler(MafwPlaylist *playlist,
239                                                     guint from,
240                                                     guint to,
241                                                     gpointer user_data)
242 {
243         MafwPlaylistIterator *iterator = (MafwPlaylistIterator *) user_data;
244         gint play_index;
245         GError *error = NULL;
246
247         g_return_if_fail(MAFW_IS_PLAYLIST(playlist));
248         g_return_if_fail(MAFW_IS_PLAYLIST_ITERATOR(iterator));
249
250         if (iterator->priv->playlist == NULL) {
251                 g_critical("Got playlist:item-moved but renderer has not a " \
252                           "playlist assigned! Skipping...");
253                 return;
254         }
255
256         play_index = iterator->priv->current_index;
257
258         if (play_index == from) {
259                 /* So the current item has been moved, let's update the
260                    the current index to the new location  */
261                 mafw_playlist_iterator_move_to_index(iterator, to, &error);
262         } else if (play_index > from && play_index <= to) {
263                 /* So we current item  has been pushed one position towards
264                    the head, let's update the current index */
265                 mafw_playlist_iterator_move_to_prev(iterator, &error);
266         }  else if (play_index >= to && play_index < from) {
267                 /* So we current item  has been pushed one position towards
268                    the head, let's update the current index */
269                 mafw_playlist_iterator_move_to_next(iterator, &error);
270         }
271
272         if (error != NULL) {
273                 g_critical("playlist::item-moved handler failed "
274                            "with \"%s\"", error->message);
275                 g_error_free (error);
276         }
277 }
278
279 MafwPlaylistIterator *
280 mafw_playlist_iterator_new(void)
281 {
282         MafwPlaylistIterator *iterator = (MafwPlaylistIterator *)
283                 g_object_new(MAFW_TYPE_PLAYLIST_ITERATOR, NULL);
284
285         g_assert(iterator != NULL);
286
287         iterator->priv->playlist = NULL;
288         iterator->priv->current_index = -1;
289         iterator->priv->current_objectid = NULL;
290         iterator->priv->size = -1;
291
292         return iterator;
293 }
294
295 void
296 mafw_playlist_iterator_initialize(MafwPlaylistIterator *iterator,
297                                    MafwPlaylist *playlist, GError **error)
298 {
299         guint size;
300         gint index = -1;
301         gchar *objectid = NULL;
302         GError *new_error = NULL;
303
304         g_return_if_fail(MAFW_IS_PLAYLIST_ITERATOR(iterator));
305         g_return_if_fail(iterator->priv->playlist == NULL);
306
307         iterator->priv->size = -1;
308
309         mafw_playlist_get_starting_index(playlist, (guint *) &index, &objectid,
310                                           &new_error);
311
312         if (new_error == NULL) {
313                 size = mafw_playlist_get_size(playlist, &new_error);
314         }
315
316         if (new_error == NULL) {
317                 iterator->priv->playlist = g_object_ref(playlist);
318                 iterator->priv->current_index = index;
319                 iterator->priv->current_objectid = objectid;
320                 iterator->priv->size = size;
321
322                 g_signal_connect(playlist,
323                                  "item-moved",
324                                  G_CALLBACK(mafw_playlist_iterator_playlist_item_moved_handler),
325                                  iterator);
326                 g_signal_connect(playlist,
327                                  "contents-changed",
328                                  G_CALLBACK(mafw_playlist_iterator_playlist_contents_changed_handler),
329                                  iterator);
330         }
331         else {
332                 g_propagate_error (error, new_error);
333         }
334 }
335
336 void
337 mafw_playlist_iterator_invalidate(MafwPlaylistIterator *iterator)
338 {
339         g_return_if_fail(MAFW_IS_PLAYLIST_ITERATOR(iterator));
340
341         if (iterator->priv->playlist != NULL) {
342                 g_signal_handlers_disconnect_matched(iterator->priv->playlist,
343                                                      (GSignalMatchType) G_SIGNAL_MATCH_FUNC,
344                                                      0, 0, NULL,
345                                                      mafw_playlist_iterator_playlist_item_moved_handler,
346                                                      NULL);
347
348                 g_signal_handlers_disconnect_matched(iterator->priv->playlist,
349                                                      (GSignalMatchType) G_SIGNAL_MATCH_FUNC,
350                                                      0, 0, NULL,
351                                                      mafw_playlist_iterator_playlist_contents_changed_handler,
352                                                      NULL);
353
354                 g_object_unref(iterator->priv->playlist);
355                 g_free(iterator->priv->current_objectid);
356                 iterator->priv->playlist = NULL;
357                 iterator->priv->current_index = -1;
358                 iterator->priv->current_objectid = NULL;
359                 iterator->priv->size = -1;
360         }
361 }
362
363 gboolean
364 mafw_playlist_iterator_is_valid(MafwPlaylistIterator *iterator)
365 {
366         g_return_val_if_fail(MAFW_IS_PLAYLIST_ITERATOR(iterator), FALSE);
367
368         return iterator->priv->playlist != NULL;
369 }
370
371 void
372 mafw_playlist_iterator_reset(MafwPlaylistIterator *iterator, GError **error)
373 {
374         gint index = -1;
375         gchar *objectid = NULL;
376         GError *new_error = NULL;
377
378         g_return_if_fail(mafw_playlist_iterator_is_valid(iterator));
379
380         mafw_playlist_get_starting_index(iterator->priv->playlist,
381                                           (guint *) &index,
382                                           &objectid, &new_error);
383
384         if (new_error == NULL) {
385                 mafw_playlist_iterator_set_data(iterator, index, objectid);
386         }
387         else {
388                 g_propagate_error (error, new_error);
389         }
390 }
391
392 void
393 mafw_playlist_iterator_move_to_last(MafwPlaylistIterator *iterator,
394                                      GError **error)
395 {
396         GError *new_error = NULL;
397         gint index = -1;
398         gchar *objectid = NULL;
399
400         g_return_if_fail(mafw_playlist_iterator_is_valid(iterator));
401
402         mafw_playlist_get_last_index(iterator->priv->playlist,
403                                       (guint *) &index,
404                                       &objectid, &new_error);
405
406         if (new_error == NULL) {
407                 mafw_playlist_iterator_set_data(iterator, index, objectid);
408         }
409         else {
410                 g_propagate_error (error, new_error);
411         }
412 }
413
414 MafwPlaylistIteratorMovementResult
415 mafw_playlist_iterator_move_to_next(MafwPlaylistIterator *iterator,
416                                      GError **error)
417 {
418         return  mafw_playlist_iterator_move_to_next_in_direction(iterator,
419                                                                   mafw_playlist_get_next,
420                                                                   error);
421 }
422
423 MafwPlaylistIteratorMovementResult
424 mafw_playlist_iterator_move_to_prev(MafwPlaylistIterator *iterator,
425                                      GError **error)
426 {
427         return  mafw_playlist_iterator_move_to_next_in_direction(iterator,
428                                                                   mafw_playlist_get_prev,
429                                                                   error);
430 }
431
432 MafwPlaylistIteratorMovementResult
433 mafw_playlist_iterator_move_to_index(MafwPlaylistIterator *iterator,
434                                       gint index,
435                                       GError **error)
436 {
437         GError *new_error = NULL;
438         MafwPlaylistIteratorMovementResult iterator_movement_result =
439                 MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_OK;
440         gint playlist_size;
441
442         g_return_val_if_fail(mafw_playlist_iterator_is_valid(iterator),
443                              MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_INVALID);
444
445         playlist_size = mafw_playlist_iterator_get_size(iterator, &new_error);
446
447         if (new_error != NULL) {
448                 g_propagate_error(error, new_error);
449                 iterator_movement_result =
450                         MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_ERROR;
451         } else if ((index < 0) || (index >= playlist_size)) {
452                 iterator_movement_result =
453                         MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_LIMIT;
454         } else {
455                 gchar *objectid =
456                         mafw_playlist_get_item(iterator->priv->playlist,
457                                                 index,
458                                                 &new_error);
459
460                 if (new_error != NULL) {
461                         g_propagate_error(error, new_error);
462                         iterator_movement_result =
463                                 MAFW_PLAYLIST_ITERATOR_MOVE_RESULT_ERROR;
464                 } else {
465                         mafw_playlist_iterator_set_data(iterator, index, objectid);
466                 }
467         }
468
469         return iterator_movement_result;
470 }
471
472 void
473 mafw_playlist_iterator_update(MafwPlaylistIterator *iterator, GError **error)
474 {
475         GError *new_error = NULL;
476         gchar *objectid = NULL;
477
478         objectid =
479                 mafw_playlist_get_item(iterator->priv->playlist,
480                                         iterator->priv->current_index,
481                                         &new_error);
482
483         if (new_error != NULL) {
484                 g_propagate_error(error, new_error);
485         } else {
486                 mafw_playlist_iterator_set_data(iterator,
487                                                  iterator->priv->current_index,
488                                                  objectid);
489         }
490 }
491
492 const gchar *
493 mafw_playlist_iterator_get_current_objectid(MafwPlaylistIterator *iterator)
494 {
495         g_return_val_if_fail(mafw_playlist_iterator_is_valid(iterator), NULL);
496
497         return iterator->priv->current_objectid;
498 }
499
500 gint
501 mafw_playlist_iterator_get_current_index(MafwPlaylistIterator *iterator)
502 {
503         g_return_val_if_fail(mafw_playlist_iterator_is_valid(iterator), 0);
504
505         return iterator->priv->current_index;
506 }
507
508 gint
509 mafw_playlist_iterator_get_size(MafwPlaylistIterator *iterator,
510                                  GError **error)
511 {
512         g_return_val_if_fail(mafw_playlist_iterator_is_valid(iterator), -1);
513
514         if (iterator->priv->size == -1) {
515                 iterator->priv->size =
516                         mafw_playlist_get_size(iterator->priv->playlist,
517                                                 error);
518         }
519
520         return iterator->priv->size;
521 }