Index: rb-mtp-source.c
===================================================================
--- rb-mtp-source.c	(revision 5571)
+++ rb-mtp-source.c	(working copy)
@@ -60,6 +60,7 @@
 static gboolean impl_show_popup (RBSource *source);
 static GList* impl_get_ui_actions (RBSource *source);
 static GList* impl_copy (RBSource *source);
+static void impl_get_status (RBSource *asource, char **text, char **progress_text, float *progress);
 
 static GList * impl_get_mime_types (RBRemovableMediaSource *source);
 static gboolean impl_track_added (RBRemovableMediaSource *source,
@@ -71,6 +72,19 @@
 				  const char *mimetype,
 				  const char *extension);
 
+static void rb_mtp_source_load_playlists (RBMtpSource *source);
+static void rb_mtp_source_add_playlist (RBMtpSource *source, LIBMTP_playlist_t *playlist);
+static void playlist_track_removed (GtkTreeModel *model, GtkTreePath *path, 
+				RhythmDBQueryModel *query, gpointer data);
+static void playlist_track_added (GtkTreeModel *model, GtkTreePath *path,
+		      GtkTreeIter *iter, gpointer data);
+static void update_mtp_playlist (GtkTreeModel *model, RBStaticPlaylistSource *playlist);
+static gboolean add_playlist_entry_to_mtp_playlist (GtkTreeModel *model, GtkTreePath *path,
+						GtkTreeIter *iter, gpointer list);
+static gboolean mtp_playlist_from_playlist_source (GtkTreeModel *model,
+						RBStaticPlaylistSource *playlist,
+						RBMtpSource *source);
+
 static RhythmDB * get_db_for_source (RBMtpSource *source);
 
 typedef struct
@@ -78,6 +92,11 @@
 	LIBMTP_mtpdevice_t *device;
 	GHashTable *entry_map;
 	char *udi;
+	GList *playlists;
+	LIBMTP_playlist_t *device_playlists;
+	GList *temp_files;
+
+	float battery_level;
 } RBMtpSourcePrivate;
 
 RB_PLUGIN_DEFINE_TYPE(RBMtpSource,
@@ -110,6 +129,7 @@
 	source_class->impl_delete_thyself = impl_delete_thyself;
 	source_class->impl_delete = impl_delete;
 	source_class->impl_copy = impl_copy;
+	source_class->impl_get_status = impl_get_status;
 
 	rms_class->impl_track_added = impl_track_added;
 	rms_class->impl_build_dest_uri = impl_build_dest_uri;
@@ -300,6 +320,17 @@
 		g_value_unset (&value);
 	}
 
+	/* Set play count*/
+	GValue value = {0, };
+	g_value_init (&value, G_TYPE_ULONG);
+	g_value_set_ulong (&value, track->usecount);
+	rb_debug ("Play count: %d", track->usecount);
+	rhythmdb_entry_set (RHYTHMDB (db), entry,
+				RHYTHMDB_PROP_PLAY_COUNT,
+				&value);
+
+	g_value_unset (&value);
+
 	/* Set title */
 	entry_set_string_prop (RHYTHMDB (db), entry, RHYTHMDB_PROP_TITLE, track->title);
 
@@ -320,27 +351,46 @@
 	RhythmDB *db = NULL;
 	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
 	LIBMTP_track_t *tracks = NULL;
+	uint8_t level, full;
 
+	if (LIBMTP_Get_Batterylevel (priv->device, &full, &level) == 0) {
+		priv->battery_level = ((float) level/(float) full);
+		rb_source_notify_status_changed (RB_SOURCE(source));
+	}
+
 	db = get_db_for_source (source);
 
 	g_assert (db != NULL);
 
-	tracks = LIBMTP_Get_Tracklisting (priv->device);
+	tracks = LIBMTP_Get_Tracklisting_With_Callback (priv->device, NULL, NULL);
 	if (tracks != NULL) {
 		LIBMTP_track_t *track, *tmp = NULL;
 		for (track = tracks; track != NULL; track = track->next) {
 			add_mtp_track_to_db (source, track);
 			tmp = track;
 		}
+		rb_mtp_source_load_playlists (source);
 	} else {
 		rb_debug ("No tracks");
 	}
 
+	
 	g_object_unref (G_OBJECT (db));
 	return FALSE;
 }
 
 static void
