/* vim: set noexpandtab tabstop=4 shiftwidth=4 nowrap textwidth=100
*
* Echo Media Player
* Copyright (C) 2008 Shane O'Connell
*
* [ The original file includes a copyright header in this location describing
* the file as being released under the terms of the GNU General Public
* License. It has been removed in order to display the file as part of the
* archive. ]
*/
using Echo.Core;
using Echo.Interfaces;
public class Echo.UI.TreeModels.PlaySourceModel : GLib.Object, Gtk.TreeModel
{
// TODO make TreeIter's use IPlaySourceTrackRef's so that they don't need to
// be invalidated
private IPlaySource source;
private ITrack _last_known_track = null;
private int _last_known_num_tracks;
private int stamp = 0;
public enum Column
{
TITLE = 0, ARTIST = 1, ALBUM = 2, TRACK_NUMBER = 3, YEAR = 4, URI = 5, PLAYING = 6,
RATING = 7
}
public PlaySourceModel(IPlaySource source)
{
this.source = source;
_last_known_num_tracks = source.get_num_tracks();
source.track_removed += (source, index) => {
_last_known_num_tracks = source.get_num_tracks();
stamp++;
this.row_deleted(get_path_from_index(index, false));
};
source.track_inserted += (source, index) => {
_last_known_num_tracks = source.get_num_tracks();
stamp++;
Gtk.TreeIter iter;
get_iter_from_index(out iter, index);
this.row_inserted(get_path_from_index(index), iter);
};
source.track_changed += (source, index) => {
Gtk.TreeIter iter;
get_iter_from_index(out iter, index);
this.row_changed(get_path_from_index(index), iter);
};
source.source_refreshed += (source) => {
Gtk.TreeIter iter;
for (int i = 0; i < _last_known_num_tracks; i++) {
if (i < source.get_num_tracks()) {
get_iter_from_index(out iter, i);
this.row_changed(get_path_from_index(i), iter);
}
else
this.row_deleted(get_path_from_index(i, false));
}
if (source.get_num_tracks() > _last_known_num_tracks)
for (int i = _last_known_num_tracks; i < source.get_num_tracks(); i++) {
get_iter_from_index(out iter, i);
this.row_inserted(get_path_from_index(i), iter);
}
};
Services.playback().track_changed += (playback_manager, is_automatic) => {
Gtk.TreeIter iter;
// Update the "Playing" field on the old track
if (_last_known_track != null && _last_known_track.valid) {
get_iter_from_index(out iter, _last_known_track.index);
this.row_changed(get_path_from_index(_last_known_track.index), iter);
_last_known_track = null;
}
if (playback_manager.current_track != null &&
playback_manager.current_track.source == this.source) {
// Update the "Playing" field on the new track
get_iter_from_index(out iter, playback_manager.current_track.index);
this.row_changed(get_path_from_index(playback_manager.current_track.index), iter);
_last_known_track = playback_manager.current_track;
}
};
// Should not be necessary
/*Services.playback().state_changed += (playback_manager) => {
if (playback_manager.current_track == null &&
_last_known_track != null && _last_known_track.valid) {
Gtk.TreeIter iter;
get_iter_from_index(out iter, _last_known_track.index);
this.row_changed(get_path_from_index(_last_known_track.index), iter);
_last_known_track = null;
}
};*/
}
public int get_n_columns()
{
return 8; // TODO Can this come directly from the enum?
}
public Type get_column_type(int index)
{
switch (index)
{
case Column.TITLE:
return typeof(string);
case Column.ARTIST:
return typeof(string);
case Column.ALBUM:
return typeof(string);
case Column.YEAR:
return typeof(int);
case Column.TRACK_NUMBER:
return typeof(int);
case Column.URI:
return typeof(string);
case Column.PLAYING:
return typeof(bool);
case Column.RATING:
return typeof(int);
default:
assert_not_reached();
}
}
public void get_value(Gtk.TreeIter iter, int column, ref GLib.Value value)
{
int index = get_index_from_iter(iter);
switch(column)
{
case Column.TITLE:
value.init(typeof(string));
value.set_string(source.get_track(index).title);
break;
case Column.ARTIST:
value.init(typeof(string));
value.set_string(source.get_track(index).artist);
break;
case Column.ALBUM:
value.init(typeof(string));
value.set_string(source.get_track(index).album);
break;
case Column.YEAR:
value.init(typeof(int));
value.set_int((int)source.get_track(index).release_year);
break;
case Column.TRACK_NUMBER:
value.init(typeof(int));
value.set_int(source.get_track(index).track_number);
break;
case Column.URI:
value.init(typeof(string));
value.set_string(source.get_track(index).uri);
break;
case Column.PLAYING:
value.init(typeof(bool));
value.set_boolean(Services.playback().current_track != null &&
source == Services.playback().current_track.source &&
index == Services.playback().current_track.index);
break;
case Column.RATING:
value.init(typeof(int));
if (source.get_track(index) is IRateableTrack)
value.set_int(((IRateableTrack)source.get_track(index)).rating);
else
value.set_int(-1);
break;
default:
assert_not_reached();
}
}
public int get_index_from_path(Gtk.TreePath path)
{
assert(path.get_depth() == 1);
assert(path.get_indices()[0] >= 0);
assert(path.get_indices()[0] < source.get_num_tracks());
return path.get_indices()[0];
}
public Gtk.TreePath get_path_from_index(int index, bool check_index_max = true)
{
assert(index >= 0);
assert(index < source.get_num_tracks() || !check_index_max);
return new Gtk.TreePath.from_indices(index, -1);
}
public int get_index_from_iter(Gtk.TreeIter iter)
{
assert(iter.stamp == stamp);
assert((int)iter.user_data >= 0);
assert((int)iter.user_data < source.get_num_tracks());
return (int)iter.user_data;
}
public void get_iter_from_index(out Gtk.TreeIter iter, int index)
{
assert(index >= 0);
assert(index < source.get_num_tracks());
iter.stamp = stamp;
iter.user_data = (void*)index;
}
public bool get_iter(out Gtk.TreeIter iter, Gtk.TreePath path)
{
if (path.get_depth() != 1 || path.get_indices()[0] >= source.get_num_tracks())
return false;
get_iter_from_index(out iter, get_index_from_path(path));
return true;
}
public Gtk.TreePath get_path(Gtk.TreeIter iter)
{
return get_path_from_index(get_index_from_iter(iter));
}
public bool iter_next(ref Gtk.TreeIter iter)
{
int index = get_index_from_iter(iter);
if (index < (source.get_num_tracks()-1)) {
index++;
get_iter_from_index(out iter, index);
return true;
}
return false;
}
public Gtk.TreeModelFlags get_flags()
{
return Gtk.TreeModelFlags.LIST_ONLY;
}
public bool iter_children(out Gtk.TreeIter iter, Gtk.TreeIter? parent)
{
return false;
}
public bool iter_has_child(Gtk.TreeIter iter)
{
return false;
}
public int iter_n_children(Gtk.TreeIter? iter)
{
return 0;
}
public bool iter_nth_child(out Gtk.TreeIter iter, Gtk.TreeIter? parent, int n)
{
return false;
}
public bool iter_parent(out Gtk.TreeIter iter, Gtk.TreeIter child)
{
return false;
}
public void ref_node(Gtk.TreeIter iter)
{
// Do nothing
}
public void unref_node(Gtk.TreeIter iter)
{
// Do nothing
}
}