hipo r143 - in branches/bgarret: . src



Author: bgarret
Date: Thu Jan 31 21:38:51 2008
New Revision: 143
URL: http://svn.gnome.org/viewvc/hipo?rev=143&view=rev

Log:
2008-01-31  Benoit Garret  <benoit garret_gnome gadz org>

	* configure.ac:
	* src/CapacityBar.cs:
	* src/DeviceSource.cs:
	* src/EditableCellRenderer.cs:
	* src/HipoMain.cs:
	* src/HipoMainWindow.cs:
	* src/Makefile.am:
	* src/PlaylistSource.cs:
	* src/PlaylistView.cs:
	* src/Saviour.cs:
	* src/Source.cs:
	* src/SourceList.cs:
	* src/Tools.cs:
	* src/TracksContainer.cs:
	* src/TracksSource.cs:
	* src/TracksView.cs:
	* src/devicepopup.xml:
	* src/errordialog.glade:
	* src/hipo.glade:
	* src/hipo.xml:
	* src/menubar.xml:
	* src/playlistpopup.xml:
	* src/trackpopup.xml:

	Big Bad Redesign



Added:
   branches/bgarret/src/CapacityBar.cs
   branches/bgarret/src/DeviceSource.cs
   branches/bgarret/src/EditableCellRenderer.cs
   branches/bgarret/src/PlaylistSource.cs
   branches/bgarret/src/Saviour.cs
   branches/bgarret/src/Source.cs
   branches/bgarret/src/SourceList.cs
   branches/bgarret/src/Tools.cs
   branches/bgarret/src/TracksContainer.cs
   branches/bgarret/src/TracksSource.cs
   branches/bgarret/src/devicepopup.xml
   branches/bgarret/src/menubar.xml
   branches/bgarret/src/playlistpopup.xml
   branches/bgarret/src/trackpopup.xml
Removed:
   branches/bgarret/src/PlaylistView.cs
   branches/bgarret/src/TracksView.cs
   branches/bgarret/src/hipo.xml
Modified:
   branches/bgarret/ChangeLog
   branches/bgarret/configure.ac
   branches/bgarret/src/Defines.cs.in
   branches/bgarret/src/HipoMain.cs
   branches/bgarret/src/HipoMainWindow.cs
   branches/bgarret/src/Makefile.am
   branches/bgarret/src/errordialog.glade
   branches/bgarret/src/hipo.glade

Modified: branches/bgarret/configure.ac
==============================================================================
--- branches/bgarret/configure.ac	(original)
+++ branches/bgarret/configure.ac	Thu Jan 31 21:38:51 2008
@@ -15,13 +15,15 @@
 
 GTK_SHARP_REQUIRED=2.10
 IPOD_SHARP_REQUIRED=0.6.3
+NDESK_DBUS_GLIB_REQUIRED=0.3
 
 PKG_CHECK_MODULES(HIPO, 
 		gtk-sharp-2.0 >= $GTK_SHARP_REQUIRED \
 		gnome-sharp-2.0 >= $GTK_SHARP_REQUIRED \
 		glade-sharp-2.0 >= $GTK_SHARP_REQUIRED \
 		ipod-sharp >= $IPOD_SHARP_REQUIRED   \
-		ipod-sharp-ui >= $IPOD_SHARP_REQUIRED)
+		ipod-sharp-ui >= $IPOD_SHARP_REQUIRED \
+		ndesk-dbus-glib-1.0 >= $NDESK_DBUS_GLIB_REQUIRED)
 
 AC_SUBST(HIPO_LIBS)
 

Added: branches/bgarret/src/CapacityBar.cs
==============================================================================
--- (empty file)
+++ branches/bgarret/src/CapacityBar.cs	Thu Jan 31 21:38:51 2008
@@ -0,0 +1,89 @@
+// CapacityBar.cs
+//
+//  Copyright (C) 2008 Benoit Garret
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+//
+
+using System;
+using IPod;
+using Gtk;
+using Mono.Unix;
+
+namespace Hipo
+{
+	public class CapacityBar : ProgressBar
+	{
+		private Device device = null;
+		
+		public Device Device
+		{
+			set {
+				if (device != null)
+				{
+					device.Changed -= OnChanged;
+					device.TrackDatabase.SaveEnded -= OnChanged;
+				}
+				
+				device = value;
+				
+				if (device != null)
+				{
+					device.Changed += OnChanged;
+					device.TrackDatabase.SaveEnded += OnChanged;
+					Refresh ();
+				}
+				else
+				{
+					Clear ();
+				}
+			}
+		}
+		
+		private void Refresh ()
+		{
+			string capacity = null;
+			string used = null;
+			double percent;
+			
+			capacity = Tools.FormatString ((double) device.VolumeInfo.Size);
+			used = Tools.FormatString ((double) device.VolumeInfo.SpaceUsed);
+			
+			percent = ((double) device.VolumeInfo.SpaceUsed * 100) / ((double) device.VolumeInfo.Size);
+			
+			Gtk.Application.Invoke (delegate {
+				
+				/* space used in the device, example: used 15G of 60G */ 
+				this.Text = String.Format (Catalog.GetString ("Using {0} of {1}"), used, capacity);
+				this.Fraction = percent  / 100;
+			});
+		}
+		
+		private void Clear ()
+		{
+			Gtk.Application.Invoke (delegate {
+				
+				this.Text = Catalog.GetString ("No iPod Found");
+				this.Fraction = 0.0;
+			});
+		}
+		
+		private void OnChanged (object o, EventArgs args)
+		{
+			Refresh ();
+		}
+	}
+}

Modified: branches/bgarret/src/Defines.cs.in
==============================================================================
--- branches/bgarret/src/Defines.cs.in	(original)
+++ branches/bgarret/src/Defines.cs.in	Thu Jan 31 21:38:51 2008
@@ -4,8 +4,8 @@
 	{
 		public const string PACKAGE  	     = "@PACKAGE@";
 		public const string VERSION          = "@VERSION@";
-	        public const string LOCALE_DIR       = "@prefix@/share/locale";
+	    public const string LOCALE_DIR       = "@prefix@/share/locale";
 		public const string GETTEXT_PACKAGE  = "@GETTEXT_PACKAGE@";
-                public const string GNOME_HELP_DIR   = "@prefix@/share/gnome/help/hipo";
+        public const string GNOME_HELP_DIR   = "@prefix@/share/gnome/help/hipo";
 	}
 }

Added: branches/bgarret/src/DeviceSource.cs
==============================================================================
--- (empty file)
+++ branches/bgarret/src/DeviceSource.cs	Thu Jan 31 21:38:51 2008
@@ -0,0 +1,145 @@
+// DeviceSource.cs
+//
+//  Copyright (C) 2008 Benoit Garret
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+//
+
+using System;
+using System.Collections.ObjectModel;
+using Glade;
+using Gtk;
+using IPod;
+using Mono.Unix;
+
+namespace Hipo
+{
+	public class DeviceSource : SourceBase
+	{
+		[Widget] Window deviceProperties;
+		[Widget] Viewport deviceViewport;
+		[Widget] Label serialLabel;
+		[Widget] Label modelLabel;
+		[Widget] Label generationLabel;
+		[Widget] Label capacityLabel;
+		[Widget] Label mountLabel;
+		[Widget] Label spaceLabel;
+		[Widget] Label firmwareLabel;
+		
+		private Device device;
+		
+		public DeviceSource (Device device)
+		{
+			this.device = device;
+			
+			this.Type = SourceType.Device;
+			this.Parent = SourceType.None;
+			this.Icon = IconTheme.Default.LoadIcon (device.ModelInfo.IconName, 16, 0);
+			
+			Glade.XML xml = new Glade.XML (null, "hipo.glade", "deviceProperties", null);;
+			xml.Autoconnect (this);
+			
+			serialLabel.Text = this.device.ProductionInfo.SerialNumber;
+			modelLabel.Text = this.device.ModelInfo.DeviceClass;
+			generationLabel.Text = String.Format ("{0}", this.device.ModelInfo.Generation);
+			capacityLabel.Text = Tools.FormatString ((double) this.device.VolumeInfo.Size);
+			mountLabel.Text = this.device.VolumeInfo.MountPoint;
+			spaceLabel.Text = String.Format ("{0}%", (int) ((double) device.VolumeInfo.SpaceUsed / (double) device.VolumeInfo.Size * 100));
+			
+			// remove the viewport from the window so we can add it elsewhere
+			deviceProperties.Remove (deviceViewport);
+			
+			// source list right click menu
+			ActionEntry[] entries =  {
+				
+				new ActionEntry ("RenameDevice",
+				                 Gtk.Stock.Copy,
+				                 Catalog.GetString ("Rename"),
+				                 null,
+				                 Catalog.GetString ("Rename the device"),
+				                 OnRename)
+			};
+			
+			ActionGroup group = new ActionGroup ("DevicePopup");
+			group.Add (entries);
+			firmwareLabel.Text = this.device.FirmwareVersion;
+			
+			UIManager.Instance.InsertActionGroup (group, 0);
+			UIManager.Instance.AddUiFromResource ("devicepopup.xml");
+		}
+		
+		public override string Name
+		{
+			get {
+				return device.Name;
+			}
+			set {
+				if (device.Name != value)
+				{
+					device.Name = value;
+					Saviour.Instance.Save ();
+				}
+			}
+		}
+		
+		public override Widget View
+		{
+			get {
+				return deviceViewport;
+			}
+		}
+		
+		public override Menu Menu
+		{
+			get {
+				return (Menu)UIManager.Instance.GetWidget ("/ui/DevicePopup");
+			}
+		}
+		
+		public void Eject ()
+		{
+			this.device.Eject ();
+		}
+		
+		public ReadOnlyCollection<ArtworkFormat> LookupArtworkFormats (ArtworkUsage usage)
+		{
+			return this.device.LookupArtworkFormats (usage);
+		}
+		
+		private void OnRename (object o, EventArgs args)
+		{
+			Dialog dialog = new Dialog (Catalog.GetString ("Rename the device"), null, Gtk.DialogFlags.DestroyWithParent);
+			
+			dialog.Modal = true;
+			dialog.AddButton ("Cancel", ResponseType.Close);
+			dialog.AddButton ("OK", ResponseType.Ok);
+			
+			Gtk.Entry entry = new Gtk.Entry (this.Name);
+			dialog.VBox.PackStart (entry, false, false, 5);
+			dialog.DefaultResponse = ResponseType.Ok;
+			
+			dialog.ShowAll ();
+			ResponseType r = (ResponseType) dialog.Run ();
+			
+			if (r == ResponseType.Ok)
+			{
+				this.Name = entry.Text;
+			}
+			
+			dialog.Destroy ();
+		}
+	}
+}

Added: branches/bgarret/src/EditableCellRenderer.cs
==============================================================================
--- (empty file)
+++ branches/bgarret/src/EditableCellRenderer.cs	Thu Jan 31 21:38:51 2008
@@ -0,0 +1,54 @@
+// EditableCellRenderer.cs
+//
+//  Copyright (C) 2008 Benoit Garret
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+//
+
+using System;
+using Gtk;
+
+namespace Hipo
+{
+	public enum Column {
+		Icon,
+		Name,
+		Count,
+		SourceType,
+		Artist,
+		Album,
+		Title,
+		Genre,
+		Id
+	}
+	
+	internal class EditableCellRenderer : CellRendererText
+	{
+		private Column column;
+		
+		public EditableCellRenderer ()
+		{
+			base.Editable = true;
+			base.Ellipsize = Pango.EllipsizeMode.End;
+		}
+		
+		public Column Column
+		{
+			get { return column; }
+			set { column = value; }
+		}
+	}
+}

Modified: branches/bgarret/src/HipoMain.cs
==============================================================================
--- branches/bgarret/src/HipoMain.cs	(original)
+++ branches/bgarret/src/HipoMain.cs	Thu Jan 31 21:38:51 2008
@@ -3,6 +3,7 @@
 using Mono.Unix;
 using Gtk;
 using Glade;
+using GLib;
 
 namespace Hipo
 {
@@ -22,27 +23,61 @@
 		
 		public void Run (string[] args)
 		{
-			AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler;
+			AppDomain.CurrentDomain.UnhandledException += AppUnhandledExceptionHandler;
+			GLib.ExceptionManager.UnhandledException += GlibUnhandledExceptionHandler;
 			
-			HipoMainWindow hmw = new HipoMainWindow ();
-			hmw.CreateWindow (args);
+			new HipoMainWindow (args);
 		}
 		
-		public void UnhandledExceptionHandler (object o, UnhandledExceptionEventArgs args)
+		public void AppUnhandledExceptionHandler (object o, UnhandledExceptionEventArgs args)
 		{
-			Glade.XML gxml = new Glade.XML ("errordialog.glade", "errorDialog");
+			UnhandledExceptionHandler ((Exception)args.ExceptionObject);
+		}
+		
+		public void GlibUnhandledExceptionHandler (GLib.UnhandledExceptionArgs args)
+		{
+			UnhandledExceptionHandler ((Exception)args.ExceptionObject);
+		}
+		
+		public void UnhandledExceptionHandler (Exception e)
+		{
+			string stack = GetStackTrace (e);
+			string msg = GetMessage (e);
 			
-			stackTrace = (TextView)gxml.GetWidget ("stackTrace");
-			message = (Label)gxml.GetWidget ("message");
-			errorDialog = (Dialog)gxml.GetWidget ("errorDialog");				
+			Tools.Log (this, "Uh oh, something went wrong...");
 			
-			Exception e = (Exception) args.ExceptionObject;
+			Gtk.Application.Invoke (delegate (object o, EventArgs args) {
+				
+				Glade.XML gxml = new Glade.XML ("errordialog.glade", "errorDialog");
+				
+				stackTrace = (TextView)gxml.GetWidget ("stackTrace");
+				message = (Label)gxml.GetWidget ("message");
+				errorDialog = (Dialog)gxml.GetWidget ("errorDialog");				
+				
+				stackTrace.Buffer.Text = stack;
+				message.Text = msg;
+				errorDialog.Run ();
+				
+				errorDialog.Destroy ();
+			});
 			
-			stackTrace.Buffer.Text = e.StackTrace;
-			message.Text = e.Message;
-			errorDialog.Run ();
+			Application.RunIteration ();
 		}
 		
+		public string GetMessage (Exception e)
+		{
+			if (e.InnerException != null)
+				return String.Concat (e.Message, " : ", GetMessage (e.InnerException));
+			else
+				return e.Message;
+		}
 		
+		public string GetStackTrace (Exception e)
+		{
+			if (e.InnerException != null)
+				return String.Concat (GetStackTrace (e.InnerException), "\n::End of inner stack trace::\n", e.StackTrace);
+			else
+				return e.StackTrace;
+		}
 	}
 }

Modified: branches/bgarret/src/HipoMainWindow.cs
==============================================================================
--- branches/bgarret/src/HipoMainWindow.cs	(original)
+++ branches/bgarret/src/HipoMainWindow.cs	Thu Jan 31 21:38:51 2008
@@ -1,603 +1,243 @@
-/* Hipo - iPod management tool
- *
- * Pedro Villavicencio Garrido <pvillavi gnome org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * (C) Copyright 2006-2007 Pedro Villavicencio Garrido <pvillavi gnome org>.
- */
+// HipoMainWindow.cs
+//
+//  Copyright (C) 2008 Bneoit Garret
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+//
 
 using System;
-using System.IO;
-using System.Threading;
-using System.Collections;
-using System.Collections.Generic;
-using System.Text;
 using Gtk;
-using Gdk;
 using Glade;
-using Gnome;
-using IPod;
+using NDesk.DBus;
 using Mono.Unix;
