[banshee] Configurable browser filters (bgo#540873)



commit 1ef1a4c868e154c446f6a1b8ae76d57cdfaa1dc0
Author: Frank Ziegler <funtastix googlemail com>
Date:   Sun Nov 6 20:22:08 2011 +0800

    Configurable browser filters (bgo#540873)
    
    Add the genre filter. Option to switch between artists and album artists.
    
    Signed-off-by: Alexander Kojevnikov <alexk gnome org>

 .../DatabaseAlbumArtistInfo.cs                     |   86 ++++++++++
 .../DatabaseAlbumArtistListModel.cs                |   78 +++++++++
 src/Core/Banshee.Services/Banshee.Services.csproj  |    2 +
 .../Banshee.Sources/DatabaseSource.cs              |    6 +-
 src/Core/Banshee.Services/Makefile.am              |    2 +
 .../CompositeTrackSourceContents.cs                |  165 ++++++++++++++++++--
 .../FilteredListSourceContents.cs                  |    8 +-
 7 files changed, 330 insertions(+), 17 deletions(-)
---
diff --git a/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseAlbumArtistInfo.cs b/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseAlbumArtistInfo.cs
new file mode 100644
index 0000000..3448cb9
--- /dev/null
+++ b/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseAlbumArtistInfo.cs
@@ -0,0 +1,86 @@
+//
+// DatabaseAlbumArtistInfo.cs
+//
+// Author:
+//   Frank Ziegler <funtastix googlemail com>
+//
+// 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 Mono.Unix;
+
+using Hyena.Data;
+using Hyena.Data.Sqlite;
+
+using Banshee.Database;
+using Banshee.ServiceStack;
+
+namespace Banshee.Collection.Database
+{
+    public class DatabaseAlbumArtistInfo : ArtistInfo
+    {
+        private static BansheeModelProvider<DatabaseAlbumArtistInfo> provider = new BansheeModelProvider<DatabaseAlbumArtistInfo> (
+            ServiceManager.DbConnection, "CoreArtists"
+        );
+
+        public static BansheeModelProvider<DatabaseAlbumArtistInfo> Provider {
+            get { return provider; }
+        }
+
+        public DatabaseAlbumArtistInfo () : base (null, null)
+        {
+        }
+
+        [DatabaseColumn("ArtistID", Constraints = DatabaseColumnConstraints.PrimaryKey)]
+        private int dbid;
+        public int DbId {
+            get { return dbid; }
+        }
+
+        [DatabaseColumn("Name")]
+        public override string Name {
+            get { return base.Name; }
+            set { base.Name = value; }
+        }
+
+        [DatabaseColumn(Select = false)]
+        internal string NameLowered {
+            get { return Hyena.StringUtil.SearchKey (DisplayName); }
+        }
+
+        [DatabaseColumn("NameSort")]
+        public override string NameSort {
+            get { return base.NameSort; }
+            set { base.NameSort = value; }
+        }
+
+        [DatabaseColumn(Select = false)]
+        internal byte[] NameSortKey {
+            get { return Hyena.StringUtil.SortKey (NameSort ?? DisplayName); }
+        }
+
+        public override string ToString ()
+        {
+            return String.Format ("DatabaseAlbumArtistInfo<DbId: {0}, Name: {1}>", DbId, Name);
+        }
+    }
+}
diff --git a/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseAlbumArtistListModel.cs b/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseAlbumArtistListModel.cs
new file mode 100644
index 0000000..0b49aec
--- /dev/null
+++ b/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseAlbumArtistListModel.cs
@@ -0,0 +1,78 @@
+//
+// DatabaseAlbumArtistListModel.cs
+//
+// Author:
+//   Frank Ziegler <funtastix googlemail com>
+//
+// 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 Mono.Unix;
+
+using Hyena;
+using Hyena.Data.Sqlite;
+using Hyena.Query;
+
+using Banshee.Database;
+
+namespace Banshee.Collection.Database
+{
+    public class DatabaseAlbumArtistListModel : DatabaseFilterListModel<DatabaseAlbumArtistInfo, ArtistInfo>
+    {
+        public DatabaseAlbumArtistListModel (Banshee.Sources.DatabaseSource source, DatabaseTrackListModel trackModel, BansheeDbConnection connection, string uuid)
+            : base (Banshee.Query.BansheeQuery.AlbumArtistField.Name, Banshee.Query.BansheeQuery.AlbumArtistField.Label,
+                    source, trackModel, connection, DatabaseAlbumArtistInfo.Provider, new ArtistInfo (null, null), uuid)
+        {
+            QueryFields = new QueryFieldSet (Banshee.Query.BansheeQuery.AlbumArtistField);
+            ReloadFragmentFormat = @"
+                FROM (SELECT DISTINCT ArtistID, ArtistNameSortKey FROM CoreAlbums) CoreArtists WHERE CoreArtists.ArtistID IN
+                    (SELECT CoreAlbums.ArtistID FROM CoreAlbums, CoreTracks, CoreCache{0}
+                        WHERE CoreCache.ModelID = {1} AND
+                              CoreTracks.AlbumID = CoreAlbums.AlbumID AND
+                              EXISTS (SELECT 1 FROM CoreArtists WHERE ArtistID = CoreAlbums.ArtistID) AND
+                              CoreCache.ItemID = {2} {3})
+                        ORDER BY ArtistNameSortKey";
+        }
+
+        public override string FilterColumn {
+            get { return "CoreTracks.AlbumID"; }
+        }
+
+        protected override string ItemToFilterValue (object item)
+        {
+            return (item is DatabaseAlbumArtistInfo) ? "SELECT CoreAlbums.AlbumID FROM CoreAlbums WHERE CoreAlbums.ArtistID = " + (item as DatabaseAlbumArtistInfo).DbId.ToString () : null;
+        }
+
+        public override string GetSqlFilter ()
+        {
+            string res = base.GetSqlFilter ();
+            if (String.IsNullOrEmpty (res))
+                return res;
+            return res.Replace (","," UNION ");
+        }
+
+        public override void UpdateSelectAllItem (long count)
+        {
+            select_all_item.Name = String.Format (Catalog.GetString ("All AlbumArtists ({0})"), count);
+        }
+    }
+}
diff --git a/src/Core/Banshee.Services/Banshee.Services.csproj b/src/Core/Banshee.Services/Banshee.Services.csproj
index 2377802..3484a6e 100644
--- a/src/Core/Banshee.Services/Banshee.Services.csproj
+++ b/src/Core/Banshee.Services/Banshee.Services.csproj
@@ -322,6 +322,8 @@
     <Compile Include="Banshee.MediaEngine\Tests.cs" />
     <Compile Include="Banshee.Sources\Tests.cs" />
     <Compile Include="Banshee.Query\Tests\BansheeQueryTests.cs" />
+    <Compile Include="Banshee.Collection.Database\DatabaseAlbumArtistInfo.cs" />
+    <Compile Include="Banshee.Collection.Database\DatabaseAlbumArtistListModel.cs" />
   </ItemGroup>
   <ItemGroup>
     <EmbeddedResource Include="Banshee.Services.addin.xml">
diff --git a/src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs b/src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs
index 785a43d..c67a14c 100644
--- a/src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs
+++ b/src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs
@@ -58,7 +58,7 @@ namespace Banshee.Sources
 
         protected DatabaseTrackListModel track_model;
         protected DatabaseAlbumListModel album_model;
-        protected DatabaseArtistListModel artist_model;
+        protected DatabaseFilterListModel<DatabaseArtistInfo, ArtistInfo> artist_model;
         protected DatabaseQueryFilterModel<string> genre_model;
 
         private RateLimiter reload_limiter;
@@ -142,6 +142,7 @@ namespace Banshee.Sources
                 yield break;
             }
 
+            DatabaseAlbumArtistListModel albumartist_model = new DatabaseAlbumArtistListModel (src, src.DatabaseTrackModel, ServiceManager.DbConnection, src.UniqueId);
             DatabaseArtistListModel artist_model = new DatabaseArtistListModel (src, src.DatabaseTrackModel, ServiceManager.DbConnection, src.UniqueId);
             DatabaseAlbumListModel album_model = new DatabaseAlbumListModel (src, src.DatabaseTrackModel, ServiceManager.DbConnection, src.UniqueId);
             DatabaseQueryFilterModel<string> genre_model = new DatabaseQueryFilterModel<string> (src, src.DatabaseTrackModel, ServiceManager.DbConnection,
@@ -153,9 +154,10 @@ namespace Banshee.Sources
                 this.genre_model = genre_model;
             }
 
+            yield return genre_model;
+            yield return albumartist_model;
             yield return artist_model;
             yield return album_model;
-            yield return genre_model;
         }
 
         protected virtual void AfterInitialized ()
