~ubuntu-branches/ubuntu/utopic/rhythmbox/utopic-proposed

« back to all changes in this revision

Viewing changes to sources/rb-playlist-source.c

Tags: upstream-0.9.2
ImportĀ upstreamĀ versionĀ 0.9.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
1
2
/*
2
3
 *  arch-tag: Implementation of playlist source object
3
4
 *
24
25
#include <gtk/gtk.h>
25
26
#include <libgnome/gnome-i18n.h>
26
27
#include <libgnomevfs/gnome-vfs-uri.h>
 
28
#include <totem-pl-parser.h>
27
29
#include <libxml/tree.h>
28
 
#include <bonobo/bonobo-ui-component.h>
29
 
#include <bonobo/bonobo-window.h>
30
30
#include <unistd.h>
31
31
#include <string.h>
32
32
 
34
34
#include "rb-entry-view.h"
35
35
#include "rb-search-entry.h"
36
36
#include "rb-file-helpers.h"
37
 
#include "rb-playlist.h"
38
 
#include "rb-thread-helpers.h"
39
37
#include "rb-preferences.h"
40
38
#include "rb-dialog.h"
41
39
#include "rb-util.h"
42
40
#include "rb-playlist-source.h"
43
 
#include "rb-volume.h"
44
 
#include "rb-bonobo-helpers.h"
 
41
#include "rb-playlist-source-recorder.h"
45
42
#include "rb-debug.h"
46
43
#include "eel-gconf-extensions.h"
47
44
#include "rb-song-info.h"
48
 
#include "rb-tree-view-column.h"
49
45
 
50
46
#define RB_PLAYLIST_XML_VERSION "1.0"
51
47
 
 
48
#define RB_PLAYLIST_PLAYLIST (xmlChar *) "playlist"
 
49
#define RB_PLAYLIST_TYPE (xmlChar *) "type"
 
50
#define RB_PLAYLIST_AUTOMATIC (xmlChar *) "automatic"
 
51
#define RB_PLAYLIST_STATIC (xmlChar *) "static"
 
52
#define RB_PLAYLIST_NAME (xmlChar *) "name"
 
53
#define RB_PLAYLIST_LIMIT_COUNT (xmlChar *) "limit-count"
 
54
#define RB_PLAYLIST_LIMIT_SIZE (xmlChar *) "limit-size"
 
55
#define RB_PLAYLIST_LIMIT_TIME (xmlChar *) "limit-time"
 
56
#define RB_PLAYLIST_SORT_KEY (xmlChar *) "sort-key"
 
57
#define RB_PLAYLIST_SORT_DIRECTION (xmlChar *) "sort-direction"
 
58
#define RB_PLAYLIST_LIMIT (xmlChar *) "limit"
 
59
#define RB_PLAYLIST_LOCATION (xmlChar *) "location"
 
60
 
52
61
static void rb_playlist_source_class_init (RBPlaylistSourceClass *klass);
53
62
static void rb_playlist_source_init (RBPlaylistSource *source);
54
63
static GObject *rb_playlist_source_constructor (GType type, guint n_construct_properties,
55
64
                                                GObjectConstructParam *construct_properties);
56
 
static void rb_playlist_source_finalize (GObject *object);
 
65
static void rb_playlist_source_dispose (GObject *object);
57
66
static void rb_playlist_source_set_property (GObject *object,
58
67
                                          guint prop_id,
59
68
                                          const GValue *value,
64
73
                                          GParamSpec *pspec);
65
74
 
66
75
/* source methods */
67
 
static const char *impl_get_status (RBSource *source);
 
76
static char *impl_get_status (RBSource *source);
68
77
static const char *impl_get_browser_key (RBSource *source);
69
78
static GdkPixbuf *impl_get_pixbuf (RBSource *source);
70
79
static RBEntryView *impl_get_entry_view (RBSource *source);
77
86
static gboolean impl_show_popup (RBSource *source);
78
87
static void rb_playlist_source_entry_added_cb (RhythmDB *db, RhythmDBEntry *entry,
79
88
                                               RBPlaylistSource *source);
 
89
static void rb_playlist_source_songs_sort_order_changed_cb (RBEntryView *view,
 
90
                                                            RBPlaylistSource *source);
80
91
 
81
92
static void rb_playlist_source_songs_show_popup_cb (RBEntryView *view, RBPlaylistSource *playlist_view);
82
93
static void rb_playlist_source_drop_cb (GtkWidget *widget,
89
100
                                     gpointer user_data);
90
101
static void rb_playlist_source_add_list_uri (RBPlaylistSource *source,
91
102
                                          GList *list);
 
103
static void rb_playlist_source_do_query (RBPlaylistSource *source,
 
104
                                         GPtrArray *query,
 
105
                                         guint limit_count,
 
106
                                         guint limit_mb,
 
107
                                         guint limit_time);
 
108
static void rb_playlist_source_row_inserted (GtkTreeModel *treemodel,
 
109
                                             GtkTreePath *path,
 
110
                                             GtkTreeIter *iter,
 
111
                                             RBPlaylistSource *source);
 
112
static void rb_playlist_source_non_entry_dropped (GtkTreeModel *model,
 
113
                                                  const char *uri,
 
114
                                                  RBPlaylistSource *source);
92
115
 
93
 
#define PLAYLIST_SOURCE_SONGS_POPUP_PATH "/popups/PlaylistSongsList"
94
 
#define PLAYLIST_SOURCE_POPUP_PATH "/popups/PlaylistSourceList"
95
 
#define PLAYLIST_SOURCE_AUTOMATIC_POPUP_PATH "/popups/AutomaticPlaylistSourceList"
 
116
#define PLAYLIST_SOURCE_SONGS_POPUP_PATH "/PlaylistViewPopup"
 
117
#define PLAYLIST_SOURCE_POPUP_PATH "/PlaylistSourcePopup"
 
118
#define PLAYLIST_SOURCE_AUTOMATIC_POPUP_PATH "/SmartPlaylistSourcePopup"
96
119
 
97
120
struct RBPlaylistSourcePrivate
98
121
{
 
122
        gboolean disposed;
 
123
        
99
124
        RhythmDB *db;
100
125
 
101
126
        gboolean automatic;
102
127
        GHashTable *entries;
103
128
 
 
129
        RhythmDBEntryType entry_type;
104
130
        RhythmDBQueryModel *model;
 
131
        gboolean query_resetting;
105
132
 
106
133
        GtkWidget *vbox;
107
134
        GdkPixbuf *normal_pixbuf;
109
136
 
110
137
        RBEntryView *songs;
111
138
 
 
139
        gboolean dirty;
 
140
        gboolean is_local;
 
141
 
112
142
        char *title;
113
 
        char *status;
114
143
};
115
144
 
116
145
enum
117
146
{
118
147
        PROP_0,
119
 
        PROP_LIBRARY,
120
 
        PROP_DB,
121
148
        PROP_AUTOMATIC,
 
149
        PROP_QUERY_MODEL,
 
150
        PROP_DIRTY,
 
151
        PROP_LOCAL,
 
152
        PROP_ENTRY_TYPE
122
153
};
123
154
 
