[banshee] [Banshee.ThickClient] Source switcher improvements



commit 8a2c14fa515b0f42eb6bd4c6a26f4ab991f3454d
Author: Gabriel Burt <gabriel burt gmail com>
Date:   Sun Apr 4 16:19:18 2010 -0700

    [Banshee.ThickClient] Source switcher improvements
    
    Now delays hiding the entry for 1s after switching to a source, so that
    if you keep typing it'll capture those keypresses still (and not
    activate any keybindings they might be bound to).

 .../Banshee.Sources.Gui/SourceSwitcherEntry.cs     |  191 ++++++++++++++++++++
 .../Banshee.Sources.Gui/SourceView.cs              |  115 +------------
 .../Banshee.ThickClient/Banshee.ThickClient.csproj |    1 +
 src/Core/Banshee.ThickClient/Makefile.am           |    1 +
 4 files changed, 195 insertions(+), 113 deletions(-)
---
diff --git a/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceSwitcherEntry.cs b/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceSwitcherEntry.cs
new file mode 100644
index 0000000..30b1003
--- /dev/null
+++ b/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceSwitcherEntry.cs
@@ -0,0 +1,191 @@
+//
+// SourceSwitcherEntry.cs
+//
+// Author:
+//   Gabriel Burt <gabriel burt gmail com>
+//
+// Copyright (C) 2010 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.Linq;
+using System.Collections.Generic;
+
+using Gtk;
+using Cairo;
+using Mono.Unix;
+
+using Hyena;
+using Hyena.Gui;
+using Hyena.Widgets;
+using Hyena.Gui.Theming;
+using Hyena.Gui.Theatrics;
+
+using Banshee.Configuration;
+using Banshee.ServiceStack;
+using Banshee.Sources;
+using Banshee.Playlist;
+
+using Banshee.Gui;
+
+namespace Banshee.Sources.Gui
+{
+    public class SourceSwitcherEntry : Hyena.Widgets.EntryPopup
+    {
+        private SourceView view;
+        private uint hide_timeout_id = 0;
+
+        public SourceSwitcherEntry (SourceView view)
+        {
+            this.view = view;
+
+            HideAfterTimeout = false;
+
+            // FIXME not sure if it's possible to do auto-complete w/o a Model
+            /*var completion = new EntryCompletion () {
+                //InlineSelection = true,
+                //InlineCompletion = true,
+                PopupCompletion = true,
+                MatchFunc = (c, key, iter) => {
+                    //Console.WriteLine ("MatchFunc called! for key {0}", key);
+                    return true;
+                },
+                PopupSingleMatch = true,
+                MinimumKeyLength = 1
+            };
+
+            var store = new ListStore (typeof (string));
+            completion.TextColumn = 0;
+            completion.Model = store;
+            completion.PopupCompletion = true;
+            completion.PopupSingleMatch = true;
+
+            Entry.Completion = completion;
+            completion.ActionActivated += (o2, a) => {
+                Console.WriteLine ("completion.ActionActivated");
+                try {
+                    SwitchSource (SourceSwitcherMatches (Text).Skip (a.Index).FirstOrDefault ());
+                } catch {}
+            };*/
+
+            Changed += delegate {
+                //store.Clear ();
+                //completion.Complete ();
+
+                if (hide_timeout_id != 0) {
+                    ServiceStack.Application.IdleTimeoutRemove (hide_timeout_id);
+                    hide_timeout_id = 0;
+                }
+
+                if (Text.Length > 0) {
+                    // If there is only one source that matches, switch to it
+                    var list = SourceSwitcherMatches (Text).ToList ();
+                    if (list.Count == 1) {
+                        SwitchSource (list[0]);
+                        // Hide only after a timeout, helps to capture extra entered chars if we switch before the user expects
+                        hide_timeout_id = ServiceStack.Application.RunTimeout (1000, delegate { Hide (); return false; });
+                    } else {
+                        /*foreach (var src in list) {
+                            store.AppendValues (src.Name);
+                        }*/
+                    }
+                }
+            };
+
+            Entry.Activated += delegate {
+                try {
+                    var src = SourceSwitcherMatches (Text).FirstOrDefault ();
+                    SwitchSource (src);
+                } catch {}
+            };
+
+            Position (view.GdkWindow);
+            HasFocus = true;
+            Show ();
+        }
+
+        private IEnumerable<Source> SourceSwitcherMatches (string query)
+        {
+            query = StringUtil.SearchKey (query);
+            if (String.IsNullOrEmpty (query)) {
+                return Enumerable.Empty<Source> ();
+            }
+
+            //Console.WriteLine ("\nGetting matches for {0}", query);
+            return ServiceManager.SourceManager.Sources
+                                               .Select  (s => new { Source = s, Priority = SourceSwitcherPriority (s, query) })
+                                               .Where   (s => s.Priority > 0)
+                                               .OrderBy (s => s.Priority)
+                                               .Select  (s => s.Source);
+        }
+
+        private int SourceSwitcherPriority (Source s, string query)
+        {
+            int priority = 0;
+            var name = StringUtil.SearchKey (s.Name);
+            if (name != null) {
+                if (name == query) {
+                    //Console.WriteLine ("{0} equals {1}", s.Name, query);
+                    priority = 10;
+                } else if (name.StartsWith (query)) {
+                    //Console.WriteLine ("{0} starts with {1}", s.Name, query);
+                    priority = 20;
+                } else {
+                    var split_name = name.Split (' ');
+                    if (split_name.Length == query.Length &&
+                        Enumerable.Range (0, query.Length).All (i => split_name[i][0] == query[i])) {
+                        //Console.WriteLine ("{0} initials are {1}", s.Name, query);
+                        priority = 30;
+                    } else if (name.Contains (query)) {
+                        //Console.WriteLine ("{0} contains {1}", s.Name, query);
+                        priority = 40;
+                    }
+                }
+
+                // Give sources under (or siblings of) the currently active source a priority bump
+                var asrc = ServiceManager.SourceManager.ActiveSource;
+                if (s.Parent != null && (s.Parent == asrc || s.Parent == asrc.Parent)) {
+                    //Console.WriteLine ("{0} is child of active, giving bump", s.Name);
+                    priority--;
+                }
+            }
+
+            return priority;
+        }
+
+        private void SwitchSource (Source src)
+        {
+            if (src != null) {
+                if (src.Parent != null) {
+                    view.Expand (src.Parent);
+                }
+
+                ServiceManager.SourceManager.SetActiveSource (src);
+
+                if (hide_timeout_id != 0) {
+                    ServiceStack.Application.IdleTimeoutRemove (hide_timeout_id);
+                    hide_timeout_id = 0;
+                }
+            }
+        }
+    }
+}
diff --git a/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView.cs b/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView.cs
index 90548ba..cf7b01a 100644
--- a/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView.cs
+++ b/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView.cs
@@ -144,7 +144,7 @@ namespace Banshee.Sources.Gui
             };
 
             ServiceManager.Get<InterfaceActionService> ().SourceActions["OpenSourceSwitcher"].Activated += delegate {
-                OpenSourceSwitcher ();
+                new SourceSwitcherEntry (this);
             };
         }
 
