banshee r4414 - in trunk/banshee: . build/m4/banshee src/Core/Banshee.Core/Banshee.Collection src/Core/Banshee.Core/Resources src/Core/Banshee.Services/Banshee.Collection.Database src/Core/Banshee.Services/Banshee.Database src/Core/Banshee.Services/Banshee.Playlist src/Core/Banshee.Services/Banshee.SmartPlaylist src/Core/Banshee.Services/Banshee.Sources src/Dap/Banshee.Dap src/Dap/Banshee.Dap/Banshee.Dap src/Libraries/Hyena/Hyena.Data.Sqlite



Author: gburt
Date: Thu Aug 21 21:03:03 2008
New Revision: 4414
URL: http://svn.gnome.org/viewvc/banshee?rev=4414&view=rev

Log:
2008-08-21  Gabriel Burt  <gabriel burt gmail com>

	* src/Dap/Banshee.Dap/Makefile.am:
	* src/Dap/Banshee.Dap/Banshee.Dap.mdp: Add new files.

	* src/Dap/Banshee.Dap/Banshee.Dap/DapSync.cs:
	* src/Dap/Banshee.Dap/Banshee.Dap/DapLibrarySync.cs: New classes that
	contain all the logic for syncing a DAP to the libraries.  Use smart
	playlists to represent the 

	* src/Dap/Banshee.Dap/Banshee.Dap/RemovableSource.cs: Add a virtual
	BytesAvailable property.

	* src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs: Remove temporary sync code
	I recently committed, add a schema pref for space_for_data and respect it
	when transferring files, override the BytesAvailable to subtract out the
	bytes reserved for data.

	* src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs:
	* src/Core/Banshee.Core/Banshee.Collection/TrackInfo.cs: Move the
	MetadataHash property to TrackInfo.

	* src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs:
	* src/Core/Banshee.Services/Banshee.Playlist/AbstractPlaylistSource.cs:
	* src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs:
	Add an IsTemporary property, and delete temporary playlists from the
	database on startup.

	* src/Core/Banshee.Services/Banshee.Sources/Source.cs: Add another
	CreateSchema override that takes a namespace.

	* src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs:
	Add IsTemporary columns to CorePlaylists/SmartPlaylists/PrimarySources.

	* src/Core/Banshee.Core/Resources/contributors.xml: Add Andrew Conkling -
	he has done so much work for so long in Bugzilla, should have been listed
	here long ago.

	* src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteConnection.cs: Fix
	small bug in HyenaDataReader in how/when it calls .Read on the underlying
	IDataReader.

	* build/m4/banshee/taglib.m4: Require 2.0.3 since that's when
	IsCompilation was introduced.



Added:
   trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapLibrarySync.cs
   trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSync.cs
Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/build/m4/banshee/taglib.m4
   trunk/banshee/src/Core/Banshee.Core/Banshee.Collection/TrackInfo.cs
   trunk/banshee/src/Core/Banshee.Core/Resources/contributors.xml
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/AbstractPlaylistSource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/Source.cs
   trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap.mdp
   trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs
   trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/RemovableSource.cs
   trunk/banshee/src/Dap/Banshee.Dap/Makefile.am
   trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteConnection.cs

Modified: trunk/banshee/build/m4/banshee/taglib.m4
==============================================================================
--- trunk/banshee/build/m4/banshee/taglib.m4	(original)
+++ trunk/banshee/build/m4/banshee/taglib.m4	Thu Aug 21 21:03:03 2008
@@ -1,5 +1,5 @@
 AC_DEFUN([BANSHEE_CHECK_TAGLIB_SHARP],
 [
-	PKG_CHECK_MODULES(TAGLIB_SHARP, taglib-sharp >= 2.0.0)
+	PKG_CHECK_MODULES(TAGLIB_SHARP, taglib-sharp >= 2.0.3)
 	AC_SUBST(TAGLIB_SHARP_LIBS)
 ])

Modified: trunk/banshee/src/Core/Banshee.Core/Banshee.Collection/TrackInfo.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Core/Banshee.Collection/TrackInfo.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Core/Banshee.Collection/TrackInfo.cs	Thu Aug 21 21:03:03 2008
@@ -361,6 +361,20 @@
             get { return can_play; }
             set { can_play = value; }
         }