124
 
static GObjectClass *parent_class = NULL;
125
 
 
126
155
static const GtkTargetEntry target_uri [] = { { "text/uri-list", 0, 0 } };
127
156
 
128
 
GType
129
 
rb_playlist_source_get_type (void)
130
 
{
131
 
        static GType rb_playlist_source_type = 0;
132
 
 
133
 
        if (rb_playlist_source_type == 0)
134
 
        {
135
 
                static const GTypeInfo our_info =
136
 
                {
137
 
                        sizeof (RBPlaylistSourceClass),
138
 
                        NULL,
139
 
                        NULL,
140
 
                        (GClassInitFunc) rb_playlist_source_class_init,
141
 
                        NULL,
142
 
                        NULL,
143
 
                        sizeof (RBPlaylistSource),
144
 
                        0,
145
 
                        (GInstanceInitFunc) rb_playlist_source_init
146
 
                };
147
 
 
148
 
                rb_playlist_source_type = g_type_register_static (RB_TYPE_SOURCE,
149
 
                                                                  "RBPlaylistSource",
150
 
                                                                  &our_info, 0);
151
 
        }
152
 
 
153
 
        return rb_playlist_source_type;
154
 
}
 
157
G_DEFINE_TYPE (RBPlaylistSource, rb_playlist_source, RB_TYPE_SOURCE);
 
158
 
155
159
 
156
160
static void
157
161
rb_playlist_source_class_init (RBPlaylistSourceClass *klass)
159
163
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
160
164
        RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
161
165
 
162
 
        parent_class = g_type_class_peek_parent (klass);
163
 
 
164
 
        object_class->finalize = rb_playlist_source_finalize;
 
166
        object_class->dispose = rb_playlist_source_dispose;
165
167
        object_class->constructor = rb_playlist_source_constructor;
166
168
 
167
169
        object_class->set_property = rb_playlist_source_set_property;
181
183
        source_class->impl_delete = impl_delete;
182
184
        source_class->impl_song_properties = impl_song_properties;
183
185
        source_class->impl_can_pause = (RBSourceFeatureFunc) rb_true_function;
184
 
        source_class->impl_have_artist_album = (RBSourceFeatureFunc) rb_true_function;
185
186
        source_class->impl_have_url = (RBSourceFeatureFunc) rb_false_function;
186
187
        source_class->impl_receive_drag = impl_receive_drag;
187
188
        source_class->impl_show_popup = impl_show_popup;
188
189
 
189
190
        g_object_class_install_property (object_class,
190
 
                                         PROP_DB,
191
 
                                         g_param_spec_object ("db",
192
 
                                                              "RhythmDB",
193
 
                                                              "RhythmDB database",
194
 
                                                              RHYTHMDB_TYPE,
195
 
                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
196
 
 
197
 
        g_object_class_install_property (object_class,
198
191
                                         PROP_AUTOMATIC,
199
192
                                         g_param_spec_boolean ("automatic",
200
193
                                                               "automatic",
201
194
                                                               "whether this playlist is a smartypants",
202
195
                                                               FALSE,
203
196
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
197
 
 
198
        g_object_class_install_property (object_class,
 
199
                                         PROP_QUERY_MODEL,
 
200
                                         g_param_spec_object ("query-model",
 
201
                                                              "query-model",
 
202
                                                              "query model for the playlist",
 
203
                                                              RHYTHMDB_TYPE_QUERY_MODEL,
 
204
                                                              G_PARAM_READABLE));
 
205
 
 
206
        g_object_class_install_property (object_class,
 
207
                                         PROP_DIRTY,
 
208
                                         g_param_spec_boolean ("dirty",
 
209
                                                               "dirty",
 
210
                                                               "whether this playlist should be saved",
 
211
                                                               FALSE,
 
212
                                                               G_PARAM_READABLE));
 
213
 
 
214
        g_object_class_install_property (object_class,
 
215
                                         PROP_LOCAL,
 
216
                                         g_param_spec_boolean ("is-local",
 
217
                                                               "is-local",
 
218
                                                               "whether this playlist is attached to the local library",
 
219
                                                               FALSE,
 
220
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
221
        g_object_class_install_property (object_class,
 
222
                                         PROP_ENTRY_TYPE,
 
223
                                         g_param_spec_int ("entry-type",
 
224
                                                           "entry-type",
 
225
                                                           "The entry type this playlist accepts",
 
226
                                                           -1, G_MAXINT, -1,
 
227
                                                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
228
 
204
229
}
205
230
 
206
231
static void
229
254
{
230
255
        RBPlaylistSource *source;
231
256
        RBPlaylistSourceClass *klass;
232
 
        GObjectClass *parent_class;  
233
 
        GtkWidget *dummy = gtk_tree_view_new ();
 
257
        RBShell *shell;
234
258
 
235
259
        klass = RB_PLAYLIST_SOURCE_CLASS (g_type_class_peek (RB_TYPE_PLAYLIST_SOURCE));
236
260
 
237
 
        parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
238
 
        source = RB_PLAYLIST_SOURCE (parent_class->constructor (type, n_construct_properties,
239
 
                                                                construct_properties));
 
261
        source = RB_PLAYLIST_SOURCE (G_OBJECT_CLASS (rb_playlist_source_parent_class)->
 
262
                        constructor (type, n_construct_properties, construct_properties));
 
263
 
 
264
        g_object_get (G_OBJECT (source), "shell", &shell, NULL);
 
265
        g_object_get (RB_SHELL (shell), "db", &source->priv->db, NULL);
 
266
        g_object_unref (G_OBJECT (shell));
240
267
 
241
268
        g_signal_connect_object (G_OBJECT (source->priv->db), "entry_added",
242
269
                                 G_CALLBACK (rb_playlist_source_entry_added_cb),
255
282
                
256
283
        source->priv->songs = rb_entry_view_new (source->priv->db, NULL, TRUE, TRUE);
257
284
 
 
285
        /* watch these to find out when things were dropping into the entry view */
 
286
        g_signal_connect_object (G_OBJECT (source->priv->model), "row-inserted",
 
287
                         G_CALLBACK (rb_playlist_source_row_inserted),
 
288
                         source, 0);
 
289
        g_signal_connect_object (G_OBJECT (source->priv->model), "non-entry-dropped",
 
290
                         G_CALLBACK (rb_playlist_source_non_entry_dropped),
 
291
                         source, 0);
 
292
 
258
293
        rb_entry_view_set_model (source->priv->songs, RHYTHMDB_QUERY_MODEL (source->priv->model));
259
294
 
260
295
        {
261
 
                GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (rb_tree_view_column_new ());
 
296
                GtkTreeViewColumn *column = gtk_tree_view_column_new ();
262
297
                GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
263
298
                gtk_tree_view_column_pack_start (column, renderer, TRUE);
264
299
 
268
303
                                                         rb_playlist_source_track_cell_data_func,
269
304
                                                         source, NULL);
270
305
                rb_entry_view_append_column_custom (source->priv->songs, column, 
271
 
                                                    _("Tra_ck"), "PlaylistTrack", NULL, NULL);
 
306
                                                    _("Trac_k"), "PlaylistTrack", NULL, NULL);
272
307
        }
273
308
 
274
309
        rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_TITLE);
275
310
        rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_GENRE);
276
311
        rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_ARTIST);
277
312
        rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_ALBUM);
 
313
        rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_YEAR);
278
314
        rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_DURATION);
279
315
        rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_RATING);