+using IPod;
 
 namespace Hipo
 {
-	internal class EditableCellRenderer : CellRendererText
-	{
-		private int column;
-		
-		public EditableCellRenderer ()
-		{
-			base.Editable = true;
-			base.Ellipsize = Pango.EllipsizeMode.End;
-		}
-		
-		public int Column
-		{
-			get { return column; }
-			set { column = value; }
-		}
-	}
-	
-	public enum SourceType {
-		Ipod,
-		Playlist,
-		SmartPlaylist
-	}
-	
 	public class HipoMainWindow
 	{
-
-		[Widget] private Gtk.Window hipoWindow;
-		[Widget] private Gtk.VBox vbox1;
-		[Widget] private Gtk.TreeView tracksView;
-		[Widget] private Gtk.TreeView plistView;
-		[Widget] private Gtk.Entry filterEntry;
-		[Widget] private Gtk.ProgressBar ipodCapacityBar;
+		[Widget] private Window hipoWindow;
+		[Widget] private VBox menuBar;
+		[Widget] private ScrolledWindow sourceListScroll;
+		[Widget] private ScrolledWindow sourceScroll;
+		[Widget] private Viewport defaultSourceWidget;
+		[Widget] private HBox searchBox;
+		[Widget] private Entry defaultSearchEntry;
+		[Widget] private VBox sourceListBox;
 		
+		private SourceList sourceList;
+		private DeviceCombo combo;
 		private Glade.XML gxml;
 		private Gnome.Program program;
-		private DeviceCombo combo;
-		private IPod.Device device = null;
-		private TrackDatabase db = null;
-		private TracksView  tracks;
-		private TreeModelFilter store_filter;
-		private PlaylistView playlists;
-		private Label numTracks;
-		private ThreadNotify notify;
-		private string[] uris;
-		private UIManager uim = null;
-		private Gtk.Menu menu;
-		private Hashtable menuTable;
-		private Gtk.Image coverpreview;
-		private ImportDialog pdialog;
+		private ImportDialog progressDialog;
+		private CapacityBar capacityBar;
 		
-		ActionGroup group = null;
-			 
-		private static TargetEntry [] tracksview_source_entries = {
-                        new TargetEntry ("text/uri-list", 0, 0),
-			new TargetEntry ("application/x-hipo", 0, 0)
-                };
-
-                private static TargetEntry [] playlist_dest_entries = {
-                        new TargetEntry ("application/x-hipo", 0, 0)
-                };
-
-		public void CreateWindow (string [] args)
+		private Widget sourceWidget;
+		private Entry searchEntry;
+		
+		public HipoMainWindow (string[] args)
 		{
-			program = new Program (Defines.PACKAGE, Defines.VERSION, Modules.UI, args);
-
+			// disable logging
+			Tools.LogEnabled = false;
+			
+			program = new Gnome.Program (Defines.PACKAGE, Defines.VERSION, Gnome.Modules.UI, args);
+			
+			// create the device combo and hook up device changed event
 			combo = new DeviceCombo ();
-
-			gxml = new Glade.XML (null, "hipo.glade", "hipoWindow", null);
-			gxml.Autoconnect (this);
-
-			tracks = new TracksView ();
-			playlists = new PlaylistView ();
+			combo.Changed += OnDeviceChanged;
 			
-			ActionEntry[] entries =  {
-
-				new ActionEntry ("FileMenu", null, Catalog.GetString ("_File"), null, null, null),
-				new ActionEntry ("EditMenu", null, Catalog.GetString ("_Edit"), null, null, null),
-				new ActionEntry ("HelpMenu", null, Catalog.GetString ("_Help"), null, null, null),
-				new ActionEntry ("AddFile", Gtk.Stock.Add, Catalog.GetString ("_Add File..."), null,
-						 Catalog.GetString ("Add a file to your iPod"), OnAddActivated),
-				new ActionEntry ("AddFolder", Gtk.Stock.Add, Catalog.GetString ("A_dd Folder..."),  "<control>O",
-						 Catalog.GetString ("Add a folder to your iPod"), OnAddFolder),
-				new ActionEntry ("Remove", Gtk.Stock.Remove, null, null,
-						 Catalog.GetString ("Remove a file from your iPod"), OnRemoveActivated),
-				new ActionEntry ("AddToPlaylist", Gtk.Stock.Add, Catalog.GetString ("Add to Playlist..."), null,
-						 Catalog.GetString ("Add file to a Playlist"), null),
-
-				new ActionEntry ("TrackProperties", Gtk.Stock.Properties, Catalog.GetString ("Track Properties"), null,
-						 Catalog.GetString ("Track Properties"), OnTrackProperties),
-				
-				new ActionEntry ("RemoveFromPlaylist", Gtk.Stock.Remove, Catalog.GetString ("_Remove from Playlist"), null,
-						 Catalog.GetString ("Remove the track from the Playlist"), OnRemoveFromPlaylist),
-				new ActionEntry ("Eject", null, Catalog.GetString ("_Eject"), null, null, OnEjectActivated),
-				new ActionEntry ("Quit", Gtk.Stock.Quit, null, "<control>Q", null, OnQuitActivated),
-				new ActionEntry ("Preferences", Gtk.Stock.Preferences, null, null,
-						 null, OnPreferences),
-				new ActionEntry ("Help", Gtk.Stock.Help, null, "F1",
-						 null, OnHelp),
-				new ActionEntry ("About", Gnome.Stock.About, null, null,
-						 null, OnAboutActivated),
-
-				new ActionEntry ("NewPlaylist", Gtk.Stock.New, Catalog.GetString ("New Playlist"), null,
-						 Catalog.GetString ("Create a new Playlist"), OnNewPlaylist),
-				new ActionEntry ("DeletePlaylist", Gtk.Stock.Remove, Catalog.GetString ("Delete Playlist"), null,
-						 Catalog.GetString ("Delete the Playlist"), OnDeletePlaylist),
-				new ActionEntry ("RenamePlaylist", Gtk.Stock.Copy, Catalog.GetString ("Rename Playlist"), null,
-						 Catalog.GetString ("Rename the Playlist"), OnRenamePlaylist),
-
-				new ActionEntry ("OnDeviceProperties", Gtk.Stock.Properties, Catalog.GetString ("Device Properties"), null,
-						 Catalog.GetString ("Device Properties"), OnDeviceProperties)
-			};
-
-			group = new ActionGroup ("Hipo");
-			group.Add (entries);
-
-			uim = new UIManager ();
-			uim.InsertActionGroup (group, 0);
-			uim.AddUiFromResource ("hipo.xml");
-			hipoWindow.AddAccelGroup (uim.AccelGroup);
+			// Even though we don't (currently) use dbus, ipod-sharp does.
+			// Without hooking up the glib main loop, some ipod-sharp functionality breaks.
+			BusG.Init ();
 			
-			numTracks = new Gtk.Label ("(0)");
-			numTracks.UseMarkup = true;
+			gxml = new Glade.XML (null, "hipo.glade", "hipoWindow", null);
+			gxml.Autoconnect (this);
 			
+			// set window icon
 			hipoWindow.Icon = Gnome.IconTheme.Default.LoadIcon ("gnome-dev-ipod", 16, 0);
 			
-			vbox1.PackStart (uim.GetWidget ("/HipoMenu"), false, false, 0);
-			vbox1.ReorderChild (uim.GetWidget ("/HipoMenu"), 0);
-			menu = (Gtk.Menu) uim.GetWidget ("/ui/TracksPopup");
-			
-			CreateTreeView ();
+			// hook up window delete event
+			hipoWindow.DeleteEvent += OnDeleteEvent;
 			
-			tracksView.Model = tracks.GetModel ();
-			plistView.Model = playlists.GetModel ();
-
-			store_filter = new Gtk.TreeModelFilter (tracksView.Model, null);
-			store_filter.VisibleFunc = SearchFilterFunc;
-			filterEntry.Changed += SearchFor;
+			// create action entries
+			ActionEntry[] entries =  {
 
-			combo.Changed += OnDeviceChanged;
-			
-			tracksView.ButtonPressEvent += OnTracksButtonPress;
-			tracksView.PopupMenu += OnTracksPopupMenu;
+				new ActionEntry ("FileMenu",
+				                 null,
+				                 Catalog.GetString ("_File"),
+				                 null,
+				                 null,
+				                 null),
+				new ActionEntry ("AddFile",
+				                 Stock.Add, Catalog.GetString ("_Add File..."),
+				                 null,
+				                 Catalog.GetString ("Add a file to your iPod"),
+				                 OnAddActivated),
+				new ActionEntry ("AddFolder",
+				                 Stock.Add,
+				                 Catalog.GetString ("A_dd Folder..."),
+				                 "<control>O",
+				                 Catalog.GetString ("Add a folder to your iPod"),
+				                 OnAddFolder),
+				new ActionEntry ("NewPlaylist",
+				                 Stock.New,
+				                 Catalog.GetString ("New Playlist"),
+				                 null,
+				                 Catalog.GetString ("Create a new Playlist"),
+				                 OnNewPlaylist),
+				new ActionEntry ("Eject",
+				                 null,
+				                 Catalog.GetString ("_Eject"),
+				                 null,
+				                 null,
+				                 OnEjectActivated),
+				new ActionEntry ("Quit",
+				                 Stock.Quit,
+				                 null,
+				                 "<control>Q",
+				                 null,
+				                 OnQuitActivated),
+				
+				new ActionEntry ("EditMenu",
+				                 null,
+				                 Catalog.GetString ("_Edit"),
+				                 null,
+				                 null,
+				                 null),
+				new ActionEntry ("Preferences",
+				                 Stock.Preferences,
+				                 null,
+				                 null,
+				                 null,
+				                 OnPreferences),
+				
+				new ActionEntry ("HelpMenu",
+				                 null,
+				                 Catalog.GetString ("_Help"),
+				                 null,
+				                 null,
+				                 null),
+				new ActionEntry ("Help",
+				                 Stock.Help,
+				                 null,
+				                 "F1",
+				                 null,
+				                 OnHelp),
+				new ActionEntry ("About",
+				                 Gnome.Stock.About,
+				                 null,
+				                 null,
+				                 null,
+				                 OnAboutActivated)
+			};
 			
+			// create the ui manager and the keyboard shortcuts
+			ActionGroup group = new ActionGroup ("Hipo");
+			group.Add (entries);
 			
-			tracksView.EnableModelDragSource (Gdk.ModifierType.Button1Mask,
-							  tracksview_source_entries, Gdk.DragAction.Copy);
-
-			tracksView.DragDataGet += OnTracksDragDataGet;
-			tracksView.Selection.Mode = SelectionMode.Multiple;
+			UIManager.Instance.InsertActionGroup (group, 0);
+			UIManager.Instance.AddUiFromResource ("menubar.xml");
+			hipoWindow.AddAccelGroup (UIManager.Instance.AccelGroup);
 			
-			plistView.ButtonPressEvent += OnPlaylistButtonPress;
-			plistView.PopupMenu += OnPlaylistPopupMenu;
+			// create the menu
+			menuBar.PackStart (UIManager.Instance.GetWidget ("/HipoMenu"), false, false, 0);
+			menuBar.ReorderChild (UIManager.Instance.GetWidget ("/HipoMenu"), 0);
 			
-			plistView.EnableModelDragDest (playlist_dest_entries, Gdk.DragAction.Copy);
+			// create the progress dialog
+			progressDialog = new ImportDialog (hipoWindow);
 			
-			plistView.DragDataReceived += OnPlistDragDataReceived;
-
-			tracksView.EnableModelDragDest (tracksview_source_entries, Gdk.DragAction.Copy);
-			tracksView.DragDataReceived += OnTracksDragDataReceived;
+			// create the capacity bar
+			capacityBar = new CapacityBar ();
+			sourceListBox.PackStart (capacityBar, false, false, 0);
 			
-			hipoWindow.DeleteEvent += OnDeleteEvent;
-			plistView.Selection.Changed += OnPlaylistSelectionChanged;
+			// create the source list
+			sourceList = SourceList.Instance;
+			sourceListScroll.Child = sourceList.View;
+			sourceListScroll.Child.ShowAll ();
 			
-			menuTable = new Hashtable ();
-			coverpreview = new Gtk.Image ();
-
-			pdialog = new ImportDialog (hipoWindow);
-
-			hipoWindow.ShowAll ();
-
-			SetDevice ();
-
-			program.Run ();
-		}
-
-		private void CreateTreeView ()
-		{
-			EditableCellRenderer cell = new EditableCellRenderer ();
-			cell.Edited += OnTrackEdit;
-			cell.Column = (int)TracksView.Column.Artist;
-			
-			TreeViewColumn column = new Gtk.TreeViewColumn (Catalog.GetString ("Artist"),
-									cell, "text", (int)TracksView.Column.Artist);
-			column.Resizable = true;
-			column.Expand = false;
-			column.SortIndicator = true;
-			column.SortColumnId = (int)TracksView.Column.Artist;
-			column.Sizing = TreeViewColumnSizing.Fixed;
-			column.FixedWidth = 200;
-			tracksView.AppendColumn (column);
-			
-			cell = new EditableCellRenderer ();
-			cell.Edited += OnTrackEdit;
-			cell.Column = (int)TracksView.Column.Album;
-				
-			column = new Gtk.TreeViewColumn (Catalog.GetString ("Album"),
-							 cell, "text", (int)TracksView.Column.Album);
-			column.Resizable = true;
-			column.Expand = false;
-			column.SortIndicator = true;
-			column.SortColumnId = (int)TracksView.Column.Album;
-			column.Sizing = TreeViewColumnSizing.Fixed;
-			column.FixedWidth = 200;
-			
-			tracksView.AppendColumn (column);
-			
-			cell = new EditableCellRenderer ();
-			cell.Edited += OnTrackEdit;
-			cell.Column = (int)TracksView.Column.Title;
-				
-			column = new Gtk.TreeViewColumn (Catalog.GetString ("Title"),
-							 cell, "text", (int)TracksView.Column.Title);
-			column.Resizable = true;
-			column.Expand = false;
-			column.SortIndicator = true;
-			column.SortColumnId = (int)TracksView.Column.Title;
-			column.Sizing = TreeViewColumnSizing.Fixed;
-			column.FixedWidth = 200;
-			
-			tracksView.AppendColumn (column);
-			
-			cell = new EditableCellRenderer ();
-			cell.Edited += OnTrackEdit;
-			cell.Column = (int)TracksView.Column.Genre;
-			
-			column = new Gtk.TreeViewColumn (Catalog.GetString ("Genre"),
-							 cell, "text", (int)TracksView.Column.Genre);
-			column.Resizable = true;
-			column.Expand = false;
-			column.SortIndicator = true;
-			column.SortColumnId = (int)TracksView.Column.Genre;
-			column.Sizing = TreeViewColumnSizing.Fixed;
-			column.FixedWidth = 100;
+			// the initial sourceWidget is the No device detected label
+			sourceWidget = defaultSourceWidget;
 			
-			tracksView.AppendColumn (column);
+			// ditto for the search entry
+			searchEntry = defaultSearchEntry;
 			
-			tracksView.HeadersVisible = true;
-			tracksView.HeadersClickable = true;
-
-			column = new Gtk.TreeViewColumn ("Icon", new Gtk.CellRendererPixbuf (), "pixbuf", (int)PlaylistView.Column.Icon);
-			column.Expand = false;
-			plistView.AppendColumn (column);
-			
-			cell = new EditableCellRenderer ();
-			cell.Edited += OnPlaylistEdit;
-			cell.Column = (int)PlaylistView.Column.Name;
-			
-			column = new Gtk.TreeViewColumn ("Name", cell, "text", (int)PlaylistView.Column.Name);
-			column.Expand = true;
-			plistView.AppendColumn (column);
-				
-			Gtk.CellRendererText celltext = new Gtk.CellRendererText ();
-			celltext.Foreground = "grey";
-			column = new Gtk.TreeViewColumn ("Counts", celltext, "text", (int)PlaylistView.Column.Count);
-			column.Expand = false;
-			plistView.AppendColumn (column);
+			// hook up the selection changed source list event
+			sourceList.SelectionChanged += OnSourceListSelectionChanged;			
 			
-			plistView.HeadersVisible = false;
-		}
-
-		[GLib.ConnectBefore]
-		private void OnTracksButtonPress (object o, ButtonPressEventArgs args)
-		{
-			switch (args.Event.Button)
-			{
-			case 3:
-				if (this.device != null) {
-					TracksPopupMenu (args.Event);
-					args.RetVal = true;
-				}
-				break;
-			}
-		}
-
-		private void TracksPopupMenu (Gdk.EventButton ev)
-		{
-			if (tracksView.Selection.CountSelectedRows () != 0) {
-				
-				Gtk.Menu playlistMenu = new Gtk.Menu ();
-				Gtk.MenuItem addToPlaylistItem = (MenuItem) uim.GetWidget ("/ui/TracksPopup/AddToPlaylist");
-				
-				menuTable.Clear ();
+			Tools.Log (this, "Finished creating the window");
 			
-				foreach (Playlist playlist in db.Playlists) {
-					ImageMenuItem item = new ImageMenuItem (playlist.Name);
-					item.Image = new Gtk.Image (Gnome.IconTheme.Default.LoadIcon ("stock_playlist", 16, 0));
-					item.Activated += OnAddToPlaylist;
-					menuTable[item] = playlist;
-					playlistMenu.Append (item);
-				}
+			hipoWindow.ShowAll ();
 			
-				addToPlaylistItem.Submenu = playlistMenu;
-				
-				menu.ShowAll ();
-				playlistMenu.ShowAll ();
+			SetDevice ();
 			
-				menu.Popup (null, null, null, (ev != null) ? ev.Button : 0,
-					    (ev != null) ? ev.Time : 0);
-			}
-		}
-
-		private void OnTracksPopupMenu (object o, PopupMenuArgs args)
-		{
-			TracksPopupMenu (null);
-		}
-
-		[GLib.ConnectBefore]
-		private void OnPlaylistButtonPress (object o, ButtonPressEventArgs args)
-		{
-			switch (args.Event.Button)
-			{
-			case 3:
-				if (this.device != null) {
-					PlaylistPopupMenu (args.Event);
-				}
-				break;
-			}             
+			program.Run ();
 		}
 		
-		private void OnTrackEdit (object o, EditedArgs args)
+		public Window Window
 		{
-			TreeIter iter = TreeIter.Zero;
-			ListStore store = tracks.GetModel ();
-			EditableCellRenderer cell = (EditableCellRenderer) o;
-			bool modified = false;
-			
-
-			if (!store.GetIter (out iter, new TreePath (args.Path)))
-				return;
-			
-			long trackId = (long) store.GetValue (iter, (int)TracksView.Column.Id);
-			Track track = tracks.GetTrackbyId (this.db, trackId);
-
-			switch (cell.Column)
-			{
-				case (int)TracksView.Column.Artist:
-					if (args.NewText != track.Artist)
-					{
-						track.Artist = args.NewText;
-						modified = true;
-					}
-					break;
-				case (int)TracksView.Column.Album:
-					if (args.NewText != track.Album)
-					{
-						track.Album = args.NewText;
-						modified = true;
-					}
-					break;
-				case (int)TracksView.Column.Title:
-					if (args.NewText != track.Title)
-					{
-						track.Title = args.NewText;
-						modified = true;
-					}
-					break;
-				case (int)TracksView.Column.Genre:
-					if (args.NewText != track.Genre)
-					{
-						track.Genre = args.NewText;
-						modified = true;
-					}
-					break;
-				default:
-					break;
-			}
-			
-			if (modified)
-			{
-				tracks.UpdateStore (track, iter);
-				
-				Thread thr = new Thread (new ThreadStart (SaveDB));
-				thr.Start ();
+			get {
+				return hipoWindow;
 			}
 		}
 		
-		private void OnPlaylistEdit (object o, EditedArgs args)
-		{
-			TreeIter iter = TreeIter.Zero;
-			TreeStore store = playlists.GetModel ();
-			bool modified = false;
-
-			if (!store.GetIter (out iter, new TreePath (args.Path)))
-				return;
-			else
-			{
-				string plistName = (string) store.GetValue (iter, (int)PlaylistView.Column.Name);
-
-				if (args.NewText != plistName)
-				{
-					if (playlists.UpdatePlaylistName (db, iter, args.NewText))
-						modified = true;
-				}
-			}
-			
-			if (modified)
-			{
-				Thread thr = new Thread (new ThreadStart (SaveDB));
-				thr.Start ();
-			}
-		}
-
-		private void OnRenamePlaylist (object o, EventArgs args)
+		private void SetDevice (IPod.Device device)
 		{
-			TreeModel model;
-			TreeIter iter;
-			bool modified = false;
+			capacityBar.Device = device;
 			
-			if (plistView.Selection.GetSelected (out model, out iter)) 
+			if (device == null)
 			{
-				string plistName = (string) model.GetValue (iter, (int)PlaylistView.Column.Name);
-				
-				Dialog dialog = new Dialog (Catalog.GetString ("Rename the Playlist"), hipoWindow, Gtk.DialogFlags.DestroyWithParent);
+				// deactivate the menu options
+				SetGreyedObjects (true);
 				
- 				dialog.Modal = true;
- 				dialog.AddButton ("Cancel", ResponseType.Close);
- 				dialog.AddButton ("OK", ResponseType.Ok);
+				progressDialog.TrackDatabase = null;
 				
-				Gtk.Entry entry = new Gtk.Entry (plistName);
-				dialog.VBox.PackStart (entry, false, false, 5);
-				dialog.DefaultResponse = ResponseType.Ok;
+				sourceList.SelectedSource = null;
+				sourceList.Clear ();
 				
-				dialog.ShowAll ();
-				ResponseType r = (ResponseType) dialog.Run ();
+				Tools.Log (this, "No device set");
 				
-				if (r == ResponseType.Ok)
-				{
-					if (entry.Text != plistName)
-					{
-						if (playlists.UpdatePlaylistName (db, iter, entry.Text))
-							modified = true;
-					}
-				}
-				
-				dialog.Destroy ();
+				return;
 			}
 			
-			if (modified)
-			{
-				Thread thr = new Thread (new ThreadStart (SaveDB));
-				thr.Start ();
-			}
-		}
-	
-		private void PlaylistPopupMenu (Gdk.EventButton ev)
-		{
-			TreeModel model;
-			TreeIter iter;
+			// activate the menu options
+			SetGreyedObjects (false);
 			
-			Gtk.Menu menupl;
-
-			if (plistView.Selection.GetSelected (out model, out iter)) {
-				
-				string plistName = (string) model.GetValue (iter, (int)PlaylistView.Column.Name);
-				Playlist plist = null;
-
-				if (model.IterHasChild (iter)) {
-					menupl = (Gtk.Menu) uim.GetWidget ("/ui/DevicePopup");
-					menupl.ShowAll ();
-
-					menupl.Popup (null, null, null, (ev != null) ? ev.Button : 0,
-						      (ev != null) ? ev.Time : 0);
-				} else {
-					if ((plist = this.db.LookupPlaylist (plistName)) != null) {
-						menupl = (Gtk.Menu) uim.GetWidget ("/ui/PlaylistPopup");
-						menupl.ShowAll ();
-						
-						menupl.Popup (null, null, null, (ev != null) ? ev.Button : 0,
-							      (ev != null) ? ev.Time : 0);
-					}                                         
-				}
-			}
-		}
-
-		private void OnPlaylistPopupMenu (object o, PopupMenuArgs args)
-		{
-			PlaylistPopupMenu (null);
-		}
-
-		private void OnDeletePlaylist (object o, EventArgs args)
-		{
-			TreeModel model;
-			TreeIter iter;
+			progressDialog.TrackDatabase = device.TrackDatabase;
 			
-			if (plistView.Selection.GetSelected (out model, out iter)) 
-			{
-				string plistName = (string) model.GetValue (iter, (int)PlaylistView.Column.Name);
-				
-				Playlist plist = this.db.LookupPlaylist (plistName);
-				this.db.RemovePlaylist (plist);
-
-				RefreshPlaylistView ();
-				playlists.RefreshDevice (this.device);
-				playlists.RemovePlaylist (iter);
-			}
-
-			Thread thr = new Thread (new ThreadStart (SaveDB));
-			thr.Start ();
-		}
-
-
-		private void OnNewPlaylist (object o, EventArgs args)
-		{
-			Gtk.HBox hbox = new Gtk.HBox ();
-			Gtk.Label name = new Gtk.Label (Catalog.GetString ("Name: "));
-			Gtk.Entry entry = new Gtk.Entry ();
-			
-			Gtk.Dialog dialog = new Gtk.Dialog (Catalog.GetString ("New Playlist"), this.hipoWindow,
-							    DialogFlags.DestroyWithParent,
-							    Gtk.Stock.Cancel, ResponseType.Cancel,
-							    Gtk.Stock.Ok, ResponseType.Accept);
-
-			hbox.BorderWidth = 5;
-			hbox.Add (name);
-			hbox.Add (entry);
-			hbox.ShowAll ();
-			dialog.VBox.Add (hbox);
-
-			ResponseType res = (ResponseType) dialog.Run ();
-			dialog.Destroy ();
+			// create the Saver instance
+			Saviour.Instantiate (device);
 			
-			if (res == ResponseType.Accept)
-			{
-				Playlist plist = null;
-				if ((plist = this.db.CreatePlaylist (entry.Text)) != null)
-				{
-					Thread thr = new Thread (new ThreadStart (SaveDB));
-					thr.Start ();
-
-					playlists.AddListToStore (plist);
-				}
-			}
-		}
-
-		private void SaveDB ()
-		{
-			lock (this.db) {
-				this.db.Save ();
-			}
-
-			notify.WakeupMain ();
-		}
-		
-		private void OnDeviceChanged (object o, EventArgs args)
-		{
-			this.device = combo.ActiveDevice;
-			SetDevice (this.device);
-		}
-		
-		private void SetDevice (IPod.Device device)
-		{
-			if (device == null)
+			// create the device source
+			sourceList.Add (new DeviceSource (device));
+			
+			// create tracks source and add it to the source list
+			sourceList.Add (new TracksSource (device.TrackDatabase));
+			
+			// for each playlist in the track database create a playlist source and add it to the source list
+			foreach (Playlist playlist in device.TrackDatabase.Playlists)
 			{
-				SetGreyedObjects (false);
-				return;
+				sourceList.Add (new PlaylistSource (playlist));
 			}
 			
-			SetGreyedObjects (true);
+			// select the tracks source
+			sourceList.SelectedSource = SourceList.Instance.Tracks;
 			
-			this.device = device;
-
-			Thread thr = new Thread (new ThreadStart (PopulateView));
-			thr.Start ();
-			notify = new ThreadNotify (new ReadyEvent (RefreshPlaylistView));
+			sourceList.ExpandAll ();
+			
+			Tools.Log (this, "Set device {0}", device.Name);
 		}
 		
 		private void SetDevice ()
@@ -608,98 +248,32 @@
 				Console.Error.WriteLine (e);
 			}
 		}
-
-		private void SetGreyedObjects (bool greyed)
-		{
-			if (!greyed) {
-				ipodCapacityBar.Text = Catalog.GetString ("No iPod Found");
-				ipodCapacityBar.Fraction = 0.0;
-				playlists.Clear ();
-				tracks.Clear ();
-			}
-
-			group["AddFile"].Sensitive = greyed;
-			group["AddFolder"].Sensitive = greyed;
-			group["Remove"].Sensitive = greyed;
-			group["Eject"].Sensitive = greyed;
-			group["NewPlaylist"].Sensitive = greyed;
-			group["OnDeviceProperties"].Sensitive = greyed;
-		}
 		
-		private void PopulateView ()
+		private void SetGreyedObjects (bool greyed)
 		{
-			Gtk.TreeIter iter;
-			
-			this.db = this.device.TrackDatabase;
-			pdialog.TrackDatabase = this.db;
-			
-			playlists.AddDeviceToStore (this.device);
-			
-			foreach (Playlist plist in this.db.Playlists)
+			foreach (ActionGroup group in UIManager.Instance.ActionGroups)
 			{
-				playlists.AddListToStore (plist);
-			}
-			
-			Thread thrb = new Thread (new ThreadStart (PopulateTracksView));
-			thrb.Start ();
-
-			if (plistView.Model.GetIterFirst (out iter)) {
-				
-				if (plistView.Model.IterHasChild (iter)) {
-					plistView.ExpandAll ();
+				if (group.Name == "Hipo")
+				{
+					group["AddFile"].Sensitive = !greyed;
+					group["AddFolder"].Sensitive = !greyed;
+					group["Eject"].Sensitive = !greyed;
+					group["NewPlaylist"].Sensitive = !greyed;
 				}
 			}
 		}
-
-		private void PopulateTracksView ()
-		{
-			foreach (Track track in this.db.Tracks)
-			{
-				tracks.AddTrackToStore (track);
-			}
-
-			notify.WakeupMain ();
-		}
-
-		private void OnAddFolder (System.Object o, EventArgs args)
-		{
-			Gtk.FileChooserDialog fileChooser = new Gtk.FileChooserDialog (Catalog.GetString ("Select a folder to add"),
-										       hipoWindow,
-										       FileChooserAction.SelectFolder,
-										       Gtk.Stock.Cancel, ResponseType.Cancel,
-										       Gtk.Stock.Add, ResponseType.Accept);
-			
-			fileChooser.LocalOnly = true;
-			
-			ResponseType res = (ResponseType) fileChooser.Run ();
-			uris = fileChooser.Uris;
-			fileChooser.Destroy ();
-			
-			if (res == ResponseType.Accept)
-			{
-				Thread thr = new Thread (new ThreadStart (AddFolder));
-				thr.Start ();
-			}
-		}
-
-		private void AddFolder ()
-		{
-			if (tracks.AddFolder (db, uris)) {
-				playlists.RefreshDevice (this.device);
-				SaveDB ();
-				notify.WakeupMain ();
-			}
-		}
 		
 		private void OnAddActivated (System.Object o, EventArgs args)
 		{
-			FileFilter filter = new Gtk.FileFilter ();
+			string[] uris;
 			
-			Gtk.FileChooserDialog fileChooser  = new Gtk.FileChooserDialog (Catalog.GetString ("Select the file to add"),
+			FileFilter filter = new FileFilter ();
+			
+			FileChooserDialog fileChooser  = new FileChooserDialog (Catalog.GetString ("Select the file to add"),
 											hipoWindow,
 											FileChooserAction.Open,
-											Gtk.Stock.Cancel, ResponseType.Cancel,
-											Gtk.Stock.Add, ResponseType.Accept);
+											Stock.Cancel, ResponseType.Cancel,
+											Stock.Add, ResponseType.Accept);
 			
 			fileChooser.SelectMultiple = true;
 			fileChooser.LocalOnly = true;
@@ -709,548 +283,116 @@
 			filter.AddMimeType ("audio/x-m4a");
 			fileChooser.AddFilter (filter);
 			
-			ResponseType res = (ResponseType) fileChooser.Run ();
+			ResponseType res = (ResponseType)fileChooser.Run ();
 			uris = fileChooser.Uris;
 			
 			fileChooser.Destroy ();
 			
 			if (res == ResponseType.Accept)
 			{
-				Thread thr = new Thread (new ThreadStart (AddTrack));
-				thr.Start ();
-			}
-		}
-
-		private void AddTrack ()
-		{
-			bool modified = false;
-			
-			foreach (string urin in uris)
-			{
-				Uri uri = new Uri (urin);
-				modified = tracks.AddTrack (this.db, uri.LocalPath);
-			}
-
-			if (modified) {
-				Thread thr = new Thread (new ThreadStart (SaveDB));
-				thr.Start ();
-		      
-				playlists.RefreshDevice (this.device);
-				notify.WakeupMain ();
+				sourceList.Tracks.AddTracks (uris, true);
 			}
 		}
-
-		private void OnAddToPlaylist (System.Object o, EventArgs args)
-		{
-			Playlist playlist = (Playlist) menuTable[o];
-
-			if (playlist == null)
-				return;
-
-			TreeIter iter;
-			TreeModel model;
-
-			Array treePaths = tracksView.Selection.GetSelectedRows (out model);
-
-			foreach (TreePath tPath in treePaths)
-			{
-				if (model.GetIter (out iter, tPath))
-				{
-					long trackId = (long) model.GetValue (iter, (int)TracksView.Column.Id);
-				
-					foreach (Track track in this.db.Tracks)
-					{
-						if (track.Id == trackId)
-							playlist.AddTrack (track);
-					}
-				}
-			}
-
-			Thread thr = new Thread (new ThreadStart (SaveDB));
-			thr.Start ();
-
-			playlists.UpdateTrackNumber (this.db, playlist);
-		}
 		
-	      	private void OnRemoveActivated (System.Object o, EventArgs args)
+		private void OnAddFolder (System.Object o, EventArgs args)
 		{
-			TreeIter iter;
-			TreeModel model;
-			ListStore store;
-			Gtk.HBox hbox;
-			Gtk.ScrolledWindow scroll;
-			TreeView view;
-			Queue iterQueue;
-
-			if (tracksView.Selection.CountSelectedRows() < 1)
-				return;
+			string[] uris;
 			
-			iterQueue = new Queue ();
-			hbox = new Gtk.HBox ();
-			hbox.BorderWidth = 5;
-
-			scroll = new Gtk.ScrolledWindow ();
-			scroll.ShadowType = ShadowType.In;
-			scroll.VscrollbarPolicy = PolicyType.Automatic;
-			scroll.HscrollbarPolicy = PolicyType.Automatic;
-
-			store = new Gtk.ListStore (typeof (string));
-			view = new Gtk.TreeView ();
-			view.AppendColumn ("Songs", new Gtk.CellRendererText (), "text", 0);
-
-			Array treePaths = tracksView.Selection.GetSelectedRows (out model);
+			FileChooserDialog fileChooser = new FileChooserDialog (Catalog.GetString ("Select a folder to add"),
+			                                                       hipoWindow,
+			                                                       FileChooserAction.SelectFolder,
+			                                                       Stock.Cancel, ResponseType.Cancel,
+			                                                       Stock.Add, ResponseType.Accept);
 			
-			MessageDialog dialog = new MessageDialog (hipoWindow,
-								  DialogFlags.DestroyWithParent,
-								  MessageType.Question,
-								  ButtonsType.OkCancel,
-								  String.Format ("<b>{0}</b>",
-										 Catalog.GetString ("Do you really want to remove the song/s?"))
-				);
+			fileChooser.LocalOnly = true;
 			
-			dialog.Resizable = true;
+			ResponseType res = (ResponseType) fileChooser.Run ();
+			uris = fileChooser.Uris;
+			fileChooser.Destroy ();
 			
-			foreach (TreePath tPath in treePaths)
+			if (res == ResponseType.Accept)
 			{
-				if (model.GetIter (out iter, tPath)) {
-					
-					string Artist = (string) model.GetValue (iter, (int)TracksView.Column.Artist);
-					string Album = (string) model.GetValue (iter, (int)TracksView.Column.Album);
-					string Title = (string) model.GetValue (iter, (int)TracksView.Column.Title);
-					
-					store.AppendValues (String.Format ("{0} - {1} - {2}", Artist, Album, Title));
-				}
+				sourceList.Tracks.AddFolder (uris, true);
 			}
+		}
+		
+		private void OnNewPlaylist (object o, EventArgs args)
+		{
+			HBox hbox = new HBox ();
+			Label name = new Label (Catalog.GetString ("Name: "));
+			Entry entry = new Entry ();
+			
+			Dialog dialog = new Dialog (Catalog.GetString ("New Playlist"), this.hipoWindow,
+			                            DialogFlags.DestroyWithParent,
+			                            Stock.Cancel, ResponseType.Cancel,
+			                            Stock.Ok, ResponseType.Accept);
 
-			view.Model = store;
-
-			scroll.Add (view);
-			hbox.Add (scroll);
+			hbox.BorderWidth = 5;
+			hbox.Add (name);
+			hbox.Add (entry);
 			hbox.ShowAll ();
 			dialog.VBox.Add (hbox);
-			
-			ResponseType response = (ResponseType) dialog.Run ();
+
+			ResponseType res = (ResponseType) dialog.Run ();
 			dialog.Destroy ();
 			
-			if (response == ResponseType.Ok)
+			if (res == ResponseType.Accept)
 			{
-				foreach (TreePath tPath in treePaths)
-				{
-					if (model.GetIter (out iter, tPath)) {
-						iterQueue.Enqueue (iter);
-						
-						long trackId = (long) model.GetValue (iter, (int)TracksView.Column.Id);
-						tracks.RemoveTracks (this.db, trackId);
-					}
-                                }
-
-				while (iterQueue.Count > 0)
-				{
-					TreeIter iterator = (TreeIter) iterQueue.Dequeue ();
-					tracks.RemoveTracks (iterator);
-				}
-
-				lock (this.db)
-					this.db.Save ();
-
-				RefreshPlaylistView ();
-				playlists.RefreshDevice (this.device);
-
+				Playlist playlist = sourceList.Tracks.CreatePlaylist (entry.Text);
+				sourceList.Add (new PlaylistSource (playlist));
 			}
 		}
-
-		[Widget] private Gtk.Dialog trackProperties;
-		[Widget] private Gtk.Entry artistEntry;
-		[Widget] private Gtk.Entry albumEntry;
-		[Widget] private Gtk.Entry titleEntry;
-		[Widget] private Gtk.Entry genreEntry;
-		[Widget] private Gtk.SpinButton numberSpin;
-		[Widget] private Gtk.Image artwork;
-		[Widget] private Gtk.Button openArtwork;
-		[Widget] private Gtk.Label titleLabel;
-		[Widget] private Gtk.Label numberLabel;
-                
-		private void OnTrackProperties (object o, EventArgs args)
+		
+		private void OnSourceListSelectionChanged (object o, SourceList.SelectionChangedArgs args)
 		{
-			Glade.XML xml = new Glade.XML (null, "hipo.glade", "trackProperties", null);
-			xml.Autoconnect (this);
-
-			bool modified = false;
-			TreeModel model;
-			Gdk.Pixbuf newCover = null;
-			string artist = "";
-			string album = "";
-			string title = "";
-			string genre = "";
-			int trackNumber = 0;
-			Gdk.Pixbuf image = null;
-			
-			/*
-			This way of doing things seems rather ugly to me (bgarret), as the conversion
-			TreeIter -> trackId -> track is done every time I iterate over the treePaths ArrayList.
-			*/
+			sourceScroll.Remove (sourceWidget);
+			searchBox.Remove (searchEntry);
 			
-			ArrayList treePaths = ArrayList.Adapter (tracksView.Selection.GetSelectedRows (out model));
-			ArrayList treeIters = new ArrayList ();
-			
-			foreach (TreePath treePath in treePaths)
+			if (args.Source != null)
 			{
-				TreeIter iter;
-				if (model.GetIter (out iter, treePath))
-				{
-					treeIters.Add (iter);
-				}
-			}
-			
-			if (treeIters.Count > 0)
-			{
-				foreach (TreeIter iter in treeIters)
-				{
-					long trackId = (long) model.GetValue (iter, (int)TracksView.Column.Id);
-					Track track = tracks.GetTrackbyId (this.db, trackId);
+				sourceWidget = args.Source.View;
+				searchEntry = args.Source.SearchEntry;
 				
-					/*
-					The values are filled in with the properties of the first track of the list.
-					A comparison is made with the subsequent tracks,
-					if the values are the same, nothing is changed,
-					if they are different, a blank value is put
-					*/
-					
-					if (treeIters.IndexOf (iter) == 0)
-					{
-						artist = track.Artist;
-						album = track.Album;
-						title = track.Title;
-						genre = track.Genre;
-						trackNumber = track.TrackNumber;
-						
-						foreach (ArtworkFormat format in this.device.LookupArtworkFormats (ArtworkUsage.Cover)) {
-
-							if (format != null) {
-								if (track.HasCoverArt (format)) 
-									image = ArtworkHelpers.ToPixbuf (format, track.GetCoverArt (format));
-							}
-						}
-						
-						if (treeIters.Count == 1)
-						{
-							/* artist name and track title properties */
-							trackProperties.Title = String.Format (Catalog.GetString ("{0} {1} Properties"),
-											       track.Artist, track.Title);
-						}
-						else
-						{
-							trackProperties.Title = Catalog.GetString ("Multiple tracks properties");
-                                                        titleEntry.Hide ();
-                                                        titleLabel.Hide ();
-                                                        numberLabel.Hide ();
-                                                        numberSpin.Hide ();
-						}
-					}
-					else
-					{
-						if (!artist.Equals("") && !artist.Equals (track.Artist))
-							artist = "";
-						
-						if (!album.Equals("") && !album.Equals (track.Album))
-							album = "";
-						
-						if (!title.Equals("") && !title.Equals (track.Title))
-							title = "";
-						
-						if (!genre.Equals("") && !genre.Equals (track.Genre))
-							genre = "";
-						
-						if ((trackNumber != 0) && (trackNumber != track.TrackNumber))
-							trackNumber = 0;
-						
-					}
-				}
-				
-				artistEntry.Text = artist;
-				albumEntry.Text = album;
-				titleEntry.Text = title;
-				genreEntry.Text = genre;
-				numberSpin.Value = trackNumber;
-				artwork.FromPixbuf = image;
 			}
-
-			openArtwork.Clicked += delegate {
-
-				FileFilter filter = new Gtk.FileFilter ();
-				
-				Gtk.FileChooserDialog fileChooser  = new Gtk.FileChooserDialog (Catalog.GetString ("Select an image"),
-												trackProperties,
-												FileChooserAction.Open,
-												Gtk.Stock.Cancel, ResponseType.Cancel,
-												Gtk.Stock.Add, ResponseType.Accept);
-				
-				fileChooser.LocalOnly = true;
-				filter.AddMimeType ("image/png");
-				filter.AddMimeType ("image/jpeg");
-				fileChooser.AddFilter (filter);
-				fileChooser.UpdatePreview += OnUpdatePreview;
-				fileChooser.PreviewWidget = coverpreview;
-				
-				ResponseType res = (ResponseType) fileChooser.Run ();
-				string uri = fileChooser.Uri;
-				
-				if (res == ResponseType.Accept)
-				{
-					Uri ur = new Uri (uri);
-					newCover = new Gdk.Pixbuf (ur.LocalPath);
-
-					artwork.FromPixbuf = newCover.ScaleSimple(200, 200, Gdk.InterpType.Bilinear);
-				}
-
-				fileChooser.Destroy ();
-			};
-
-			ResponseType response = (ResponseType) trackProperties.Run ();
-				
-			if (response == ResponseType.Ok)
+			else
 			{
-				if (artistEntry.Text != artist) {
-					modified = true;
-					foreach (TreeIter iter in treeIters)
-					{
-						long trackId = (long) model.GetValue (iter, (int)TracksView.Column.Id);
-						Track track = tracks.GetTrackbyId (this.db, trackId);
-						track.Artist = artistEntry.Text;
-					}
-				}
-
-				if (albumEntry.Text != album) {
-					modified = true;
-					foreach (TreeIter iter in treeIters)
-					{
-						long trackId = (long) model.GetValue (iter, (int)TracksView.Column.Id);
-						Track track = tracks.GetTrackbyId (this.db, trackId);
-						track.Album = albumEntry.Text;
-					}
-				}
-
-				if (titleEntry.Text != title) {
-					modified = true;
-					foreach (TreeIter iter in treeIters)
-					{
-						long trackId = (long) model.GetValue (iter, (int)TracksView.Column.Id);
-						Track track = tracks.GetTrackbyId (this.db, trackId);
-						track.Title = titleEntry.Text;
-					}
-				}
-
-				if (genreEntry.Text != genre) {
-					modified = true;
-					foreach (TreeIter iter in treeIters)
-					{
-						long trackId = (long) model.GetValue (iter, (int)TracksView.Column.Id);
-						Track track = tracks.GetTrackbyId (this.db, trackId);
-						track.Genre = genreEntry.Text;
-					}
-				}
-
-				if (numberSpin.Value != trackNumber) {
-					modified = true;
-					foreach (TreeIter iter in treeIters)
-					{
-						long trackId = (long) model.GetValue (iter, (int)TracksView.Column.Id);
-						Track track = tracks.GetTrackbyId (this.db, trackId);
-						track.TrackNumber = (int) numberSpin.Value;
-					}
-				}
-
-				if (newCover != null) {
-					
-					foreach (ArtworkFormat format in this.device.LookupArtworkFormats (ArtworkUsage.Cover)) {
-
-						// maybe is a good idea to set all the album of the current selected track with the new cover.
-						// we can set this on a gconf key.
-						
-						foreach (TreeIter iter in treeIters)
-						{
-							long trackId = (long) model.GetValue (iter, (int)TracksView.Column.Id);
-							Track track = tracks.GetTrackbyId (this.db, trackId);
-							track.SetCoverArt (format, ArtworkHelpers.ToBytes (format, newCover));
-						}
-					}
-					
-					modified = true;
-				}
+				sourceWidget = defaultSourceWidget;
+				searchEntry = defaultSearchEntry;
 			}
-
-			if (modified) {
-				foreach (TreeIter iter in treeIters)
-					{
-						long trackId = (long) model.GetValue (iter, (int)TracksView.Column.Id);
-						Track track = tracks.GetTrackbyId (this.db, trackId);
-						tracks.UpdateStore (track, iter);
-				}
-				
-				Thread thr = new Thread (new ThreadStart (SaveDB));
-				thr.Start ();
-			}
-
-			trackProperties.Destroy ();
+			
+			sourceScroll.Child = sourceWidget;
+			searchBox.PackStart (searchEntry, false, true, 0);
+			sourceWidget.ShowAll ();
+			searchEntry.ShowAll ();
 		}
-
-		[Widget] Gtk.Dialog deviceProperties;
-		[Widget] Gtk.Label serialLabel;
-		[Widget] Gtk.Label modelLabel;
-		[Widget] Gtk.Label generationLabel;
-		[Widget] Gtk.Label capacityLabel;
-		[Widget] Gtk.Label mountLabel;
-		[Widget] Gtk.Label spaceLabel;
-		[Widget] Gtk.Label firmwareLabel;
-		[Widget] Gtk.Entry nameEntry;
 		
-		private void OnDeviceProperties (object o, EventArgs args)
-		{
-			Glade.XML xml = new Glade.XML (null, "hipo.glade", "deviceProperties", null);
-			xml.Autoconnect (this);
-			/* ipod name properties ex: my ipod properties */
-			deviceProperties.Title = String.Format (Catalog.GetString ("{0} Properties"), this.device.Name);
-			nameEntry.Text = this.device.Name;
-
-			serialLabel.Text = this.device.SerialNumber;
-			modelLabel.Text = this.device.ModelString;
-			generationLabel.Text = String.Format ("{0}", this.device.Generation);
-			capacityLabel.Text = FormatString ((double) this.device.VolumeSize);
-			mountLabel.Text = this.device.MountPoint;
-			spaceLabel.Text = String.Format ("{0}%", (int) ((double) device.VolumeUsed / (double) device.VolumeSize * 100));
-			firmwareLabel.Text = this.device.FirmwareVersion;
-
-
-			ResponseType res = (ResponseType) deviceProperties.Run ();
-				
-			if (res == ResponseType.Ok)
-			{
-				if (this.device.Name != nameEntry.Text.Trim ())
-				{
-					this.device.Name = nameEntry.Text;
-					
-					SaveDB ();
-					playlists.RefreshDevice (this.device);
-				}
-			}
-
-			deviceProperties.Destroy ();
-		}
-
-		private void OnUpdatePreview (object o, EventArgs args)
+		private void OnDeviceChanged (object o, EventArgs args)
 		{
-			try {
-				if (((FileChooser)o).PreviewFilename != null) {
-					Gdk.Pixbuf cover = new Gdk.Pixbuf (((FileChooser)o).PreviewFilename);
-					
-					coverpreview.Pixbuf = cover.ScaleSimple(150, 150, Gdk.InterpType.Bilinear);
-					
-					coverpreview.Show ();
-				}
-			} catch (Exception e) {
-				coverpreview.Hide ();
-				Console.WriteLine (e.Message);
-			}
+			SetDevice (combo.ActiveDevice);
 		}
 		
-		private void OnPlaylistSelectionChanged (object o, EventArgs args)
-		{
-			TreeModel model;
-			TreeIter iter;
-			
-			if (((TreeSelection)o).GetSelected (out model, out iter)) {
-				int sourceType = (int) model.GetValue (iter, (int)PlaylistView.Column.SourceType);
-				filterEntry.Text = "";
-
-				switch (sourceType)
-				{
-					case (int)SourceType.Ipod:
-						menu = (Gtk.Menu) uim.GetWidget ("/ui/TracksPopup");
-						tracksView.Model = tracks.GetModel ();
-					break;
-
-					case (int)SourceType.Playlist:
-						IPod.Playlist plist;
-						if ((plist = this.db.LookupPlaylist ((string)model.GetValue (iter, (int)PlaylistView.Column.Name))) != null) {
-							menu = (Gtk.Menu) uim.GetWidget ("/ui/TracksPlaylistPopup");
-							tracksView.Model = playlists.GetModel (plist);
-						}
-					break;
-					
-					default:
-					break;
-				}
-				store_filter = new Gtk.TreeModelFilter (tracksView.Model, null);
-				store_filter.VisibleFunc = SearchFilterFunc;
-			}
-		}
-
-		private void OnRemoveFromPlaylist (object o, EventArgs args)
-		{
-			TreeModel model;
-			TreeModel modelpl;
-			TreeIter iterpl;
-			Playlist plist = null;
-
-			Queue iterQueue = new Queue ();
-
-			Array treePaths = tracksView.Selection.GetSelectedRows (out model);
-			
-			if (plistView.Selection.GetSelected (out modelpl, out iterpl))
-			{
-				string playlistName = (string) plistView.Model.GetValue (iterpl, (int)PlaylistView.Column.Name);
-				plist = this.db.LookupPlaylist (playlistName);
-			}
-
-			foreach (TreePath tPath in treePaths)
-			{
-				TreeIter iter;
-
-				if (model.GetIter (out iter, tPath))
-				{
-					long trackId = (long) model.GetValue (iter, (int)TracksView.Column.Id);
-					iterQueue.Enqueue (iter);
-
-					Track t = tracks.GetTrackbyId (this.db, trackId);
-
-					if (t != null)
-						plist.RemoveTrack (t);
-				}
-			}
-
-			while (iterQueue.Count > 0)
-			{
-				TreeIter iter = (TreeIter) iterQueue.Dequeue ();
-				playlists.RemoveFromPlaylist (iter);
-			}
-
-			SaveDB ();
-
-			playlists.UpdateTrackNumber (this.db, plist);
-		}
-
 		private void OnDeleteEvent (object o, DeleteEventArgs args)
 		{
 			OnQuitActivated (o, null);
 		}
-
+		
 		private void OnQuitActivated (object o, EventArgs args)
 		{
 			Application.Quit ();
 		}
-
+		
 		private void OnEjectActivated (object o, EventArgs args)
 		{
 			try {
-				device.Eject ();
-				Application.Quit ();
+				SourceList.Instance.Device.Eject ();
+				Gtk.Application.Quit ();
 			} catch (Exception e) {
 				MessageDialog error = new MessageDialog (hipoWindow,
 									 DialogFlags.DestroyWithParent,
 									 MessageType.Error,
 									 ButtonsType.Close,
 									 Catalog.GetString ("There was an error ejecting the iPod:")
-					);
+				                                         );
 				
 				error.SecondaryText = e.Message;
 				
@@ -1258,56 +400,55 @@
 				error.Destroy ();
 			}
 		}
-
+		
 		private void OnPreferences (object o, EventArgs args)
 		{
 			// FIXME
 		}
-
+		
 		private void OnHelp (object o, EventArgs args)
 		{
 			ShowHelp ("hipo.xml", null, hipoWindow.Screen, null);
 		}
-
-                // borrowed from tomboy
-                public void ShowHelp (string filename, string link_id, Gdk.Screen screen, Gtk.Window parent)
-                {
-                        try {
-                                Gnome.Help.DisplayDesktopOnScreen (
-                                        Gnome.Program.Get (),
-                                        Defines.GNOME_HELP_DIR,
-                                        filename,
-                                        link_id,
-                                        screen);
-                        } catch {
-                                string message =
-                                        Catalog.GetString ("The \"Hipo Manual\" could " +
-                                                           "not be found.  Please verify " +
-                                                           "that your installation has been " +
-                                                           "completed successfully.");
-                                MessageDialog dialog = new MessageDialog (parent,
-                                                                          Gtk.DialogFlags.DestroyWithParent,
-                                                                          Gtk.MessageType.Error,
-                                                                          Gtk.ButtonsType.Ok,
-                                                                          Catalog.GetString ("Help not found"),
-                                                                          message);
-                                dialog.Run ();
-                                dialog.Destroy ();
-                        }
-                }
-                        
-                
+		
+		// borrowed from tomboy
+		private void ShowHelp (string filename, string link_id, Gdk.Screen screen, Window parent)
+		{
+			try {
+				Gnome.Help.DisplayDesktopOnScreen (
+				              Gnome.Program.Get (),
+				              Defines.GNOME_HELP_DIR,
+				              filename,
+				              link_id,
+				              screen);
+			} catch {
+				string message =
+					Catalog.GetString ("The \"Hipo Manual\" could " +
+					                   "not be found.  Please verify " +
+					                   "that your installation has been " +
+					                   "completed successfully.");
+				MessageDialog dialog = new MessageDialog (parent,
+				                                          DialogFlags.DestroyWithParent,
+				                                          MessageType.Error,
+				                                          ButtonsType.Ok,
+				                                          Catalog.GetString ("Help not found"),
+				                                          message);
+				dialog.Run ();
+				dialog.Destroy ();
+			}
+		}
+		
 		private void OnAboutActivated (object o, EventArgs args)
 		{
-			Gtk.AboutDialog aboutDialog = new Gtk.AboutDialog ();
+			AboutDialog aboutDialog = new AboutDialog ();
 			string[] authors = { "Pedro Villavicencio Garrido <pvillavi gnome org>",
-					     "Felipe Barros S. <felipeb gnome cl>",
-                                             "Benoit Garret <benoit garret_gnome gadz org>" };
+				                 "Felipe Barros S. <felipeb gnome cl>",
+				                 "Benoit Garret <benoit garret_gnome gadz org>" };
 			string[] artists = { "Carlos Candia Flores <cerealk vtr net>",
-					     "Gabriel Bustos Farret  <lemut lemut com>"	};
-
-                        string[] documenters = { "Gabriel Felipe Cornejo Salas <gfc gnome cl>",
-                                                 "Basilio Kublik <basilio gnome cl>" };
+				                 "Gabriel Bustos Farret  <lemut lemut com>"	};
+			
+			string[] documenters = { "Gabriel Felipe Cornejo Salas <gfc gnome cl>",
+				                     "Basilio Kublik <basilio gnome cl>" };
 			
 			aboutDialog.Authors = authors;
 			aboutDialog.Copyright = "Copyright  2006-2007 Pedro Villavicencio Garrido";
