[banshee/source-contents] 2009-03-04 Gabriel Burt <gabriel burt gmail com>



commit d9ff21cca37ed96b850fe775ba48c72c999b6a76
Author: Gabriel Burt <gabriel burt gmail com>
Date:   Mon Mar 2 17:19:12 2009 -0600

    2009-03-04 Gabriel Burt <gabriel burt gmail com>
    
    This patch lets extensions provide alternate views ("contents") for
    	sources, and lets users switch between them via a menu.
    
    	* src/Clients/Nereid/Nereid/PlayerInterface.cs: Delegate to the
    	ViewContainer to setup the content when the source changes.
    
    	* src/Clients/Nereid/Nereid/ViewContainer.cs: Add a title button that is
    	shown if there is more than one content extension available for a given
    	source (otherwise just a label is shown as before).  Put all the sources'
    	contents into a SourceContentNotebook, and use update the content (and
    	content options) with the new SourceContentManager.
    
    	* src/Core/Banshee.ThickClient/Banshee.Gui/CommonServices.cs: Register the
    	SourceContentManager.
    
    	* src/Core/Banshee.ThickClient/Banshee.Sources.Gui/CompositeTrackSourceContents.cs:
    	* src/Core/Banshee.ThickClient/Banshee.Sources.Gui/ObjectListSourceContents.cs:
    	Add a SourceContentProvider subclass/extension.
    
    	* src/Core/Banshee.ThickClient/Banshee.ThickClient.addin.xml: Declare the
    	new SourceContentProvider extension point, and the two above extensions.
    
    	* src/Core/Banshee.ThickClient/Banshee.Sources.Gui/ISourceContents.cs:
    	Update header.
    
    	* src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceContentManager.cs:
    	New service that loads /Banshee/ThickClient/SourceContentProvider
    	extensions, and has methods for getting the contents that support a given
    	source.
    
    	* src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceContentMenu.cs:
    	New Menu subclass that has one item per content that a source supports,
    	and when clicked it switches to that page in the associated Notebook.
    
    	* src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceContentNotebook.cs:
    	New Notebook subclass that knows how to Activate (create/switch to) the
    	hidden tab for a particular SourceContentProvider's content; also saves
    	the id of the last activated content provider.
    
    	* src/Core/Banshee.ThickClient/Makefile.am: Add the three new files above.
    
    	* src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying.addin.xml:
    	* src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingInterface.cs:
    	* src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingSource.cs:
    	Intead of explicitly defining the content for the Now Playing source, just
    	declare a content extension that is compatible with it.  This should make
    	it pretty easy to add other content, such as visualization.
---
 ChangeLog                                          |   50 +++++++
 src/Clients/Nereid/Nereid/PlayerInterface.cs       |   35 +-----
 src/Clients/Nereid/Nereid/ViewContainer.cs         |  127 ++++++++++++------
 .../Banshee.Gui/CommonServices.cs                  |    1 +
 .../CompositeTrackSourceContents.cs                |   28 ++++
 .../Banshee.Sources.Gui/ISourceContents.cs         |    2 +-
 .../ObjectListSourceContents.cs                    |   27 ++++
 .../Banshee.Sources.Gui/SourceContentManager.cs    |  136 ++++++++++++++++++++
 .../Banshee.Sources.Gui/SourceContentMenu.cs       |   81 ++++++++++++
 .../Banshee.Sources.Gui/SourceContentNotebook.cs   |   81 ++++++++++++
 .../Banshee.ThickClient.addin.xml                  |   11 +-
 src/Core/Banshee.ThickClient/Makefile.am           |    3 +
 .../Banshee.NowPlaying.addin.xml                   |    4 +
 .../Banshee.NowPlaying/NowPlayingInterface.cs      |   28 ++++
 .../Banshee.NowPlaying/NowPlayingSource.cs         |   19 +--
 15 files changed, 543 insertions(+), 90 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index aca54cc..91850e7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -776,6 +776,56 @@
 
 2009-03-04  Gabriel Burt  <gabriel burt gmail com>
 