280
316
        rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_PLAY_COUNT);
281
317
        rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_LAST_PLAYED);
282
 
        rb_entry_view_set_columns_clickable (source->priv->songs, FALSE);
 
318
        rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_FIRST_SEEN);
283
319
 
284
320
        g_signal_connect_object (G_OBJECT (source->priv->songs), "show_popup",
285
321
                                 G_CALLBACK (rb_playlist_source_songs_show_popup_cb), source, 0);
 
322
        g_signal_connect_object (G_OBJECT (source->priv->songs), "sort-order-changed",
 
323
                                 G_CALLBACK (rb_playlist_source_songs_sort_order_changed_cb), source, 0);
286
324
                
287
325
        g_signal_connect_object (G_OBJECT (source->priv->songs), "drag_data_received",
288
326
                                 G_CALLBACK (rb_playlist_source_drop_cb), source, 0);
289
327
        gtk_drag_dest_set (GTK_WIDGET (source->priv->songs), GTK_DEST_DEFAULT_ALL,
290
328
                           target_uri, G_N_ELEMENTS (target_uri), GDK_ACTION_COPY);
291
 
                
292
 
        source->priv->normal_pixbuf = gtk_widget_render_icon (dummy,
293
 
                                                       RB_STOCK_PLAYLIST,
294
 
                                                       GTK_ICON_SIZE_LARGE_TOOLBAR,
295
 
                                                       NULL);
296
 
        source->priv->smartypants_pixbuf = gtk_widget_render_icon (dummy,
297
 
                                                                   RB_STOCK_AUTOMATIC_PLAYLIST,
298
 
                                                                   GTK_ICON_SIZE_LARGE_TOOLBAR,
299
 
                                                                   NULL);
300
 
        gtk_widget_destroy (dummy);
301
 
                
 
329
 
 
330
        {
 
331
                GtkIconTheme *theme = gtk_icon_theme_get_default();
 
332
                gint size;
 
333
 
 
334
                gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR, &size, NULL);
 
335
                source->priv->normal_pixbuf = gtk_icon_theme_load_icon (theme,
 
336
                                                                        "stock_playlist",
 
337
                                                                        size,
 
338
                                                                        0, NULL);
 
339
                source->priv->smartypants_pixbuf = gtk_icon_theme_load_icon (theme,
 
340
                                                                             "stock_smart-playlist",
 
341
                                                                             size,
 
342
                                                                             0, NULL);
 
343
        }
 
344
                
 
345
        rb_entry_view_set_columns_clickable (source->priv->songs, FALSE);
 
346
        source->priv->query_resetting = FALSE;
 
347
 
302
348
        gtk_box_pack_start_defaults (GTK_BOX (source->priv->vbox), GTK_WIDGET (source->priv->songs));
303
349
                
304
350
        gtk_widget_show_all (GTK_WIDGET (source));
310
356
rb_playlist_source_songs_show_popup_cb (RBEntryView *view,
311
357
                                        RBPlaylistSource *playlist_view)
312
358
{
313
 
        rb_bonobo_show_popup (GTK_WIDGET (view), PLAYLIST_SOURCE_SONGS_POPUP_PATH);
 
359
        _rb_source_show_popup (RB_SOURCE (playlist_view), 
 
360
                               PLAYLIST_SOURCE_SONGS_POPUP_PATH);
314
361
}
315
362
 
316
363
static void
320
367
}
321
368
 
322
369
static void
323
 
rb_playlist_source_finalize (GObject *object)
 
370
rb_playlist_source_dispose (GObject *object)
324
371
{
325
372
        RBPlaylistSource *source;
326
 
 
327
 
        g_return_if_fail (object != NULL);
328
 
        g_return_if_fail (RB_IS_PLAYLIST_SOURCE (object));
329
 
 
330
373
        source = RB_PLAYLIST_SOURCE (object);
331
374
 
332
 
        g_return_if_fail (source->priv != NULL);
333
 
 
334
 
        g_hash_table_destroy (source->priv->entries);
335
 
 
336
 
        g_free (source->priv->title);
337
 
        g_free (source->priv->status);
338
 
 
339
 
        g_free (source->priv);
340
 
 
341
 
        G_OBJECT_CLASS (parent_class)->finalize (object);
 
375
        if (source->priv) {
 
376
                g_hash_table_destroy (source->priv->entries);
 
377
                g_object_unref (source->priv->db);
 
378
                g_free (source->priv->title);
 
379
        
 
380
                g_free (source->priv);
 
381
                source->priv = NULL;
 
382
        }
 
383
 
 
384
        G_OBJECT_CLASS (rb_playlist_source_parent_class)->dispose (object);
342
385
}
343
386
 
344
387
static void
351
394
 
352
395
        switch (prop_id)
