~ubuntu-branches/ubuntu/karmic/quodlibet/karmic

« back to all changes in this revision

Viewing changes to qltk/information.py

  • Committer: Bazaar Package Importer
  • Author(s): Luca Falavigna
  • Date: 2009-01-30 23:55:34 UTC
  • mfrom: (1.1.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20090130235534-l4e72ulw0vqfo17w
Tags: 2.0-1ubuntu1
* Merge from Debian experimental (LP: #276856), remaining Ubuntu changes:
  + debian/patches/40-use-music-profile.patch:
    - Use the "Music and Movies" pipeline per default.
* Refresh the above patch for new upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: utf-8 -*-
2
 
# Copyright 2004-2005 Joe Wreschnig, Michael Urman, Iñigo Serna
3
 
#
4
 
# This program is free software; you can redistribute it and/or modify
5
 
# it under the terms of the GNU General Public License version 2 as
6
 
# published by the Free Software Foundation
7
 
#
8
 
# $Id: information.py 4020 2007-04-26 04:37:42Z piman $
9
 
 
10
 
import time
11
 
 
12
 
import gtk
13
 
import pango
14
 
 
15
 
import const
16
 
import qltk
17
 
import util
18
 
 
19
 
from qltk.bookmarks import EditBookmarksPane
20
 
from qltk.cover import CoverImage
21
 
from qltk.lyrics import LyricsPane
22
 
from qltk.x import Window
23
 
from util import tag
24
 
 
25
 
def Label(*args):
26
 
    l = gtk.Label(*args)
27
 
    l.set_selectable(True)
28
 
    l.set_alignment(0, 0)
29
 
    return l
30
 
 
31
 
def Frame(name, widget):
32
 
    f = gtk.Frame()
33
 
    f.set_shadow_type(gtk.SHADOW_NONE)
34
 
    l = gtk.Label()
35
 
    l.set_markup("<u><b>%s</b></u>" % name)
36
 
    f.set_label_widget(l)
37
 
    a = gtk.Alignment(xalign=0, yalign=0, xscale=1, yscale=1)
38
 
    a.set_padding(3, 0, 12, 0)
39
 
    f.add(a)
40
 
    a.add(widget)
41
 
    return f
42
 
 
43
 
def SW():
44
 
    swin = gtk.ScrolledWindow()
45
 
    swin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
46
 
    return swin
47
 
 
48
 
class ErrorPane(gtk.VBox):
49
 
    def __init__(self, song):
50
 
        super(ErrorPane, self).__init__(spacing=6)
51
 
        self.set_border_width(12)
52
 
        sw = gtk.ScrolledWindow()
53
 
        view = gtk.TextView()
54
 
        view.get_buffer().set_text(song.get("~errors", ""))
55
 
        view.set_wrap_mode(gtk.WRAP_WORD)
56
 
        sw.add(view)
57
 
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
58
 
        sw.set_shadow_type(gtk.SHADOW_IN)
59
 
        button = qltk.Button(_("_Clear Errors"), gtk.STOCK_DIALOG_ERROR)
60
 
        button.connect('clicked', self.__clear_errors, song, view)
61
 
        view.set_editable(False)
62
 
        self.pack_start(sw, expand=True, fill=True)
63
 
        self.pack_start(button, expand=False, fill=True)
64
 
 
65
 
    def __clear_errors(self, button, song, view):
66
 
        try: del(song["~errors"])
67
 
        except KeyError: pass
68
 
        view.get_buffer().set_text("")
69
 
 
70
 
class NoSongs(gtk.Label):
71
 
    def __init__(self):
72
 
        super(NoSongs, self).__init__(_("No songs are selected."))
73
 
        self.title = _("No Songs")
74
 
 
75
 
class OneSong(qltk.Notebook):
76
 
    def __init__(self, library, song):
77
 
        super(OneSong, self).__init__()
78
 
        vbox = gtk.VBox(spacing=12)
79
 
        vbox.set_border_width(12)
80
 
        self._title(song, vbox)
81
 
        self._album(song, vbox)
82
 
        self._people(song, vbox)
83
 
        self._library(song, vbox)
84
 
        self._file(song, vbox)
85
 
        sw = SW()
86
 
        sw.title = _("Information")
87
 
        sw.add_with_viewport(vbox)
88
 
        self.append_page(sw)
89
 
        lyrics = LyricsPane(song)
90
 
        lyrics.title = _("Lyrics")
91
 
        self.append_page(lyrics)
92
 
 
93
 
        bookmarks = EditBookmarksPane(None, song)
94
 
        bookmarks.title = _("Bookmarks")
95
 
        bookmarks.set_border_width(12)
96
 
        self.append_page(bookmarks)
97
 
 
98
 
        if "~errors" in song:
99
 
            errors = ErrorPane(song)
100
 
            errors.title = _("Errors")
101
 
            self.append_page(errors)
102
 
 
103
 
        s = library.connect('changed', self.__check_changed, vbox, song)
104
 
        self.connect_object('destroy', library.disconnect, s)
105
 
 
106
 
    def __check_changed(self, library, songs, vbox, song):
107
 
        if song in songs:
108
 
            for c in vbox.get_children():
109
 
                vbox.remove(c)
110
 
                c.destroy()
111
 
            self._title(song, vbox)
112
 
            self._album(song, vbox)
113
 
            self._people(song, vbox)
114
 
            self._library(song, vbox)
115
 
            self._file(song, vbox)
116
 
            parent = qltk.get_top_parent(self)
117
 
            if parent:
118
 
                parent.set_title(self.title + " - Quod Libet")
119
 
            vbox.show_all()
120
 
 
121
 
    def _title(self, song, box):
122
 
        l = Label()
123
 
        text = "<big><b>%s</b></big>" % util.escape(song("title"))
124
 
        if "version" in song:
125
 
            text += "\n" + util.escape(song.comma("version"))
126
 
        l.set_markup(text)
127
 
        l.set_ellipsize(pango.ELLIPSIZE_END)
128
 
        box.pack_start(l, expand=False, fill=False)
129
 
        self.title = song("title")
130
 
 
131
 
    def _album(self, song, box):
132
 
        if "album" not in song: return
133
 
        w = Label("")
134
 
        text = []
135
 
        text.append("<i>%s</i>" % util.escape(song.comma("album")))
136
 
        if "date" in song:
137
 
            text[-1] += " (%s)" % util.escape(song.comma("date"))
138
 
        secondary = []
139
 
        if "discnumber" in song:
140
 
            secondary.append(_("Disc %s") % song["discnumber"])
141
 
        if "part" in song:
142
 
            secondary.append("<i>%s</i>" %
143
 
                             util.escape(song.comma("part")))
144
 
        if "tracknumber" in song:
145
 
            secondary.append(_("Track %s") % song["tracknumber"])
146
 
        if secondary: text.append(" - ".join(secondary))
147
 
 
148
 
        if "organization" in song or "labelid" in song:
149
 
            t = util.escape(song.comma("~organization~labelid"))
150
 
            text.append(t)
151
 
 
152
 
        if "producer" in song:
153
 
            text.append("Produced by %s" %(
154
 
                util.escape(song.comma("producer"))))
155
 
 
156
 
        w.set_markup("\n".join(text))
157
 
        w.set_ellipsize(pango.ELLIPSIZE_END)
158
 
        hb = gtk.HBox(spacing=12)
159
 
 
160
 
        cover = CoverImage([70, 70], song)
161
 
        if cover: hb.pack_start(cover, expand=False)
162
 
        else: cover.destroy()
163
 
                            
164
 
        hb.pack_start(w)
165
 
        box.pack_start(Frame(tag("album"), hb), expand=False, fill=False)
166
 
 
167
 
    def _people(self, song, box):
168
 
        vb = gtk.VBox()
169
 
        if "artist" in song:
170
 
            if len(song.list("artist")) == 1: title = _("artist")
171
 
            else: title = _("artists")
172
 
            title = util.capitalize(title)
173
 
            l = Label(song["artist"])
174
 
            l.set_ellipsize(pango.ELLIPSIZE_END)
175
 
            vb.pack_start(l, expand=False)
176
 
        else:
177
 
            title = tag("~people")
178
 
        for names, tag_ in [
179
 
            ("performers", "performer"),
180
 
            ("lyricists", "lyricist"),
181
 
            ("arrangers", "arranger"),
182
 
            ("composers", "composer"),
183
 
            ("conductors", "conductor"),
184
 
            ("authors", "author")]:
185
 
            if tag_ in song:
186
 
                l = Label(song[tag_])
187
 
                l.set_ellipsize(pango.ELLIPSIZE_END)
188
 
                if len(song.list(tag_)) == 1: name = tag(tag_)
189
 
                else: name = _(names)
190
 
                vb.pack_start(Frame(util.capitalize(name), l), expand=False)
191
 
        if not vb.get_children(): vb.destroy()
192
 
        else: box.pack_start(Frame(title, vb), expand=False, fill=False)
193
 
 
194
 
    def _library(self, song, box):
195
 
        def counter(i):
196
 
            if i == 0: return _("Never")
197
 
            else: return ngettext("%d time", "%d times", i) % i
198
 
        def ftime(t):
199
 
            if t == 0:
200
 
                return _("Unknown")
201
 
            else:
202
 
                timestr = time.strftime("%c", time.localtime(t))
203
 
                return timestr.decode(const.ENCODING)
204
 
 
205
 
        playcount = counter(song.get("~#playcount", 0))
206
 
        skipcount = counter(song.get("~#skipcount", 0))
207
 
        lastplayed = ftime(song.get("~#lastplayed", 0))
208
 
        if lastplayed == _("Unknown"):
209
 
            lastplayed = _("Never")
210
 
        added = ftime(song.get("~#added", 0))
211
 
        rating = song("~rating")
212
 
 
213
 
        t = gtk.Table(5, 2)
214
 
        t.set_col_spacings(6)
215
 
        t.set_homogeneous(False)
216
 
        table = [(_("added"), added),
217
 
                 (_("last played"), lastplayed),
218
 
                 (_("plays"), playcount),
219
 
                 (_("skips"), skipcount),
220
 
                 (_("rating"), rating)]
221
 
 
222
 
        for i, (l, r) in enumerate(table):
223
 
            l = "<b>%s</b>" % util.capitalize(util.escape(l) + ":")
224
 
            lab = Label()
225
 
            lab.set_markup(l)
226
 
            t.attach(lab, 0, 1, i + 1, i + 2, xoptions=gtk.FILL)
227
 
            t.attach(Label(r), 1, 2, i + 1, i + 2)
228
 
 
229
 
        box.pack_start(Frame(_("Library"), t), expand=False, fill=False)
230
 
 
231
 
    def _file(self, song, box):
232
 
        def ftime(t):
233
 
            if t == 0:
234
 
                return _("Unknown")
235
 
            else:
236
 
                timestr = time.strftime("%c", time.localtime(t))
237
 
                return timestr.decode(const.ENCODING)
238
 
 
239
 
        fn = util.fsdecode(util.unexpand(song["~filename"]))
240
 
        length = util.format_time_long(song["~#length"])
241
 
        size = util.format_size(util.size(song["~filename"]))
242
 
        mtime = ftime(util.mtime(song["~filename"]))
243
 
        if "~#bitrate" in song and song["~#bitrate"] != 0:
244
 
            bitrate = _("%d kbps") % int(song["~#bitrate"]/1000)
245
 
        else: bitrate = False
246
 
 
247
 
        t = gtk.Table(4, 2)
248
 
        t.set_col_spacings(6)
249
 
        t.set_homogeneous(False)
250
 
        table = [(_("length"), length),
251
 
                 (_("file size"), size),
252
 
                 (_("modified"), mtime)]
253
 
        if bitrate:
254
 
            table.insert(1, (_("bitrate"), bitrate))
255
 
        fnlab = Label(fn)
256
 
        fnlab.set_ellipsize(pango.ELLIPSIZE_MIDDLE)
257
 
        t.attach(fnlab, 0, 2, 0, 1, xoptions=gtk.FILL)
258
 
        for i, (l, r) in enumerate(table):
259
 
            l = "<b>%s</b>" % util.capitalize(util.escape(l) + ":")
260
 
            lab = Label()
261
 
            lab.set_markup(l)
262
 
            t.attach(lab, 0, 1, i + 1, i + 2, xoptions=gtk.FILL)
263
 
            t.attach(Label(r), 1, 2, i + 1, i + 2)
264
 
 
265
 
        box.pack_start(Frame(_("File"), t), expand=False, fill=False)
266
 
 
267
 
class OneAlbum(qltk.Notebook):
268
 
    def __init__(self, songs):
269
 
        super(OneAlbum, self).__init__()
270
 
        swin = SW()
271
 
        swin.title = _("Information")
272
 
        vbox = gtk.VBox(spacing=12)
273
 
        vbox.set_border_width(12)
274
 
        swin.add_with_viewport(vbox)
275
 
        # Needed to get proper track/disc/part ordering
276
 
        songs = sorted(songs)
277
 
        self._title(songs, vbox)
278
 
        self._album(songs, vbox)
279
 
        self._people(songs, vbox)
280
 
        self._description(songs, vbox)
281
 
        self.append_page(swin)
282
 
 
283
 
    def _title(self, songs, box):
284
 
        song = songs[0]
285
 
        l = Label()
286
 
        l.set_ellipsize(pango.ELLIPSIZE_END)
287
 
        text = "<big><b>%s</b></big>" % util.escape(song["album"])
288
 
        if "date" in song: text += "\n" + song["date"]
289
 
        l.set_markup(text)
290
 
        box.pack_start(l, expand=False, fill=False)
291
 
        self.title = song["album"]
292
 
 
293
 
    def _album(self, songs, box):
294
 
        text = []
295
 
 
296
 
        discs = {}
297
 
        for song in songs:
298
 
            try:
299
 
                discs[song("~#disc")] = int(
300
 
                    song["tracknumber"].split("/")[1])
301
 
            except (AttributeError, ValueError, IndexError, KeyError):
302
 
                discs[song("~#disc")] = max([
303
 
                    song("~#track", discs.get(song("~#disc"), 0))])
304
 
        tracks = sum(discs.values())
305
 
        discs = len(discs)
306
 
        length = sum([song["~#length"] for song in songs])
307
 
 
308
 
        if tracks == 0 or tracks < len(songs): tracks = len(songs)
309
 
 
310
 
        parts = []
311
 
        if discs > 1:
312
 
            parts.append(
313
 
                ngettext("%d disc", "%d discs", discs) % discs)
314
 
        parts.append(
315
 
                ngettext("%d track", "%d tracks", tracks) % tracks)
316
 
        if tracks != len(songs):
317
 
            parts.append(ngettext("%d selected", "%d selected",
318
 
                len(songs)) % len(songs))
319
 
 
320
 
        text.append(", ".join(parts))
321
 
        text.append(util.format_time_long(length))
322
 
 
323
 
        if "location" in song:
324
 
            text.append(util.escape(song["location"]))
325
 
        if "organization" in song or "labelid" in song:
326
 
            t = util.escape(song.comma("~organization~labelid"))
327
 
            text.append(t)
328
 
 
329
 
        if "producer" in song:
330
 
            text.append(_("Produced by %s") %(
331
 
                util.escape(song.comma("producer"))))
332
 
 
333
 
        w = Label("")
334
 
        w.set_ellipsize(pango.ELLIPSIZE_END)
335
 
        w.set_markup("\n".join(text))
336
 
        hb = gtk.HBox(spacing=12)
337
 
 
338
 
        cover = CoverImage([70, 70], song)
339
 
        if cover: hb.pack_start(cover, expand=False)
340
 
        else: cover.destroy()
341
 
 
342
 
        hb.pack_start(w)
343
 
        box.pack_start(hb, expand=False, fill=False)
344
 
 
345
 
    def _people(self, songs, box):
346
 
        artists = set([])
347
 
        performers = set([])
348
 
        for song in songs:
349
 
            artists.update(song.list("artist"))
350
 
            performers.update(song.list("performer"))
351
 
 
352
 
        artists = sorted(artists)
353
 
        performers = sorted(performers)
354
 
 
355
 
        if artists:
356
 
            if len(artists) == 1: title = _("artist")
357
 
            else: title = _("artists")
358
 
            title = util.capitalize(title)
359
 
            box.pack_start(Frame(title, Label("\n".join(artists))),
360
 
                           expand=False, fill=False)
361
 
        if performers:
362
 
            if len(artists) == 1: title = _("performer")
363
 
            else: title = _("performers")
364
 
            title = util.capitalize(title)
365
 
            box.pack_start(Frame(title, Label("\n".join(performers))),
366
 
                           expand=False, fill=False)
367
 
 
368
 
    def _description(self, songs, box):
369
 
        text = []
370
 
        cur_disc = songs[0]("~#disc", 1) - 1
371
 
        cur_part = None
372
 
        cur_track = songs[0]("~#track", 1) - 1
373
 
        for song in songs:
374
 
            track = song("~#track", 0)
375
 
            disc = song("~#disc", 0)
376
 
            part = song.get("part")
377
 
            if disc != cur_disc:
378
 
                if cur_disc: text.append("")
379
 
                cur_track = song("~#track", 1) - 1
380
 
                cur_part = None
381
 
                cur_disc = disc
382
 
                if disc:
383
 
                    text.append("<b>%s</b>" % (_("Disc %s") % disc))
384
 
            if part != cur_part:
385
 
                ts = "    " * bool(disc)
386
 
                cur_part = part
387
 
                if part:
388
 
                    text.append("%s<b>%s</b>" %(ts, util.escape(part)))
389
 
            cur_track += 1
390
 
            ts = "    " * (bool(disc) + bool(part))
391
 
            while cur_track < track:
392
 
                text.append("%s<b>%d.</b> <i>%s</i>" %(
393
 
                    ts, cur_track, _("Track unavailable")))
394
 
                cur_track += 1
395
 
            text.append("%s<b>%d.</b> %s" %(
396
 
                ts, track, util.escape(song.comma("~title~version"))))
397
 
        l = Label()
398
 
        l.set_markup("\n".join(text))
399
 
        l.set_ellipsize(pango.ELLIPSIZE_END)
400
 
        box.pack_start(Frame(_("Track List"), l), expand=False, fill=False)
401
 
 
402
 
class OneArtist(qltk.Notebook):
403
 
    def __init__(self, songs):
404
 
        super(OneArtist, self).__init__()
405
 
        swin = SW()
406
 
        swin.title = _("Information")
407
 
        vbox = gtk.VBox(spacing=12)
408
 
        vbox.set_border_width(12)
409
 
        swin.add_with_viewport(vbox)
410
 
        self._title(songs, vbox)
411
 
        self._album(songs, vbox)
412
 
        self.append_page(swin)
413
 
 
414
 
    def _title(self, songs, box):
415
 
        l = Label()
416
 
        l.set_ellipsize(pango.ELLIPSIZE_END)
417
 
        artist = util.escape(songs[0]("artist"))
418
 
        l.set_markup("<b><big>%s</big></b>" % artist)
419
 
        box.pack_start(l, expand=False, fill=False)
420
 
        self.title = songs[0]["artist"]
421
 
 
422
 
    def _album(self, songs, box):
423
 
        noalbum = 0
424
 
        albums = {}
425
 
        for song in songs:
426
 
            if "album" in song:
427
 
                albums[song.list("album")[0]] = song
428
 
            else: noalbum += 1
429
 
        albums = [(song.get("date"), song, album) for
430
 
                  album, song in albums.items()]
431
 
        albums.sort()
432
 
        def format((date, song, album)):
433
 
            if date: return "%s (%s)" % (album, date[:4])
434
 
            else: return album
435
 
        covers = [(a, s.find_cover(), s) for d, s, a in albums]
436
 
        albums = map(format, albums)
437
 
        if noalbum:
438
 
            albums.append(ngettext("%d song with no album",
439
 
                "%d songs with no album", noalbum) % noalbum)
440
 
        l = Label("\n".join(albums))
441
 
        l.set_ellipsize(pango.ELLIPSIZE_END)
442
 
        box.pack_start(Frame(_("Selected Discography"), l))
443
 
 
444
 
        tips = qltk.Tooltips(self)
445
 
        covers = [ac for ac in covers if bool(ac[1])]
446
 
        t = gtk.Table(4, (len(covers) // 4) + 1)
447
 
        t.set_col_spacings(12)
448
 
        t.set_row_spacings(12)
449
 
        added = set()
450
 
        for i, (album, cover, song) in enumerate(covers):
451
 
            if cover.name in added: continue
452
 
            cov = CoverImage([70, 70], song)
453
 
            tips.set_tip(cov.child, album)
454
 
            c = i % 4
455
 
            r = i // 4
456
 
            t.attach(cov, c, c + 1, r, r + 1,
457
 
                     xoptions=gtk.EXPAND, yoptions=0)
458
 
            added.add(cover.name)
459
 
        box.pack_start(t)
460
 
 
461
 
class ManySongs(qltk.Notebook):
462
 
    def __init__(self, songs):
463
 
        super(ManySongs, self).__init__()
464
 
        swin = SW()
465
 
        swin.title = _("Information")
466
 
        vbox = gtk.VBox(spacing=12)
467
 
        vbox.set_border_width(12)
468
 
        swin.add_with_viewport(vbox)
469
 
        self._title(songs, vbox)
470
 
        self._people(songs, vbox)
471
 
        self._album(songs, vbox)
472
 
        self._file(songs, vbox)
473
 
        self.append_page(swin)
474
 
 
475
 
    def _title(self, songs, box):
476
 
        l = Label()
477
 
        t = ngettext("%d song", "%d songs", len(songs)) % len(songs)
478
 
        l.set_markup("<big><b>%s</b></big>" % t)
479
 
        self.title = t
480
 
        box.pack_start(l, expand=False, fill=False)
481
 
 
482
 
    def _people(self, songs, box):
483
 
        artists = set([])
484
 
        none = 0
485
 
        for song in songs:
486
 
            if "artist" in song: artists.update(song.list("artist"))
487
 
            else: none += 1
488
 
        artists = sorted(artists)
489
 
        num_artists = len(artists)
490
 
 
491
 
        if none: artists.append(ngettext("%d song with no artist",
492
 
                "%d songs with no artist", none) % none)
493
 
        box.pack_start(Frame(
494
 
            "%s (%d)" % (util.capitalize(_("artists")), num_artists),
495
 
            Label("\n".join(artists))),
496
 
                        expand=False, fill=False)
497
 
 
498
 
    def _album(self, songs, box):
499
 
        albums = set([])
500
 
        none = 0
501
 
        for song in songs:
502
 
            if "album" in song: albums.update(song.list("album"))
503
 
            else: none += 1
504
 
        albums = sorted(albums)
505
 
        num_albums = len(albums)
506
 
 
507
 
        if none: albums.append(ngettext("%d song with no album",
508
 
            "%d songs with no album", none) % none)
509
 
        box.pack_start(Frame(
510
 
            "%s (%d)" % (util.capitalize(_("albums")), num_albums),
511
 
            Label("\n".join(albums))),
512
 
                        expand=False, fill=False)
513
 
 
514
 
    def _file(self, songs, box):
515
 
        time = 0
516
 
        size = 0
517
 
        for song in songs:
518
 
            time += song["~#length"]
519
 
            try: size += util.size(song["~filename"])
520
 
            except EnvironmentError: pass
521
 
        table = gtk.Table(2, 2)
522
 
        table.set_col_spacings(6)
523
 
        table.attach(Label(_("Total length:")), 0, 1, 0, 1,
524
 
                     xoptions=gtk.FILL)
525
 
        table.attach(
526
 
            Label(util.format_time_long(time)), 1, 2, 0, 1)
527
 
        table.attach(Label(_("Total size:")), 0, 1, 1, 2,
528
 
                     xoptions=gtk.FILL)
529
 
        table.attach(Label(util.format_size(size)), 1, 2, 1, 2)
530
 
        box.pack_start(Frame(_("Files"), table),
531
 
                       expand=False, fill=False)
532
 
 
533
 
class Information(Window):
534
 
    def __init__(self, library, songs):
535
 
        super(Information, self).__init__()
536
 
        self.set_border_width(12)
537
 
        self.set_default_size(400, 400)
538
 
        if len(songs) > 1:
539
 
            sig = library.connect('changed', self.__check_changed)
540
 
            self.connect_object('destroy', library.disconnect, sig)
541
 
        if len(songs) > 0:
542
 
            sig = library.connect('removed', self.__check_removed)
543
 
            self.connect_object('destroy', library.disconnect, sig)
544
 
        self.__songs = songs
545
 
        self.__update(library)
546
 
        self.show_all()
547
 
 
548
 
    def __check_changed(self, library, songs):
549
 
        changed = set(songs)
550
 
        for song in self.__songs:
551
 
            if song in changed:
552
 
                self.__update(library)
553
 
                break
554
 
 
555
 
    def __check_removed(self, library, songs):
556
 
        gone = set(songs)
557
 
        old = len(self.__songs)
558
 
        self.__songs = filter(lambda s: s not in gone, self.__songs)
559
 
        if len(self.__songs) != old: self.__update(library)
560
 
 
561
 
    def __update(self, library):
562
 
        songs = self.__songs
563
 
        if self.child: self.child.destroy()
564
 
        self.__songs = songs
565
 
        if not songs: self.add(NoSongs())
566
 
        elif len(songs) == 1: self.add(OneSong(library, songs[0]))
567
 
        else:
568
 
            tags = [(s.get("artist"), s.get("album")) for s in songs]
569
 
            artists, albums = zip(*tags)
570
 
            if min(albums) == max(albums) and albums[0]:
571
 
                self.add(OneAlbum(songs))
572
 
            elif min(artists) == max(artists) and artists[0]:
573
 
                self.add(OneArtist(songs))
574
 
            else: self.add(ManySongs(songs))
575
 
 
576
 
        self.set_title(self.child.title + " - Quod Libet")
577
 
        self.child.show_all()