diff --git a/src/Core/Banshee.Services/Makefile.am b/src/Core/Banshee.Services/Makefile.am
index c361c2f..ff63324 100644
--- a/src/Core/Banshee.Services/Makefile.am
+++ b/src/Core/Banshee.Services/Makefile.am
@@ -6,6 +6,8 @@ SOURCES =  \
 	Banshee.Base/RateLimiter.cs \
 	Banshee.Collection.Database/Bookmark.cs \
 	Banshee.Collection.Database/CachedList.cs \
+	Banshee.Collection.Database/DatabaseAlbumArtistInfo.cs \
+	Banshee.Collection.Database/DatabaseAlbumArtistListModel.cs \
 	Banshee.Collection.Database/DatabaseAlbumInfo.cs \
 	Banshee.Collection.Database/DatabaseAlbumListModel.cs \
 	Banshee.Collection.Database/DatabaseArtistInfo.cs \
diff --git a/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/CompositeTrackSourceContents.cs b/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/CompositeTrackSourceContents.cs
index 366cbe1..6e1fa85 100644
--- a/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/CompositeTrackSourceContents.cs
+++ b/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/CompositeTrackSourceContents.cs
@@ -46,37 +46,164 @@ using Banshee.Configuration;
 using Banshee.Gui;
 using Banshee.Collection.Gui;
 