@@ -1315,251 +456,15 @@
 			aboutDialog.Comments = Catalog.GetString ("iPod Management Tool");
 			aboutDialog.Version = Defines.VERSION;
 			aboutDialog.Artists = artists;
-                        aboutDialog.Documenters = documenters;
+			aboutDialog.Documenters = documenters;
 			aboutDialog.Logo = new Gdk.Pixbuf (null, "hipo-logo.png");
-
+			
 			aboutDialog.TranslatorCredits = Catalog.GetString ("translator-credits");
-
+			
 			aboutDialog.Website = "http://www.gnome.org/projects/hipo/";;
 			
 			aboutDialog.Run ();
 			aboutDialog.Destroy ();
 		}
-
-		private void RefreshPlaylistView ()
-		{
-			ScanCapacity ();
-		}				
-
-		private void ScanCapacity ()
-		{
-			string capacity = null;
-			string used = null;
-			double percent;
-
-			capacity = FormatString ((double) this.device.VolumeSize);
-			used = FormatString ((double) this.device.VolumeUsed);
-
-			percent = ((double) this.device.VolumeUsed * 100) / ((double) this.device.VolumeSize);
-                        /* space used in the device, example: used 15G of 60G */ 
-			ipodCapacityBar.Text = String.Format (Catalog.GetString ("Used {0} of {1}"), used, capacity);
-			ipodCapacityBar.Fraction = percent  / 100;
-		}
-
-		private string FormatString (double value)
-		{
-			if (value < 1073741824) {
-				return String.Format ("{0:0.0} MB", (value / 1048576));
-			} else {
-				return String.Format ("{0:0.0} GB", (value / 1073741824));
-			}
-		}
-
-		public static Gdk.Pixbuf GetDeviceIcon (IPod.Device device)
-		{
-			string deviceId = null;
-			
-			switch (device.Model) {
-
-			case DeviceModel.Color:
-				deviceId = "multimedia-player-ipod-standard-color";
-				break;
-			case DeviceModel.ColorU2:
-				deviceId = "multimedia-player-ipod-U2-color";
-				break;
-			case DeviceModel.RegularU2:
-				deviceId = "multimedia-player-ipod-U2-monochrome";
-				break;
-			case DeviceModel.Mini:
-				deviceId = "multimedia-player-ipod-mini-silver";
-				break;
-			case DeviceModel.MiniBlue:
-				deviceId = "multimedia-player-ipod-mini-blue";
-				break;
-			case DeviceModel.MiniPink:
-				deviceId = "multimedia-player-ipod-mini-pink";
-				break;
-			case DeviceModel.MiniGreen:
-				deviceId = "multimedia-player-ipod-mini-green";
-				break;
-			case DeviceModel.MiniGold:
-				deviceId = "multimedia-player-ipod-mini-gold";
-				break;
-			case DeviceModel.Shuffle:
-				deviceId = "multimedia-player-ipod-shuffle";
-				break;
-			case DeviceModel.NanoWhite:
-				deviceId = "multimedia-player-ipod-nano-white";
-				break;
-			case DeviceModel.NanoBlack:
-				deviceId = "multimedia-player-ipod-nano-black";
-				break;
-			case DeviceModel.VideoWhite:
-				deviceId = "multimedia-player-ipod-video-white";
-				break;
-			case DeviceModel.VideoBlack:
-				deviceId = "multimedia-player-ipod-video-black";
-				break;
-			default:
-				deviceId = "multimedia-player-ipod-standard-monochrome";
-				break;
-			}
-
-			Gdk.Pixbuf deviceIcon = Gtk.IconTheme.Default.LoadIcon (deviceId, 16, 0);
-			
-			return (deviceIcon);
-		}
-
-		private void OnTracksDragDataGet (object o, DragDataGetArgs args)
-                {
-                        TreeIter iter;
-                        TreeModel model;
-                        Atom[] targets = args.Context.Targets; 
-			ArrayList list = new ArrayList ();
-			StringBuilder dragData = new StringBuilder ();
-			
-			Array treePaths = tracksView.Selection.GetSelectedRows (out model);
-
-			foreach (TreePath tPath in treePaths)
-			{
-				if (model.GetIter (out iter, tPath)) {
-					
-					long trackId = (long) model.GetValue (iter, (int)TracksView.Column.Id);
-					Track track = tracks.GetTrackbyId (this.db, trackId);
-
-					if (track != null)
-						list.Add (track);
-				}
-			}
-
-			Track[] songs = (Track[]) list.ToArray (typeof  (Track));
-			
-			if (args.SelectionData.Target == "text/uri-list") {
-				foreach (Track track in songs) {
-					dragData.Append (track.FileName + "\r\n");
-				}
-				
-				args.SelectionData.Set (targets[0], 8,
-							System.Text.Encoding.UTF8.GetBytes (dragData.ToString()));
-				
-			} else {
-				foreach (Track track in songs) {
-					dragData.Append (track.Id + "\n");
-				}
-				
-				args.SelectionData.Set (targets[0], 8,
-							System.Text.Encoding.UTF8.GetBytes (dragData.ToString ()));
-			}
-			
-                }
-
-		private void OnPlistDragDataReceived (object o, DragDataReceivedArgs args)
-                {
-                        TreePath treepath;
-                        TreeViewDropPosition position;
-                        TreeModel model = plistView.Model;
-                        TreeIter iter;
-                        Playlist plist;
-
-                        plistView.GetDestRowAtPos (args.X, args.Y, out treepath, out position);
-                        model.GetIter (out iter, treepath);
-
-                        try {
-				string plistName = (string) model.GetValue (iter, (int)PlaylistView.Column.Name);
-
-				if ((plist = this.db.LookupPlaylist (plistName)) != null) {
-					string data = System.Text.Encoding.UTF8.GetString (args.SelectionData.Data);
-
-					foreach (string d in data.Trim ().Split ('\n')) {
-						Track track = tracks.GetTrackbyId (this.db, long.Parse (d));
-						
-						if (track == null)
-							return;
-					
-						plist.AddTrack (track);
-					}
-
-					Thread thr = new Thread (new ThreadStart (SaveDB));
-					thr.Start ();
-
-					playlists.UpdateTrackNumber (this.db, plist);
-
-					Gtk.Drag.Finish (args.Context, true, false, args.Time);
-				}
-				
-			} catch (Exception e) {
-				Console.WriteLine ("{0}", e.Message);
-			}
-                }
-
-		private void OnTracksDragDataReceived (object o, DragDataReceivedArgs args)
-		{
-			try {
-				if ((Gtk.Drag.GetSourceWidget (args.Context) != tracksView) &&
-				    (args.SelectionData.Length >=0 && args.SelectionData.Format == 8))
-				{
-					string data = System.Text.Encoding.UTF8.GetString (args.SelectionData.Data);
-
-					bool modified = false;
-
-					foreach (string ur in data.Trim ().Split ('\n')) {
-						string formatUri = ur.Trim ();
-						
-						Uri uri = new Uri (formatUri);
-
-						if (Directory.Exists (uri.LocalPath)) {
-							string[] tmp = { uri.LocalPath };
-							if (tracks.AddFolder (this.db, tmp))
-								if (!modified)
-									modified = true;
-						} else if (File.Exists (uri.LocalPath)) {
-							if (tracks.AddTrack (this.db, uri.LocalPath))
-								if (!modified)
-									modified = true;
-						}
-					}
-					
-					Gtk.Drag.Finish (args.Context, true, false, args.Time);
-					
-					if (modified) {
-						Thread thr = new Thread (new ThreadStart (SaveDB));
-						thr.Start ();
-						
-						playlists.RefreshDevice (this.device);
-					}
-					
-				}
-			} catch (Exception e) {
-				Console.WriteLine (e.Message);
-			}
-		}
-                
-		private bool SearchFilterFunc (Gtk.TreeModel model, Gtk.TreeIter iter)
-		{
-			if (filterEntry.Text.Trim().Length < 1)
-				return true;
-			bool ret = true;
-			try {
-				string search_term = filterEntry.Text.Trim().ToLower();
-				string artist = ((string) model.GetValue (iter, (int)TracksView.Column.Artist)).ToLower();
-				string album = ((string) model.GetValue (iter, (int)TracksView.Column.Album)).ToLower();
-				string title = ((string) model.GetValue (iter, (int)TracksView.Column.Title)).ToLower();
-				string genre = ((string) model.GetValue (iter, (int)TracksView.Column.Genre)).ToLower();
-				ret = ( artist.Contains(search_term) ||
-					album.Contains(search_term) ||
-					title.Contains(search_term) ||
-					genre.Contains(search_term)
-					);
-			} catch (Exception e) {
-				Console.WriteLine (e.Message);
-			}
-			return ret;
-		}
-                
-		private void SearchFor (object o, EventArgs args)
-		{
-			tracksView.Model = store_filter;
-			store_filter.Refilter();
-		}
 	}
 }

