hythmbox-2.98/sources/sync/rb-sync-settings-ui.c

No issues found

  1 /*
  2  *  Copyright (C) 2009 Paul Bellamy  <paul.a.bellamy@gmail.com>
  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/gi18n.h>
 32 
 33 #include "rb-sync-settings-ui.h"
 34 #include "rb-debug.h"
 35 #include "rb-util.h"
 36 #include "rb-playlist-manager.h"
 37 #include "rb-podcast-entry-types.h"
 38 
 39 struct _RBSyncSettingsUIPrivate
 40 {
 41 	RBMediaPlayerSource *source;
 42 	RBSyncSettings *sync_settings;
 43 
 44 	GtkTreeStore *sync_tree_store;
 45 };
 46 
 47 enum {
 48 	PROP_0,
 49 	PROP_SOURCE,
 50 	PROP_SYNC_SETTINGS
 51 };
 52 
 53 G_DEFINE_TYPE (RBSyncSettingsUI, rb_sync_settings_ui, GTK_TYPE_VBOX)
 54 
 55 
 56 static void
 57 set_treeview_children (RBSyncSettingsUI *ui,
 58 		       GtkTreeIter *parent,
 59 		       const char *category,
 60 		       gboolean value,
 61 		       gboolean apply_to_settings)
 62 {
 63 	GtkTreeIter iter;
 64 	char *group;
 65 	gboolean valid;
 66 
 67 	valid = gtk_tree_model_iter_children (GTK_TREE_MODEL (ui->priv->sync_tree_store), &iter, parent);
 68 
 69 	while (valid) {
 70 		gtk_tree_model_get (GTK_TREE_MODEL (ui->priv->sync_tree_store), &iter,
 71 				    2, &group,
 72 				    -1);
 73 
 74 		if (apply_to_settings) {
 75 			rb_sync_settings_set_group (ui->priv->sync_settings, category, group, value);
 76 		}
 77 		gtk_tree_store_set (ui->priv->sync_tree_store, &iter,
 78 		/* Active */	    0, value,
 79 				    -1);
 80 
 81 		g_free (group);
 82 		valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (ui->priv->sync_tree_store), &iter);
 83 	}
 84 }
 85 
 86 static void
 87 sync_entries_changed_cb (GtkCellRendererToggle *cell_renderer,
 88 			 gchar *path,
 89 			 RBSyncSettingsUI *ui)
 90 {
 91 	GtkTreeIter iter;
 92 	char *group;
 93 	char *category_name;
 94 	gboolean is_category;
 95 	gboolean value;
 96 
 97 	if (gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (ui->priv->sync_tree_store), &iter, path) == FALSE) {
 98 		return;
 99 	}
