[banshee] [Audiobook] Add BookView



commit 9bfe9fcb9c28a16b190ebe5bea3d9e2a6a5396d9
Author: Gabriel Burt <gabriel burt gmail com>
Date:   Fri May 14 14:20:26 2010 -0700

    [Audiobook] Add BookView

 .../Banshee.Audiobook/Banshee.Audiobook.csproj     |   11 +-
 .../Banshee.Audiobook/Banshee.Audiobook/Actions.cs |    2 +
 .../Banshee.Audiobook/AudiobookLibrarySource.cs    |   18 +-
 .../Banshee.Audiobook/BookCover.cs                 |   60 +++
 .../Banshee.Audiobook/BookView.cs                  |  415 ++++++++++++++++++++
 src/Extensions/Banshee.Audiobook/Makefile.am       |    4 +-
 6 files changed, 506 insertions(+), 4 deletions(-)
---
diff --git a/src/Extensions/Banshee.Audiobook/Banshee.Audiobook.csproj b/src/Extensions/Banshee.Audiobook/Banshee.Audiobook.csproj
index 00add42..70164ed 100644
--- a/src/Extensions/Banshee.Audiobook/Banshee.Audiobook.csproj
+++ b/src/Extensions/Banshee.Audiobook/Banshee.Audiobook.csproj
@@ -65,15 +65,24 @@
     <Reference Include="taglib-sharp, Version=2.0.3.6, Culture=neutral, PublicKeyToken=db62eba44689b5b0">
       <HintPath>..\..\..\bin\taglib-sharp.dll</HintPath>
     </Reference>
+    <Reference Include="Mono.Cairo" />
   </ItemGroup>
   <ItemGroup>
     <EmbeddedResource Include="Banshee.Audiobook.addin.xml">
       <LogicalName>Banshee.Audiobook.addin.xml</LogicalName>
     </EmbeddedResource>
+    <EmbeddedResource Include="Resources\ActiveSourceUI.xml" />
+    <EmbeddedResource Include="Resources\GlobalUI.xml" />
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="Banshee.Audiobook\AudiobookLibrarySource.cs" />
+    <Compile Include="Banshee.Audiobook\Actions.cs" />
+    <Compile Include="Banshee.Audiobook\AudiobookContent.cs" />
     <Compile Include="Banshee.Audiobook\AudiobookFileNamePattern.cs" />
+    <Compile Include="Banshee.Audiobook\AudiobookGrid.cs" />
+    <Compile Include="Banshee.Audiobook\AudiobookLibrarySource.cs" />
+    <Compile Include="Banshee.Audiobook\AudiobookModel.cs" />
+    <Compile Include="Banshee.Audiobook\BookView.cs" />
+    <Compile Include="Banshee.Audiobook\BookCover.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ProjectExtensions>
diff --git a/src/Extensions/Banshee.Audiobook/Banshee.Audiobook/Actions.cs b/src/Extensions/Banshee.Audiobook/Banshee.Audiobook/Actions.cs
index 8d6e0ce..98bbbb8 100644
--- a/src/Extensions/Banshee.Audiobook/Banshee.Audiobook/Actions.cs
+++ b/src/Extensions/Banshee.Audiobook/Banshee.Audiobook/Actions.cs
@@ -92,6 +92,8 @@ namespace Banshee.Audiobook
             if (index > -1) {
                 var book = library.BooksModel[index];
                 Console.WriteLine ("Asked to open {0}", book);
+
+                library.SwitchToBookView (book as DatabaseAlbumInfo);
             }
         }
 
