~ubuntu-branches/ubuntu/wily/banshee-community-extensions/wily

« back to all changes in this revision

Viewing changes to .pc/0001-LiveRadio-prevent-crash-when-updating-GUI-by-using-H.patch/src/LiveRadio/Banshee.LiveRadio/LiveRadioPluginSourceContents.cs

  • Committer: Package Import Robot
  • Author(s): Andreas Moog
  • Date: 2012-02-11 19:30:25 UTC
  • mfrom: (4.2.10 sid)
  • Revision ID: package-import@ubuntu.com-20120211193025-parsyvdy4lblt2dv
Tags: 2.2.0-3ubuntu1
* Merge from debian/unstable to drop clutterflow extension, 
  remaining change:
  - Enable Appindicator extension

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
//
 
3
// LiveRadioPluginSourceContents.cs
 
4
//
 
5
// Author:
 
6
//   Frank Ziegler <funtastix@googlemail.com>
 
7
//   Aaron Bockover <abockover@novell.com>
 
8
//
 
9
// Copyright (C) 2008 Novell, Inc.
 
10
// Copyright (C) 2010 Frank Ziegler
 
11
//
 
12
// Permission is hereby granted, free of charge, to any person obtaining
 
13
// a copy of this software and associated documentation files (the
 
14
// "Software"), to deal in the Software without restriction, including
 
15
// without limitation the rights to use, copy, modify, merge, publish,
 
16
// distribute, sublicense, and/or sell copies of the Software, and to
 
17
// permit persons to whom the Software is furnished to do so, subject to
 
18
// the following conditions:
 
19
//
 
20
// The above copyright notice and this permission notice shall be
 
21
// included in all copies or substantial portions of the Software.
 
22
//
 
23
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
24
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
25
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
26
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 
27
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 
28
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
29
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
30
//
 
31
 
 
32
using System;
 
33
using System.Collections.Generic;
 
34
 
 
35
using Gtk;
 
36
using ScrolledWindow = Gtk.ScrolledWindow;
 
37
 
 
38
using Mono.Addins;
 
39
 
 
40
using Hyena;
 
41
using Hyena.Widgets;
 
42
using Hyena.Data.Gui;
 
43
 
 
44
using Banshee.Configuration;
 
45
using Banshee.Sources;
 
46
using Banshee.Sources.Gui;
 
47
using Banshee.ServiceStack;
 
48
using Banshee.Collection;
 
49
using Banshee.Collection.Database;
 
50
using Banshee.Collection.Gui;
 
51
using Banshee.Gui;
 
52
using Banshee.LiveRadio.Plugins;
 
53
 
 
54
namespace Banshee.LiveRadio
 