+impl_get_status (RBSource *asource, char **text, char **progress_text, float *progress)
+{
+	RBMtpSource *source = RB_MTP_SOURCE (asource);
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+
+	*progress_text = g_strdup_printf("Battery level: %u%%",
+					(int)(priv->battery_level * 100));
+	*progress =  priv->battery_level;
+}
+
+static void
 rb_mtp_source_load_tracks (RBMtpSource *source)
 {
 	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
@@ -363,6 +413,100 @@
 	g_free (name);
 }
 
+static void
+rb_mtp_source_load_playlists (RBMtpSource *source)
+{
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	LIBMTP_playlist_t *pl, *tmp;
+
+	pl = LIBMTP_Get_Playlist_List (priv->device);
+	priv->device_playlists = pl;
+	while (pl != NULL) {
+		rb_debug("mtp-playlist: %s", pl->name);
+		rb_mtp_source_add_playlist (source, pl);
+		tmp = pl;
+		pl = pl->next;
+		//LIBMTP_destroy_playlist_t (tmp);
+	}
+
+}
+
+static void
+rb_mtp_source_add_playlist (RBMtpSource *source, LIBMTP_playlist_t *playlist)
+{
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	RBShell *shell;
+	RhythmDB *db = get_db_for_source (source);
+	RBSource *playlist_source;
+	RhythmDBEntry *entry;
+	RhythmDBEntryType entry_type;
+	uint32_t i;
+	RhythmDBQueryModel *model;
+
+	g_object_get (source,
+			  "shell", &shell,
+			  "entry-type", &entry_type,
+			  NULL);
+
+	playlist_source = rb_static_playlist_source_new (shell,
+							 playlist->name,
+							 FALSE,
+							 entry_type);
+	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+
+
+
+
+	for (i = 0; i < playlist->no_tracks; i++) {
+		LIBMTP_track_t *track;
+		char *loc;
+
+		track = LIBMTP_Get_Trackmetadata(priv->device,
+						playlist->tracks[i]);
+		loc = g_strdup_printf ("rb-mtp-%i", track->item_id);
+		rb_debug ("track location: %s", loc);
+		if (track != NULL) {
+			entry = rhythmdb_entry_lookup_by_location (db, loc);
+			if (entry)
+				rb_static_playlist_source_add_entry (
+						RB_STATIC_PLAYLIST_SOURCE (playlist_source),
+						entry,
+						-1);
+
+			 //LIBMTP_destroy_track_t(track);
+		} else {
+			rb_debug ("Invalid track");
+		}
+		
+	}
+	g_object_unref (db);
+
+	model = rb_playlist_source_get_query_model (RB_PLAYLIST_SOURCE (playlist_source));
+	g_signal_connect (model, "row-inserted",
+			          G_CALLBACK (playlist_track_added),
+			          playlist_source);
+	g_signal_connect (model, "row-deleted",
+			          G_CALLBACK (playlist_track_removed),
+			          playlist_source);
+
+	g_object_set_data (G_OBJECT (playlist_source),
+			           "mtp-source", source);
+	g_object_set_data (G_OBJECT (playlist_source),
+			           "mtp-playlist-id", &playlist->playlist_id);
+	g_object_set_data (G_OBJECT (playlist_source),
+			           "mtp-playlist", playlist);
+
+	g_object_ref (G_OBJECT(playlist_source));
+	priv->playlists = g_list_prepend (priv->playlists, playlist_source);
+
+	if (playlist_source != NULL)
+		rb_shell_append_source (shell, playlist_source, RB_SOURCE (source));
+	g_object_unref (shell);
+}
+
+
+
+
 static gboolean
 destroy_entry_map_pair (RhythmDBEntry *entry, LIBMTP_track_t *track, RhythmDB *db)
 {
@@ -376,7 +520,10 @@
 {
 	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (asource);
 	RhythmDB *db = get_db_for_source (RB_MTP_SOURCE (asource));
+	GList *p, *q;
+	gchar *data = NULL;
 
+
 	if (priv->entry_map) {
 		g_hash_table_foreach_remove (priv->entry_map, (GHRFunc)destroy_entry_map_pair, db);
 		g_hash_table_destroy (priv->entry_map);
@@ -385,10 +532,32 @@
 	}
 
 	g_object_unref (db);
-
+	
+	LIBMTP_destroy_playlist_t (priv->device_playlists);
+	rb_debug ("Destroyed local device playlist info");
 	LIBMTP_Release_Device (priv->device);
 	priv->device = NULL;
+	rb_debug ("Disconnected device");
 
+	for (q = priv->temp_files; q != NULL; q = q->next) {
+		data = q->data;
+		rb_debug("temp_files->data: %s", data);
+		gnome_vfs_unlink (data);
+	}
+	g_free (data);
+	g_list_free (priv->temp_files);
+	priv->temp_files = NULL;
+	rb_debug("clear transferred files");
+	
+	for (p = priv->playlists; p != NULL; p = p->next) {
+		RBSource *playlist = RB_SOURCE (p->data);
+		rb_source_delete_thyself (playlist);
+	}
+	g_list_free (priv->playlists);
+	priv->playlists = NULL;
+	rb_debug("Deleted playlist sources");
+
+
 	if (priv->udi != NULL) {
 		g_free (priv->udi);
 		priv->udi = NULL;
@@ -591,6 +760,7 @@
 
 	if (rb_mtp_source_transfer_track_to_disk (priv->device, track, uri) == TRUE) {
 		s = g_strdup_printf ("file://%s", uri);
+		priv->temp_files = g_list_prepend(priv->temp_files, strdup(s));
 		g_free (uri);
 		return s;
 	} else {
@@ -658,9 +828,10 @@
 		RhythmDBEntry *entry,
 		const char *filename,
 		const char *mimetype)
-{
+{	
 	LIBMTP_track_t *trackmeta = LIBMTP_new_track_t ();
 	GDate d;
+	struct stat stbuf;
 
 	trackmeta->title = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_TITLE);
 	trackmeta->album = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_ALBUM);
@@ -674,7 +845,10 @@
 	}
 	trackmeta->tracknumber = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TRACK_NUMBER);
 	trackmeta->duration = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DURATION) * 1000;
