diff --git a/emmental/tracklist/row.py b/emmental/tracklist/row.py index 9003466..97a1330 100644 --- a/emmental/tracklist/row.py +++ b/emmental/tracklist/row.py @@ -14,6 +14,7 @@ class TrackRow(factory.ListRow): property = GObject.Property(type=str) mediumid = GObject.Property(type=int) + album_binding = GObject.Property(type=GObject.Binding) def __init__(self, listitem: Gtk.ListItem, property: str): """Initialize a TrackRow.""" @@ -26,10 +27,30 @@ class TrackRow(factory.ListRow): self.bind_and_set(library, "online", self, "online") self.bind_active("active") + def do_unbind(self) -> None: + """Extra handling to make sure we unbind the album property.""" + super().do_unbind() + if self.album_binding is not None: + self.album_binding.unbind() + self.album_binding = None + + def bind_album(self, child_prop: str) -> None: + """Bind an album property to the TrackRow child.""" + album = self.item.get_medium().get_album() + self.child.set_property(child_prop, album.get_property(self.property)) + self.album_binding = album.bind_property(self.property, + self.child, child_prop) + def bind_to_self(self, item_prop: str, child_prop: str) -> None: """Bind an item property directly to a TrackRow property.""" self.bind_and_set(self.item, item_prop, self, child_prop) + def rebind_album(self, child_prop: str) -> None: + """Rebind an album property to the TrackRow child.""" + if self.album_binding is not None: + self.album_binding.unbind() + self.bind_album(child_prop) + @GObject.Property(type=bool, default=False) def active(self) -> bool: """Get the active state of this Row.""" @@ -190,6 +211,23 @@ class TracknoString(InscriptionRow): self.bind_to_self("number", "number") +class AlbumString(InscriptionRow): + """A Track Row to display Album properties.""" + + def __init__(self, *args, **kwargs): + """Initialize a AlbumString.""" + super().__init__(*args, **kwargs) + self.connect("notify::mediumid", self.__update_album) + + def __update_album(self, row: InscriptionRow, param) -> None: + self.rebind_album("text") + + def do_bind(self) -> None: + """Bind an album string to the AlbumString.""" + super().do_bind() + self.bind_to_self("mediumid", "mediumid") + + class FavoriteButton(TrackRow): """A TrackRow with an toggle to set Track favorite status.""" diff --git a/emmental/tracklist/trackview.py b/emmental/tracklist/trackview.py index db92e83..84b9152 100644 --- a/emmental/tracklist/trackview.py +++ b/emmental/tracklist/trackview.py @@ -36,6 +36,10 @@ class TrackView(Gtk.Frame): self.__append_column("Length", "length", row.LengthString, xalign=1.0, numeric=True) self.__append_column("Artist", "artist", row.TrackString, width=250) + self.__append_column("Album Artist", "artist", row.AlbumString, + width=250, visible=False) + self.__append_column("Release", "release", row.AlbumString, + width=115, numeric=True) self.__append_column("Play Count", "playcount", row.PlayCountString, width=135, numeric=True) self.__append_column("Last Started", "laststarted", diff --git a/tests/test_settings.py b/tests/test_settings.py index b136470..92739bf 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -126,6 +126,8 @@ class TestSettings(unittest.TestCase): self.assertEqual(self.settings["tracklist.title.size"], 300) self.assertEqual(self.settings["tracklist.length.size"], -1) self.assertEqual(self.settings["tracklist.artist.size"], 250) + self.assertEqual(self.settings["tracklist.album-artist.size"], 250) + self.assertEqual(self.settings["tracklist.release.size"], 115) self.assertEqual(self.settings["tracklist.play-count.size"], 135) self.assertEqual(self.settings["tracklist.last-started.size"], 250) self.assertEqual(self.settings["tracklist.last-played.size"], 250) @@ -139,6 +141,8 @@ class TestSettings(unittest.TestCase): self.assertEqual(self.settings["tracklist.title.size"], 123) self.assertEqual(self.settings["tracklist.length.size"], 123) self.assertEqual(self.settings["tracklist.artist.size"], 123) + self.assertEqual(self.settings["tracklist.album-artist.size"], 123) + self.assertEqual(self.settings["tracklist.release.size"], 123) self.assertEqual(self.settings["tracklist.play-count.size"], 123) self.assertEqual(self.settings["tracklist.last-started.size"], 123) self.assertEqual(self.settings["tracklist.last-played.size"], 123) @@ -151,6 +155,8 @@ class TestSettings(unittest.TestCase): self.assertTrue(self.settings["tracklist.title.visible"]) self.assertTrue(self.settings["tracklist.length.visible"]) self.assertTrue(self.settings["tracklist.artist.visible"]) + self.assertFalse(self.settings["tracklist.album-artist.visible"]) + self.assertTrue(self.settings["tracklist.release.visible"]) self.assertTrue(self.settings["tracklist.play-count.visible"]) self.assertFalse(self.settings["tracklist.last-started.visible"]) self.assertTrue(self.settings["tracklist.last-played.visible"]) @@ -164,6 +170,8 @@ class TestSettings(unittest.TestCase): self.assertFalse(self.settings["tracklist.title.visible"]) self.assertFalse(self.settings["tracklist.length.visible"]) self.assertFalse(self.settings["tracklist.artist.visible"]) + self.assertTrue(self.settings["tracklist.album-artist.visible"]) + self.assertFalse(self.settings["tracklist.release.visible"]) self.assertFalse(self.settings["tracklist.play-count.visible"]) self.assertTrue(self.settings["tracklist.last-started.visible"]) self.assertFalse(self.settings["tracklist.last-played.visible"]) diff --git a/tests/tracklist/test_row.py b/tests/tracklist/test_row.py index e543eb7..046a70f 100644 --- a/tests/tracklist/test_row.py +++ b/tests/tracklist/test_row.py @@ -7,6 +7,7 @@ import emmental.factory import emmental.tracklist.row import tests.util import unittest.mock +from gi.repository import GObject from gi.repository import Gtk from gi.repository import Adw @@ -37,6 +38,7 @@ class TestTrackRowWidgets(tests.util.TestCase): """Test the base Track Row.""" row = emmental.tracklist.row.TrackRow(self.listitem, "property") self.assertIsInstance(row, emmental.factory.ListRow) + self.assertIsNone(row.album_binding) self.assertEqual(row.property, "property") self.assertEqual(row.mediumid, 0) @@ -148,6 +150,24 @@ class TestTrackRowWidgets(tests.util.TestCase): self.track.mediumid = medium.mediumid self.assertEqual(row.child.get_text(), "3-03") + def test_album_string(self): + """Test the Album String widget.""" + row = emmental.tracklist.row.AlbumString(self.listitem, "artist") + self.assertIsInstance(row, emmental.tracklist.row.InscriptionRow) + self.assertEqual(row.property, "artist") + + row.bind() + self.assertIsInstance(row.album_binding, GObject.Binding) + self.assertEqual(row.child.get_text(), "Artist") + + album = self.sql.albums.create("Other Album", "Other Artist", "2022") + medium = self.sql.media.create(album, "Other Medium", number=4) + self.track.mediumid = medium.mediumid + self.assertEqual(row.child.get_text(), "Other Artist") + + row.unbind() + self.assertIsNone(row.album_binding) + def test_favorite_button(self): """Test the Favorite Button widget.""" row = emmental.tracklist.row.FavoriteButton(self.listitem, "favorite") diff --git a/tests/tracklist/test_trackview.py b/tests/tracklist/test_trackview.py index e4aae9a..000bfbb 100644 --- a/tests/tracklist/test_trackview.py +++ b/tests/tracklist/test_trackview.py @@ -173,7 +173,39 @@ class TestTrackViewColumns(tests.util.TestCase): self.assertEqual(self.listitem.listrow.child.get_xalign(), 0.0) self.assertFalse(self.listitem.listrow.child.has_css_class("numeric")) - def test_playcount_column(self, i: int = 5): + def test_album_artist_column(self, i: int = 5): + """Test the album artist column.""" + self.assertEqual(self.columns[i].get_title(), "Album Artist") + self.assertEqual(self.columns[i].get_fixed_width(), 250) + self.assertTrue(self.columns[i].get_resizable()) + self.assertFalse(self.columns[i].get_visible()) + + factory = self.columns[i].get_factory() + self.assertIsInstance(factory, emmental.factory.Factory) + self.assertEqual(factory.row_type, emmental.tracklist.row.AlbumString) + + factory.emit("setup", self.listitem) + self.assertEqual(self.listitem.listrow.property, "artist") + self.assertEqual(self.listitem.listrow.child.get_xalign(), 0.0) + self.assertFalse(self.listitem.listrow.child.has_css_class("numeric")) + + def test_release_column(self, i: int = 6): + """Test the release date column.""" + self.assertEqual(self.columns[i].get_title(), "Release") + self.assertEqual(self.columns[i].get_fixed_width(), 115) + self.assertTrue(self.columns[i].get_resizable()) + self.assertTrue(self.columns[i].get_visible()) + + factory = self.columns[i].get_factory() + self.assertIsInstance(factory, emmental.factory.Factory) + self.assertEqual(factory.row_type, emmental.tracklist.row.AlbumString) + + factory.emit("setup", self.listitem) + self.assertEqual(self.listitem.listrow.property, "release") + self.assertEqual(self.listitem.listrow.child.get_xalign(), 0.0) + self.assertTrue(self.listitem.listrow.child.has_css_class("numeric")) + + def test_playcount_column(self, i: int = 7): """Test the play count column.""" self.assertEqual(self.columns[i].get_title(), "Play Count") self.assertEqual(self.columns[i].get_fixed_width(), 135) @@ -190,7 +222,7 @@ class TestTrackViewColumns(tests.util.TestCase): self.assertEqual(self.listitem.listrow.child.get_xalign(), 0.0) self.assertTrue(self.listitem.listrow.child.has_css_class("numeric")) - def test_last_started_column(self, i: int = 6): + def test_last_started_column(self, i: int = 8): """Test the last started column.""" self.assertEqual(self.columns[i].get_title(), "Last Started") self.assertEqual(self.columns[i].get_fixed_width(), 250) @@ -207,7 +239,7 @@ class TestTrackViewColumns(tests.util.TestCase): self.assertEqual(self.listitem.listrow.child.get_xalign(), 0.0) self.assertTrue(self.listitem.listrow.child.has_css_class("numeric")) - def test_last_played_column(self, i: int = 7): + def test_last_played_column(self, i: int = 9): """Test the last played column.""" self.assertEqual(self.columns[i].get_title(), "Last Played") self.assertEqual(self.columns[i].get_fixed_width(), 250) @@ -224,7 +256,7 @@ class TestTrackViewColumns(tests.util.TestCase): self.assertEqual(self.listitem.listrow.child.get_xalign(), 0.0) self.assertTrue(self.listitem.listrow.child.has_css_class("numeric")) - def test_filepath_column(self, i: int = 8): + def test_filepath_column(self, i: int = 10): """Test the last played column.""" self.assertEqual(self.columns[i].get_title(), "Filepath") self.assertEqual(self.columns[i].get_fixed_width(), -1)