Try to fix selecting issue.
[gmpc.git] / src / gmpc-mpddata-model.gob
blob61a843f8456c54a9e5f8844e74c826a8e6beaca7
1 /* Gnome Music Player Client (GMPC)
2  * Copyright (C) 2004-2012 Qball Cow <qball@gmpclient.org>
3  * Project homepage: http://gmpclient.org/
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 <config.h>
24 #include <gtk/gtk.h>
25 #include <libmpd/libmpd.h>
26 #include <libmpd/libmpd-internal.h>
29 %privateheader{
30 //#include "playlist3.h"
31 #include "config1.h"
32 #include "config-defaults.h"
33 #include "main.h"
34 #include "misc.h"
37 %h{
38 #define GMPC_MPD_DATA_MODEL(a) GMPC_MPDDATA_MODEL(a)
39         enum
40         {
41                 MPDDATA_MODEL_COL_MPDSONG = 0,                /* get the mpd_Song */
42                 MPDDATA_MODEL_COL_PLAYING,                                    /* Shows if this song is the current song */
43                 MPDDATA_MODEL_COL_PLAYING_FONT_WEIGHT,  /* Shows if this song is the current song */
44                 MPDDATA_MODEL_COL_PATH,                                         /* Path to song/file/directory */
45                 MPDDATA_MODEL_COL_MARKUP,                                     /* a string that has FALSEmarkup */
46                 MPDDATA_MODEL_COL_SONG_ARTIST,                      /* artist name */
47                 MPDDATA_MODEL_COL_SONG_ALBUM,                         /* album name */
48                 MPDDATA_MODEL_COL_SONG_TITLE,                         /* song title */
49                 MPDDATA_MODEL_COL_SONG_TITLEFILE,                   /* song title */
50                 MPDDATA_MODEL_COL_SONG_GENRE,                         /* song genre */
51                 MPDDATA_MODEL_COL_SONG_TRACK,                         /* song track */
52                 MPDDATA_MODEL_COL_SONG_NAME,                          /* stream name */
53                 MPDDATA_MODEL_COL_SONG_COMPOSER,                    /* composer name */
54                 MPDDATA_MODEL_COL_SONG_PERFORMER,                   /* performer */
55                 MPDDATA_MODEL_COL_SONG_DATE,                          /* date */
56                 MPDDATA_MODEL_COL_SONG_LENGTH_FORMAT,     /* length formatted */
57                 MPDDATA_MODEL_COL_SONG_DISC,                          /* disc */
58                 MPDDATA_MODEL_COL_SONG_COMMENT,                     /* comment */
59                 MPDDATA_MODEL_COL_SONG_POS,                                   /* position */
60         MPDDATA_MODEL_COL_SONG_ALBUMARTIST,
61                 MPDDATA_MODEL_COL_PATH_EXTENSION,                               /* Extention */
62                 MPDDATA_MODEL_COL_PATH_DIRECTORY,                               /* Directory */
63                 MPDDATA_MODEL_COL_SONG_ID,                                    /* col id */
64                 MPDDATA_MODEL_COL_ICON_ID,                                    /* icon id */
65                 MPDDATA_MODEL_COL_SONG_LENGTH,                      /* length */
66                 MPDDATA_MODEL_TAG_TYPE,                                   /* tag type */
67                 MPDDATA_MODEL_ROW_TYPE,                                         /* type of the row */
68                 MPDDATA_MODEL_META_DATA,                        /* metadata */
69                 MPDDATA_MODEL_USERDATA,
70         MPDDATA_MODEL_COL_SONG_PRIORITY,                /* priority */
71                 MPDDATA_MODEL_N_COLUMNS
72         } ;
76 #define LOG_DOMAIN "MpdData.Model"
79  class Gmpc:MpdData:Model from G:Object
80           (interface Gtk:Tree:Sortable)
81             (interface Gtk:Tree:Drag:Source)
82             (interface Gtk:Tree:Model)
84     private gint stamp          = {g_random_int()};
85     public      GType types[MPDDATA_MODEL_N_COLUMNS];
86     private MpdData *data       = NULL;
87     public gint num_rows = 0;
88     private GmpcPixbufLoaderAsync **images = NULL;
89     private gchar *req_artist = {NULL} destroywith g_free;
90     private GdkPixbuf *blank = {NULL} destroywith g_object_unref;
91     public gint icon_size = {cfg_get_single_value_as_int_with_default(config, "gmpc-mpddata-model", "icon-size", 32)};
93     /* sorting */
94     private GtkSortType sort_order = GTK_SORT_ASCENDING;
95     private int sort_column = GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID;
96     private int old_sort_column = GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID;
97     public gboolean has_up       = FALSE;
98     private gchar *markup        = {cfg_get_single_value_as_string_with_default(config, "playlist", "browser_markup",DEFAULT_MARKUP_BROWSER)} destroywith g_free;
100     private gulong playtime = {0};
103     private gboolean use_images = TRUE;
105     property BOOLEAN has_up
106         (nick = "Has Up",
107          blurb = "Show an 'up row",
108          default_value = FALSE,
109          export,
110          link);
112     init(self)
113     {
114         self->types[MPDDATA_MODEL_COL_MPDSONG] = G_TYPE_POINTER;
115         self->types[MPDDATA_MODEL_COL_MARKUP] = G_TYPE_STRING;
116         self->types[MPDDATA_MODEL_COL_PLAYING] = G_TYPE_BOOLEAN;
117         self->types[MPDDATA_MODEL_COL_PLAYING_FONT_WEIGHT] = G_TYPE_INT;
118         self->types[MPDDATA_MODEL_COL_PATH] = G_TYPE_STRING;
119         self->types[MPDDATA_MODEL_COL_SONG_ARTIST] = G_TYPE_STRING;
120         self->types[MPDDATA_MODEL_COL_SONG_ALBUM] = G_TYPE_STRING;
121         self->types[MPDDATA_MODEL_COL_SONG_TITLE] = G_TYPE_STRING;
122         self->types[MPDDATA_MODEL_COL_SONG_TITLEFILE] = G_TYPE_STRING;
123         self->types[MPDDATA_MODEL_COL_SONG_TRACK] = G_TYPE_STRING;
124         self->types[MPDDATA_MODEL_COL_SONG_GENRE] = G_TYPE_STRING;
125         self->types[MPDDATA_MODEL_COL_SONG_NAME] = G_TYPE_STRING;
126         self->types[MPDDATA_MODEL_COL_SONG_COMPOSER] = G_TYPE_STRING;
127         self->types[MPDDATA_MODEL_COL_SONG_PERFORMER]= G_TYPE_STRING;
128         self->types[MPDDATA_MODEL_COL_SONG_DATE] = G_TYPE_STRING;
129         self->types[MPDDATA_MODEL_COL_SONG_LENGTH] = G_TYPE_INT;
130         self->types[MPDDATA_MODEL_COL_SONG_LENGTH_FORMAT] = G_TYPE_STRING;
131         self->types[MPDDATA_MODEL_COL_SONG_DISC] = G_TYPE_STRING;
132         self->types[MPDDATA_MODEL_COL_SONG_COMMENT] = G_TYPE_STRING;
133         self->types[MPDDATA_MODEL_COL_SONG_POS] = G_TYPE_INT;
134         self->types[MPDDATA_MODEL_COL_SONG_ALBUMARTIST] = G_TYPE_STRING;
135         self->types[MPDDATA_MODEL_COL_PATH_EXTENSION] = G_TYPE_STRING;
136         self->types[MPDDATA_MODEL_COL_PATH_DIRECTORY] = G_TYPE_STRING;
137         self->types[MPDDATA_MODEL_COL_SONG_ID] = G_TYPE_INT;
138         self->types[MPDDATA_MODEL_COL_ICON_ID] = G_TYPE_STRING;
139         self->types[MPDDATA_MODEL_TAG_TYPE] = G_TYPE_INT;
140         self->types[MPDDATA_MODEL_ROW_TYPE] = G_TYPE_INT;
141         self->types[MPDDATA_MODEL_USERDATA] = G_TYPE_POINTER;
142         self->types[MPDDATA_MODEL_META_DATA] = GDK_TYPE_PIXBUF;
143         self->types[MPDDATA_MODEL_COL_SONG_PRIORITY] = G_TYPE_INT;
146         self->_priv->blank = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, self->icon_size, self->icon_size);
147         gdk_pixbuf_fill(self->_priv->blank, 0x00000000);
148     }
149     class_init(klass);
151     public
152         Gmpc:MpdData:Model *new (void)
153         {
154             return GET_NEW;
155         }
157     override (G:Object)
158         void
159         finalize (G:Object *obj)
160         {
161             int i =0;
162             Self *self = GMPC_MPDDATA_MODEL(obj);
164             if(self->_priv->data)
165             {
166                 mpd_data_free(self->_priv->data);
167                 self->_priv->data = NULL;
168             }
169             if(self->_priv->images && self->_priv->use_images)
170             {
171                 for(i=0;i<self->num_rows;i++)
172                 {
173                     if(self->_priv->images[i]) {
174                         g_object_unref(self->_priv->images[i]);
175                         self->_priv->images[i] = NULL;
176                     }
177                 }
178                 q_free(self->_priv->images);
179                 /* q_free should do it, but force it */
180                 self->_priv->images = NULL;
181             }
182             PARENT_HANDLER(obj);
183         }
184     /* function implemented for the Gtk:Tree:Model interface */
185     interface Gtk:Tree:Model
186         private GtkTreeModelFlags
187         get_flags (Gtk:Tree:Model *self (check null type))
188         {
189             /* Here would be the implementation */
190             return (GtkTreeModelFlags)GTK_TREE_MODEL_LIST_ONLY;
191         }
194     interface Gtk:Tree:Model
195         public
196         gboolean iter_children(Gtk:Tree:Model *model, GtkTreeIter *iter, GtkTreeIter *parent)
197         {
198             Self *self  = GMPC_MPDDATA_MODEL(model);
199             if(parent)
200                 return FALSE;
201             if(self->num_rows == 0)
202                 return FALSE;
203             /* Set iter to first item in list */
204             iter->stamp = self->_priv->stamp;
205             iter->user_data = self->_priv->data;
206             iter->user_data2 =  GINT_TO_POINTER(0);
207             iter->user_data3 = NULL;    /* unused */
209             return TRUE;
210         }
211     /**
212      * Unused, not known in the model directly?
213      */
214     interface Gtk:Tree:Model
215         public
216         gint get_n_columns(Gtk:Tree:Model *model)
217         {
218             return MPDDATA_MODEL_N_COLUMNS;
219         }
221     interface Gtk:Tree:Model
222         private gboolean
223         get_iter(Gtk:Tree:Model *model (check null type),
224                 Gtk:Tree:Iter *iter (check null),
225                 Gtk:Tree:Path *path (check null))
226         {
227             Self *self = GMPC_MPDDATA_MODEL(model);
228             MpdData_real *data = NULL;
229             gint i=0;
230             const gint *indices = gtk_tree_path_get_indices(path);
231             gint depth = gtk_tree_path_get_depth(path);
232             gint n = indices[0];        /* the n-th top level row */
234             /* No Children */
235             g_assert(depth == 1);
237             if (n >= self->num_rows || n < 0)
238                 return FALSE;
240             g_assert(n<self->num_rows);
241             /* If it is the first item in a has_up list, do nothing */
242             if(self->has_up && n == 0){
243                 data = NULL;
244                 goto end;
245             }
246             data = (MpdData_real *)self->_priv->data;
248             if(self->has_up)
249                 i=1;
251             for(; i < (n);i++)
252             {
253                 data = data->next;
254             }
255 end:
256             iter->stamp = self->_priv->stamp;
257             iter->user_data = data;
258             iter->user_data2 = GINT_TO_POINTER(n);
259             return TRUE;
260         }
262     interface Gtk:Tree:Model
263         private gboolean
264         iter_next(Gtk:Tree:Model *model(check null type), GtkTreeIter *iter (check null))
265         {
266             Self *self = GMPC_MPDDATA_MODEL(model);
267             MpdData *data = iter->user_data;
268             int n = GPOINTER_TO_INT(iter->user_data2) ;
269             /* if the row is the last row in the list or bigger then the last row, return FALSE */
270             if(n >= self->num_rows)
271             {
272                 return FALSE;
273             }
274             /* if the row is the first row in the list, and it has a "go-up" entry,
275              * it can have a next entry
276              */
277             if(data == NULL &&  n == 0 && self->has_up == TRUE)
278             {
279                 iter->user_data = (MpdData *)self->_priv->data;
280                 iter->user_data2 = GINT_TO_POINTER(1);
281                 if(iter->user_data == NULL)
282                     return FALSE;
283                 return TRUE;
284             }
285             if(mpd_data_get_next_real(data,FALSE) == NULL)
286             {
287                 return FALSE;
288             }
289             iter->user_data = (MpdData *)mpd_data_get_next_real(data,FALSE);
290             iter->user_data2 = GINT_TO_POINTER(n+1);
291             g_assert(iter->user_data != NULL);
292             return TRUE;
293         }
295     interface Gtk:Tree:Model
296         private gboolean
297         iter_has_child(Gtk:Tree:Model *self (check null type), GtkTreeIter *iter)
298         {
299             return FALSE;
300         }
301     interface Gtk:Tree:Model
302         private gint
303         iter_n_children(Gtk:Tree:Model *model (check null type), GtkTreeIter *iter)
304         {
305             Self *list = GMPC_MPDDATA_MODEL(model);
306             if(iter)
307                 return 0;
308             return list->num_rows;
309         }
311     interface Gtk:Tree:Model
312         private gboolean
313         iter_parent(Gtk:Tree:Model *model (check null type), Gtk:Tree:Iter *iter, Gtk:Tree:Iter *child)
314         {
315             return FALSE;
316         }
317     private
318         void
319         cover_art_fetched(mpd_Song *song, MetaDataResult ret,MetaData *met,GtkTreeRowReference *ref)
320         {
322             if(ref)
323             {
324                 GtkTreePath *path =gtk_tree_row_reference_get_path(ref);
325                 GtkTreeModel *model = gtk_tree_row_reference_get_model(ref);
326                 if(path && model)
327                 {
328                                         int n;
329                     Self *self = GMPC_MPDDATA_MODEL(model);
330                     GtkTreeIter iter;
332                     g_assert(self->_priv->use_images == TRUE);
334                     gtk_tree_model_get_iter(model, &iter, path);
335                     n = GPOINTER_TO_INT(iter.user_data2) ;
337                     if(self->_priv->images[n] == NULL){
338                         self->_priv->images[n]= gmpc_pixbuf_loader_async_new();
339                         gmpc_pixbuf_loader_async_set_rref(GMPC_PIXBUF_LOADER_ASYNC(self->_priv->images[n]), ref);
340                     }
342                     if(ret == META_DATA_AVAILABLE)
343                     {
345                         GdkPixbuf *pb = NULL;
346                                                 if (met->content_type == META_DATA_CONTENT_RAW) {
347                             MpdData_real *data = iter.user_data;
348                             gmpc_pixbuf_loader_async_set_from_raw(GMPC_PIXBUF_LOADER_ASYNC(self->_priv->images[n]),
349                                     met->content, met->size, self->icon_size, self->icon_size,
350                                     ((data->type == MPD_DATA_TYPE_TAG && data->tag_type == MPD_TAG_ITEM_ALBUM) || (data->type == MPD_DATA_TYPE_SONG)?GMPC_MODIFICATION_TYPE_CASING: GMPC_MODIFICATION_TYPE_NONE),
351                                                                         met->md5sum);
353                         }else{
354                             pb = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "gmpc-no-cover", self->icon_size, 0,NULL);
355                             gmpc_pixbuf_loader_async_set_pixbuf(self->_priv->images[n], pb);
356                             g_object_unref(pb);
357                         }
358                     }
359                     else   if(ret == META_DATA_UNAVAILABLE)
360                     {
361                         GdkPixbuf *pb2;
362                         pb2 = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "gmpc-no-cover", self->icon_size, 0,NULL);
363                         gmpc_pixbuf_loader_async_set_pixbuf(self->_priv->images[n], pb2);
364                         g_object_unref(pb2);
365                     }
366                     gtk_tree_model_row_changed(model,path, &iter);
367                     gtk_tree_path_free(path);
368                 }
370                 if(ret == META_DATA_AVAILABLE || ret == META_DATA_UNAVAILABLE)
371                 {
372                     if(ref)
373                     {
374                         gtk_tree_row_reference_free(ref);
375                     }
376                 }
377             }
378         }
380     interface Gtk:Tree:Model
381         public void
382         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))
383         {
384             Self *self = GMPC_MPDDATA_MODEL(model);
385             MpdData_real *data = iter->user_data;
386             int n = GPOINTER_TO_INT(iter->user_data2);
388             if(self->_priv->data == NULL)
389                 g_warning("self->_priv->data == NULL");
390             /* set value to the correct type */
391             g_value_init(value, self->types[column]);
393             /**
394              * Sanity checks
395              */
396              g_assert((n < self->num_rows || n == 0));
397             g_assert(!(data == NULL && n != 0));
399             /* handle row up */
400             if(data == NULL && n == 0)
401             {
402                 switch(column)
403                 {
404                     case MPDDATA_MODEL_COL_ICON_ID:
405                         g_value_set_string(value, GTK_STOCK_GO_UP);
406                         break;
407                     case MPDDATA_MODEL_ROW_TYPE:
408                         /**
409                          * Make define
410                          */
411                         g_value_set_int(value, -1);
412                         break;
413                     case MPDDATA_MODEL_COL_SONG_TITLE:
414                     case MPDDATA_MODEL_COL_MARKUP:
415                         {
416                             g_value_set_string(value,"..");
417                             break;
418                         }
419                     default:
420                         break;
421                 }
422                 return;
423             }
425             if(column == MPDDATA_MODEL_META_DATA)
426             {
427                 if(self->_priv->use_images && self->_priv->images)
428                 {
429                     if(self->_priv->images[n] == NULL)
430                     {
431                         GtkTreePath *path;
432                         GtkTreeRowReference *ref;
433                         path = gtk_tree_model_get_path(GTK_TREE_MODEL(self), iter);
434                         ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(self),path);
436                         self->_priv->images[n]= gmpc_pixbuf_loader_async_new();
437                         gmpc_pixbuf_loader_async_set_rref(GMPC_PIXBUF_LOADER_ASYNC(self->_priv->images[n]), ref);
438                         if(data->type == MPD_DATA_TYPE_TAG && (data->tag_type == MPD_TAG_ITEM_ARTIST || data->tag_type == MPD_TAG_ITEM_ALBUM_ARTIST) )
439                         {
440                             mpd_Song *song;
441                             GdkPixbuf *pb = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "gmpc-loading-cover", self->icon_size, 0,NULL);
442                             gmpc_pixbuf_loader_async_set_pixbuf(self->_priv->images[n], pb);
443                             g_object_unref(pb);
444                             song = mpd_newSong();
445                             song->artist = g_strdup(data->tag);
446                             song->album = NULL;
447                             meta_data_get_path_callback(song, META_ARTIST_ART, (MetaDataCallback)self_cover_art_fetched, (gpointer)ref);
448                             mpd_freeSong(song);
449                         }
451                         else if(data->type == MPD_DATA_TYPE_TAG && data->tag_type == MPD_TAG_ITEM_ALBUM && self->_priv->req_artist)
452                         {
453                             mpd_Song *song;
454                             GdkPixbuf *pb = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "gmpc-loading-cover", self->icon_size, 0,NULL);
455                             gmpc_pixbuf_loader_async_set_pixbuf(self->_priv->images[n],pb);
456                             g_object_unref(pb);
457                             song = mpd_newSong();
458                             song->artist = g_strdup(self->_priv->req_artist);
459                             song->albumartist = g_strdup(self->_priv->req_artist);
460                             song->album = g_strdup(data->tag);
461                             meta_data_get_path_callback(song, META_ALBUM_ART, (MetaDataCallback)self_cover_art_fetched, ref);
462                             mpd_freeSong(song);
463                         }
464                         else if(data->type == MPD_DATA_TYPE_SONG&& data->song && data->song->album && (data->song->artist || self->_priv->req_artist))
465                         {
466                             if(data->prev && data->prev->type == MPD_DATA_TYPE_SONG && data->prev->song->album && g_utf8_collate(data->song->album, data->prev->song->album) ==0)
467                             {
468                                 gmpc_pixbuf_loader_async_set_pixbuf(self->_priv->images[n],self->_priv->blank);
469                             }else{
470                                 mpd_Song *song;
471                                 GdkPixbuf *pb = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "gmpc-loading-cover", self->icon_size, 0,NULL);
472                                 gmpc_pixbuf_loader_async_set_pixbuf(self->_priv->images[n],pb);
473                                 g_object_unref(pb);
474                                 song = mpd_newSong();
475                                 song->artist = g_strdup((data->song->artist)?data->song->artist:self->_priv->req_artist);
476                                 song->albumartist = g_strdup((data->song->albumartist)?data->song->albumartist:self->_priv->req_artist);
477                                 song->album = g_strdup(data->song->album);
478                                 meta_data_get_path_callback(song, META_ALBUM_ART, (MetaDataCallback)self_cover_art_fetched, ref);
479                                 mpd_freeSong(song);
480                             }
481                         }
482                         else
483                         {
484                             GdkPixbuf *pb = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "gmpc-no-cover", self->icon_size, 0,NULL);
485                             gmpc_pixbuf_loader_async_set_pixbuf(self->_priv->images[n],pb);
486                             g_object_unref(pb);
487                         }
488                         gtk_tree_path_free(path);
489                     }
490                     g_value_set_object(value, gmpc_pixbuf_loader_async_get_pixbuf(self->_priv->images[n]));
491                 }else{
492                     g_value_set_object(value,NULL);
493                 }
494             }
495             if(column == MPDDATA_MODEL_USERDATA)
496             {
497                 g_value_set_pointer(value,data->userdata);
499             }
500             /* handle row type, this is independent of the row type */
501             if(column == MPDDATA_MODEL_ROW_TYPE)
502             {
503                 g_value_set_int(value, data->type);
504                 return;
505             }
506             if (data->type == MPD_DATA_TYPE_TAG) {
507                 switch(column)
508                 {
509                     case MPDDATA_MODEL_COL_ICON_ID:
510                         switch(data->tag_type)
511                         {
512                             case MPD_TAG_ITEM_ALBUM:
513                                 g_value_set_string(value, "media-album");
514                                 break;
515                             case MPD_TAG_ITEM_ARTIST:
516                                 g_value_set_string(value, "media-artist");
517                                 break;
518                             case MPD_TAG_ITEM_GENRE:
519                                 g_value_set_string(value, "media-genre");
520                                 break;
521                             case MPD_TAG_ITEM_TRACK:
522                                 g_value_set_string(value, "media-num-tracks");
523                                 break;
524                             default:
525                                 g_value_set_string(value, "media-tag");
526                         }
527                         break;
528                     case MPDDATA_MODEL_COL_SONG_TITLE:
529                     case MPDDATA_MODEL_COL_MARKUP:
530                         {
531                             g_value_set_string(value, data->tag);
532                             break;
533                         }
534                     case MPDDATA_MODEL_COL_PATH:
535                         g_value_set_string(value, data->tag);
536                         break;
537                     case MPDDATA_MODEL_TAG_TYPE:
538                         g_value_set_int(value, data->tag_type);
539                         break;
540                     default:
541                         break;
542                 }
543             } else if(data->type == MPD_DATA_TYPE_DIRECTORY) {
544                 switch(column)
545                 {
546                     case MPDDATA_MODEL_COL_ICON_ID:
547                         g_value_set_string(value, GTK_STOCK_OPEN);
548                         break;
549                     case MPDDATA_MODEL_COL_SONG_TITLE:
550                     case MPDDATA_MODEL_COL_SONG_TITLEFILE:
551                     case MPDDATA_MODEL_COL_MARKUP:
552                         {
553                             gchar *basename = g_path_get_basename(data->directory);
554                             g_value_set_string(value, basename);
555                             g_free(basename);
556                             break;
557                         }
558                     case MPDDATA_MODEL_COL_PATH:
559                         g_value_set_string(value, data->directory);
560                         break;
561                     default:
562                         break;
563                 }
564             }
565             else if(data->type == MPD_DATA_TYPE_PLAYLIST)
566             {
567                 switch(column)
568                 {
569                     case MPDDATA_MODEL_COL_ICON_ID:
570                         g_value_set_string(value, "media-playlist");
571                         break;
572                     case MPDDATA_MODEL_COL_SONG_TITLE:
573                     case MPDDATA_MODEL_COL_SONG_TITLEFILE:
574                     case MPDDATA_MODEL_COL_MARKUP:
575                         {
576                             gchar *basename = g_path_get_basename(data->playlist->path);
577                             g_value_set_string(value, basename);
578                             g_free(basename);
579                             break;
580                         }
581                     case MPDDATA_MODEL_COL_PATH:
582                         g_value_set_string(value, data->playlist->path);
583                         break;
584                     default:
585                         break;
586                 }
587             }
588             else if(data->type == MPD_DATA_TYPE_SONG)
589             {
590                 mpd_Song *song = data->song;
591                 switch (column) {
592                     case MPDDATA_MODEL_COL_MPDSONG:
593                         g_value_set_pointer(value, song);
594                         break;
595                     case MPDDATA_MODEL_COL_PLAYING:
596                         g_value_set_boolean(value, FALSE);
597                         break;
598                     case MPDDATA_MODEL_COL_PLAYING_FONT_WEIGHT:
599                         g_value_set_int(value, PANGO_WEIGHT_NORMAL);
600                         break;
601                     case MPDDATA_MODEL_COL_MARKUP:
602                         {
603                             /* we want to go cache this stuff */
604                             gchar buffer[1024];
605                             mpd_song_markup(buffer, 1024, GMPC_MPDDATA_MODEL(model)->_priv->markup, song);
606                             g_value_set_string(value, buffer);
607                             break;
608                         }
609                     case MPDDATA_MODEL_COL_PATH:
610                         g_value_set_string(value, song->file);
611                         break;
612                                                                                 case MPDDATA_MODEL_COL_PATH_EXTENSION:
613                                                                                                 {
614                                                                                                         int j = strlen(song->file);
615                                                                                                         for(;j>0&&song->file[j] != '.';j--);
616                                                                                                         g_value_set_string(value, &(song->file)[j+1]);
617                                                                                                         break;
618                                                                                                 }
619                                                                                 case MPDDATA_MODEL_COL_PATH_DIRECTORY:
620                                                                                                 {
621                                                                                                         gchar *dir = g_path_get_dirname(song->file);
622                                                                                                         g_value_set_string(value, dir);
623                                                                                                         g_free(dir);
624                                                                                                         break;
625                                                                                                 }
626                     case MPDDATA_MODEL_COL_SONG_ARTIST:
627                         g_value_set_string(value, song->artist);
628                         break;
629                     case MPDDATA_MODEL_COL_SONG_ALBUM:
630                         g_value_set_string(value, song->album);
631                         break;
632                     case MPDDATA_MODEL_COL_SONG_TITLE:
633                         /* If there is a song available use that, else use the filename */
634                         if(song->title) {
635                             g_value_set_string(value, song->title);
636                         } else if (song->name) {
637                             g_value_set_string(value, song->name);
638                         }else {
639                             /* Use the markup stuff, this makes sure it gets processed equaly */
640                             gchar buffer[1024];
641                             mpd_song_markup(buffer, 1024, "%shortfile%", song);
642                             g_value_set_string(value, buffer);
643                         }
644                         break;
645                     case MPDDATA_MODEL_COL_SONG_TITLEFILE:
646                         {
647                             gchar *path = g_path_get_basename(song->file);
648                             g_value_set_string(value, path);
649                             g_free(path);
650                         }
651                         break;
652                     case MPDDATA_MODEL_COL_SONG_GENRE:
653                         g_value_set_string(value, song->genre);
654                         break;
655                     case MPDDATA_MODEL_COL_SONG_TRACK:
656                         g_value_set_string(value, song->track);
657                         break;
658                     case MPDDATA_MODEL_COL_SONG_NAME:
659                         g_value_set_string(value, song->name);
660                         break;
661                     case MPDDATA_MODEL_COL_SONG_COMPOSER:
662                         g_value_set_string(value, song->composer);
663                         break;
664                     case MPDDATA_MODEL_COL_SONG_PERFORMER:
665                         g_value_set_string(value, song->performer);
666                         break;
667                     case MPDDATA_MODEL_COL_SONG_DATE:
668                         g_value_set_string(value, song->date);
669                         break;
670                     case MPDDATA_MODEL_COL_SONG_LENGTH:
671                         g_value_set_int(value, song->time);
672                         break;
673                     case MPDDATA_MODEL_COL_SONG_LENGTH_FORMAT:
674                         {
675                             if(song->time >= 0) {
676                                 gchar *strdata = g_strdup_printf("%02i:%02i",
677                                         song->time/60, song->time%60);
678                                 g_value_set_string(value, strdata);
679                                 g_free(strdata);
680                             } else {
681                                 g_value_set_string(value, "n/a");
682                             }
683                         }
684                         break;
685                     case MPDDATA_MODEL_COL_SONG_DISC:
686                         g_value_set_string(value, song->disc);
687                         break;
688                     case MPDDATA_MODEL_COL_SONG_COMMENT:
689                         g_value_set_string(value, song->comment);
690                         break;
691                     case MPDDATA_MODEL_COL_SONG_POS:
692                         g_value_set_int(value, song->pos+1);
693                         break;
694                     case MPDDATA_MODEL_COL_SONG_ALBUMARTIST:
695                         g_value_set_string(value, song->albumartist);
696                         break;
697                     case MPDDATA_MODEL_COL_SONG_ID:
698                         g_value_set_int(value, song->id);
699                         break;
701                     case MPDDATA_MODEL_COL_ICON_ID:
702                         if (strstr(song->file, "://")) {
703                             g_value_set_string(value, "media-stream");
704                         } else {
705                             g_value_set_string(value, "media-audiofile");
706                         }
707                         break;
708                     case MPDDATA_MODEL_COL_SONG_PRIORITY:
709                         g_value_set_int(value, song->priority);
710                         break;
711                     default:
712                         break;
713                 }
714             }
715         }
717     interface Gtk:Tree:Model
718         private gboolean
719         iter_nth_child(Gtk:Tree:Model *model(check null type), GtkTreeIter *iter (check null), GtkTreeIter *parent, gint n (check >=0))
720         {
721             Self *self = GMPC_MPDDATA_MODEL(model);
722             int i;
723             MpdData_real *data = NULL;
724             if(parent)
725                 return FALSE;
726             if (n >= self->num_rows || n < 0)
727                 return FALSE;
729             data = (MpdData_real *)self->_priv->data;
730             i=0;
731             if(self->has_up)
732                 i=1;
733             for(; i < (n);i++)
734             {
735                 data = data->next;//mpd_data_get_next_real(data, FALSE);
736                 g_assert(data != NULL);
737             }
739             if(self->has_up && n == 0)
740                 data = NULL;
742             iter->stamp = self->_priv->stamp;
743             iter->user_data = data;
744             iter->user_data2 = GINT_TO_POINTER(n);
745             return TRUE;
746         }
748     interface Gtk:Tree:Model
749         private GtkTreePath *
750         get_path(Gtk:Tree:Model *self (check null type), GtkTreeIter *iter (check null))
751         {
752             GtkTreePath *path = NULL;
753             path = gtk_tree_path_new();
754             gtk_tree_path_append_index(path, GPOINTER_TO_INT(iter->user_data2));
755             return path;
756         }
758     interface Gtk:Tree:Model
759         private GType
760         get_column_type(Gtk:Tree:Model *model(check null type), gint ind (check >= 0))
761         {
762             Self *self = GMPC_MPDDATA_MODEL(model);
763             return self->types[ind];
764         }
765     public
766         void
767         set_request_artist(self, const char *artist)
768         {
769             int i;
770             GtkTreePath *path = NULL;
771             GtkTreeIter iter;
772             if(self->_priv->req_artist)
773                 q_free(self->_priv->req_artist);
774             self->_priv->req_artist = (artist != NULL && artist[0] != '\0')?g_strdup(artist):NULL;
775             /* Free possible stored images */
776             if(self->_priv->images && self->_priv->use_images)
777             {
778                 MpdData *data2 = mpd_data_get_first(self->_priv->data);
779                 for(i=0;i<self->num_rows;i++)
780                 {
781                     if(self->_priv->images[i]){
782                         g_object_unref(self->_priv->images[i]);
783                         self->_priv->images[i] = NULL;
785                         /* Update the view */
786                         path = gtk_tree_path_new();
787                         gtk_tree_path_append_index(path,i);
788                         iter.stamp = self->_priv->stamp;
789                         iter.user_data = data2;
790                         iter.user_data2 =  GINT_TO_POINTER(i);
791                         /* propegate change */
792                         gtk_tree_model_row_changed(GTK_TREE_MODEL(self), path, &iter);
793                         gtk_tree_path_free(path);
794                     }
795                     data2 = mpd_data_get_next_real(data2,FALSE);
796                 }
797             }
798         }
799         public
800         const char *
801         get_request_artist(self)
802         {
803             return self->_priv->req_artist;
804         }
805     public
806         long unsigned set_mpd_data(self, MpdData *data2)
807         {
808             int i;
809             long unsigned retval = 0;
810             GtkTreeIter iter;
811             GtkTreePath *path = NULL;
812             int old_num_rows = self->num_rows;
813             /* Do some cleanup, like removing rows, and so */
814             /* loop and remove */
815             while ( self->num_rows > 0 ) {
816                 path = gtk_tree_path_new();
817                 gtk_tree_path_append_index(path, self->num_rows - 1 );
818                 /* propegate change */
819                 gtk_tree_model_row_deleted(GTK_TREE_MODEL(self), path);
820                 gtk_tree_path_free(path);
821                 self->num_rows--;
822             }
825             /**
826              * Free if there is a list and set it to NULL
827              */
828             if(self->_priv->data){
829                 mpd_data_free(mpd_data_get_first(self->_priv->data));
830             }
831             self->_priv->data = NULL;
833             if(self->num_rows != 0)
834                 g_log(LOG_DOMAIN, G_LOG_LEVEL_WARNING,"not every row cleared %i\n",self->num_rows);
835             self->num_rows =0;
836             /* Free possible stored images */
837             if(self->_priv->images && self->_priv->use_images)
838             {
839                 for(i=0;i< old_num_rows;i++)
840                 {
841                     if(self->_priv->images[i])
842                         g_object_unref(self->_priv->images[i]);
843                 }
844                 q_free(self->_priv->images);
845             }
846             if(data2 == NULL)
847             {
848                 self->_priv->playtime = 0;
849                 self_playtime_changed(self, self->_priv->playtime);
850                 return 0;
851             }
853             self->_priv->data = mpd_data_get_first(data2);
854             data2 = NULL;
855             if(self->_priv->sort_column == MPDDATA_MODEL_COL_ICON_ID)
856             {
857                 self->_priv->data = misc_sort_mpddata_by_album_disc_track(self->_priv->data);
858             }
859             else if ( self->_priv->sort_column != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID )
860             {
861                 self->_priv->data = misc_sort_mpddata(self->_priv->data,(GCompareDataFunc)self_sort_func,self );
862             }
864             if(self->has_up) {
865                 path = gtk_tree_path_new();
866                 gtk_tree_path_append_index(path, self->num_rows);
867                 iter.stamp = self->_priv->stamp;
868                 iter.user_data = NULL;
869                 iter.user_data2 =  GINT_TO_POINTER(self->num_rows);
871                 self->num_rows++;
872                 /* propegate change */
873                 gtk_tree_model_row_inserted(GTK_TREE_MODEL(self), path, &iter);
874                 gtk_tree_path_free(path);
875             }
876             for(data2 = mpd_data_get_first(self->_priv->data);data2; data2 = mpd_data_get_next_real(data2,FALSE)) {
877                 path = gtk_tree_path_new();
878                 gtk_tree_path_append_index(path,self->num_rows);
879                 iter.stamp = self->_priv->stamp;
880                 iter.user_data = data2;
881                 iter.user_data2 =  GINT_TO_POINTER(self->num_rows);
883                 self->num_rows++;
884                 /* propegate change */
885                 gtk_tree_model_row_inserted(GTK_TREE_MODEL(self), path, &iter);
886                 gtk_tree_path_free(path);
887                 if(data2->type == MPD_DATA_TYPE_SONG)
888                 {
889                     if(data2->song && data2->song->time > 0)
890                         retval+= data2->song->time;
891                 }
892             }
893             if(self->_priv->use_images)
894             {
895                 self->_priv->images = g_malloc0((self->num_rows)*sizeof(*(self->_priv->images)));
896             }
898             self->_priv->playtime = retval;
899             self_playtime_changed(self, self->_priv->playtime);
900             return retval;
901         }
903     /* Sorting */
904     interface Gtk:Tree:Sortable
905         private
906         gboolean get_sort_column_id (Gtk:Tree:Sortable *model ,  gint *sort_column_id, GtkSortType *order)
907         {
908             Self *self = GMPC_MPDDATA_MODEL(model);
909             if(sort_column_id)
910                 *sort_column_id = self->_priv->sort_column;
911             if(order)
912                 *order = self->_priv->sort_order;
913             return TRUE;
914         }
916     interface Gtk:Tree:Sortable
917         private
918         void set_sort_column_id (Gtk:Tree:Sortable *model ,  gint sort_column_id, GtkSortType order)
919         {
920             Self *self = GMPC_MPDDATA_MODEL(model);
921             gint old_col = self->_priv->sort_column;
922             GtkSortType old_ord = self->_priv->sort_order;
923             self->_priv->sort_column = sort_column_id;
924             self->_priv->sort_order = order;
925             /* trigger signal */
926             if(old_col != sort_column_id || old_ord != order)
927                 gtk_tree_sortable_sort_column_changed(model);
928             self->_priv->old_sort_column = self->_priv->sort_column;
930         }
932     interface Gtk:Tree:Sortable
933         private
934         gboolean
935         has_default_sort_func(Gtk:Tree:Sortable *model)
936         {
937             return FALSE;
938         }
939       private
940         int sort_func(gpointer ppaa, gpointer ppbb, Self *self)
941         {
942             MpdData_real *a = *(MpdData_real **)ppaa;
943             MpdData_real *b = *(MpdData_real **)ppbb;
944             int fact = (self->_priv->sort_order == GTK_SORT_ASCENDING)?-1:1;
946             if(a->type != b->type )
947             {
948                 int val = a->type - b->type;
949                 return val;
950             }
951             else if(a->type == b->type)
952             {
953                 int val=0;
954                 GtkTreeIter iter;
955                 GValue va = {0,},vb = {0,};
956                 /* Get values from tree view, so we don't have to replicate code to sort the right entries */
957                 iter.user_data = a;
958                 iter.user_data2 = GPOINTER_TO_INT(0);
959                 gtk_tree_model_get_value(GTK_TREE_MODEL(self), &iter, self->_priv->sort_column, &va);
960                 iter.user_data = b;
961                 gtk_tree_model_get_value(GTK_TREE_MODEL(self), &iter, self->_priv->sort_column, &vb);
962                 /* if the type is a directory or a tag, always sort on the title column */
963                 if(a->type == MPD_DATA_TYPE_DIRECTORY || b->type == MPD_DATA_TYPE_TAG)
964                 {
965                     const char *ca,*cb;
966                     ca = g_value_get_string(&va);
967                     cb = g_value_get_string(&vb);
968                     if(ca && cb) {
969                         gchar *aa,*bb;
970                         aa = g_utf8_strdown(ca, -1);
971                         bb = g_utf8_strdown(cb, -1);
972                         val = g_utf8_collate(aa,bb);
973                         g_free(aa);
974                         g_free(bb);
975                     } else {
976                         val = (ca == NULL)?((cb==NULL)?0:-1):1;
977                     }
978                     g_value_unset(&va);
979                     g_value_unset(&vb);
980                     /* return */
981                     return val*fact;
982                 }
983                 if(self->_priv->sort_column == MPDDATA_MODEL_COL_SONG_TRACK)
984                 {
985                     const char *ca = g_value_get_string(&va);
986                     const char *cb = g_value_get_string(&vb);
987                     gint ca1 = (ca)?atoi(ca):0;
988                     gint cb1 = (cb)?atoi(cb):0;
989                     g_value_unset(&va);
990                     g_value_unset(&vb);
991                     return fact*(ca1-cb1);
992                 }
993                 else if(self->types[self->_priv->sort_column] == G_TYPE_INT)
994                 {
995                     val = g_value_get_int(&va) - g_value_get_int(&vb);
996                 }
997                 else if (self->types[self->_priv->sort_column] == G_TYPE_STRING)
998                 {
999                     const char *ca = g_value_get_string(&va);
1000                     const char *cb = g_value_get_string(&vb);
1001                     if(ca && cb) {
1002                         gchar *aa,*bb;
1003                         aa = g_utf8_normalize(ca, -1,G_NORMALIZE_ALL);
1004                         bb = g_utf8_normalize(cb, -1,G_NORMALIZE_ALL);
1005                         val = g_utf8_collate(aa,bb);
1006                         g_free(aa);
1007                         g_free(bb);
1008                     } else {
1009                         val = (ca == NULL)?((cb==NULL)?0:-1):1;
1010                     }
1011                 }
1013                 if (val == 0 &&
1014                         a->type == MPD_DATA_TYPE_SONG &&
1015                         b->type == MPD_DATA_TYPE_SONG &&
1016                         a->song->file &&
1017                         b->song->file)
1018                 {
1019                     val = strcmp (a->song->file, b->song->file);
1020                 }
1022                 g_value_unset(&va);
1023                 g_value_unset(&vb);
1024                 return fact*val;
1025             }
1026             return 0;
1027         }
1029     interface Gtk:Tree:Sortable
1030         private
1031         void
1032         sort_column_changed(Gtk:Tree:Sortable *model)
1033         {
1034             Self *self = GMPC_MPDDATA_MODEL(model);
1035             if(!self->_priv->data || !(((MpdData_real *)self->_priv->data)->next))
1036                 return;
1037             if(self->_priv->sort_column == MPDDATA_MODEL_COL_ICON_ID)
1038             {
1039                 self->_priv->data = misc_sort_mpddata_by_album_disc_track(self->_priv->data);
1040             }
1041             else if(self->_priv->sort_column !=  GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
1042             {
1043                 self->_priv->data = misc_sort_mpddata(self->_priv->data,(GCompareDataFunc)self_sort_func,self );
1044             }
1045             self->_priv->old_sort_column = self->_priv->sort_column;
1047             /* tell the view that rows have changed  */
1048             {
1049                 int i=0;
1050                 GtkTreePath *path = NULL;
1051                 GtkTreeIter iter;
1052                 MpdData *data2 = mpd_data_get_first(self->_priv->data);
1053                 if(self->has_up) i = 1;
1054                 for(;data2; data2 = mpd_data_get_next_real(data2,FALSE))
1055                 {
1056                     path = gtk_tree_path_new();
1057                     gtk_tree_path_append_index(path,i);
1058                     iter.stamp = self->_priv->stamp;
1059                     iter.user_data = data2;
1060                     iter.user_data2 =  GINT_TO_POINTER(i);
1062                     /* propegate change */
1063                     gtk_tree_model_row_changed(GTK_TREE_MODEL(self), path, &iter);
1064                     gtk_tree_path_free(path);
1065                     i++;
1066                 }
1067             }
1068         }
1070     public 
1071         int
1072         test_sort_func(gpointer ppaa, gpointer ppbb, GmpcMpdDataModel *self)
1073         {
1074             MpdData_real *a = *(MpdData_real **)ppaa;
1075             MpdData_real *b = *(MpdData_real **)ppbb;
1076             if(a->type == MPD_DATA_TYPE_TAG && b->type == MPD_DATA_TYPE_TAG)
1077             {
1078                 if(a->tag_type != b->tag_type)
1079                     return a->tag_type - b->tag_type;
1080                 if(a->tag== NULL && b->tag != NULL)
1081                     return -1;
1082                 else if(b->tag == NULL && a->tag != NULL)
1083                     return 1;
1084                 else if (a->tag  && b->tag)
1085                 {
1086                     int val;
1087                     if(a->tag && b->tag) {
1088                         gchar *sa,*sb;
1089                         sa = g_utf8_strdown(a->tag, -1);
1090                         sb = g_utf8_strdown(b->tag, -1);
1091                         val = g_utf8_collate(sa,sb);
1092                         g_free(sa);
1093                         g_free(sb);
1094                     } else {
1095                         val = (a == NULL)?((b==NULL)?0:-1):1;
1096                     }
1097                     return val;
1098                 }
1099             }
1100             return a->type - b->type;
1101         }
1103         /**
1104          * For now this assumes tag list only.
1105          */
1106     public
1107         long unsigned set_mpd_data_slow (self, MpdData *data2)
1108         {
1109             MpdData_real *new_list = NULL;
1110             int i=0;
1111             int items=0;
1112             MpdData_real *original = (MpdData_real *)mpd_data_get_first(self->_priv->data);
1113             MpdData_real *new = (MpdData_real *) data2;
1114             GtkTreePath *path =NULL;
1115             GtkTreeIter iter;
1116             int old_list_size = self->num_rows;
1118             /* sort it identical */
1119             data2 = misc_sort_mpddata(data2,(GCompareDataFunc)self_test_sort_func,self );
1120             new = (MpdData_real *)data2;
1122             if(new) {
1123                 MpdData_real *n = new->first;
1124                 while(n) {
1125                     items++;
1126                     n = n->next;
1127                 }
1128             }
1131             /* Free possible stored images */
1132             /**
1133              * TODO: Don't free the list, but grow it to MAX(items, self->num_rows);
1134              * Then after updating, resize it to new size
1135              */
1136             /* Grow the list when needed */
1138             if(self->_priv->use_images)
1139             {
1140                 /* Clean them, they might not be in the right place anymore */
1141                 for(i=0;i< old_list_size; i++)
1142                 {
1143                     if(self->_priv->images[i] != NULL) g_object_unref(self->_priv->images[i]);
1144                     self->_priv->images[i] = NULL;
1145                 }
1146                 if(items > self->num_rows)
1147                 {
1148                     self->_priv->images = g_realloc(self->_priv->images, items*sizeof(GdkPixbuf *));
1149                     /* set the new ones to NUll */
1150                     for(i=self->num_rows;i<items;i++)
1151                     {
1152                         self->_priv->images[i] = NULL;
1153                     }
1154                 }
1155             }
1160             i=0;
1161             /* compare lists */
1162             if(self->_priv->data && original == NULL) g_warning("weirdness\n");
1163             if(self->_priv->data)
1164             {
1165                 int has_next;
1166                 do
1167                 {
1168                     has_next = 0;
1169                     if(new == NULL)
1170                     {
1171                         if(self->num_rows > items)
1172                         {
1173                             MpdData_real *n = original->next;
1174                             /* remove current row */
1175                             self->num_rows--;
1177                             path = gtk_tree_path_new();
1178                             gtk_tree_path_append_index(path,i);
1180                             /* propegate change */
1181                             gtk_tree_model_row_deleted(GTK_TREE_MODEL(self), path);
1182                             gtk_tree_path_free(path);
1184                             original =(MpdData_real *) mpd_data_delete_item((MpdData *)original);
1185                             self->_priv->data = mpd_data_get_first((MpdData *)original);
1187                             original=n;
1188                             has_next = (original )?1:0;
1189                         }
1190                     }
1191                     else
1192                     {
1193                         int compare;
1194                         compare = g_utf8_collate(new->tag,original->tag);
1195                         if(compare < 0)
1196                         {
1197                             /* add */
1198                             MpdData_real *n = (MpdData_real *) mpd_new_data_struct();
1199                             n->type = MPD_DATA_TYPE_TAG;
1200                             n->tag_type = new->tag_type;
1201                             n->tag = new->tag;
1202                             new->tag = NULL;
1204                             /* add */
1206                             self->num_rows++;
1207                             n->prev = original->prev;
1209                             if(original->prev)
1210                                 original->prev->next = n;
1211                             n->next = original;
1212                             n->first = original->first;
1213                             original->prev = n;
1214                             if(n->prev == NULL){
1215                                 MpdData_real *fiter;
1216                                 for(fiter = n;fiter;fiter = fiter->next){
1217                                     fiter->first = n;
1218                                 }
1219                             }
1221                             self->_priv->data = mpd_data_get_first((MpdData *)original);
1222                             {
1223                                 path = gtk_tree_path_new();
1224                                 gtk_tree_path_append_index(path,i);
1225                                 iter.stamp = self->_priv->stamp;
1226                                 iter.user_data = n;
1227                                 iter.user_data2 =  GINT_TO_POINTER(i);
1229                                 gtk_tree_model_row_inserted(GTK_TREE_MODEL(self), path, &iter);
1230                                 gtk_tree_path_free(path);
1231                             }
1232                             /* mark for insert */
1233                             new=new->next;
1234                             i++;
1235                             has_next = 1;
1236                         }
1237                         else if (compare > 0)
1238                         {
1239                             MpdData_real *n = original->next;
1240                             path = gtk_tree_path_new();
1241                             gtk_tree_path_append_index(path,i);
1242                             /* propegate change */
1244                             self->num_rows--;
1245                             gtk_tree_model_row_deleted(GTK_TREE_MODEL(self), path);
1246                             gtk_tree_path_free(path);
1249                             original = (MpdData_real *)mpd_data_delete_item((MpdData *)original);
1250                             self->_priv->data = mpd_data_get_first((MpdData *)original);
1251                             original = n;
1252                             //original = original->next;
1253                             has_next = (original )?1:0;
1255                         }else{
1256                             new = new->next;
1257                             original = original->next;
1258                             has_next = (original )?1:0;
1259                             i++;
1260                         }
1261                     }
1262                 }while(has_next);
1263             }
1264             /* add entries remaining in new */
1265             if(new)
1266             {
1268                 new_list = (MpdData_real *) self->_priv->data;
1269                 while(new_list && new_list->next) new_list = new_list->next;
1270                 do{
1271                     new_list = (MpdData_real *)mpd_new_data_struct_append((MpdData*)new_list);
1272                     new_list->type = MPD_DATA_TYPE_TAG;
1273                     new_list->tag_type = new->tag_type;
1274                     new_list->tag = new->tag;
1275                     new->tag = NULL;
1277                     self->_priv->data = (MpdData *)new_list->first;
1278                     if(self->_priv->data == NULL) g_warning("self->_priv->data == NULL");
1279                     self->num_rows++;
1280                     {
1281                         path = gtk_tree_path_new();
1282                         gtk_tree_path_append_index(path,i);
1283                         iter.stamp = self->_priv->stamp;
1284                         iter.user_data = new_list;
1285                         iter.user_data2 =  GINT_TO_POINTER(i);
1287                         gtk_tree_model_row_inserted(GTK_TREE_MODEL(self), path, &iter);
1288                         gtk_tree_path_free(path);
1289                     }
1291                     new = new->next;
1292                     i++;
1293                 }while(new);
1294             }
1297             if(self->_priv->use_images){
1298                 if(self->num_rows < old_list_size){
1299                     for(i=self->num_rows;i< old_list_size; i++)
1300                     {
1301                         /* clean it */
1302                         if(self->_priv->images[i] != NULL) g_object_unref(self->_priv->images[i]);
1303                     }
1304                     self->_priv->images = g_realloc(self->_priv->images, (self->num_rows)*sizeof(GdkPixbuf *));
1305                 }
1306             }
1310             if(data2)
1311                 mpd_data_free(data2);
1313             g_assert(items == self->num_rows);
1314             return 0;
1315         }
1317         signal last NONE (LONG)
1318         void
1319         playtime_changed(self, gulong playtime)
1320         {
1321             return;
1322         }
1324     public
1325     gulong
1326     get_playtime(self)
1327     {
1328         return self->_priv->playtime;
1329     }
1330     public
1331     gint
1332     get_pos( self, GtkTreeIter *iter)
1333     {
1334             g_assert(iter->stamp == self->_priv->stamp);
1335             return GPOINTER_TO_INT(iter->user_data2);
1336     }
1338     public
1339     void
1340     disable_image(self)
1341     {
1342         g_assert(self->_priv->data == NULL);
1343         self->_priv->use_images = FALSE;
1344     }
1346     public
1347     MpdData *
1348     steal_mpd_data(self)
1349     {
1350         GtkTreePath *path;
1351         int i;
1352         int old_num_rows = self->num_rows;
1353         MpdData *data = self->_priv->data;
1354         while ( self->num_rows > 0 ) {
1355             path = gtk_tree_path_new();
1356             gtk_tree_path_append_index(path, self->num_rows - 1 );
1357             /* propegate change */
1358             gtk_tree_model_row_deleted(GTK_TREE_MODEL(self), path);
1359             gtk_tree_path_free(path);
1360             self->num_rows--;
1361         }
1363         /* Clear */
1364         self->_priv->data = NULL;
1365         /* Free possible stored images */
1366         if(self->_priv->images && self->_priv->use_images)
1367         {
1368             for(i=0;i<  old_num_rows;i++)
1369             {
1370                 if(self->_priv->images[i])
1371                     g_object_unref(self->_priv->images[i]);
1372             }
1373             q_free(self->_priv->images);
1374         }
1375         self->_priv->playtime = 0;
1376         self_playtime_changed(self, self->_priv->playtime);
1378         return mpd_data_get_first(data);
1379     }
1381     /* Drag and stop handling */
1384                 interface Gtk:Tree:Drag:Source
1385                 private
1386                 gboolean row_draggable (Gtk:Tree:Drag:Source *drag_source, Gtk:Tree:Path *path)
1387                 {
1388             GtkTreeIter iter;
1389             if(gtk_tree_model_get_iter(GTK_TREE_MODEL(drag_source), &iter, path))
1390             {
1391                 MpdData *data = iter.user_data;
1392                 if(data->type == MPD_DATA_TYPE_SONG) {
1393                     return TRUE;
1394                 }
1395             }
1396             return FALSE;
1397         }
1399         interface Gtk:Tree:Drag:Source
1400         private
1401                 gboolean drag_data_delete (Gtk:Tree:Drag:Source *drag_source, Gtk:Tree:Path *path)
1402                 {
1403                         return TRUE;
1404                 }
1405                 interface Gtk:Tree:Drag:Source
1406                         private
1407                 gboolean drag_data_get (Gtk:Tree:Drag:Source *drag_source, Gtk:Tree:Path *path, Gtk:Selection:Data *selection_data)
1408                 {
1409             if(!gtk_tree_set_row_drag_data(selection_data,GTK_TREE_MODEL(drag_source), path)) {
1410                 return FALSE;
1411             }
1412                         return TRUE;
1413                 }