-	trackmeta->filesize = rhythmdb_entry_get_uint64 (entry, RHYTHMDB_PROP_FILE_SIZE);
+	/*trackmeta->filesize = rhythmdb_entry_get_uint64 (entry, RHYTHMDB_PROP_FILE_SIZE);*/
+	stat(filename, &stbuf);
+	trackmeta->filesize = stbuf.st_size;
+
 	if (mimetype == NULL) {
 		trackmeta->filetype = mimetype_to_filetype (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MIMETYPE));
 	} else {
@@ -753,3 +927,167 @@
 	return uri;
 }
 
+static void
+playlist_track_added (GtkTreeModel *model, GtkTreePath *path,
+		      GtkTreeIter *iter, gpointer data)
+{
+	rb_debug ("Track added");
+	RBStaticPlaylistSource *playlist = RB_STATIC_PLAYLIST_SOURCE (data);
+	rb_debug ("  update playlist");
+	update_mtp_playlist (model, playlist);
+}
+
+static void
+playlist_track_removed (GtkTreeModel *model, GtkTreePath *path, 
+				RhythmDBQueryModel *query, gpointer data)
+{
+	rb_debug ("Track removed");
+	RBStaticPlaylistSource *playlist = RB_STATIC_PLAYLIST_SOURCE (data);
+	update_mtp_playlist (model, playlist);
+}
+
+static void
+update_mtp_playlist (GtkTreeModel *model, RBStaticPlaylistSource *playlist)
+{
+	RBMtpSource *source = g_object_get_data (G_OBJECT (playlist), "mtp-source");
+	//RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+
+	/*gtk_tree_model_get (model, iter, 0, &entry, -1);
+        track = g_hash_table_lookup (priv->entry_map, entry);
+	g_return_if_fail (track != NULL);*/
+	rb_debug ("Create playlist");
+
+	if (!mtp_playlist_from_playlist_source (model, playlist, source))
+		rb_debug ("Failed to save playlist to device");
+	
+	
+	g_object_unref (model);
+}
+
+static gboolean
+add_playlist_entry_to_mtp_playlist (GtkTreeModel *model,
+			    GtkTreePath *path,
+			    GtkTreeIter *iter,
+			    gpointer list)
+{
+	RhythmDBEntry *entry = NULL;
+	GList **tracks;
+	tracks = (GList **) list;
+	
+	gtk_tree_model_get (model, iter, 0, &entry, -1);
+	if (entry == NULL)
+		return TRUE;
+
+	if (g_str_has_prefix (rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_LOCATION), "rb-mtp-")) {
+		char *num = strrchr(rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_LOCATION), '-') + 1;
+		rb_debug ("   processing %s", num);
+		uint32_t track_id = (uint32_t) g_ascii_strtod(num, NULL);
+		rb_debug ("   |->track id: %d", track_id);
+		*tracks = g_list_append (*tracks, GINT_TO_POINTER(track_id));
+		rb_debug ("   next track");
+	}
+	return FALSE;
+		
+}
+
+static gboolean
+mtp_playlist_from_playlist_source (GtkTreeModel *model, RBStaticPlaylistSource *playlist,
+					RBMtpSource *source)
+{
+	LIBMTP_playlist_t *pl = LIBMTP_new_playlist_t();
+	LIBMTP_playlist_t *oldlist;
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	GList *ids = NULL;
+	GList *tmp;
+	
+	/* Maybe the other way is better...
+	rb_debug ("pl id: %d", pl->playlist_id);
+	pl->playlist_id = (uint32_t) GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (playlist), "mtp-playlist-id"));
+	rb_debug ("pl id: %d", pl->playlist_id);
+	*/
+	
+	g_object_get (G_OBJECT (playlist), "name", &pl->name, "mtp-playlist", &oldlist, NULL);
+	
+	rb_debug ("Old id: %d  New id: %d", oldlist->playlist_id, pl->playlist_id);
+	pl->playlist_id = oldlist->playlist_id;
+
+	rb_debug ("Updating playlist from source %s with id %d",pl->name, pl->playlist_id);
+
+	gtk_tree_model_foreach (GTK_TREE_MODEL (model), 
+			(GtkTreeModelForeachFunc) add_playlist_entry_to_mtp_playlist, &ids);
+	if (ids == NULL) {
+		return FALSE;
+		rb_debug ("Null list");
+	}
+		
+	rb_debug ("GList length %d", g_list_length(ids));
+	if (g_list_length (ids) < 1) {
+		rb_debug ("No tracks in list... error!");
+		return FALSE;
+	}
+	rb_debug ("  done iterating...");
+	pl->no_tracks = (uint32_t) g_list_length (ids);
+	rb_debug ("space for array");
+	pl->tracks = (uint32_t *) malloc (sizeof (uint32_t) * pl->no_tracks);
+	rb_debug("Put tracks in array");
+	int i = 0;
+	for (tmp = g_list_first (ids); tmp != NULL; tmp = tmp->next) {
+		//tracks[i] = (uint32_t) malloc (sizeof (uint32_t));
+		pl->tracks[i] = (uint32_t) GPOINTER_TO_INT (tmp->data);
+		rb_debug ("  * track %d", pl->tracks[i]);
+		i++;
+	}
+	rb_debug ("Done making track list for playlist %d", pl->playlist_id);
+	
+	//pl->next = oldlist->next;
+
+	if (LIBMTP_Update_Playlist (priv->device, pl) != 0) {
+		rb_debug ("Couldn't update playlist");
+		LIBMTP_Dump_Errorstack(priv->device);
+		LIBMTP_Clear_Errorstack(priv->device);
+		return FALSE;
+	} else {
+		rb_debug ("Successfully updated playlist");
+		
+	}
+
+	/*
+
+	if (priv->device_playlists == NULL) {
+		pl->next = NULL;
+	} else {
+		rb_debug ("Finding next playlist");
+		LIBMTP_playlist_t *list;
+		list = priv->device_playlists;
+		rb_debug ("Global data ok");
+
+		if (list == NULL) 
+			rb_debug ("Null playlist");
+		while (list != NULL) {
+			rb_debug ("PL IDs: new: %d old: %d", pl->playlist_id, list->playlist_id);
+			if (list->playlist_id == pl->playlist_id) {
+
+				rb_debug ("Found the playlist to update");
+				pl->next = list->next;
+
+				if (LIBMTP_Update_Playlist (priv->device, pl) != 0) {
+					rb_debug ("Couldn't update playlist");
+					LIBMTP_Dump_Errorstack(priv->device);
+					LIBMTP_Clear_Errorstack(priv->device);
+					return FALSE;
+				} else {
+					rb_debug ("Successfully updated playlist");
+					
+				}
+				
+			}
+			list = list->next;
+		}
+	}*/
+
+
+
+			
+	return TRUE;
+}
+
