1# This program is free software; you can redistribute it and/or modify 2# it under the terms of the GNU General Public License as published by 3# the Free Software Foundation; either version 2 of the License, or 4# (at your option) any later version. 5 6from gi.repository import Gtk 7from senf import fsnative 8 9from tests import TestCase 10 11from quodlibet.library import SongLibrary 12from quodlibet.qltk.songlist import SongList, set_columns, get_columns, \ 13 header_tag_split, get_sort_tag 14from quodlibet.formats import AudioFile 15from quodlibet import config 16 17 18class TSongList(TestCase): 19 HEADERS = ["acolumn", "~#lastplayed", "~foo~bar", "~#rating", 20 "~#length", "~dirname", "~#track"] 21 22 def setUp(self): 23 config.init() 24 self.songlist = SongList(SongLibrary()) 25 26 self.orders_changed = 0 27 28 def orders_changed_cb(*args): 29 self.orders_changed += 1 30 31 self.songlist.connect("orders-changed", orders_changed_cb) 32 33 def test_set_all_column_headers(self): 34 SongList.set_all_column_headers(self.HEADERS) 35 headers = [col.header_name for col in self.songlist.get_columns()] 36 self.failUnlessEqual(headers, self.HEADERS) 37 38 def test_set_column_headers(self): 39 self.songlist.set_column_headers(self.HEADERS) 40 headers = [col.header_name for col in self.songlist.get_columns()] 41 self.failUnlessEqual(headers, self.HEADERS) 42 43 def test_drop(self): 44 self.songlist.enable_drop() 45 self.songlist.disable_drop() 46 47 def test_sort_by(self): 48 self.songlist.set_column_headers(["one", "two", "three"]) 49 for key, order in [("one", True), 50 ("two", False), 51 ("three", False)]: 52 self.songlist.set_sort_orders([(key, order)]) 53 self.failUnlessEqual( 54 self.songlist.get_sort_orders(), [(key, order)]) 55 56 self.songlist.toggle_column_sort(self.songlist.get_columns()[-1]) 57 self.failUnlessEqual( 58 self.songlist.get_sort_orders(), [("three", True)]) 59 60 def test_sort_orders(self): 61 s = self.songlist 62 63 s.set_column_headers(["foo", "quux", "bar"]) 64 values = [("foo", True), ("bar", False)] 65 s.set_sort_orders(values) 66 self.assertEqual(s.get_sort_orders(), values) 67 68 s.toggle_column_sort(s.get_columns()[1], replace=False) 69 self.assertEqual(s.get_sort_orders(), values + [("quux", False)]) 70 71 s.toggle_column_sort(s.get_columns()[1], replace=True) 72 self.assertEqual(s.get_sort_orders(), [("quux", False)]) 73 74 def test_toggle_sort(self): 75 s = self.songlist 76 77 s.set_column_headers(["foo"]) 78 self.assertEqual(self.orders_changed, 1) 79 s.toggle_column_sort(s.get_columns()[0], replace=True) 80 self.assertEqual(self.orders_changed, 2) 81 self.assertEqual(s.get_sort_orders(), [("foo", False)]) 82 s.toggle_column_sort(s.get_columns()[0], replace=True) 83 self.assertEqual(self.orders_changed, 3) 84 self.assertEqual(s.get_sort_orders(), [("foo", True)]) 85 86 def test_clear_sort(self): 87 s = self.songlist 88 s.set_column_headers(["foo"]) 89 s.toggle_column_sort(s.get_columns()[0], replace=True) 90 self.assertTrue(s.get_sort_orders()) 91 s.clear_sort() 92 self.assertFalse(s.get_sort_orders()) 93 94 def test_not_sortable(self): 95 s = self.songlist 96 s.sortable = False 97 s.set_column_headers(["foo"]) 98 s.toggle_column_sort(s.get_columns()[0]) 99 self.assertEqual(self.orders_changed, 0) 100 self.assertFalse(s.get_sort_orders()) 101 102 def test_find_default_sort_column(self): 103 s = self.songlist 104 self.assertTrue(s.find_default_sort_column() is None) 105 s.set_column_headers(["~#track"]) 106 self.assertTrue(s.find_default_sort_column()) 107 108 def test_inline_search_state(self): 109 self.assertEqual(self.songlist.get_search_column(), 0) 110 self.assertTrue(self.songlist.get_enable_search()) 111 112 def test_set_songs(self): 113 self.songlist.set_songs([], sorted=True) 114 self.songlist.set_songs([], sorted=False) 115 self.songlist.set_songs([], scroll_select=True) 116 self.songlist.set_songs([], scroll_select=False) 117 self.songlist.set_songs([], scroll=True) 118 self.songlist.set_songs([], scroll=False) 119 120 def test_set_songs_restore_select(self): 121 song = AudioFile({"~filename": "/dev/null"}) 122 self.songlist.add_songs([song]) 123 sel = self.songlist.get_selection() 124 sel.select_path(Gtk.TreePath.new_first()) 125 126 self.songlist.set_songs([song], scroll_select=True) 127 self.assertEqual(self.songlist.get_selected_songs(), [song]) 128 129 song2 = AudioFile({"~filename": "/dev/null"}) 130 self.songlist.set_songs([song2], scroll_select=True) 131 self.assertEqual(self.songlist.get_selected_songs(), []) 132 133 def test_set_songs_no_restore_select(self): 134 song = AudioFile({"~filename": "/dev/null"}) 135 self.songlist.add_songs([song]) 136 model = self.songlist.get_model() 137 model.go_to(song) 138 self.assertIs(model.current, song) 139 # only restore if there was a selected one 140 self.songlist.set_songs([song], scroll_select=True) 141 self.assertEqual(self.songlist.get_selected_songs(), []) 142 143 def test_get_selected_songs(self): 144 song = AudioFile({"~filename": "/dev/null"}) 145 self.songlist.add_songs([song]) 146 sel = self.songlist.get_selection() 147 148 sel.select_path(Gtk.TreePath.new_first()) 149 self.assertEqual(self.songlist.get_selected_songs(), [song]) 150 self.assertEqual(self.songlist.get_first_selected_song(), song) 151 152 sel.unselect_all() 153 self.assertEqual(self.songlist.get_selected_songs(), []) 154 self.assertIs(self.songlist.get_first_selected_song(), None) 155 156 def test_add_songs(self): 157 song = AudioFile({"~filename": "/dev/null"}) 158 159 # unsorted 160 self.songlist.add_songs([song]) 161 self.songlist.add_songs([song]) 162 163 # sorted 164 self.songlist.set_column_headers(["foo"]) 165 self.songlist.toggle_column_sort(self.songlist.get_columns()[0]) 166 self.songlist.add_songs([]) 167 self.songlist.add_songs([song]) 168 self.songlist.add_songs([song]) 169 170 self.assertEqual(self.songlist.get_songs(), [song] * 4) 171 172 def test_header_menu(self): 173 from quodlibet import browsers 174 from quodlibet.library import SongLibrary, SongLibrarian 175 176 song = AudioFile({"~filename": fsnative(u"/dev/null")}) 177 song.sanitize() 178 self.songlist.set_songs([song]) 179 180 library = SongLibrary() 181 library.librarian = SongLibrarian() 182 browser = browsers.get("SearchBar")(library) 183 184 self.songlist.set_column_headers(["foo"]) 185 186 self.assertFalse(self.songlist.Menu("foo", browser, library)) 187 sel = self.songlist.get_selection() 188 sel.select_all() 189 self.assertTrue(self.songlist.Menu("foo", browser, library)) 190 191 def test_get_columns_migrated(self): 192 self.failIf(config.get("settings", "headers", None)) 193 columns = "~album,~#replaygain_track_gain,foobar" 194 config.set("settings", "columns", columns) 195 self.failUnlessEqual(get_columns(), 196 ["~album", "~#replaygain_track_gain", "foobar"]) 197 self.failIf(config.get("settings", "headers", None)) 198 199 def test_get_set_columns(self): 200 self.failIf(config.get("settings", "headers", None)) 201 self.failIf(config.get("settings", "columns", None)) 202 columns = ["first", "won't", "two words", "4"] 203 set_columns(columns) 204 self.failUnlessEqual(columns, get_columns()) 205 columns += ["~~another~one"] 206 set_columns(columns) 207 self.failUnlessEqual(columns, get_columns()) 208 self.failIf(config.get("settings", "headers", None)) 209 210 def test_header_tag_split(self): 211 self.assertEqual(header_tag_split("foo"), ["foo"]) 212 self.assertEqual(header_tag_split("~foo~bar"), ["foo", "bar"]) 213 self.assertEqual(header_tag_split("<foo>"), ["foo"]) 214 self.assertEqual(header_tag_split("<~foo~bar>"), ["foo", "bar"]) 215 self.assertEqual(header_tag_split("pattern <~foo~bar>"), 216 ["foo", "bar"]) 217 218 def test_get_sort_tag(self): 219 self.assertEqual(get_sort_tag("~#track"), "") 220 self.assertEqual(get_sort_tag("artist"), "artistsort") 221 self.assertEqual(get_sort_tag("date"), "date") 222 self.assertEqual(get_sort_tag("~artist~date"), "~artistsort~date") 223 self.assertEqual(get_sort_tag("~date~artist"), "~date~artistsort") 224 self.assertEqual(get_sort_tag("composer"), "composersort") 225 226 def tearDown(self): 227 self.songlist.destroy() 228 config.quit() 229