~ubuntu-branches/ubuntu/precise/rhythmbox/precise-201203091205

« back to all changes in this revision

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

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

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 -*- */
 
2
/*
 
3
 *  Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
 
4
 *  Copyright (C) 2003 Colin Walters <walters@gnome.org>
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; either version 2 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  This program is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with this program; if not, write to the Free Software
 
18
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
19
 *
 
20
 */
 
21
 
 
22
#include <config.h>
 
23
#include <gtk/gtk.h>
 
24
#include <libgnome/gnome-i18n.h>
 
25
#include <libgnomevfs/gnome-vfs-uri.h>
 
26
#include <libxml/tree.h>
 
27
#include <string.h>
 
28
 
 
29
#include "rb-auto-playlist-source.h"
 
30
#include "rb-util.h"
 
31
#include "rb-debug.h"
 
32
#include "rb-stock-icons.h"
 
33
#include "rb-playlist-xml.h"
 
34
 
 
35
static GObject *rb_auto_playlist_source_constructor (GType type, guint n_construct_properties,
 
36
                                                      GObjectConstructParam *construct_properties);
 
37
/* source methods */
 
38
static GdkPixbuf *impl_get_pixbuf (RBSource *source);
 
39
static gboolean impl_show_popup (RBSource *source);
 
40
static gboolean impl_receive_drag (RBSource *asource, GtkSelectionData *data);
 
41
static void impl_search (RBSource *asource, const char *search_text);
 
42
static void impl_reset_filters (RBSource *asource);
 
43
 
 
44
/* playlist methods */
 
45
static void impl_save_contents_to_xml (RBPlaylistSource *source,
 
46
                                       xmlNodePtr node);
 
47
 
 
48
static void rb_auto_playlist_source_songs_sort_order_changed_cb (RBEntryView *view, 
 
49
                                                                 RBAutoPlaylistSource *source); 
 
50
static void rb_auto_playlist_source_do_query (RBAutoPlaylistSource *source);
 
51
 
 
52
#define AUTO_PLAYLIST_SOURCE_POPUP_PATH "/AutoPlaylistSourcePopup"
 
53
 
 
54
typedef struct _RBAutoPlaylistSourcePrivate RBAutoPlaylistSourcePrivate;
 
55
 
 
56
struct _RBAutoPlaylistSourcePrivate
 
57
{
 
58
        GPtrArray *query;
 
59
        gboolean query_resetting;
 
60
        char *search_text;
 
61
        guint limit_count;
 
62
        guint limit_mb;
 
63
        guint limit_time;
 
64
};
 
65
 
 
66
G_DEFINE_TYPE (RBAutoPlaylistSource, rb_auto_playlist_source, RB_TYPE_PLAYLIST_SOURCE)
 
67
#define RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), RB_TYPE_AUTO_PLAYLIST_SOURCE, RBAutoPlaylistSourcePrivate))
 
68
 
 
69
static void
 
70
rb_auto_playlist_source_class_init (RBAutoPlaylistSourceClass *klass)
 
71
{
 
72
        gint size;
 
73
 
 
74
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
75
        RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
 
76
        RBPlaylistSourceClass *playlist_class = RB_PLAYLIST_SOURCE_CLASS (klass);
 
77
 
 
78
        object_class->constructor = rb_auto_playlist_source_constructor;
 
79
 
 
80
        source_class->impl_get_pixbuf = impl_get_pixbuf;
 
81
        source_class->impl_can_cut = (RBSourceFeatureFunc) rb_false_function;
 
82
        source_class->impl_can_delete = (RBSourceFeatureFunc) rb_false_function;
 
83
        source_class->impl_receive_drag = impl_receive_drag;
 
84
        source_class->impl_show_popup = impl_show_popup;
 
85
        source_class->impl_can_search = (RBSourceFeatureFunc) rb_true_function;
 
86
        source_class->impl_search = impl_search;
 
87
        source_class->impl_reset_filters = impl_reset_filters;
 
88
 
 
89
        playlist_class->impl_save_contents_to_xml = impl_save_contents_to_xml;
 
90
        
 
91
        gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR, &size, NULL);
 
92
        klass->pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
 
93
                                                  GNOME_MEDIA_AUTO_PLAYLIST,
 