353
396
        {
354
 
        case PROP_DB:
355
 
                source->priv->db = g_value_get_object (value);
356
 
                break;
357
397
        case PROP_AUTOMATIC:
358
398
                source->priv->automatic = g_value_get_boolean (value);
359
399
                break;
 
400
        case PROP_LOCAL:
 
401
                source->priv->is_local = g_value_get_boolean (value);
 
402
                break;
 
403
        case PROP_ENTRY_TYPE:
 
404
                source->priv->entry_type = g_value_get_int (value);
 
405
                break;
360
406
        default:
361
407
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
362
408
                break;
373
419
 
374
420
        switch (prop_id)
375
421
        {
376
 
        case PROP_DB:
377
 
                g_value_set_object (value, source->priv->db);
378
 
                break;
379
422
        case PROP_AUTOMATIC:
380
423
                g_value_set_boolean (value, source->priv->automatic);
381
424
                break;
 
425
        case PROP_DIRTY:
 
426
                g_value_set_boolean (value, source->priv->dirty);
 
427
                break;
 
428
        case PROP_QUERY_MODEL:
 
429
                g_value_set_object (value, source->priv->model);
 
430
                break;
 
431
        case PROP_LOCAL:
 
432
                g_value_set_boolean (value, source->priv->is_local);
 
433
                break;
 
434
        case PROP_ENTRY_TYPE:
 
435
                g_value_set_int (value, source->priv->entry_type);
 
436
                break;
382
437
        default:
383
438
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
384
439
                break;
386
441
}
387
442
 
388
443
RBSource *
389
 
rb_playlist_source_new (RhythmDB *db, gboolean automatic)
 
444
rb_playlist_source_new (RBShell *shell, gboolean automatic, gboolean local, RhythmDBEntryType entry_type)
390
445
{
391
446
        RBSource *source;
392
447
        
393
448
        source = RB_SOURCE (g_object_new (RB_TYPE_PLAYLIST_SOURCE,
394
449
                                          "name", _("Unknown"),
395
 
                                          "db", db,
 
450
                                          "shell", shell,
396
451
                                          "automatic", automatic,
 
452
                                          "is-local", local,
 
453
                                          "entry-type", entry_type,
397
454
                                          NULL));
398
455
 
399
456
        return source;
408
465
        if (source->priv->automatic)
409
466
                return;
410
467
        
411
 
        location = rhythmdb_entry_get_string (db, entry,
412
 
                                              RHYTHMDB_PROP_LOCATION);
 
468
        location = entry->location;
413
469
        if (g_hash_table_lookup (source->priv->entries, location)) {
414
470
                rhythmdb_query_model_add_entry (source->priv->model, entry);
 
471
                source->priv->dirty = TRUE;
415
472
        }
416
473
}
417
474
 
418
 
RhythmDBQueryModel *
419
 
rb_playlist_source_get_model (RBPlaylistSource *source)
420
 
{
421
 
        return source->priv->model;
422
 
}
423
 
 
424
475
void
425
476
rb_playlist_source_set_query (RBPlaylistSource *source,
426
477
                              GPtrArray *query,
427
478
                              guint limit_count,
428
 
                              guint limit_mb)
 
479
                              guint limit_mb,
 
480
                              guint limit_time,
 
481
                              const char *sort_key,
 
482
                              gint sort_direction)
429
483
{
430
 
        RhythmDBQueryModel *query_model;
431
 
        GtkTreeModel *model;
432
 
        
433
484
        g_assert (source->priv->automatic);
434
485
 
435
 
        source->priv->model = query_model
436
 
                = g_object_new (RHYTHMDB_TYPE_QUERY_MODEL,
437
 
                                "db", source->priv->db,
438
 
                                "max-count", limit_count,
439
 
                                "max-size", limit_mb, 
440
 
                                NULL);
441
 
 
442
 
        model = GTK_TREE_MODEL (query_model);
443
 
 
444
 
        rb_entry_view_set_model (source->priv->songs, RHYTHMDB_QUERY_MODEL (query_model));
445
 
 
446
 
        rhythmdb_read_lock (source->priv->db);
447
 
        rhythmdb_do_full_query_async_parsed (source->priv->db, model, query);
448
 
 
449
 
        g_object_unref (G_OBJECT (query_model));
450
 
        rb_entry_view_poll_model (source->priv->songs);
 
486
        source->priv->query_resetting = TRUE;
 
487
 
 
488
        /* playlists that aren't limited, with a particular sort order, are user-orderable */
 
489
        rb_entry_view_set_columns_clickable (source->priv->songs, (limit_count == 0 && limit_mb == 0));
 
490
        rb_entry_view_set_sorting_order (source->priv->songs, sort_key, sort_direction);
 
491
 
 
492
        rb_playlist_source_do_query (source, query, limit_count, limit_mb, limit_time);
 
493
        rhythmdb_query_free (query);
 
494
        source->priv->query_resetting = FALSE;
451
495
}
452
496
 
453
497
void
454
498
rb_playlist_source_get_query (RBPlaylistSource *source,
455
499
                              GPtrArray **query,
456
500
                              guint *limit_count,
457
 
                              guint *limit_mb)
 
501
                              guint *limit_mb,
 
502
                              guint *limit_time,
 
503
                              const char **sort_key,
 
504
                              gint *sort_direction)
458
505
{
459
506
        g_assert (source->priv->automatic);
460
507
 
461
508
        g_object_get (G_OBJECT (source->priv->model),
462
509
                      "query", query,
463
510
                      "max-count", limit_count,
464
 
                      "max-size", limit_mb, NULL);
 
511
                      "max-size", limit_mb,
 
512
                      "max-time", limit_time,
 
513
                      NULL);
 
514
 
 
515
        rb_entry_view_get_sorting_order (source->priv->songs, sort_key, sort_direction);
465
516
}
466
517
 
467
 
static const char *
 
518
static char *
468
519
impl_get_status (RBSource *asource)
469
520
{
470
521
 
471
522
        RBPlaylistSource *source = RB_PLAYLIST_SOURCE (asource);
472
 
        g_free (source->priv->status);
473
 
        source->priv->status = rhythmdb_compute_status_normal (rb_entry_view_get_num_entries (source->priv->songs),
474
 
                                                               rb_entry_view_get_duration (source->priv->songs),
475
 
                                                               rb_entry_view_get_total_size (source->priv->songs));
476
 
        return source->priv->status;
 
523
        gchar *status;
 
524
 
 
525
        status = rhythmdb_compute_status_normal (rb_entry_view_get_num_entries (source->priv->songs),
 
526
                                                 rb_entry_view_get_duration (source->priv->songs),
 
527
                                                 rb_entry_view_get_total_size (source->priv->songs));
 
528
        return status;
477
529
}
478
530
 
479
531
static const char *
574
626
        GList *list;
575
627
        RBPlaylistSource *source = RB_PLAYLIST_SOURCE (asource);
576
628
 