diff --git a/src/Extensions/Banshee.Audiobook/Banshee.Audiobook/AudiobookLibrarySource.cs b/src/Extensions/Banshee.Audiobook/Banshee.Audiobook/AudiobookLibrarySource.cs
index ec42371..02968c2 100644
--- a/src/Extensions/Banshee.Audiobook/Banshee.Audiobook/AudiobookLibrarySource.cs
+++ b/src/Extensions/Banshee.Audiobook/Banshee.Audiobook/AudiobookLibrarySource.cs
@@ -47,7 +47,9 @@ namespace Banshee.Audiobook
 {
     public class AudiobookLibrarySource : LibrarySource
     {
-        private AudiobookModel books_model;
+        AudiobookModel books_model;
+        LazyLoadSourceContents<AudiobookContent> grid_view;
+        LazyLoadSourceContents<BookView> book_view;
 
         public Actions Actions { get; private set; }
 
@@ -81,10 +83,15 @@ namespace Banshee.Audiobook
             pattern.FileSchema   = CreateSchema<string> ("file_pattern",   pattern.DefaultFile, "", "");
             SetFileNamePattern (pattern);
 
-            Properties.Set<ISourceContents> ("Nereid.SourceContents", new LazyLoadSourceContents<AudiobookContent> ());
+            grid_view = new LazyLoadSourceContents<AudiobookContent> ();
+            Properties.Set<ISourceContents> ("Nereid.SourceContents", grid_view);
+
+            book_view = new LazyLoadSourceContents<BookView> ();
+
             //Properties.SetString ("GtkActionPath", "/LastfmStationSourcePopup");
             Properties.SetString ("ActiveSourceUIResource", "ActiveSourceUI.xml");
             Properties.Set<bool> ("ActiveSourceUIResourcePropagate", true);
+            Properties.Set<System.Action> ("ActivationAction", delegate { Properties.Set<ISourceContents> ("Nereid.SourceContents", grid_view); });
 
             Actions = new Actions (this);
 
@@ -96,6 +103,13 @@ namespace Banshee.Audiobook
             TrackModel.Reloaded += delegate { Console.WriteLine ("Audiobooks track model reloaded"); };
         }
 
+        public void SwitchToBookView (DatabaseAlbumInfo book)
+        {
+            Properties.Set<ISourceContents> ("Nereid.SourceContents", book_view);
+            book_view.SetSource (null);
+            book_view.Contents.SetBook (book);
+        }
+
         private void MergeBooksAddedSince (DateTime since)
         {
             // TODO after import of files or move to audiobook:
diff --git a/src/Extensions/Banshee.Audiobook/Banshee.Audiobook/BookCover.cs b/src/Extensions/Banshee.Audiobook/Banshee.Audiobook/BookCover.cs
new file mode 100644
index 0000000..20f5007
--- /dev/null
+++ b/src/Extensions/Banshee.Audiobook/Banshee.Audiobook/BookCover.cs
@@ -0,0 +1,60 @@
+// 
+// BookCover.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 Gtk;
+
+using Banshee.Gui.Widgets;
+using Banshee.Collection;
+using Hyena.Gui.Theming;
+
+namespace Banshee.Audiobook
+{
+    public class BookCover : CoverArtDisplay
+    {
+        Widget parent;
+
+        public BookCover (Widget parent)
+        {
+            this.parent = parent;
+            MissingVideoIconName = MissingAudioIconName = "audiobook";
+        }
+
+        protected override void OnThemeChanged ()
+        {
+            base.OnThemeChanged ();
+
+            var theme = Hyena.Gui.Theming.ThemeEngine.CreateTheme (parent);
+            BackgroundColor = theme.Colors.GetWidgetColor (GtkColorClass.Base, StateType.Normal);
+        }
+
+        public void LoadImage (TrackMediaAttributes attr, string artwork_id)
+        {
+             LoadImage (attr, artwork_id, true);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Extensions/Banshee.Audiobook/Banshee.Audiobook/BookView.cs b/src/Extensions/Banshee.Audiobook/Banshee.Audiobook/BookView.cs
new file mode 100644
index 0000000..2cc1b52
--- /dev/null
+++ b/src/Extensions/Banshee.Audiobook/Banshee.Audiobook/BookView.cs
@@ -0,0 +1,415 @@
+//
+// BookView.cs
+//
+// Authors:
+//   Gabriel Burt <gburt novell 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.Collections.Generic;
+using System.Linq;
+
+using Mono.Unix;
+using Gtk;
+
+using Hyena;
+using Hyena.Collections;
+using Hyena.Data.Sqlite;
+
+using Hyena.Data;
+using Hyena.Data.Gui;
+using Hyena.Widgets;
+
+using Banshee.Base;
+using Banshee.Collection;
+using Banshee.Collection.Gui;
+using Banshee.Collection.Database;
+using Banshee.Configuration;
+using Banshee.Database;
+using Banshee.Gui;
+using Banshee.Gui.Widgets;
+using Banshee.Library;
+using Banshee.MediaEngine;
+using Banshee.PlaybackController;
+using Banshee.Playlist;
+using Banshee.Preferences;
+using Banshee.ServiceStack;
+using Banshee.Sources;
+using Hyena.Gui.Theming;
+
+namespace Banshee.Audiobook
+{
+    public class BookView : Hyena.Widgets.RoundedFrame, Banshee.Sources.Gui.ISourceContents, IDisposable
+    {
+        AudiobookLibrarySource library;
+
+        Alignment align;
+        Label title;
+        BookCover cover;
+        BaseTrackListView track_list;
+
+        public BookView ()
+        {
+            BuildInfoBox ();
+            //BuildFilesBox ();
+
+            ShowAll ();
+        }
+
+        public void SetBook (DatabaseAlbumInfo book)
+        {
+            ThreadAssist.AssertInMainThread ();
+
+            title.Markup = String.Format (
+                "<span size=\"x-large\" weight=\"bold\">{0}</span>\n" +
+                "{1}",
+                GLib.Markup.EscapeText (book.Title),
+                GLib.Markup.EscapeText (book.ArtistName)
+            );
+
+            cover.LoadImage (
+                TrackMediaAttributes.AudioStream | TrackMediaAttributes.AudioBook,
+                CoverArtSpec.CreateArtistAlbumId (book.ArtistName, book.Title)
+            );
+        }
+
+        public override void Dispose ()
+        {
+            if (cover != null) {
+                cover.Dispose ();
+                cover = null;
+            }
+
+            base.Dispose ();
+        }
+
+#region ISourceContents
+
+        public bool SetSource (ISource source)
+        {
+            library = source as AudiobookLibrarySource;
+
+            if (library != null) {
+                track_list.SetModel (library.TrackModel);
+            }
+
+            return library != null;
+        }
+
+        public void ResetSource ()
+        {
+        }
+
+        public ISource Source { get { return library; } }
+
+        public Widget Widget { get { return this; } }
+
+#endregion
+
+        private void BuildInfoBox ()
+        {
+            align = new Alignment (0.5f, 0.0f, 0.0f, 0.0f) { BorderWidth = 6 };
+            align.TopPadding = 6;
+
+            var hbox = new HBox () { Spacing = 12 };
+
+            // Left box - cover art, title, etc
+            var left_box = new VBox () { Spacing = 12 };
+
+            // Cover art
+            cover = new BookCover (this) {
+                WidthRequest = 300,
+                HeightRequest = 300
+            };
+            var editable_cover = TrackInfoDisplay.GetEditable (cover);
+
+            // Title
+            title = new Label () {
+                Xalign = 0,
+                Yalign = 0
+            };
+
+            // Packing
+            left_box.PackStart (editable_cover, false, false,  0);
+            left_box.PackStart (title, true, true,  0);
+
+            hbox.PackStart (left_box, false, false, 0);
+
+            // Right box - bookmarks, track list
+            var right_box = new VBox () { Spacing = 12 };
+
+            var notebook = new Notebook () { WidthRequest = 450, HeightRequest = 600 };
+            notebook.ShowBorder = false;
+            notebook.AppendPage (new Label ("...my bookmarks..."), new Label ("Bookmarks"));
+
+            // Tracks
+
+            track_list = new BaseTrackListView () {
+                HeaderVisible = true,
+                IsEverReorderable = false
+            };
+
+            var columns = new DefaultColumnController ();
+            var file_columns = new ColumnController ();
+            file_columns.AddRange (
+                columns.IndicatorColumn,
+                columns.DiscNumberAndCountColumn,
+                columns.TitleColumn,
+                columns.DurationColumn
+            );
+            file_columns.SortColumn = columns.DiscNumberAndCountColumn;
+
+            var track_sw = new Gtk.ScrolledWindow ();
+            track_sw.Child = track_list;
+
+            foreach (var col in file_columns) {
+                col.Visible = true;
+            }
+
+            track_list.ColumnController = file_columns;
+
+            notebook.AppendPage (track_sw, new Label ("Tracks"));
+
+
+            right_box.PackStart (notebook, false, false, 0);
+
+            hbox.PackStart (right_box, false, false, 0);
+
+            //var vbox2 = new VBox ();
+            //vbox2.PackStart (vbox, false, false, 0);
+
+            //var sw = new Gtk.ScrolledWindow () { ShadowType = ShadowType.None };
+            //sw.AddWithViewport (vbox2);
+            //(sw.Child as Viewport).ShadowType = ShadowType.None;
+            //frame.Child = sw;
+            //frame.Child = vbox;
+            //frame.ShowAll ();
+
+            /*sw.Child.ModifyBg (StateType.Normal, Style.Base (StateType.Normal));
+            sw.Child.ModifyFg (StateType.Normal, Style.Text (StateType.Normal));
+            sw.Child.ModifyText (StateType.Normal, Style.Text (StateType.Normal));
+            StyleSet += delegate {
+                sw.Child.ModifyBg (StateType.Normal, Style.Base (StateType.Normal));
+                sw.Child.ModifyFg (StateType.Normal, Style.Text (StateType.Normal));
+                sw.Child.ModifyText (StateType.Normal, Style.Text (StateType.Normal));
+            };*/
+
+            //Add (frame);
+            align.Child = hbox;
+            Child = align;
+            ShowAll ();
+        }
+
+        /*private void BuildFilesBox ()
+        {
+            var vbox = new VBox ();
+            vbox.Spacing = 6;
+
+            var file_list = new BaseTrackListView () {
+                HeaderVisible = true,
+                IsEverReorderable = false
+            };
+
+            var files_model = source.TrackModel as MemoryTrackListModel;
+            var columns = new DefaultColumnController ();
+            columns.TrackColumn.Title = "#";
+            var file_columns = new ColumnController ();
+            file_columns.AddRange (
+                columns.IndicatorColumn,
+                columns.TrackColumn,
+                columns.TitleColumn,
+                columns.DurationColumn,
+                columns.FileSizeColumn
+            );
+
+            foreach (var col in file_columns) {
+                col.Visible = true;
+            }
+
+            var file_sw = new Gtk.ScrolledWindow ();
+            file_sw.Child = file_list;
+
+            var tracks = new List<TrackInfo> ();
+
+            var files = new List<IA.DetailsFile> (details.Files);
+
+            string [] format_blacklist = new string [] { "metadata", "fingerprint", "checksums", "xml", "m3u", "dublin core", "unknown" };
+            var formats = new List<string> ();
+            foreach (var f in files) {
+                var track = new TrackInfo () {
+                    Uri         = new SafeUri (f.Location),
+                    FileSize    = f.Size,
+                    TrackNumber = f.Track,
+                    ArtistName  = f.Creator ?? details.Creator,
+                    AlbumTitle  = item.Title,
+                    TrackTitle  = f.Title,
+                    BitRate     = f.BitRate,
+                    MimeType    = f.Format,
+                    Duration    = f.Length
+                };
+
+                // Fix up duration/track#/title
+                if ((f.Length == TimeSpan.Zero || f.Title == null || f.Track == 0) && !f.Location.Contains ("zip") && !f.Location.EndsWith ("m3u")) {
+                    foreach (var b in files) {
+                        if ((f.Title != null && f.Title == b.Title)
+                                || (f.OriginalFile != null && b.Location != null && b.Location.EndsWith (f.OriginalFile))
+                                || (f.OriginalFile != null && f.OriginalFile == b.OriginalFile)) {
+                            if (track.Duration == TimeSpan.Zero)
+                                track.Duration = b.Length;
+
+                            if (track.TrackTitle == null)
+                                track.TrackTitle = b.Title;
+
+                            if (track.TrackNumber == 0)
+                                track.TrackNumber = b.Track;
+
+                            if (track.Duration != TimeSpan.Zero && track.TrackTitle != null && track.TrackNumber != 0)
+                                break;
+                        }
+                    }
+                }
+
+                track.TrackTitle = track.TrackTitle ?? System.IO.Path.GetFileName (f.Location);
+
+                tracks.Add (track);
+
+                if (f.Format != null && !formats.Contains (f.Format)) {
+                    if (!format_blacklist.Any (fmt => f.Format.ToLower ().Contains (fmt))) {
+                        formats.Add (f.Format);
+                    }
+                }
+            }
+
+            // Order the formats according to the preferences
+            string format_order = String.Format (", {0}, {1}, {2},", HomeSource.VideoTypes.Get (), HomeSource.AudioTypes.Get (), HomeSource.TextTypes.Get ()).ToLower ();
+
+            var sorted_formats = formats.Select (f => new { Format = f, Order = Math.Max (format_order.IndexOf (", " + f.ToLower () + ","), format_order.IndexOf (f.ToLower ())) })
+                                        .OrderBy (o => o.Order == -1 ? Int32.MaxValue : o.Order);
+
+            // See if all the files contain their track #
+            bool all_tracks_have_num_in_title = tracks.All (t => t.TrackNumber == 0 || t.TrackTitle.Contains (t.TrackNumber.ToString ()));
+
+            // Make these columns snugly fix their data
+            if (tracks.Count > 0) {
+                // Mono in openSUSE 11.0 doesn't like this
+                //SetWidth (columns.TrackColumn,    all_tracks_have_num_in_title ? 0 : tracks.Max (f => f.TrackNumber), 0);
+                int max_track = 0;
+                long max_size = 0;
+                foreach (var t in tracks) {
+                    max_track = Math.Max (max_track, t.TrackNumber);
+                    max_size = Math.Max (max_size, t.FileSize);
+                }
+                SetWidth (columns.TrackColumn,    all_tracks_have_num_in_title ? 0 : max_track, 0);
+
+                // Mono in openSUSE 11.0 doesn't like this
+                //SetWidth (columns.FileSizeColumn, tracks.Max (f => f.FileSize), 0);
+                SetWidth (columns.FileSizeColumn, max_size, 0);
+                SetWidth (columns.DurationColumn, tracks.Max (f => f.Duration), TimeSpan.Zero);
+            }
+
+            string max_title = "     ";
+            if (tracks.Count > 0) {
+                var sorted_by_title = files.Where (t => !t.Location.Contains ("zip"))
+                                           .OrderBy (f => f.Title == null ? 0 : f.Title.Length)
+                                           .ToList ();
+                string nine_tenths = sorted_by_title[(int)Math.Floor (.90 * sorted_by_title.Count)].Title ?? "";
+                string max = sorted_by_title[sorted_by_title.Count - 1].Title ?? "";
+                max_title = ((double)max.Length >= (double)(1.6 * (double)nine_tenths.Length)) ? nine_tenths : max;
+            }
+            (columns.TitleColumn.GetCell (0) as ColumnCellText).SetMinMaxStrings (max_title);
+
+            file_list.ColumnController = file_columns;
+            file_list.SetModel (files_model);
+
+            var format_list = ComboBox.NewText ();
+            format_list.RowSeparatorFunc = (model, iter) => {
+                return (string)model.GetValue (iter, 0) == "---";
+            };
+
+            bool have_sep = false;
+            int active_format = 0;
+            foreach (var fmt in sorted_formats) {
+                if (fmt.Order == -1 && !have_sep) {
+                    have_sep = true;
+                    if (format_list.Model.IterNChildren () > 0) {
+                        format_list.AppendText ("---");
+                    }
+                }
+
+                format_list.AppendText (fmt.Format);
+
+                if (active_format == 0 && fmt.Format == item.SelectedFormat) {
+                    active_format = format_list.Model.IterNChildren () - 1;
+                }
+            }
+
+            format_list.Changed += (o, a) => {
+                files_model.Clear ();
+
+                var selected_fmt = format_list.ActiveText;
+                foreach (var track in tracks) {
+                    if (track.MimeType == selected_fmt) {
+                        files_model.Add (track);
+                    }
+                }
+
+                files_model.Reload ();
+
+                item.SelectedFormat = selected_fmt;
+                item.Save ();
+            };
+
+            if (formats.Count > 0) {
+                format_list.Active = active_format;
+            }
+
+            vbox.PackStart (file_sw, true, true, 0);
+            vbox.PackStart (format_list, false, false, 0);
+
+            file_list.SizeAllocated += (o, a) => {
+                int target_list_width = file_list.MaxWidth;
+                if (file_sw.VScrollbar != null && file_sw.VScrollbar.IsMapped) {
+                    target_list_width += file_sw.VScrollbar.Allocation.Width + 2;
+                }
+
+                // Don't let the track list be too wide
+                target_list_width = Math.Min (target_list_width, (int) (0.5 * (double)Allocation.Width));
+
+                if (a.Allocation.Width != target_list_width && target_list_width > 0) {
+                    file_sw.SetSizeRequest (target_list_width, -1);
+                }
+            };
+
+            PackStart (vbox, false, false, 0);
+        }*/
+
+        /*private void SetWidth<T> (Column col, T max, T zero)
+        {
+            (col.GetCell (0) as ColumnCellText).SetMinMaxStrings (max, max);
+            if (zero.Equals (max)) {
+                col.Visible = false;
+            }
+        }*/
+    }
+}
diff --git a/src/Extensions/Banshee.Audiobook/Makefile.am b/src/Extensions/Banshee.Audiobook/Makefile.am
index 3013bc9..b8ec015 100644
--- a/src/Extensions/Banshee.Audiobook/Makefile.am
+++ b/src/Extensions/Banshee.Audiobook/Makefile.am
@@ -9,7 +9,9 @@ SOURCES =  \
 	Banshee.Audiobook/AudiobookFileNamePattern.cs \
 	Banshee.Audiobook/AudiobookGrid.cs \
 	Banshee.Audiobook/AudiobookLibrarySource.cs \
-	Banshee.Audiobook/AudiobookModel.cs
+	Banshee.Audiobook/AudiobookModel.cs \
+	Banshee.Audiobook/BookCover.cs \
+	Banshee.Audiobook/BookView.cs
 
 RESOURCES =  \
 	Banshee.Audiobook.addin.xml \



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