+        
+        public virtual string MetadataHash {
+            get {
+                System.Text.StringBuilder sb = new System.Text.StringBuilder ();
+                sb.Append (AlbumTitle);
+                sb.Append (ArtistName);
+                sb.Append ((int)Duration.TotalSeconds);
+                sb.Append (Genre);
+                sb.Append (TrackTitle);
+                sb.Append (TrackNumber);
+                sb.Append (Year);
+                return Hyena.CryptoUtil.Md5Encode (sb.ToString (), System.Text.Encoding.UTF8);
+            }
+        }
 
         private TrackMediaAttributes media_attributes = TrackMediaAttributes.Default;
         public virtual TrackMediaAttributes MediaAttributes {

Modified: trunk/banshee/src/Core/Banshee.Core/Resources/contributors.xml
==============================================================================
--- trunk/banshee/src/Core/Banshee.Core/Resources/contributors.xml	(original)
+++ trunk/banshee/src/Core/Banshee.Core/Resources/contributors.xml	Thu Aug 21 21:03:03 2008
@@ -7,6 +7,7 @@
   <contributor>Alexander Hixon</contributor>
   <contributor>Alexandros Frantzis</contributor>
   <contributor>Alp Toker</contributor>
+  <contributor>Andrew Conkling</contributor>
   <contributor>Andy Midgette</contributor>
   <contributor>Aydemir UlaÅ Åahin</contributor>
   <contributor>Ben Maurer</contributor>

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs	Thu Aug 21 21:03:03 2008
@@ -370,18 +370,8 @@
         }
 
         [DatabaseColumn(Select = false)]
-        protected string MetadataHash {
-            get {
-                System.Text.StringBuilder sb = new System.Text.StringBuilder ();
-                sb.Append (AlbumTitle);
-                sb.Append (ArtistName);
-                sb.Append ((int)Duration.TotalSeconds);
-                sb.Append (Genre);
-                sb.Append (TrackTitle);
-                sb.Append (TrackNumber);
-                sb.Append (Year);
-                return Hyena.CryptoUtil.Md5Encode (sb.ToString (), System.Text.Encoding.UTF8);
-            }
+        public override string MetadataHash {
+            get { return base.MetadataHash; }
         }
         
         [DatabaseColumn]

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs	Thu Aug 21 21:03:03 2008
@@ -52,7 +52,7 @@
         // NOTE: Whenever there is a change in ANY of the database schema,
         //       this version MUST be incremented and a migration method
         //       MUST be supplied to match the new version number
-        protected const int CURRENT_VERSION = 19;
+        protected const int CURRENT_VERSION = 20;
         protected const int CURRENT_METADATA_VERSION = 4;
         
 #region Migration Driver
@@ -509,6 +509,19 @@
         
 #endregion
 
+#region Version 20
+
+        [DatabaseVersion (20)]
+        private bool Migrate_20 ()
+        {
+            Execute ("ALTER TABLE CoreSmartPlaylists ADD COLUMN IsTemporary INTEGER DEFAULT 0");
+            Execute ("ALTER TABLE CorePlaylists ADD COLUMN IsTemporary INTEGER DEFAULT 0");
+            Execute ("ALTER TABLE CorePrimarySources ADD COLUMN IsTemporary INTEGER DEFAULT 0");
+            return true;
+        }
+        
+#endregion
+
 #pragma warning restore 0169
         
 #region Fresh database setup
@@ -543,7 +556,8 @@
                 CREATE TABLE CorePrimarySources (
                     PrimarySourceID     INTEGER PRIMARY KEY,
                     StringID            TEXT UNIQUE,
-                    CachedCount         INTEGER
+                    CachedCount         INTEGER,
+                    IsTemporary         INTEGER DEFAULT 0
                 )
             ");
             Execute ("INSERT INTO CorePrimarySources (StringID) VALUES ('MusicLibrarySource-Library')");
@@ -648,7 +662,8 @@
                     SortColumn          INTEGER NOT NULL DEFAULT -1,
                     SortType            INTEGER NOT NULL DEFAULT 0,
                     Special             INTEGER NOT NULL DEFAULT 0,
-                    CachedCount         INTEGER
+                    CachedCount         INTEGER,
+                    IsTemporary         INTEGER DEFAULT 0
                 )
             ");
             
@@ -671,7 +686,8 @@
                     OrderBy             TEXT,
                     LimitNumber         TEXT,
                     LimitCriterion      TEXT,
-                    CachedCount         INTEGER
+                    CachedCount         INTEGER,
+                    IsTemporary         INTEGER DEFAULT 0
                 )
             ");
                 

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/AbstractPlaylistSource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/AbstractPlaylistSource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/AbstractPlaylistSource.cs	Thu Aug 21 21:03:03 2008
@@ -78,6 +78,12 @@
             get { return true; }
         }
 