577
 
 
578
629
        if (data->type == gdk_atom_intern ("text/uri-list", TRUE)) {
579
 
                list = gnome_vfs_uri_list_parse (data->data);
 
630
                list = gnome_vfs_uri_list_parse ((char *) data->data);
580
631
 
581
632
                if (list != NULL)
582
633
                        rb_playlist_source_add_list_uri (source, list);
584
635
                        return FALSE;
585
636
 
586
637
        } else {
587
 
                GPtrArray *query;
588
 
                GPtrArray *subquery;
589
 
 
590
 
                subquery = rhythmdb_query_parse (source->priv->db,
591
 
                                                 RHYTHMDB_QUERY_PROP_EQUALS,
592
 
                                                 rb_playlist_source_drag_atom_to_prop (data->type),
593
 
                                                 data->data,
594
 
                                                 RHYTHMDB_QUERY_END);
595
 
                query = rhythmdb_query_parse (source->priv->db,
596
 
                                              RHYTHMDB_QUERY_PROP_EQUALS,
597
 
                                              RHYTHMDB_PROP_TYPE,
598
 
                                              RHYTHMDB_ENTRY_TYPE_SONG,
599
 
                                              RHYTHMDB_QUERY_SUBQUERY,
600
 
                                              subquery,
601
 
                                              RHYTHMDB_QUERY_END);
602
 
                rb_playlist_source_set_query (source, query, 0, 0);
 
638
                GPtrArray *subquery = NULL;
 
639
                gchar **names = g_strsplit ((char *)data->data, "\r\n", 0);
 
640
                guint propid = rb_playlist_source_drag_atom_to_prop (data->type);
 
641
                int i;
 
642
 
 
643
                for (i=0; names[i]; i++) {
 
644
                        if (subquery == NULL) 
 
645
                                subquery = rhythmdb_query_parse (source->priv->db,
 
646
                                                                 RHYTHMDB_QUERY_PROP_EQUALS,
 
647
                                                                 propid,
 
648
                                                                 names[i],
 
649
                                                                 RHYTHMDB_QUERY_END);
 
650
                        else
 
651
                                rhythmdb_query_append (source->priv->db,
 
652
                                                       subquery,
 
653
                                                       RHYTHMDB_QUERY_DISJUNCTION,
 
654
                                                       RHYTHMDB_QUERY_PROP_EQUALS,
 
655
                                                       propid,
 
656
                                                       names[i],
 
657
                                                       RHYTHMDB_QUERY_END);
 
658
                }
 
659
 
 
660
                g_strfreev (names);
 
661
 
 
662
                if (subquery) {
 
663
                        RhythmDBEntryType qtype = RHYTHMDB_ENTRY_TYPE_SONG;
 
664
                        GPtrArray *query;
 
665
                        
 
666
                        if (source->priv->entry_type != -1)
 
667
                                qtype = source->priv->entry_type;
 
668
 
 
669
                        query = rhythmdb_query_parse (source->priv->db,
 
670
                                                      RHYTHMDB_QUERY_PROP_EQUALS,
 
671
                                                      RHYTHMDB_PROP_TYPE,
 
672
                                                      qtype,
 
673
                                                      RHYTHMDB_QUERY_SUBQUERY,
 
674
                                                      subquery,
 
675
                                                      RHYTHMDB_QUERY_END);
 
676
                        rb_playlist_source_set_query (source, query, 0, 0, 0, NULL, 0);
 
677
                }
603
678
        }
604
679
 
605
680
        return TRUE;
609
684
impl_show_popup (RBSource *asource)
610
685
{
611
686
        RBPlaylistSource *source = RB_PLAYLIST_SOURCE (asource);
612
 
        if (source->priv->automatic)
613
 
                rb_bonobo_show_popup (GTK_WIDGET (source), PLAYLIST_SOURCE_AUTOMATIC_POPUP_PATH);
614
 
        else
615
 
                rb_bonobo_show_popup (GTK_WIDGET (source), PLAYLIST_SOURCE_POPUP_PATH);
 
687
 
 
688
        if (source->priv->automatic) {
 
689
                _rb_source_show_popup (RB_SOURCE (asource), PLAYLIST_SOURCE_AUTOMATIC_POPUP_PATH);
 
690
        } else {
 
691
                _rb_source_show_popup (RB_SOURCE (asource), PLAYLIST_SOURCE_POPUP_PATH);
 
692
        }
616
693
        return TRUE;
617
694
}
618
695
 
642
719
        gtk_drag_finish (context, TRUE, FALSE, time);
643
720
}
644
721
 
 
722
 
 
723
 
 
724
static void
 
725
rb_playlist_source_add_location_swapped (const char *uri, RBPlaylistSource *source)
 
726
{
 
727
        rb_playlist_source_add_location (source, uri);
 
728
}
 
729
 
645
730
void
646
731
rb_playlist_source_add_location (RBPlaylistSource *source,
647
732
                                 const char *location)
648
733
{
649
734
        RhythmDBEntry *entry;
650
 
 
651
 
        rhythmdb_read_lock (source->priv->db);
652
 
        if (g_hash_table_lookup (source->priv->entries, location)) {
653
 
                rhythmdb_read_unlock (source->priv->db);
 
735
        
 
736
        entry = rhythmdb_entry_lookup_by_location (source->priv->db, location);
 
737
        if (entry != NULL && 
 
738
            source->priv->entry_type != -1 &&
 
739
            rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TYPE) != source->priv->entry_type) {
 
740
                rb_debug ("attempting to add an entry of the wrong type to playlist");
654
741
                return;
655
742
        }
656
743
 
657
 
        g_hash_table_insert (source->priv->entries,
658
 
                             g_strdup (location), GINT_TO_POINTER (1));
659
 
 
660
 
        entry = rhythmdb_entry_lookup_by_location (source->priv->db, location);
661
 
        if (entry)
662
 
                rhythmdb_entry_ref_unlocked (source->priv->db, entry);
663
 
        rhythmdb_read_unlock (source->priv->db);
664
 
 
665
 
        if (entry != NULL) {
666
 
                rhythmdb_query_model_add_entry (source->priv->model, entry);
667
 
                rhythmdb_entry_unref (source->priv->db, entry);
668
 
        }
669
 
}
 
744
        if (rb_uri_is_directory (location)) {
 
745
                rb_uri_handle_recursively (location,
 
746
                                           (GFunc) rb_playlist_source_add_location_swapped,
 
747
                                           NULL,
 
748
                                           source);
 
749
        } else {
 
750
                if (g_hash_table_lookup (source->priv->entries, location)) {
 
751
                        return;
 
752
                }
 
753
 
 
754
                g_hash_table_insert (source->priv->entries,
 
755
                                     g_strdup (location), GINT_TO_POINTER (1));
 
756
 
 
757
                if (entry != NULL) {
 
758
                        rhythmdb_query_model_add_entry (source->priv->model, entry);
 
759
 
 
760
                        source->priv->dirty = TRUE;
 
761
                }
 
762
        }
 
763
}
 
764
 
 
765
void
 
766
rb_playlist_source_add_locations (RBPlaylistSource *source,
 
767
                                  GList *locations)
 
768
{
 
769
        GList *l;
 
770
 
 
771
        for (l = locations; l; l = l->next) {
 
772
                const gchar *uri = (const gchar *)l->data;
 
773
                
 
774
                rb_playlist_source_add_location (RB_PLAYLIST_SOURCE (source), 
 
775
                                                 uri);
 
776
        }
 
777
}
 
778
 
670
779
 
671
780
void
672
781
rb_playlist_source_remove_location (RBPlaylistSource *source,
675
784
        RhythmDBEntry *entry;
676
785
 
677
786
        g_return_if_fail (g_hash_table_lookup (source->priv->entries, location) != NULL);
678
 
        g_hash_table_remove (source->priv->entries,
679
 
                             location);
680
 
        rhythmdb_read_lock (source->priv->db);
 
787
 
 
788
        g_hash_table_remove (source->priv->entries, location);
681
789
        entry = rhythmdb_entry_lookup_by_location (source->priv->db, location);
682
 
        rhythmdb_read_unlock (source->priv->db);
683
 
        if (entry != NULL)
684
 
                rhythmdb_query_model_remove_entry (source->priv->model, entry);
 
790
        if (entry != NULL) {
 
791
                gboolean removed;
 
792
                
 
793
                removed = rhythmdb_query_model_remove_entry (source->priv->model, entry);
 
794
                g_assert (removed); /* if this fails, the model and the playlist are out of sync */
 
795
                source->priv->dirty = TRUE;
 
796
        }
685
797
}
686
798
 