Modified: branches/bgarret/src/Makefile.am
==============================================================================
--- branches/bgarret/src/Makefile.am	(original)
+++ branches/bgarret/src/Makefile.am	Thu Jan 31 21:38:51 2008
@@ -9,21 +9,32 @@
 
 HIPO_GENERATED_FILES = Defines.cs
 
-HIPO_SOURCES =				\
-	$(srcdir)/HipoMain.cs		\
-	$(srcdir)/HipoMainWindow.cs	\
-	$(srcdir)/TracksView.cs		\
+HIPO_SOURCES =					\
+	$(srcdir)/Saviour.cs			\
+	$(srcdir)/Tools.cs			\
+	$(srcdir)/Source.cs			\
 	$(srcdir)/ImportDialog.cs		\
-	$(srcdir)/PlaylistView.cs	
+	$(srcdir)/CapacityBar.cs		\
+	$(srcdir)/EditableCellRenderer.cs	\
+	$(srcdir)/TracksContainer.cs		\
+	$(srcdir)/DeviceSource.cs		\
+	$(srcdir)/PlaylistSource.cs		\
+	$(srcdir)/TracksSource.cs		\
+	$(srcdir)/SourceList.cs			\
+	$(srcdir)/HipoMainWindow.cs		\
+	$(srcdir)/HipoMain.cs
 
 HIPO_RESOURCES =			\
 	$(srcdir)/hipo.glade		\
 	$(srcdir)/errordialog.glade	\
-	$(srcdir)/hipo.xml		\
+	$(srcdir)/menubar.xml		\
+	$(srcdir)/devicepopup.xml	\
+	$(srcdir)/playlistpopup.xml	\
+	$(srcdir)/trackpopup.xml	\
 	$(top_srcdir)/data/hipo-logo.png \
 	$(top_srcdir)/data/ipod.gif
 
-HIPO_ASSEMBLIES = -r:Mono.Posix -pkg:gtk-sharp-2.0,gnome-sharp-2.0,glade-sharp-2.0,ipod-sharp,ipod-sharp-ui -r:$(top_builddir)/taglib-sharp/taglib-sharp.dll
+HIPO_ASSEMBLIES = -r:Mono.Posix -pkg:gtk-sharp-2.0,gnome-sharp-2.0,glade-sharp-2.0,ipod-sharp,ipod-sharp-ui,ndesk-dbus-glib-1.0 -r:$(top_builddir)/taglib-sharp/taglib-sharp.dll
 
 ASSEMBLY = hipo.exe
 