@@ -232,117 +232,6 @@ namespace Banshee.Sources.Gui
             return base.OnButtonPressEvent (press);
         }
 
-        private void OpenSourceSwitcher ()
-        {
-            var popup = new Hyena.Widgets.EntryPopup ();
-            popup.HideAfterTimeout = false;
-
-            // FIXME not sure if it's possible to do auto-complete w/o a Model
-            /*var completion = new EntryCompletion () {
-                InlineSelection = true,
-                InlineCompletion = true,
-                PopupCompletion = true,
-                PopupSingleMatch = true,
-                MinimumKeyLength = 2
-            };
-
-            popup.Entry.Completion = completion;
-            completion.ActionActivated += (o2, a) => {
-                try {
-                    var src = SourceSwitcherMatches (popup.Text).Skip (a.Index).FirstOrDefault ();
-                    if (src != null) {
-                        ServiceManager.SourceManager.SetActiveSource (src);
-                    }
-                } catch {}
-            };*/
-
-            popup.Changed += delegate {
-                if (popup.Text.Length > 0) {
-                    // If there is only one source that matches, switch to it
-                    var list = SourceSwitcherMatches (popup.Text).ToList ();
-                    if (list.Count == 1) {
-                        if (list[0].Parent != null) {
-                            Expand (list[0].Parent);
-                        }
-                        ServiceManager.SourceManager.SetActiveSource (list[0]);
-                        popup.Hide ();
-                    }
-                }
-                /*completion.Clear ();
-                completion.Complete ();
-
-                int i = 0;
-                foreach (var src in SourceSwitcherMatches (popup.Text)) {
-                    completion.InsertActionText (i++, src.Name);
-                }*/
-            };
-
-            popup.Entry.Activated += delegate {
-                try {
-                    var src = SourceSwitcherMatches (popup.Text).FirstOrDefault ();
-                    if (src != null) {
-                        if (src.Parent != null) {
-                            Expand (src.Parent);
-                        }
-                        ServiceManager.SourceManager.SetActiveSource (src);
-                    }
-                } catch {}
-            };
-
-            popup.Position (GdkWindow);
-            popup.HasFocus = true;
-            popup.Show ();
-        }
-
-        private IEnumerable<Source> SourceSwitcherMatches (string query)
-        {
-            query = StringUtil.SearchKey (query);
-            if (String.IsNullOrEmpty (query)) {
-                return Enumerable.Empty<Source> ();
-            }
-
-            Console.WriteLine ("\nGetting matches for {0}", query);
-            return ServiceManager.SourceManager.Sources
-                                               .Select  (s => new { Source = s, Priority = SourceSwitcherPriority (s, query) })
-                                               .Where   (s => s.Priority > 0)
-                                               .OrderBy (s => s.Priority)
-                                               .Select  (s => s.Source);
-        }
-
-        private int SourceSwitcherPriority (Source s, string query)
-        {
-            int priority = 0;
-            var name = StringUtil.SearchKey (s.Name);
-            if (name != null) {
-                if (name == query) {
-                    Console.WriteLine ("{0} equals {1}", s.Name, query);
-                    priority = 10;
-                } else if (name.StartsWith (query)) {
-                    Console.WriteLine ("{0} starts with {1}", s.Name, query);
-                    priority = 20;
-                } else {
-                    var split_name = name.Split (' ');
-                    if (split_name.Length == query.Length &&
-                        Enumerable.Range (0, query.Length).All (i => split_name[i][0] == query[i])) {
-                        Console.WriteLine ("{0} initials are {1}", s.Name, query);
-                        priority = 30;
-                    } else if (name.Contains (query)) {
-                        Console.WriteLine ("{0} contains {1}", s.Name, query);
-                        priority = 40;
-                    }
-                }
-
-                // Give sources under (or siblings of) the currently active source a priority bump
-                var asrc = ServiceManager.SourceManager.ActiveSource;
-                if (s.Parent != null && (s.Parent == asrc || s.Parent == asrc.Parent)) {
-                    Console.WriteLine ("{0} is child of active, giving bump", s.Name);
-                    priority--;
-                }
-            }
-
-            return priority;
-        }
-
         protected override bool OnPopupMenu ()
         {
             ServiceManager.Get<InterfaceActionService> ().SourceActions["SourceContextMenuAction"].Activate ();
@@ -456,7 +345,7 @@ namespace Banshee.Sources.Gui
             QueueDraw ();
         }
 
