Good evening Banshee lovers.
attached is the patch for browser appliable against 0_10_2.
with all its good and evil...
do not hesitate to report problems. (i wont break your legs if it is a false alarm ;) )
Have Fun!
Ulaas.
P.S.
Index: src/PlayerInterface.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/PlayerInterface.cs,v
retrieving revision 1.123
diff -u -r1.123 PlayerInterface.cs
--- src/PlayerInterface.cs 22 Dec 2005 03:06:16 -0000 1.123
+++ src/PlayerInterface.cs 25 Dec 2005 00:58:29 -0000
@@ -58,6 +58,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;
@@ -76,6 +78,7 @@
private Tooltips toolTips;
private Hashtable playlistMenuMap;
private Viewport sourceViewLoadingVP;
+ private BrowserParent browser;
private MultiStateToggleButton repeat_toggle_button;
private MultiStateToggleButton shuffle_toggle_button;
@@ -458,6 +461,14 @@
gxml["SearchLabel"].Sensitive = false;
searchEntry.Sensitive = false;
+
+ // Custom Expander and browser related stuff.
+ CustomExpander = ((Expander)gxml["CustomExpander"]);
+ DisclosureBox = ((VBox)gxml["DisclosureBox"]);
+ CustomExpander.Activated += OnExpandAreaClicked;
+ browser = new BrowserParent();
+ browser.BrowserSearchActivated += OnBrowserSearchActivated;
+ DisclosureBox.Add(browser);
// Repeat/Shuffle buttons
@@ -675,6 +686,11 @@
searchEntry.Sensitive = true;
}
+ private void OnBrowserSearchActivated(object o, BrowserSearchEventArgs args)
+ {
+ playlistModel.LoadFromBrowserSearch(args.artist, args.album);
+ }
+
private void OnLibraryTransactionStatusStopped(object o, EventArgs args)
{
headerNotebook.RemovePage(libraryTransactionStatus);
@@ -873,6 +889,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;
}
args.RetVal = handled;
@@ -1245,26 +1272,36 @@
audiocd_statusbar.Visible = false;
if(source is LibrarySource) {
- playlistModel.LoadFromLibrary();
+ if(!browser.BrowserHasFilter()) {
+ playlistModel.LoadFromLibrary();
+ }
playlistModel.Source = source;
+ browser.Active(true);
+ Application.Invoke(delegate {
+ browser.BrowserFilter();
+ });
} else if(source is LocalQueueSource) {
playlistModel.LoadFromLocalQueue();
playlistModel.Source = source;
+ browser.Active(false);
} else if(source is DapSource) {
playlistModel.Clear();
playlistModel.Source = source;
DapSource dap_source = source as DapSource;
playlistModel.LoadFromDapSource(dap_source);
UpdateDapDiskUsageBar(dap_source);
+ browser.Active(false);
} else if(source is AudioCdSource) {
playlistModel.Clear();
playlistModel.Source = source;
AudioCdSource cdSource = source as AudioCdSource;
playlistModel.LoadFromAudioCdSource(cdSource);
UpdateAudioCdStatus(cdSource.Disk);
+ browser.Active(false);
} else {
playlistModel.LoadFromPlaylist(source.Name);
playlistModel.Source = source;
+ browser.Active(false);
}
(gxml["ViewNameLabel"] as Label).Markup = "<b>" + GLib.Markup.EscapeText(source.Name) + "</b>";
@@ -1608,6 +1645,7 @@
{
Source source = sourceView.SelectedSource;
playlistModel.Clear();
+ browser.BrowserReset();
if(!searchEntry.IsQueryAvailable) {
if(source.Type == SourceType.Dap) {
@@ -2064,6 +2102,7 @@
}
playlistModel.AddTrack(ti);
+ browser.BrowserUpdate();
});
}
} catch(Entagged.Audioformats.Exceptions.CannotReadException) {
@@ -2183,6 +2222,9 @@
{
playlistView.QueueDraw();
sourceView.QueueDraw();
+ Application.Invoke(delegate {
+ browser.BrowserUpdate();
+ });
}
[GLib.ConnectBefore]
@@ -2506,6 +2548,20 @@
ToggleAction action = o as ToggleAction;
playlistModel.Shuffle = action.Active;
Globals.Configuration.Set(GConfKeys.PlaylistShuffle, action.Active);
+ }
+
+ // --- Expander ---
+
+ private void OnExpandAreaClicked (object sender, EventArgs args)
+ {
+ if (CustomExpander.Expanded)
+ {
+ DisclosureBox.Visible = true;
+ }
+ else
+ {
+ DisclosureBox.Visible = false;
+ }
}
// --- View Menu ---
Index: src/PlaylistModel.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/PlaylistModel.cs,v
retrieving revision 1.28
diff -u -r1.28 PlaylistModel.cs
--- src/PlaylistModel.cs 22 Dec 2005 02:25:53 -0000 1.28
+++ src/PlaylistModel.cs 25 Dec 2005 00:58:30 -0000
@@ -174,6 +174,51 @@
RaiseUpdated(this, new EventArgs());
}
+ public void LoadFromBrowserSearch(BrowserEventInfo beiArtist, BrowserEventInfo beiAlbum)
+ {
+ ClearModel();
+ ICollection collection = null;
+ collection = Core.Library.Tracks.Values;
+
+ foreach(TrackInfo ti in collection) {
+ try {
+ if(DoesTrackMatchSearch(ti, beiArtist, beiAlbum)) {
+ AddTrack(ti);
+ }
+ } catch(Exception) {
+ continue;
+ }
+ }
+ }
+
+ 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;
+ }
+
public void LoadFromDapSource(DapSource dapSource)
{
ClearModel();
Index: src/Makefile.am
===================================================================
RCS file: /cvs/gnome/banshee/src/Makefile.am,v
retrieving revision 1.81
diff -u -r1.81 Makefile.am
--- src/Makefile.am 22 Dec 2005 05:29:50 -0000 1.81
+++ src/Makefile.am 25 Dec 2005 00:58:32 -0000
@@ -73,6 +73,8 @@
FileSystemMonitor/FileSystemWatcherWatch.cs \
ToggleStates.cs \
DapPropertiesDialog.cs \
+ ArtistAlbumBrowser.cs \
+ BrowserParent.cs \
FileTrackInfo.cs
banshee_resources = \
Index: data/banshee.glade
===================================================================
RCS file: /cvs/gnome/banshee/data/banshee.glade,v
retrieving revision 1.3
diff -u -r1.3 banshee.glade
--- data/banshee.glade 19 Dec 2005 22:12:03 -0000 1.3
+++ data/banshee.glade 25 Dec 2005 00:58:48 -0000
@@ -275,22 +275,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>
@@ -399,30 +415,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/ArtistAlbumBrowser.cs 2005-12-25 03:13:11.000000000 +0200
+++ src/ArtistAlbumBrowser.cs 2005-12-25 02:34:44.000000000 +0200
@@ -0,0 +1,340 @@
+// created on 11/19/2005 at 1:26 AM by Aydemir Ulas Sahin
+
+using System;
+using System.Data;
+using System.IO;
+using System.Collections;
+using GLib;
+using Gtk;
+using Mono.Unix;
+using Sql;
+
+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 ArtistAlbumBrowser : 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 Statement query;
+
+ private int [] ResetSelectPath = {0};
+
+ public event BrowserSearchEventHandler BrowserClicked;
+
+ public ArtistAlbumBrowser() : base()
+ {
+ BuildUI();
+ Init();
+ }
+
+ 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;
+
+ }
+
+ private void Init()
+ {
+ query = new Select("Tracks", new Statement("DISTINCT Artist")) + new OrderBy("Artist", OrderDirection.Asc);
+ PopulateArtistStore(false);
+ PopulateAlbumStore(false);
+
+ artist_tree.Selection.SelectPath(new TreePath(ResetSelectPath));
+ album_tree.Selection.SelectPath(new TreePath(ResetSelectPath));
+
+ this.ShowAll();
+ }
+
+ public void Reset()
+ {
+ query = new Select("Tracks", new Statement("DISTINCT Artist")) + new OrderBy("Artist", OrderDirection.Asc) ;
+ artist_tree.Selection.SelectPath(new TreePath(ResetSelectPath));
+ artist_tree.ScrollToPoint(0,0);
+ album_tree.Selection.SelectPath(new TreePath(ResetSelectPath));
+ album_tree.ScrollToPoint(0,0);
+ }
+
+ public void Update(bool isFiltered)
+ {
+ query = new Select("Tracks", new Statement("DISTINCT Artist")) + new OrderBy("Artist", OrderDirection.Asc);
+ 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));
+
+ //We dont need a sort for this view but in case anyone asks...
+ /*
+ store.SetSortFunc(1, delegate(TreeModel model, TreeIter a, TreeIter b) {
+ try {
+ String a_string = (String)store.GetValue(a, 1);
+ String b_string = (String)store.GetValue(b, 1);
+ return String.Compare(a_string, b_string);
+ } catch(Exception) {
+ return 0;
+ }
+ });
+ store.SetSortColumnId(1, SortType.Descending);
+ */
+ return store;
+ }
+
+ private void PopulateArtistStore(bool isUpdate)
+ {
+ artist_store.Clear();
+ ArrayList artistlist = new ArrayList();
+ try
+ {
+ IDataReader reader = Core.Library.Db.Query(query);
+ while(reader.Read())
+ {
+ artistlist.Add((reader[0] 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();
+ ArrayList albumlist = new ArrayList();
+ if (artist_selection_index == 0)
+ {
+ query = new Select("Tracks", new Statement("DISTINCT AlbumTitle"))
+ + new OrderBy("AlbumTitle", OrderDirection.Asc);
+ }
+ else
+ {
+ query = new Select("Tracks", new Statement("DISTINCT AlbumTitle"))
+ + new Where(new Compare("Artist", Op.EqualTo, artist_selected))
+ + new OrderBy("AlbumTitle", OrderDirection.Asc);
+ }
+
+ try
+ {
+ IDataReader reader = Core.Library.Db.Query(query);
+ while(reader.Read())
+ {
+ albumlist.Add((reader[0] 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);
+ }
+ }
+
+ }
+}
--- src/BrowserParent.cs 2005-12-25 03:13:13.000000000 +0200
+++ src/BrowserParent.cs 2005-12-25 02:34:44.000000000 +0200
@@ -0,0 +1,66 @@
+// created on 11/19/2005 at 1:26 AM by Aydemir Ulas Sahin
+
+using System;
+using GLib;
+using Gtk;
+using Mono.Unix;
+using Sql;
+
+namespace Banshee
+{
+ public class BrowserParent : VBox
+ {
+ private ArtistAlbumBrowser browser;
+
+ public event BrowserSearchEventHandler BrowserSearchActivated;
+
+ public BrowserParent() : base()
+ {
+ BuildUI();
+ }
+
+ private void BuildUI()
+ {
+ browser = new ArtistAlbumBrowser();
+ browser.HeightRequest = 150;
+ browser.BrowserClicked += OnBrowserClicked;
+
+ PackStart(browser,true,true,0);
+
+ ShowAll();
+ }
+
+ private void OnBrowserClicked(object o, BrowserSearchEventArgs args)
+ {
+ BrowserSearchEventHandler handler = BrowserSearchActivated;
+ //BrowserSearchEventArgs browser_args = new BrowserSearchEventArgs();
+ if(handler != null)
+ handler(this, args);
+ }
+
+ public void BrowserReset()
+ {
+ 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;
+ }
+ }
+}