Added: branches/bgarret/src/PlaylistSource.cs
==============================================================================
--- (empty file)
+++ branches/bgarret/src/PlaylistSource.cs	Thu Jan 31 21:38:51 2008
@@ -0,0 +1,313 @@
+// PlaylistSource.cs
+//
+//  Copyright (C) 2008 Benoit Garret
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+//
+
+using System;
+using System.Collections.Generic;
+using Gtk;
+using IPod;
+using Mono.Unix;
+
+namespace Hipo
+{
+	public class PlaylistSource : TracksContainer
+	{
+		Playlist playlist;
+		public override event SourceDeletedEventHandler Deleted;
+		
+		public PlaylistSource (Playlist playlist) : base ()
+		{
+			this.playlist = playlist;
+			Tracks = playlist.Tracks;
+			
+			this.Type = Hipo.SourceType.Playlist;
+			this.Parent = SourceType.Device;
+			this.Icon = Gnome.IconTheme.Default.LoadIcon ("stock_playlist", 16, 0);
+			
+			// hook up add and remove track event
+			playlist.TrackAdded += OnTrackAdded;
+			playlist.TrackRemoved += OnTrackRemoved;
+			
+			// source list right click menu
+			// don't connect the handlers now
+			ActionEntry[] entries =  {
+				
+				new ActionEntry ("RenamePlaylist",
+				                 Gtk.Stock.Copy,
+				                 Catalog.GetString ("Rename"),
+				                 null,
+				                 Catalog.GetString ("Rename the playlist"),
+				                 null),
+				new ActionEntry ("DeletePlaylist",
+				                 Gtk.Stock.Delete,
+				                 Catalog.GetString ("Delete"),
+				                 null,
+				                 Catalog.GetString ("Delete the playlist"),
+				                 null)
+			};
+			
+			ActionGroup group = new ActionGroup ("PlaylistPopup");
+			group.Add (entries);
+			
+			UIManager.Instance.InsertActionGroup (group, 0);
+			UIManager.Instance.AddUiFromResource ("playlistpopup.xml");
+		}
+		
+		public override string Name
+		{
+			get {
+				return playlist.Name;
+			}
+			set {
+				if (value != playlist.Name)
+				{
+					playlist.Name = value;
+					Saviour.Instance.Save ();
+				}
+			}
+		}
+		
+		public override Menu Menu
+		{
+			get {
+				return (Menu)UIManager.Instance.GetWidget ("/ui/PlaylistPopup");
+			}
+		}
+		
+		public override int Count
+		{
+			get {
+				return playlist.Tracks.Count;
+			}
+		}
+		
+		public void AddTrack (Track track)
+		{
+			AddTrack (track, true);
+		}
+		
+		public void AddTracks (List<Track> tracks)
+		{
+			foreach (Track track in tracks)
+			{
+				AddTrack (track, false);
+			}
+			
+			Saviour.Instance.Save ();
+		}
+		
+		private void AddTrack (Track track, bool save)
+		{
+			playlist.AddTrack (track);
+		}
+		
+		// Adds the tracks to the database, then to the playlist
+		public override bool AddTracks (string[] uris, bool save)
+		{
+			bool trackAdded = false;
+			
+			foreach (string uri in uris)
+			{
+				Uri u = new Uri (uri);
+				Track track = SourceList.Instance.Tracks.AddTrack (u.LocalPath, false);
+				
+				if (track == null)
+					trackAdded |= false;
+				else
+				{
+					trackAdded |= true;
+					AddTrack (track, false);
+				}
+			}
+			
+			if (trackAdded && save)
+				Saviour.Instance.Save ();
+			
+			return trackAdded;
+		}
+		
+		// Adds the tracks to the database, then to the playlist
+		public override bool AddFolder (string[] dirs, bool save)
+		{
+			// returns true if at least one track has been added
+			bool trackAdded = false;
+			
+			foreach (string path in dirs)
+			{
+				if (path == null)
+					return false;
+
+				System.Uri uri = new System.Uri (path);
+
+				UnixDirectoryInfo info = new UnixDirectoryInfo (uri.LocalPath);
+				foreach (UnixFileSystemInfo file in info.GetFileSystemEntries ())
+				{
+					// |= gives true as soon as one of the arguments is true
+					if (!file.IsDirectory)
+					{
+						Track track = SourceList.Instance.Tracks.AddTrack (file.FullName, false);
+					
+						if (track == null)
+							trackAdded |= false;
+						else
+						{
+							trackAdded |= true;
+							AddTrack (track, false);
+						}
+					}
+					else
+					{
+						string[] tmp = { file.FullName };
+						trackAdded |= AddFolder (tmp, false);
+					}
+				}
+			}
+			
+			if (trackAdded && save)
+				Saviour.Instance.Save ();
+
+			return trackAdded;
+		}
+		
+		public void RemoveTrack (Track track)
+		{
+			RemoveTrack (track, true);
+		}
+		
+		public override void RemoveTracks (List<Track> tracks)
+		{
+			Tools.Log (this, "Removing {0} tracks from the playlist {1}", tracks.Count, playlist.Name);
+			
+			foreach (Track track in tracks)
+			{
+				RemoveTrack (track, false);
+			}
+			
+			Saviour.Instance.Save ();
+		}
+		
+		private void RemoveTrack (Track track, bool save)
+		{
+			playlist.RemoveTrack (track);
+			
+			if (save)
+				Saviour.Instance.Save ();
+		}
+		
+		protected override void AddEventHandlers ()
+		{
+			Tools.Log (this, "Hooking {0} source menu event handlers", this.Name);
+			
+			Menu menu = (Menu)UIManager.Instance.GetWidget ("/ui/PlaylistPopup");
+			
+			// re-bind the menu items to the correct methods
+			foreach (MenuItem item in menu.Children)
+			{
+				switch (item.Name)
+				{
+				case "RenamePlaylist":
+					item.Activated += OnRename;
+					break;
+				case "DeletePlaylist":
+					item.Activated += OnDelete;
+					break;
+				}
+			}
+			
+			base.AddEventHandlers ();
+		}
+		
+		protected override void RemoveEventHandlers ()
+		{
+			Tools.Log (this, "Unhooking {0} source menu event handlers", this.Name);
+			
+			Menu menu = (Menu)UIManager.Instance.GetWidget ("/ui/PlaylistPopup");
+			
+			// re-bind the menu items to the correct methods
+			foreach (MenuItem item in menu.Children)
+			{
+				switch (item.Name)
+				{
+				case "RenamePlaylist":
+					item.Activated -= OnRename;
+					break;
+				case "DeletePlaylist":
+					item.Activated -= OnDelete;
+					break;
+				}
+			}
+			
+			base.RemoveEventHandlers ();
+		}
+		
+		private void OnTrackAdded (object o, int index, Track track)
+		{
+			Tools.Log (this, "Adding track {0} to playlist {1} at position {2}", track.Title, this.Name, index);
+			store.AppendValues (track);
+		}
+		
+		private void OnTrackRemoved (object o, int index, Track track)
+		{
+			TreePath path = new TreePath ();
+            path.AppendIndex (index);
+
+            TreeIter iter = TreeIter.Zero;
+
+            if (!store.GetIter (out iter, path))
+                return;
+            
+            store.Remove (ref iter);
+		}
+		
+		private void OnRename (object o, EventArgs args)
+		{
+			Dialog dialog = new Dialog (Catalog.GetString ("Rename the playlist"), null, Gtk.DialogFlags.DestroyWithParent);
+			
+			dialog.Modal = true;
+			dialog.AddButton ("Cancel", ResponseType.Close);
+			dialog.AddButton ("OK", ResponseType.Ok);
+			
+			Gtk.Entry entry = new Gtk.Entry (this.Name);
+			dialog.VBox.PackStart (entry, false, false, 5);
+			dialog.DefaultResponse = ResponseType.Ok;
+			
+			dialog.ShowAll ();
+			ResponseType r = (ResponseType) dialog.Run ();
+			
+			if (r == ResponseType.Ok)
+			{
+				this.Name = entry.Text;
+			}
+			
+			dialog.Destroy ();
+		}
+		
+		private void OnDelete (object o, EventArgs args)
+		{
+			SourceList.Instance.Tracks.DeletePlaylist (playlist);
+			
+			if (Deleted != null)
+			{
+				Deleted (this);
+			}
+			
+			Saviour.Instance.Save ();
+		}
+	}
+}

Added: branches/bgarret/src/Saviour.cs
==============================================================================
--- (empty file)
+++ branches/bgarret/src/Saviour.cs	Thu Jan 31 21:38:51 2008
@@ -0,0 +1,85 @@
+// Saver.cs
+//
+//  Copyright (C) 2008 Benoit Garret
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+//
+
+using System;
+using System.Threading;
+using IPod;
+
+namespace Hipo
+{
+	// handles the save operations
+	public class Saviour
+	{
+		private static Saviour saviour = null;
+		private Device device;
+		
+		public Saviour (Device device)
+		{
+			Tools.Log (this, "A saviour named {0} is born", device.Name);
+			this.device = device;
+		}
+		
+		public static Saviour Instance {
+			
+			get {
+				return saviour;
+			}
+		}
+		
+		public static void Instantiate (Device device)
+		{
+			saviour = new Saviour (device);
+		}
+		
+		public void Save ()
+		{
+			ThreadStart starter = delegate {
+				
+				lock (this.device) {
+					this.device.Save ();
+				}
+			};
+			
+			new Thread(starter).Start();
+		}
+	}
+	
+	public class UIManager : Gtk.UIManager
+	{
+		private static Gtk.UIManager manager = null;
+		
+		public UIManager () : base ()
+		{
+			Tools.Log (this, "Creating a new UIManager");
+		}
+		
+		public static Gtk.UIManager Instance {
+			
+			get {
+				if (manager == null)
+				{
+					manager = new UIManager ();
+				}
+				
+				return manager;
+			}
+		}
+	}
+}

Added: branches/bgarret/src/Source.cs
==============================================================================
--- (empty file)
+++ branches/bgarret/src/Source.cs	Thu Jan 31 21:38:51 2008
@@ -0,0 +1,195 @@
+// Source.cs
+//
+//  Copyright (C) 2008 Benoit Garret
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+//
+
+using System;
+using System.Collections.Generic;
+using Gtk;
+using Gdk;
+
+namespace Hipo
+{	
+	public delegate void SourceDeletedEventHandler (object source);
+	
+	public interface ISource
+	{
+		event SourceDeletedEventHandler Deleted;
+		
+		// name displayed in the source list
+		string Name {get; set;}
+		
+		// widget providing a view of the source (goes in the right panel)
+		Widget View {get;}
+		
+		// search entry filtering tracks, photos, etc
+		Entry SearchEntry {get;}
+		
+		// menu shown when right clicked in the source list
+		Menu Menu {get;}
+		
+		// source type
+		SourceType Type {get;}
+		
+		// source icon
+		Pixbuf Icon {get;}
+		
+		bool Selected {get; set;}
+		
+		// source item count
+		int Count {get;}
+		
+		// source id
+		int Id {get;}
+		
+		// source parent
+		SourceType Parent {get;}
+	}
+	
+	public abstract class SourceBase : ISource
+	{
+		private static int idCounter = 0;
+		private int id;
+		private string name;
+		private Viewport view;
+		private Entry searchEntry;
+		private Menu menu;
+		private SourceType type;
+		private Pixbuf icon;
+		private int count;
+		private SourceType parent;
+		private bool selected;
+		
+		public virtual event SourceDeletedEventHandler Deleted;
+		
+		public SourceBase ()
+		{
+			id = idCounter;
+			idCounter++;
+			
+			// initialize everything with dummy values
+			view = new Viewport ();
+			searchEntry = new Entry ();
+			searchEntry.Sensitive = false;
+			menu = new Menu ();
+			type = SourceType.None;
+			selected = false;
+			count = 0;
+			name = "Default name, override me";
+		}
+		
+		public virtual string Name
+		{
+			get {
+				return name;
+			}
+			
+			set {
+				name = value;
+			}
+		}
+		
+		public virtual Widget View
+		{
+			get {
+				return view;
+			}
+		}
+		
+		public virtual Entry SearchEntry
+		{
+			get {
+				return searchEntry;
+			}
+		}
+		
+		public virtual Menu Menu
+		{
+			get {
+				return menu;
+			}
+		}
+		
+		public virtual SourceType Type
+		{
+			get {
+				return type;
+			}
+			
+			protected set {
+				type = value;
+			}
+		}
+		
+		public virtual Pixbuf Icon
+		{
+			get {
+				return icon;
+			}
+			
+			protected set {
+				icon = value;
+			}
+		}
+		
+		public virtual SourceType Parent
+		{
+			get {
+				return parent;
+			}
+			
+			protected set {
+				parent = value;
+			}
+		}
+		
+		public virtual bool Selected
+		{
+			get {
+				return selected;
+			}
+			
+			set {
+				selected = value;
+			}
+		}
+		
+		public virtual int Count
+		{
+			get {
+				return count;
+			}
+		}
+		
+		public int Id
+		{
+			get {
+				return id;
+			}
+		}
+	}
+	
+	public enum SourceType
+	{
+		None,
+		Device,
+		Tracks,
+		Playlist,
+		SmartPlaylist
+	}
+}

Added: branches/bgarret/src/SourceList.cs
==============================================================================
--- (empty file)
+++ branches/bgarret/src/SourceList.cs	Thu Jan 31 21:38:51 2008
@@ -0,0 +1,440 @@
+// SourceList.cs
+//
+//  Copyright (C) 2008 Benoit Garret
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+//
+
+using System;
+using System.Collections.Generic;
+using Gtk;
+using IPod;
+
+namespace Hipo
+{
+	public class SourceList
+	{
+		private static SourceList instance = null;
+		
+		private TreeView view;
+		private TreeStore store;
+		private Menu menu;
+		private List<ISource> sources;
+		private ISource selectedSource;
+		
+		private static TargetEntry [] dest_entries = {
+			new TargetEntry ("application/x-hipo", 0, 0)
+		};
+		
+		public event SelectionChangedEventHandler SelectionChanged;
+		public delegate void SelectionChangedEventHandler (object source, SelectionChangedArgs e);
+		
+		public class SelectionChangedArgs : EventArgs
+		{
+			ISource source;
+			
+			public SelectionChangedArgs (ISource source)
+			{
+				this.source = source;
+			}
+			
+			public ISource Source
+			{
+				get {
+					return source;
+				}
+			}
+		}
+		
+		private SourceList ()
+		{
+			// initialize playlist list
+			
+			sources = new List<ISource>();
+			
+			// create the columns, treeview, etc
+			
+			view = new TreeView ();
+			view.HeadersVisible = false;
+			
+			CellRendererPixbuf pixbufCell = new CellRendererPixbuf ();
+			TreeViewColumn column = new TreeViewColumn ();
+			column.PackStart (pixbufCell, true);
+			
+			TreeCellDataFunc iconCellDataFunc = new TreeCellDataFunc (IconCellDataFunc);
+			column.SetCellDataFunc (pixbufCell, iconCellDataFunc);
+			
+			column.Expand = false;
+			column.Resizable = true;
+			view.AppendColumn (column);
+			
+			
+			EditableCellRenderer textCell = new EditableCellRenderer ();
+			textCell.Edited += OnSourceEdit;
+			textCell.Column = Column.Name;
+			
+			column = new TreeViewColumn ();
+			column.PackStart (textCell, true);
+			
+			TreeCellDataFunc textCellDataFunc = new TreeCellDataFunc (TextCellDataFunc);
+			column.SetCellDataFunc (textCell, textCellDataFunc);
+			
+			column.Expand = true;
+			view.AppendColumn (column);
+			
+			
+			CellRendererText countCell = new CellRendererText ();
+			column = new TreeViewColumn ();
+			column.PackStart (countCell, true);
+			
+			TreeCellDataFunc countCellDataFunc = new TreeCellDataFunc (CountCellDataFunc);
+			column.SetCellDataFunc (countCell, countCellDataFunc);
+			
+			column.Expand = false;
+			view.AppendColumn (column);
+			
+			// create the store
+			store = new TreeStore (typeof (ISource));
+			
+			// bind store and view
+			view.Model = store;
+			
+			// enable drag and drop
+			view.EnableModelDragDest (dest_entries, Gdk.DragAction.Copy);			
+			view.DragDataReceived += OnDragDataReceived;
+			
+			// hook up delegates
+			view.Selection.Changed += OnSelectionChanged;
+			
+			// hook up popup menu handlers
+			view.KeyPressEvent += OnKeyPress;
+			view.ButtonPressEvent += OnButtonPress;
+		}
+		
+		private void TextCellDataFunc (TreeViewColumn column, CellRenderer renderer,
+		                               TreeModel model, TreeIter iter)
+		{
+			ISource source = (ISource)model.GetValue (iter, 0);
+			EditableCellRenderer cell = (EditableCellRenderer)renderer;
+			
+			switch (cell.Column)
+			{
+			case Column.Name:
+				cell.Text = source.Name;
+				break;
+			default:
+				break;
+			}
+		}
+		
+		private void IconCellDataFunc (TreeViewColumn column, CellRenderer renderer,
+		                               TreeModel model, TreeIter iter)
+		{
+			ISource source = (ISource)model.GetValue (iter, 0);
+			CellRendererPixbuf cell = (CellRendererPixbuf)renderer;
+			
+			cell.Pixbuf = source.Icon;
+		}
+		
+		private void CountCellDataFunc (TreeViewColumn column, CellRenderer renderer,
+		                                TreeModel model, TreeIter iter)
+		{
+			ISource source = (ISource)model.GetValue (iter, 0);
+			CellRendererText cell = (CellRendererText)renderer;
+			
+			cell.Foreground = "grey";
+			
+			if (source.Count < 1)
+				cell.Text = "";
+			else
+				cell.Text = "(" + source.Count + ")";
+		}
+		
+		public Widget View
+		{
+			get {
+				return (Widget) view;
+			}
+		}
+		
+		public ISource SelectedSource
+		{
+			get {
+				return selectedSource;
+			}
+			
+			set {
+				if (value != null)
+					Tools.Log (this, "Selecting source {0}", value.Name);
+				else
+					Tools.Log (this, "No source selected");
+				
+				if (selectedSource != null)
+					selectedSource.Selected = false;
+				
+				selectedSource = value;
+				
+				if (selectedSource != null)
+				{
+					selectedSource.Selected = true;
+					
+					store.Foreach (delegate (TreeModel model, TreePath path, TreeIter iter) {
+						
+						ISource source = (ISource)store.GetValue (iter, 0);
+						
+						if (source.Id == selectedSource.Id)
+						{
+							view.Selection.SelectIter (iter);
+							return true;
+						}
+						else
+							return false;
+					});
+					
+					if (SelectionChanged != null)
+					{
+						SelectionChanged (this, new SelectionChangedArgs (selectedSource));
+						Tools.Log (this, "Source {0} selected", selectedSource.Name);
+					}
+				}
+				else
+				{
+					if (SelectionChanged != null)
+					{
+						SelectionChanged (this, new SelectionChangedArgs (null));
+						Tools.Log (this, "No source selected");
+					}
+				}
+			}
+		}
+		
+		public DeviceSource Device
+		{
+			get {
+				DeviceSource device = (DeviceSource)sources.Find (delegate (ISource source) {
+					if (source.Type == SourceType.Device)
+						return true;
+					else
+						return false;
+				});
+				
+				return device;
+			}
+		}
+		
+		public TracksSource Tracks
+		{
+			get {
+				TracksSource tracks = (TracksSource)sources.Find (delegate (ISource source) {
+					if (source.Type == SourceType.Tracks)
+						return true;
+					else
+						return false;
+				});
+				
+				return tracks;
+			}
+		}
+		
+		public List<ISource> Playlists
+		{
+			get {
+				return sources.FindAll (delegate (ISource source) {
+					if (source.Type == SourceType.Playlist)
+						return true;
+					else
+						return false;
+				});
+			}
+		}
+		
+		public Menu Menu
+		{
+			get {
+				return menu;
+			}
+		}
+		
+		public static SourceList Instance {
+			
+			get {
+				if (instance == null)
+					instance = new SourceList ();
+				
+				return instance;
+			}
+		}
+		
+		public void Add (ISource source)
+		{
+			sources.Add (source);
+			source.Deleted += OnSourceDeleted;
+			
+			if (source.Parent == SourceType.None)
+				store.AppendValues (source);
+			else
+			{
+				store.Foreach (delegate (TreeModel model, TreePath path, TreeIter iter) {
+					
+					ISource s = (ISource)model.GetValue (iter, 0);
+					
+					if (s.Type == source.Parent)
+					{
+						store.AppendValues (iter, source);
+						return true;
+					}
+					else
+						return false;
+				});
+			}
+			
+			Tools.Log (this, "Added source {0} with id {1} to the list", source.Name, source.Id);
+		}
+		
+		public void RefreshView ()
+		{
+			view.QueueDraw ();
+		}
+		
+		public void Clear ()
+		{
+			this.store.Clear ();
+			this.sources.Clear ();
+		}
+		
+		public void ExpandAll ()
+		{
+			view.ExpandAll ();
+		}
+		
+		private void OnSelectionChanged (object o, EventArgs args)
+		{
+			TreeIter iter;
+			TreeModel model;
+			
+			if (((TreeSelection)o).GetSelected (out model, out iter))
+			{
+				ISource source = (ISource)model.GetValue (iter, 0);
+				
+				this.SelectedSource = source;
+			}
+		}
+		
+		[GLib.ConnectBefore]
+		private void OnButtonPress (object o, ButtonPressEventArgs args)
+		{
+			// if right click then show the menu
+			switch (args.Event.Button)
+			{
+			case 3:
+				Tools.Log (this, "Ooooh, right click");
+				PopupMenu (args.Event);
+				args.RetVal = true;
+				break;
+			}
+		}
+		
+		private void OnKeyPress (object o, KeyPressEventArgs args)
+		{
+			switch (args.Event.Key)
+			{
+			case Gdk.Key.Menu:
+				Tools.Log (this, "Ooooh, menu button");
+				PopupMenu (args.Event);
+				args.RetVal = true;
+				break;
+			}
+		}
+		
+		private void PopupMenu (Gdk.Event ev)
+		{
+			// build the menu and show it
+			Menu menu = selectedSource.Menu;
+			
+			if (menu != null)
+				menu.Popup (null, null, null,
+				            ((ev != null) && ev.Type == Gdk.EventType.ButtonPress) ? ((Gdk.EventButton)ev).Button : 0,
+				            Gdk.EventHelper.GetTime (ev));
+		}
+		
+		private void OnSourceEdit (object o, EditedArgs args)
+		{
+			TreeIter iter = TreeIter.Zero;
+			
+			if (!store.GetIter (out iter, new TreePath (args.Path)))
+				return;
+			
+			ISource source = (ISource)store.GetValue (iter, 0);
+			
+			source.Name = args.NewText;
+		}
+		
+		private void OnSourceDeleted (object o)
+		{
+			ISource source = (ISource)o;
+			
+			sources.Remove (source);
+			store.Foreach (delegate (TreeModel model, TreePath path, TreeIter iter) {
+				
+				ISource s = (ISource)model.GetValue (iter, 0);
+				
+				if (source.Id == s.Id)
+				{
+					store.Remove (ref iter);
+					return true;
+				}
+				else
+					return false;
+			});
+		}
+		
+		private void OnDragDataReceived (object o, DragDataReceivedArgs args)
+		{
+			TreePath treepath;
+			TreeViewDropPosition position;
+			TreeIter iter;
+			
+			view.GetDestRowAtPos (args.X, args.Y, out treepath, out position);
+			store.GetIter (out iter, treepath);
+			
+			try {
+				ISource source = (ISource) store.GetValue (iter, 0);
+				
+				if (source.Type == SourceType.Playlist)
+				{
+					string data = System.Text.Encoding.UTF8.GetString (args.SelectionData.Data);
+					
+					foreach (string d in data.Trim ().Split ('\n')) {
+						
+						Track track = Tracks.GetTrack (long.Parse (d));
+						
+						if (track == null)
+							return;
+							
+						((PlaylistSource)source).AddTrack (track);
+					}
+					
+					Saviour.Instance.Save ();
+				}
+				
+				Drag.Finish (args.Context, true, false, args.Time);
+				
+			} catch (Exception e) {
+				Tools.Log (this, "{0}", e.Message);
+			}
+		}
+	}
+}

