2
// MediaPanelContents.cs
5
// Aaron Bockover <abockover@novell.com>
7
// Copyright 2010 Novell, Inc.
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
// of this software and associated documentation files (the "Software"), to deal
11
// in the Software without restriction, including without limitation the rights
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
// copies of the Software, and to permit persons to whom the Software is
14
// furnished to do so, subject to the following conditions:
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28
using System.Collections.Generic;
38
using Banshee.ServiceStack;
39
using Banshee.Sources;
40
using Banshee.Sources.Gui;
41
using Banshee.Collection;
42
using Banshee.Collection.Gui;
43
using Banshee.MediaEngine;
45
using Banshee.Gui.Widgets;
47
namespace Banshee.MeeGo
49
public class MediaPanelContents : Table, ITrackModelSourceContents
51
private ArtistListView artist_view;
52
private AlbumListView album_view;
53
private TerseTrackListView track_view;
55
private SourceComboBox source_combo_box;
56
private SearchEntry search_entry;
57
private MeeGoTrackInfoDisplay track_info_display;
59
private ISource source;
60
private Dictionary<object, double> model_positions = new Dictionary<object, double> ();
62
protected MediaPanelContents (IntPtr raw) : base (raw)
66
public MediaPanelContents () : base (2, 2, false)
71
RedrawOnAllocate = true;
79
SetSource (ServiceManager.SourceManager.ActiveSource);
82
private void ConnectEvents ()
84
ServiceManager.SourceManager.ActiveSourceChanged += OnActiveSourceChanged;
86
ServiceManager.Get<InterfaceActionService> ().TrackActions ["SearchForSameArtistAction"].Activated += OnProgrammaticSearch;
87
ServiceManager.Get<InterfaceActionService> ().TrackActions ["SearchForSameAlbumAction"].Activated += OnProgrammaticSearch;
89
ServiceManager.PlayerEngine.ConnectEvent ((args) => track_info_display.Visible =
90
ServiceManager.PlayerEngine.CurrentState != PlayerState.Idle,
91
PlayerEvent.StateChange | PlayerEvent.StartOfStream);
93
source_combo_box.Model.Filter = (source) => source is ITrackModelSource;
94
source_combo_box.Model.Refresh ();
95
source_combo_box.UpdateActiveSource ();
97
search_entry.Changed += OnSearchEntryChanged;
99
artist_view.SelectionProxy.Changed += OnBrowserViewSelectionChanged;
100
album_view.SelectionProxy.Changed += OnBrowserViewSelectionChanged;
103
#region UI Construction
105
private void BuildHeader ()
108
Markup = String.Format ("<span font_desc=\"Droid Sans Bold\" " +
109
"size=\"x-large\" foreground=\"#606eff\">{0}</span>",
110
GLib.Markup.EscapeText (Catalog.GetString ("Media"))),
114
AttachOptions.Fill | AttachOptions.Expand,
115
AttachOptions.Shrink, 12, 0);
118
private void BuildLibrary ()
120
var box = new MeeGoHeaderBox () { Title = Catalog.GetString ("Library") };
122
// Build the Library Header
123
var header = new HBox () {
128
var app_button = new Button (new Image () {
129
IconSize = (int)IconSize.LargeToolbar,
130
IconName = "media-player-banshee"
132
TooltipText = Catalog.GetString ("Launch the Banshee Media Player")
134
app_button.Clicked += (o, e) => {
135
ServiceManager.SourceManager.SetActiveSource (ServiceManager.SourceManager.MusicLibrary);
136
ServiceManager.Get<MeeGoService> ().PresentPrimaryInterface ();
139
header.PackStart (source_combo_box = new SourceComboBox (), false, false, 0);
140
header.PackStart (app_button, false, false, 0);
141
header.PackStart (search_entry = new SearchEntry (), true, true, 0);
142
box.PackStartHighlighted (header, false, false, 0, MeeGoHeaderBox.HighlightFlags.Background);
144
// Build the Library Views
145
var views = new HBox () { Spacing = 5 };
146
views.PackStart (SetupView (artist_view = new ArtistListView () {
147
Name = "meego-panel-artists",
149
DoNotRenderNullModel = true
150
}), false, false, 0);
151
views.PackStart (SetupView (album_view = new AlbumListView () {
152
Name = "meego-panel-albums",
153
DoNotRenderNullModel = true
155
box.PackStart (views, true, true, 0);
157
Attach (box, 0, 1, 1, 2,
158
AttachOptions.Expand | AttachOptions.Fill,
159
AttachOptions.Expand | AttachOptions.Fill,
163
private void BuildNowPlaying ()
165
var box = new MeeGoHeaderBox () { Title = Catalog.GetString ("Now Playing") };
167
var seek_slider = new ConnectedSeekSlider (SeekSliderLayout.Horizontal);
168
seek_slider.StreamPositionLabel.FormatString = "<small>{0}</small>";
170
track_info_display = new MeeGoTrackInfoDisplay () {
175
track_view = new TerseTrackListView () {
176
Name = "meego-panel-tracks",
179
track_view.ColumnController.Insert (new Column (null, "indicator",
180
new ColumnCellStatusIndicator (null), 0.05, true, 20, 20), 0);
182
box.PackStartHighlighted (track_info_display, false, false, 0, MeeGoHeaderBox.HighlightFlags.Background);
183
box.PackStartHighlighted (seek_slider, false, false, 0, MeeGoHeaderBox.HighlightFlags.Background);
184
box.PackStart (SetupView (track_view), true, true, 0);
185
box.PackStartHighlighted (new PlaybackBox (), false, false, 0, MeeGoHeaderBox.HighlightFlags.TopLine);
187
Attach (box, 1, 2, 1, 2,
188
AttachOptions.Shrink,
189
AttachOptions.Expand | AttachOptions.Fill,
193
private ScrolledWindow SetupView (Widget view)
195
var scrolled = new ScrolledWindow () {
196
VscrollbarPolicy = PolicyType.Automatic,
197
HscrollbarPolicy = PolicyType.Never,
198
ShadowType = ShadowType.None
206
#region Background Rendering
208
protected override void OnParentSet (Widget previous)
210
base.OnParentSet (previous);
212
if (Parent != null) {
213
Parent.ModifyBg (StateType.Normal, Style.White);
217
protected override bool OnExposeEvent (Gdk.EventExpose evnt)
219
if (!Visible || !IsMapped) {
223
RenderBackground (evnt.Window, evnt.Region);
224
foreach (var child in Children) {
225
PropagateExpose (child, evnt);
231
private void RenderBackground (Gdk.Window window, Gdk.Region region)
233
var cr = Gdk.CairoHelper.Create (window);
235
var grad = new Cairo.LinearGradient (0, 0, 0, Allocation.Height);
236
grad.AddColorStop (0, CairoExtensions.RgbToColor (0xffffff));
237
grad.AddColorStop (1, CairoExtensions.RgbToColor (0xc3c3c3));
239
cr.Rectangle (0, 0, Allocation.Width, Allocation.Height);
243
CairoExtensions.DisposeContext (cr);
248
#region Event Handlers
250
private void OnProgrammaticSearch (object o, EventArgs args)
252
Source source = ServiceManager.SourceManager.ActiveSource;
253
search_entry.Ready = false;
254
search_entry.Query = source.FilterQuery;
255
search_entry.Ready = true;
258
private void OnBrowserViewSelectionChanged (object o, EventArgs args)
260
// Scroll the raising filter view to the top if "all" is selected
261
var selection = (Hyena.Collections.Selection)o;
262
if (!selection.AllSelected) {
266
if (artist_view.Selection == selection) {
267
artist_view.ScrollTo (0);
268
} else if (album_view.Selection == selection) {
269
album_view.ScrollTo (0);
273
private void OnSearchEntryChanged (object o, EventArgs args)
275
var source = ServiceManager.SourceManager.ActiveSource;
276
if (source == null) {
280
source.FilterType = (TrackFilterType)search_entry.ActiveFilterID;
281
source.FilterQuery = search_entry.Query;
284
private void OnActiveSourceChanged (SourceEventArgs args)
286
ThreadAssist.ProxyToMain (delegate {
287
var source = ServiceManager.SourceManager.ActiveSource;
289
search_entry.Ready = false;
290
search_entry.CancelSearch ();
291
search_entry.SearchSensitive = source != null && source.CanSearch;
293
if (source != null && source.FilterQuery != null) {
294
search_entry.Query = source.FilterQuery;
295
search_entry.ActivateFilter ((int)source.FilterType);
301
search_entry.Ready = true;
303
if (source != null && source != ServiceManager.SourceManager.MusicLibrary
304
&& source.Parent != ServiceManager.SourceManager.MusicLibrary) {
305
ServiceManager.Get<MeeGoService> ().PresentPrimaryInterface ();
310
internal void SyncSearchEntry ()
312
OnActiveSourceChanged (null);
317
#region View<->Model binding
319
private void SetModel<T> (IListModel<T> model)
321
ListView<T> view = FindListView <T> ();
323
SetModel (view, model);
325
Hyena.Log.DebugFormat ("Unable to find view for model {0}", model);
329
private void SetModel<T> (ListView<T> view, IListModel<T> model)
331
if (view.Model != null) {
332
model_positions[view.Model] = view.Vadjustment.Value;
336
view.SetModel (null);
340
if (!model_positions.ContainsKey (model)) {
341
model_positions[model] = 0.0;
344
view.SetModel (model, model_positions[model]);
347
private ListView<T> FindListView<T> ()
349
foreach (var view in new IListView [] { artist_view, album_view, track_view }) {
350
if (view is ListView<T>) {
351
return (ListView<T>)view;
359
#region ISourceContents
361
public bool SetSource (ISource source)
363
var track_source = source as ITrackModelSource;
364
var filterable_source = source as IFilterableSource;
365
if (track_source == null) {
369
this.source = source;
371
SetModel (track_view, track_source.TrackModel);
373
if (filterable_source != null && filterable_source.CurrentFilters != null) {
374
foreach (var model in filterable_source.CurrentFilters) {
375
if (model is IListModel<ArtistInfo>) {
376
SetModel (artist_view, (model as IListModel<ArtistInfo>));
377
} else if (model is IListModel<AlbumInfo>) {
378
SetModel (album_view, (model as IListModel<AlbumInfo>));
386
public void ResetSource ()
389
SetModel (track_view, null);
390
SetModel (artist_view, null);
391
SetModel (album_view, null);
392
track_view.HeaderVisible = false;
395
public ISource Source {
396
get { return source; }
399
public Widget Widget {
405
#region ITrackModelSourceContents
407
public IListView<TrackInfo> TrackView {
408
get { return track_view; }