1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3
* Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
4
* Copyright (C) 2003 Colin Walters <walters@gnome.org>
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.
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.
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.
24
#include <libgnome/gnome-i18n.h>
25
#include <libgnomevfs/gnome-vfs-uri.h>
26
#include <libxml/tree.h>
29
#include "rb-auto-playlist-source.h"
32
#include "rb-stock-icons.h"
33
#include "rb-playlist-xml.h"
35
static GObject *rb_auto_playlist_source_constructor (GType type, guint n_construct_properties,
36
GObjectConstructParam *construct_properties);
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);
44
/* playlist methods */
45
static void impl_save_contents_to_xml (RBPlaylistSource *source,
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);
52
#define AUTO_PLAYLIST_SOURCE_POPUP_PATH "/AutoPlaylistSourcePopup"
54
typedef struct _RBAutoPlaylistSourcePrivate RBAutoPlaylistSourcePrivate;
56
struct _RBAutoPlaylistSourcePrivate
59
gboolean query_resetting;
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))
70
rb_auto_playlist_source_class_init (RBAutoPlaylistSourceClass *klass)
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);
78
object_class->constructor = rb_auto_playlist_source_constructor;
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;
89
playlist_class->impl_save_contents_to_xml = impl_save_contents_to_xml;
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,
97
g_type_class_add_private (klass, sizeof (RBAutoPlaylistSourcePrivate));
101
rb_auto_playlist_source_init (RBAutoPlaylistSource *source)
106
rb_auto_playlist_source_constructor (GType type, guint n_construct_properties,
107
GObjectConstructParam *construct_properties)
110
RBAutoPlaylistSource *source;
111
GObjectClass *parent_class = G_OBJECT_CLASS (rb_auto_playlist_source_parent_class);
113
source = RB_AUTO_PLAYLIST_SOURCE (
114
parent_class->constructor (type, n_construct_properties, construct_properties));
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);
120
return G_OBJECT (source);
124
rb_auto_playlist_source_new (RBShell *shell, const char *name, gboolean local)
129
return RB_SOURCE (g_object_new (RB_TYPE_AUTO_PLAYLIST_SOURCE,
133
"entry-type", RHYTHMDB_ENTRY_TYPE_SONG,
138
rb_auto_playlist_source_new_from_xml (RBShell *shell, xmlNodePtr node)
140
RBAutoPlaylistSource *source = RB_AUTO_PLAYLIST_SOURCE (rb_auto_playlist_source_new (shell, NULL, TRUE));
145
gint limit_count = 0, limit_mb = 0, limit_time = 0;
146
gchar *sort_key = NULL;
147
gint sort_direction = 0;
149
child = node->children;
150
while (xmlNodeIsText (child))
153
query = rhythmdb_query_deserialize (rb_playlist_source_get_db (RB_PLAYLIST_SOURCE (source)),
156
tmp = xmlGetProp (node, RB_PLAYLIST_LIMIT_COUNT);
157
if (!tmp) /* Backwards compatibility */
158
tmp = xmlGetProp (node, RB_PLAYLIST_LIMIT);
160
limit_count = atoi ((char*) tmp);
163
tmp = xmlGetProp (node, RB_PLAYLIST_LIMIT_SIZE);
165
limit_mb = atoi ((char*) tmp);
168
tmp = xmlGetProp (node, RB_PLAYLIST_LIMIT_TIME);
170
limit_time = atoi ((char*) tmp);
174
sort_key = (gchar*) xmlGetProp (node, RB_PLAYLIST_SORT_KEY);
175
if (sort_key && *sort_key) {
176
tmp = xmlGetProp (node, RB_PLAYLIST_SORT_DIRECTION);
178
sort_direction = atoi ((char*) tmp);
187
rb_auto_playlist_source_set_query (source, query,
195
return RB_SOURCE (source);
199
impl_get_pixbuf (RBSource *asource)
201
RBAutoPlaylistSourceClass *klass = RB_AUTO_PLAYLIST_SOURCE_GET_CLASS (asource);
202
return klass->pixbuf;
206
impl_show_popup (RBSource *source)
208
_rb_source_show_popup (source, AUTO_PLAYLIST_SOURCE_POPUP_PATH);
213
impl_reset_filters (RBSource *source)
215
RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
216
gboolean changed = FALSE;
218
if (priv->search_text != NULL) {
220
g_free (priv->search_text);
221
priv->search_text = NULL;
225
rb_auto_playlist_source_do_query (RB_AUTO_PLAYLIST_SOURCE (source));
226
rb_source_notify_filter_changed (source);
231
impl_search (RBSource *source, const char *search_text)
233
RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
235
if (search_text == NULL && priv->search_text == NULL)
237
if (search_text != NULL && priv->search_text != NULL &&
238
!strcmp (search_text, priv->search_text))
241
if (search_text[0] == '\0')
244
rb_debug ("doing search for \"%s\"", search_text ? search_text : "(NULL)");
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));
250
rb_source_notify_filter_changed (source);
253
static RhythmDBPropType
254
rb_auto_playlist_source_drag_atom_to_prop (GdkAtom smasher)
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;
263
g_assert_not_reached ();
269
impl_receive_drag (RBSource *asource, GtkSelectionData *data)
271
RBAutoPlaylistSource *source = RB_AUTO_PLAYLIST_SOURCE (asource);
273
GPtrArray *subquery = NULL;
279
/* ignore URI lists */
280
if (data->type == gdk_atom_intern ("text/uri-list", TRUE))
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);
287
for (i=0; names[i]; i++) {
288
if (subquery == NULL)
289
subquery = rhythmdb_query_parse (db,
290
RHYTHMDB_QUERY_PROP_EQUALS,
295
rhythmdb_query_append (db,
297
RHYTHMDB_QUERY_DISJUNCTION,
298
RHYTHMDB_QUERY_PROP_EQUALS,
307
RhythmDBEntryType qtype;
310
g_object_get (G_OBJECT (source), "entry-type", &qtype, NULL);
312
qtype = RHYTHMDB_ENTRY_TYPE_SONG;
314
query = rhythmdb_query_parse (db,
315
RHYTHMDB_QUERY_PROP_EQUALS,
318
RHYTHMDB_QUERY_SUBQUERY,
321
rb_auto_playlist_source_set_query (RB_AUTO_PLAYLIST_SOURCE (source), query, 0, 0, 0, NULL, 0);
324
g_object_unref (G_OBJECT (db));
330
impl_save_contents_to_xml (RBPlaylistSource *psource, xmlNodePtr node)
333
guint max_count, max_size_mb, max_time;
334
const gchar *sort_key;
337
RBAutoPlaylistSource *source = RB_AUTO_PLAYLIST_SOURCE (psource);
339
xmlSetProp (node, RB_PLAYLIST_TYPE, RB_PLAYLIST_AUTOMATIC);
341
rb_auto_playlist_source_get_query (source,
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);
348
temp_str = g_strdup_printf ("%d", max_size_mb);
349
xmlSetProp (node, RB_PLAYLIST_LIMIT_SIZE, BAD_CAST temp_str);
351
temp_str = g_strdup_printf ("%d", max_time);
352
xmlSetProp (node, RB_PLAYLIST_LIMIT_TIME, BAD_CAST temp_str);
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);
362
rhythmdb_query_serialize (rb_playlist_source_get_db (psource), query, node);
366
rb_auto_playlist_source_do_query (RBAutoPlaylistSource *source)
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;
372
model = g_object_new (RHYTHMDB_TYPE_QUERY_MODEL,
374
"max-count", priv->limit_count,
375
"max-size", priv->limit_mb,
376
"max-time", priv->limit_time,
379
if (priv->search_text) {
380
GPtrArray *query = rhythmdb_query_copy (priv->query);
382
rhythmdb_query_append (db,
384
RHYTHMDB_QUERY_PROP_LIKE,
385
RHYTHMDB_PROP_SEARCH_MATCH,
388
rhythmdb_do_full_query_async_parsed (db, GTK_TREE_MODEL (model), query);
389
rhythmdb_query_free (query);
391
rhythmdb_do_full_query_async_parsed (db, GTK_TREE_MODEL (model), priv->query);
393
rb_playlist_source_set_query_model (RB_PLAYLIST_SOURCE (source), model);
397
rb_auto_playlist_source_set_query (RBAutoPlaylistSource *source,
402
const char *sort_key,
405
RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
406
RBEntryView *songs = rb_source_get_entry_view (RB_SOURCE (source));
408
priv->query_resetting = TRUE;
410
rhythmdb_query_free (priv->query);
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);
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);
422
priv->query_resetting = FALSE;
426
rb_auto_playlist_source_get_query (RBAutoPlaylistSource *source,
431
const char **sort_key,
432
gint *sort_direction)
434
RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
435
RBEntryView *songs = rb_source_get_entry_view (RB_SOURCE (source));
437
*query = priv->query;
438
*limit_count = priv->limit_count;
439
*limit_mb = priv->limit_mb;
440
*limit_time = priv->limit_time;
442
rb_entry_view_get_sorting_order (songs, sort_key, sort_direction);
446
rb_auto_playlist_source_songs_sort_order_changed_cb (RBEntryView *view, RBAutoPlaylistSource *source)
448
RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
450
/* don't process this if we are in the middle of setting a query */
451
if (priv->query_resetting)
453
rb_debug ("sort order changed");
455
rb_entry_view_resort_model (view);