Added: branches/bgarret/src/Tools.cs
==============================================================================
--- (empty file)
+++ branches/bgarret/src/Tools.cs	Thu Jan 31 21:38:51 2008
@@ -0,0 +1,60 @@
+// Tools.cs
+//
+//  Copyright (C) 2008 Benoit Garret
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+//
+
+using System;
+
+namespace Hipo
+{
+	public static class Tools
+	{
+		private static bool logEnabled;
+		
+		public static string FormatString (double value)
+		{
+			if (value < 1073741824) {
+				return String.Format ("{0:0.0} MB", (value / 1048576));
+			} else {
+				return String.Format ("{0:0.0} GB", (value / 1073741824));
+			}
+		}
+		
+		public static void Log (object o, string message)
+		{
+			if (logEnabled)
+				Console.WriteLine ("{0}: {1}", o, message);
+		}
+		
+		public static void Log (object o, string format, params object[] args)
+		{
+			Log (o, String.Format (format, args));
+		}
+		
+		public static bool LogEnabled
+		{
+			get {
+				return logEnabled;
+			}
+			
+			set {
+				logEnabled = value;
+			}
+		}
+	}
+}

Added: branches/bgarret/src/TracksContainer.cs
==============================================================================
--- (empty file)
+++ branches/bgarret/src/TracksContainer.cs	Thu Jan 31 21:38:51 2008
@@ -0,0 +1,782 @@
+// TracksContainer.cs
+//
+//  Copyright (C) 2008 Benoit Garret
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+//
+
+using System;
+using System.IO;
+using System.Threading;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+using Gtk;
+using Gdk;
+using Glade;
+using IPod;
+using Mono.Unix;
+
+namespace Hipo
+{
+	// this class contains the shared code for all sources containing tracks
+	
+	public abstract class TracksContainer  : SourceBase
+	{
+		private TreeView view;
+		protected ListStore store;
+		private TreeModelFilter store_filter;
+		private Entry search;
+		private SourceType type;
+		private bool selected;
+		private IList<Track> tracks;
+		private Column sortColumn = Column.Artist;
+		
+		private static TargetEntry [] source_entries = {
+			new TargetEntry ("text/uri-list", 0, 0),
+			new TargetEntry ("application/x-hipo", 0, 0)
+		};
+		
+		public TracksContainer ()
+		{
+			// create the columns, treeview, etc
+			view = new TreeView ();
+			
+			TreeViewColumn column = BuildColumn (Column.Artist);
+			view.AppendColumn (column);
+			
+			column = BuildColumn (Column.Album);
+			view.AppendColumn (column);
+			
+			column = BuildColumn (Column.Title);
+			view.AppendColumn (column);
+			
+			column = BuildColumn (Column.Genre);
+			view.AppendColumn (column);
+			
+			view.HeadersVisible = true;
+			view.HeadersClickable = true;
+			
+			// create the store
+			store = new ListStore (typeof (Track));
+			store.SetSortFunc (0, CompareFunc);
+			
+			// bind store and view
+			view.Model = store;
+			
+			// enable drag and drop
+			view.EnableModelDragSource (Gdk.ModifierType.Button1Mask,
+			                            source_entries, Gdk.DragAction.Copy);
+			view.DragDataGet += OnDragDataGet;
+
+			view.EnableModelDragDest (source_entries, Gdk.DragAction.Copy);
+			view.DragDataReceived += OnDragDataReceived;
+			
+			view.Selection.Mode = SelectionMode.Multiple;
+			
+			// hook up popup menu handlers
+			view.KeyPressEvent += OnKeyPress;
+			view.ButtonPressEvent += OnButtonPress;
+			
+			// create the search entry and bind the changed event
+			search = new Entry ();
+			search.Changed += SearchFor;
+			store_filter = new TreeModelFilter (view.Model, null);
+			store_filter.VisibleFunc = SearchFilterFunc;
+			
+			// create action entries
+			ActionEntry[] entries =  {
+
+				new ActionEntry ("AddToPlaylist",
+				                 Gtk.Stock.Add, Catalog.GetString ("Add to Playlist..."),
+				                 null,
+				                 Catalog.GetString ("Add the track to a Playlist"),
+				                 null),
+				new ActionEntry ("Remove",
+				                 Gtk.Stock.Remove,
+				                 null,
+				                 null,
+				                 Catalog.GetString ("Remove the track from your iPod"),
+				                 null),
+				new ActionEntry ("TrackProperties",
+				                 Gtk.Stock.Properties,
+				                 Catalog.GetString ("Track Properties"),
+				                 null,
+				                 Catalog.GetString ("Track Properties"),
+				                 null),
+			};
+			
+			// create the ui manager and the keyboard shortcuts
+			ActionGroup group = new ActionGroup ("TrackPopup");
+			group.Add (entries);
+			
+			UIManager.Instance.InsertActionGroup (group, 0);
+			UIManager.Instance.AddUiFromResource ("trackpopup.xml");
+		}
+		
+		TreeViewColumn BuildColumn (Column column)
+		{
+			EditableCellRenderer cell = new EditableCellRenderer ();
+			cell.Edited += OnTrackEdit;
+			cell.Column = column;
+			
+			TreeViewColumn col = new TreeViewColumn ();
+			col.Title = Catalog.GetString (column.ToString ());
+			col.PackStart (cell, true);
+			
+			TreeCellDataFunc textCellDataFunc = new TreeCellDataFunc (TextCellDataFunc);
+			col.SetCellDataFunc (cell, textCellDataFunc);
+			
+			col.Clickable = true;
+			col.Clicked += delegate { sortColumn = column; };
+			
+			col.Resizable = true;
+			col.Expand = false;
+			
+			col.SortIndicator = true;
+			col.SortColumnId = 0;
+			
+			col.Sizing = TreeViewColumnSizing.Fixed;
+			
+			if (column == Column.Genre)
+				col.FixedWidth = 100;
+			else
+				col.FixedWidth = 200;
+			
+			return col;
+		}
+		
+		private void TextCellDataFunc (TreeViewColumn column, CellRenderer renderer,
+		                               TreeModel model, TreeIter iter)
+		{
+			Track track = (Track) model.GetValue (iter, 0);
+			EditableCellRenderer cell = (EditableCellRenderer)renderer;
+			
+			switch (cell.Column)
+			{
+			case Column.Album:
+				cell.Text = track.Album;
+				break;
+			case Column.Artist:
+				cell.Text = track.Artist;
+				break;
+			case Column.Genre:
+				cell.Text = track.Genre;
+				break;
+			case Column.Title:
+				cell.Text = track.Title;
+				break;
+			default:
+				cell.Text = "";
+				break;
+			}
+		}
+		
+		int CompareFunc (TreeModel model, TreeIter a, TreeIter b)
+		{
+			Track tracka = (Track)store.GetValue (a, 0);
+			Track trackb = (Track)store.GetValue (b, 0);
+			
+			switch (sortColumn)
+			{
+			case Column.Album:
+				return String.Compare (tracka.Album, trackb.Album);
+			case Column.Artist:
+				return String.Compare (tracka.Artist, trackb.Artist);
+			case Column.Genre:
+				return String.Compare (tracka.Genre, trackb.Genre);
+			case Column.Title:
+				return String.Compare (tracka.Title, trackb.Title);
+			default:
+				return 0;
+			}
+		}
+		
+		public override Widget View
+		{
+			get {
+				return (Widget)view;
+			}
+		}
+
+		public override Entry SearchEntry
+		{
+			get {
+				return search;
+			}
+		}
+
+		public override SourceType Type
+		{
+			get {
+				return type;
+			}
+			
+			protected set {
+				this.type = value;
+			}
+		}
+		
+		protected IList<Track> Tracks
+		{
+			set {
+				tracks = value;
+				store.Clear ();
+				
+				foreach (Track track in tracks)
+				{
+					store.AppendValues (track);
+				}
+			}
+			
+			get {
+				return tracks;
+			}
+		}
+		
+		public override bool Selected
+		{
+			get {
+				return selected;
+			}
+			
+			set {
+				this.selected = value;
+				
+				if (this.selected)
+					AddEventHandlers ();
+				else
+					RemoveEventHandlers ();
+			}
+		}
+		
+		// the two following methods have to be implemented
+		// to add tracks to the source when drag and dropped to.
+		public virtual bool AddTracks (string[] paths, bool save)
+		{
+			return true;
+		}
+		
+		public virtual bool AddFolder (string[] dirs, bool save)
+		{
+			return true;
+		}
+		
+		// implement this to make the right click menu delete item work
+		public virtual void RemoveTracks (List<Track> tracks)
+		{
+			
+		}
+		
+		[GLib.ConnectBefore]
+		private void OnButtonPress (object o, ButtonPressEventArgs args)
+		{
+			// if right click then show the menu
+			switch (args.Event.Button)
+			{
+			case 3:
+				Tools.Log (this, "Ooooh, right click");
+				PopupMenu (args.Event);
+				args.RetVal = true;
+				break;
+			}
+		}
+		
+		private void OnKeyPress (object o, KeyPressEventArgs args)
+		{
+			switch (args.Event.Key)
+			{
+			case Gdk.Key.Menu:
+				Tools.Log (this, "Ooooh, menu button");
+				PopupMenu (args.Event);
+				args.RetVal = true;
+				break;
+			case Gdk.Key.Delete:
+				Tools.Log (this, "Ooooh, delete button");
+				RemoveTracks (GetSelectedTracks ());
+				args.RetVal = true;
+				break;
+			}
+		}
+		
+		private void PopupMenu (Gdk.Event ev)
+		{
+			// build the menu and show it
+			
+			if (view.Selection.CountSelectedRows () > 0)
+			{
+				Tools.Log (this, "Building and showing track popup menu");
+				
+				Menu playlistMenu = new Menu ();
+				MenuItem addToPlaylistItem = (MenuItem)UIManager.Instance.GetWidget ("/ui/TrackPopup/AddToPlaylist");
+				
+				foreach (ISource source in SourceList.Instance.Playlists)
+				{
+					PlaylistSource playlistSource = (PlaylistSource)source;
+					ImageMenuItem item = new ImageMenuItem (playlistSource.Name);
+					item.Image = new Gtk.Image (Gnome.IconTheme.Default.LoadIcon ("stock_playlist", 16, 0));
+					// eww, ugly 
+					item.Activated += delegate {
+						
+						AddToPlaylist (playlistSource);
+					};
+					playlistMenu.Append (item);
+					Tools.Log (this, "Added playlist {0} to the menu", playlistSource.Name);
+				}
+				
+				addToPlaylistItem.Submenu = playlistMenu;
+				
+				Menu menu = (Menu)Hipo.UIManager.Instance.GetWidget ("/ui/TrackPopup");
+				
+				if (menu == null)
+					Console.WriteLine ("menu");
+				
+				menu.ShowAll ();
+				playlistMenu.ShowAll ();
+				
+				menu.Popup (null, null, null, ((ev != null) && ev.Type == Gdk.EventType.ButtonPress) ? ((Gdk.EventButton)ev).Button : 0,
+				            Gdk.EventHelper.GetTime (ev));
+			}
+		}
+		
+		private void AddToPlaylist (PlaylistSource playlistSource)
+		{
+			playlistSource.AddTracks (GetSelectedTracks ());
+		}
+		
+		protected virtual void AddEventHandlers ()
+		{
+			Tools.Log (this, "Hooking {0} track menu event handlers", this.Name);
+			
+			Menu menu = (Menu)UIManager.Instance.GetWidget ("/ui/TrackPopup");
+			
+			// re-bind the menu items to the correct methods
+			foreach (MenuItem item in menu.Children)
+			{
+				switch (item.Name)
+				{
+				case "Remove":
+					item.Activated += OnRemove;
+					break;
+				case "TrackProperties":
+					item.Activated += OnTrackProperties;
+					break;
+				}
+			}
+		}
+		
+		protected virtual void RemoveEventHandlers ()
+		{
+			Tools.Log (this, "Unhooking {0} track menu event handlers", this.Name);
+			
+			Menu menu = (Menu)UIManager.Instance.GetWidget ("/ui/TrackPopup");
+			
+			// re-bind the menu items to the correct methods
+			foreach (MenuItem item in menu.Children)
+			{
+				switch (item.Name)
+				{
+				case "Remove":
+					item.Activated -= OnRemove;
+					break;
+				case "TrackProperties":
+					item.Activated -= OnTrackProperties;
+					break;
+				}
+			}
+		}
+		
+		private List<Track> GetSelectedTracks ()
+		{
+			TreeIter iter;
+			TreeModel model;
+			
+			Array treePaths = view.Selection.GetSelectedRows (out model);
+			List<Track> selectedTracks = new List<Track>();
+			
+			foreach (TreePath tPath in treePaths)
+			{
+				if (model.GetIter (out iter, tPath))
+				{
+					Track track = (Track)model.GetValue (iter, 0);
+					selectedTracks.Add (track);
+				}
+			}
+			
+			return selectedTracks;
+		}
+		
+		private void OnTrackEdit (object o, EditedArgs args)
+		{
+			TreeIter iter = TreeIter.Zero;
+			EditableCellRenderer cell = (EditableCellRenderer) o;
+			bool modified = false;
+			
+			if (!store.GetIter (out iter, new TreePath (args.Path)))
+				return;
+			
+			Track track = (Track)store.GetValue (iter, 0);
+			
+			switch (cell.Column)
+			{
+				case Column.Artist:
+					if (args.NewText != track.Artist)
+					{
+						track.Artist = args.NewText;
+						modified = true;
+					}
+					break;
+				case Column.Album:
+					if (args.NewText != track.Album)
+					{
+						track.Album = args.NewText;
+						modified = true;
+					}
+					break;
+				case Column.Title:
+					if (args.NewText != track.Title)
+					{
+						track.Title = args.NewText;
+						modified = true;
+					}
+					break;
+				case Column.Genre:
+					if (args.NewText != track.Genre)
+					{
+						track.Genre = args.NewText;
+						modified = true;
+					}
+					break;
+				default:
+					break;
+			}
+			
+			if (modified)
+			{
+				Saviour.Instance.Save ();
+			}
+		}
+		
+		[Widget] private Gtk.Dialog trackProperties;
+		[Widget] private Gtk.Entry artistEntry;
+		[Widget] private Gtk.Entry albumEntry;
+		[Widget] private Gtk.Entry titleEntry;
+		[Widget] private Gtk.Entry genreEntry;
+		[Widget] private Gtk.SpinButton numberSpin;
+		[Widget] private Gtk.Image artwork;
+		[Widget] private Gtk.Button openArtwork;
+		[Widget] private Gtk.Label titleLabel;
+		[Widget] private Gtk.Label numberLabel;
+                
+		private void OnTrackProperties (object o, EventArgs args)
+		{
+			Glade.XML xml = new Glade.XML (null, "hipo.glade", "trackProperties", null);
+			xml.Autoconnect (this);
+
+			bool modified = false;
+			Gdk.Pixbuf newCover = null;
+			string artist = "";
+			string album = "";
+			string title = "";
+			string genre = "";
+			int trackNumber = 0;
+			Gdk.Pixbuf image = null;
+			
+			List<Track> selectedTracks = GetSelectedTracks ();
+			
+			if (selectedTracks.Count > 0)
+			{
+				foreach (Track track in selectedTracks)
+				{
+					/*
+					The values are filled in with the properties of the first track of the list.
+					A comparison is made with the subsequent tracks,
+					if the values are the same, nothing is changed,
+					if they are different, a blank value is put
+					*/
+					
+					if (selectedTracks.IndexOf (track) == 0)
+					{
+						artist = track.Artist;
+						album = track.Album;
+						title = track.Title;
+						genre = track.Genre;
+						trackNumber = track.TrackNumber;
+						
+						foreach (ArtworkFormat format in SourceList.Instance.Device.LookupArtworkFormats (ArtworkUsage.Cover)) {
+
+							if (format != null) {
+								if (track.HasCoverArt (format)) 
+									image = ArtworkHelpers.ToPixbuf (format, track.GetCoverArt (format));
+							}
+						}
+						
+						if (selectedTracks.Count == 1)
+						{
+							/* artist name and track title properties */
+							trackProperties.Title = String.Format (Catalog.GetString ("{0} {1} Properties"),
+											       track.Artist, track.Title);
+						}
+						else
+						{
+							trackProperties.Title = Catalog.GetString ("Multiple tracks properties");
+                                                        titleEntry.Hide ();
+                                                        titleLabel.Hide ();
+                                                        numberLabel.Hide ();
+                                                        numberSpin.Hide ();
+						}
+					}
+					else
+					{
+						if (!artist.Equals("") && !artist.Equals (track.Artist))
+							artist = "";
+						
+						if (!album.Equals("") && !album.Equals (track.Album))
+							album = "";
+						
+						if (!title.Equals("") && !title.Equals (track.Title))
+							title = "";
+						
+						if (!genre.Equals("") && !genre.Equals (track.Genre))
+							genre = "";
+						
+						if ((trackNumber != 0) && (trackNumber != track.TrackNumber))
+							trackNumber = 0;
+						
+					}
+				}
+				
+				artistEntry.Text = artist;
+				albumEntry.Text = album;
+				titleEntry.Text = title;
+				genreEntry.Text = genre;
+				numberSpin.Value = trackNumber;
+				artwork.FromPixbuf = image;
+			}
+
+			openArtwork.Clicked += delegate {
+
+				FileFilter filter = new Gtk.FileFilter ();
+				
+				Gtk.FileChooserDialog fileChooser  = new Gtk.FileChooserDialog (Catalog.GetString ("Select an image"),
+												trackProperties,
+												FileChooserAction.Open,
+												Gtk.Stock.Cancel, ResponseType.Cancel,
+												Gtk.Stock.Add, ResponseType.Accept);
+				
+				fileChooser.LocalOnly = true;
+				filter.AddMimeType ("image/png");
+				filter.AddMimeType ("image/jpeg");
+				fileChooser.AddFilter (filter);
+				fileChooser.UpdatePreview += OnUpdatePreview;
+				fileChooser.PreviewWidget = new Gtk.Image ();
+				
+				ResponseType res = (ResponseType) fileChooser.Run ();
+				string uri = fileChooser.Uri;
+				
+				if (res == ResponseType.Accept)
+				{
+					Uri ur = new Uri (uri);
+					newCover = new Gdk.Pixbuf (ur.LocalPath);
+
+					artwork.FromPixbuf = newCover.ScaleSimple(200, 200, Gdk.InterpType.Bilinear);
+				}
+
+				fileChooser.Destroy ();
+			};
+
+			ResponseType response = (ResponseType) trackProperties.Run ();
+				
+			if (response == ResponseType.Ok)
+			{
+				if (artistEntry.Text != artist) {
+					modified = true;
+					foreach (Track track in selectedTracks)
+					{
+						track.Artist = artistEntry.Text;
+					}
+				}
+
+				if (albumEntry.Text != album) {
+					modified = true;
+					foreach (Track track in selectedTracks)
+					{
+						track.Album = albumEntry.Text;
+					}
+				}
+
+				if (titleEntry.Text != title) {
+					modified = true;
+					foreach (Track track in selectedTracks)
+					{
+						track.Title = titleEntry.Text;
+					}
+				}
+
+				if (genreEntry.Text != genre) {
+					modified = true;
+					foreach (Track track in selectedTracks)
+					{
+						track.Genre = genreEntry.Text;
+					}
+				}
+
+				if (numberSpin.Value != trackNumber) {
+					modified = true;
+					foreach (Track track in selectedTracks)
+					{
+						track.TrackNumber = (int) numberSpin.Value;
+					}
+				}
+
+				if (newCover != null) {
+					
+					foreach (ArtworkFormat format in SourceList.Instance.Device.LookupArtworkFormats (ArtworkUsage.Cover)) {
+
+						// maybe is a good idea to set all the album of the current selected track with the new cover.
+						// we can set this on a gconf key.
+						
+						foreach (Track track in selectedTracks)
+						{
+							track.SetCoverArt (format, ArtworkHelpers.ToBytes (format, newCover));
+						}
+					}
+					
+					modified = true;
+				}
+			}
+
+			if (modified)
+				Saviour.Instance.Save ();
+
+			trackProperties.Destroy ();
+		}
+		
+		private void OnUpdatePreview (object o, EventArgs args)
+		{
+			FileChooser fileChooser = (FileChooser)o;
+			
+			try {
+				
+				if (fileChooser.PreviewFilename != null)
+				{
+					Gdk.Pixbuf cover = new Gdk.Pixbuf (fileChooser.PreviewFilename);
+					
+					((Gtk.Image)fileChooser.PreviewWidget).Pixbuf = cover.ScaleSimple (150, 150, Gdk.InterpType.Bilinear);
+					
+					((Gtk.Image)fileChooser.PreviewWidget).Show ();	
+				}
+			} catch (Exception e) {
+				
+				((Gtk.Image)fileChooser.PreviewWidget).Hide ();
+				Console.WriteLine (e.Message);
+			}
+		}
+		
+		private void OnRemove (object o, EventArgs args)
+		{
+			RemoveTracks (GetSelectedTracks ());
+		}
+		
+		private void OnDragDataGet (object o, DragDataGetArgs args)
+		{
+			Atom[] targets = args.Context.Targets; 
+			StringBuilder dragData = new StringBuilder ();
+			
+			List<Track> selectedTracks = GetSelectedTracks ();
+			
+			foreach (Track track in selectedTracks)
+			{
+				if (args.SelectionData.Target == "text/uri-list")
+					dragData.Append (track.FileName + "\r\n");
+				else
+					dragData.Append (track.Id + "\n");
+			}
+			
+			args.SelectionData.Set (targets[0], 8,
+			                        System.Text.Encoding.UTF8.GetBytes (dragData.ToString()));
+		}
+		
+		private void OnDragDataReceived (object o, DragDataReceivedArgs args)
+		{
+			try {
+				
+				if ((Gtk.Drag.GetSourceWidget (args.Context) != view) &&
+				    (args.SelectionData.Length >=0 && args.SelectionData.Format == 8))
+				{
+					string data = System.Text.Encoding.UTF8.GetString (args.SelectionData.Data);
+					bool trackAdded = false;
+					
+					foreach (string ur in data.Trim ().Split ('\n'))
+					{
+						string formatUri = ur.Trim ();
+						
+						Uri uri = new Uri (formatUri);
+						
+						if (Directory.Exists (uri.LocalPath))
+						{
+							string[] tmp = { formatUri };
+							trackAdded |= AddFolder (tmp, false);
+						}
+						else if (File.Exists (uri.LocalPath))
+						{
+							string[] tmp = { formatUri };
+							trackAdded |= AddTracks (tmp, false);
+						}
+					}
+					
+					if (trackAdded)
+						Saviour.Instance.Save ();
+					
+					Gtk.Drag.Finish (args.Context, true, false, args.Time);
+				}
+			} catch (Exception e) {
+				Console.WriteLine (e.Message);
+			}
+		}
+		
+		private bool SearchFilterFunc (TreeModel model, TreeIter iter)
+		{
+			if (search.Text.Trim().Length < 1)
+				return true;
+			
+			bool ret = true;
+			Track track = (Track)model.GetValue (iter, 0);
+			
+			try {
+				string search_term = search.Text.Trim().ToLower();
+				string artist = track.Artist.ToLower();
+				string album = track.Album.ToLower();
+				string title = track.Title.ToLower();
+				string genre = track.Genre.ToLower();
+				ret = ( artist.Contains(search_term) ||
+					album.Contains(search_term) ||
+					title.Contains(search_term) ||
+					genre.Contains(search_term)
+					);
+			} catch (Exception e) {
+				Console.WriteLine (e.Message);
+			}
+			return ret;
+		}
+		
+		private void SearchFor (object o, EventArgs args)
+		{
+			view.Model = store_filter;
+			store_filter.Refilter();
+		}
+	}
+}