+        private bool is_temporary = false;
+        public bool IsTemporary {
+            get { return is_temporary; }
+            set { is_temporary = value; }
+        }
+
         public int? DbId {
             get { return dbid; }
             protected set {
@@ -123,13 +129,14 @@
         }
 
         public AbstractPlaylistSource (string generic_name, string name, int primarySourceId)
-            : this (generic_name, name, null, -1, 0, primarySourceId)
+            : this (generic_name, name, null, -1, 0, primarySourceId, false)
         {
         }
 
-        public AbstractPlaylistSource (string generic_name, string name, int? dbid, int sortColumn, int sortType, int primarySourceId)
+        public AbstractPlaylistSource (string generic_name, string name, int? dbid, int sortColumn, int sortType, int primarySourceId, bool is_temp)
             : base (generic_name, name, Convert.ToString (dbid), 500)
         {
+            IsTemporary = is_temp;
             this.primary_source_id = primarySourceId;
         }
 

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs	Thu Aug 21 21:03:03 2008
@@ -111,12 +111,12 @@
         {
         }
 
-        protected PlaylistSource (string name, int? dbid, int primarySourceId) : this (name, dbid, -1, 0, primarySourceId, 0)
+        protected PlaylistSource (string name, int? dbid, int primarySourceId) : this (name, dbid, -1, 0, primarySourceId, 0, false)
         {
         }
 
-        protected PlaylistSource (string name, int? dbid, int sortColumn, int sortType, int primarySourceId, int count)
-            : base (generic_name, name, dbid, sortColumn, sortType, primarySourceId)
+        protected PlaylistSource (string name, int? dbid, int sortColumn, int sortType, int primarySourceId, int count, bool is_temp)
+            : base (generic_name, name, dbid, sortColumn, sortType, primarySourceId, is_temp)
         {
             Properties.SetString ("Icon.Name", "source-playlist");
             Properties.SetString ("RemoveTracksActionLabel", Catalog.GetString ("Remove From Playlist"));
@@ -153,19 +153,20 @@
                         SET Name = ?,
                             SortColumn = ?,
                             SortType = ?,
-                            CachedCount = ?
+                            CachedCount = ?,
+                            IsTemporary = ?
                         WHERE PlaylistID = ?",
                     SourceTable
-                ), Name, -1, 0, Count, dbid
+                ), Name, -1, 0, Count, IsTemporary, dbid
             ));
         }
 
         protected override void Create ()
         {
             DbId = ServiceManager.DbConnection.Execute (new HyenaSqliteCommand (
-                @"INSERT INTO CorePlaylists (PlaylistID, Name, SortColumn, SortType, PrimarySourceID)
-                    VALUES (NULL, ?, ?, ?, ?)",
-                Name, -1, 1, PrimarySourceId //SortColumn, SortType
+                @"INSERT INTO CorePlaylists (PlaylistID, Name, SortColumn, SortType, PrimarySourceID, IsTemporary)
+                    VALUES (NULL, ?, ?, ?, ?, ?)",
+                Name, -1, 1, PrimarySourceId, IsTemporary //SortColumn, SortType
             ));
         }
 