+using ScrolledWindow=Gtk.ScrolledWindow;
+
 namespace Banshee.Sources.Gui
 {
     public class CompositeTrackSourceContents : FilteredListSourceContents, ITrackModelSourceContents
     {
-        // private QueryFilterView<string> genre_view;
+        private QueryFilterView<string> genre_view;
         private ArtistListView artist_view;
+        private ArtistListView albumartist_view;
         private AlbumListView album_view;
         private TrackListView track_view;
 
+        private InterfaceActionService action_service;
+        private ActionGroup configure_browser_actions;
+
+        private static string menu_xml = @"
+            <ui>
+              <menubar name=""MainMenu"">
+                <menu name=""ViewMenu"" action=""ViewMenuAction"">
+                  <placeholder name=""BrowserViews"">
+                    <menu name=""BrowserListsMenu"" action=""BrowserListsMenuAction"">
+                        <menuitem name=""Artist"" action=""ArtistAction"" />
+                        <menuitem name=""AlbumArtist"" action=""AlbumArtistAction"" />
+                        <separator />
+                        <menuitem name=""Genre"" action=""GenreAction"" />
+                    </menu>
+                    <separator />
+                  </placeholder>
+                </menu>
+              </menubar>
+            </ui>
+        ";
+
         public CompositeTrackSourceContents () : base ("albumartist")
         {
+            if (ServiceManager.Contains ("InterfaceActionService")) {
+                action_service = ServiceManager.Get<InterfaceActionService> ();
+
+                if (action_service.FindActionGroup ("BrowserConfiguration") == null) {
+                    configure_browser_actions = new ActionGroup ("BrowserConfiguration");
+
+                    configure_browser_actions.Add (new ActionEntry [] {
+                        new ActionEntry ("BrowserListsMenuAction", null,
+                            Catalog.GetString ("Configure Browser"), null,
+                            Catalog.GetString ("Configure the filters available in the browser"), null)
+                    });
+
+                    configure_browser_actions.Add (new RadioActionEntry [] {
+                        new RadioActionEntry ("ArtistAction", null,
+                            Catalog.GetString ("Use all available artists"), null,
+                            Catalog.GetString ("Use all available artists in the browser filter list"), 0),
+
+                        new RadioActionEntry ("AlbumArtistAction", null,
+                            Catalog.GetString ("Use album artists only"), null,
+                            Catalog.GetString ("Use only album artists, not the ones with only single tracks"), 1),
+                    }, ArtistListViewType.Get ().Equals ("artist") ? 0 : 1 , null);
+
+                    configure_browser_actions.Add (new ToggleActionEntry [] {
+                        new ToggleActionEntry ("GenreAction", null,
+                            Catalog.GetString ("Show Genre filter"), null,
+                            Catalog.GetString ("Show a list of genres to filter by"), null, GenreListShown.Get ())});
+
+                    action_service.AddActionGroup (configure_browser_actions);
+                    action_service.UIManager.AddUiFromString (menu_xml);
+                }
+
+                (action_service.FindAction("BrowserConfiguration.ArtistAction") as RadioAction).Changed += OnArtistFilterChanged;
+                //(action_service.FindAction("BrowserConfiguration.AlbumArtistAction") as RadioAction).Changed += OnArtistFilterChanged;
+                action_service.FindAction("BrowserConfiguration.GenreAction").Activated += OnGenreFilterChanged;;
+            }
+        }
+
+        private void OnGenreFilterChanged (object o, EventArgs args)
+        {
+            ToggleAction action = (ToggleAction)o;
+
+            ClearFilterSelections ();
+
+            GenreListShown.Set (action.Active);
+
+            Widget genre_view_widget = (Widget)genre_view;
+            genre_view_widget.Parent.Visible = GenreListShown.Get ();
+        }
+
+        private void OnArtistFilterChanged (object o, ChangedArgs args)
+        {
+            Widget new_artist_view = args.Current.Value == 0 ? artist_view : albumartist_view;
+            Widget old_artist_view = args.Current.Value == 1 ? artist_view : albumartist_view;
+
+            List<ScrolledWindow> new_filter_list = new List<ScrolledWindow> ();
+            List<ScrolledWindow> old_filter_list = new List<ScrolledWindow> (filter_scrolled_windows);
+            foreach (ScrolledWindow fw in old_filter_list)
+            {
+                bool contains = false;
+                foreach (Widget child in fw.AllChildren)
+                    if (child == old_artist_view)
+                        contains = true;
+                if (contains)
+                {
+                    Widget view_widget = (Widget)new_artist_view;
+                    if (view_widget.Parent == null)
+                            SetupFilterView (new_artist_view as ArtistListView);
+
+                    ScrolledWindow win = (ScrolledWindow)view_widget.Parent;
+
+                    new_filter_list.Add (win);
+                } else
+                    new_filter_list.Add (fw);
+            }
+
+            filter_scrolled_windows = new_filter_list;
+
+            ClearFilterSelections ();
+
+            if (BrowserPosition.Get ().Equals ("left")) {
+                LayoutLeft ();
+            } else {
+                LayoutTop ();
+            }
+
+            ArtistListViewType.Set (args.Current.Value == 1 ? "albumartist" : "artist");
         }
 
         protected override void InitializeViews ()
         {
             SetupMainView (track_view = new TrackListView ());
-            // SetupFilterView (genre_view = new QueryFilterView<string> (Catalog.GetString ("Not Set")));
-            SetupFilterView (artist_view = new ArtistListView ());
+
+            SetupFilterView (genre_view = new QueryFilterView<string> (Catalog.GetString ("Not Set")));
+            Widget genre_view_widget = (Widget)genre_view;
+            genre_view_widget.Parent.Shown += delegate {
+                genre_view_widget.Parent.Visible = GenreListShown.Get ();
+            };
+
+            if (ArtistListViewType.Get ().Equals ("artist")) {
+                SetupFilterView (artist_view = new ArtistListView ());
+                albumartist_view = new ArtistListView ();
+            } else {
+                SetupFilterView (albumartist_view = new ArtistListView ());
+                artist_view = new ArtistListView ();
+            }
+
             SetupFilterView (album_view = new AlbumListView ());
         }
 
         protected override void ClearFilterSelections ()
         {
-            // if (genre_view.Model != null) {
-            //     genre_view.Selection.Clear ();
-            // }
+            if (genre_view.Model != null) {
+                genre_view.Selection.Clear ();
+            }
 
             if (artist_view.Model != null) {
                 artist_view.Selection.Clear ();
             }
 
+            if (albumartist_view.Model != null) {
+                albumartist_view.Selection.Clear ();
+            }
+
             if (album_view.Model != null) {
                 album_view.Selection.Clear ();
             }
@@ -87,7 +214,7 @@ namespace Banshee.Sources.Gui
             SetModel (track);
             SetModel (artist);
             SetModel (album);
-            // SetModel (genre);
+            SetModel (genre);
         }
 
         IListView<TrackInfo> ITrackModelSourceContents.TrackView {
@@ -128,12 +255,14 @@ namespace Banshee.Sources.Gui
 
             if (filterable_source != null && filterable_source.CurrentFilters != null) {
                 foreach (IListModel model in filterable_source.CurrentFilters) {
-                    if (model is IListModel<ArtistInfo>)
+                    if (model is IListModel<ArtistInfo> && model is DatabaseArtistListModel)
                         SetModel (artist_view, (model as IListModel<ArtistInfo>));
+                    else if (model is IListModel<ArtistInfo> && model is DatabaseAlbumArtistListModel)
+                        SetModel (albumartist_view, (model as IListModel<ArtistInfo>));
                     else if (model is IListModel<AlbumInfo>)
                         SetModel (album_view, (model as IListModel<AlbumInfo>));
-                    // else if (model is IListModel<QueryFilterInfo<string>>)
-                    //    SetModel (genre_view, (model as IListModel<QueryFilterInfo<string>>));
+                    else if (model is IListModel<QueryFilterInfo<string>>)
+                        SetModel (genre_view, (model as IListModel<QueryFilterInfo<string>>));
                     // else
                     //    Hyena.Log.DebugFormat ("CompositeTrackSourceContents got non-album/artist filter model: {0}", model);
                 }
@@ -148,12 +277,26 @@ namespace Banshee.Sources.Gui
             source = null;
             SetModel (track_view, null);
             SetModel (artist_view, null);
+            SetModel (albumartist_view, null);
             SetModel (album_view, null);
-            // SetModel (genre_view, null);
+            SetModel (genre_view, null);
             track_view.HeaderVisible = false;
         }
 
 #endregion
 
+        public static readonly SchemaEntry<string> ArtistListViewType = new SchemaEntry<string> (
+            "artist_list_view", "type",
+            "artist",
+            "Artist/AlbumArtist List View Type",
+            "The type of the Artist/AlbumArtist list view; either 'artist' or 'albumartist'"
+        );
+
+        public static readonly SchemaEntry<bool> GenreListShown = new SchemaEntry<bool> (
+            "genre_list_view", "shown",
+            false,
+            "GenreListView Shown",
+            "Define if the GenreList filter view is shown or not"
+        );
     }
 }
diff --git a/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/FilteredListSourceContents.cs b/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/FilteredListSourceContents.cs
index 640b871..00523fa 100644
--- a/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/FilteredListSourceContents.cs
+++ b/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/FilteredListSourceContents.cs
@@ -58,7 +58,7 @@ namespace Banshee.Sources.Gui
         private Gtk.ScrolledWindow main_scrolled_window;
 
         private List<object> filter_views = new List<object> ();
-        private List<ScrolledWindow> filter_scrolled_windows = new List<ScrolledWindow> ();
+        protected List<ScrolledWindow> filter_scrolled_windows = new List<ScrolledWindow> ();
 
         private Dictionary<object, double> model_positions = new Dictionary<object, double> ();
 
@@ -196,12 +196,12 @@ namespace Banshee.Sources.Gui
             }
         }
 
-        private void LayoutLeft ()
+        protected void LayoutLeft ()
         {
             Layout (false);
         }
 
-        private void LayoutTop ()
+        protected void LayoutTop ()
         {
             Layout (true);
         }
@@ -325,7 +325,7 @@ namespace Banshee.Sources.Gui
         protected void SetModel<T> (ListView<T> view, IListModel<T> model)
         {
             if (view.Model != null) {
-                model_positions[view.Model] = view.Vadjustment.Value;
+                model_positions[view.Model] = view.Vadjustment != null ? view.Vadjustment.Value : 0;
             }
 
             if (model == null) {



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