94
                                                  size,
 
95
                                                  0, NULL);
 
96
        
 
97
        g_type_class_add_private (klass, sizeof (RBAutoPlaylistSourcePrivate));
 
98
}
 
99
 
 
100
static void
 
101
rb_auto_playlist_source_init (RBAutoPlaylistSource *source)
 
102
{
 
103
}
 
104
 
 
105
static GObject *
 
106
rb_auto_playlist_source_constructor (GType type, guint n_construct_properties,
 
107
                                      GObjectConstructParam *construct_properties)
 
108
{
 
109
        RBEntryView *songs;
 
110
        RBAutoPlaylistSource *source;
 
111
        GObjectClass *parent_class = G_OBJECT_CLASS (rb_auto_playlist_source_parent_class);
 
112
 
 
113
        source = RB_AUTO_PLAYLIST_SOURCE (
 
114
                        parent_class->constructor (type, n_construct_properties, construct_properties));
 
115
 
 
116
        songs = rb_source_get_entry_view (RB_SOURCE (source));
 
117
        g_signal_connect_object (G_OBJECT (songs), "sort-order-changed",
 
118
                                 G_CALLBACK (rb_auto_playlist_source_songs_sort_order_changed_cb), source, 0);
 
119
        
 
120
        return G_OBJECT (source);
 
121
}
 
122
 
 
123
RBSource *
 
124
rb_auto_playlist_source_new (RBShell *shell, const char *name, gboolean local)
 
125
{
 
126
        if (name == NULL)
 
127
                name = "";
 
128
 
 
129
        return RB_SOURCE (g_object_new (RB_TYPE_AUTO_PLAYLIST_SOURCE,
 
130
                                        "name", name,
 
131
                                        "shell", shell,
 
132
                                        "is-local", local,
 
133
                                        "entry-type", RHYTHMDB_ENTRY_TYPE_SONG,
 
134
                                        NULL));
 
135
}
 
136
 
 
137
RBSource *      
 
138
rb_auto_playlist_source_new_from_xml (RBShell *shell, xmlNodePtr node)
 
139
{
 
140
        RBAutoPlaylistSource *source = RB_AUTO_PLAYLIST_SOURCE (rb_auto_playlist_source_new (shell, NULL, TRUE));
 
141
 
 
142
        xmlNodePtr child;
 
143
        xmlChar *tmp;
 
144
        GPtrArray *query;
 
145
        gint limit_count = 0, limit_mb = 0, limit_time = 0;
 
146
        gchar *sort_key = NULL;
 
147
        gint sort_direction = 0;
 
148
 
 
149
        child = node->children;
 
150
        while (xmlNodeIsText (child))
 
151
                child = child->next;
 
152
 
 
153
        query = rhythmdb_query_deserialize (rb_playlist_source_get_db (RB_PLAYLIST_SOURCE (source)), 
 
154
                                            child);
 
155
 
 
156
        tmp = xmlGetProp (node, RB_PLAYLIST_LIMIT_COUNT);
 
157
        if (!tmp) /* Backwards compatibility */
 
158
                tmp = xmlGetProp (node, RB_PLAYLIST_LIMIT);
 
159
        if (tmp) {
 
160
                limit_count = atoi ((char*) tmp);
 
161
                g_free (tmp);
 
162
        }
 
163
        tmp = xmlGetProp (node, RB_PLAYLIST_LIMIT_SIZE);
 
164
        if (tmp) {
 
165
                limit_mb = atoi ((char*) tmp);
 
166
                g_free (tmp);
 
167
        }
 
168
        tmp = xmlGetProp (node, RB_PLAYLIST_LIMIT_TIME);
 
169
        if (tmp) {
 
170
                limit_time = atoi ((char*) tmp);
 
171
                g_free (tmp);
 
172
        }
 
173
 
 
174
        sort_key = (gchar*) xmlGetProp (node, RB_PLAYLIST_SORT_KEY);
 
175
        if (sort_key && *sort_key) {
 
176
                tmp = xmlGetProp (node, RB_PLAYLIST_SORT_DIRECTION);
 
177
                if (tmp) {
 
178
                        sort_direction = atoi ((char*) tmp);
 
179
                        g_free (tmp);
 
180
                }
 
181
        } else {
 
182
                g_free (sort_key);
 
183
                sort_key = NULL;
 
184
                sort_direction = 0;
 
185
        }
 
186
 
 
187
        rb_auto_playlist_source_set_query (source, query,
 
188
                                            limit_count,
 
189
                                            limit_mb,
 
190
                                            limit_time,
 
191
                                            sort_key,
 
192
                                            sort_direction);
 
193
        g_free (sort_key);
 
194
 
 
195
        return RB_SOURCE (source);
 
196
}
 
