2006-05-13 James Livingston <doclivingston@gmail.com>
[rhythmbox.git] / sources / rb-missing-files-source.c
blob3e1848c3411d771180a7bdac7605c16eb2546715
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * Copyright (C) 2006 Jonathan Matthew <jonathan@kaolin.wh9.net>
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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22 * This source lists files rhythmbox cannot find, and maybe tries to stop
23 * you from trying to play them.
26 #include <config.h>
27 #include <gtk/gtk.h>
28 #include <glib/gi18n.h>
30 #include "rb-entry-view.h"
31 #include "rb-missing-files-source.h"
32 #include "rb-song-info.h"
33 #include "rb-util.h"
34 #include "rb-debug.h"
37 static void rb_missing_files_source_class_init (RBMissingFilesSourceClass *klass);
38 static void rb_missing_files_source_init (RBMissingFilesSource *source);
39 static GObject *rb_missing_files_source_constructor (GType type, guint n_construct_properties,
40 GObjectConstructParam *construct_properties);
41 static void rb_missing_files_source_dispose (GObject *object);
42 static void rb_missing_files_source_set_property (GObject *object,
43 guint prop_id,
44 const GValue *value,
45 GParamSpec *pspec);
46 static void rb_missing_files_source_get_property (GObject *object,
47 guint prop_id,
48 GValue *value,
49 GParamSpec *pspec);
51 static RBEntryView *impl_get_entry_view (RBSource *source);
52 static void impl_song_properties (RBSource *source);
53 static void impl_delete (RBSource *source);
54 static void impl_get_status (RBSource *source, char **text, char **progress_text, float *progress);
56 static void rb_missing_files_source_songs_show_popup_cb (RBEntryView *view,
57 gboolean over_entry,
58 RBMissingFilesSource *source);
59 static void rb_missing_files_source_songs_sort_order_changed_cb (RBEntryView *view,
60 RBMissingFilesSource *source);
62 #define MISSING_FILES_SOURCE_SONGS_POPUP_PATH "/MissingFilesViewPopup"
64 struct RBMissingFilesSourcePrivate
66 RhythmDB *db;
67 RhythmDBQueryModel *model;
68 RBEntryView *view;
69 RhythmDBEntryType entry_type;
72 enum
74 PROP_0,
75 PROP_ENTRY_TYPE
78 G_DEFINE_TYPE (RBMissingFilesSource, rb_missing_files_source, RB_TYPE_SOURCE);
80 static void
81 rb_missing_files_source_class_init (RBMissingFilesSourceClass *klass)
83 GObjectClass *object_class = G_OBJECT_CLASS (klass);
84 RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
86 object_class->dispose = rb_missing_files_source_dispose;
87 object_class->constructor = rb_missing_files_source_constructor;
89 object_class->set_property = rb_missing_files_source_set_property;
90 object_class->get_property = rb_missing_files_source_get_property;
92 source_class->impl_can_browse = (RBSourceFeatureFunc) rb_false_function;
93 source_class->impl_get_entry_view = impl_get_entry_view;
94 source_class->impl_can_rename = (RBSourceFeatureFunc) rb_false_function;
95 source_class->impl_can_search = (RBSourceFeatureFunc) rb_false_function;
97 source_class->impl_can_cut = (RBSourceFeatureFunc) rb_false_function;
98 source_class->impl_can_delete = (RBSourceFeatureFunc) rb_true_function;
99 source_class->impl_can_move_to_trash = (RBSourceFeatureFunc) rb_false_function;
100 source_class->impl_can_copy = (RBSourceFeatureFunc) rb_false_function;
101 source_class->impl_can_add_to_queue = (RBSourceFeatureFunc) rb_false_function;
103 source_class->impl_delete = impl_delete;
105 source_class->impl_song_properties = impl_song_properties;
106 source_class->impl_try_playlist = (RBSourceFeatureFunc) rb_false_function;
107 source_class->impl_can_pause = (RBSourceFeatureFunc) rb_false_function;
109 source_class->impl_have_url = (RBSourceFeatureFunc) rb_false_function;
110 source_class->impl_get_status = impl_get_status;
113 g_object_class_install_property (object_class,
114 PROP_ENTRY_TYPE,
115 g_param_spec_pointer ("entry-type",
116 "Entry type",
117 "Type of the entries which should be displayed by this source",
118 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
120 g_type_class_add_private (klass, sizeof (RBMissingFilesSourcePrivate));
123 static void
124 rb_missing_files_source_init (RBMissingFilesSource *source)
126 gint size;
127 GdkPixbuf *pixbuf;
129 source->priv = G_TYPE_INSTANCE_GET_PRIVATE (source, RB_TYPE_MISSING_FILES_SOURCE, RBMissingFilesSourcePrivate);
131 gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR, &size, NULL);
132 pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
133 GTK_STOCK_MISSING_IMAGE,
134 size,
135 0, NULL);
136 rb_source_set_pixbuf (RB_SOURCE (source), pixbuf);
137 if (pixbuf != NULL) {
138 g_object_unref (pixbuf);
141 source->priv->entry_type = RHYTHMDB_ENTRY_TYPE_SONG;
144 static GObject *
145 rb_missing_files_source_constructor (GType type, guint n_construct_properties,
146 GObjectConstructParam *construct_properties)
148 GObject *shell_player;
149 RBMissingFilesSource *source;
150 RBMissingFilesSourceClass *klass;
151 RBShell *shell;
152 GPtrArray *query;
154 klass = RB_MISSING_FILES_SOURCE_CLASS (g_type_class_peek (RB_TYPE_MISSING_FILES_SOURCE));
156 source = RB_MISSING_FILES_SOURCE (G_OBJECT_CLASS (rb_missing_files_source_parent_class)->
157 constructor (type, n_construct_properties, construct_properties));
159 g_object_get (G_OBJECT (source), "shell", &shell, NULL);
160 g_object_get (G_OBJECT (shell), "db", &source->priv->db, NULL);
161 shell_player = rb_shell_get_player (shell);
162 g_object_unref (G_OBJECT (shell));
164 /* construct real query */
165 query = rhythmdb_query_parse (source->priv->db,
166 RHYTHMDB_QUERY_PROP_EQUALS,
167 RHYTHMDB_PROP_TYPE,
168 source->priv->entry_type,
169 RHYTHMDB_QUERY_PROP_EQUALS,
170 RHYTHMDB_PROP_HIDDEN,
171 TRUE,
172 RHYTHMDB_QUERY_END);
173 source->priv->model = rhythmdb_query_model_new (source->priv->db, query,
174 NULL, NULL, NULL, FALSE);
175 g_ptr_array_free (query, TRUE);
177 g_object_set (G_OBJECT (source->priv->model), "show-hidden", TRUE, NULL);
178 _rb_source_hide_when_empty (RB_SOURCE (source), source->priv->model);
180 /* set up entry view */
181 source->priv->view = rb_entry_view_new (source->priv->db, shell_player,
182 NULL, FALSE, FALSE);
184 rb_entry_view_set_model (source->priv->view, source->priv->model);
186 rb_entry_view_append_column (source->priv->view, RB_ENTRY_VIEW_COL_TRACK_NUMBER, FALSE);
187 rb_entry_view_append_column (source->priv->view, RB_ENTRY_VIEW_COL_TITLE, TRUE);
188 /* rb_entry_view_append_column (source->priv->view, RB_ENTRY_VIEW_COL_GENRE, FALSE); */
189 rb_entry_view_append_column (source->priv->view, RB_ENTRY_VIEW_COL_ARTIST, FALSE);
190 rb_entry_view_append_column (source->priv->view, RB_ENTRY_VIEW_COL_ALBUM, FALSE);
191 rb_entry_view_append_column (source->priv->view, RB_ENTRY_VIEW_COL_LOCATION, TRUE);
192 rb_entry_view_append_column (source->priv->view, RB_ENTRY_VIEW_COL_LAST_SEEN, TRUE);
194 rb_entry_view_set_columns_clickable (source->priv->view, TRUE);
196 gtk_container_add (GTK_CONTAINER (source), GTK_WIDGET (source->priv->view));
197 g_signal_connect_object (G_OBJECT (source->priv->view), "show_popup",
198 G_CALLBACK (rb_missing_files_source_songs_show_popup_cb), source, 0);
199 g_signal_connect_object (G_OBJECT (source->priv->view), "sort-order-changed",
200 G_CALLBACK (rb_missing_files_source_songs_sort_order_changed_cb), source, 0);
202 gtk_widget_show_all (GTK_WIDGET (source));
204 /* use a fake model for the source's query model property, so we can't try to play
205 * any of the hidden entries.
207 g_object_set (G_OBJECT (source),
208 "query-model", rhythmdb_query_model_new_empty (source->priv->db),
209 NULL);
211 return G_OBJECT (source);
214 static void
215 rb_missing_files_source_dispose (GObject *object)
217 RBMissingFilesSource *source = RB_MISSING_FILES_SOURCE (object);
219 if (source->priv->db) {
220 g_object_unref (G_OBJECT (source->priv->db));
221 source->priv->db = NULL;
223 if (source->priv->model) {
224 g_object_unref (G_OBJECT (source->priv->model));
225 source->priv->model = NULL;
228 G_OBJECT_CLASS (rb_missing_files_source_parent_class)->dispose (object);
232 static RBEntryView *
233 impl_get_entry_view (RBSource *asource)
235 RBMissingFilesSource *source = RB_MISSING_FILES_SOURCE (asource);
236 return source->priv->view;
239 static void
240 rb_missing_files_source_set_property (GObject *object,
241 guint prop_id,
242 const GValue *value,
243 GParamSpec *pspec)
245 RBMissingFilesSource *source = RB_MISSING_FILES_SOURCE (object);
247 switch (prop_id)
249 case PROP_ENTRY_TYPE:
250 source->priv->entry_type = g_value_get_pointer (value);
251 break;
252 default:
253 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
254 break;
258 static void
259 rb_missing_files_source_get_property (GObject *object,
260 guint prop_id,
261 GValue *value,
262 GParamSpec *pspec)
264 RBMissingFilesSource *source = RB_MISSING_FILES_SOURCE (object);
266 switch (prop_id)
268 case PROP_ENTRY_TYPE:
269 g_value_set_pointer (value, source->priv->entry_type);
270 break;
271 default:
272 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
273 break;
277 RBSource *
278 rb_missing_files_source_new (RBShell *shell,
279 RBLibrarySource *library)
281 RBSource *source;
282 RhythmDBEntryType entry_type;
284 g_object_get (G_OBJECT (library), "entry-type", &entry_type, NULL);
285 source = RB_SOURCE (g_object_new (RB_TYPE_MISSING_FILES_SOURCE,
286 "name", _("Missing Files"),
287 "entry-type", entry_type,
288 "shell", shell,
289 "visibility", FALSE,
290 NULL));
291 return source;
294 static void
295 rb_missing_files_source_songs_show_popup_cb (RBEntryView *view,
296 gboolean over_entry,
297 RBMissingFilesSource *source)
299 if (over_entry)
300 _rb_source_show_popup (RB_SOURCE (source), MISSING_FILES_SOURCE_SONGS_POPUP_PATH);
303 static void
304 impl_song_properties (RBSource *asource)
306 RBMissingFilesSource *source = RB_MISSING_FILES_SOURCE (asource);
307 GtkWidget *song_info = NULL;
309 g_return_if_fail (source->priv->view != NULL);
311 song_info = rb_song_info_new (asource, NULL);
312 if (song_info)
313 gtk_widget_show_all (song_info);
314 else
315 rb_debug ("failed to create dialog, or no selection!");
318 static void
319 impl_delete (RBSource *asource)
321 RBMissingFilesSource *source = RB_MISSING_FILES_SOURCE (asource);
322 GList *sel, *tem;
324 sel = rb_entry_view_get_selected_entries (source->priv->view);
325 for (tem = sel; tem != NULL; tem = tem->next) {
326 rhythmdb_entry_delete (source->priv->db, tem->data);
327 rhythmdb_commit (source->priv->db);
329 g_list_free (sel);
332 static void
333 rb_missing_files_source_songs_sort_order_changed_cb (RBEntryView *view,
334 RBMissingFilesSource *source)
336 rb_entry_view_resort_model (view);
339 static void
340 impl_get_status (RBSource *asource, char **text, char **progress_text, float *progress)
342 RBMissingFilesSource *source = RB_MISSING_FILES_SOURCE (asource);
343 gint count;
345 count = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (source->priv->model), NULL);
346 *text = g_strdup_printf (ngettext ("%d missing file", "%d missing files", count),
347 count);