55
{
 
56
 
 
57
    /// <summary>
 
58
    /// The source contents for a plugin source. It creates a view with a genre choose box, a query field
 
59
    /// and the view for the retrieved station tracks.
 
60
    /// The source contents is also the connector between plugin and source, as it handles just about all
 
61
    /// refresh/notify events coming from either side.
 
62
    /// </summary>
 
63
    public class LiveRadioPluginSourceContents : VBox, ISourceContents, ITrackModelSourceContents
 
64
    {
 
65
        private TrackListView track_view;
 
66
        private Gtk.ScrolledWindow main_scrolled_window;
 
67
        protected ISource source;
 
68
 
 
69
        private Paned container;
 
70
        private Widget browser_container;
 
71
        private InterfaceActionService action_service;
 
72
        private ActionGroup browser_view_actions;
 
73
 
 
74
        private ILiveRadioPlugin plugin;
 
75
        private LiveRadioFilterView filter_box;
 
76
 
 
77
        private static string menu_xml = @"
 
78
            <ui>
 
79
              <menubar name=""MainMenu"">
 
80
                <menu name=""ViewMenu"" action=""ViewMenuAction"">
 
81
                  <placeholder name=""BrowserViews"">
 
82
                    <menuitem name=""BrowserVisible"" action=""BrowserVisibleAction"" />
 
83
                    <separator />
 
84
                    <menuitem name=""BrowserTop"" action=""BrowserTopAction"" />
 
85
                    <menuitem name=""BrowserLeft"" action=""BrowserLeftAction"" />
 
86
                    <separator />
 
87
                  </placeholder>
 
88
                </menu>
 
89
              </menubar>
 
90
            </ui>
 
91
        ";
 
92
 
 
93
        /// <summary>
 
94
        /// Constructor -- creates the source contents for a plugin and sets up the event handlers for the view
 
95
        /// and the plugin refresh events.
 
96
        /// </summary>
 
97
        /// <param name="plugin">
 
98
        /// A <see cref="ILiveRadioPlugin"/> -- the plugin to set up the source contents for.
 
99
        /// </param>
 
100
        public LiveRadioPluginSourceContents (ILiveRadioPlugin plugin)
 
101
        {
 
102
            base.Name = plugin.Name;
 
103
            this.plugin = plugin;
 
104
 
 
105
            InitializeViews ();
 
106
 
 
107
            string position = ForcePosition == null ? BrowserPosition.Get () : ForcePosition;
 
108
            if (position == "top") {
 
109
                LayoutTop ();
 
110
            } else {
 
111
                LayoutLeft ();
 
112
            }
 
113
 
 
114
            plugin.GenreListLoaded += OnPluginGenreListLoaded;
 
115
            plugin.RequestResultRetrieved += OnPluginRequestResultRetrieved;
 
116
 
 
117
            if (ForcePosition != null) {
 
118
                return;
 
119
            }
 
120
 
 
121
            if (ServiceManager.Contains ("InterfaceActionService")) {
 
122
                action_service = ServiceManager.Get<InterfaceActionService> ();
 
123
 
 
124
                if (action_service.FindActionGroup ("BrowserView") == null) {
 
125
                    browser_view_actions = new ActionGroup ("BrowserView");
 
126
 
 
127
                    browser_view_actions.Add (new RadioActionEntry [] {
 
128
                        new RadioActionEntry ("BrowserLeftAction", null,
 
129
                            AddinManager.CurrentLocalizer.GetString ("Browser on Left"), null,
 
130
                            AddinManager.CurrentLocalizer.GetString ("Show the artist/album browser to the left of the track list"), 0),
 
131
 
 
132
                        new RadioActionEntry ("BrowserTopAction", null,
 
133
                            AddinManager.CurrentLocalizer.GetString ("Browser on Top"), null,
 
134
                            AddinManager.CurrentLocalizer.GetString ("Show the artist/album browser above the track list"), 1),
 
135
                    }, position == "top" ? 1 : 0, null);
 
136
 
 
137
                    browser_view_actions.Add (new ToggleActionEntry [] {
 
138
                        new ToggleActionEntry ("BrowserVisibleAction", null,
 
139
                            AddinManager.CurrentLocalizer.GetString ("Show Browser"), "<control>B",
 
140
                            AddinManager.CurrentLocalizer.GetString ("Show or hide the artist/album browser"),
 
141
                            null, BrowserVisible.Get ())
 
142
                    });
 
143
 
 
144
 
 
145
                    action_service.AddActionGroup (browser_view_actions);
 
146
                    action_service.UIManager.AddUiFromString (menu_xml);
 
147
                }
 
148
 
 
149
                (action_service.FindAction ("BrowserView.BrowserLeftAction") as RadioAction).Changed += OnViewModeChanged;
 
150
                (action_service.FindAction ("BrowserView.BrowserTopAction") as RadioAction).Changed += OnViewModeChanged;
 
151
                action_service.FindAction ("BrowserView.BrowserVisibleAction").Activated += OnToggleBrowser;
 
152
            }
 
153
 
 
154
            ServiceManager.SourceManager.ActiveSourceChanged += delegate {
 
155
                ThreadAssist.ProxyToMain (delegate {
 
156
                    browser_container.Visible = ActiveSourceCanHasBrowser ? BrowserVisible.Get () : false;
 
157
                });
 
158
            };
 
159
 
 
160
            NoShowAll = true;
 
161
 
 
162
        }
 
163
 
 
164
        /// <summary>
 
165
        /// Initiate a refesh of the contents: clear the genre list, add a fake "loading" entry and
 
166
        /// prohibit interaction with the elements
 
167
        /// </summary>
 
168
        public void InitRefresh ()
 
169
        {
 
170
            main_scrolled_window.Sensitive = false;
 
171
            List<Genre> fakeresult = new List<Genre> ();
 
172
            fakeresult.Add (new Genre(AddinManager.CurrentLocalizer.GetString("Loading...")));
 
173
            filter_box.UpdateGenres (fakeresult);
 
174
            filter_box.Sensitive = false;
 
175
        }
 
176
 
 
177
        /// <summary>
 
178
        /// Handles when a new result for a previous query request is received from the corresponding plugin. Transfers the
 
179
        /// received result to the plugin's source, and if there are none, set up a fake entry.
 
180
        /// </summary>
 
181
        /// <param name="sender">
 
182
        /// A <see cref="System.Object"/> -- The plugin that sent the results. Implements ILiveRadioPlugin.
 
183
        /// </param>
 
184
        /// <param name="request">
 
185
        /// A <see cref="System.String"/> -- The requested query string, either a genre name or the freetext (see request_type).
 
186
        /// </param>
 
187
        /// <param name="request_type">
 
188
        /// A <see cref="LiveRadioRequestType"/> -- The type of the request.
 
189
        /// </param>
 
190
        /// <param name="result">
 
191
        /// A <see cref="List<DatabaseTrackInfo>"/> -- A list of DatabaseTrackInfo objects that fulfil the query.
 
192
        /// </param>
 
193
        void OnPluginRequestResultRetrieved (object sender,
 
194
                                             string request,
 
195
                                             LiveRadioRequestType request_type,
 
196
                                             List<DatabaseTrackInfo> result)
 
197
        {
 
198
            if ((request_type == LiveRadioRequestType.ByFreetext)
 
199
                || (filter_box.GetSelectedGenre ().Name.Equals (request) && request_type == LiveRadioRequestType.ByGenre))
 
200
            {
 
201
                if (result == null)
 
202
                {
 
203
                    SetFakeTrack (AddinManager.CurrentLocalizer.GetString("Error... Please Reload"));
 
204
                } else if (result.Count > 0) {
 
205
                    plugin.PluginSource.SetStations (result);
 
206
                    main_scrolled_window.Sensitive = true;
 
207
                } else {
 
208
                    string message = (request_type == LiveRadioRequestType.ByGenre ? "Error... Please Reload" : "No Results");
 
209
                    SetFakeTrack (AddinManager.CurrentLocalizer.GetString(message));
 
210
                }
 
211
            }
 
212
        }
 
213
 
 
214
        /// <summary>
 
215
        /// Adds a fake track to the source and disables interaction with the track view.
 
216
        /// </summary>
 
217
        /// <param name="info">
 
218
        /// A <see cref="System.String"/> -- The information to display will be set as the fake track title and artist.
 
219
        /// </param>
 
220
        protected void SetFakeTrack (string info)
 
221
        {
 
222
            List<DatabaseTrackInfo> fakeresult = new List<DatabaseTrackInfo> ();
 
223
            DatabaseTrackInfo faketrack = new DatabaseTrackInfo ();
 
224
            faketrack.TrackTitle = info;
 
225
            faketrack.ArtistName = info;
 
226
            faketrack.AlbumArtist = info;
 
227
            faketrack.Uri = new SafeUri ("http://test.com/test.pls");
 
228
 
 
229
            fakeresult.Add (faketrack);
 
230
            plugin.PluginSource.SetStations (fakeresult);
 
231
            main_scrolled_window.Sensitive = false;
 
232
        }
 
233
 
 
234
        /// <summary>
 
235
        /// Handles when a genre list has been retrieved by the plugin. Fills the genre choose box with the results or
 
236
        /// adds a info message in case of an empty result and disables interaction with the control.
 
237
        /// </summary>
 
238
        /// <param name="sender">
 
239
        /// A <see cref="System.Object"/>
 
240
        /// </param>
 
241
        /// <param name="genres">
 
242
        /// A <see cref="List<Genre>"/>
 
243
        /// </param>
 
244
        void OnPluginGenreListLoaded (object sender, List<Genre> genres)
 
245
        {
 
246
            if (genres.Count > 0) {
 
247
                filter_box.UpdateGenres (genres);
 
248
                filter_box.Sensitive = true;
 
249
            } else {
 
250
                List<Genre> fakeresult = new List<Genre> ();
 
251
                fakeresult.Add (new Genre(AddinManager.CurrentLocalizer.GetString("Error... Please Reload")));
 
252
                filter_box.UpdateGenres (fakeresult);
 
253
                filter_box.Sensitive = false;
 
254
            }
 
255
        }
 
256
 
 
257
        /// <summary>
 
258
        /// Initialize the main track view
 
259
        /// </summary>
 
260
        protected void InitializeViews ()
 
261
        {
 
262
            SetupMainView (track_view = new TrackListView ());
 
263
        }
 
264
 
 
265
 
 
266
        /// <summary>
 
267
        /// Setup the main track view and disable interaction
 
268
        /// </summary>
 
269
        /// <param name="main_view">
 
270
        /// A <see cref="ListView<T>"/> -- the main track view to set up
 
271
        /// </param>
 
272
        protected void SetupMainView<T> (ListView<T> main_view)
 
273
        {
 
274
            main_scrolled_window = SetupView (main_view);
 
275
            main_scrolled_window.Sensitive = false;
 
276
        }
 
277
 
 
278
        /// <summary>
 
279
        /// Capsules a widget in a scrolled window to add scrolling.
 
280
        /// </summary>
 
281
        /// <param name="view">
 
282
        /// A <see cref="Widget"/> -- the view to capsule
 
283
        /// </param>
 
284
        /// <returns>
 
285
        /// A <see cref="ScrolledWindow"/> -- the scrolled window containing the capsuled view
 
286
        /// </returns>
 
287
        private ScrolledWindow SetupView (Widget view)
 
288
        {
 
289
            ScrolledWindow window = null;
 
290
 
 
291
            if (ApplicationContext.CommandLine.Contains ("smooth-scroll")) {
 
292
                window = new SmoothScrolledWindow ();
 
293
            } else {
 
294
                window = new ScrolledWindow ();
 
295
            }
 
296
 
 
297
            window.Add (view);
 
298
            window.HscrollbarPolicy = PolicyType.Automatic;
 
299
            window.VscrollbarPolicy = PolicyType.Automatic;
 
300
 
 
301
            return window;
 
302
        }
 
303
 
 
304
        /// <summary>
 
305
        /// Unparent the views' scrolled window parents so they can be re-packed in
 
306
        /// a new layout. The main container gets destroyed since it will be recreated.
 
307
        /// </summary>
 
308
        private void Reset ()
 
309
        {
 
310
            if (container != null && main_scrolled_window != null) {
 
311
                container.Remove (main_scrolled_window);
 
312
            }
 
313
 
 
314
            if (container != null) {
 
315
                Remove (container);
 
316
            }
 
317
        }
 
318
 
 
319
        /// <summary>
 
320
        /// Make a layout with the filter views on the left hand side
 
321
        /// </summary>
 
322
        private void LayoutLeft ()
 
323
        {
 
324
            Layout (false);
 
325
        }
 
326
 
 
327
        /// <summary>
 
328
        /// Make a layout with the filter views on top
 
329
        /// </summary>
 
330
        private void LayoutTop ()
 
331
        {
 
332
            Layout (true);
 
333
        }
 
334
 
 
335
        /// <summary>
 
336
        /// Create the contents of the source contents in the desired layout.
 
337
        /// </summary>
 
338
        /// <param name="top">
 
339
        /// A <see cref="System.Boolean"/> -- whether to create a LayoutTop (true) or a LayoutLeft (false)
 
340
        /// </param>
 
341
        private void Layout (bool top)
 
342
        {
 
343
            Reset ();
 
344
 
 
345
            container = GetPane (!top);
 
346
            filter_box = new LiveRadioFilterView ();
 
347
            filter_box.Sensitive = false;
 
348
            filter_box.GenreSelected += OnViewGenreSelected;
 
349
            filter_box.GenreActivated += OnViewGenreSelected;
 
350
            filter_box.QuerySent += OnViewQuerySent;
 
351
 
 
352
            container.Pack1 (filter_box, false, false);
 
353
            container.Pack2 (main_scrolled_window, true, false);
 
354
            browser_container = filter_box;
 
355
 
 
356
            container.Position = top ? 175 : 275;
 
357
            ShowPack ();
 
358
        }
 
359
 
 
360
        /// <summary>
 
361
        /// Handles when the user sends a query through the Entry box of the UI and initiates request execution
 
362
        /// in the plugin object. The track view is reset with a fake entry.
 
363
        /// </summary>
 
364
        /// <param name="sender">
 
365
        /// A <see cref="System.Object"/> -- the sender of the event
 
366
        /// </param>
 
367
        /// <param name="query">
 
368
        /// A <see cref="System.String"/> -- the query string the user entered
 
369
        /// </param>
 
370
        void OnViewQuerySent (object sender, string query)
 
371
        {
 
372
            SetFakeTrack (AddinManager.CurrentLocalizer.GetString("Loading..."));
 
373
            plugin.ExecuteRequest (LiveRadioRequestType.ByFreetext, query);
 
374
        }
 
375
 
 
376
        /// <summary>
 
377
        /// Handles when the user activates a genre in the genre choose box and initiates request execution
 
378
        /// in the plugin object. The track view is reset with a fake entry.
 
379
        /// </summary>
 
380
        /// <param name="sender">
 
381
        /// A <see cref="System.Object"/> -- the sender of the event
 
382
        /// </param>
 
383
        /// <param name="genre">
 
384
        /// A <see cref="Genre"/> -- the genre the user selected
 
385
        /// </param>
 
386
        void OnViewGenreSelected (object sender, Genre genre)
 
387
        {
 
388
            SetFakeTrack (AddinManager.CurrentLocalizer.GetString("Loading..."));
 
389
            plugin.ExecuteRequest (LiveRadioRequestType.ByGenre, genre.Name);
 
390
        }
 
391
        /// <summary>
 
392
        /// Draw the source contents
 
393
        /// </summary>
 
394
        private void ShowPack ()
 
395
        {
 
396
            PackStart (container, true, true, 0);
 
397
            VBox instruct = new VBox ();
 
398
            //instruct.ExposeEvent += (o, a) => {
 
399
            //    using (Cairo.Context cr = Gdk.CairoHelper.Create (instruct.GdkWindow)) {
 
400
            //        double radius = 10;
 
401
            //        int x = a.Event.Area.X;
 
402
            //        int y = a.Event.Area.Y;
 
403
            //        int width = a.Event.Area.Width;
 
404
            //        int height = a.Event.Area.Height;
 
405
 
 
406
            //        cr.MoveTo (x + radius, y);
 
407
            //        cr.Arc (x + width - radius, y + radius, radius, Math.PI * 1.5, Math.PI * 2);
 
408
            //        cr.Arc (x + width - radius, y + height - radius, radius, 0, Math.PI * .5);
 
409
            //        cr.Arc (x + radius, y + height - radius, radius, Math.PI * .5, Math.PI);
 
410
            //        cr.Arc (x + radius, y + radius, radius, Math.PI, Math.PI * 1.5);
 
411
            //        cr.Color = new Cairo.Color (.5, .5, .5, 1);
 
412
            //        cr.Stroke ();
 
413
            //    }
 
414
                // not yet sure which is the better code.
 
415
                //                Gdk.Window win = a.Event.Window;
 
416
                //                Gdk.Rectangle area = a.Event.Area;
 
417
                //
 
418
                //                win.DrawRectangle (Style.BaseGC (StateType.Active), false, area);
 
419
                //
 
420
                //                a.RetVal = true;
 
421
            //};
 
422
            Label help_label = new Label (
 
423
                  AddinManager.CurrentLocalizer.GetString ("Click a genre to load/refresh entries or type a query. Use the refresh button to refresh genres."));
 
424
            instruct.PackStart(help_label, false, true, 10);
 
425
            PackStart (instruct, false, true, 10);
 
426
            NoShowAll = false;
 
427
            ShowAll ();
 
428
            NoShowAll = true;
 
429
            browser_container.Visible = ForcePosition != null || BrowserVisible.Get ();
 
430
        }
 
431
 
 
432
        /// <summary>
 
433
        /// Helper function to make a new Paned with the correct layout
 
434
        /// </summary>
 
435
        /// <param name="hpane">
 
436
        /// A <see cref="System.Boolean"/>
 
437
        /// </param>
 
438
        /// <returns>
 
439
        /// A <see cref="Paned"/>
 
440
        /// </returns>
 
441
        private Paned GetPane (bool hpane)
 
442
        {
 
443
            if (hpane)
 
444
                return new HPaned ();
 
445
            else
 
446
                return new VPaned ();
 
447
        }
 
448
 
 
449
        /// <summary>
 
450
        /// Handles when the user selects a different view mode.
 
451
        /// </summary>
 
452
        /// <param name="o">
 
453
        /// A <see cref="System.Object"/>
 
454
        /// </param>
 
455
        /// <param name="args">
 
456
        /// A <see cref="ChangedArgs"/>
 
457
        /// </param>
 
458
        private void OnViewModeChanged (object o, ChangedArgs args)
 
459
        {
 
460
            if (args.Current.Value == 0) {
 
461
                LayoutLeft ();
 
462
                BrowserPosition.Set ("left");
 
463
            } else {
 
464
                LayoutTop ();
 
465
                BrowserPosition.Set ("top");
 
466
            }
 
467
        }
 
468
 
 
469
        /// <summary>
 
470
        /// Handles when browser visibility is toggled
 
471
        /// </summary>
 
472
        /// <param name="o">
 
473
        /// A <see cref="System.Object"/>
 
474
        /// </param>
 
475
        /// <param name="args">
 
476
        /// A <see cref="EventArgs"/>
 
477
        /// </param>
 
478
        private void OnToggleBrowser (object o, EventArgs args)
 
479
        {
 
480
            ToggleAction action = (ToggleAction)o;
 
481
 
 
482
            browser_container.Visible = action.Active && ActiveSourceCanHasBrowser;
 
483
            BrowserVisible.Set (action.Active);
 
484
 
 
485
        }
 
486
 
 
487
        protected bool ActiveSourceCanHasBrowser {
 
488
            get { return true; }
 
489
        }
 
490
 
 
491
        protected string ForcePosition {
 
492
            get { return "bottom"; }
 
493
        }
 
494
 
 
495
        #region Implement ISourceContents
 
496
 
 
497
        /// <summary>
 
498
        /// Sets the source and the track model for the source contents
 
499
        /// </summary>
 
500
        /// <param name="source">
 
501
        /// A <see cref="ISource"/>
 
502
        /// </param>
 
503
        /// <returns>
 
504
        /// A <see cref="System.Boolean"/>
 
505
        /// </returns>
 
506
        public bool SetSource (ISource source)
 
507
        {
 
508
            DatabaseSource track_source = source as DatabaseSource;
 
509
            if (track_source == null) {
 
510
                return false;
 
511
            }
 
512
 
 
513
            this.source = source;
 
514
 
 
515
            track_view.SetModel (track_source.TrackModel);
 
516
 
 
517
            return true;
 
518
        }
 
519
 
 
520
        /// <summary>
 
521
        /// Sets the source and track model references to null
 
522
        /// </summary>
 
523
        public void ResetSource ()
 
524
        {
 
525
            this.source = null;
 
526
            track_view.SetModel (null);
 
527
        }
 
528
 
 
529
        /// <summary>
 
530
        /// The ISource source of this source contents
 
531
        /// </summary>
 
532
        public ISource Source {
 
533
            get { return source; }
 
534
        }
 
535
 
 
536
        /// <summary>
 
537
        /// The Widget of the source contents
 
538
        /// </summary>
 
539
        public Widget Widget {
 
540
            get { return this; }
 
541
        }
 
542
 
 
543
        #endregion
 
544
 
 
545
        #region ITrackModelSourceContents implementation
 
546
 
 
547
        /// <summary>
 
548
        /// returns the track view of this source contents
 
549
        /// </summary>
 
550
        public IListView<TrackInfo> TrackView {
 
551
            get { return track_view; }
 
552
        }
 
553
 
 
554
        #endregion
 
555
 
 
556
        public static readonly SchemaEntry<bool> BrowserVisible = new SchemaEntry<bool> (
 
557
            "browser", "visible",
 
558
            true,
 
559
            "Artist/Album Browser Visibility",
 
560
            "Whether or not to show the Artist/Album browser"
 
561
        );
 
562
 
 
563
        public static readonly SchemaEntry<string> BrowserPosition = new SchemaEntry<string> (
 
564
            "browser", "position",
 
565
            "left",
 
566
            "Artist/Album Browser Position",
 
567
            "The position of the Artist/Album browser; either 'top' or 'left'"
 
568
        );
 
569
    }
 
570
}