hythmbox-2.98/plugins/ipod/rb-ipod-static-playlist-source.c

No issues found

  1 /*
  2  *  Copyright (C) 2007 James Livingston  <doclivingston@gmail.com>
  3  *
  4  *  This program is free software; you can redistribute it and/or modify
  5  *  it under the terms of the GNU General Public License as published by
  6  *  the Free Software Foundation; either version 2 of the License, or
  7  *  (at your option) any later version.
  8  *
  9  *  This program is distributed in the hope that it will be useful,
 10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12  *  GNU General Public License for more details.
 13  *
 14  *  You should have received a copy of the GNU General Public License
 15  *  along with this program; if not, write to the Free Software
 16  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
 17  *
 18  */
 19 
 20 #include "config.h"
 21 
 22 #include <string.h>
 23 
 24 #include <glib/gi18n.h>
 25 #include <gtk/gtk.h>
 26 #include <gpod/itdb.h>
 27 
 28 #include "rb-debug.h"
 29 #include "rb-util.h"
 30 #include "rhythmdb.h"
 31 
 32 #include "rb-ipod-static-playlist-source.h"
 33 #include "rb-media-player-source.h"
 34 #include "rb-ipod-source.h"
 35 
 36 static void rb_ipod_static_playlist_source_constructed (GObject *object);
 37 static void rb_ipod_static_playlist_source_dispose (GObject *object);
 38 static void rb_ipod_static_playlist_source_set_property (GObject *object,
 39 			                  guint prop_id,
 40 			                  const GValue *value,
 41 			                  GParamSpec *pspec);
 42 static void rb_ipod_static_playlist_source_get_property (GObject *object,
 43 			                  guint prop_id,
 44 			                  GValue *value,
 45 			                  GParamSpec *pspec);
 46 
 47 static gboolean impl_show_popup (RBDisplayPage *page);
 48 
 49 typedef struct
 50 {
 51 	RbIpodDb	*ipod_db;
 52 	Itdb_Playlist	*itdb_playlist;
 53 	RBiPodSource	*ipod_source;
 54 	gboolean	was_reordered;
 55 } RBIpodStaticPlaylistSourcePrivate;
 56 
 57 G_DEFINE_DYNAMIC_TYPE(RBIpodStaticPlaylistSource, rb_ipod_static_playlist_source, RB_TYPE_STATIC_PLAYLIST_SOURCE)
 58 
 59 #define IPOD_STATIC_PLAYLIST_SOURCE_GET_PRIVATE(o)   (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_IPOD_STATIC_PLAYLIST_SOURCE, RBIpodStaticPlaylistSourcePrivate))
 60 
 61 enum {
 62 	PROP_0,
 63 	PROP_IPOD_SOURCE,
 64 	PROP_IPOD_DB,
 65 	PROP_ITDB_PLAYLIST
 66 };
 67 
 68 static void
 69 playlist_track_removed (RhythmDBQueryModel *m,
 70 			RhythmDBEntry *entry,
 71 			gpointer data)
 72 {
 73 	RBIpodStaticPlaylistSourcePrivate *priv = IPOD_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (data);
 74 	Itdb_Track *track;
 75 
 76 	track = rb_ipod_source_lookup_track (priv->ipod_source, entry);
 77 	g_return_if_fail (track != NULL);
 78 	rb_ipod_db_remove_from_playlist (priv->ipod_db, priv->itdb_playlist, track);
 79 }
 80 
 81 static void
 82 playlist_track_added (GtkTreeModel *model,
 83 		      GtkTreePath *path,
 84 		      GtkTreeIter *iter,
 85 		      gpointer data)
 86 {
 87 	RBIpodStaticPlaylistSourcePrivate *priv = IPOD_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (data);
 88 	Itdb_Track *track;
 89 	RhythmDBEntry *entry;
 90 
 91 	gtk_tree_model_get (model, iter, 0, &entry, -1);
 92 	track = rb_ipod_source_lookup_track (priv->ipod_source, entry);
 93 	g_return_if_fail (track != NULL);
 94 
 95 	rb_ipod_db_add_to_playlist (priv->ipod_db, priv->itdb_playlist, track);
 96 }
 97 
 98 static void
 99 playlist_before_save (RbIpodDb *ipod_db, gpointer data)