687
799
void
688
800
rb_playlist_source_add_entry (RBPlaylistSource *source,
689
801
                              RhythmDBEntry *entry)
690
802
{
691
 
        const char *location;
692
 
 
693
 
        rhythmdb_read_lock (source->priv->db);
694
 
        location = rhythmdb_entry_get_string (source->priv->db, entry,
695
 
                                              RHYTHMDB_PROP_LOCATION);
696
 
        rhythmdb_read_unlock (source->priv->db);
697
 
 
698
 
        rb_playlist_source_add_location (source, location);
 
803
        rb_playlist_source_add_location (source, entry->location);
699
804
}
700
805
 
701
806
void
702
807
rb_playlist_source_remove_entry (RBPlaylistSource *source,
703
808
                                 RhythmDBEntry *entry)
704
809
{
705
 
        const char *location;
706
 
 
707
 
        rhythmdb_read_lock (source->priv->db);
708
 
        location = rhythmdb_entry_get_string (source->priv->db, entry,
709
 
                                              RHYTHMDB_PROP_LOCATION);
710
 
        rhythmdb_read_unlock (source->priv->db);
711
 
 
712
 
        rb_playlist_source_remove_location (source, location);
 
810
        rb_playlist_source_remove_location (source, entry->location);
713
811
}
714
812
 
715
813
static void
721
819
        g_return_if_fail (list != NULL);
722
820
 
723
821
        for (i = list; i != NULL; i = g_list_next (i))
724
 
                uri_list = g_list_append (uri_list, gnome_vfs_uri_to_string ((const GnomeVFSURI *) i->data, 0));
 
822
                uri_list = g_list_prepend (uri_list, gnome_vfs_uri_to_string ((const GnomeVFSURI *) i->data, 0));
 
823
        uri_list = g_list_reverse (uri_list);
725
824
 
726
825
        gnome_vfs_uri_list_free (list);
727
826
 
731
830
        for (i = uri_list; i != NULL; i = i->next) {
732
831
                char *uri = i->data;
733
832
                if (uri != NULL) {
734
 
                        rhythmdb_read_lock (source->priv->db);
 
833
                        rhythmdb_add_uri (source->priv->db, uri);
735
834
                        rb_playlist_source_add_location (source, uri);
736
 
                        rhythmdb_read_unlock (source->priv->db);
737
835
                }
738
836
 
739
837
                g_free (uri);
743
841
}
744
842
 
745
843
static void
746
 
playlist_iter_func (GtkTreeModel *model, GtkTreeIter *iter, char **uri, char **title)
 
844
playlist_iter_func (GtkTreeModel *model, GtkTreeIter *iter, char **uri, char **title, gpointer user_data)
747
845
{
748
 
        RhythmDB *db;
749
846
        RhythmDBEntry *entry;
750
847
 
751
 
        g_object_get (G_OBJECT (model), "db", &db, NULL);
752
 
        
753
848
        gtk_tree_model_get (model, iter, 0, &entry, -1);
754
849
 
755
 
        rhythmdb_read_lock (db);
756
 
 
757
 
        *uri = g_strdup (rhythmdb_entry_get_string (db, entry, RHYTHMDB_PROP_LOCATION));
758
 
        *title = g_strdup (rhythmdb_entry_get_string (db, entry, RHYTHMDB_PROP_TITLE));
759
 
 
760
 
        rhythmdb_read_unlock (db);
 
850
        *uri = g_strdup (entry->location);
 
851
        *title = g_strdup (rb_refstring_get (entry->title));
761
852
}
762
853
 
763
854
void
764
855
rb_playlist_source_save_playlist (RBPlaylistSource *source, const char *uri)
765
856
{
766
 
        RBPlaylist *playlist;
 
857
        TotemPlParser *playlist;
767
858
        GError *error = NULL;
 
859
        char *name;
 
860
 
 
861
 
768
862
        rb_debug ("saving playlist");
769
 
 
770
 
        playlist = rb_playlist_new ();
771
 
 
772
 
        rb_playlist_write (playlist, GTK_TREE_MODEL (source->priv->model),
773
 
                           playlist_iter_func, uri, &error);
 
863
        playlist = totem_pl_parser_new ();
 
864
 
 
865
        g_object_get (G_OBJECT (source), "name", &name, NULL);
 
866
 
 
867
        totem_pl_parser_write_with_title (playlist, GTK_TREE_MODEL (source->priv->model),
 
868
                                          playlist_iter_func, uri, name,
 
869
                                          TOTEM_PL_PARSER_PLS, NULL, &error);
774
870
        if (error != NULL)
775
 
                rb_error_dialog ("%s", error->message);
 
871
                rb_error_dialog (NULL, _("Couldn't save playlist"),
 
872
                                 "%s", error->message);
 
873
}
 
874
 
 
875
static void
 
876
burn_playlist_iter_func (GtkTreeModel *model, GtkTreeIter *iter, char **uri, char **artist, char **title, gulong *duration)
 
877
{
 
878
        RhythmDBEntry *entry;
 
879
 
 
880
        gtk_tree_model_get (model, iter, 0, &entry, -1);
 
881
 
 
882
        *uri = g_strdup (entry->location);
 
883
        *artist = g_strdup (rb_refstring_get (entry->artist));
 
884
        *title = g_strdup (rb_refstring_get (entry->title));
 
885
        *duration = entry->duration;
 
886
}
 
887
 
 
888
void
 
889
rb_playlist_source_burn_playlist (RBPlaylistSource *source)
 
890
{
 
891
        GtkWidget *recorder;
 
892
        char *name;
 
893
        RBShell *shell;
 
894
 
 
895
        /* don't burn if the playlist is empty */
 
896
        if (gtk_tree_model_iter_n_children (GTK_TREE_MODEL (source->priv->model), NULL) == 0)
 
897
                return;
 
898
 
 
899
        rb_debug ("burning playlist");
 
900
 
 
901
        g_object_get (source, "name", &name, "shell", &shell, NULL);
 
902
 
 
903
        recorder = rb_playlist_source_recorder_new (gtk_widget_get_toplevel (GTK_WIDGET (source)),
 
904
                                                    shell,
 
905
                                                    name);
 
906
        g_object_unref (shell);
 
907
        g_free (name);
 
908
 
 
909
        rb_playlist_source_recorder_add_from_model (RB_PLAYLIST_SOURCE_RECORDER (recorder),
 
910
                                                    GTK_TREE_MODEL (source->priv->model),
 
911
                                                    burn_playlist_iter_func,
 
912
                                                    NULL);
 
913
 
 
914
        g_signal_connect (recorder,
 
915
                          "response",
 
916
                          G_CALLBACK (gtk_widget_destroy),
 
917
                          NULL);
 
918
 
 
919
        gtk_widget_show (recorder);
776
920
}
777
921
 
778
922
RBSource *
779
 