+	This patch lets extensions provide alternate views ("contents") for
+	sources, and lets users switch between them via a menu.
+
+	* src/Clients/Nereid/Nereid/PlayerInterface.cs: Delegate to the
+	ViewContainer to setup the content when the source changes.
+
+	* src/Clients/Nereid/Nereid/ViewContainer.cs: Add a title button that is
+	shown if there is more than one content extension available for a given
+	source (otherwise just a label is shown as before).  Put all the sources'
+	contents into a SourceContentNotebook, and use update the content (and
+	content options) with the new SourceContentManager.
+
+	* src/Core/Banshee.ThickClient/Banshee.Gui/CommonServices.cs: Register the
+	SourceContentManager.
+
+	* src/Core/Banshee.ThickClient/Banshee.Sources.Gui/CompositeTrackSourceContents.cs:
+	* src/Core/Banshee.ThickClient/Banshee.Sources.Gui/ObjectListSourceContents.cs:
+	Add a SourceContentProvider subclass/extension.
+
+	* src/Core/Banshee.ThickClient/Banshee.ThickClient.addin.xml: Declare the
+	new SourceContentProvider extension point, and the two above extensions.
+
+	* src/Core/Banshee.ThickClient/Banshee.Sources.Gui/ISourceContents.cs:
+	Update header.
+
+	* src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceContentManager.cs:
+	New service that loads /Banshee/ThickClient/SourceContentProvider
+	extensions, and has methods for getting the contents that support a given
+	source.
+
+	* src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceContentMenu.cs:
+	New Menu subclass that has one item per content that a source supports,
+	and when clicked it switches to that page in the associated Notebook.
+
+	* src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceContentNotebook.cs:
+	New Notebook subclass that knows how to Activate (create/switch to) the
+	hidden tab for a particular SourceContentProvider's content; also saves
+	the id of the last activated content provider.
+
+	* src/Core/Banshee.ThickClient/Makefile.am: Add the three new files above.
+
+	* src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying.addin.xml:
+	* src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingInterface.cs:
+	* src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingSource.cs:
+	Intead of explicitly defining the content for the Now Playing source, just
+	declare a content extension that is compatible with it.  This should make
+	it pretty easy to add other content, such as visualization.
+
+2009-03-04  Gabriel Burt  <gabriel burt gmail com>
+
 	* src/Core/Banshee.Core/Resources/contributors.xml: Add a bunch of people
 	as developers and contributors, most of whom should have been in here for
 	some time.
diff --git a/src/Clients/Nereid/Nereid/PlayerInterface.cs b/src/Clients/Nereid/Nereid/PlayerInterface.cs
index 1b95574..f2fa914 100644
--- a/src/Clients/Nereid/Nereid/PlayerInterface.cs
+++ b/src/Clients/Nereid/Nereid/PlayerInterface.cs
@@ -65,8 +65,6 @@ namespace Nereid
         
         // Major Interaction Components
         private SourceView source_view;
-        private CompositeTrackSourceContents composite_view;
-        private ObjectListSourceContents object_view;
         private Label status_label;
 
         protected PlayerInterface (IntPtr ptr) : base (ptr)
@@ -84,8 +82,6 @@ namespace Nereid
 
             ActionService.SourceActions.SourceView = this;
             
-            composite_view.TrackView.HasFocus = true;
-            
             InitialShowPresent ();
         }
         
@@ -161,14 +157,10 @@ namespace Nereid
             view_container = new ViewContainer ();
             
             source_view = new SourceView ();
-            composite_view = new CompositeTrackSourceContents ();
             
             Hyena.Widgets.ScrolledWindow source_scroll = new Hyena.Widgets.ScrolledWindow ();
             source_scroll.AddWithFrame (source_view);       
             
-            composite_view.TrackView.HeaderVisible = false;
-            view_container.Content = composite_view;
-            
             source_box.PackStart (source_scroll, true, true, 0);
             source_box.PackStart (new UserJobTileHost (), false, false, 0);
             
@@ -341,34 +333,9 @@ namespace Nereid
             if (source == null) {
                 return;
             }
-            
-            // Connect the source models to the views if possible
-            ISourceContents contents = source.GetProperty<ISourceContents> ("Nereid.SourceContents",
-                source.GetInheritedProperty<bool> ("Nereid.SourceContentsPropagate"));
 
             view_container.ClearFooter ();