100 
101 	gtk_tree_model_get (GTK_TREE_MODEL (ui->priv->sync_tree_store),
102 			    &iter,
103 			    2, &group,
104 			    4, &is_category,
105 			    5, &category_name,
106 			    -1);
107 
108 	value = !gtk_cell_renderer_toggle_get_active (cell_renderer);
109 
110 	if (is_category) {
111 		rb_debug ("state for category %s changed to %d", category_name, value);
112 		rb_sync_settings_set_category (ui->priv->sync_settings, category_name, value);
113 		rb_sync_settings_clear_groups (ui->priv->sync_settings, category_name);
114 
115 		gtk_tree_store_set (ui->priv->sync_tree_store,
116 				    &iter,
117 				    0, value,
118 				    1, FALSE,		/* category is no longer inconsistent */
119 				    -1);
120 		set_treeview_children (ui, &iter, category_name, value, FALSE);
121 	} else {
122 		gboolean parent_value;
123 		gboolean parent_inconsistent;
124 		GtkTreeIter parent;
125 		rb_debug ("state for group %s in category %s changed to %d", group, category_name, value);
126 
127 		/* update parent state.  if the parent was previously enabled or disabled, then we
128 		 * set all the other groups to that state before setting the row that was just changed,
129 		 * and set the parent to inconsistent state.
130 		 */
131 		gtk_tree_model_iter_parent (GTK_TREE_MODEL (ui->priv->sync_tree_store), &parent, &iter);
132 		gtk_tree_model_get (GTK_TREE_MODEL (ui->priv->sync_tree_store), &parent,
133 				    0, &parent_value,
134 				    1, &parent_inconsistent,
135 				    -1);
136 		if (parent_inconsistent == FALSE) {
137 			/* category is now inconsistent */
138 			rb_debug ("setting category %s to disabled, inconsistent", category_name);
139 			rb_sync_settings_set_category (ui->priv->sync_settings, category_name, FALSE);
140 			gtk_tree_store_set (ui->priv->sync_tree_store,
141 					    &parent,
142 					    0, FALSE,
143 					    1, TRUE,
144 					    -1);
145 
146 			/* set all groups in the category to the parent's state */
147 			set_treeview_children (ui, &parent, category_name, parent_value, TRUE);
148 		}
149 
150 		rb_sync_settings_set_group (ui->priv->sync_settings, category_name, group, value);
151 		gtk_tree_store_set (ui->priv->sync_tree_store, &iter,
152 				    0, value,
153 				    -1);
154 
155 		/* if no groups are enabled, the category is no longer inconsistent */
156 		if (value == FALSE && rb_sync_settings_has_enabled_groups (ui->priv->sync_settings, category_name) == FALSE) {
157 			rb_debug ("no enabled groups left in category %s", category_name);
158 			gtk_tree_store_set (ui->priv->sync_tree_store, &parent,
159 					    1, FALSE,
160 					    -1);
161 		} else if (value == FALSE) {
162 			rb_debug ("category %s still has some groups", category_name);
163 		}
164 	}
165 
166 	g_free (category_name);
167 	g_free (group);
168 }
169 
170 
171 GtkWidget *
172 rb_sync_settings_ui_new (RBMediaPlayerSource *source, RBSyncSettings *settings)
173 {
174 	GObject *ui;
175 	ui = g_object_new (RB_TYPE_SYNC_SETTINGS_UI,
176 			   "source", source,
177 			   "sync-settings", settings,
178 			   NULL);
179 	return GTK_WIDGET (ui);
180 }
181 
182 static void
183 rb_sync_settings_ui_init (RBSyncSettingsUI *ui)
184 {
185 	ui->priv = G_TYPE_INSTANCE_GET_PRIVATE (ui, RB_TYPE_SYNC_SETTINGS_UI, RBSyncSettingsUIPrivate);
186 }
187 
188 static void
189 impl_constructed (GObject *object)
190 {
191 	RBSyncSettingsUI *ui = RB_SYNC_SETTINGS_UI (object);
192 	GtkTreeIter tree_iter;
193 	GtkTreeIter parent_iter;
194 	GtkTreeModel *query_model;
195 	GtkCellRenderer *renderer;
196 	GtkTreeViewColumn *col;
197 	GtkWidget *tree_view;
198 	GList *l;
199 	GList *playlists;
200 	RBShell *shell;
201 	RhythmDB *db;
202 	RBPlaylistManager *playlist_manager;
203 	gboolean valid;
204 
205 	g_object_get (ui->priv->source, "shell", &shell, NULL);
206 	g_object_get (shell, "db", &db, "playlist-manager", &playlist_manager, NULL);
207 
208 	/* tree_store columns are: active, inconsistent, name, display-name, is-category, category name */
209 	ui->priv->sync_tree_store = gtk_tree_store_new (6, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_STRING);
210 
211 	/* music library parent */
212 	gtk_tree_store_append (ui->priv->sync_tree_store, &parent_iter, NULL);
213 	gtk_tree_store_set (ui->priv->sync_tree_store, &parent_iter,
214 			    0, rb_sync_settings_sync_category (ui->priv->sync_settings, SYNC_CATEGORY_MUSIC),
215 			    1, rb_sync_settings_has_enabled_groups (ui->priv->sync_settings, SYNC_CATEGORY_MUSIC),
216 			    2, _("Music"),
217 			    3, _("Music"),
218 			    4, TRUE,
219 			    5, SYNC_CATEGORY_MUSIC,
220 			    -1);
221 
222 	/* 'all music' entry */
223 	gtk_tree_store_append (ui->priv->sync_tree_store, &tree_iter, &parent_iter);
224 	gtk_tree_store_set (ui->priv->sync_tree_store, &tree_iter,
225 			    0, rb_sync_settings_sync_group (ui->priv->sync_settings, SYNC_CATEGORY_MUSIC, SYNC_GROUP_ALL_MUSIC),
226 			    1, FALSE,
227 			    2, SYNC_GROUP_ALL_MUSIC,
228 			    3, _("All Music"),
229 			    4, FALSE,
230 			    5, SYNC_CATEGORY_MUSIC,
231 			    -1);
232 
233 	/* playlist entries */
234 	playlists = rb_playlist_manager_get_playlists (playlist_manager);
235 	for (l = playlists; l != NULL; l = l->next) {
236 		char *name;
237 
238 		gtk_tree_store_append (ui->priv->sync_tree_store, &tree_iter, &parent_iter);
239 		/* set playlists data here */
240 		g_object_get (l->data, "name", &name, NULL);
241 
242 		/* set this row's data */
243 		gtk_tree_store_set (ui->priv->sync_tree_store, &tree_iter,
244 				    0, rb_sync_settings_sync_group (ui->priv->sync_settings, SYNC_CATEGORY_MUSIC, name),
245 				    1, FALSE,
246 				    2, name,
247 				    3, name,
248 				    4, FALSE,
249 				    5, SYNC_CATEGORY_MUSIC,
250 				    -1);
251 
252 		g_free (name);
253 	}
254 
255 	/* Append the Podcasts parent */
256 	gtk_tree_store_append (ui->priv->sync_tree_store,
257 			       &parent_iter,
258 			       NULL);
259 	gtk_tree_store_set (ui->priv->sync_tree_store, &parent_iter,
260 			    0, rb_sync_settings_sync_category (ui->priv->sync_settings, SYNC_CATEGORY_PODCAST),
261 			    1, rb_sync_settings_has_enabled_groups (ui->priv->sync_settings, SYNC_CATEGORY_PODCAST),
262 			    2, _("Podcasts"),
263 			    3, _("Podcasts"),
264 			    4, TRUE,
265 			    5, SYNC_CATEGORY_PODCAST,
266 			    -1);
267 
268 	/* this really needs to use a live query model */
269 	query_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db));
270 	rhythmdb_query_model_set_sort_order (RHYTHMDB_QUERY_MODEL (query_model),
271 					     (GCompareDataFunc) rhythmdb_query_model_title_sort_func,
272 					     NULL, NULL, FALSE);
273 	rhythmdb_do_full_query (db, RHYTHMDB_QUERY_RESULTS (query_model),
274 				RHYTHMDB_QUERY_PROP_EQUALS,
275 				RHYTHMDB_PROP_TYPE, RHYTHMDB_ENTRY_TYPE_PODCAST_FEED,
276 				RHYTHMDB_QUERY_END);
277 	valid = gtk_tree_model_get_iter_first (query_model, &tree_iter);
278 	while (valid) {
279 		RhythmDBEntry *entry;
280 		GtkTreeIter tree_iter2;
281 		const char *name;
282 		const char *feed;
283 
284 		entry = rhythmdb_query_model_iter_to_entry (RHYTHMDB_QUERY_MODEL (query_model), &tree_iter);
285 		gtk_tree_store_append (ui->priv->sync_tree_store, &tree_iter2, &parent_iter);
286 
287 		/* set up this row */
288 		name = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE);
289 		feed = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
290 		rb_debug ("adding feed %s (name %s)", feed, name);
291 		gtk_tree_store_set (ui->priv->sync_tree_store, &tree_iter2,
292 				    0, rb_sync_settings_sync_group (ui->priv->sync_settings, SYNC_CATEGORY_PODCAST, feed),
293 				    1, FALSE,
294 				    2, feed,
295 				    3, name,
296 				    4, FALSE,
297 				    5, SYNC_CATEGORY_PODCAST,
298 				    -1);
299 
300 		valid = gtk_tree_model_iter_next (query_model, &tree_iter);
301 	}
302 
303 	/* Set up the treeview */
304 	tree_view = gtk_tree_view_new ();
305 	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
306 	gtk_box_pack_start (GTK_BOX (ui), tree_view, TRUE, TRUE, 0);
307 
308 	/* First column */
309 	renderer = gtk_cell_renderer_toggle_new ();
310 	col = gtk_tree_view_column_new_with_attributes (NULL,
311 							renderer,
312 							"active", 0,
313 							"inconsistent", 1,
314 							NULL);
315 	g_signal_connect (G_OBJECT (renderer),
316 			  "toggled", G_CALLBACK (sync_entries_changed_cb),
317 			  ui);
318 	gtk_tree_view_append_column(GTK_TREE_VIEW (tree_view), col);
319 
320 	/* Second column */
321 	renderer = gtk_cell_renderer_text_new ();
322 	col = gtk_tree_view_column_new_with_attributes (NULL,
323 							renderer,
324 							"text", 3,
325 							NULL);
326 	gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
327 	gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view),
328 				 GTK_TREE_MODEL (ui->priv->sync_tree_store));
329 	gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)),
330 				    GTK_SELECTION_NONE);
331 
332 	g_object_unref (playlist_manager);
333 	g_object_unref (shell);
334 	g_object_unref (db);
335 
336 	gtk_widget_show_all (GTK_WIDGET (ui));
337 
338 	RB_CHAIN_GOBJECT_METHOD(rb_sync_settings_ui_parent_class, constructed, object);
339 }
340 
341 
342 static void
343 impl_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
344 {
345 	RBSyncSettingsUI *ui = RB_SYNC_SETTINGS_UI (object);
346 	switch (prop_id) {
347 	case PROP_SOURCE:
348 		ui->priv->source = g_value_get_object (value);
349 		break;
350 	case PROP_SYNC_SETTINGS:
351 		ui->priv->sync_settings = g_value_get_object (value);
352 		break;
353 	default:
354 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
355 		break;
356 	}
357 }
358 
359 static void
360 impl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
361 {
362 	RBSyncSettingsUI *ui = RB_SYNC_SETTINGS_UI (object);
363 	switch (prop_id) {
364 	case PROP_SOURCE:
365 		g_value_set_object (value, ui->priv->source);
366 		break;
367 	case PROP_SYNC_SETTINGS:
368 		g_value_set_object (value, ui->priv->sync_settings);
369 		break;
370 	default:
371 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
372 		break;
373 	}
374 }
375 
376 static void
377 impl_dispose (GObject *object)
378 {
379 	RBSyncSettingsUI *ui = RB_SYNC_SETTINGS_UI (object);
380 
381 	if (ui->priv->sync_tree_store) {
382 		g_object_unref (ui->priv->sync_tree_store);
383 		ui->priv->sync_tree_store = NULL;
384 	}
385 
386 	G_OBJECT_CLASS (rb_sync_settings_ui_parent_class)->dispose (object);
387 }
388 
389 static void
390 rb_sync_settings_ui_class_init (RBSyncSettingsUIClass *klass)
391 {
392 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
393 
394 	object_class->dispose = impl_dispose;
395 	object_class->constructed = impl_constructed;
396 
397 	object_class->set_property = impl_set_property;
398 	object_class->get_property = impl_get_property;
399 
400 	g_object_class_install_property (object_class,
401 					 PROP_SOURCE,
402 					 g_param_spec_object ("source",
403 							      "source",
404 							      "RBMediaPlayerSource instance",
405 							      RB_TYPE_MEDIA_PLAYER_SOURCE,
406 							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
407 	g_object_class_install_property (object_class,
408 					 PROP_SYNC_SETTINGS,
409 					 g_param_spec_object ("sync-settings",
410 							      "sync settings",
411 							      "RBSyncSettings instance",
412 							      RB_TYPE_SYNC_SETTINGS,
413 							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
414 
415 	g_type_class_add_private (object_class, sizeof (RBSyncSettingsUIPrivate));
416 }