rb_playlist_source_new_from_xml (RhythmDB *db,
 
923
rb_playlist_source_new_from_xml (RBShell *shell,
780
924
                                 xmlNodePtr node)
781
925
{
782
926
        RBPlaylistSource *source;
783
927
        xmlNodePtr child;
784
 
        char *tmp;
785
 
 
786
 
        source = RB_PLAYLIST_SOURCE (rb_playlist_source_new (db, FALSE));
787
 
 
788
 
        tmp = xmlGetProp (node, "type");
789
 
        if (!strcmp (tmp, "automatic"))
 
928
        xmlChar *tmp;
 
929
 
 
930
        source = RB_PLAYLIST_SOURCE (rb_playlist_source_new (shell, FALSE, TRUE, RHYTHMDB_ENTRY_TYPE_SONG));
 
931
 
 
932
        tmp = xmlGetProp (node, RB_PLAYLIST_TYPE);
 
933
        if (!xmlStrcmp (tmp, RB_PLAYLIST_AUTOMATIC))
790
934
                source->priv->automatic = TRUE;
791
935
        g_free (tmp);
792
936
 
793
 
        tmp = xmlGetProp (node, "name");
 
937
        tmp = xmlGetProp (node, RB_PLAYLIST_NAME);
794
938
        g_object_set (G_OBJECT (source), "name", tmp, NULL);
795
939
        g_free (tmp);
796
940
 
797
 
        tmp = xmlGetProp (node, "internal-name");
798
 
        if (!tmp) {
799
 
                GTimeVal serial;
800
 
                /* Hm.  Upgrades. */
801
 
                g_get_current_time (&serial);
802
 
                tmp = g_strdup_printf ("<playlist:%ld:%ld>",
803
 
                                       serial.tv_sec, serial.tv_usec);
804
 
        }
805
 
        g_object_set (G_OBJECT (source), "internal-name", tmp, NULL);
806
 
        g_free (tmp);
807
 
 
808
941
        if (source->priv->automatic) {
809
942
                GPtrArray *query;
810
 
                gchar *limit_str;
811
 
                guint limit_count = 0;
812
 
                guint limit_mb = 0;
 
943
                gint limit_count = 0, limit_mb = 0, limit_time = 0;
 
944
                gchar *sort_key = NULL;
 
945
                gint sort_direction = 0;
813
946
 
814
947
                child = node->children;
815
948
                while (xmlNodeIsText (child))
816
949
                        child = child->next;
817
950
 
818
 
                query = rhythmdb_query_deserialize (db, child);
819
 
                limit_str = xmlGetProp (node, "limit-count");
820
 
                if (!limit_str) /* Backwards compatibility */
821
 
                        limit_str = xmlGetProp (node, "limit");
822
 
                if (limit_str) {
823
 
                        limit_count = atoi (limit_str);
824
 
                        g_free (limit_str);
825
 
                }
826
 
                limit_str = xmlGetProp (node, "limit-size");
827
 
                if (limit_str) {
828
 
                        limit_mb = atoi (limit_str);
829
 
                        g_free (limit_str);
830
 
                }
 
951
                query = rhythmdb_query_deserialize (source->priv->db, child);
 
952
                tmp = xmlGetProp (node, RB_PLAYLIST_LIMIT_COUNT);
 
953
                if (!tmp) /* Backwards compatibility */
 
954
                        tmp = xmlGetProp (node, RB_PLAYLIST_LIMIT);
 
955
                if (tmp) {
 
956
                        limit_count = atoi ((char*) tmp);
 
957
                        g_free (tmp);
 
958
                }
 
959
                tmp = xmlGetProp (node, RB_PLAYLIST_LIMIT_SIZE);
 
960
                if (tmp) {
 
961
                        limit_mb = atoi ((char*) tmp);
 
962
                        g_free (tmp);
 
963
                }
 
964
                tmp = xmlGetProp (node, RB_PLAYLIST_LIMIT_TIME);
 
965
                if (tmp) {
 
966
                        limit_time = atoi ((char*) tmp);
 
967
                        g_free (tmp);
 
968
                }
 
969
 
 
970
                sort_key = (gchar*) xmlGetProp (node, RB_PLAYLIST_SORT_KEY);
 
971
                if (sort_key && *sort_key) {
 
972
                        tmp = xmlGetProp (node, RB_PLAYLIST_SORT_DIRECTION);
 
973
                        if (tmp) {
 
974
                                sort_direction = atoi ((char*) tmp);
 
975
                                g_free (tmp);
 
976
                        }
 
977
                } else {
 
978
                        g_free (sort_key);
 
979
                        sort_key = NULL;
 
980
                        sort_direction = 0;
 
981
                }
 
982
 
831
983
                rb_playlist_source_set_query (source, query,
832
984
                                              limit_count,
833
 
                                              limit_mb);
 
985
                                              limit_mb,
 
986
                                              limit_time,
 
987
                                              sort_key,
 
988
                                              sort_direction);
 
989
                g_free (sort_key);
834
990
        } else {
835
991
                for (child = node->children; child; child = child->next) {
836
 
                        char *location;
 
992
                        xmlChar *location;
837
993
 
838
994
                        if (xmlNodeIsText (child))
839
995
                                continue;
840
996
                
841
 
                        if (strcmp (child->name, "location"))
 
997
                        if (xmlStrcmp (child->name, RB_PLAYLIST_LOCATION))
842
998
                                continue;
843
999
                
844
1000
                        location = xmlNodeGetContent (child);
845
 
                        rb_playlist_source_add_location (source, location);
 
1001
                        rb_playlist_source_add_location (source,
 
1002
                                                         (char *) location);
846
1003
                }
847
1004
        }
848
1005
 
853
1010
rb_playlist_source_save_to_xml (RBPlaylistSource *source, xmlNodePtr parent_node)
854
1011
{
855
1012
        xmlNodePtr node;
856
 
        char *name;
857
 
        char *internal_name;
 
1013
        xmlChar *name;
858
1014
        GtkTreeIter iter;
859
1015
 
860
 
        node = xmlNewChild (parent_node, NULL, "playlist", NULL);
861
 
        g_object_get (G_OBJECT (source), "name", &name,
862
 
                      "internal-name", &internal_name, NULL);
863
 
        xmlSetProp (node, "name", name);
864
 
        xmlSetProp (node, "internal-name", internal_name);
865
 
        xmlSetProp (node, "type", source->priv->automatic ? "automatic" : "static");
866
 
        
 
1016
        node = xmlNewChild (parent_node, NULL, RB_PLAYLIST_PLAYLIST, NULL);
 
1017
        g_object_get (G_OBJECT (source), "name", &name, NULL);
 
1018
        xmlSetProp (node, RB_PLAYLIST_NAME, name);
 
1019
        xmlSetProp (node, RB_PLAYLIST_TYPE, source->priv->automatic ? RB_PLAYLIST_AUTOMATIC : RB_PLAYLIST_STATIC);
 
1020
 
867
1021
        if (!source->priv->automatic) {
868
1022
                if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (source->priv->model),
869
1023
                                                    &iter))
870
1024
                        return;
871
1025
                do { 
872
 
                        xmlNodePtr child_node = xmlNewChild (node, NULL, "location", NULL);
 
1026
                        xmlNodePtr child_node = xmlNewChild (node, NULL, RB_PLAYLIST_LOCATION, NULL);
873
1027
                        RhythmDBEntry *entry;
874
 
                        const char *location;
875
 
                        char *encoded;
 
1028
                        xmlChar *encoded;
876
1029
 
877
1030
                        gtk_tree_model_get (GTK_TREE_MODEL (source->priv->model), &iter, 0, &entry, -1);
878
1031
 
879
 
                        rhythmdb_read_lock (source->priv->db);
880
 
                        location = rhythmdb_entry_get_string (source->priv->db, entry,
881
 
                                                              RHYTHMDB_PROP_LOCATION);
882
 
                        rhythmdb_read_unlock (source->priv->db);
883
 
                        
884
 
                        encoded = xmlEncodeEntitiesReentrant (NULL, location);                  
885
 
                        
 
1032
                        encoded = xmlEncodeEntitiesReentrant (NULL, BAD_CAST entry->location);
 
1033
 
886
1034
                        xmlNodeSetContent (child_node, encoded);
887
1035
                        g_free (encoded);
888
1036
                } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (source->priv->model),
889
1037
                                                   &iter));