Added: branches/bgarret/src/TracksSource.cs
==============================================================================
--- (empty file)
+++ branches/bgarret/src/TracksSource.cs	Thu Jan 31 21:38:51 2008
@@ -0,0 +1,263 @@
+// TracksSource.cs
+//
+//  Copyright (C) 2008 Benoit Garret
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+//
+
+using System;
+using System.IO;
+using System.Collections.Generic;
+using Gtk;
+using Gdk;
+using IPod;
+using Mono.Unix;
+
+namespace Hipo
+{
+	public class TracksSource : TracksContainer
+	{
+		private TrackDatabase tracksDb;
+		private string name;
+		
+		public TracksSource (TrackDatabase db) : base ()
+		{
+			this.tracksDb = db;
+			Tracks = db.Tracks;
+			
+			this.name = Catalog.GetString ("Music");
+			this.Icon = Gnome.IconTheme.Default.LoadIcon ("stock_music-library", 16, 0);
+			
+			this.Type = Hipo.SourceType.Tracks;
+			this.Parent = SourceType.Device;
+		}
+		
+		public override string Name
+		{
+			get {
+				return name;
+			}
+			
+			set {
+			
+			}
+		}
+		
+		public override Menu Menu
+		{
+			get {
+				return null;
+			}
+		}
+		
+		public override int Count
+		{
+			get {
+				return tracksDb.Tracks.Count;
+			}
+		}
+		
+		public Playlist CreatePlaylist (string name)
+		{
+			Playlist playlist = null;
+			
+			if ((playlist = tracksDb.CreatePlaylist (name)) != null)
+			{
+				Saviour.Instance.Save ();
+			}
+			
+			return playlist;
+		}
+		
+		public void DeletePlaylist (Playlist playlist)
+		{
+			tracksDb.RemovePlaylist (playlist);
+		}
+		
+		public bool AddTrack (string path)
+		{
+			Track track = AddTrack (path, true);
+			
+			if (track != null)
+				Saviour.Instance.Save ();
+			
+			if (track == null)
+				return false;
+			else
+				return true;
+		}
+		
+		public override bool AddTracks (string[] uris, bool save)
+		{
+			bool trackAdded = false;
+			
+			foreach (string uri in uris)
+			{
+				Tools.Log (this, "Adding uri {0}", uri);
+				
+				Uri u = new Uri (uri);
+				Track track = AddTrack (u.LocalPath, false);
+				
+				if (track == null)
+					trackAdded |= false;
+				else
+				{
+					trackAdded |= true;
+				}
+			}
+			
+			if (trackAdded && save)
+				Saviour.Instance.Save ();
+			
+			return trackAdded;
+		}
+		
+		public Track AddTrack (string path, bool save)
+		{
+			Track track = null;
+			string ext = Path.GetExtension (path);
+
+			if ((ext.ToLower () == ".mp3") || (ext.ToLower () == ".mp4") ||
+			    (ext.ToLower () == ".m4a"))
+			{
+				TagLib.File file = TagLib.File.Create (path);
+				
+				track = tracksDb.CreateTrack ();
+				
+				if ((file.Tag.FirstArtist == null) || (file.Tag.FirstArtist == String.Empty))
+					track.Artist = "Unknown";
+				else
+					track.Artist = file.Tag.FirstArtist;
+				
+				if ((file.Tag.Title == null) || (file.Tag.Title == String.Empty))
+					track.Title = "Unknown";
+				else
+					track.Title = file.Tag.Title;
+				
+				if ((file.Tag.Album == null) || (file.Tag.Album == String.Empty))
+					track.Album = "Unknown";
+				else
+					track.Album = file.Tag.Album;
+				
+				if ((file.Tag.FirstGenre == null) || (file.Tag.FirstGenre == String.Empty))
+					track.Genre = "Unknown";
+				else
+					track.Genre = file.Tag.FirstGenre;
+				
+				track.FileName = path;
+				track.Duration = file.Properties.Duration;
+				track.TrackNumber = (int) file.Tag.Track;
+				
+				store.AppendValues (track);
+				
+				Tools.Log (this, "Added {0}", path);
+			}
+			
+			if (save && (track != null))
+				Saviour.Instance.Save ();
+			
+			return track;
+		}
+		
+		public override bool AddFolder (string[] dirs, bool save)
+		{
+			// returns true if at least one track has been added
+			bool trackAdded = false;
+			
+			foreach (string path in dirs)
+			{
+				if (path == null)
+					return false;
+				
+				Tools.Log (this, "Adding uri {0}", path);
+				
+				System.Uri uri = new System.Uri (path);
+
+				UnixDirectoryInfo info = new UnixDirectoryInfo (uri.LocalPath);
+				foreach (UnixFileSystemInfo file in info.GetFileSystemEntries ())
+				{
+					// |= gives true as soon as one of the arguments is true
+					if (!file.IsDirectory)
+					{
+						Track track = AddTrack (file.FullName, false);
+						if (track == null)
+							trackAdded |= false;
+						else
+							trackAdded |= true;
+					}
+					else
+					{
+						string[] tmp = { file.FullName };
+						trackAdded |= AddFolder (tmp, false);
+					}
+				}
+			}
+			
+			if (trackAdded && save)
+				Saviour.Instance.Save ();
+
+			return trackAdded;
+		}
+		
+		public void RemoveTrack (Track track)
+		{
+			RemoveTrack (track, true);
+		}
+		
+		public override void RemoveTracks (List<Track> tracks)
+		{
+			Tools.Log (this, "Removing {0} tracks from the database", tracks.Count);
+			
+			foreach (Track track in tracks)
+			{
+				RemoveTrack (track, false);
+			}
+			
+			Saviour.Instance.Save ();
+		}
+		
+		private void RemoveTrack (Track track, bool save)
+		{
+			tracksDb.RemoveTrack (track);
+			store.Foreach (delegate (TreeModel model, TreePath path, TreeIter iter) {
+				
+				Track t = (Track)model.GetValue (iter, 0);
+				
+				if (track.Id == t.Id)
+				{
+					store.Remove (ref iter);
+					return true;
+				}
+				else
+					return false;
+			});
+			
+			if (save)
+				Saviour.Instance.Save ();
+		}
+		
+		public Track GetTrack (long id)
+		{
+			foreach (Track track in Tracks)
+			{
+				if (track.Id == id)
+					return track;
+			}
+			
+			return null;
+		}
+	}
+}

Added: branches/bgarret/src/devicepopup.xml
==============================================================================
--- (empty file)
+++ branches/bgarret/src/devicepopup.xml	Thu Jan 31 21:38:51 2008
@@ -0,0 +1,6 @@
+<ui>
+  <popup name="DevicePopup">
+    <menuitem action="RenameDevice" />
+  </popup>
+</ui>
+

Modified: branches/bgarret/src/errordialog.glade
==============================================================================
--- branches/bgarret/src/errordialog.glade	(original)
+++ branches/bgarret/src/errordialog.glade	Thu Jan 31 21:38:51 2008
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
-<!--Generated with glade3 3.4.0 on Sun Dec  2 21:04:20 2007 -->
+<!--Generated with glade3 3.4.0 on Mon Jan 28 21:16:26 2008 -->
 <glade-interface>
   <widget class="GtkDialog" id="errorDialog">
     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
@@ -55,6 +55,7 @@
             <property name="visible">True</property>
             <property name="can_focus">True</property>
             <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">5</property>
             <child>
               <widget class="GtkScrolledWindow" id="scrolledwindow1">
                 <property name="visible">True</property>

Modified: branches/bgarret/src/hipo.glade
==============================================================================
--- branches/bgarret/src/hipo.glade	(original)
+++ branches/bgarret/src/hipo.glade	Thu Jan 31 21:38:51 2008
@@ -1,1185 +1,598 @@
-<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
-<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd";>
-
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
 <glade-interface>