-            
-            if (contents != null) {
-                if (view_container.Content != contents) {
-                    view_container.Content = contents;
-                }
-                view_container.Content.SetSource (source);
-                view_container.Show ();
-            } else if (source is ITrackModelSource) {
-                view_container.Content = composite_view;
-                view_container.Content.SetSource (source);
-                view_container.Show ();
-            } else if (source is Hyena.Data.IObjectListModel) {
-                if (object_view == null) {
-                    object_view = new ObjectListSourceContents ();
-                }
-                
-                view_container.Content = object_view;
-                view_container.Content.SetSource (source);
-                view_container.Show ();
-            } else {
-                view_container.Hide ();
-            }
+            view_container.SetSource (source);
 
             // Associate the view with the model
             if (view_container.Visible && view_container.Content is ITrackModelSourceContents) {
diff --git a/src/Clients/Nereid/Nereid/ViewContainer.cs b/src/Clients/Nereid/Nereid/ViewContainer.cs
index 41c51c3..b4c504d 100644
--- a/src/Clients/Nereid/Nereid/ViewContainer.cs
+++ b/src/Clients/Nereid/Nereid/ViewContainer.cs
@@ -31,6 +31,8 @@ using System.Collections.Generic;
 using Gtk;
 using Mono.Unix;
 
+using Hyena.Widgets;
+
 using Banshee.Widgets;
 using Banshee.Gui.Widgets;
 using Banshee.Sources.Gui;
@@ -38,25 +40,37 @@ using Banshee.Collection;
 
 using Banshee.Gui;
 using Banshee.ServiceStack;
+using Banshee.Sources;
 
 namespace Nereid
 {
-
     public class ViewContainer : VBox
     {
         private SearchEntry search_entry;
         private HBox header;
+        private Label title_button_label;
         private Label title_label;
+        private SourceContentMenu content_menu;
         private Label search_label;
         private VBox footer;
+        private MenuButton title_button;
         
         private ISourceContents content;
+        private ISourceContents explicit_content;
+        private SourceContentNotebook notebook;
+
+        private SourceContentManager content_manager;
         
         public ViewContainer ()
         {
-            BuildHeader ();           
-            
             Spacing = 8;
+            content_manager = ServiceManager.Get<SourceContentManager> ();
+            notebook = new SourceContentNotebook ();
+
+            BuildHeader ();
+
+            PackStart (notebook, true, true, 0);
+            
             SearchSensitive = false;
         }
         
@@ -65,32 +79,30 @@ namespace Nereid
             header = new HBox ();
             footer = new VBox ();
             
-            EventBox title_box = new EventBox ();
+            content_menu = new SourceContentMenu (notebook);
+
             title_label = new Label ();
             title_label.Xalign = 0.0f;
-            title_label.Ellipsize = Pango.EllipsizeMode.End;
+            title_label.Xpad = 6;
+            title_label.Ypad = 6;
+            title_label.NoShowAll = true;
 
-            title_box.Add (title_label);
+            title_button_label = new Label ();
+            title_button_label.Xalign = 0.0f;
+            title_button_label.Xpad = 6;
+            title_button_label.Ypad = 6;
 
-            // Show the source context menu when the title is right clicked
-            title_box.PopupMenu += delegate {
-                ServiceManager.Get<InterfaceActionService> ().SourceActions ["SourceContextMenuAction"].Activate ();
-            };
+            title_button = new MenuButton (title_button_label, content_menu, true);
 
-            title_box.ButtonPressEvent += delegate (object o, ButtonPressEventArgs press) {
-                if (press.Event.Button == 3) {
-                    ServiceManager.Get<InterfaceActionService> ().SourceActions ["SourceContextMenuAction"].Activate ();
-                }
-            };
-            
             BuildSearchEntry ();
             
             search_label = new Label (Catalog.GetString ("_Search:"));
             search_label.MnemonicWidget = search_entry.InnerEntry;
             
-            header.PackStart (title_box, true, true, 0);
-            header.PackStart (search_label, false, false, 5);
-            header.PackStart (search_entry, false, false, 0);
+            header.PackStart (title_label, false, false, 0);
+            header.PackStart (title_button, false, false, 0);
+            header.PackEnd (search_entry, false, false, 0);
+            header.PackEnd (search_label, false, false, 5);
             
             InterfaceActionService uia = ServiceManager.Get<InterfaceActionService> ();
             if (uia != null) {
@@ -201,36 +213,69 @@ namespace Nereid
         public SearchEntry SearchEntry {
             get { return search_entry; }
         }
-        
-        public ISourceContents Content {
-            get { return content; }
-            set {
-                if (content == value) {
-                    return;
-                }
 
-                // Hide the old content widget
-                if (content != null && content.Widget != null) {
-                    content.Widget.Hide ();
-                }
+        public void SetSource (Source source)
+        {
+            if (source == null) {
+                return;
+            }
+
+            bool show_menu = false;
+
+            if (explicit_content != null) {
+                explicit_content.Widget.Hide ();
+            }
+
+            // If the Source has an explicit view set in its Properties, then honor that, otherwise
+            // determine what content to show from the content extensions that are compatible
+            explicit_content = source.GetProperty<ISourceContents> ("Nereid.SourceContents",
+                source.GetInheritedProperty<bool> ("Nereid.SourceContentsPropagate"));
 
-                // Add and show the new one
-                if (value != null && value.Widget != null) {
-                    PackStart (value.Widget, true, true, 0);
-                    value.Widget.Show ();
+            if (explicit_content != null) {
+                Hyena.Log.DebugFormat ("Honoring explicit content request ({0}) from source ({1})", explicit_content, source);
+                explicit_content.SetSource (source);
+                notebook.Hide ();
+                if (explicit_content.Widget.Parent == null) {
+                    PackStart (explicit_content.Widget, true, true, 0);
                 }
-                
-                // Remove the old one
-                if (content != null && content.Widget != null) {
-                    Remove (content.Widget);
+                explicit_content.Widget.Show ();
+            } else {
+                List<SourceContentProvider> providers = new List<SourceContentProvider> (content_manager.GetProvidersFor (source));
+                SourceContentProvider default_provider = content_manager.GetLastOrDefaultProviderFor (source);
+                if (default_provider == null) {
+                    Hyena.Log.ErrorFormat ("No default content provider found for source '{0}' (type {1})", source, source.GetType ());
+                    source.SetStatus (Catalog.GetString ("Error: No view found for this source"), true);
+                    notebook.Hide ();
+                    return;
                 }
-                
-                content = value;
+
+                notebook.SetSource (source, default_provider);
+                content_menu.SetSource (source, providers, default_provider);
+
+                show_menu = (content_menu.Children.Length > 1);
+                notebook.Show ();
             }
+
+            if (show_menu) {
+                title_label.Hide ();
+                content_menu.ShowAll ();
+                title_button.Show ();
+            } else {
+                title_button.Hide ();
+                title_label.Show ();
+            }
+
+            Show ();
+        }
+
+        public ISourceContents Content {
+            get { return content; }
         }
         
         public string Title {
-            set { title_label.Markup = String.Format ("<b>{0}</b>", GLib.Markup.EscapeText (value)); }
+            set {
+                title_button_label.Markup = title_label.Markup = String.Format ("<b>{0}</b>", GLib.Markup.EscapeText (value));
+            }
         }
         
         public bool SearchSensitive {
diff --git a/src/Core/Banshee.ThickClient/Banshee.Gui/CommonServices.cs b/src/Core/Banshee.ThickClient/Banshee.Gui/CommonServices.cs
index 6f336b3..8961f4a 100644
--- a/src/Core/Banshee.ThickClient/Banshee.Gui/CommonServices.cs
+++ b/src/Core/Banshee.ThickClient/Banshee.Gui/CommonServices.cs
@@ -38,6 +38,7 @@ namespace Banshee.Gui
         {
             ServiceManager.RegisterService <Banshee.Gui.GtkElementsService> ();
             ServiceManager.RegisterService <Banshee.Gui.InterfaceActionService> ();
+            ServiceManager.RegisterService <Banshee.Sources.Gui.SourceContentManager> ();
             ServiceManager.RegisterService <Banshee.Collection.Gui.ArtworkManager> ();
         }
     }
diff --git a/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/CompositeTrackSourceContents.cs b/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/CompositeTrackSourceContents.cs
index 8be3609..1374b4f 100644
--- a/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/CompositeTrackSourceContents.cs
+++ b/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/CompositeTrackSourceContents.cs
@@ -48,6 +48,34 @@ using Banshee.Collection.Gui;
 
 namespace Banshee.Sources.Gui
 {
+    public class CompositeTrackContentProvider : SourceContentProvider
+    {
+        CompositeTrackSourceContents contents;
+
+        public CompositeTrackContentProvider ()
+        {
+            Id = "composite-track-list";
+            Name = Catalog.GetString ("Standard Track List");
+            IsDefault = true;
+        }
+
+        public override bool Supports (Source source)
+        {
+            return source is ITrackModelSource;
+        }
+
+        public override ISourceContents CreateFor (Source source)
+        {
+            if (contents == null) {
+                contents = new CompositeTrackSourceContents ();
+            }
+
+            contents.ResetSource ();
+            contents.SetSource (source);
+            return contents;
+        }
+    }
+
     public class CompositeTrackSourceContents : FilteredListSourceContents, ITrackModelSourceContents
     {
         // private QueryFilterView<string> genre_view;
diff --git a/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/ISourceContents.cs b/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/ISourceContents.cs
index c93b8c4..b91d7c9 100644
--- a/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/ISourceContents.cs
+++ b/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/ISourceContents.cs
@@ -4,7 +4,7 @@
 // Author:
 //   Gabriel Burt <gburt novell com>
 //
-// Copyright (C) 2007 Novell, Inc.
+// 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
diff --git a/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/ObjectListSourceContents.cs b/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/ObjectListSourceContents.cs
index 8c5cbfc..e61162b 100644
--- a/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/ObjectListSourceContents.cs
+++ b/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/ObjectListSourceContents.cs
@@ -45,6 +45,33 @@ using Banshee.Collection.Gui;
 
 namespace Banshee.Sources.Gui
 {
+    public class ObjectListContentProvider : SourceContentProvider
+    {
+        ObjectListSourceContents contents;
+
+        public ObjectListContentProvider ()
+        {
+            Id = "object-list";
+            Name = Catalog.GetString ("Object List");
+        }
+
+        public override bool Supports (Source source)
+        {
+            return source is Hyena.Data.IObjectListModel;
+        }
+
+        public override ISourceContents CreateFor (Source source)
+        {
+            if (contents == null) {
+                contents = new ObjectListSourceContents ();
+            }
+
+            contents.ResetSource ();
+            contents.SetSource (source);
+            return contents;
+        }
+    }
+
     public class ObjectListSourceContents : ScrolledWindow, ISourceContents
     {
         private ObjectListView object_view;
diff --git a/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceContentManager.cs b/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceContentManager.cs
new file mode 100644
index 0000000..a3223b7
--- /dev/null
+++ b/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceContentManager.cs
@@ -0,0 +1,136 @@
+//
+// SourceContentManager.cs
+//
+// Author:
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2009 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 Mono.Addins;
+using Hyena;
+
+using Banshee.ServiceStack;
+using Banshee.Configuration;
+using Banshee.Sources;
+
+namespace Banshee.Sources.Gui
+{
+    public abstract class SourceContentProvider
+    {
+        private string id;
+        public string Id {
+            get { return id; }
+            protected set { id = value; }
+        }
+
+        private string name;
+        public string Name {
+            get { return name; }
+            protected set { name = value; }
+        }
+
+        private bool is_default;
+        public bool IsDefault {
+            get { return is_default; }
+            protected set { is_default = value; }
+        }
+
+        // Inheritable?
+        // IconName?
+
+        public abstract bool Supports (Source source);
+        public abstract ISourceContents CreateFor (Source source);
+    }
+
+    // Responsible for loading ISourceContents and pairing them up with Sources
+    public class SourceContentManager : IRequiredService
+    {
+        private Dictionary<string, SourceContentProvider> providers = new Dictionary<string, SourceContentProvider> ();
+
+        public SourceContentManager ()
+        {
+            AddinManager.AddExtensionNodeHandler ("/Banshee/ThickClient/SourceContentProvider", OnExtensionChanged);
+        }
+
+        public void Dispose ()
+        {
+            AddinManager.RemoveExtensionNodeHandler ("/Banshee/ThickClient/SourceContentProvider", OnExtensionChanged);
+        }
+
+        private void OnExtensionChanged (object o, ExtensionNodeEventArgs args) 
+        {
+            lock (providers) {
+                TypeExtensionNode node = (TypeExtensionNode)args.ExtensionNode;
+                
+                if (args.Change == ExtensionChange.Add && !providers.ContainsKey (node.Id)) {
+                    SourceContentProvider provider = (SourceContentProvider) node.CreateInstance ();
+                    providers.Add (node.Id, provider);
+                    Log.DebugFormat ("Loaded SourceContentProvider: '{0}'", provider.Id);
+                } else if (args.Change == ExtensionChange.Remove && providers.ContainsKey (node.Id)) {
+                    //SourceContentProvider provider = providers[node.Id];
+                    //provider.Dispose ();
+                    providers.Remove (node.Id);
+                }
+            }
+        }
+
+        public IEnumerable<SourceContentProvider> GetProvidersFor (Source source)
+        {
+            foreach (SourceContentProvider provider in providers.Values) {
+                if (provider.Supports (source)) {
+                    yield return provider;
+                }
+            }
+        }
+
+        public SourceContentProvider GetLastOrDefaultProviderFor (Source source)
+        {
+            string default_id = source.CreateSchema<string> ("last_content").Get ();
+
+            SourceContentProvider first = null;
+            SourceContentProvider first_default = null;
+
+            // Return the last provider used
+            foreach (var provider in GetProvidersFor (source)) {
+                if (provider.Id == default_id) {
+                    return provider;
+                }
+
+                first = first ?? provider;
+                if (provider.IsDefault) {
+                    first_default = first_default ?? provider;
+                }
+            }
+
+            // If none/not found, return the first default provider, or just the first
+            return first_default ?? first;
+        }
+
+        string IService.ServiceName {
+            get { return "SourceContentManager"; }
+        } 
+    }
+}
diff --git a/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceContentMenu.cs b/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceContentMenu.cs
new file mode 100644
index 0000000..12f465a
--- /dev/null
+++ b/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceContentMenu.cs
@@ -0,0 +1,81 @@
+// 
+// SourceContentMenu.cs
+//
+// Author:
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2009 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 Gtk;
+using Mono.Unix;
+
+using Hyena.Widgets;
+
+using Banshee.Widgets;
+using Banshee.Gui.Widgets;
+using Banshee.Sources.Gui;
+using Banshee.Collection;
+
+using Banshee.Gui;
+using Banshee.ServiceStack;
+using Banshee.Sources;
+
+namespace Banshee.Sources.Gui
+{
+    public class SourceContentMenu : Menu
+    {
+        private SourceContentNotebook notebook;
+
+        public SourceContentMenu (SourceContentNotebook notebook)
+        {
+            this.notebook = notebook;
+        }
+
+        public void SetSource (Source source, List<SourceContentProvider> providers, SourceContentProvider current_provider)
+        {
+            // Clear out the last source's content options, fill in ours, and show/hide the title
+            // label / button depending on if there's more than one option.
+            while (Children.Length > 0) {
+                Remove (Children [Children.Length - 1]);
+            }
+
+            RadioMenuItem first_item = new RadioMenuItem ("");
+            foreach (var provider in providers) {
+                RadioMenuItem item = new RadioMenuItem (first_item, provider.Name);
+                item.Active = provider == current_provider;
+
+                var p = provider; // Capture into a local var
+                item.Toggled += delegate (object o, EventArgs args) {
+                    if (item.Active) {
+                        notebook.Activate (p);
+                    }
+                };
+
+                Append (item);
+                first_item = first_item ?? item;
+            }
+        }
+    }
+}
diff --git a/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceContentNotebook.cs b/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceContentNotebook.cs
new file mode 100644
index 0000000..e30e034
--- /dev/null
+++ b/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceContentNotebook.cs
@@ -0,0 +1,81 @@
+//
+// SourceContentNotebook.cs
+//
+// Authors:
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2009 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.Reflection;
+using System.Collections.Generic;
+
+using Gtk;
+using Mono.Unix;
+
+using Hyena.Data;
+using Hyena.Data.Gui;
+using Hyena.Widgets;
+
+using Banshee.Sources;
+using Banshee.ServiceStack;
+using Banshee.Collection;
+using Banshee.Configuration;
+using Banshee.Gui;
+using Banshee.Collection.Gui;
+
+namespace Banshee.Sources.Gui
+{
+    public class SourceContentNotebook : Notebook
+    {
+        private Source source;
+
+        public SourceContentNotebook () : base ()
+        {
+            ShowBorder = false;
+            ShowTabs = false;
+        }
+
+        public void SetSource (Source source, SourceContentProvider provider)
+        {
+            this.source = source;
+
+            Activate (provider);
+        }
+
+        public void Activate (SourceContentProvider provider)
+        {
+            ISourceContents content = provider.CreateFor (source);
+            content.SetSource (source);
+            content.Widget.Show ();
+            source.CreateSchema<string> ("last_content").Set (provider.Id);
+
+            if (PageNum (content.Widget) < 0) {
+                AppendPage (content.Widget, null);
+            }
+
+            CurrentPage = PageNum (content.Widget);
+        }
+    }
+}
diff --git a/src/Core/Banshee.ThickClient/Banshee.ThickClient.addin.xml b/src/Core/Banshee.ThickClient/Banshee.ThickClient.addin.xml
index 9b094b0..593465b 100644
--- a/src/Core/Banshee.ThickClient/Banshee.ThickClient.addin.xml
+++ b/src/Core/Banshee.ThickClient/Banshee.ThickClient.addin.xml
@@ -19,7 +19,7 @@
     <ImportSource class="Banshee.Library.Gui.PhotoFolderImportSource"/>
     <ImportSource class="Banshee.Library.Gui.FileImportSource"/>
   </Extension>
-  
+
   <Extension path="/Banshee/Gui/TrackEditor/NotebookPage">
     <TrackEditorPage class="Banshee.Gui.TrackEditor.BasicTrackDetailsPage"/>
     <TrackEditorPage class="Banshee.Gui.TrackEditor.ExtraTrackDetailsPage"/>
@@ -28,6 +28,11 @@
     <TrackEditorPage class="Banshee.Gui.TrackEditor.StatisticsPage"/>
     <!--<TrackEditorPage class="Banshee.Gui.TrackEditor.HelpPage"/>-->
   </Extension>
+
+  <Extension path="/Banshee/ThickClient/SourceContentProvider">
+    <Provider class="Banshee.Sources.Gui.CompositeTrackContentProvider"/>
+    <Provider class="Banshee.Sources.Gui.ObjectListContentProvider"/>
+  </Extension>
   
   <!-- Exported Extension Points -->
   
@@ -36,9 +41,9 @@
     <ExtensionNode name="ActionGroup"/>
   </ExtensionPoint>
 
-  <ExtensionPoint path="/Banshee/ThickClient/SourceView">
+  <ExtensionPoint path="/Banshee/ThickClient/SourceContentProvider">
     <Description>Defines a new GTK+ source view, possibly in conjunction with a Source extension.</Description>
-    <ExtensionNode name="SourceView"/>
+    <ExtensionNode name="Provider"/>
   </ExtensionPoint>
   
   <ExtensionPoint path="/Banshee/Gui/TrackEditor/NotebookPage">
diff --git a/src/Core/Banshee.ThickClient/Makefile.am b/src/Core/Banshee.ThickClient/Makefile.am
index 317e690..c0fbb5f 100644
--- a/src/Core/Banshee.ThickClient/Makefile.am
+++ b/src/Core/Banshee.ThickClient/Makefile.am
@@ -142,6 +142,9 @@ SOURCES =  \
 	Banshee.Sources.Gui/ITrackModelSourceContents.cs \
 	Banshee.Sources.Gui/ObjectListSourceContents.cs \
 	Banshee.Sources.Gui/SourceComboBox.cs \
+	Banshee.Sources.Gui/SourceContentManager.cs \
+	Banshee.Sources.Gui/SourceContentMenu.cs \
+	Banshee.Sources.Gui/SourceContentNotebook.cs \
 	Banshee.Sources.Gui/SourceIconResolver.cs \
 	Banshee.Sources.Gui/SourceModel.cs \
 	Banshee.Sources.Gui/SourceRowRenderer.cs \
diff --git a/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying.addin.xml b/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying.addin.xml
index 46c55b3..04ba776 100644
--- a/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying.addin.xml
+++ b/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying.addin.xml
@@ -24,6 +24,10 @@
     <Source class="Banshee.NowPlaying.NowPlayingSource"/>
   </Extension>
 
+  <Extension path="/Banshee/ThickClient/SourceContentProvider">
+    <Provider class="Banshee.NowPlaying.NowPlayingContentProvider"/>
+  </Extension>
+
   <ExtensionPoint path="/Banshee/NowPlaying/FullscreenAdapter">
     <ExtensionNode name="FullscreenAdapter"/>
   </ExtensionPoint>
diff --git a/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingInterface.cs b/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingInterface.cs
index 7f8a823..8050bb1 100644
--- a/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingInterface.cs
+++ b/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingInterface.cs
@@ -38,6 +38,34 @@ using Banshee.Sources.Gui;
 
 namespace Banshee.NowPlaying
 {
+    public class NowPlayingContentProvider : SourceContentProvider
+    {
+        NowPlayingInterface contents;
+
+        public NowPlayingContentProvider ()
+        {
+            Id = "now-playing-standard";
+            Name = Catalog.GetString ("Now Playing (Video and Track Info)");
+            IsDefault = true;
+        }
+
+        public override bool Supports (Source source)
+        {
+            return source is NowPlayingSource;
+        }
+
+        public override ISourceContents CreateFor (Source source)
+        {
+            if (contents == null) {
+                contents = new NowPlayingInterface ();
+            }
+
+            contents.ResetSource ();
+            contents.SetSource (source);
+            return contents;
+        }
+    }
+
     public class NowPlayingInterface : VBox, ISourceContents
     {   
         private NowPlayingSource source;
diff --git a/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingSource.cs b/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingSource.cs
index 44d0422..b6c15c2 100644
--- a/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingSource.cs
+++ b/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingSource.cs
@@ -43,7 +43,6 @@ namespace Banshee.NowPlaying
     public class NowPlayingSource : Source, IDisposable
     {
         private TrackInfo transitioned_track;
-        private NowPlayingInterface now_playing_interface;
         
         public NowPlayingSource () : base ("now-playing", Catalog.GetString ("Now Playing"), 10, "now-playing")
         {
@@ -52,11 +51,8 @@ namespace Banshee.NowPlaying
                 throw new ApplicationException ("Unsupported video display context");
             }
         
-            now_playing_interface = new NowPlayingInterface ();
-        
             Properties.SetString ("Icon.Name", "applications-multimedia");
-            Properties.Set<ISourceContents> ("Nereid.SourceContents", now_playing_interface);
-            Properties.Set<bool> ("Nereid.SourceContents.HeaderVisible", false);
+            //Properties.Set<bool> ("Nereid.SourceContents.HeaderVisible", false);
             Properties.SetString ("ActiveSourceUIResource", "ActiveSourceUI.xml");
             
             ServiceManager.SourceManager.AddSource (this);
@@ -72,11 +68,12 @@ namespace Banshee.NowPlaying
             ServiceManager.PlaybackController.TrackStarted -= OnPlaybackControllerTrackStarted;
             ServiceManager.PlayerEngine.DisconnectEvent (OnTrackInfoUpdated);
 
-            if (now_playing_interface != null) {
+            // FIXME need to Dispose via the new SourceContentManager
+            /*if (now_playing_interface != null) {
                 now_playing_interface.Destroy ();
                 now_playing_interface.Dispose ();
                 now_playing_interface = null;
-            }
+            }*/
         }
         
         private void OnTrackInfoUpdated (PlayerEventArgs args)
@@ -109,16 +106,16 @@ namespace Banshee.NowPlaying
         
         public override void Activate ()
         {
-            if (now_playing_interface != null) {
+            /*if (now_playing_interface != null) {
                 now_playing_interface.OverrideFullscreen ();
-            }
+            }*/
         }
 
         public override void Deactivate ()
         {
-            if (now_playing_interface != null) {
+            /*if (now_playing_interface != null) {
                 now_playing_interface.RelinquishFullscreen ();
-            }
+            }*/
         }
     }
 }



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