Modify version string to post-release version 0.18.101
[gmpc.git] / src / gmpc-mpddata-model.gob
blob45c8763ff154b067e2aa26dd408a39028edb8758
1 /* Gnome Music Player Client (GMPC)
2  * Copyright (C) 2004-2009 Qball Cow <qball@sarine.nl>
3  * Project homepage: http://gmpc.wikia.com/
4  
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 requires 2.0.0
22 %ht{
23 #include <gtk/gtk.h>
24 #include <libmpd/libmpd.h>
25 #include <libmpd/libmpd-internal.h>
28 %privateheader{
29 //#include "playlist3.h"
30 #include "config1.h"
31 #include "config-defaults.h"
32 #include "main.h"
33 #include "misc.h"
36 %h{
37 #define GMPC_MPD_DATA_MODEL(a) GMPC_MPDDATA_MODEL(a)
38         enum
39         {
40                 MPDDATA_MODEL_COL_MPDSONG = 0,                /* get the mpd_Song */
41                 MPDDATA_MODEL_COL_PLAYING,                                    /* Shows if this song is the current song */
42                 MPDDATA_MODEL_COL_PLAYING_FONT_WEIGHT,  /* Shows if this song is the current song */
43                 MPDDATA_MODEL_COL_PATH,                                         /* Path to song/file/directory */ 
44                 MPDDATA_MODEL_COL_MARKUP,                                     /* a string that has FALSEmarkup */
45                 MPDDATA_MODEL_COL_SONG_ARTIST,                      /* artist name */
46                 MPDDATA_MODEL_COL_SONG_ALBUM,                         /* album name */
47                 MPDDATA_MODEL_COL_SONG_TITLE,                         /* song title */
48                 MPDDATA_MODEL_COL_SONG_TITLEFILE,                   /* song title */
49                 MPDDATA_MODEL_COL_SONG_GENRE,                         /* song genre */
50                 MPDDATA_MODEL_COL_SONG_TRACK,                         /* song track */
51                 MPDDATA_MODEL_COL_SONG_NAME,                          /* stream name */
52                 MPDDATA_MODEL_COL_SONG_COMPOSER,                    /* composer name */
53                 MPDDATA_MODEL_COL_SONG_PERFORMER,                   /* performer */
54                 MPDDATA_MODEL_COL_SONG_DATE,                          /* date */
55                 MPDDATA_MODEL_COL_SONG_LENGTH_FORMAT,     /* length formatted */
56                 MPDDATA_MODEL_COL_SONG_DISC,                          /* disc */
57                 MPDDATA_MODEL_COL_SONG_COMMENT,                     /* comment */
58                 MPDDATA_MODEL_COL_SONG_POS,                                   /* position */
59         MPDDATA_MODEL_COL_SONG_ALBUMARTIST,
60                 MPDDATA_MODEL_COL_PATH_EXTENSION,                               /* Extention */
61                 MPDDATA_MODEL_COL_PATH_DIRECTORY,                               /* Directory */
62                 MPDDATA_MODEL_COL_SONG_ID,                                    /* col id */
63                 MPDDATA_MODEL_COL_ICON_ID,                                    /* icon id */
64                 MPDDATA_MODEL_COL_SONG_LENGTH,                      /* length */
65                 MPDDATA_MODEL_TAG_TYPE,                                   /* tag type */
66                 MPDDATA_MODEL_ROW_TYPE,                                         /* type of the row */
67                 MPDDATA_MODEL_META_DATA,                        /* metadata */
68                 MPDDATA_MODEL_USERDATA,
69                 MPDDATA_MODEL_N_COLUMNS
70         } ;
73  class Gmpc:MpdData:Model from G:Object
74           (interface Gtk:Tree:Sortable)
75           (interface Gtk:Tree:Model)
77     private gint stamp          = {g_random_int()};
78     public      GType types[MPDDATA_MODEL_N_COLUMNS]; 
79     private MpdData *data       = NULL;
80     public gint num_rows = 0;
81     private GdkPixbuf **images = NULL;
82     private gchar *req_artist = {NULL} destroywith g_free;
83     public gint icon_size = {cfg_get_single_value_as_int_with_default(config, "gmpc-mpddata-model", "icon-size", 32)};
85     /* sorting */
86     private GtkSortType sort_order = GTK_SORT_ASCENDING;
87     private int sort_column = GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID;
88     private int old_sort_column = GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID;
89     public gboolean has_up       = FALSE;
90     private gchar *markup        = {cfg_get_single_value_as_string_with_default(config, "playlist", "browser_markup",DEFAULT_MARKUP_BROWSER)} destroywith g_free;
92     private gulong playtime = {0};
95     private gboolean use_images = TRUE;
97     property BOOLEAN has_up
98         (nick = "Has Up",
99          blurb = "Show an 'up row",
100          default_value = FALSE,
101          export,
102          link);
104     init(self)
105     {
106         self->types[MPDDATA_MODEL_COL_MPDSONG] = G_TYPE_POINTER;
107         self->types[MPDDATA_MODEL_COL_MARKUP] = G_TYPE_STRING;
108         self->types[MPDDATA_MODEL_COL_PLAYING] = G_TYPE_BOOLEAN;
109         self->types[MPDDATA_MODEL_COL_PLAYING_FONT_WEIGHT] = G_TYPE_INT;
110         self->types[MPDDATA_MODEL_COL_PATH] = G_TYPE_STRING;
111         self->types[MPDDATA_MODEL_COL_SONG_ARTIST] = G_TYPE_STRING;
112         self->types[MPDDATA_MODEL_COL_SONG_ALBUM] = G_TYPE_STRING;
113         self->types[MPDDATA_MODEL_COL_SONG_TITLE] = G_TYPE_STRING;
114         self->types[MPDDATA_MODEL_COL_SONG_TITLEFILE] = G_TYPE_STRING;
115         self->types[MPDDATA_MODEL_COL_SONG_TRACK] = G_TYPE_STRING;
116         self->types[MPDDATA_MODEL_COL_SONG_GENRE] = G_TYPE_STRING;
117         self->types[MPDDATA_MODEL_COL_SONG_NAME] = G_TYPE_STRING;
118         self->types[MPDDATA_MODEL_COL_SONG_COMPOSER] = G_TYPE_STRING;
119         self->types[MPDDATA_MODEL_COL_SONG_PERFORMER]= G_TYPE_STRING;
120         self->types[MPDDATA_MODEL_COL_SONG_DATE] = G_TYPE_STRING;
121         self->types[MPDDATA_MODEL_COL_SONG_LENGTH] = G_TYPE_INT;
122         self->types[MPDDATA_MODEL_COL_SONG_LENGTH_FORMAT] = G_TYPE_STRING;
123         self->types[MPDDATA_MODEL_COL_SONG_DISC] = G_TYPE_STRING;
124         self->types[MPDDATA_MODEL_COL_SONG_COMMENT] = G_TYPE_STRING;
125         self->types[MPDDATA_MODEL_COL_SONG_POS] = G_TYPE_INT;
126         self->types[MPDDATA_MODEL_COL_SONG_ALBUMARTIST] = G_TYPE_STRING;
127         self->types[MPDDATA_MODEL_COL_PATH_EXTENSION] = G_TYPE_STRING;
128         self->types[MPDDATA_MODEL_COL_PATH_DIRECTORY] = G_TYPE_STRING;
129         self->types[MPDDATA_MODEL_COL_SONG_ID] = G_TYPE_INT;
130         self->types[MPDDATA_MODEL_COL_ICON_ID] = G_TYPE_STRING;
131         self->types[MPDDATA_MODEL_TAG_TYPE] = G_TYPE_INT;
132         self->types[MPDDATA_MODEL_ROW_TYPE] = G_TYPE_INT;
133         self->types[MPDDATA_MODEL_USERDATA] = G_TYPE_POINTER;
134         self->types[MPDDATA_MODEL_META_DATA] = GDK_TYPE_PIXBUF;
135     }
136     class_init(klass);
138     public
139         Gmpc:MpdData:Model *new (void)
140         {
141             return GET_NEW;
142         }
144     override (G:Object)
145         void 
146         finalize (G:Object *obj)
147         {
148             int i =0;
149             Self *self = GMPC_MPDDATA_MODEL(obj); 
151             if(self->_priv->data)
152             {
153                 mpd_data_free(self->_priv->data);
154                 self->_priv->data = NULL;
155             }
156             if(self->_priv->images && self->_priv->use_images)
157             {
158                 for(i=0;i<self->num_rows;i++)
159                 {
160                     if(self->_priv->images[i]) {
161                         g_object_unref(self->_priv->images[i]);
162                         self->_priv->images[i] = NULL;
163                     }
164                 }
165                 q_free(self->_priv->images);
166                 /* q_free should do it, but force it */
167                 self->_priv->images = NULL;
168             }
169             PARENT_HANDLER(obj);
170         }
171     /* function implemented for the Gtk:Tree:Model interface */
172     interface Gtk:Tree:Model
173         private GtkTreeModelFlags
174         get_flags (Gtk:Tree:Model *self (check null type))
175         {
176             /* Here would be the implementation */
177             return (GtkTreeModelFlags)GTK_TREE_MODEL_LIST_ONLY;
178         }
181     interface Gtk:Tree:Model
182         public
183         gboolean iter_children(Gtk:Tree:Model *model, GtkTreeIter *iter, GtkTreeIter *parent)
184         {
185             Self *self  = GMPC_MPDDATA_MODEL(model);
186             if(parent)
187                 return FALSE;
188             if(self->num_rows == 0)
189                 return FALSE;
190             /* Set iter to first item in list */
191             iter->stamp = self->_priv->stamp; 
192             iter->user_data = self->_priv->data;
193             iter->user_data2 =  GINT_TO_POINTER(0);
194             iter->user_data3 = NULL;    /* unused */
196             return TRUE;
197         }
198     /**
199      * Unused, not known in the model directly? 
200      */
201     interface Gtk:Tree:Model    
202         public
203         gint get_n_columns(Gtk:Tree:Model *model)
204         {
205             return MPDDATA_MODEL_N_COLUMNS;
206         }
208     interface Gtk:Tree:Model
209         private gboolean
210         get_iter(Gtk:Tree:Model *model (check null type),
211                 Gtk:Tree:Iter *iter (check null),
212                 Gtk:Tree:Path *path (check null))
213         {
214             Self *self = GMPC_MPDDATA_MODEL(model);
215             MpdData_real *data = NULL;
216             gint i=0;
217             const gint *indices = gtk_tree_path_get_indices(path);
218             gint depth = gtk_tree_path_get_depth(path);
219             gint n = indices[0];        /* the n-th top level row */
221             /* No Children */
222             g_assert(depth == 1); 
224             if (n >= self->num_rows || n < 0)
225                 return FALSE; 
227             g_assert(n<self->num_rows);
228             /* If it is the first item in a has_up list, do nothing */
229             if(self->has_up && n == 0){
230                 data = NULL;
231                 goto end;
232             }
233             data = (MpdData_real *)self->_priv->data;
235             if(self->has_up)
236                 i=1;
238             for(; i < (n);i++)
239             {
240                 data = data->next; 
241             }
242 end:
243             iter->stamp = self->_priv->stamp;
244             iter->user_data = data; 
245             iter->user_data2 = GINT_TO_POINTER(n);
246             return TRUE;
247         }
249     interface Gtk:Tree:Model
250         private gboolean
251         iter_next(Gtk:Tree:Model *model(check null type), GtkTreeIter *iter (check null))
252         {
253             Self *self = GMPC_MPDDATA_MODEL(model);
254             MpdData *data = iter->user_data;
255             int n = GPOINTER_TO_INT(iter->user_data2) ;
256             /* if the row is the last row in the list or bigger then the last row, return FALSE */
257             if(n >= self->num_rows)
258             {
259                 return FALSE;
260             }
261             /* if the row is the first row in the list, and it has a "go-up" entry, 
262              * it can have a next entry
263              */
264             if(data == NULL &&  n == 0 && self->has_up == TRUE)
265             {
266                 iter->user_data = (MpdData *)self->_priv->data; 
267                 iter->user_data2 = GINT_TO_POINTER(1);
268                 if(iter->user_data == NULL)
269                     return FALSE;
270                 return TRUE;
271             }
272             if(mpd_data_get_next_real(data,FALSE) == NULL)
273             {
274                 return FALSE;
275             }
276             iter->user_data = (MpdData *)mpd_data_get_next_real(data,FALSE); 
277             iter->user_data2 = GINT_TO_POINTER(n+1);
278             g_assert(iter->user_data != NULL);
279             return TRUE;
280         }
282     interface Gtk:Tree:Model
283         private gboolean
284         iter_has_child(Gtk:Tree:Model *self (check null type), GtkTreeIter *iter)
285         {
286             return FALSE;
287         }
288     interface Gtk:Tree:Model
289         private gint
290         iter_n_children(Gtk:Tree:Model *model (check null type), GtkTreeIter *iter)
291         { 
292             Self *list = GMPC_MPDDATA_MODEL(model);
293             if(iter)
294                 return 0;
295             return list->num_rows;
296         }
298     interface Gtk:Tree:Model
299         private gboolean
300         iter_parent(Gtk:Tree:Model *model (check null type), Gtk:Tree:Iter *iter, Gtk:Tree:Iter *child)
301         {
302             return FALSE;
303         }
304     private 
305         void
306         cover_art_fetched(mpd_Song *song, MetaDataResult ret,MetaData *met,GtkTreeRowReference *ref)
307         {
309             if(ref)
310             {
311                 GtkTreePath *path =gtk_tree_row_reference_get_path(ref);
312                 GtkTreeModel *model = gtk_tree_row_reference_get_model(ref);
313                 if(path && model)
314                 {
315                                         int n;  
316                     Self *self = GMPC_MPDDATA_MODEL(model);
317                     GtkTreeIter iter;
319                     g_assert(self->_priv->use_images == TRUE);
321                     gtk_tree_model_get_iter(model, &iter, path);
322                     n = GPOINTER_TO_INT(iter.user_data2) ;
323                     if(ret == META_DATA_AVAILABLE)
324                     {
325                         
326                         GdkPixbuf *pb = NULL;
327                         if(met->content_type == META_DATA_CONTENT_URI)
328                         {
329                             const gchar *coverpath = meta_data_get_uri(met);
330                             pb = gdk_pixbuf_new_from_file_at_size(coverpath,self->icon_size,self->icon_size,NULL);
331                             screenshot_add_border(&pb);
332                         }else{
333                             pb = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "gmpc-no-cover", self->icon_size, 0,NULL);
334                         }
335                         if(self->_priv->images[n]) g_object_unref(self->_priv->images[n]); 
336                         self->_priv->images[n] = pb;
337                     }
338                     else   if(ret == META_DATA_UNAVAILABLE)
339                     {
340                         GdkPixbuf *pb2;
341                         pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "gmpc-no-cover", self->icon_size, 0,NULL);
342                         if(self->_priv->images[n]) g_object_unref(self->_priv->images[n]); 
343                         self->_priv->images[n] = pb2;
344                     }
345                     gtk_tree_model_row_changed(model,path, &iter);
346                     gtk_tree_path_free(path);
347                 }
349                 if(ret == META_DATA_AVAILABLE || ret == META_DATA_UNAVAILABLE)
350                 {
351                     if(ref)
352                     {
353                         gtk_tree_row_reference_free(ref);
354                     }
355                 }
356             }
357         }
359     interface Gtk:Tree:Model
360         public void
361         get_value(Gtk:Tree:Model *model(check null type), GtkTreeIter *iter (check null), gint column (check >= 0 < MPDDATA_MODEL_N_COLUMNS), GValue *value (check null))
362         {
363             Self *self = GMPC_MPDDATA_MODEL(model);
364             MpdData_real *data = iter->user_data;       
365             int n = GPOINTER_TO_INT(iter->user_data2);
367             if(self->_priv->data == NULL)
368                 g_warning("self->_priv->data == NULL");
369             /* set value to the correct type */
370             g_value_init(value, self->types[column]);
372             /** 
373              * Sanity checks 
374              */
375              g_assert((n < self->num_rows || n == 0));
376             g_assert(!(data == NULL && n != 0));
378             /* handle row up */
379             if(data == NULL && n == 0)
380             {
381                 switch(column)
382                 {
383                     case MPDDATA_MODEL_COL_ICON_ID:
384                         g_value_set_string(value, GTK_STOCK_GO_UP);
385                         break;
386                     case MPDDATA_MODEL_ROW_TYPE:
387                         /**
388                          * Make define 
389                          */
390                         g_value_set_int(value, -1);
391                         break;
392                     case MPDDATA_MODEL_COL_SONG_TITLE:
393                     case MPDDATA_MODEL_COL_MARKUP:
394                         {
395                             g_value_set_string(value,"..");
396                             break;
397                         }
398                     default:
399                         break;
400                 }
401                 return;
402             }
404             if(column == MPDDATA_MODEL_META_DATA)
405             {
406                 if(self->_priv->use_images && self->_priv->images)
407                 {
408                     if(self->_priv->images[n] == NULL)
409                     {
410                         if(data->type == MPD_DATA_TYPE_TAG && (data->tag_type == MPD_TAG_ITEM_ARTIST || data->tag_type == MPD_TAG_ITEM_ALBUM_ARTIST) )
411                         {
412                             mpd_Song *song;
413                             GtkTreePath *path;
414                             GtkTreeRowReference *ref;
415                             self->_priv->images[n] = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "gmpc-loading-cover", self->icon_size, 0,NULL);
416                             song = mpd_newSong();
417                             song->artist = g_strdup(data->tag);
418                             song->album = NULL; 
419                             path = gtk_tree_model_get_path(GTK_TREE_MODEL(self), iter);
420                             ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(self),path);
421                             gmpc_meta_watcher_get_meta_path_callback(gmw,song, META_ARTIST_ART, (MetaDataCallback)self_cover_art_fetched, (gpointer)ref);
422                             mpd_freeSong(song); 
423                             gtk_tree_path_free(path);
424                         }
426                         else if(data->type == MPD_DATA_TYPE_TAG && data->tag_type == MPD_TAG_ITEM_ALBUM && self->_priv->req_artist)
427                         {
428                             mpd_Song *song;
429                             GtkTreePath *path;
430                             GtkTreeRowReference *ref;
431                             self->_priv->images[n] = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "gmpc-loading-cover", self->icon_size, 0,NULL);
432                             song = mpd_newSong();
433                             song->artist = g_strdup(self->_priv->req_artist); 
434                             song->albumartist = g_strdup(self->_priv->req_artist); 
435                             song->album = g_strdup(data->tag);
436                             path = gtk_tree_model_get_path(GTK_TREE_MODEL(self), iter);
437                             ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(self),path);
438                             gmpc_meta_watcher_get_meta_path_callback(gmw,song, META_ALBUM_ART, (MetaDataCallback)self_cover_art_fetched, ref);
439                             mpd_freeSong(song); 
440                             gtk_tree_path_free(path);
441                         }
442                         else if(data->type == MPD_DATA_TYPE_SONG&& data->song && data->song->album && (data->song->artist || self->_priv->req_artist)) 
443                         {
444                             mpd_Song *song;
445                             GtkTreePath *path;
446                             GtkTreeRowReference *ref;
447                             self->_priv->images[n] = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "gmpc-loading-cover", self->icon_size, 0,NULL);
448                             song = mpd_newSong();
449                             song->artist = g_strdup((data->song->artist)?data->song->artist:self->_priv->req_artist); 
450                             song->albumartist = g_strdup((data->song->albumartist)?data->song->albumartist:self->_priv->req_artist); 
451                             song->album = g_strdup(data->song->album);
452                             path = gtk_tree_model_get_path(GTK_TREE_MODEL(self), iter);
453                             ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(self),path);
454                             gmpc_meta_watcher_get_meta_path_callback(gmw,song, META_ALBUM_ART, (MetaDataCallback)self_cover_art_fetched, ref);
455                             mpd_freeSong(song); 
456                             gtk_tree_path_free(path);
457                         }
458                         else 
459                         {
460                             self->_priv->images[n] = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "gmpc-no-cover", self->icon_size, 0,NULL);
461                         }
462                     }
463                     g_value_set_object(value, self->_priv->images[n]);
464                 }else{
465                     g_value_set_object(value,NULL); 
466                 }
467             }
468             if(column == MPDDATA_MODEL_USERDATA)
469             {
470                 g_value_set_pointer(value,data->userdata);
472             }
473             /* handle row type, this is independent of the row type */
474             if(column == MPDDATA_MODEL_ROW_TYPE)
475             {
476                 g_value_set_int(value, data->type);
477                 return;
478             } 
479             if (data->type == MPD_DATA_TYPE_TAG) {
480                 switch(column)
481                 {
482                     case MPDDATA_MODEL_COL_ICON_ID:
483                         switch(data->tag_type) 
484                         {
485                             case MPD_TAG_ITEM_ALBUM:
486                                 g_value_set_string(value, "media-album");
487                                 break;
488                             case MPD_TAG_ITEM_ARTIST:
489                                 g_value_set_string(value, "media-artist");
490                                 break;
491                             default:
492                                 g_value_set_string(value, "media-tag");
493                         }
494                         break;
495                     case MPDDATA_MODEL_COL_SONG_TITLE:
496                     case MPDDATA_MODEL_COL_MARKUP:
497                         {
498                             g_value_set_string(value, data->tag);
499                             break;
500                         }
501                     case MPDDATA_MODEL_COL_PATH:
502                         g_value_set_string(value, data->tag);
503                         break;                                                  
504                     case MPDDATA_MODEL_TAG_TYPE:
505                         g_value_set_int(value, data->tag_type);
506                         break;                                                  
507                     default:
508                         break;
509                 }
510             } else if(data->type == MPD_DATA_TYPE_DIRECTORY) {
511                 switch(column)
512                 {
513                     case MPDDATA_MODEL_COL_ICON_ID:
514                         g_value_set_string(value, GTK_STOCK_OPEN);
515                         break;
516                     case MPDDATA_MODEL_COL_SONG_TITLE:
517                     case MPDDATA_MODEL_COL_SONG_TITLEFILE:
518                     case MPDDATA_MODEL_COL_MARKUP:
519                         {
520                             gchar *basename = g_path_get_basename(data->directory);
521                             g_value_set_string(value, basename);
522                             g_free(basename);
523                             break;
524                         }
525                     case MPDDATA_MODEL_COL_PATH:
526                         g_value_set_string(value, data->directory);
527                         break;                                                  
528                     default:
529                         break;
530                 }
531             }
532             else if(data->type == MPD_DATA_TYPE_PLAYLIST)
533             {
534                 switch(column)
535                 {
536                     case MPDDATA_MODEL_COL_ICON_ID:
537                         g_value_set_string(value, "media-playlist");
538                         break;
539                     case MPDDATA_MODEL_COL_SONG_TITLE:
540                     case MPDDATA_MODEL_COL_SONG_TITLEFILE:
541                     case MPDDATA_MODEL_COL_MARKUP:
542                         {
543                             gchar *basename = g_path_get_basename(data->playlist->path);
544                             g_value_set_string(value, basename);
545                             g_free(basename);
546                             break;
547                         }
548                     case MPDDATA_MODEL_COL_PATH:
549                         g_value_set_string(value, data->playlist->path);
550                         break;                                                  
551                     default:
552                         break;
553                 }
554             }
555             else if(data->type == MPD_DATA_TYPE_SONG)
556             {
557                 mpd_Song *song = data->song;
558                 switch (column) {
559                     case MPDDATA_MODEL_COL_MPDSONG:
560                         g_value_set_pointer(value, song);
561                         break;
562                     case MPDDATA_MODEL_COL_PLAYING:
563                         g_value_set_boolean(value, FALSE);
564                         break;
565                     case MPDDATA_MODEL_COL_PLAYING_FONT_WEIGHT:
566                         g_value_set_int(value, PANGO_WEIGHT_NORMAL);
567                         break;
568                     case MPDDATA_MODEL_COL_MARKUP:
569                         {
570                             /* we want to go cache this stuff */
571                             gchar buffer[1024];
572                             mpd_song_markup(buffer, 1024, GMPC_MPDDATA_MODEL(model)->_priv->markup, song);
573                             g_value_set_string(value, buffer);
574                             break;
575                         }
576                     case MPDDATA_MODEL_COL_PATH:
577                         g_value_set_string(value, song->file);
578                         break;
579                                                                                 case MPDDATA_MODEL_COL_PATH_EXTENSION:
580                                                                                                 {
581                                                                                                         int j = strlen(song->file);
582                                                                                                         for(;j>0&&song->file[j] != '.';j--);
583                                                                                                         g_value_set_string(value, &(song->file)[j+1]);
584                                                                                                         break;
585                                                                                                 }
586                                                                                 case MPDDATA_MODEL_COL_PATH_DIRECTORY:
587                                                                                                 {
588                                                                                                         gchar *dir = g_path_get_dirname(song->file);
589                                                                                                         g_value_set_string(value, dir);
590                                                                                                         g_free(dir);
591                                                                                                         break;
592                                                                                                 }
593                     case MPDDATA_MODEL_COL_SONG_ARTIST:
594                         g_value_set_string(value, song->artist);
595                         break;
596                     case MPDDATA_MODEL_COL_SONG_ALBUM:
597                         g_value_set_string(value, song->album);
598                         break;
599                     case MPDDATA_MODEL_COL_SONG_TITLE:
600                         /* If there is a song available use that, else use the filename */
601                         if(song->title) {
602                             g_value_set_string(value, song->title);
603                         } else {
604                             /* Use the markup stuff, this makes sure it gets processed equaly */
605                             gchar buffer[1024];
606                             mpd_song_markup(buffer, 1024, "%shortfile%", song);
607                             g_value_set_string(value, buffer);
608                         }
609                         break;
610                     case MPDDATA_MODEL_COL_SONG_TITLEFILE:
611                         {
612                             gchar *path = g_path_get_basename(song->file);
613                             g_value_set_string(value, path);
614                             g_free(path);
615                         }
616                         break;                                                          
617                     case MPDDATA_MODEL_COL_SONG_GENRE:
618                         g_value_set_string(value, song->genre);
619                         break;
620                     case MPDDATA_MODEL_COL_SONG_TRACK:
621                         g_value_set_string(value, song->track);
622                         break;
623                     case MPDDATA_MODEL_COL_SONG_NAME:
624                         g_value_set_string(value, song->name);
625                         break;
626                     case MPDDATA_MODEL_COL_SONG_COMPOSER:
627                         g_value_set_string(value, song->composer);
628                         break;
629                     case MPDDATA_MODEL_COL_SONG_PERFORMER:
630                         g_value_set_string(value, song->performer);
631                         break;
632                     case MPDDATA_MODEL_COL_SONG_DATE:
633                         g_value_set_string(value, song->date);
634                         break;
635                     case MPDDATA_MODEL_COL_SONG_LENGTH:
636                         g_value_set_int(value, song->time);
637                         break;
638                     case MPDDATA_MODEL_COL_SONG_LENGTH_FORMAT:
639                         {
640                             if(song->time >= 0) {
641                                 gchar *strdata = g_strdup_printf("%02i:%02i",
642                                         song->time/60, song->time%60);
643                                 g_value_set_string(value, strdata);
644                                 g_free(strdata);
645                             } else {
646                                 g_value_set_string(value, "n/a");
647                             }
648                         }
649                         break;                                                  
650                     case MPDDATA_MODEL_COL_SONG_DISC:
651                         g_value_set_string(value, song->disc);
652                         break;
653                     case MPDDATA_MODEL_COL_SONG_COMMENT:
654                         g_value_set_string(value, song->comment);
655                         break;                                                  
656                     case MPDDATA_MODEL_COL_SONG_POS:
657                         g_value_set_int(value, song->pos+1);
658                         break;
659                     case MPDDATA_MODEL_COL_SONG_ALBUMARTIST:
660                         g_value_set_string(value, song->albumartist);
661                         break;
662                     case MPDDATA_MODEL_COL_SONG_ID:
663                         g_value_set_int(value, song->id);
664                         break;
666                     case MPDDATA_MODEL_COL_ICON_ID:
667                         if (strstr(song->file, "://")) {
668                             g_value_set_string(value, "media-stream");
669                         } else {
670                             g_value_set_string(value, "media-audiofile");
671                         }
672                         break;
673                     default:
674                         break;
675                 }
676             }
677         }
679     interface Gtk:Tree:Model
680         private gboolean
681         iter_nth_child(Gtk:Tree:Model *model(check null type), GtkTreeIter *iter (check null), GtkTreeIter *parent, gint n (check >=0)) 
682         {
683             Self *self = GMPC_MPDDATA_MODEL(model);
684             int i;
685             MpdData_real *data = NULL;
686             if(parent)
687                 return FALSE;
688             if (n >= self->num_rows || n < 0)
689                 return FALSE; 
691             data = (MpdData_real *)self->_priv->data;
692             i=0;
693             if(self->has_up)
694                 i=1;
695             for(; i < (n);i++)
696             {
697                 data = data->next;//mpd_data_get_next_real(data, FALSE);
698                 g_assert(data != NULL);
699             }
701             if(self->has_up && n == 0)
702                 data = NULL;
704             iter->stamp = self->_priv->stamp;
705             iter->user_data = data; 
706             iter->user_data2 = GINT_TO_POINTER(n);
707             return TRUE;
708         }
710     interface Gtk:Tree:Model
711         private GtkTreePath *
712         get_path(Gtk:Tree:Model *self (check null type), GtkTreeIter *iter (check null))
713         {
714             GtkTreePath *path = NULL;
715             path = gtk_tree_path_new();
716             gtk_tree_path_append_index(path, GPOINTER_TO_INT(iter->user_data2));
717             return path;
718         }
720     interface Gtk:Tree:Model
721         private GType
722         get_column_type(Gtk:Tree:Model *model(check null type), gint ind (check >= 0))
723         {
724             Self *self = GMPC_MPDDATA_MODEL(model);
725             return self->types[ind];
726         } 
727     public 
728         void 
729         set_request_artist(self, const char *artist)
730         {
731             int i;
732             GtkTreePath *path = NULL;
733             GtkTreeIter iter;
734             if(self->_priv->req_artist) 
735                 q_free(self->_priv->req_artist);
736             self->_priv->req_artist = (artist != NULL && artist[0] != '\0')?g_strdup(artist):NULL;
737             /* Free possible stored images */
738             if(self->_priv->images && self->_priv->use_images)
739             {
740                 MpdData *data2 = mpd_data_get_first(self->_priv->data); 
741                 for(i=0;i<self->num_rows;i++)
742                 {
743                     if(self->_priv->images[i]){
744                         g_object_unref(self->_priv->images[i]);
745                         self->_priv->images[i] = NULL;
746                     
747                         /* Update the view */
748                         path = gtk_tree_path_new();
749                         gtk_tree_path_append_index(path,i);
750                         iter.stamp = self->_priv->stamp;
751                         iter.user_data = data2;
752                         iter.user_data2 =  GINT_TO_POINTER(i);
753                         /* propegate change */
754                         gtk_tree_model_row_changed(GTK_TREE_MODEL(self), path, &iter);
755                         gtk_tree_path_free(path);
756                     }
757                     data2 = mpd_data_get_next_real(data2,FALSE);
758                 }
759             }
760         }
761         public
762         const char *
763         get_request_artist(self)
764         {
765             return self->_priv->req_artist;
766         }
767     public 
768         long unsigned set_mpd_data(self, MpdData *data2)
769         {
770             int i;
771             long unsigned retval = 0;
772             GtkTreeIter iter;
773             GtkTreePath *path = NULL;
774             int old_num_rows = self->num_rows;
775             /* Do some cleanup, like removing rows, and so */
776             /* loop and remove */
777             while ( self->num_rows > 0 ) {
778                 path = gtk_tree_path_new();
779                 gtk_tree_path_append_index(path, self->num_rows - 1 );
780                 /* propegate change */
781                 gtk_tree_model_row_deleted(GTK_TREE_MODEL(self), path);
782                 gtk_tree_path_free(path);
783                 self->num_rows--;
784             }
787             /**
788              * Free if there is a list and set it to NULL 
789              */
790             if(self->_priv->data)
791                 mpd_data_free(self->_priv->data);
792             self->_priv->data = NULL;
794             if(self->num_rows != 0)
795                 debug_printf(DEBUG_ERROR,"not every row cleared %i\n",self->num_rows);
796             self->num_rows =0;
797             /* Free possible stored images */
798             if(self->_priv->images && self->_priv->use_images)
799             {
800                 for(i=0;i< old_num_rows;i++)
801                 {
802                     if(self->_priv->images[i])
803                         g_object_unref(self->_priv->images[i]);
804                 }
805                 q_free(self->_priv->images);
806             }
807             if(data2 == NULL)
808             {
809                 self->_priv->playtime = 0;
810                 self_playtime_changed(self, self->_priv->playtime);
811                 return 0;
812             }
814             self->_priv->data = mpd_data_get_first(data2);
815             data2 = NULL;
816             if(self->_priv->sort_column == MPDDATA_MODEL_COL_ICON_ID)
817             {
818                 self->_priv->data = misc_sort_mpddata_by_album_disc_track(self->_priv->data);
819             }
820             else if ( self->_priv->sort_column != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID )
821             {
822                 self->_priv->data = misc_sort_mpddata(self->_priv->data,(GCompareDataFunc)self_sort_func,self ); 
823             }
825             if(self->has_up) {
826                 path = gtk_tree_path_new();
827                 gtk_tree_path_append_index(path, self->num_rows);
828                 iter.stamp = self->_priv->stamp;
829                 iter.user_data = NULL; 
830                 iter.user_data2 =  GINT_TO_POINTER(self->num_rows);
832                 self->num_rows++;
833                 /* propegate change */
834                 gtk_tree_model_row_inserted(GTK_TREE_MODEL(self), path, &iter);
835                 gtk_tree_path_free(path);
836             }
837             for(data2 = mpd_data_get_first(self->_priv->data);data2; data2 = mpd_data_get_next_real(data2,FALSE)) {
838                 path = gtk_tree_path_new();
839                 gtk_tree_path_append_index(path,self->num_rows);
840                 iter.stamp = self->_priv->stamp;
841                 iter.user_data = data2;
842                 iter.user_data2 =  GINT_TO_POINTER(self->num_rows);
844                 self->num_rows++;
845                 /* propegate change */
846                 gtk_tree_model_row_inserted(GTK_TREE_MODEL(self), path, &iter);
847                 gtk_tree_path_free(path);
848                 if(data2->type == MPD_DATA_TYPE_SONG)
849                 {
850                     if(data2->song && data2->song->time > 0)
851                         retval+= data2->song->time;
852                 }
853             }
854             if(self->_priv->use_images)
855             {
856                 self->_priv->images = g_malloc0((self->num_rows)*sizeof(*(self->_priv->images)));
857             }
859             self->_priv->playtime = retval;
860             self_playtime_changed(self, self->_priv->playtime);
861             return retval;
862         }
864     /* Sorting */
865     interface Gtk:Tree:Sortable
866         private 
867         gboolean get_sort_column_id (Gtk:Tree:Sortable *model ,  gint *sort_column_id, GtkSortType *order)
868         {
869             Self *self = GMPC_MPDDATA_MODEL(model);
870             if(sort_column_id) 
871                 *sort_column_id = self->_priv->sort_column;
872             if(order)
873                 *order = self->_priv->sort_order;
874             return TRUE;
875         }
877     interface Gtk:Tree:Sortable
878         private 
879         void set_sort_column_id (Gtk:Tree:Sortable *model ,  gint sort_column_id, GtkSortType order)
880         {
881             Self *self = GMPC_MPDDATA_MODEL(model);
882             gint old_col = self->_priv->sort_column;
883             GtkSortType old_ord = self->_priv->sort_order;
884             self->_priv->sort_column = sort_column_id;
885             self->_priv->sort_order = order;
886             /* trigger signal */
887             if(old_col != sort_column_id || old_ord != order)
888                 gtk_tree_sortable_sort_column_changed(model);
889             self->_priv->old_sort_column = self->_priv->sort_column;
891         }
893     interface Gtk:Tree:Sortable
894         private
895         gboolean
896         has_default_sort_func(Gtk:Tree:Sortable *model)
897         {
898             return FALSE;
899         }
900       private 
901         int sort_func(gpointer ppaa, gpointer ppbb, Self *self)
902         {
903             MpdData_real *a = *(MpdData_real **)ppaa;
904             MpdData_real *b = *(MpdData_real **)ppbb;
905             int fact = (self->_priv->sort_order == GTK_SORT_ASCENDING)?-1:1;
907             if(a->type != b->type )
908             {
909                 int val = a->type - b->type; 
910                 return val; 
911             }
912             else if(a->type == b->type)
913             {
914                 int val=0;
915                 GtkTreeIter iter;
916                 GValue va = {0,},vb = {0,};
917                 /* Get values from tree view, so we don't have to replicate code to sort the right entries */
918                 iter.user_data = a;
919                 iter.user_data2 = GPOINTER_TO_INT(0);
920                 gtk_tree_model_get_value(GTK_TREE_MODEL(self), &iter, self->_priv->sort_column, &va);
921                 iter.user_data = b;
922                 gtk_tree_model_get_value(GTK_TREE_MODEL(self), &iter, self->_priv->sort_column, &vb);
923                 /* if the type is a directory or a tag, always sort on the title column */
924                 if(a->type == MPD_DATA_TYPE_DIRECTORY || b->type == MPD_DATA_TYPE_TAG)
925                 {
926                     const char *ca,*cb;
927                     ca = g_value_get_string(&va);
928                     cb = g_value_get_string(&vb);
929                     if(ca && cb) {
930                         gchar *aa,*bb;
931                         aa = g_utf8_strdown(ca, -1);
932                         bb = g_utf8_strdown(cb, -1);
933                         val = g_utf8_collate(aa,bb);
934                         g_free(aa);
935                         g_free(bb);
936                     } else {
937                         val = (ca == NULL)?((cb==NULL)?0:-1):1;
938                     }
939                     g_value_unset(&va);
940                     g_value_unset(&vb);
941                     /* return */
942                     return val*fact;
943                 }
944                 if(self->_priv->sort_column == MPDDATA_MODEL_COL_SONG_TRACK)
945                 {
946                     const char *ca = g_value_get_string(&va);
947                     const char *cb = g_value_get_string(&vb);
948                     gint ca1 = (ca)?atoi(ca):0;
949                     gint cb1 = (cb)?atoi(cb):0;
950                     g_value_unset(&va);
951                     g_value_unset(&vb);
952                     return fact*(ca1-cb1);
953                 }
954                 else if(self->types[self->_priv->sort_column] == G_TYPE_INT)
955                 {
956                     val = g_value_get_int(&va) - g_value_get_int(&vb);
957                 }
958                 else if (self->types[self->_priv->sort_column] == G_TYPE_STRING)
959                 {
960                     const char *ca = g_value_get_string(&va);
961                     const char *cb = g_value_get_string(&vb);
962                     if(ca && cb) {
963                         gchar *aa,*bb;
964                         aa = g_utf8_normalize(ca, -1,G_NORMALIZE_ALL);
965                         bb = g_utf8_normalize(cb, -1,G_NORMALIZE_ALL);
966                         val = g_utf8_collate(aa,bb);
967                         g_free(aa);
968                         g_free(bb);
969                     } else {
970                         val = (ca == NULL)?((cb==NULL)?0:-1):1;
971                     }
972                 }
973                 g_value_unset(&va);
974                 g_value_unset(&vb);
975                 return fact*val; 
976             }
977             return 0;
978         }
980     interface Gtk:Tree:Sortable
981         private
982         void 
983         sort_column_changed(Gtk:Tree:Sortable *model)
984         {
985             Self *self = GMPC_MPDDATA_MODEL(model);
986             if(!self->_priv->data || !(((MpdData_real *)self->_priv->data)->next))
987                 return; 
988             if(self->_priv->sort_column == MPDDATA_MODEL_COL_ICON_ID)
989             {
990                 self->_priv->data = misc_sort_mpddata_by_album_disc_track(self->_priv->data); 
991             }
992             else if(self->_priv->sort_column !=  GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
993             {
994                 self->_priv->data = misc_sort_mpddata(self->_priv->data,(GCompareDataFunc)self_sort_func,self ); 
995             }
996             self->_priv->old_sort_column = self->_priv->sort_column;
998             /* tell the view that rows have changed  */    
999             {
1000                 int i=0;
1001                 GtkTreePath *path = NULL;
1002                 GtkTreeIter iter;
1003                 MpdData *data2 = mpd_data_get_first(self->_priv->data); 
1004                 if(self->has_up) i = 1;
1005                 for(;data2; data2 = mpd_data_get_next_real(data2,FALSE)) 
1006                 {
1007                     path = gtk_tree_path_new();
1008                     gtk_tree_path_append_index(path,i);
1009                     iter.stamp = self->_priv->stamp;
1010                     iter.user_data = data2;
1011                     iter.user_data2 =  GINT_TO_POINTER(i);
1013                     /* propegate change */
1014                     gtk_tree_model_row_changed(GTK_TREE_MODEL(self), path, &iter);
1015                     gtk_tree_path_free(path);
1016                     i++;
1017                 }
1018             }
1019         }
1021         private
1022         int
1023         test_sort_func(gpointer ppaa, gpointer ppbb, Self *self)
1024         {
1025             MpdData_real *a = *(MpdData_real **)ppaa;
1026             MpdData_real *b = *(MpdData_real **)ppbb;
1027             return strcmp(a->tag, b->tag); 
1028         }
1030         /**
1031          * For now this assumes tag list only.
1032          */
1033     public 
1034         long unsigned set_mpd_data_slow (self, MpdData *data2)
1035         {                                               
1036             MpdData_real *new_list = NULL;
1037             int i=0;
1038             int items=0;
1039             MpdData_real *original = (MpdData_real *)mpd_data_get_first(self->_priv->data);
1040             MpdData_real *new = (MpdData_real *) data2;
1041             GtkTreePath *path =NULL;
1042             GtkTreeIter iter;
1043             int old_list_size = self->num_rows;
1045             /* sort it identical */
1046             data2 = misc_sort_mpddata(data2,(GCompareDataFunc)self_test_sort_func,self ); 
1047             new = (MpdData_real *)data2;
1049             if(new) {
1050                 MpdData_real *n = new->first;
1051                 while(n) {
1052                     items++;
1053                     n = n->next;
1054                 }
1055             }
1058             /* Free possible stored images */
1059             /**
1060              * TODO: Don't free the list, but grow it to MAX(items, self->num_rows);
1061              * Then after updating, resize it to new size 
1062              */
1063             /* Grow the list when needed */
1065             if(self->_priv->use_images)
1066             {
1067                 /* Clean them, they might not be in the right place anymore */
1068                 for(i=0;i< old_list_size; i++)
1069                 {
1070                     if(self->_priv->images[i] != NULL) g_object_unref(self->_priv->images[i]);
1071                     self->_priv->images[i] = NULL;
1072                 }
1073                 if(items > self->num_rows)
1074                 {
1075                     self->_priv->images = g_realloc(self->_priv->images, items*sizeof(GdkPixbuf *));
1076                     /* set the new ones to NUll */
1077                     for(i=self->num_rows;i<items;i++)
1078                     {
1079                         self->_priv->images[i] = NULL;
1080                     }
1081                 }
1082             }
1087             i=0;
1088             /* compare lists */
1089             if(self->_priv->data && original == NULL) g_warning("weirdness\n");
1090             if(self->_priv->data)
1091             {
1092                 int has_next;
1093                 do
1094                 {
1095                     has_next = 0;
1096                     if(new == NULL)
1097                     {
1098                         if(self->num_rows > items)
1099                         {
1100                             MpdData_real *n = original->next;
1101                             /* remove current row */
1102                             self->num_rows--;
1104                             path = gtk_tree_path_new();
1105                             gtk_tree_path_append_index(path,i);
1107                             /* propegate change */
1108                             gtk_tree_model_row_deleted(GTK_TREE_MODEL(self), path);
1109                             gtk_tree_path_free(path);
1110                            
1111                             original =(MpdData_real *) mpd_data_delete_item((MpdData *)original); 
1112                             self->_priv->data = mpd_data_get_first((MpdData *)original);
1114                             original=n;
1115                             has_next = (original )?1:0;
1116                         }
1117                     }
1118                     else
1119                     {
1120                         int compare = strcmp(new->tag, original->tag);
1121                         if(compare < 0)
1122                         {
1123                             /* add */
1124                             MpdData_real *n = (MpdData_real *) mpd_new_data_struct();
1125                             n->type = MPD_DATA_TYPE_TAG;
1126                             n->tag_type = new->tag_type;
1127                             n->tag = new->tag;
1128                             new->tag = NULL;
1130                             /* add */
1132                             self->num_rows++;
1133                             n->prev = original->prev;
1135                             if(original->prev)
1136                                 original->prev->next = n;
1137                             n->next = original;
1138                             n->first = original->first;
1139                             original->prev = n;
1140                             if(n->prev == NULL){
1141                                 MpdData_real *fiter;
1142                                 for(fiter = n;fiter;fiter = fiter->next){
1143                                     fiter->first = n;
1144                                 }
1145                             }
1147                             self->_priv->data = mpd_data_get_first((MpdData *)original);
1148                             {
1149                                 path = gtk_tree_path_new();
1150                                 gtk_tree_path_append_index(path,i);
1151                                 iter.stamp = self->_priv->stamp;
1152                                 iter.user_data = n;
1153                                 iter.user_data2 =  GINT_TO_POINTER(i);
1155                                 gtk_tree_model_row_inserted(GTK_TREE_MODEL(self), path, &iter);
1156                                 gtk_tree_path_free(path);
1157                             }
1158                             /* mark for insert */
1159                             new=new->next;
1160                             i++;
1161                             has_next = 1;
1162                         }
1163                         else if (compare > 0)
1164                         {
1165                             MpdData_real *n = original->next;
1166                             path = gtk_tree_path_new();
1167                             gtk_tree_path_append_index(path,i);
1168                             /* propegate change */
1170                             self->num_rows--;
1171                             gtk_tree_model_row_deleted(GTK_TREE_MODEL(self), path);
1172                             gtk_tree_path_free(path);
1175                             original = (MpdData_real *)mpd_data_delete_item((MpdData *)original); 
1176                             self->_priv->data = mpd_data_get_first((MpdData *)original);
1177                             original = n;
1178                             //original = original->next; 
1179                             has_next = (original )?1:0;
1181                         }else{
1182                             new = new->next;
1183                             original = original->next;
1184                             has_next = (original )?1:0;
1185                             i++;
1186                         }
1187                     }            
1188                 }while(has_next);
1189             }
1190             /* add entries remaining in new */
1191             if(new)
1192             {
1193                 
1194                 new_list = (MpdData_real *) self->_priv->data;
1195                 while(new_list && new_list->next) new_list = new_list->next;
1196                 do{
1197                     new_list = (MpdData_real *)mpd_new_data_struct_append((MpdData*)new_list); 
1198                     new_list->type = MPD_DATA_TYPE_TAG;
1199                     new_list->tag_type = new->tag_type;
1200                     new_list->tag = new->tag;
1201                     new->tag = NULL;
1203                     self->_priv->data = (MpdData *)new_list->first;
1204                     if(self->_priv->data == NULL) g_warning("self->_priv->data == NULL");
1205                     self->num_rows++;
1206                     {
1207                         path = gtk_tree_path_new();
1208                         gtk_tree_path_append_index(path,i);
1209                         iter.stamp = self->_priv->stamp;
1210                         iter.user_data = new_list;
1211                         iter.user_data2 =  GINT_TO_POINTER(i);
1213                         gtk_tree_model_row_inserted(GTK_TREE_MODEL(self), path, &iter);
1214                         gtk_tree_path_free(path);
1215                     }
1217                     new = new->next;
1218                     i++;
1219                 }while(new);
1220             }
1223             if(self->_priv->use_images){
1224                 if(self->num_rows < old_list_size){
1225                     for(i=self->num_rows;i< old_list_size; i++)
1226                     {
1227                         /* clean it */
1228                         if(self->_priv->images[i] != NULL) g_object_unref(self->_priv->images[i]);
1229                     }
1230                     self->_priv->images = g_realloc(self->_priv->images, (self->num_rows)*sizeof(GdkPixbuf *));
1231                 }
1232             }
1234    
1236             if(data2)
1237                 mpd_data_free(data2);
1239             g_assert(items == self->num_rows);
1240             return 0;                    
1241         }
1243         signal last NONE (LONG)
1244         void
1245         playtime_changed(self, gulong playtime)
1246         {
1247             return;
1248         }
1250     public
1251     gulong
1252     get_playtime(self)
1253     {
1254         return self->_priv->playtime;
1255     }
1256     public
1257     gint
1258     get_pos( self, GtkTreeIter *iter)
1259     {
1260             g_assert(iter->stamp == self->_priv->stamp);
1261             return GPOINTER_TO_INT(iter->user_data2);
1262     }
1264     public
1265     void
1266     disable_image(self)
1267     {
1268         g_assert(self->_priv->data == NULL);
1269         self->_priv->use_images = FALSE;
1270     }
1272     public
1273     MpdData * 
1274     steal_mpd_data(self)
1275     {
1276         GtkTreePath *path;
1277         int i;
1278         int old_num_rows = self->num_rows;
1279         MpdData *data = self->_priv->data; 
1280         while ( self->num_rows > 0 ) {
1281             path = gtk_tree_path_new();
1282             gtk_tree_path_append_index(path, self->num_rows - 1 );
1283             /* propegate change */
1284             gtk_tree_model_row_deleted(GTK_TREE_MODEL(self), path);
1285             gtk_tree_path_free(path);
1286             self->num_rows--;
1287         }
1289         /* Clear */
1290         self->_priv->data = NULL;
1291         /* Free possible stored images */
1292         if(self->_priv->images && self->_priv->use_images)
1293         {
1294             for(i=0;i<  old_num_rows;i++)
1295             {
1296                 if(self->_priv->images[i])
1297                     g_object_unref(self->_priv->images[i]);
1298             }
1299             q_free(self->_priv->images);
1300         }
1301         self->_priv->playtime = 0;
1302         self_playtime_changed(self, self->_priv->playtime);
1304         return mpd_data_get_first(data);
1305     }