197
 
 
198
static GdkPixbuf *
 
199
impl_get_pixbuf (RBSource *asource)
 
200
{
 
201
        RBAutoPlaylistSourceClass *klass = RB_AUTO_PLAYLIST_SOURCE_GET_CLASS (asource);
 
202
        return klass->pixbuf;
 
203
}
 
204
 
 
205
static gboolean
 
206
impl_show_popup (RBSource *source)
 
207
{
 
208
        _rb_source_show_popup (source, AUTO_PLAYLIST_SOURCE_POPUP_PATH);
 
209
        return TRUE;
 
210
}
 
211
 
 
212
static void
 
213
impl_reset_filters (RBSource *source)
 
214
{
 
215
        RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
 
216
        gboolean changed = FALSE;
 
217
 
 
218
        if (priv->search_text != NULL) {
 
219
                changed = TRUE;
 
220
                g_free (priv->search_text);
 
221
                priv->search_text = NULL;
 
222
        }
 
223
 
 
224
        if (changed) {
 
225
                rb_auto_playlist_source_do_query (RB_AUTO_PLAYLIST_SOURCE (source));
 
226
                rb_source_notify_filter_changed (source);
 
227
        }
 
228
}
 
229
 
 
230
static void
 
231
impl_search (RBSource *source, const char *search_text)
 
232
{
 
233
        RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
 
234
 
 
235
        if (search_text == NULL && priv->search_text == NULL)
 
236
                return;
 
237
        if (search_text != NULL && priv->search_text != NULL &&
 
238
            !strcmp (search_text, priv->search_text))
 
239
                return;
 
240
 
 
241
        if (search_text[0] == '\0')
 
242
                search_text = NULL;
 
243
 
 
244
        rb_debug ("doing search for \"%s\"", search_text ? search_text : "(NULL)");
 
245
 
 
246
        g_free (priv->search_text);
 
247
        priv->search_text = g_strdup (search_text);
 
248
        rb_auto_playlist_source_do_query (RB_AUTO_PLAYLIST_SOURCE (source));
 
249
 
 
250
        rb_source_notify_filter_changed (source);
 
251
}
 
252
 
 
253
static RhythmDBPropType
 
254
rb_auto_playlist_source_drag_atom_to_prop (GdkAtom smasher)
 
255
{
 
256
        if (smasher == gdk_atom_intern ("text/x-rhythmbox-album", TRUE))
 
257
                return RHYTHMDB_PROP_ALBUM;
 
258
        else if (smasher == gdk_atom_intern ("text/x-rhythmbox-artist", TRUE))
 
259
                return RHYTHMDB_PROP_ARTIST;
 
260
        else if (smasher == gdk_atom_intern ("text/x-rhythmbox-genre", TRUE))
 
261
                return RHYTHMDB_PROP_GENRE;
 
262
        else {
 
263
                g_assert_not_reached ();
 
264
                return 0;
 
265
        }
 
266
}
 
267
 
 
268
static gboolean
 
269
impl_receive_drag (RBSource *asource, GtkSelectionData *data)
 
