Hi Aaron,
Attached is the patch for HEAD.
Please let me know when you review. If you are ok with it and want to commit, I can get a ChangeLog ready for you..
Best
Ulas.
Index: src/PlayerInterface.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/PlayerInterface.cs,v
retrieving revision 1.128
diff -u -r1.128 PlayerInterface.cs
--- src/PlayerInterface.cs 5 Jan 2006 22:48:36 -0000 1.128
+++ src/PlayerInterface.cs 7 Jan 2006 15:50:30 -0000
@@ -59,6 +59,8 @@
[Widget] private Gtk.Label LabelInfo;
[Widget] private HPaned SourceSplitter;
[Widget] private Button HeaderCycleButton;
+ [Widget] private Expander CustomExpander;
+ [Widget] private Gtk.VBox DisclosureBox;
private PlaylistModel playlistModel;
@@ -75,6 +77,7 @@
private Tooltips toolTips;
private Hashtable playlistMenuMap;
private Viewport sourceViewLoadingVP;
+ private BrowserBox browser;
private MultiStateToggleButton repeat_toggle_button;
private MultiStateToggleButton shuffle_toggle_button;
@@ -442,6 +445,14 @@
gxml["SearchLabel"].Sensitive = false;
searchEntry.Sensitive = false;
+
+ // Custom Expander and browser related stuff.
+ CustomExpander = ((Expander)gxml["CustomExpander"]);
+ DisclosureBox = ((VBox)gxml["DisclosureBox"]);
+ browser = new BrowserBox();
+ DisclosureBox.Add(browser);
+ CustomExpander.Activated += OnExpandAreaClicked;
+ browser.BrowserSearchActivated += OnBrowserSearchActivated;
// Repeat/Shuffle buttons
@@ -642,6 +653,8 @@
PromptForImport();
});
}
+
+ browser.BrowserReset();
}
private bool PromptForImportTimeout()
@@ -782,6 +795,17 @@
handled = true;
}
break;
+ case Gdk.Key.F5:
+ if((args.Event.State & Gdk.ModifierType.ControlMask) != 0) {
+ if (CustomExpander.Expanded) {
+ CustomExpander.Expanded = false;
+ } else {
+ CustomExpander.Expanded = true;
+ }
+ OnExpandAreaClicked(this, new EventArgs());
+ handled = true;
+ }
+ break;
case Gdk.Key.Left:
if((args.Event.State & Gdk.ModifierType.ControlMask) != 0) {
PlayerEngineCore.ActivePlayer.Position -= SkipDelta;
@@ -1073,13 +1097,15 @@
private void OnSourceManagerActiveSourceChanged(SourceEventArgs args)
{
ThreadAssist.ProxyToMain(HandleSourceChanged);
+ browser.BrowserReset();
}
private void OnSourceManagerSourceUpdated(SourceEventArgs args)
{
if(args.Source == SourceManager.ActiveSource) {
UpdateViewName(args.Source);
- }
+ }
+ browser.BrowserUpdate();
}
private void UpdateViewName(Source source)
@@ -1525,16 +1551,26 @@
playlistModel.Clear();
if(!searchEntry.IsQueryAvailable) {
- playlistModel.ReloadSource();
+ if (browser.BrowserHasFilter()) {
+ playlistModel.SearchSource(null,null);
+ } else {
+ playlistModel.ReloadSource();
+ }
+
return;
}
- ICollection collection = SourceManager.ActiveSource.Tracks;
-
- foreach(TrackInfo track in collection) {
+ ICollection collection = null;
+ if (browser.BrowserHasFilter()) {
+ collection = playlistModel.GetBrowsedTracks();
+ } else {
+ collection = SourceManager.ActiveSource.Tracks;
+ }
+
+ foreach(TrackInfo ti in collection) {
try {
- if(DoesTrackMatchSearch(track)) {
- playlistModel.AddTrack(track);
+ if(DoesTrackMatchSearch(ti)) {
+ playlistModel.AddTrack(ti);
}
} catch(Exception) {
continue;
@@ -1949,6 +1985,7 @@
}
playlistModel.AddTrack(ti);
+ browser.BrowserFilter();
});
}
} catch(Entagged.Audioformats.Exceptions.CannotReadException) {
@@ -2051,6 +2088,14 @@
playlistView.QueueDraw();
}
+ private void OnBrowserSearchActivated(object o, BrowserSearchEventArgs args)
+ {
+ playlistModel.SearchSource(args.artist, args.album);
+ if(searchEntry.IsQueryAvailable) {
+ OnSimpleSearch(o, new EventArgs());
+ }
+ }
+
private void OnLibraryTrackRemoveFinished(object o, EventArgs args)
{
}
@@ -2408,6 +2453,17 @@
}
log_viewer.Show();
+ }
+
+ // --- Expander ---
+
+ private void OnExpandAreaClicked (object sender, EventArgs args)
+ {
+ if (CustomExpander.Expanded) {
+ DisclosureBox.Visible = true;
+ } else {
+ DisclosureBox.Visible = false;
+ }
}
// --- Help Menu ---
Index: src/PlaylistModel.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/PlaylistModel.cs,v
retrieving revision 1.31
diff -u -r1.31 PlaylistModel.cs
--- src/PlaylistModel.cs 6 Jan 2006 06:12:52 -0000 1.31
+++ src/PlaylistModel.cs 7 Jan 2006 15:50:35 -0000
@@ -50,6 +50,7 @@
private TimeSpan totalDuration = new TimeSpan(0);
private ArrayList trackInfoQueue;
+ private ArrayList browsedTracks;
private bool trackInfoQueueLocked = false;
private TreeIter playingIter;
@@ -68,6 +69,7 @@
public PlaylistModel() : base(typeof(TrackInfo))
{
trackInfoQueue = new ArrayList();
+ browsedTracks = new ArrayList();
GLib.Timeout.Add(300, new GLib.TimeoutHandler(OnIdle));
SourceManager.ActiveSourceChanged += delegate(SourceEventArgs args) {
ReloadSource();
@@ -158,6 +160,67 @@
SyncPlayingIter();
}
+
+ public void SearchSource(BrowserEventInfo beiArtist, BrowserEventInfo beiAlbum)
+ {
+ ClearModel();
+ if (beiArtist != null && beiAlbum!= null) {
+ browsedTracks.Clear();
+ ICollection collection = SourceManager.ActiveSource.Tracks;
+ foreach(TrackInfo ti in collection) {
+ try {
+ if(DoesTrackMatchSearch(ti, beiArtist, beiAlbum)) {
+ AddTrack(ti);
+ browsedTracks.Add(ti);
+ }
+ } catch(Exception) {
+ continue;
+ }
+ }
+
+ } else {
+ foreach(TrackInfo ti in browsedTracks) {
+ try {
+ AddTrack(ti);
+ } catch(Exception) {
+ continue;
+ }
+ }
+ }
+ }
+
+ public ICollection GetBrowsedTracks()
+ {
+ return browsedTracks;
+ }
+
+ private bool DoesTrackMatchSearch(TrackInfo ti, BrowserEventInfo Artist, BrowserEventInfo Album)
+ {
+ string artist = Artist.StrData.ToLower();
+ string album = Album.StrData.ToLower();
+ string ti_artist = ti.Artist.ToString().ToLower();
+ string ti_album = ti.Album.ToString().ToLower();
+ int artist_index = Artist.IntIndex;
+ int album_index = Album.IntIndex;
+
+ if (artist_index == 0 && album_index == 0) {
+ return true;
+ } else if (artist_index == 0) {
+ if (album.Equals(ti_album)) {
+ return true;
+ }
+ } else if (album_index == 0) {
+ if (artist.Equals(ti_artist)) {
+ return true;
+ }
+ } else if (album_index != 0 && artist_index != 0) {
+ if (artist.Equals(ti_artist) && album.Equals(ti_album)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
// --- Helper Methods ---
Index: src/Makefile.am
===================================================================
RCS file: /cvs/gnome/banshee/src/Makefile.am,v
retrieving revision 1.84
diff -u -r1.84 Makefile.am
--- src/Makefile.am 5 Jan 2006 22:48:36 -0000 1.84
+++ src/Makefile.am 7 Jan 2006 15:50:35 -0000
@@ -58,6 +58,7 @@
ExceptionDialog.cs \
VersionInformationDialog.cs \
LogCoreViewer.cs \
+ SourceBrowser.cs \
ToggleStates.cs
banshee_resources = \
Index: data/banshee.glade
===================================================================
RCS file: /cvs/gnome/banshee/data/banshee.glade,v
retrieving revision 1.5
diff -u -r1.5 banshee.glade
--- data/banshee.glade 5 Jan 2006 22:48:34 -0000 1.5
+++ data/banshee.glade 7 Jan 2006 15:50:42 -0000
@@ -249,22 +249,38 @@
<property name="spacing">5</property>
<child>
- <widget class="GtkLabel" id="ViewNameLabel">
+ <widget class="GtkExpander" id="CustomExpander">
<property name="visible">True</property>
- <property name="label" translatable="yes"><b>Loading...</b></property>
- <property name="use_underline">False</property>
- <property name="use_markup">True</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">4</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
+ <property name="can_focus">True</property>
+ <property name="expanded">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <placeholder/>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="ViewNameLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"><b>Loading...</b></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">4</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
</widget>
<packing>
<property name="padding">0</property>
@@ -373,30 +389,57 @@
</child>
<child>
- <widget class="GtkAlignment" id="LibraryAlignment">
+ <widget class="GtkVPaned" id="VPane">
<property name="visible">True</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xscale">1</property>
- <property name="yscale">1</property>
- <property name="top_padding">0</property>
- <property name="bottom_padding">0</property>
- <property name="left_padding">0</property>
- <property name="right_padding">0</property>
+ <property name="can_focus">True</property>
+ <property name="position">200</property>
<child>
- <widget class="GtkScrolledWindow" id="LibraryContainer">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="shadow_type">GTK_SHADOW_IN</property>
- <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+ <widget class="GtkVBox" id="DisclosureBox">
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
<child>
<placeholder/>
</child>
</widget>
+ <packing>
+ <property name="shrink">False</property>
+ <property name="resize">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="LibraryAlignment">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="LibraryContainer">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">True</property>
+ <property name="resize">True</property>
+ </packing>
</child>
</widget>
<packing>
--- src/SourceBrowser.cs 2006-01-07 19:25:49.000000000 +0200
+++ src/SourceBrowser.cs 2006-01-07 19:20:22.000000000 +0200
@@ -0,0 +1,431 @@
+/* -*- Mode: csharp; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: t -*- */
+/***************************************************************************
+ * SourceBrowser.cs
+ *
+ *
+ * Written by Aydemir Ulas Sahin (ulas arttek com tr)
+ ****************************************************************************/
+
+/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW:
+ *
+ * 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;
+using System.Collections.Specialized;
+using GLib;
+using Gtk;
+using Mono.Unix;
+
+using Banshee.Base;
+using Banshee.Sources;
+
+namespace Banshee
+{
+ public delegate void BrowserSearchEventHandler(object o, BrowserSearchEventArgs args);
+
+ public class BrowserEventInfo
+ {
+ private string strdata;
+ private int index;
+
+ public BrowserEventInfo(string str_data, int int_index)
+ {
+ this.StrData = str_data;
+ this.IntIndex = int_index;
+ }
+
+
+ public string StrData
+ {
+ get {
+ return this.strdata;
+ }
+ set {
+ this.strdata = value;
+ }
+ }
+
+ public int IntIndex
+ {
+ get {
+ return this.index;
+ }
+ set {
+ this.index = value;
+ }
+ }
+ }
+
+
+ public class BrowserSearchEventArgs : EventArgs
+ {
+ public BrowserEventInfo artist;
+ public BrowserEventInfo album;
+
+ public BrowserSearchEventArgs(BrowserEventInfo beiArtist, BrowserEventInfo beiAlbum)
+ {
+ this.artist = beiArtist;
+ this.album = beiAlbum;
+ }
+ }
+
+ public class SourceBrowser : VBox
+ {
+ private Gtk.HBox main_box = new Gtk.HBox();
+ private Gtk.ScrolledWindow artist_scroller = new Gtk.ScrolledWindow();
+ private Gtk.ScrolledWindow album_scroller = new Gtk.ScrolledWindow();
+ private Gtk.TreeView artist_tree = new Gtk.TreeView();
+ private Gtk.TreeView album_tree = new Gtk.TreeView();
+
+ private ListStore artist_store;
+ private ListStore album_store;
+
+ private string artist_selected = "none";
+ private string album_selected = "none";
+
+ private int artist_selection_index = 0;
+ private int album_selection_index = 0;
+
+ private int [] ResetSelectPath = {0};
+
+ public event BrowserSearchEventHandler BrowserClicked;
+
+ public SourceBrowser() : base()
+ {
+ BuildUI();
+ }
+
+ private void BuildUI()
+ {
+ artist_scroller.HscrollbarPolicy = PolicyType.Automatic;
+ artist_scroller.VscrollbarPolicy = PolicyType.Always;
+ artist_scroller.ShadowType = ShadowType.EtchedIn;
+ artist_scroller.BorderWidth = 3;
+
+ album_scroller.HscrollbarPolicy = PolicyType.Automatic;
+ album_scroller.VscrollbarPolicy = PolicyType.Always;
+ album_scroller.ShadowType = ShadowType.EtchedIn;
+ album_scroller.BorderWidth = 3;
+
+ artist_tree.HeadersVisible = true;
+ artist_tree.AppendColumn(Catalog.GetString("Artist"), new CellRendererText(), "text", 0);
+ artist_store = CreateStore();
+ artist_tree.Model = artist_store;
+ artist_tree.CursorChanged += OnArtistCursorChanged;
+ artist_scroller.Add(artist_tree);
+
+ album_tree.HeadersVisible = true;
+ album_tree.AppendColumn(Catalog.GetString("Album"), new CellRendererText(), "text", 0);
+ album_store = CreateStore();
+ album_tree.Model = album_store;
+ album_tree.CursorChanged += OnAlbumCursorChanged;
+ album_scroller.Add(album_tree);
+
+ main_box.PackStart(artist_scroller, true, true, 0);
+ main_box.PackStart(album_scroller, true, true, 0);
+
+ PackStart(main_box, true, true, 0);
+ Spacing = 5;
+
+ this.ShowAll();
+ }
+
+ public void Reset()
+ {
+ ResetArtistList();
+ ResetAlbumList();
+ PopulateAlbumStore(false);
+ }
+
+ public void Update(bool isFiltered)
+ {
+ PopulateArtistStore(true);
+ PopulateAlbumStore(true);
+ if(isFiltered) {
+ RunSearch();
+ }
+ }
+
+ public bool FilterStatus()
+ {
+ if(artist_selection_index == 0 && album_selection_index == 0) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ private ListStore CreateStore()
+ {
+ ListStore store = new ListStore(typeof(string));
+ return store;
+ }
+
+ private ICollection SortTracks(ICollection collection, TrackInfoComparer.Types type)
+ {
+ ArrayList sortedlist = new ArrayList();
+ sortedlist.AddRange(collection);
+ sortedlist.Sort(new TrackInfoComparer(type));
+ return sortedlist;
+ }
+
+ private void PopulateArtistStore(bool isUpdate)
+ {
+ artist_store.Clear();
+ StringCollection artistlist = new StringCollection();
+
+ try
+ {
+ ICollection collection = SortTracks(SourceManager.ActiveSource.Tracks,
+ TrackInfoComparer.Types.artist);
+ foreach(TrackInfo track in collection) {
+ if (!artistlist.Contains(track.Artist)) {
+ artistlist.Add(track.Artist as string);
+ }
+ }
+ } catch(Exception) {
+
+ }
+
+ AddEntry("All", true, artist_store);
+ foreach(string entry in artistlist) {
+ AddEntry(entry, false, artist_store);
+ }
+
+ if (isUpdate) {
+ UpdateArtistList();
+ } else {
+ ResetArtistList();
+ }
+ }
+
+ private void PopulateAlbumStore(bool isUpdate)
+ {
+ album_store.Clear();
+ StringCollection albumlist = new StringCollection();
+
+ try
+ {
+ ICollection collection = SortTracks(SourceManager.ActiveSource.Tracks,
+ TrackInfoComparer.Types.album);
+ if (artist_selection_index == 0) {
+ foreach(TrackInfo track in collection) {
+ if (!albumlist.Contains(track.Album)) {
+ albumlist.Add(track.Album as string);
+ }
+ }
+ } else {
+ foreach(TrackInfo track in collection) {
+ if (!albumlist.Contains(track.Album)) {
+ if (track.Artist.Equals(artist_selected)) {
+ albumlist.Add(track.Album as string);
+ }
+ }
+ }
+ }
+ } catch(Exception) {
+
+ }
+
+ AddEntry("All", true, album_store);
+ foreach(string entry in albumlist) {
+ AddEntry(entry, false, album_store);
+ }
+
+ if (isUpdate) {
+ UpdateAlbumList();
+ } else {
+ ResetAlbumList();
+ }
+ }
+
+ private void UpdateAlbumList()
+ {
+ int [] UpdateSelectPath = {album_selection_index };
+ album_tree.Selection.SelectPath(new TreePath(UpdateSelectPath));
+ }
+
+ private void UpdateArtistList()
+ {
+ int [] UpdateSelectPath = {artist_selection_index };
+ artist_tree.Selection.SelectPath(new TreePath(UpdateSelectPath));
+ }
+
+ private void ResetAlbumList()
+ {
+ album_tree.Selection.SelectPath(new TreePath(ResetSelectPath));
+ TreePath[] treeIndex = album_tree.Selection.GetSelectedRows();
+ album_selection_index = treeIndex[0].Indices[0];
+ }
+
+ private void ResetArtistList()
+ {
+ artist_tree.Selection.SelectPath(new TreePath(ResetSelectPath));
+ TreePath[] treeIndex = artist_tree.Selection.GetSelectedRows();
+ artist_selection_index = treeIndex[0].Indices[0];
+ }
+
+ private void AddEntry(string entry, bool prepend,ListStore store)
+ {
+ TreeIter iter = prepend ? store.Insert(0) : store.Append();
+ store.SetValue(iter, 0, entry);
+ }
+
+ private void OnArtistCursorChanged(object o, EventArgs args)
+ {
+ TreeIter iter;
+ if(!artist_tree.Selection.GetSelected(out iter)) {
+ return;
+ }
+
+ object artist_name = artist_store.GetValue(iter, 0);
+ artist_selected = (artist_name as string);
+
+ TreePath[] treeIndex = artist_tree.Selection.GetSelectedRows();
+ artist_selection_index = treeIndex[0].Indices[0];
+
+ if(artist_name == null) {
+ return;
+ }
+
+ PopulateAlbumStore(false);
+ RunSearch();
+ }
+
+ private void OnAlbumCursorChanged(object o, EventArgs args)
+ {
+ TreeIter iter;
+ if(!album_tree.Selection.GetSelected(out iter)) {
+ return;
+ }
+
+ object album_name = album_store.GetValue(iter, 0);
+ album_selected = (album_name as string);
+
+ TreePath[] treeIndex = album_tree.Selection.GetSelectedRows();
+ album_selection_index = treeIndex[0].Indices[0];
+
+ if(album_name == null) {
+ return;
+ }
+
+ RunSearch();
+ }
+
+ private void RunSearch()
+ {
+ BrowserSearchEventHandler handler = BrowserClicked;
+ BrowserEventInfo bei_artist = new BrowserEventInfo(artist_selected, artist_selection_index);
+ BrowserEventInfo bei_album = new BrowserEventInfo(album_selected, album_selection_index);
+ BrowserSearchEventArgs browserArgs = new BrowserSearchEventArgs(bei_artist, bei_album);
+ if(handler != null)
+ {
+ handler(this, browserArgs);
+ }
+ }
+ }
+
+ public class TrackInfoComparer : IComparer
+ {
+ public enum Types : int { artist = 0, album = 1 };
+
+ private int type = (int) TrackInfoComparer.Types.artist;
+
+ public TrackInfoComparer() {}
+
+ public TrackInfoComparer(Types type) { this.type = (int) type; }
+
+ public int Compare(object x, object y)
+ {
+ try {
+ string xstring;
+ string ystring;
+
+ if(this.type == 0) {
+ xstring = ((TrackInfo)x).Artist;
+ ystring = ((TrackInfo)y).Artist;
+ } else {
+ xstring = ((TrackInfo)x).Album;
+ ystring = ((TrackInfo)y).Album;
+ }
+ return xstring.CompareTo(ystring);
+ } catch (Exception){
+ return 0;
+ }
+ }
+ }
+
+ public class BrowserBox : VBox
+ {
+ private SourceBrowser browser;
+
+ public event BrowserSearchEventHandler BrowserSearchActivated;
+
+ public BrowserBox() : base()
+ {
+ BuildUI();
+ }
+
+ private void BuildUI()
+ {
+ browser = new SourceBrowser();
+ browser.HeightRequest = 150;
+ browser.BrowserClicked += OnBrowserClicked;
+
+ PackStart(browser,true,true,0);
+
+ ShowAll();
+ }
+
+ private void OnBrowserClicked(object o, BrowserSearchEventArgs args)
+ {
+ BrowserSearchEventHandler handler = BrowserSearchActivated;
+ if(handler != null)
+ handler(this, args);
+ }
+
+ public void BrowserReset()
+ {
+ browser.Update(false);
+ browser.Reset();
+ }
+
+ public void BrowserUpdate()
+ {
+ browser.Update(false);
+ }
+
+ public void BrowserFilter()
+ {
+ browser.Update(true);
+ }
+
+ public bool BrowserHasFilter()
+ {
+ return browser.FilterStatus();
+ }
+
+ public void Active(bool status)
+ {
+ this.Sensitive = status;
+ }
+ }
+}