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