890
1038
        } else {
891
1039
                GPtrArray *query;
892
 
                guint max_count;
893
 
                guint max_size_mb;
894
 
                char *limit_str;
895
 
 
896
 
                g_object_get (G_OBJECT (source->priv->model),
897
 
                              "max-count", &max_count,
898
 
                              "max-size", &max_size_mb,
899
 
                              "query", &query, NULL);
900
 
                limit_str = g_strdup_printf ("%d", max_count);
901
 
                xmlSetProp (node, "limit-count", limit_str);
902
 
                g_free (limit_str);
903
 
                limit_str = g_strdup_printf ("%d", max_size_mb);
904
 
                xmlSetProp (node, "limit-size", limit_str);
905
 
                g_free (limit_str);
 
1040
                guint max_count, max_size_mb, max_time;
 
1041
                const gchar *sort_key;
 
1042
                gint sort_direction;
 
1043
                gchar *temp_str;
 
1044
 
 
1045
                rb_playlist_source_get_query (source,
 
1046
                                              &query,
 
1047
                                              &max_count, &max_size_mb, &max_time,
 
1048
                                              &sort_key, &sort_direction);
 
1049
                temp_str = g_strdup_printf ("%d", max_count);
 
1050
                xmlSetProp (node, RB_PLAYLIST_LIMIT_COUNT, BAD_CAST temp_str);
 
1051
                g_free (temp_str);
 
1052
                temp_str = g_strdup_printf ("%d", max_size_mb);
 
1053
                xmlSetProp (node, RB_PLAYLIST_LIMIT_SIZE, BAD_CAST temp_str);
 
1054
                g_free (temp_str);
 
1055
                temp_str = g_strdup_printf ("%d", max_time);
 
1056
                xmlSetProp (node, RB_PLAYLIST_LIMIT_TIME, BAD_CAST temp_str);
 
1057
                g_free (temp_str);
 
1058
 
 
1059
                if (sort_key && *sort_key) {
 
1060
                        xmlSetProp (node, RB_PLAYLIST_SORT_KEY, BAD_CAST sort_key);
 
1061
                        temp_str = g_strdup_printf ("%d", sort_direction);
 
1062
                        xmlSetProp (node, RB_PLAYLIST_SORT_DIRECTION, BAD_CAST temp_str);
 
1063
                        g_free (temp_str);
 
1064
                }
 
1065
 
906
1066
                rhythmdb_query_serialize (source->priv->db, query, node);
907
1067
        }
 
1068
 
 
1069
        source->priv->dirty = FALSE;
 
1070
}
 
1071
 
 
1072
static void
 
1073
rb_playlist_source_songs_sort_order_changed_cb (RBEntryView *view, RBPlaylistSource *source)
 
1074
{
 
1075
        GPtrArray *query;
 
1076
        guint limit_count, limit_mb, limit_time;
 
1077
 
 
1078
        g_assert (source->priv->automatic);
 
1079
 
 
1080
        /* don't process this if we are in the middle of setting a query */
 
1081
        if (source->priv->query_resetting)
 
1082
                return;
 
1083
        rb_debug ("sort order changed");
 
1084
 
 
1085
        /* need to re-run query with the same settings*/
 
1086
        g_object_get (G_OBJECT (source->priv->model),
 
1087
                      "query", &query,
 
1088
                      "max-count", &limit_count,
 
1089
                      "max-size", &limit_mb,
 
1090
                      "max-size", &limit_time,
 
1091
                      NULL);
 
1092
 
 
1093
        rb_playlist_source_do_query (source, query, limit_count, limit_mb, limit_time);
 
1094
        rhythmdb_query_free (query);
 
1095
}
 
1096
 
 
1097
static void
 
1098
rb_playlist_source_do_query (RBPlaylistSource *source,
 
1099
                              GPtrArray *query,
 
1100
                              guint limit_count,
 
1101
                              guint limit_mb,
 
1102
                              guint limit_time)
 
1103
{
 
1104
        g_assert (source->priv->automatic);
 
1105
 
 
1106
        source->priv->model = g_object_new (RHYTHMDB_TYPE_QUERY_MODEL,
 
1107
                                    "db", source->priv->db,
 
1108
                                    "max-count", limit_count,
 
1109
                                    "max-size", limit_mb, 
 
1110
                                    "max-time", limit_time, 
 
1111
                                    NULL);
 
1112
 
 
1113
        rb_entry_view_set_model (source->priv->songs, source->priv->model);
 
1114
        rhythmdb_do_full_query_async_parsed (source->priv->db, GTK_TREE_MODEL (source->priv->model), query);
 
1115
 
 
1116
        /* emit notification the the property has changed */
 
1117
        g_object_notify (G_OBJECT (source), "query-model");
 
1118
}
 
1119
 
 
1120
static void
 
1121
rb_playlist_source_non_entry_dropped (GtkTreeModel *model,
 
1122
                                      const char *uri,
 
1123
                                      RBPlaylistSource *source)
 
1124
{
 
1125
        rb_playlist_source_add_location (source, uri);
 
1126
}
 
1127
 
 
1128
static void
 
1129
rb_playlist_source_row_inserted (GtkTreeModel *model,
 
1130
                                 GtkTreePath *path,
 
1131
                                 GtkTreeIter *iter,
 
1132
                                 RBPlaylistSource *source)
 
1133
{
 
1134
        RhythmDBEntry *entry;
 
1135
 
 
1136
        gtk_tree_model_get (model, iter, 0, &entry, -1);
 
1137
 
 
1138
        rb_playlist_source_add_location (source, rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION));
908
1139
}