1# Copyright 2011-2016 Nick Boultbee
2#           2005 Joe Wreschnig
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 as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8
9from gi.repository import Gtk
10
11from quodlibet import _
12from quodlibet import util
13from quodlibet import config
14from quodlibet import qltk
15from quodlibet.config import RATINGS
16from quodlibet.qltk import Icons
17from quodlibet.qltk import SeparatorMenuItem
18
19
20class ConfirmRateMultipleDialog(qltk.Message):
21    def __init__(self, parent, action_title, count, value):
22        assert count > 1
23
24        title = (_("Are you sure you want to change the "
25                   "rating of all %d songs?") % count)
26        desc = (_("The saved ratings will be removed") if value is None
27                else _("The rating of all selected songs will be changed to "
28                       "'%s'") % util.format_rating(value))
29
30        super(ConfirmRateMultipleDialog, self).__init__(
31            Gtk.MessageType.WARNING, parent, title, desc, Gtk.ButtonsType.NONE)
32
33        self.add_button(_("_Cancel"), Gtk.ResponseType.CANCEL)
34        self.add_button(action_title, Gtk.ResponseType.YES)
35
36
37class RatingsMenuItem(Gtk.ImageMenuItem):
38
39    def __init__(self, songs, library, label=_("_Rating")):
40        super(RatingsMenuItem, self).__init__(label=label, use_underline=True)
41        self._songs = songs
42        image = Gtk.Image.new_from_icon_name(Icons.FAVORITE, Gtk.IconSize.MENU)
43        image.show()
44        self.set_image(image)
45
46        submenu = Gtk.Menu()
47        self.set_submenu(submenu)
48        self._rating_menu_items = []
49        for i in RATINGS.all:
50            text = "%0.2f\t%s" % (i, util.format_rating(i))
51            itm = Gtk.CheckMenuItem(label=text)
52            itm.rating = i
53            submenu.append(itm)
54            handler = itm.connect(
55                'toggled', self._on_rating_change, i, library)
56            self._rating_menu_items.append((itm, handler))
57        reset = Gtk.MenuItem(label=_("_Remove Rating"), use_underline=True)
58        reset.connect('activate', self._on_rating_remove, library)
59        self._select_ratings()
60
61        submenu.append(SeparatorMenuItem())
62        submenu.append(reset)
63        submenu.show_all()
64
65    def set_songs(self, songs):
66        """Set a new set of songs affected by the rating menu"""
67        self._songs = songs
68        self._select_ratings()
69
70    def _select_ratings(self):
71        ratings = [song("~#rating") for song in self._songs
72                   if song and song.has_rating]
73        song_count = len(self._songs)
74        for (menu_item, handler) in self._rating_menu_items:
75            rating_val = menu_item.rating
76            rated_count = ratings.count(rating_val)
77            menu_item.handler_block(handler)
78            if rated_count == 0:
79                menu_item.set_active(False)
80            elif rated_count == song_count:
81                menu_item.set_active(True)
82            else:
83                menu_item.set_inconsistent(True)
84            menu_item.handler_unblock(handler)
85
86    def _on_rating_change(self, menuitem, value, library):
87        self.set_rating(value, self._songs, library)
88
89    def _on_rating_remove(self, menutitem, library):
90        self.remove_rating(self._songs, library)
91
92    def set_rating(self, value, songs, librarian):
93        count = len(songs)
94        if (count > 1 and
95                config.getboolean("browsers", "rating_confirm_multiple")):
96            parent = qltk.get_menu_item_top_parent(self)
97            dialog = ConfirmRateMultipleDialog(
98                parent, _("Change _Rating"), count, value)
99            if dialog.run() != Gtk.ResponseType.YES:
100                return
101        for song in songs:
102            song["~#rating"] = value
103        librarian.changed(songs)
104
105    def remove_rating(self, songs, librarian):
106        count = len(songs)
107        if (count > 1 and
108                config.getboolean("browsers", "rating_confirm_multiple")):
109            parent = qltk.get_menu_item_top_parent(self)
110            dialog = ConfirmRateMultipleDialog(
111                parent, _("_Remove Rating"), count, None)
112            if dialog.run() != Gtk.ResponseType.YES:
113                return
114        reset = []
115        for song in songs:
116            if "~#rating" in song:
117                del song["~#rating"]
118                reset.append(song)
119        librarian.changed(reset)
120