270
{
 
271
        RBAutoPlaylistSource *source = RB_AUTO_PLAYLIST_SOURCE (asource);
 
272
        
 
273
        GPtrArray *subquery = NULL;
 
274
        gchar **names;
 
275
        guint propid;
 
276
        int i;
 
277
        RhythmDB *db;
 
278
 
 
279
        /* ignore URI lists */
 
280
        if (data->type == gdk_atom_intern ("text/uri-list", TRUE))
 
281
                return TRUE;
 
282
 
 
283
        names = g_strsplit ((char *)data->data, "\r\n", 0);
 
284
        propid = rb_auto_playlist_source_drag_atom_to_prop (data->type);
 
285
        g_object_get (G_OBJECT (asource), "db", &db, NULL);
 
286
 
 
287
        for (i=0; names[i]; i++) {
 
288
                if (subquery == NULL) 
 
289
                        subquery = rhythmdb_query_parse (db,
 
290
                                                         RHYTHMDB_QUERY_PROP_EQUALS,
 
291
                                                         propid,
 
292
                                                         names[i],
 
293
                                                         RHYTHMDB_QUERY_END);
 
294
                else
 
295
                        rhythmdb_query_append (db,
 
296
                                               subquery,
 
297
                                               RHYTHMDB_QUERY_DISJUNCTION,
 
298
                                               RHYTHMDB_QUERY_PROP_EQUALS,
 
299
                                               propid,
 
300
                                               names[i],
 
301
                                               RHYTHMDB_QUERY_END);
 
302
        }
 
303
 
 
304
        g_strfreev (names);
 
305
 
 
306
        if (subquery) {
 
307
                RhythmDBEntryType qtype;
 
308
                GPtrArray *query;
 
309
                
 
310
                g_object_get (G_OBJECT (source), "entry-type", &qtype, NULL);
 
311
                if (qtype == -1)
 
312
                        qtype = RHYTHMDB_ENTRY_TYPE_SONG;
 
313
 
 
314
                query = rhythmdb_query_parse (db,
 
315
                                              RHYTHMDB_QUERY_PROP_EQUALS,
 
316
                                              RHYTHMDB_PROP_TYPE,
 
317
                                              qtype,
 
318
                                              RHYTHMDB_QUERY_SUBQUERY,
 
319
                                              subquery,
 
320
                                              RHYTHMDB_QUERY_END);
 
321
                rb_auto_playlist_source_set_query (RB_AUTO_PLAYLIST_SOURCE (source), query, 0, 0, 0, NULL, 0);
 
322
        }
 
323
 
 
324
        g_object_unref (G_OBJECT (db));
 
325
 
 
326
        return TRUE;
 
327
}
 
328
 
 
329
static void 
 
330
impl_save_contents_to_xml (RBPlaylistSource *psource, xmlNodePtr node)
 
331
{
 
332
        GPtrArray *query;
 
333
        guint max_count, max_size_mb, max_time;
 
334
        const gchar *sort_key;
 
335
        gint sort_direction;
 
336
        gchar *temp_str;
 
337
        RBAutoPlaylistSource *source = RB_AUTO_PLAYLIST_SOURCE (psource);
 
338
 
 
339
        xmlSetProp (node, RB_PLAYLIST_TYPE, RB_PLAYLIST_AUTOMATIC);
 
340
 
 
341
        rb_auto_playlist_source_get_query (source,
 
342
                                            &query,
 
343
                                            &max_count, &max_size_mb, &max_time,
 
344
                                            &sort_key, &sort_direction);
 
345
        temp_str = g_strdup_printf ("%d", max_count);
 
346
        xmlSetProp (node, RB_PLAYLIST_LIMIT_COUNT, BAD_CAST temp_str);
 
347
        g_free (temp_str);
 
348
        temp_str = g_strdup_printf ("%d", max_size_mb);
 
349
        xmlSetProp (node, RB_PLAYLIST_LIMIT_SIZE, BAD_CAST temp_str);
 
350
        g_free (temp_str);
 
351
        temp_str = g_strdup_printf ("%d", max_time);
 
352
        xmlSetProp (node, RB_PLAYLIST_LIMIT_TIME, BAD_CAST temp_str);
 
353
        g_free (temp_str);
 
354
 
 
355
        if (sort_key && *sort_key) {
 
356
                xmlSetProp (node, RB_PLAYLIST_SORT_KEY, BAD_CAST sort_key);
 
357
                temp_str = g_strdup_printf ("%d", sort_direction);
 
358
                xmlSetProp (node, RB_PLAYLIST_SORT_DIRECTION, BAD_CAST temp_str);
 
359
                g_free (temp_str);
 
360
        }
 
361
 
 
362
        rhythmdb_query_serialize (rb_playlist_source_get_db (psource), query, node);
 
363
}
 