-
-<widget class="GtkWindow" id="hipoWindow">
-  <property name="visible">True</property>
-  <property name="title" translatable="yes" context="yes">Hipo iPod Management Tool</property>
-  <property name="type">GTK_WINDOW_TOPLEVEL</property>
-  <property name="window_position">GTK_WIN_POS_NONE</property>
-  <property name="modal">False</property>
-  <property name="default_width">800</property>
-  <property name="default_height">600</property>
-  <property name="resizable">True</property>
-  <property name="destroy_with_parent">False</property>
-  <property name="decorated">True</property>
-  <property name="skip_taskbar_hint">False</property>
-  <property name="skip_pager_hint">False</property>
-  <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
-  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
-  <property name="focus_on_map">True</property>
-  <property name="urgency_hint">False</property>
-
-  <child>
-    <widget class="GtkVBox" id="vbox1">
-      <property name="visible">True</property>
-      <property name="homogeneous">False</property>
-      <property name="spacing">0</property>
-
-      <child>
-	<placeholder/>
-      </child>
-
-      <child>
-	<widget class="GtkHBox" id="hbox1">
-	  <property name="visible">True</property>
-	  <property name="homogeneous">False</property>
-	  <property name="spacing">0</property>
-
-	  <child>
-	    <widget class="GtkHPaned" id="hpaned1">
-	      <property name="border_width">5</property>
-	      <property name="visible">True</property>
-	      <property name="position">200</property>
-
-	      <child>
-		<widget class="GtkVBox" id="vbox2">
-		  <property name="visible">True</property>
-		  <property name="homogeneous">False</property>
-		  <property name="spacing">5</property>
-
-		  <child>
-		    <widget class="GtkLabel" id="label2">
-		      <property name="visible">True</property>
-		      <property name="label" translatable="yes" context="yes">&lt;b&gt;Music Library&lt;/b&gt;</property>
-		      <property name="use_underline">True</property>
-		      <property name="use_markup">True</property>
-		      <property name="justify">GTK_JUSTIFY_LEFT</property>
-		      <property name="wrap">True</property>
-		      <property name="selectable">False</property>
-		      <property name="xalign">0.0500000007451</property>
-		      <property name="yalign">0.5</property>
-		      <property name="xpad">0</property>
-		      <property name="ypad">0</property>
-		      <property name="mnemonic_widget">hpaned1</property>
-		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-		      <property name="width_chars">-1</property>
-		      <property name="single_line_mode">False</property>
-		      <property name="angle">0</property>
-		    </widget>
-		    <packing>
-		      <property name="padding">0</property>
-		      <property name="expand">False</property>
-		      <property name="fill">False</property>
-		    </packing>
-		  </child>
-
-		  <child>
-		    <widget class="GtkScrolledWindow" id="scrolledwindow2">
-		      <property name="visible">True</property>
-		      <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
-		      <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
-		      <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-		      <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
-
-		      <child>
-			<widget class="GtkTreeView" id="plistView">
-			  <property name="visible">True</property>
-			  <property name="headers_visible">True</property>
-			  <property name="rules_hint">False</property>
-			  <property name="reorderable">False</property>
-			  <property name="enable_search">True</property>
-			  <property name="fixed_height_mode">False</property>
-			  <property name="hover_selection">False</property>
-			  <property name="hover_expand">False</property>
-			</widget>
-		      </child>
-		    </widget>
-		    <packing>
-		      <property name="padding">0</property>
-		      <property name="expand">True</property>
-		      <property name="fill">True</property>
-		    </packing>
-		  </child>
-
-		  <child>
-		    <widget class="GtkProgressBar" id="ipodCapacityBar">
-		      <property name="visible">True</property>
-		      <property name="orientation">GTK_PROGRESS_LEFT_TO_RIGHT</property>
-		      <property name="fraction">0</property>
-		      <property name="pulse_step">0.10000000149</property>
-		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-		    </widget>
-		    <packing>
-		      <property name="padding">0</property>
-		      <property name="expand">False</property>
-		      <property name="fill">True</property>
-		    </packing>
-		  </child>
-		</widget>
-		<packing>
-		  <property name="shrink">True</property>
-		  <property name="resize">False</property>
-		</packing>
-	      </child>
-
-	      <child>
-		<widget class="GtkVBox" id="vbox3">
-		  <property name="visible">True</property>
-		  <property name="homogeneous">False</property>
-		  <property name="spacing">0</property>
-
-		  <child>
-		    <widget class="GtkHBox" id="hbox2">
-		      <property name="border_width">5</property>
-		      <property name="visible">True</property>
-		      <property name="homogeneous">False</property>
-		      <property name="spacing">5</property>
-
-		      <child>
-			<widget class="GtkLabel" id="label3">
-			  <property name="visible">True</property>
-			  <property name="label" translatable="yes" context="yes">_Search:</property>
-			  <property name="use_underline">True</property>
-			  <property name="use_markup">False</property>
-			  <property name="justify">GTK_JUSTIFY_LEFT</property>
-			  <property name="wrap">False</property>
-			  <property name="selectable">False</property>
-			  <property name="xalign">0.5</property>
-			  <property name="yalign">0.5</property>
-			  <property name="xpad">0</property>
-			  <property name="ypad">0</property>
-			  <property name="mnemonic_widget">filterEntry</property>
-			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-			  <property name="width_chars">-1</property>
-			  <property name="single_line_mode">False</property>
-			  <property name="angle">0</property>
-			</widget>
-			<packing>
-			  <property name="padding">0</property>
-			  <property name="expand">False</property>
-			  <property name="fill">False</property>
-			</packing>
-		      </child>
-
-		      <child>
-			<widget class="GtkEntry" id="filterEntry">
-			  <property name="width_request">255</property>
-			  <property name="visible">True</property>
-			  <property name="editable">True</property>
-			  <property name="visibility">True</property>
-			  <property name="max_length">0</property>
-			  <property name="text" translatable="yes"></property>
-			  <property name="has_frame">True</property>
-			  <property name="invisible_char">â</property>
-			  <property name="activates_default">False</property>
-			</widget>
-			<packing>
-			  <property name="padding">0</property>
-			  <property name="expand">False</property>
-			  <property name="fill">True</property>
-			</packing>
-		      </child>
-		    </widget>
-		    <packing>
-		      <property name="padding">0</property>
-		      <property name="expand">False</property>
-		      <property name="fill">True</property>
-		    </packing>
-		  </child>
-
-		  <child>
-		    <widget class="GtkScrolledWindow" id="scrolledwindow3">
-		      <property name="visible">True</property>
-		      <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
-		      <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
-		      <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-		      <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
-
-		      <child>
-			<widget class="GtkTreeView" id="tracksView">
-			  <property name="visible">True</property>
-			  <property name="headers_visible">True</property>
-			  <property name="rules_hint">True</property>
-			  <property name="reorderable">False</property>
-			  <property name="enable_search">True</property>
-			  <property name="fixed_height_mode">False</property>
-			  <property name="hover_selection">False</property>
-			  <property name="hover_expand">False</property>
-			</widget>
-		      </child>
-		    </widget>
-		    <packing>
-		      <property name="padding">0</property>
-		      <property name="expand">True</property>
-		      <property name="fill">True</property>
-		    </packing>
-		  </child>
-		</widget>
-		<packing>
-		  <property name="shrink">True</property>
-		  <property name="resize">True</property>
-		</packing>
-	      </child>
-	    </widget>
-	    <packing>
-	      <property name="padding">0</property>
-	      <property name="expand">True</property>
-	      <property name="fill">True</property>
-	    </packing>
-	  </child>
-	</widget>
-	<packing>
-	  <property name="padding">0</property>
-	  <property name="expand">True</property>
-	  <property name="fill">True</property>
-	</packing>
-      </child>
-
-      <child>
-	<widget class="GtkStatusbar" id="statusbar1">
-	  <property name="visible">True</property>
-	  <property name="has_resize_grip">True</property>
-	</widget>
-	<packing>
-	  <property name="padding">0</property>
-	  <property name="expand">False</property>
-	  <property name="fill">False</property>
-	</packing>
-      </child>
-    </widget>
-  </child>
-</widget>
-
-<widget class="GtkDialog" id="trackProperties">
-  <property name="visible">True</property>
-  <property name="title" translatable="yes"></property>
-  <property name="type">GTK_WINDOW_TOPLEVEL</property>
-  <property name="window_position">GTK_WIN_POS_NONE</property>
-  <property name="modal">False</property>
-  <property name="resizable">True</property>
-  <property name="destroy_with_parent">False</property>
-  <property name="decorated">True</property>
-  <property name="skip_taskbar_hint">False</property>
-  <property name="skip_pager_hint">False</property>
-  <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
-  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
-  <property name="focus_on_map">True</property>
-  <property name="urgency_hint">False</property>
-  <property name="has_separator">True</property>
-
-  <child internal-child="vbox">
-    <widget class="GtkVBox" id="dialog-vbox1">
-      <property name="visible">True</property>
-      <property name="homogeneous">False</property>
-      <property name="spacing">0</property>
-
-      <child internal-child="action_area">
-	<widget class="GtkHButtonBox" id="dialog-action_area1">
-	  <property name="visible">True</property>
-	  <property name="layout_style">GTK_BUTTONBOX_END</property>
-
-	  <child>
-	    <widget class="GtkButton" id="cancelbutton1">
-	      <property name="visible">True</property>
-	      <property name="can_default">True</property>
-	      <property name="can_focus">True</property>
-	      <property name="label">gtk-close</property>
-	      <property name="use_stock">True</property>
-	      <property name="relief">GTK_RELIEF_NORMAL</property>
-	      <property name="focus_on_click">True</property>
-	      <property name="response_id">-7</property>
-	    </widget>
-	  </child>
-
-	  <child>
-	    <widget class="GtkButton" id="okbutton1">
-	      <property name="visible">True</property>
-	      <property name="can_default">True</property>
-	      <property name="can_focus">True</property>
-	      <property name="label">gtk-save</property>
-	      <property name="use_stock">True</property>
-	      <property name="relief">GTK_RELIEF_NORMAL</property>
-	      <property name="focus_on_click">True</property>
-	      <property name="response_id">-5</property>
-	    </widget>
-	  </child>
-	</widget>
-	<packing>
-	  <property name="padding">0</property>
-	  <property name="expand">False</property>
-	  <property name="fill">True</property>
-	  <property name="pack_type">GTK_PACK_END</property>
-	</packing>
-      </child>
-
-      <child>
-	<widget class="GtkTable" id="table1">
-	  <property name="border_width">5</property>
-	  <property name="visible">True</property>
-	  <property name="n_rows">6</property>
-	  <property name="n_columns">2</property>
-	  <property name="homogeneous">False</property>
-	  <property name="row_spacing">5</property>
-	  <property name="column_spacing">12</property>
-
-	  <child>
-	    <widget class="GtkLabel" id="label4">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes">&lt;b&gt;_Artist:&lt;/b&gt;</property>
-	      <property name="use_underline">True</property>
-	      <property name="use_markup">True</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="mnemonic_widget">artistEntry</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">0</property>
-	      <property name="right_attach">1</property>
-	      <property name="top_attach">0</property>
-	      <property name="bottom_attach">1</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="label5">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes">&lt;b&gt;_Album:&lt;/b&gt;</property>
-	      <property name="use_underline">True</property>
-	      <property name="use_markup">True</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="mnemonic_widget">albumEntry</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">0</property>
-	      <property name="right_attach">1</property>
-	      <property name="top_attach">1</property>
-	      <property name="bottom_attach">2</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="titleLabel">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes">&lt;b&gt;_Title:&lt;/b&gt;</property>
-	      <property name="use_underline">True</property>
-	      <property name="use_markup">True</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="mnemonic_widget">titleEntry</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">0</property>
-	      <property name="right_attach">1</property>
-	      <property name="top_attach">2</property>
-	      <property name="bottom_attach">3</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="label7">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes">&lt;b&gt;_Genre:&lt;/b&gt;</property>
-	      <property name="use_underline">True</property>
-	      <property name="use_markup">True</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="mnemonic_widget">genreEntry</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">0</property>
-	      <property name="right_attach">1</property>
-	      <property name="top_attach">3</property>
-	      <property name="bottom_attach">4</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="numberLabel">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes">&lt;b&gt;_Track Number:&lt;/b&gt;</property>
-	      <property name="use_underline">True</property>
-	      <property name="use_markup">True</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="mnemonic_widget">numberSpin</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">0</property>
-	      <property name="right_attach">1</property>
-	      <property name="top_attach">4</property>
-	      <property name="bottom_attach">5</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="label9">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes">&lt;b&gt;_Artwork:&lt;/b&gt;</property>
-	      <property name="use_underline">True</property>
-	      <property name="use_markup">True</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">0</property>
-	      <property name="right_attach">1</property>
-	      <property name="top_attach">5</property>
-	      <property name="bottom_attach">6</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkEntry" id="artistEntry">
-	      <property name="visible">True</property>
-	      <property name="can_focus">True</property>
-	      <property name="editable">True</property>
-	      <property name="visibility">True</property>
-	      <property name="max_length">0</property>
-	      <property name="text" translatable="yes"></property>
-	      <property name="has_frame">True</property>
-	      <property name="invisible_char">â</property>
-	      <property name="activates_default">False</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">1</property>
-	      <property name="right_attach">2</property>
-	      <property name="top_attach">0</property>
-	      <property name="bottom_attach">1</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkEntry" id="albumEntry">
-	      <property name="visible">True</property>
-	      <property name="can_focus">True</property>
-	      <property name="editable">True</property>
-	      <property name="visibility">True</property>
-	      <property name="max_length">0</property>
-	      <property name="text" translatable="yes"></property>
-	      <property name="has_frame">True</property>
-	      <property name="invisible_char">â</property>
-	      <property name="activates_default">False</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">1</property>
-	      <property name="right_attach">2</property>
-	      <property name="top_attach">1</property>
-	      <property name="bottom_attach">2</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkEntry" id="titleEntry">
-	      <property name="visible">True</property>
-	      <property name="can_focus">True</property>
-	      <property name="editable">True</property>
-	      <property name="visibility">True</property>
-	      <property name="max_length">0</property>
-	      <property name="text" translatable="yes"></property>
-	      <property name="has_frame">True</property>
-	      <property name="invisible_char">â</property>
-	      <property name="activates_default">False</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">1</property>
-	      <property name="right_attach">2</property>
-	      <property name="top_attach">2</property>
-	      <property name="bottom_attach">3</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkEntry" id="genreEntry">
-	      <property name="visible">True</property>
-	      <property name="can_focus">True</property>
-	      <property name="editable">True</property>
-	      <property name="visibility">True</property>
-	      <property name="max_length">0</property>
-	      <property name="text" translatable="yes"></property>
-	      <property name="has_frame">True</property>
-	      <property name="invisible_char">â</property>
-	      <property name="activates_default">False</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">1</property>
-	      <property name="right_attach">2</property>
-	      <property name="top_attach">3</property>
-	      <property name="bottom_attach">4</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkSpinButton" id="numberSpin">
-	      <property name="visible">True</property>
-	      <property name="can_focus">True</property>
-	      <property name="climb_rate">1</property>
-	      <property name="digits">0</property>
-	      <property name="numeric">True</property>
-	      <property name="update_policy">GTK_UPDATE_ALWAYS</property>
-	      <property name="snap_to_ticks">False</property>
-	      <property name="wrap">False</property>
-	      <property name="adjustment">0 0 1000 1 10 10</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">1</property>
-	      <property name="right_attach">2</property>
-	      <property name="top_attach">4</property>
-	      <property name="bottom_attach">5</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkVBox" id="vbox4">
-	      <property name="visible">True</property>
-	      <property name="homogeneous">False</property>
-	      <property name="spacing">5</property>
-
-	      <child>
-		<widget class="GtkImage" id="artwork">
-		  <property name="visible">True</property>
-		  <property name="xalign">0.5</property>
-		  <property name="yalign">0.5</property>
-		  <property name="xpad">0</property>
-		  <property name="ypad">0</property>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">True</property>
-		  <property name="fill">True</property>
-		</packing>
-	      </child>
-
-	      <child>
-		<widget class="GtkButton" id="openArtwork">
-		  <property name="visible">True</property>
-		  <property name="can_focus">True</property>
-		  <property name="label">gtk-open</property>
-		  <property name="use_stock">True</property>
-		  <property name="relief">GTK_RELIEF_NORMAL</property>
-		  <property name="focus_on_click">True</property>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">False</property>
-		  <property name="fill">False</property>
-		</packing>
-	      </child>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">1</property>
-	      <property name="right_attach">2</property>
-	      <property name="top_attach">5</property>
-	      <property name="bottom_attach">6</property>
-	      <property name="x_options"></property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-	</widget>
-	<packing>
-	  <property name="padding">0</property>
-	  <property name="expand">True</property>
-	  <property name="fill">True</property>
-	</packing>
-      </child>
-    </widget>
-  </child>
-</widget>
-
-<widget class="GtkDialog" id="deviceProperties">
-  <property name="visible">True</property>
-  <property name="title" translatable="yes"></property>
-  <property name="type">GTK_WINDOW_TOPLEVEL</property>
-  <property name="window_position">GTK_WIN_POS_NONE</property>
-  <property name="modal">False</property>
-  <property name="resizable">True</property>
-  <property name="destroy_with_parent">False</property>
-  <property name="decorated">True</property>
-  <property name="skip_taskbar_hint">False</property>
-  <property name="skip_pager_hint">False</property>
-  <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
-  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
-  <property name="focus_on_map">True</property>
-  <property name="urgency_hint">False</property>
-  <property name="has_separator">True</property>
-
-  <child internal-child="vbox">
-    <widget class="GtkVBox" id="dialog-vbox2">
-      <property name="visible">True</property>
-      <property name="homogeneous">False</property>
-      <property name="spacing">0</property>
-
-      <child internal-child="action_area">
-	<widget class="GtkHButtonBox" id="dialog-action_area2">
-	  <property name="visible">True</property>
-	  <property name="layout_style">GTK_BUTTONBOX_END</property>
-
-	  <child>
-	    <widget class="GtkButton" id="cancelbutton2">
-	      <property name="visible">True</property>
-	      <property name="can_default">True</property>
-	      <property name="can_focus">True</property>
-	      <property name="label">gtk-close</property>
-	      <property name="use_stock">True</property>
-	      <property name="relief">GTK_RELIEF_NORMAL</property>
-	      <property name="focus_on_click">True</property>
-	      <property name="response_id">-7</property>
-	    </widget>
-	  </child>
-
-	  <child>
-	    <widget class="GtkButton" id="okbutton2">
-	      <property name="visible">True</property>
-	      <property name="can_default">True</property>
-	      <property name="can_focus">True</property>
-	      <property name="label">gtk-save</property>
-	      <property name="use_stock">True</property>
-	      <property name="relief">GTK_RELIEF_NORMAL</property>
-	      <property name="focus_on_click">True</property>
-	      <property name="response_id">-5</property>
-	    </widget>
-	  </child>
-	</widget>
-	<packing>
-	  <property name="padding">0</property>
-	  <property name="expand">False</property>
-	  <property name="fill">True</property>
-	  <property name="pack_type">GTK_PACK_END</property>
-	</packing>
-      </child>
-
-      <child>
-	<widget class="GtkTable" id="table2">
-	  <property name="border_width">5</property>
-	  <property name="visible">True</property>
-	  <property name="n_rows">8</property>
-	  <property name="n_columns">2</property>
-	  <property name="homogeneous">False</property>
-	  <property name="row_spacing">5</property>
-	  <property name="column_spacing">12</property>
-
-	  <child>
-	    <widget class="GtkLabel" id="label10">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes">&lt;b&gt;Name:&lt;/b&gt;</property>
-	      <property name="use_underline">False</property>
-	      <property name="use_markup">True</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">0</property>
-	      <property name="right_attach">1</property>
-	      <property name="top_attach">0</property>
-	      <property name="bottom_attach">1</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="label11">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes">&lt;b&gt;Model:&lt;/b&gt;</property>
-	      <property name="use_underline">False</property>
-	      <property name="use_markup">True</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">0</property>
-	      <property name="right_attach">1</property>
-	      <property name="top_attach">1</property>
-	      <property name="bottom_attach">2</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="label12">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes">&lt;b&gt;Serial Number:&lt;/b&gt;</property>
-	      <property name="use_underline">False</property>
-	      <property name="use_markup">True</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">0</property>
-	      <property name="right_attach">1</property>
-	      <property name="top_attach">2</property>
-	      <property name="bottom_attach">3</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkEntry" id="nameEntry">
-	      <property name="visible">True</property>
-	      <property name="can_focus">True</property>
-	      <property name="editable">True</property>
-	      <property name="visibility">True</property>
-	      <property name="max_length">0</property>
-	      <property name="text" translatable="yes"></property>
-	      <property name="has_frame">True</property>
-	      <property name="invisible_char">â</property>
-	      <property name="activates_default">False</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">1</property>
-	      <property name="right_attach">2</property>
-	      <property name="top_attach">0</property>
-	      <property name="bottom_attach">1</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="modelLabel">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes"></property>
-	      <property name="use_underline">False</property>
-	      <property name="use_markup">False</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">1</property>
-	      <property name="right_attach">2</property>
-	      <property name="top_attach">1</property>
-	      <property name="bottom_attach">2</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="serialLabel">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes"></property>
-	      <property name="use_underline">False</property>
-	      <property name="use_markup">False</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">1</property>
-	      <property name="right_attach">2</property>
-	      <property name="top_attach">2</property>
-	      <property name="bottom_attach">3</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="label15">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes">&lt;b&gt;Mount Point:&lt;/b&gt;</property>
-	      <property name="use_underline">False</property>
-	      <property name="use_markup">True</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">0</property>
-	      <property name="right_attach">1</property>
-	      <property name="top_attach">5</property>
-	      <property name="bottom_attach">6</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="label16">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes">&lt;b&gt;Space Used:&lt;/b&gt;</property>
-	      <property name="use_underline">False</property>
-	      <property name="use_markup">True</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">0</property>
-	      <property name="right_attach">1</property>
-	      <property name="top_attach">6</property>
-	      <property name="bottom_attach">7</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="capacityLabel">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes"></property>
-	      <property name="use_underline">False</property>
-	      <property name="use_markup">False</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">1</property>
-	      <property name="right_attach">2</property>
-	      <property name="top_attach">4</property>
-	      <property name="bottom_attach">5</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="mountLabel">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes"></property>
-	      <property name="use_underline">False</property>
-	      <property name="use_markup">False</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">1</property>
-	      <property name="right_attach">2</property>
-	      <property name="top_attach">5</property>
-	      <property name="bottom_attach">6</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="spaceLabel">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes"></property>
-	      <property name="use_underline">False</property>
-	      <property name="use_markup">False</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">1</property>
-	      <property name="right_attach">2</property>
-	      <property name="top_attach">6</property>
-	      <property name="bottom_attach">7</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="label14">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes">&lt;b&gt;Capacity:&lt;/b&gt;</property>
-	      <property name="use_underline">False</property>
-	      <property name="use_markup">True</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">0</property>
-	      <property name="right_attach">1</property>
-	      <property name="top_attach">4</property>
-	      <property name="bottom_attach">5</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="label17">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes">&lt;b&gt;Generation:&lt;/b&gt;</property>
-	      <property name="use_underline">False</property>
-	      <property name="use_markup">True</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">0</property>
-	      <property name="right_attach">1</property>
-	      <property name="top_attach">3</property>
-	      <property name="bottom_attach">4</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="generationLabel">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes"></property>
-	      <property name="use_underline">False</property>
-	      <property name="use_markup">False</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">1</property>
-	      <property name="right_attach">2</property>
-	      <property name="top_attach">3</property>
-	      <property name="bottom_attach">4</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="label18">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes">&lt;b&gt;Firmware Version:&lt;/b&gt;</property>
-	      <property name="use_underline">False</property>
-	      <property name="use_markup">True</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">0</property>
-	      <property name="right_attach">1</property>
-	      <property name="top_attach">7</property>
-	      <property name="bottom_attach">8</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="firmwareLabel">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes"></property>
-	      <property name="use_underline">False</property>
-	      <property name="use_markup">False</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="left_attach">1</property>
-	      <property name="right_attach">2</property>
-	      <property name="top_attach">7</property>
-	      <property name="bottom_attach">8</property>
-	      <property name="x_options">fill</property>
-	      <property name="y_options"></property>
-	    </packing>
-	  </child>
-	</widget>
-	<packing>
-	  <property name="padding">0</property>
-	  <property name="expand">True</property>
-	  <property name="fill">True</property>
-	</packing>
-      </child>
-    </widget>
-  </child>
-</widget>
-
+  <widget class="GtkWindow" id="hipoWindow">
+    <property name="visible">True</property>
+    <property name="title" translatable="yes" context="yes">Hipo iPod Management Tool</property>
+    <property name="default_width">800</property>
+    <property name="default_height">600</property>
+    <child>
+      <widget class="GtkVBox" id="menuBar">
+        <property name="visible">True</property>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <widget class="GtkHBox" id="hbox1">
+            <property name="visible">True</property>
+            <child>
+              <widget class="GtkHPaned" id="hpaned1">
+                <property name="visible">True</property>
+                <property name="border_width">5</property>
+                <property name="position">200</property>
+                <child>
+                  <widget class="GtkVBox" id="sourceListBox">
+                    <property name="visible">True</property>
+                    <property name="spacing">5</property>
+                    <child>
+                      <widget class="GtkScrolledWindow" id="sourceListScroll">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                        <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                        <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+                        <child>
+                          <placeholder/>
+                        </child>
+                      </widget>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="resize">False</property>
+                    <property name="shrink">True</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkVBox" id="vbox3">
+                    <property name="visible">True</property>
+                    <child>
+                      <widget class="GtkHBox" id="searchBox">
+                        <property name="visible">True</property>
+                        <property name="border_width">5</property>
+                        <property name="spacing">5</property>
+                        <child>
+                          <widget class="GtkLabel" id="searchLabel">
+                            <property name="visible">True</property>
+                            <property name="label" translatable="yes" context="yes">_Search:</property>
+                            <property name="use_underline">True</property>
+                          </widget>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkEntry" id="defaultSearchEntry">
+                            <property name="visible">True</property>
+                            <property name="sensitive">False</property>
+                            <property name="can_focus">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                          </widget>
+                          <packing>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </widget>
+                      <packing>
+                        <property name="expand">False</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkScrolledWindow" id="sourceScroll">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                        <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                        <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+                        <child>
+                          <widget class="GtkViewport" id="defaultSourceWidget">
+                            <property name="visible">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="resize_mode">GTK_RESIZE_QUEUE</property>
+                            <property name="shadow_type">GTK_SHADOW_NONE</property>
+                            <child>
+                              <widget class="GtkLabel" id="sourceLabel">
+                                <property name="visible">True</property>
+                                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                <property name="label" translatable="yes" context="yes">No device found.</property>
+                              </widget>
+                            </child>
+                          </widget>
+                        </child>
+                      </widget>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="resize">True</property>
+                    <property name="shrink">True</property>
+                  </packing>
+                </child>
+              </widget>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkStatusbar" id="statusbar1">
+            <property name="visible">True</property>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkDialog" id="trackProperties">
+    <property name="visible">True</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <child>
+          <widget class="GtkTable" id="table1">
+            <property name="visible">True</property>
+            <property name="border_width">5</property>
+            <property name="n_rows">6</property>
+            <property name="n_columns">2</property>
+            <property name="column_spacing">12</property>
+            <property name="row_spacing">5</property>
+            <child>
+              <widget class="GtkVBox" id="vbox4">
+                <property name="visible">True</property>
+                <property name="spacing">5</property>
+                <child>
+                  <widget class="GtkImage" id="artwork">
+                    <property name="visible">True</property>
+                    <property name="stock">gtk-missing-image</property>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkButton" id="openArtwork">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="label" context="yes">gtk-open</property>
+                    <property name="use_stock">True</property>
+                    <property name="response_id">0</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">5</property>
+                <property name="bottom_attach">6</property>
+                <property name="x_options"></property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkSpinButton" id="numberSpin">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="adjustment">0 0 1000 1 10 10</property>
+                <property name="climb_rate">1</property>
+                <property name="numeric">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">4</property>
+                <property name="bottom_attach">5</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkEntry" id="genreEntry">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">3</property>
+                <property name="bottom_attach">4</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkEntry" id="titleEntry">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkEntry" id="albumEntry">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkEntry" id="artistEntry">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label9">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes" context="yes">&lt;b&gt;_Artwork:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+                <property name="use_underline">True</property>
+              </widget>
+              <packing>
+                <property name="top_attach">5</property>
+                <property name="bottom_attach">6</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="numberLabel">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes" context="yes">&lt;b&gt;_Track Number:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">numberSpin</property>
+              </widget>
+              <packing>
+                <property name="top_attach">4</property>
+                <property name="bottom_attach">5</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label7">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes" context="yes">&lt;b&gt;_Genre:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">genreEntry</property>
+              </widget>
+              <packing>
+                <property name="top_attach">3</property>
+                <property name="bottom_attach">4</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="titleLabel">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes" context="yes">&lt;b&gt;_Title:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">titleEntry</property>
+              </widget>
+              <packing>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label5">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes" context="yes">&lt;b&gt;_Album:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">albumEntry</property>
+              </widget>
+              <packing>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label4">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes" context="yes">&lt;b&gt;_Artist:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">artistEntry</property>
+              </widget>
+              <packing>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="cancelbutton1">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="label" context="yes">gtk-close</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-7</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="okbutton1">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="label" context="yes">gtk-save</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-5</property>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkWindow" id="deviceProperties">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <child>
+      <widget class="GtkViewport" id="deviceViewport">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="resize_mode">GTK_RESIZE_QUEUE</property>
+        <property name="shadow_type">GTK_SHADOW_NONE</property>
+        <child>
+          <widget class="GtkTable" id="deviceTable">
+            <property name="visible">True</property>
+            <property name="border_width">10</property>
+            <property name="n_rows">7</property>
+            <property name="n_columns">2</property>
+            <property name="column_spacing">12</property>
+            <property name="row_spacing">5</property>
+            <child>
+              <widget class="GtkLabel" id="firmwareLabel">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">6</property>
+                <property name="bottom_attach">7</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label18">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes" context="yes">&lt;b&gt;Firmware Version:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="top_attach">6</property>
+                <property name="bottom_attach">7</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="generationLabel">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label17">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes" context="yes">&lt;b&gt;Generation:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label14">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes" context="yes">&lt;b&gt;Capacity:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="top_attach">3</property>
+                <property name="bottom_attach">4</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="spaceLabel">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">5</property>
+                <property name="bottom_attach">6</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="mountLabel">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">4</property>
+                <property name="bottom_attach">5</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="capacityLabel">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">3</property>
+                <property name="bottom_attach">4</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label16">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes" context="yes">&lt;b&gt;Space Used:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="top_attach">5</property>
+                <property name="bottom_attach">6</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label15">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes" context="yes">&lt;b&gt;Mount Point:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="top_attach">4</property>
+                <property name="bottom_attach">5</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="serialLabel">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="modelLabel">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label12">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes" context="yes">&lt;b&gt;Serial Number:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label11">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes" context="yes">&lt;b&gt;Model:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+          </widget>
+        </child>
+      </widget>
+    </child>
+  </widget>
 </glade-interface>

Added: branches/bgarret/src/menubar.xml
==============================================================================
--- (empty file)
+++ branches/bgarret/src/menubar.xml	Thu Jan 31 21:38:51 2008
@@ -0,0 +1,22 @@
+<ui>
+  <menubar name="HipoMenu">
+    <menu name="File" action="FileMenu">
+      <menuitem name="AddFile" action="AddFile" />
+      <menuitem name="AddFolder" action="AddFolder" />
+      <separator />
+      <menuitem name="NewPlaylist" action="NewPlaylist" />
+      <separator />
+      <menuitem name="Eject" action="Eject" />
+      <menuitem name="Quit" action="Quit" />
+    </menu>
+    <menu name="Edit" action="EditMenu">
+      <menuitem name="Preferences" action="Preferences" />
+    </menu>
+    <menu name="Help" action="HelpMenu">
+      <menuitem name="Contents" action="Help" />
+      <separator />
+      <menuitem name="About" action="About" />
+    </menu>
+  </menubar>
+</ui>
+

Added: branches/bgarret/src/playlistpopup.xml
==============================================================================
--- (empty file)
+++ branches/bgarret/src/playlistpopup.xml	Thu Jan 31 21:38:51 2008
@@ -0,0 +1,6 @@
+<ui>
+  <popup name="PlaylistPopup">
+    <menuitem action="RenamePlaylist" />
+    <menuitem action="DeletePlaylist" />
+  </popup>
+</ui>

Added: branches/bgarret/src/trackpopup.xml
==============================================================================
--- (empty file)
+++ branches/bgarret/src/trackpopup.xml	Thu Jan 31 21:38:51 2008
@@ -0,0 +1,7 @@
+<ui>
+  <popup name="TrackPopup">
+    <menuitem action="AddToPlaylist" />
+    <menuitem action="Remove" />
+    <menuitem action="TrackProperties" />
+  </popup>
+</ui>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]