1# Copyright 2012 Christoph Reiter 2# 3# This program is free software; you can redistribute it and/or modify 4# it under the terms of the GNU General Public License as published by 5# the Free Software Foundation; either version 2 of the License, or 6# (at your option) any later version. 7 8from gi.repository import Gtk 9 10from quodlibet import _ 11from quodlibet.plugins.songsmenu import SongsMenuPlugin 12from quodlibet.util.tags import MACHINE_TAGS 13from quodlibet.util import build_filter_query 14from quodlibet.qltk import Window, Icons, Button 15 16 17class SelectionWindow(Window): 18 def __init__(self, filters, browser, parent=None): 19 super(SelectionWindow, self).__init__() 20 self.set_border_width(10) 21 self.set_title(FilterAll.PLUGIN_NAME) 22 self.set_default_size(200, 250) 23 self.set_transient_for(parent) 24 25 model = Gtk.ListStore(bool, str, str) 26 for key, value in sorted(filters.items()): 27 model.append(row=[False, key, value]) 28 29 toggle = Gtk.CellRendererToggle() 30 toggle.connect("toggled", self.__toggeled, model, browser) 31 text = Gtk.CellRendererText() 32 33 toggle_column = Gtk.TreeViewColumn("", toggle, active=0) 34 column = Gtk.TreeViewColumn(_("Tag"), text, text=1) 35 36 view = Gtk.TreeView(model) 37 view.append_column(toggle_column) 38 view.append_column(column) 39 40 sw = Gtk.ScrolledWindow() 41 sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) 42 sw.set_shadow_type(Gtk.ShadowType.IN) 43 sw.add(view) 44 45 buttons = Gtk.HButtonBox() 46 buttons.set_spacing(6) 47 buttons.set_layout(Gtk.ButtonBoxStyle.END) 48 close = Button(_("_Close"), Icons.WINDOW_CLOSE) 49 close.connect('clicked', lambda *x: self.destroy()) 50 buttons.pack_start(close, True, True, 0) 51 52 box = Gtk.VBox(spacing=12) 53 box.pack_start(sw, True, True, 0) 54 box.pack_start(buttons, False, True, 0) 55 56 self.add(box) 57 58 self.show_all() 59 60 def __filter(self, model, browser): 61 selected = {} 62 for row in model: 63 sel, key, value = row 64 if sel: 65 selected[key] = value 66 67 joined = ", ".join(sorted(selected.values())) 68 if len(selected) >= 2: 69 joined = "&(%s)" % joined 70 71 browser.filter_text(joined) 72 73 def __toggeled(self, render, path, model, browser): 74 model[path][0] = not model[path][0] 75 self.__filter(model, browser) 76 77 78class FilterAll(SongsMenuPlugin): 79 PLUGIN_ID = "FilterAll" 80 PLUGIN_NAME = _("Filter on Any Tag") 81 PLUGIN_DESC = _("Creates a search query based on " 82 "tags of the selected songs.") 83 PLUGIN_ICON = Icons.EDIT_FIND 84 REQUIRES_ACTION = True 85 86 def plugin_songs(self, songs): 87 browser = self.plugin_window.browser 88 if not browser.can_filter_text(): 89 return 90 91 keys = {key for song in songs 92 for key in song.realkeys()} 93 keys.difference_update(MACHINE_TAGS) 94 95 filters = {} 96 for key in keys: 97 values = set() 98 for song in songs: 99 values.update(song.list(key)) 100 filters[key] = build_filter_query(key, values) 101 102 SelectionWindow(filters, browser, parent=self.plugin_window) 103