mpclient: change info from function to var.
[nephilim.git] / nephilim / plugins / Library.py
blob74c5464fb333a74546d83daec2e8fb61bd8da625
2 # Copyright (C) 2009 Anton Khirnov <wyskas@gmail.com>
4 # Nephilim 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 3 of the License, or
7 # (at your option) any later version.
9 # Nephilim is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with Nephilim. If not, see <http://www.gnu.org/licenses/>.
18 from PyQt4 import QtGui, QtCore
19 from PyQt4.QtCore import QVariant
21 from ..plugin import Plugin
23 class Library(Plugin):
24 # public, const
25 info = 'Display MPD database as a tree.'
27 # public, read-only
28 o=None
29 DEFAULTS = {'modes' : QtCore.QStringList(['artist',
30 'artist/album',
31 'artist/date/album',
32 'genre',
33 'genre/artist',
34 'genre/artist/album'])}
36 def _load(self):
37 self.o = LibraryWidget(self)
38 def _unload(self):
39 self.o = None
41 def getInfo(self):
42 return "List showing all the songs allowing filtering and grouping."
44 def _get_dock_widget(self):
45 return self._create_dock(self.o)
47 def fill_library(self, params):
48 if not self.o:
49 return
50 self.o.fill_library()
52 class SettingsWidgetLibrary(Plugin.SettingsWidget):
53 modes = None
54 def __init__(self, plugin):
55 Plugin.SettingsWidget.__init__(self, plugin)
56 self.setLayout(QtGui.QVBoxLayout())
58 self.modes = QtGui.QComboBox()
59 self.modes.setEditable(True)
60 for mode in self.settings.value(self.plugin.name + '/modes').toStringList():
61 self.modes.addItem(mode)
62 self._add_widget(self.modes, 'Modes', 'How should the songs in library be grouped.\n'
63 'Should be written in form tag1/tag2/...,\n'
64 'using tags supported by MPD.')
66 def save_settings(self):
67 modes = QtCore.QStringList()
68 for i in range(0, self.modes.count()):
69 modes.append(self.modes.itemText(i))
70 self.settings.setValue(self.plugin.name + '/modes', QVariant(modes))
71 self.plugin.o.refresh_modes()
73 def get_settings_widget(self):
74 return self.SettingsWidgetLibrary(self)
77 class LibraryWidget(QtGui.QWidget):
78 library_view = None
79 library_model = None
80 search_txt = None
81 modes = None
82 settings = None
83 plugin = None
84 logger = None
86 class LibraryModel(QtGui.QStandardItemModel):
87 def fill(self, songs, mode):
88 self.clear()
90 tree = [{},self.invisibleRootItem()]
91 for song in songs:
92 cur_item = tree
93 for part in mode.split('/'):
94 tag = song.tag(part)
95 if isinstance(tag, list):
96 tag = tag[0] #FIXME hack to make songs with multiple genres work.
97 if not tag:
98 tag = 'Unknown'
99 if tag in cur_item[0]:
100 cur_item = cur_item[0][tag]
101 else:
102 it = QtGui.QStandardItem(tag)
103 it.setFlags(QtCore.Qt.ItemIsSelectable|QtCore.Qt.ItemIsEnabled)
104 cur_item[1].appendRow(it)
105 cur_item[0][tag] = [{}, it]
106 cur_item = cur_item[0][tag]
107 it = QtGui.QStandardItem('%s%02d %s'%(song.tag('disc') + '/' if song.tag('disc') else '',
108 song.track() if song.track() else 0,
109 song.title() if song.title() else song.filepath()))
110 it.setFlags(QtCore.Qt.ItemIsSelectable|QtCore.Qt.ItemIsEnabled)
111 it.setData(QVariant(song), QtCore.Qt.UserRole)
112 cur_item[1].appendRow(it)
114 self.sort(0, QtCore.Qt.AscendingOrder)
116 class LibraryView(QtGui.QTreeView):
117 def __init__(self):
118 QtGui.QTreeView.__init__(self)
120 self.setAlternatingRowColors(True)
121 self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
122 self.setUniformRowHeights(True)
123 self.setHeaderHidden(True)
125 def selectedItems(self):
126 ret = []
127 for index in self.selectedIndexes():
128 ret.append(self.model().itemFromIndex(index))
130 return ret
132 def __init__(self, plugin):
133 QtGui.QWidget.__init__(self)
134 self.plugin = plugin
135 self.logger = plugin.logger
136 self.settings = QtCore.QSettings()
137 self.settings.beginGroup(self.plugin.name)
139 self.modes = QtGui.QComboBox()
140 self.refresh_modes()
141 self.modes.activated.connect(self.modes_activated)
143 self.search_txt = QtGui.QLineEdit()
144 self.search_txt.textChanged.connect(self.filter_changed)
145 self.search_txt.returnPressed.connect(self.add_filtered)
147 #construct the library
148 self.library_model = self.LibraryModel()
149 self.fill_library()
151 self.library_view = self.LibraryView()
152 self.library_view.setModel(self.library_model)
153 self.library_view.activated.connect(self.add_selection)
155 self.setLayout(QtGui.QVBoxLayout())
156 self.layout().setSpacing(2)
157 self.layout().setMargin(0)
158 self.layout().addWidget(self.modes)
159 self.layout().addWidget(self.search_txt)
160 self.layout().addWidget(self.library_view)
162 self.plugin.mpclient.connect_changed.connect(self.fill_library)
163 self.plugin.mpclient.db_updated.connect(self.fill_library)
165 def refresh_modes(self):
166 self.modes.clear()
167 for mode in self.settings.value('/modes').toStringList():
168 self.modes.addItem(mode)
169 self.modes.setCurrentIndex(self.settings.value('current_mode').toInt()[0])
171 def fill_library(self):
172 self.logger.info('Refreshing library.')
173 self.library_model.fill(self.plugin.mpclient.library(), str(self.modes.currentText()))
175 def filter_changed(self, text):
176 items = self.library_model.findItems(text, QtCore.Qt.MatchContains|QtCore.Qt.MatchRecursive)
177 for i in range(self.library_model.rowCount()):
178 self.library_view.setRowHidden(i, QtCore.QModelIndex(), True)
179 for item in items:
180 while item.parent():
181 item = item.parent()
182 self.library_view.setRowHidden(item.row(), QtCore.QModelIndex(), False)
183 self.filtered_items = items
185 def add_filtered(self):
186 self.add_items(self.filtered_items)
187 self.search_txt.clear()
189 def add_selection(self):
190 self.add_items(self.library_view.selectedItems())
192 def add_items(self, items):
193 paths = []
194 for item in items:
195 self.item_to_playlist(item, paths)
196 self.plugin.mpclient.add(paths)
198 def item_to_playlist(self, item, add_queue):
199 if not item.hasChildren():
200 add_queue.append(item.data(QtCore.Qt.UserRole).toPyObject().filepath())
201 else:
202 for i in range(item.rowCount()):
203 self.item_to_playlist(item.child(i), add_queue)
205 def modes_activated(self):
206 self.settings.setValue('current_mode', QVariant(self.modes.currentIndex()))
207 self.fill_library()