-        private void Expand (Source src)
+        internal void Expand (Source src)
         {
             Expand (store.FindSource (src));
             src.Expanded = true;
diff --git a/src/Core/Banshee.ThickClient/Banshee.ThickClient.csproj b/src/Core/Banshee.ThickClient/Banshee.ThickClient.csproj
index 4c58e01..b19dbed 100644
--- a/src/Core/Banshee.ThickClient/Banshee.ThickClient.csproj
+++ b/src/Core/Banshee.ThickClient/Banshee.ThickClient.csproj
@@ -130,6 +130,7 @@
     <Compile Include="Banshee.Collection.Gui\AlbumListView.cs" />
     <Compile Include="Banshee.Collection.Gui\DataViewChildAlbum.cs" />
     <Compile Include="Banshee.Sources.Gui\SourceView.cs" />
+    <Compile Include="Banshee.Sources.Gui\SourceSwitcherEntry.cs" />
     <Compile Include="Banshee.Gui.DragDrop\DragDropTarget.cs" />
     <Compile Include="Banshee.Gui.DragDrop\DragDropUtilities.cs" />
     <Compile Include="Banshee.Gui\IconThemeUtils.cs" />
diff --git a/src/Core/Banshee.ThickClient/Makefile.am b/src/Core/Banshee.ThickClient/Makefile.am
index d8ac95b..4285c26 100644
--- a/src/Core/Banshee.ThickClient/Makefile.am
+++ b/src/Core/Banshee.ThickClient/Makefile.am
@@ -156,6 +156,7 @@ SOURCES =  \
 	Banshee.Sources.Gui/SourceIconResolver.cs \
 	Banshee.Sources.Gui/SourceModel.cs \
 	Banshee.Sources.Gui/SourceRowRenderer.cs \
+	Banshee.Sources.Gui/SourceSwitcherEntry.cs \
 	Banshee.Sources.Gui/SourceView.cs \
 	Banshee.Sources.Gui/SourceView_DragAndDrop.cs
 



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