No issues found
Tool | Failure ID | Location | Function | Message | Data |
---|---|---|---|---|---|
clang-analyzer | no-output-found | rb-missing-files-source.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None | |
clang-analyzer | no-output-found | rb-missing-files-source.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None |
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>
4 *
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.
9 *
10 * The Rhythmbox authors hereby grant permission for non-GPL compatible
11 * GStreamer plugins to be used and distributed together with GStreamer
12 * and Rhythmbox. This permission is above and beyond the permissions granted
13 * by the GPL license by which Rhythmbox is covered. If you modify this code
14 * you may extend this exception to your version of the code, but you are not
15 * obligated to do so. If you do not wish to do so, delete this exception
16 * statement from your version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26 *
27 */
28
29 #include "config.h"
30
31 #include <gtk/gtk.h>
32 #include <glib/gi18n.h>
33
34 #include "rb-entry-view.h"
35 #include "rb-missing-files-source.h"
36 #include "rb-song-info.h"
37 #include "rb-util.h"
38 #include "rb-debug.h"
39
40 /**
41 * SECTION:rb-missing-files-source
42 * @short_description: source displaying files missing from the library
43 *
44 * This source displays files that rhythmbox cannot find at the expected
45 * locations. On startup, it does a file access check for every file
46 * in the library, hiding those that fail. This source sets up a
47 * query model that matches only hidden entries. It displays the file
48 * location and the last time the file was successfully accessed.
49 *
50 * The source only displayed in the source list when there are hidden
51 * entries to show.
52 */
53
54 static void rb_missing_files_source_class_init (RBMissingFilesSourceClass *klass);
55 static void rb_missing_files_source_init (RBMissingFilesSource *source);
56 static void rb_missing_files_source_constructed (GObject *object);
57 static void rb_missing_files_source_dispose (GObject *object);
58 static void rb_missing_files_source_set_property (GObject *object,
59 guint prop_id,
60 const GValue *value,
61 GParamSpec *pspec);
62 static void rb_missing_files_source_get_property (GObject *object,
63 guint prop_id,
64 GValue *value,
65 GParamSpec *pspec);
66
67 static RBEntryView *impl_get_entry_view (RBSource *source);
68 static void impl_song_properties (RBSource *source);
69 static void impl_delete (RBSource *source);
70 static void impl_get_status (RBDisplayPage *page, char **text, char **progress_text, float *progress);
71
72 static void rb_missing_files_source_songs_show_popup_cb (RBEntryView *view,
73 gboolean over_entry,
74 RBMissingFilesSource *source);
75 static void rb_missing_files_source_songs_sort_order_changed_cb (GObject *object,
76 GParamSpec *pspec,
77 RBMissingFilesSource *source);
78
79 #define MISSING_FILES_SOURCE_SONGS_POPUP_PATH "/MissingFilesViewPopup"
80
81 struct RBMissingFilesSourcePrivate
82 {
83 RhythmDB *db;
84 RBEntryView *view;
85 };
86
87 G_DEFINE_TYPE (RBMissingFilesSource, rb_missing_files_source, RB_TYPE_SOURCE);
88
89 static void
90 rb_missing_files_source_class_init (RBMissingFilesSourceClass *klass)
91 {
92 GObjectClass *object_class = G_OBJECT_CLASS (klass);
93 RBDisplayPageClass *page_class = RB_DISPLAY_PAGE_CLASS (klass);
94 RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
95
96 object_class->dispose = rb_missing_files_source_dispose;
97 object_class->constructed = rb_missing_files_source_constructed;
98
99 object_class->set_property = rb_missing_files_source_set_property;
100 object_class->get_property = rb_missing_files_source_get_property;
101
102 page_class->get_status = impl_get_status;
103
104 source_class->impl_get_entry_view = impl_get_entry_view;
105 source_class->impl_can_rename = (RBSourceFeatureFunc) rb_false_function;
106
107 source_class->impl_can_cut = (RBSourceFeatureFunc) rb_false_function;
108 source_class->impl_can_delete = (RBSourceFeatureFunc) rb_true_function;
109 source_class->impl_can_move_to_trash = (RBSourceFeatureFunc) rb_false_function;
110 source_class->impl_can_copy = (RBSourceFeatureFunc) rb_false_function;
111 source_class->impl_can_add_to_queue = (RBSourceFeatureFunc) rb_false_function;
112
113 source_class->impl_delete = impl_delete;
114
115 source_class->impl_song_properties = impl_song_properties;
116 source_class->impl_try_playlist = (RBSourceFeatureFunc) rb_false_function;
117 source_class->impl_can_pause = (RBSourceFeatureFunc) rb_false_function;
118
119 g_type_class_add_private (klass, sizeof (RBMissingFilesSourcePrivate));
120 }
121
122 static void
123 rb_missing_files_source_init (RBMissingFilesSource *source)
124 {
125 gint size;
126 GdkPixbuf *pixbuf;
127
128 source->priv = G_TYPE_INSTANCE_GET_PRIVATE (source, RB_TYPE_MISSING_FILES_SOURCE, RBMissingFilesSourcePrivate);
129
130 gtk_icon_size_lookup (RB_SOURCE_ICON_SIZE, &size, NULL);
131 pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
132 "dialog-warning",
133 size,
134 0, NULL);
135 g_object_set (source, "pixbuf", pixbuf, NULL);
136 if (pixbuf != NULL) {
137 g_object_unref (pixbuf);
138 }
139 }
140
141 static void
142 rb_missing_files_source_constructed (GObject *object)
143 {
144 GObject *shell_player;
145 RBMissingFilesSource *source;
146 RBShell *shell;
147 GPtrArray *query;
148 RhythmDBQueryModel *model;
149 RhythmDBEntryType *entry_type;
150
151 RB_CHAIN_GOBJECT_METHOD (rb_missing_files_source_parent_class, constructed, object);
152 source = RB_MISSING_FILES_SOURCE (object);
153
154 g_object_get (source,
155 "shell", &shell,
156 "entry-type", &entry_type,
157 NULL);
158 g_object_get (shell,
159 "db", &source->priv->db,
160 "shell-player", &shell_player,
161 NULL);
162 g_object_unref (shell);
163
164 /* construct real query */
165 query = rhythmdb_query_parse (source->priv->db,
166 RHYTHMDB_QUERY_PROP_EQUALS,
167 RHYTHMDB_PROP_TYPE,
168 entry_type,
169 RHYTHMDB_QUERY_PROP_EQUALS,
170 RHYTHMDB_PROP_HIDDEN,
171 TRUE,
172 RHYTHMDB_QUERY_END);
173 g_object_unref (entry_type);
174
175 model = rhythmdb_query_model_new (source->priv->db, query,
176 NULL, NULL, NULL, FALSE);
177
178 rhythmdb_query_free (query);
179
180 g_object_set (model, "show-hidden", TRUE, NULL);
181
182 /* set up entry view */
183 source->priv->view = rb_entry_view_new (source->priv->db, shell_player,
184 FALSE, FALSE);
185 g_object_unref (shell_player);
186
187 rb_entry_view_set_model (source->priv->view, model);
188
189 rb_entry_view_append_column (source->priv->view, RB_ENTRY_VIEW_COL_TRACK_NUMBER, FALSE);
190 rb_entry_view_append_column (source->priv->view, RB_ENTRY_VIEW_COL_TITLE, TRUE);
191 /* rb_entry_view_append_column (source->priv->view, RB_ENTRY_VIEW_COL_GENRE, FALSE); */
192 rb_entry_view_append_column (source->priv->view, RB_ENTRY_VIEW_COL_ARTIST, FALSE);
193 rb_entry_view_append_column (source->priv->view, RB_ENTRY_VIEW_COL_ALBUM, FALSE);
194 rb_entry_view_append_column (source->priv->view, RB_ENTRY_VIEW_COL_LOCATION, TRUE);
195 rb_entry_view_append_column (source->priv->view, RB_ENTRY_VIEW_COL_LAST_SEEN, TRUE);
196
197 rb_entry_view_set_columns_clickable (source->priv->view, TRUE);
198
199 gtk_container_add (GTK_CONTAINER (source), GTK_WIDGET (source->priv->view));
200 g_signal_connect_object (source->priv->view, "show_popup",
201 G_CALLBACK (rb_missing_files_source_songs_show_popup_cb), source, 0);
202 g_signal_connect_object (source->priv->view, "notify::sort-order",
203 G_CALLBACK (rb_missing_files_source_songs_sort_order_changed_cb), source, 0);
204
205 gtk_widget_show_all (GTK_WIDGET (source));
206
207 g_object_set (source, "query-model", model, NULL);
208 g_object_unref (model);
209 }
210
211 static void
212 rb_missing_files_source_dispose (GObject *object)
213 {
214 RBMissingFilesSource *source = RB_MISSING_FILES_SOURCE (object);
215
216 if (source->priv->db != NULL) {
217 g_object_unref (source->priv->db);
218 source->priv->db = NULL;
219 }
220
221 G_OBJECT_CLASS (rb_missing_files_source_parent_class)->dispose (object);
222 }
223
224 static RBEntryView *
225 impl_get_entry_view (RBSource *asource)
226 {
227 RBMissingFilesSource *source = RB_MISSING_FILES_SOURCE (asource);
228 return source->priv->view;
229 }
230
231 static void
232 rb_missing_files_source_set_property (GObject *object,
233 guint prop_id,
234 const GValue *value,
235 GParamSpec *pspec)
236 {
237 /*RBMissingFilesSource *source = RB_MISSING_FILES_SOURCE (object);*/
238
239 switch (prop_id)
240 {
241 default:
242 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
243 break;
244 }
245 }
246
247 static void
248 rb_missing_files_source_get_property (GObject *object,
249 guint prop_id,
250 GValue *value,
251 GParamSpec *pspec)
252 {
253 /*RBMissingFilesSource *source = RB_MISSING_FILES_SOURCE (object);*/
254
255 switch (prop_id)
256 {
257 default:
258 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
259 break;
260 }
261 }
262
263 /**
264 * rb_missing_files_source_new:
265 * @shell: the #RBShell instance
266 * @library: the #RBLibrarySource instance
267 *
268 * Creates the missing files source. It extracts the
269 * entry type from the library source instance, so it
270 * currently only works for files in the library, but
271 * it would be trivial to make it use any source type
272 * that did file access checks for its contents.
273 *
274 * Return value: the #RBMissingFilesSource
275 */
276 RBSource *
277 rb_missing_files_source_new (RBShell *shell,
278 RBLibrarySource *library)
279 {
280 RBSource *source;
281 RhythmDBEntryType *entry_type;
282
283 g_object_get (library, "entry-type", &entry_type, NULL);
284 source = RB_SOURCE (g_object_new (RB_TYPE_MISSING_FILES_SOURCE,
285 "name", _("Missing Files"),
286 "entry-type", entry_type,
287 "shell", shell,
288 "visibility", FALSE,
289 "hidden-when-empty", TRUE,
290 NULL));
291 g_object_unref (entry_type);
292 return source;
293 }
294
295 static void
296 rb_missing_files_source_songs_show_popup_cb (RBEntryView *view,
297 gboolean over_entry,
298 RBMissingFilesSource *source)
299 {
300 if (over_entry)
301 _rb_display_page_show_popup (RB_DISPLAY_PAGE (source), MISSING_FILES_SOURCE_SONGS_POPUP_PATH);
302 }
303
304 static void
305 impl_song_properties (RBSource *asource)
306 {
307 RBMissingFilesSource *source = RB_MISSING_FILES_SOURCE (asource);
308 GtkWidget *song_info = NULL;
309
310 g_return_if_fail (source->priv->view != NULL);
311
312 song_info = rb_song_info_new (asource, NULL);
313 if (song_info)
314 gtk_widget_show_all (song_info);
315 else
316 rb_debug ("failed to create dialog, or no selection!");
317 }
318
319 static void
320 impl_delete (RBSource *asource)
321 {
322 RBMissingFilesSource *source = RB_MISSING_FILES_SOURCE (asource);
323 GList *sel, *tem;
324
325 sel = rb_entry_view_get_selected_entries (source->priv->view);
326 for (tem = sel; tem != NULL; tem = tem->next) {
327 rhythmdb_entry_delete (source->priv->db, tem->data);
328 rhythmdb_commit (source->priv->db);
329 }
330
331 g_list_foreach (sel, (GFunc)rhythmdb_entry_unref, NULL);
332 g_list_free (sel);
333 }
334
335 static void
336 rb_missing_files_source_songs_sort_order_changed_cb (GObject *object,
337 GParamSpec *pspec,
338 RBMissingFilesSource *source)
339 {
340 rb_entry_view_resort_model (RB_ENTRY_VIEW (object));
341 }
342
343 static void
344 impl_get_status (RBDisplayPage *page, char **text, char **progress_text, float *progress)
345 {
346 RhythmDBQueryModel *model;
347 gint count;
348
349 g_object_get (page, "query-model", &model, NULL);
350 count = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (model), NULL);
351 g_object_unref (model);
352
353 *text = g_strdup_printf (ngettext ("%d missing file", "%d missing files", count),
354 count);
355 }