100 {
101 	RBIpodStaticPlaylistSourcePrivate *priv = IPOD_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (data);
102 	RhythmDBQueryModel *model;
103 	GtkTreeIter iter;
104 
105 	if (priv->was_reordered == FALSE)
106 		return;
107 	priv->was_reordered = FALSE;
108 
109 	/* Sanity check that all tracks are in entry_map */
110 
111 	g_object_get (G_OBJECT (data), "base-query-model", &model, NULL);
112 	if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter)) {
113 		do {
114 			RhythmDBEntry *entry;
115 			Itdb_Track *track;
116 
117 			gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &entry, -1);
118 			track = rb_ipod_source_lookup_track (priv->ipod_source, entry);
119 
120 			g_return_if_fail (track != NULL);
121 		} while (gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter));
122 	}
123 
124 	/* Remove all tracks then re-add in correct order */
125 
126 	while (priv->itdb_playlist->members != NULL) {
127 		Itdb_Track *track;
128 
129 		track = (Itdb_Track *)priv->itdb_playlist->members->data;
130 
131 		rb_debug ("removing \"%s\" from \"%s\"", track->title, priv->itdb_playlist->name);
132 
133 		/* Call directly to itdb to avoid scheduling another save */
134 		itdb_playlist_remove_track (priv->itdb_playlist, track);
135 	}
136 
137 	if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter)) {
138 		do {
139 			RhythmDBEntry *entry;
140 			Itdb_Track *track;
141 
142 			gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &entry, -1);
143 			track = rb_ipod_source_lookup_track (priv->ipod_source, entry);
144 
145 			rb_debug ("adding \"%s\" to \"%s\"", track->title, priv->itdb_playlist->name);
146 
147 			/* Call directly to itdb to avoid scheduling another save */
148 			itdb_playlist_add_track (priv->itdb_playlist, track, -1);
149 		} while (gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter));
150 	}
151 
152 	g_object_unref (model);
153 }
154 
155 static void
156 playlist_rows_reordered (GtkTreeModel *model,
157 			 GtkTreePath *path,
158 			 GtkTreeIter *iter,
159 			 gint *order,
160 			 gpointer data)
161 {
162 	RBIpodStaticPlaylistSourcePrivate *priv = IPOD_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (data);
163 	priv->was_reordered = TRUE;
164 
165 	rb_ipod_db_save_async (priv->ipod_db);
166 }
167 
168 static void
169 playlist_source_model_disconnect_signals (RBIpodStaticPlaylistSource *source)
170 {
171 	RhythmDBQueryModel *model;
172 
173 	g_return_if_fail (RB_IS_IPOD_STATIC_PLAYLIST_SOURCE (source));
174 
175 	g_object_get (source, "base-query-model", &model, NULL);
176 
177 	g_signal_handlers_disconnect_by_func (model,
178 					      G_CALLBACK (playlist_track_added),
179 					      source);
180 	g_signal_handlers_disconnect_by_func (model,
181 					      G_CALLBACK (playlist_track_removed),
182 					      source);
183 	g_signal_handlers_disconnect_by_func (model,
184 					      G_CALLBACK (playlist_rows_reordered),
185 					      source);
186 
187 	g_object_unref (model);
188 }
189 
190 static void
191 playlist_source_model_connect_signals (RBIpodStaticPlaylistSource *playlist_source)
192 {
193 	RhythmDBQueryModel *model;
194 
195 	g_return_if_fail (RB_IS_IPOD_STATIC_PLAYLIST_SOURCE (playlist_source));
196 
197 	g_object_get (playlist_source, "base-query-model", &model, NULL);
198 	g_signal_connect (model, "row-inserted",
199 			  G_CALLBACK (playlist_track_added),
200 			  playlist_source);
201 	g_signal_connect (model, "entry-removed",
202 			  G_CALLBACK (playlist_track_removed),
203 			  playlist_source);
204 	g_signal_connect (model, "rows-reordered",
205 			  G_CALLBACK (playlist_rows_reordered),
206 			  playlist_source);
207 	g_object_unref (model);
208 }
209 
210 static void
211 source_name_changed_cb (RBIpodStaticPlaylistSource *source,
212 			GParamSpec *spec,
213 			gpointer data)
214 {
215 	RBIpodStaticPlaylistSourcePrivate *priv = IPOD_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (source);
216 	char *name;
217 
218 	g_object_get (source, "name", &name, NULL);
219 
220 	if ((priv->itdb_playlist != NULL) && (strcmp (name, priv->itdb_playlist->name) != 0)) {
221 		rb_debug ("changing playlist name to %s", name);
222 		rb_ipod_db_rename_playlist (priv->ipod_db, priv->itdb_playlist, name);
223 	}
224 	g_free (name);
225 }
226 
227 
228 static void
229 rb_ipod_static_playlist_source_class_init (RBIpodStaticPlaylistSourceClass *klass)
230 {
231 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
232 	RBDisplayPageClass *page_class = RB_DISPLAY_PAGE_CLASS (klass);
233 	RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
234 
235 	object_class->constructed = rb_ipod_static_playlist_source_constructed;
236 	object_class->dispose = rb_ipod_static_playlist_source_dispose;
237 	object_class->get_property = rb_ipod_static_playlist_source_get_property;
238 	object_class->set_property = rb_ipod_static_playlist_source_set_property;
239 
240 	page_class->show_popup = impl_show_popup;
241 
242 	source_class->impl_can_move_to_trash = (RBSourceFeatureFunc) rb_false_function;
243 	source_class->impl_can_delete = (RBSourceFeatureFunc) rb_true_function;
244 
245 	/* Don't override impl_delete here -- it's provided by RBStaticPlaylistSource */
246 
247 	g_object_class_install_property (object_class,
248 					 PROP_IPOD_SOURCE,
249 					 g_param_spec_object ("ipod-source",
250 							      "ipod-source",
251 							      "ipod-source",
252 							      RB_TYPE_IPOD_SOURCE,
253 							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
254 
255 	g_object_class_install_property (object_class,
256 					 PROP_IPOD_DB,
257 					 g_param_spec_object ("ipod-db",
258 							      "ipod-db",
259 							      "ipod-db",
260 							      RB_TYPE_IPOD_DB,
261 							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
262 
263 	g_object_class_install_property (object_class,
264 					 PROP_ITDB_PLAYLIST,
265 					 g_param_spec_pointer ("itdb-playlist",
266 							      "itdb-playlist",
267 							      "itdb-playlist",
268 							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
269 
270 	g_type_class_add_private (klass, sizeof (RBIpodStaticPlaylistSourcePrivate));
271 }
272 
273 static void
274 rb_ipod_static_playlist_source_class_finalize (RBIpodStaticPlaylistSourceClass *klass)
275 {
276 }
277 
278 static void
279 rb_ipod_static_playlist_source_init (RBIpodStaticPlaylistSource *source)
280 {
281 
282 }
283 
284 static void
285 rb_ipod_static_playlist_source_constructed (GObject *object)
286 {
287 	RBIpodStaticPlaylistSourcePrivate *priv = IPOD_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (object);
288 	RhythmDBQueryModel *model;
289 
290 	RB_CHAIN_GOBJECT_METHOD (rb_ipod_static_playlist_source_parent_class, constructed, object);
291 
292 	g_signal_connect (object, "notify::name", (GCallback)source_name_changed_cb, NULL);
293 
294 	g_object_get (object, "base-query-model", &model, NULL);
295 	g_signal_connect (priv->ipod_db, "before-save",
296 			  G_CALLBACK (playlist_before_save),
297 			  object);
298 	g_object_unref (model);
299 	playlist_source_model_connect_signals (RB_IPOD_STATIC_PLAYLIST_SOURCE (object));
300 
301 }
302 
303 static void
304 rb_ipod_static_playlist_source_dispose (GObject *object)
305 {
306 	RBIpodStaticPlaylistSource *source = RB_IPOD_STATIC_PLAYLIST_SOURCE (object);
307 	RBIpodStaticPlaylistSourcePrivate *priv = IPOD_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (object);
308 
309 	if (priv->ipod_source) {
310 		g_object_unref (priv->ipod_source);
311 		priv->ipod_source = NULL;
312 	}
313 	if (priv->ipod_db) {
314 		g_signal_handlers_disconnect_by_func (priv->ipod_db,
315 						      G_CALLBACK (playlist_before_save),
316 						      source);
317 
318 		g_object_unref (priv->ipod_db);
319 		priv->ipod_db = NULL;
320 	}
321 
322 	playlist_source_model_disconnect_signals (source);
323 
324 	G_OBJECT_CLASS (rb_ipod_static_playlist_source_parent_class)->dispose (object);
325 }
326 
327 RBIpodStaticPlaylistSource *
328 rb_ipod_static_playlist_source_new (RBShell *shell,
329 				    RBiPodSource *ipod_source,
330 				    RbIpodDb *ipod_db,
331 				    Itdb_Playlist *playlist,
332 				    RhythmDBEntryType *entry_type)
333 {
334 	RBIpodStaticPlaylistSource *source;
335 
336 	g_assert (RB_IS_IPOD_SOURCE (ipod_source));
337 
338 	source = RB_IPOD_STATIC_PLAYLIST_SOURCE (g_object_new (RB_TYPE_IPOD_STATIC_PLAYLIST_SOURCE,
339 							       "entry-type", entry_type,
340 							       "shell", shell,
341 							       "is-local", FALSE,
342 							       "name", playlist->name,
343 							       "ipod-source", ipod_source,
344 							       "ipod-db", ipod_db,
345 							       "itdb-playlist", playlist,
346 							       NULL));
347 
348 	return source;
349 }
350 
351 
352 static void
353 rb_ipod_static_playlist_source_set_property (GObject *object,
354 				guint prop_id,
355 				const GValue *value,
356 				GParamSpec *pspec)
357 {
358 	RBIpodStaticPlaylistSourcePrivate *priv = IPOD_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (object);
359 
360 	switch (prop_id) {
361 	case PROP_IPOD_SOURCE:
362 		priv->ipod_source = g_value_dup_object (value);
363 		break;
364 	case PROP_IPOD_DB:
365 		priv->ipod_db = g_value_dup_object (value);
366 		break;
367 	case PROP_ITDB_PLAYLIST:
368 		priv->itdb_playlist = g_value_get_pointer (value);
369 		break;
370 	default:
371 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
372 		break;
373 	}
374 }
375 
376 static void
377 rb_ipod_static_playlist_source_get_property (GObject *object,
378 				guint prop_id,
379 				GValue *value,
380 				GParamSpec *pspec)
381 {
382 	RBIpodStaticPlaylistSourcePrivate *priv = IPOD_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (object);
383 
384 	switch (prop_id) {
385 	case PROP_IPOD_SOURCE:
386 		g_value_set_object (value, priv->ipod_source);
387 		break;
388 	case PROP_IPOD_DB:
389 		g_value_set_object (value, priv->ipod_db);
390 		break;
391 	case PROP_ITDB_PLAYLIST:
392 		g_value_set_pointer (value, priv->itdb_playlist);
393 		break;
394 	default:
395 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
396 		break;
397 	}
398 }
399 
400 static gboolean
401 impl_show_popup (RBDisplayPage *page)
402 {
403 	_rb_display_page_show_popup (page, "/iPodPlaylistSourcePopup");
404 	return TRUE;
405 }
406 
407 void
408 _rb_ipod_static_playlist_source_register_type (GTypeModule *module)
409 {
410 	rb_ipod_static_playlist_source_register_type (module);
411 }