@@ -330,19 +331,34 @@
 
         public static IEnumerable<PlaylistSource> LoadAll (int primary_id)
         {
-            using (IDataReader reader = ServiceManager.DbConnection.Query (
-                @"SELECT PlaylistID, Name, SortColumn, SortType, PrimarySourceID, CachedCount FROM CorePlaylists 
-                    WHERE Special = 0 AND PrimarySourceID = ?", primary_id)) {
+            ClearTemporary ();
+            using (HyenaDataReader reader = new HyenaDataReader (ServiceManager.DbConnection.Query (
+                @"SELECT PlaylistID, Name, SortColumn, SortType, PrimarySourceID, CachedCount, IsTemporary FROM CorePlaylists 
+                    WHERE Special = 0 AND PrimarySourceID = ?", primary_id))) {
                 while (reader.Read ()) {
                     yield return new PlaylistSource (
-                        reader[1] as string, Convert.ToInt32 (reader[0]),
-                        Convert.ToInt32 (reader[2]), Convert.ToInt32 (reader[3]), Convert.ToInt32 (reader[4]),
-                        Convert.ToInt32 (reader[5])
+                        reader.Get<string> (1), reader.Get<int> (0),
+                        reader.Get<int> (2), reader.Get<int> (3), reader.Get<int> (4),
+                        reader.Get<int> (5), reader.Get<bool> (6)
                     );
                 }
             }
         }
 
+        private static bool temps_cleared = false;
+        private static void ClearTemporary ()
+        {
+            if (!temps_cleared) {
+                temps_cleared = true;
+                ServiceManager.DbConnection.Execute (@"
+                    BEGIN TRANSACTION;
+                        DELETE FROM CorePlaylistEntries WHERE PlaylistID IN (SELECT PlaylistID FROM CorePlaylists WHERE IsTemporary = 1);
+                        DELETE FROM CorePlaylists WHERE IsTemporary = 1;
+                    COMMIT TRANSACTION"
+                );
+            }
+        }
+
         public override void SetParentSource (Source parent)
         {
             base.SetParentSource (parent);

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs	Thu Aug 21 21:03:03 2008
@@ -182,12 +182,12 @@
 
 #region Constructors
 
-        public SmartPlaylistSource (string name, int primarySourceId) : this (null, name, String.Empty, String.Empty, String.Empty, String.Empty, primarySourceId, 0)
+        public SmartPlaylistSource (string name, int primarySourceId) : this (null, name, String.Empty, String.Empty, String.Empty, String.Empty, primarySourceId, 0, false)
         {
         }
 
         public SmartPlaylistSource (string name, QueryNode condition, QueryOrder order, QueryLimit limit, IntegerQueryValue limit_value, int primarySourceId)
-            : base (generic_name, name, null, -1, 0, primarySourceId)
+            : base (generic_name, name, null, -1, 0, primarySourceId, false)
         {
             ConditionTree = condition;
             QueryOrder = order;
@@ -199,8 +199,8 @@
         }
 
         // For existing smart playlists that we're loading from the database
-        protected SmartPlaylistSource (int? dbid, string name, string condition_xml, string order_by, string limit_number, string limit_criterion, int primarySourceId, int count) :
-            base (generic_name, name, dbid, -1, 0, primarySourceId)
+        protected SmartPlaylistSource (int? dbid, string name, string condition_xml, string order_by, string limit_number, string limit_criterion, int primarySourceId, int count, bool is_temp) :
+            base (generic_name, name, dbid, -1, 0, primarySourceId, is_temp)
         {
             ConditionXml = condition_xml;
             QueryOrder = BansheeQuery.FindOrder (order_by);
@@ -275,13 +275,13 @@
         {
             DbId = ServiceManager.DbConnection.Execute (new HyenaSqliteCommand (@"
                 INSERT INTO CoreSmartPlaylists
-                    (Name, Condition, OrderBy, LimitNumber, LimitCriterion, PrimarySourceID)
-                    VALUES (?, ?, ?, ?, ?, ?)",
+                    (Name, Condition, OrderBy, LimitNumber, LimitCriterion, PrimarySourceID, IsTemporary)
+                    VALUES (?, ?, ?, ?, ?, ?, ?)",
                 Name, ConditionXml,
                 IsLimited ? QueryOrder.Name : null,
                 IsLimited ? LimitValue.ToSql () : null,
                 IsLimited ? Limit.Name : null,
-                PrimarySourceId
+                PrimarySourceId, IsTemporary
             ));
             UpdateDependencies ();
         }
@@ -295,13 +295,14 @@
                         OrderBy = ?,
                         LimitNumber = ?,
                         LimitCriterion = ?,
-                        CachedCount = ?
+                        CachedCount = ?,
+                        IsTemporary = ?
                     WHERE SmartPlaylistID = ?",
                 Name, ConditionXml,
                 IsLimited ? QueryOrder.Name : null,
                 IsLimited ? LimitValue.ToSql () : null,
                 IsLimited ? Limit.Name : null,
-                Count, DbId
+                Count, IsTemporary, DbId
             ));
             UpdateDependencies ();
         }
@@ -479,17 +480,18 @@
 
         public static IEnumerable<SmartPlaylistSource> LoadAll (int primary_id)
         {
-            using (IDataReader reader = ServiceManager.DbConnection.Query (
-                @"SELECT SmartPlaylistID, Name, Condition, OrderBy, LimitNumber, LimitCriterion, PrimarySourceID, CachedCount
-                    FROM CoreSmartPlaylists WHERE PrimarySourceID = ?", primary_id)) {
+            ClearTemporary ();
+            using (HyenaDataReader reader = new HyenaDataReader (ServiceManager.DbConnection.Query (
+                @"SELECT SmartPlaylistID, Name, Condition, OrderBy, LimitNumber, LimitCriterion, PrimarySourceID, CachedCount, IsTemporary
+                    FROM CoreSmartPlaylists WHERE PrimarySourceID = ?", primary_id))) {
                 while (reader.Read ()) {
                     SmartPlaylistSource playlist = null;
                     try {
                         playlist = new SmartPlaylistSource (
-                            Convert.ToInt32 (reader[0]), reader[1] as string,
-                            reader[2] as string, reader[3] as string,
-                            reader[4] as string, reader[5] as string,
-                            Convert.ToInt32 (reader[6]), Convert.ToInt32 (reader[7])
+                            reader.Get<int> (0), reader.Get<string> (1),
+                            reader.Get<string> (2), reader.Get<string> (3),
+                            reader.Get<string> (4), reader.Get<string> (5),
+                            reader.Get<int> (6), reader.Get<int> (7), reader.Get<bool> (8)
                         );
                     } catch (Exception e) {
                         Log.Warning ("Ignoring Smart Playlist", String.Format ("Caught error: {0}", e), false);
@@ -502,6 +504,20 @@
             }
         }
 
+        private static bool temps_cleared = false;
+        private static void ClearTemporary ()
+        {
+            if (!temps_cleared) {
+                temps_cleared = true;
+                ServiceManager.DbConnection.Execute (@"
+                    BEGIN TRANSACTION;
+                        DELETE FROM CoreSmartPlaylistEntries WHERE SmartPlaylistID IN (SELECT SmartPlaylistID FROM CoreSmartPlaylists WHERE IsTemporary = 1);
+                        DELETE FROM CoreSmartPlaylists WHERE IsTemporary = 1;
+                    COMMIT TRANSACTION"
+                );
+            }
+        }
+
         private static void HandleSourceAdded (SourceEventArgs args)
         {
             SmartPlaylistSource playlist = args.Source as SmartPlaylistSource;

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/Source.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/Source.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/Source.cs	Thu Aug 21 21:03:03 2008
@@ -559,9 +559,14 @@
             return CreateSchema<T> (name, default(T), null, null);
         }
         
-        public SchemaEntry<T> CreateSchema<T> (string name, T defaultValue, string shotDescription, string longDescription)
+        public SchemaEntry<T> CreateSchema<T> (string name, T defaultValue, string shortDescription, string longDescription)
         {
-            return new SchemaEntry<T> (String.Format ("sources.{0}", ConfigurationId), name, defaultValue, shotDescription, longDescription); 
+            return new SchemaEntry<T> (String.Format ("sources.{0}", ConfigurationId), name, defaultValue, shortDescription, longDescription); 
+        }
+        
+        public SchemaEntry<T> CreateSchema<T> (string ns, string name, T defaultValue, string shortDescription, string longDescription)
+        {
+            return new SchemaEntry<T> (String.Format ("sources.{0}.{1}", ConfigurationId, ns), name, defaultValue, shortDescription, longDescription); 
         }
         
         public void CycleStatusFormat ()

Modified: trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap.mdp
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap.mdp	(original)
+++ trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap.mdp	Thu Aug 21 21:03:03 2008
@@ -19,6 +19,8 @@
     <File name="Banshee.Dap/MusicGroupSource.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Dap.Gui/DapInfoBar.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Dap.Gui/DapPropertiesDisplay.cs" subtype="Code" buildaction="Compile" />
+    <File name="Banshee.Dap/DapSync.cs" subtype="Code" buildaction="Compile" />
+    <File name="Banshee.Dap/DapLibrarySync.cs" subtype="Code" buildaction="Compile" />
   </Contents>
   <References>
     <ProjectReference type="Project" localcopy="True" refto="Banshee.Core" />
@@ -31,6 +33,7 @@
     <ProjectReference type="Gac" localcopy="True" refto="Mono.Cairo, Version=2.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756" />
     <ProjectReference type="Project" localcopy="True" refto="Banshee.Widgets" />
   </References>
+  <GtkDesignInfo gtkVersion="2.12.1" />
   <MonoDevelop.Autotools.MakefileInfo IntegrationEnabled="True" RelativeMakefileName="./Makefile.am">
     <BuildFilesVar Sync="True" Name="SOURCES" />
     <DeployFilesVar />

Added: trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapLibrarySync.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapLibrarySync.cs	Thu Aug 21 21:03:03 2008
@@ -0,0 +1,180 @@
+//
+// DapLibrarySync.cs
+//
+// Authors:
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+
+using Hyena;
+using Hyena.Query;
+
+using Banshee.Configuration;
+using Banshee.Sources;
+using Banshee.ServiceStack;
+using Banshee.Library;
+using Banshee.Playlist;
+using Banshee.SmartPlaylist;
+using Banshee.Query;
+
+namespace Banshee.Dap
+{ 
+    public sealed class DapLibrarySync
+    {
+        private DapSync sync;
+        private LibrarySource library;
+        private string conf_ns;
+        private SchemaEntry<bool> enabled, sync_entire_library;
+        private SchemaEntry<string[]> playlist_ids;
+        private SmartPlaylistSource sync_src, to_add;
+        
+        #region Public Properties
+
+        public bool Enabled {
+            get { return sync.Enabled && enabled.Get (); }
+        }
+        
+        public bool SyncEntireLibrary {
+            get { return sync_entire_library.Get (); }
+        }
+        
+        #endregion
+        
+        private string [] SyncPlaylistIds {
+            get { return playlist_ids.Get (); }
+        }
+        
+        List<AbstractPlaylistSource> sync_playlists;
+        private IList<AbstractPlaylistSource> SyncPlaylists {
+            get {
+                if (sync_playlists == null) {
+                    sync_playlists = new List<AbstractPlaylistSource> ();
+                    foreach (string id in SyncPlaylistIds) {
+                        foreach (Source src in library.Children) {
+                            if (src.UniqueId == id) {
+                                sync_playlists.Add (src as AbstractPlaylistSource);
+                                break;
+                            }
+                        }
+                    }
+                }
+                return sync_playlists;
+            }
+        }
+
+        internal string SmartPlaylistId {
+            get { return sync_src.DbId.ToString (); }
+        }
+        
+        internal DapLibrarySync (DapSync sync, LibrarySource library)
+        {
+            this.sync = sync;
+            this.library = library;
+            conf_ns = String.Format ("{0}.{1}", sync.ConfigurationNamespace, library.ConfigurationId);
+            
+            enabled = sync.Dap.CreateSchema<bool> (conf_ns, "enabled", true,
+                "Whether sync is enabled for this device and library source.", "");
+            
+            sync_entire_library = sync.Dap.CreateSchema<bool> (conf_ns, "sync_entire_library", true,
+                "Whether to sync the entire library and all playlists.", "");
+            
+            playlist_ids = sync.Dap.CreateSchema<string[]> (conf_ns, "playlist_ids", new string [0],
+                "If sync_entire_library is false, this contains a list of playlist ids specifically to sync", "");
+
+            // This smart playlist is the list of items we want on the device - nothing more, nothing less
+            sync_src = new SmartPlaylistSource ("sync_list", library.DbId);
+            sync_src.IsTemporary = true;
+            sync_src.Save ();
+
+            // This is the same as the previous list with the items that are already on the device removed
+            to_add = new SmartPlaylistSource ("to_add", library.DbId);
+            to_add.IsTemporary = true;
+            to_add.Save ();
+            to_add.ConditionTree = UserQueryParser.Parse (String.Format ("smartplaylistid:{0}", sync_src.DbId),
+                Banshee.Query.BansheeQuery.FieldSet);
+            to_add.DatabaseTrackModel.AddCondition (String.Format (
+                "MetadataHash NOT IN (SELECT MetadataHash FROM CoreTracks WHERE PrimarySourceId = {0})", sync.Dap.DbId
+            ));
+        }
+        
+        internal void CalculateSync ()
+        {
+            if (SyncEntireLibrary) {
+                to_add.ConditionTree = null;
+            } else if (SyncPlaylistIds.Length > 0) {
+                QueryListNode playlists_node = new QueryListNode (Keyword.Or);
+                foreach (AbstractPlaylistSource src in SyncPlaylists) {
+                    if (src is PlaylistSource) {
+                        playlists_node.AddChild (UserQueryParser.Parse (String.Format ("playlistid:{0}", src.DbId), BansheeQuery.FieldSet));
+                    } else if (src is SmartPlaylistSource) {
+                        playlists_node.AddChild (UserQueryParser.Parse (String.Format ("smartplaylistid:{0}", src.DbId), BansheeQuery.FieldSet));
+                    }
+                }
+                sync_src.ConditionTree = playlists_node;
+            }
+            sync_src.RefreshAndReload ();
+            to_add.RefreshAndReload ();
+        }
+
+        public override string ToString ()
+        {
+            return String.Format ("Sync calculated for {1}: to add: {0} items", to_add.Count, library.Name);
+        }
+        
+        internal void Sync ()
+        {
+            CalculateSync ();
+            
+            DoSyncPlaylists ();
+        }
+        
+        private void DoSyncPlaylists ()
+        {
+            // Remove all playlists
+            foreach (Source child in sync.Dap.Children) {
+                if (child is AbstractPlaylistSource && !(child is MediaGroupSource)) {
+                    (child as IUnmapableSource).Unmap ();
+                }
+            }
+            
+            if (!SyncEntireLibrary && SyncPlaylistIds.Length == 0) {
+                return;
+            }
+
+            foreach (AbstractPlaylistSource src in SyncPlaylists) {
+                SyncPlaylist (src);
+            }
+        }
+        
+        private void SyncPlaylist (AbstractPlaylistSource from)
+        {
+            //PlaylistSource to = new PlaylistSource (from.Name, sync.Dap.DbId);
+            //to.Save ();
+            
+            // copy playlist/track entries based on metadatahash..
+        }
+    }
+}

Modified: trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs	(original)
+++ trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs	Thu Aug 21 21:03:03 2008
@@ -82,6 +82,7 @@
         {
             this.device = device;
             type_unique_id = device.Uuid;
+            space_for_data = CreateSchema<long> ("space_for_data", 0, "How much space, in bytes, to reserve for data on the device.", "");
         }
 
         public override void Dispose ()
@@ -201,76 +202,7 @@
 #endregion
         
 #region Track Management/Syncing   
-
-        public void SyncWith (PrimarySource source)
-        {
-            try {
-                SourceSync from_music = new SourceSync (ServiceManager.SourceManager.MusicLibrary, this);
-                Log.Information (from_music.ToString ());
-                
-                SourceSync to_music = new SourceSync (this, ServiceManager.SourceManager.MusicLibrary);
-                Log.Information (to_music.ToString ());
-            } catch (Exception e) {
-                Log.Exception (e);
-            }
-        }
-        
-        public class SourceSync
-        {
-            const string intersection = @"PrimarySourceId = ? AND MetadataHash NOT IN 
-                    (SELECT MetadataHash FROM CoreTracks WHERE PrimarySourceID = ?)";
-            
-            PrimarySource from, to;
-            int count;
-            long file_size;
-            TimeSpan duration;
-            
-            public SourceSync (PrimarySource from, PrimarySource to)
-            {
-                this.from = from;
-                this.to = to;
-                Update ();
-            }
-            
-            public void Update ()
-            {
-                using (new Hyena.Timer ("seeing what there is to sync")) {
-                    using (HyenaDataReader reader = new HyenaDataReader (ServiceManager.DbConnection.Query (SelectSql (
-                        "COUNT(*), SUM(FileSize), SUM(Duration)")))) {
-                        count = reader.Get<int> (0);
-                        file_size = reader.Get<long> (1);
-                        duration = reader.Get<TimeSpan> (2); 
-                    }
-                }
-            }
-                    
-            private HyenaSqliteCommand SelectSql (string select)
-            {
-                return new HyenaSqliteCommand (
-                    String.Format ("SELECT {0} FROM CoreTracks WHERE {1}", select, intersection),
-                    from.DbId, to.DbId
-                );
-            }
-            
-            public int Count {
-                get { return count; }
-            }
-            
-            public long FileSize {
-                get { return file_size; }
-            }
-            
-            public TimeSpan Duration {
-                get { return duration; }
-            }
-            
-            public override string ToString ()
-            {
-                return String.Format ("There are {0} items, {1} MB, and {2} to sync from {3} to {4}",
-                    count, file_size/(1024*1024), duration, from, to);
-            }
-        }
-        
+ 
         public void LoadDeviceContents ()
         {
             ThreadPool.QueueUserWorkItem (ThreadedLoadDeviceContents);
@@ -285,7 +217,9 @@
                 OnTracksAdded ();
                 HideStatus ();
                 
-                SyncWith (ServiceManager.SourceManager.MusicLibrary);
+                using (new Hyena.Timer ("calculating sync for dap..")) {
+                new DapSync (this).CalculateSync ();
+                }
             } catch (Exception e) {
                 Log.Exception (e);
             }
@@ -294,8 +228,15 @@
         protected virtual void LoadFromDevice ()
         {
         }
+
+        private void AttemptToAddTrackToDevice (DatabaseTrackInfo track, SafeUri fromUri)
+        {
+            if (BytesAvailable - Banshee.IO.File.GetSize (fromUri) >= 0) {
+                AddTrackToDevice (track, fromUri);
+            }
+        }
         
-        protected abstract void AddTrackToDevice (DatabaseTrackInfo track, SafeUri fromUri);  
+        protected abstract void AddTrackToDevice (DatabaseTrackInfo track, SafeUri fromUri);
 
         protected bool TrackNeedsTranscoding (TrackInfo track)
         {
@@ -328,7 +269,7 @@
         protected override void AddTrackAndIncrementCount (DatabaseTrackInfo track)
         {
             if (!TrackNeedsTranscoding (track)) {
-                AddTrackToDevice (track, track.Uri);
+                AttemptToAddTrackToDevice (track, track.Uri);
                 IncrementAddedTracks ();
                 return;
             }
@@ -356,7 +297,7 @@
             AddTrackJob.Status = String.Format ("{0} - {1}", track.ArtistName, track.TrackTitle);
             
             try {
-                AddTrackToDevice ((DatabaseTrackInfo)track, outputUri);
+                AttemptToAddTrackToDevice ((DatabaseTrackInfo)track, outputUri);
             } catch (Exception e) {
                 Log.Exception (e);
             }
@@ -433,7 +374,21 @@
         public long BytesMusic {
             get { return MusicGroupSource == null ? 0 : MusicGroupSource.BytesUsed; }
         }
-        
+                    
+        public long BytesData {
+            get { return BytesUsed - BytesVideo - BytesMusic; }
+        }
+                    
+        public long BytesReserved {
+            get { return space_for_data.Get (); }
+            set { space_for_data.Set (value); }
+        }
+                    
+        public override long BytesAvailable {
+            get { return BytesCapacity - BytesUsed - Math.Max (0, BytesReserved - BytesData); }
+        }
+            
+        private Banshee.Configuration.SchemaEntry<long> space_for_data;
 #endregion
         
     }

Added: trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSync.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSync.cs	Thu Aug 21 21:03:03 2008
@@ -0,0 +1,156 @@
+//
+// DapSync.cs
+//
+// Authors:
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+
+using Hyena;
+using Hyena.Query;
+
+using Banshee.Configuration;
+using Banshee.Sources;
+using Banshee.ServiceStack;
+using Banshee.Library;
+using Banshee.Playlist;
+using Banshee.SmartPlaylist;
+using Banshee.Query;
+
+namespace Banshee.Dap
+{
+    public sealed class DapSync
+    {
+        private DapSource dap;
+        private string conf_ns;
+        private List<DapLibrarySync> library_syncs = new List<DapLibrarySync> ();
+        private SchemaEntry<bool> enabled, auto_sync;
+        private SmartPlaylistSource to_remove;
+
+        internal string ConfigurationNamespace {
+            get { return conf_ns; }
+        }
+        
+        #region Public Properites
+        
+        public DapSource Dap {
+            get { return dap; }
+        }
+        
+        public bool Enabled {
+            get { return enabled.Get (); }
+        }
+        
+        public bool AutoSync {
+            get { return auto_sync.Get (); }
+        }
+        
+        #endregion
+        
+        public DapSync (DapSource dapSource)
+        {
+            dap = dapSource;
+            conf_ns = String.Format ("{0}.{1}", dapSource.ConfigurationId, "sync");
+            
+            enabled = dap.CreateSchema<bool> (conf_ns, "enabled", true,  // todo change default to false
+                "Whether sync is enabled at all for this device", "");
+            
+            auto_sync = dap.CreateSchema<bool> (conf_ns, "auto_sync", false,
+                "If syncing is enabled, whether to sync the device as soon as its plugged in or the libraries change", "");
+
+            foreach (Source source in ServiceManager.SourceManager.Sources) {
+                if (source is LibrarySource) {
+                    library_syncs.Add (new DapLibrarySync (this, source as LibrarySource));
+                }
+            }
+
+            bool first = true;
+            System.Text.StringBuilder sb = new System.Text.StringBuilder ();
+            foreach (DapLibrarySync sync in library_syncs) {
+                if (first) {
+                    first = false;
+                } else {
+                    sb.Append (",");
+                }
+                sb.Append (sync.SmartPlaylistId);
+            }
+
+            // Any items on the device that aren't in the sync lists need to be removed
+            to_remove = new SmartPlaylistSource ("to_remove", dap.DbId);
+            to_remove.IsTemporary = true;
+            to_remove.Save ();
+            to_remove.DatabaseTrackModel.AddCondition (String.Format (
+                @"MetadataHash NOT IN (SELECT MetadataHash FROM CoreTracks, CoreSmartPlaylistEntries 
+                    WHERE CoreSmartPlaylistEntries.SmartPlaylistID IN ({0}) AND
+                        CoreTracks.TrackID = CoreSmartPlaylistEntries.TrackID)",
+                sb.ToString ()
+            ));
+        }
+        
+        public int ItemCount {
+            get { return 0; }
+        }
+        
+        public long FileSize {
+            get { return 0; }
+        }
+        
+        public TimeSpan Duration {
+            get { return TimeSpan.Zero; }
+        }
+        
+        public void CalculateSync ()
+        {
+            foreach (DapLibrarySync library_sync in library_syncs) {
+                library_sync.CalculateSync ();
+            }
+            to_remove.RefreshAndReload ();
+            Log.Information (ToString ());
+        }
+
+        public override string ToString ()
+        {
+            System.Text.StringBuilder sb = new System.Text.StringBuilder ();
+            foreach (DapLibrarySync library_sync in library_syncs) {
+                sb.Append (library_sync.ToString ());
+                sb.Append ("\n");
+            }
+
+            sb.Append (String.Format ("And {0} items to remove", to_remove.Count));
+            return sb.ToString ();
+        }
+
+        
+        public void Sync ()
+        {
+            foreach (DapLibrarySync library_sync in library_syncs) {
+                library_sync.Sync ();
+            }
+
+            // TODO: remove all items in to_remove
+        }
+    }
+}

Modified: trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/RemovableSource.cs
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/RemovableSource.cs	(original)
+++ trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/RemovableSource.cs	Thu Aug 21 21:03:03 2008
@@ -145,6 +145,9 @@
         
         public abstract long BytesUsed { get; }
         public abstract long BytesCapacity { get; }
+        public virtual long BytesAvailable {
+            get { return BytesCapacity - BytesUsed; }
+        }
 
         public abstract void Import ();
 

Modified: trunk/banshee/src/Dap/Banshee.Dap/Makefile.am
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap/Makefile.am	(original)
+++ trunk/banshee/src/Dap/Banshee.Dap/Makefile.am	Thu Aug 21 21:03:03 2008
@@ -7,8 +7,10 @@
 	Banshee.Dap.Gui/DapInfoBar.cs \
 	Banshee.Dap.Gui/DapPropertiesDialog.cs \
 	Banshee.Dap.Gui/DapPropertiesDisplay.cs \
+	Banshee.Dap/DapLibrarySync.cs \
 	Banshee.Dap/DapService.cs \
 	Banshee.Dap/DapSource.cs \
+	Banshee.Dap/DapSync.cs \
 	Banshee.Dap/InvalidDeviceException.cs \
 	Banshee.Dap/MediaGroupSource.cs \
 	Banshee.Dap/MusicGroupSource.cs \

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteConnection.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteConnection.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteConnection.cs	Thu Aug 21 21:03:03 2008
@@ -42,20 +42,24 @@
     public class HyenaDataReader : IDisposable
     {
         private IDataReader reader;
+        private bool read = false;
         
         public HyenaDataReader (IDataReader reader)
         {
             this.reader = reader;
-            reader.Read ();
         }
         
         public T Get<T> (int i)
         {
+            if (!read) {
+                Read ();
+            }
             return (T) SqliteUtils.FromDbFormat (typeof(T), reader[i]);
         }
         
         public bool Read ()
         {
+            read = true;
             return reader.Read ();
         }
         



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