hythmbox-2.98/podcast/rb-podcast-main-source.c

No issues found

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found rb-podcast-main-source.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
clang-analyzer no-output-found rb-podcast-main-source.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
  1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  2  *
  3  *  Copyright (C) 2010 Jonathan Matthew <jonathan@d14n.org>
  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 <glib.h>
 32 #include <glib/gi18n.h>
 33 
 34 #include "rb-podcast-settings.h"
 35 #include "rb-podcast-main-source.h"
 36 #include "rb-podcast-entry-types.h"
 37 #include "rb-shell.h"
 38 #include "rb-builder-helpers.h"
 39 #include "rb-file-helpers.h"
 40 #include "rb-util.h"
 41 #include "rb-stock-icons.h"
 42 
 43 struct _RBPodcastMainSourcePrivate
 44 {
 45 	GtkWidget *config_widget;
 46 };
 47 
 48 G_DEFINE_TYPE (RBPodcastMainSource, rb_podcast_main_source, RB_TYPE_PODCAST_SOURCE)
 49 
 50 
 51 RBSource *
 52 rb_podcast_main_source_new (RBShell *shell, RBPodcastManager *podcast_manager)
 53 {
 54 	RBSource *source;
 55 	RhythmDBQuery *base_query;
 56 	RhythmDB *db;
 57 	GSettings *settings;
 58 
 59 	g_object_get (shell, "db", &db, NULL);
 60 	base_query = rhythmdb_query_parse (db,
 61 					   RHYTHMDB_QUERY_PROP_EQUALS,
 62 					   RHYTHMDB_PROP_TYPE,
 63 					   RHYTHMDB_ENTRY_TYPE_PODCAST_POST,
 64 					   RHYTHMDB_QUERY_END);
 65 	g_object_unref (db);
 66 
 67 	settings = g_settings_new (PODCAST_SETTINGS_SCHEMA);
 68 
 69 	source = RB_SOURCE (g_object_new (RB_TYPE_PODCAST_MAIN_SOURCE,
 70 					  "name", _("Podcasts"),
 71 					  "shell", shell,
 72 					  "entry-type", RHYTHMDB_ENTRY_TYPE_PODCAST_POST,
 73 					  "podcast-manager", podcast_manager,
 74 					  "base-query", base_query,
 75 					  "settings", g_settings_get_child (settings, "source"),
 76 					  "toolbar-path", "/PodcastSourceToolBar",
 77 					  NULL));
 78 	g_object_unref (settings);
 79 
 80 	rhythmdb_query_free (base_query);
 81 
 82 	rb_shell_register_entry_type_for_source (shell, source,
 83 						 RHYTHMDB_ENTRY_TYPE_PODCAST_FEED);
 84 	rb_shell_register_entry_type_for_source (shell, source,
 85 						 RHYTHMDB_ENTRY_TYPE_PODCAST_POST);
 86 
 87 	return source;
 88 }
 89 
 90 void
 91 rb_podcast_main_source_add_subsources (RBPodcastMainSource *source)
 92 {
 93 	RhythmDBQuery *query;
 94 	RBSource *podcast_subsource;
 95 	RBPodcastManager *podcast_mgr;
 96 	RhythmDB *db;
 97 	RBShell *shell;
 98 
 99 	g_object_get (source,
100 		      "shell", &shell,
101 		      "podcast-manager", &podcast_mgr,
102 		      NULL);
103 	g_object_get (shell, "db", &db, NULL);
104 
105 	query = rhythmdb_query_parse (db,
106 				      RHYTHMDB_QUERY_PROP_EQUALS,
107 				      RHYTHMDB_PROP_TYPE,
108 				      RHYTHMDB_ENTRY_TYPE_PODCAST_POST,
109 				      RHYTHMDB_QUERY_PROP_CURRENT_TIME_WITHIN,
110 				      RHYTHMDB_PROP_FIRST_SEEN,
111 				      3600 * 24 * 7,
112 				      RHYTHMDB_QUERY_END);
113 
114 	podcast_subsource = rb_podcast_source_new (shell,
115 						   podcast_mgr,
116 						   query,
117 						   _("New Episodes"),
118 						   RB_STOCK_AUTO_PLAYLIST);
119 	rhythmdb_query_free (query);
120 	rb_source_set_hidden_when_empty (podcast_subsource, TRUE);
121 	rb_shell_append_display_page (shell, RB_DISPLAY_PAGE (podcast_subsource), RB_DISPLAY_PAGE (source));
122 
123 	query = rhythmdb_query_parse (db,
124 				      RHYTHMDB_QUERY_PROP_EQUALS,
125 				      RHYTHMDB_PROP_TYPE,
126 				      RHYTHMDB_ENTRY_TYPE_PODCAST_POST,
127 				      RHYTHMDB_QUERY_PROP_CURRENT_TIME_WITHIN,
128 				      RHYTHMDB_PROP_LAST_SEEN,
129 				      3600 * 24 * 7,
130 				      RHYTHMDB_QUERY_END);
131 
132 	podcast_subsource = rb_podcast_source_new (shell,
133 						   podcast_mgr,
134 						   query,
135 						   _("New Downloads"),		/* better name? */
136 						   RB_STOCK_AUTO_PLAYLIST);
137 	rhythmdb_query_free (query);
138 	rb_source_set_hidden_when_empty (podcast_subsource, TRUE);
139 	rb_shell_append_display_page (shell, RB_DISPLAY_PAGE (podcast_subsource), RB_DISPLAY_PAGE (source));
140 
141 	g_object_unref (db);
142 	g_object_unref (shell);
143 }
144 
145 static void
146 start_download_cb (RBPodcastManager *pd,
147 		   RhythmDBEntry *entry,
148 		   RBPodcastMainSource *source)
149 {
150 	RBShell *shell;
151 	char *podcast_name;
152 
153 	podcast_name = g_markup_escape_text (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE), -1);
154 
155 	g_object_get (source, "shell", &shell, NULL);
156 	rb_shell_notify_custom (shell, 4000, _("Downloading podcast"), podcast_name, NULL, FALSE);
157 	g_object_unref (shell);
158 
159 	g_free (podcast_name);
160 }
161 
162 static void
163 finish_download_cb (RBPodcastManager *pd,
164 		    RhythmDBEntry *entry,
165 		    RBPodcastMainSource *source)
166 {
167 	RBShell *shell;
168 	char *podcast_name;
169 
170 	podcast_name = g_markup_escape_text (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE), -1);
171 
172 	g_object_get (source, "shell", &shell, NULL);
173 	rb_shell_notify_custom (shell, 4000, _("Finished downloading podcast"), podcast_name, NULL, FALSE);
174 	g_object_unref (shell);
175 
176 	g_free (podcast_name);
177 }
178 
179 static void
180 feed_updates_available_cb (RBPodcastManager *pd,
181 			   RhythmDBEntry *entry,
182 			   RBPodcastMainSource *source)
183 {
184 	RBShell *shell;
185 	char *podcast_name;
186 
187 	podcast_name = g_markup_escape_text (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE), -1);
188 
189 	g_object_get (source, "shell", &shell, NULL);
190 	rb_shell_notify_custom (shell, 4000, _("New updates available from"), podcast_name, NULL, FALSE);
191 	g_object_unref (shell);
192 
193 	g_free (podcast_name);
194 
195 }
196 
197 static void
198 error_dialog_response_cb (GtkDialog *dialog, int response, RBPodcastMainSource *source)
199 {
200 	const char *url = g_object_get_data (G_OBJECT (dialog), "feed-url");
201 
202 	if (response == GTK_RESPONSE_YES) {
203 		RBPodcastManager *pd;
204 		g_object_get (source, "podcast-manager", &pd, NULL);
205 		rb_podcast_manager_insert_feed_url (pd, url);
206 		g_object_unref (pd);
207 	}
208 
209 	gtk_widget_destroy (GTK_WIDGET (dialog));
210 }
211 
212 static void
213 feed_error_cb (RBPodcastManager *pd,
214 	       const char *url,
215 	       const char *error,
216 	       gboolean existing,
217 	       RBPodcastMainSource *source)
218 {
219 	GtkWidget *dialog;
220 
221 	/* if the podcast feed doesn't already exist in the db,
222 	 * ask if the user wants to add it anyway; if it already
223 	 * exists, there's nothing to do besides reporting the error.
224 	 */
225 	dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (source))),
226 					 GTK_DIALOG_DESTROY_WITH_PARENT,
227 					 GTK_MESSAGE_ERROR,
228 					 existing ? GTK_BUTTONS_OK : GTK_BUTTONS_YES_NO,
229 					 _("Error in podcast"));
230 
231 	if (existing) {
232 		gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
233 							  "%s", error);
234 	} else {
235 		gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
236 							  _("%s. Would you like to add the podcast feed anyway?"), error);
237 	}
238 
239 	gtk_window_set_title (GTK_WINDOW (dialog), "");
240 	gtk_container_set_border_width (GTK_CONTAINER (dialog), 6);
241 
242 	g_object_set_data_full (G_OBJECT (dialog), "feed-url", g_strdup (url), g_free);
243 	g_signal_connect (dialog, "response", G_CALLBACK (error_dialog_response_cb), source);
244 
245 	gtk_widget_show_all (dialog);
246 }
247 
248 static void
249 rb_podcast_main_source_btn_file_change_cb (GtkFileChooserButton *widget, RBPodcastSource *source)
250 {
251 	GSettings *settings;
252 	char *uri;
253 
254 	settings = g_settings_new (PODCAST_SETTINGS_SCHEMA);
255 
256 	uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (widget));
257 	g_settings_set_string (settings, PODCAST_DOWNLOAD_DIR_KEY, uri);
258 	g_free (uri);
259 
260 	g_object_unref (settings);
261 }
262 
263 static GtkWidget *
264 impl_get_config_widget (RBDisplayPage *page, RBShellPreferences *prefs)
265 {
266 	RBPodcastMainSource *source = RB_PODCAST_MAIN_SOURCE (page);
267 	RBPodcastManager *podcast_mgr;
268 	GtkBuilder *builder;
269 	GtkWidget *update_interval;
270 	GtkWidget *btn_file;
271 	GSettings *settings;
272 	char *download_dir;
273 
274 	if (source->priv->config_widget)
275 		return source->priv->config_widget;
276 
277 	builder = rb_builder_load ("podcast-prefs.ui", source);
278 	source->priv->config_widget = GTK_WIDGET (gtk_builder_get_object (builder, "podcast_vbox"));
279 
280 	btn_file = GTK_WIDGET (gtk_builder_get_object (builder, "location_chooser"));
281 	gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (btn_file),
282 					      rb_music_dir (),
283 					      NULL);
284 
285 	g_object_get (source,
286 		      "podcast-manager", &podcast_mgr,
287 		      NULL);
288 	download_dir = rb_podcast_manager_get_podcast_dir (podcast_mgr);
289 
290 	gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (btn_file),
291 						 download_dir);
292 	g_object_unref (podcast_mgr);
293 	g_free (download_dir);
294 
295 	g_signal_connect_object (btn_file,
296 				 "selection-changed",
297 				 G_CALLBACK (rb_podcast_main_source_btn_file_change_cb),
298 				 source, 0);
299 
300 	update_interval = GTK_WIDGET (gtk_builder_get_object (builder, "update_interval"));
301 	g_object_set (update_interval, "id-column", 1, NULL);
302 
303 	settings = g_settings_new (PODCAST_SETTINGS_SCHEMA);
304 	g_settings_bind (settings, PODCAST_DOWNLOAD_INTERVAL,
305 			 update_interval, "active-id",
306 			 G_SETTINGS_BIND_DEFAULT);
307 	g_object_unref (settings);
308 
309 	return source->priv->config_widget;
310 }
311 
312 static guint
313 impl_want_uri (RBSource *source, const char *uri)
314 {
315 	if (g_str_has_prefix (uri, "http://") == FALSE)
316 		return 0;
317 
318 	if (g_str_has_suffix (uri, ".xml") ||
319 	    g_str_has_suffix (uri, ".rss"))
320 		return 100;
321 
322 	return 0;
323 }
324 
325 static void
326 impl_add_uri (RBSource *source,
327 	      const char *uri,
328 	      const char *title,
329 	      const char *genre,
330 	      RBSourceAddCallback callback,
331 	      gpointer data,
332 	      GDestroyNotify destroy_data)
333 {
334 	RBPodcastManager *podcast_mgr;
335 
336 	g_object_get (source, "podcast-manager", &podcast_mgr, NULL);
337 	rb_podcast_manager_subscribe_feed (podcast_mgr, uri, FALSE);
338 	g_object_unref (podcast_mgr);
339 
340 	if (callback != NULL) {
341 		callback (source, uri, data);
342 		if (destroy_data != NULL) {
343 			destroy_data (data);
344 		}
345 	}
346 }
347 
348 static void
349 impl_constructed (GObject *object)
350 {
351 	RBPodcastMainSource *source;
352 	RBPodcastManager *podcast_mgr;
353 	GdkPixbuf *pixbuf;
354 	gint size;
355 
356 	RB_CHAIN_GOBJECT_METHOD (rb_podcast_main_source_parent_class, constructed, object);
357 	source = RB_PODCAST_MAIN_SOURCE (object);
358 
359 	g_object_get (source, "podcast-manager", &podcast_mgr, NULL);
360 
361 	g_signal_connect_object (podcast_mgr,
362 			        "start_download",
363 				G_CALLBACK (start_download_cb),
364 				source, 0);
365 
366 	g_signal_connect_object (podcast_mgr,
367 				"finish_download",
368 				G_CALLBACK (finish_download_cb),
369 				source, 0);
370 
371 	g_signal_connect_object (podcast_mgr,
372 				"feed_updates_available",
373 				G_CALLBACK (feed_updates_available_cb),
374 				source, 0);
375 
376 	g_signal_connect_object (podcast_mgr,
377 				 "process_error",
378 				 G_CALLBACK (feed_error_cb),
379 				 source, 0);
380 
381 	gtk_icon_size_lookup (RB_SOURCE_ICON_SIZE, &size, NULL);
382 	pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
383 					   RB_STOCK_PODCAST,
384 					   size,
385 					   0, NULL);
386 
387 	if (pixbuf != NULL) {
388 		g_object_set (source, "pixbuf", pixbuf, NULL);
389 		g_object_unref (pixbuf);
390 	}
391 }
392 
393 static void
394 impl_dispose (GObject *object)
395 {
396 	RBPodcastMainSource *source;
397 
398 	source = RB_PODCAST_MAIN_SOURCE (object);
399 	if (source->priv->config_widget != NULL) {
400 		g_object_unref (source->priv->config_widget);
401 		source->priv->config_widget = NULL;
402 	}
403 
404 	G_OBJECT_CLASS (rb_podcast_main_source_parent_class)->dispose (object);
405 }
406 
407 static void
408 rb_podcast_main_source_init (RBPodcastMainSource *source)
409 {
410 	source->priv = G_TYPE_INSTANCE_GET_PRIVATE (source,
411 						    RB_TYPE_PODCAST_MAIN_SOURCE,
412 						    RBPodcastMainSourcePrivate);
413 }
414 
415 static void
416 rb_podcast_main_source_class_init (RBPodcastMainSourceClass *klass)
417 {
418 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
419 	RBDisplayPageClass *page_class = RB_DISPLAY_PAGE_CLASS (klass);
420 	RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
421 
422 	object_class->dispose = impl_dispose;
423 	object_class->constructed = impl_constructed;
424 
425 	page_class->get_config_widget = impl_get_config_widget;
426 
427 	source_class->impl_want_uri = impl_want_uri;
428 	source_class->impl_add_uri = impl_add_uri;
429 
430 	g_type_class_add_private (klass, sizeof (RBPodcastMainSourcePrivate));
431 }