[banshee] [Banshee.ThickClient] Source switcher improvements
- From: Gabriel Burt <gburt src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [banshee] [Banshee.ThickClient] Source switcher improvements
- Date: Sun, 4 Apr 2010 23:22:37 +0000 (UTC)
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]