364
 
 
365
static void
 
366
rb_auto_playlist_source_do_query (RBAutoPlaylistSource *source)
 
367
{
 
368
        RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
 
369
        RhythmDB *db = rb_playlist_source_get_db (RB_PLAYLIST_SOURCE (source));
 
370
        RhythmDBQueryModel *model;
 
371
 
 
372
        model = g_object_new (RHYTHMDB_TYPE_QUERY_MODEL,
 
373
                              "db", db,
 
374
                              "max-count", priv->limit_count,
 
375
                              "max-size", priv->limit_mb, 
 
376
                              "max-time", priv->limit_time, 
 
377
                              NULL);
 
378
 
 
379
        if (priv->search_text) {
 
380
                GPtrArray *query = rhythmdb_query_copy (priv->query);
 
381
 
 
382
                rhythmdb_query_append (db,
 
383
                                       query,
 
384
                                       RHYTHMDB_QUERY_PROP_LIKE,
 
385
                                       RHYTHMDB_PROP_SEARCH_MATCH,
 
386
                                       priv->search_text,
 
387
                                       RHYTHMDB_QUERY_END);
 
388
                rhythmdb_do_full_query_async_parsed (db, GTK_TREE_MODEL (model), query);
 
389
                rhythmdb_query_free (query);
 
390
        } else {
 
391
                rhythmdb_do_full_query_async_parsed (db, GTK_TREE_MODEL (model), priv->query);
 
392
        }
 
393
        rb_playlist_source_set_query_model (RB_PLAYLIST_SOURCE (source), model);
 
394
}
 
395
 
 
396
void
 
397
rb_auto_playlist_source_set_query (RBAutoPlaylistSource *source,
 
398
                                    GPtrArray *query,
 
399
                                    guint limit_count,
 
400
                                    guint limit_mb,
 
401
                                    guint limit_time,
 
402
                                    const char *sort_key,
 
403
                                    gint sort_direction)
 
404
{
 
405
        RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
 
406
        RBEntryView *songs = rb_source_get_entry_view (RB_SOURCE (source));
 
407
 
 
408
        priv->query_resetting = TRUE;
 
409
        if (priv->query)
 
410
                rhythmdb_query_free (priv->query);
 
411
 
 
412
        /* playlists that aren't limited, with a particular sort order, are user-orderable */
 
413
        rb_entry_view_set_columns_clickable (songs, (limit_count == 0 && limit_mb == 0));
 
414
        rb_entry_view_set_sorting_order (songs, sort_key, sort_direction);
 
415
 
 
416
        priv->query = query;
 
417
        priv->limit_count = limit_count;
 
418
        priv->limit_mb = limit_mb;
 
419
        priv->limit_time = limit_time;
 
420
        rb_auto_playlist_source_do_query (source);
 
421
 
 
422
        priv->query_resetting = FALSE;
 
423
}
 
424
 
 
425
void
 
426
rb_auto_playlist_source_get_query (RBAutoPlaylistSource *source,
 
427
                                    GPtrArray **query,
 
428
                                    guint *limit_count,
 
429
                                    guint *limit_mb,
 
430
                                    guint *limit_time,
 
431
                                    const char **sort_key,
 
432
                                    gint *sort_direction)
 
433
{
 
434
        RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
 
435
        RBEntryView *songs = rb_source_get_entry_view (RB_SOURCE (source));
 
436
 
 
437
        *query = priv->query;
 
438
        *limit_count = priv->limit_count;
 
439
        *limit_mb = priv->limit_mb;
 
440
        *limit_time = priv->limit_time;
 
441
 
 
442
        rb_entry_view_get_sorting_order (songs, sort_key, sort_direction);
 
443
}
 
444
 
 
445
static void
 
446
rb_auto_playlist_source_songs_sort_order_changed_cb (RBEntryView *view, RBAutoPlaylistSource *source)
 
447
{
 
448
        RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
 
449
 
 
450
        /* don't process this if we are in the middle of setting a query */
 
451
        if (priv->query_resetting)
 
452
                return;
 
453
        rb_debug ("sort order changed");
 
454
 
 
455
        rb_entry_view_resort_model (view);
 
456
}
 
457