100l - fix some typos in last updates.
[nephilim.git] / nephilim / plugins / Library.py
blob391c7a14ad292249643e13a6710e617f4dd10ba3
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 o=None
25 DEFAULTS = {'modes' : ['artist',
26 'artist/album',
27 'artist/date/album',
28 'genre',
29 'genre/artist',
30 'genre/artist/album']}
32 def _load(self):
33 self.o = LibraryWidget(self)
34 def _unload(self):
35 self.o = None
37 def getInfo(self):
38 return "List showing all the songs allowing filtering and grouping."
40 def _get_dock_widget(self):
41 return self._create_dock(self.o)
43 def fill_library(self, params):
44 if not self.o:
45 return
46 self.o.fill_library()
48 class SettingsWidgetLibrary(Plugin.SettingsWidget):
49 modes = None
50 def __init__(self, plugin):
51 Plugin.SettingsWidget.__init__(self, plugin)
52 self.setLayout(QtGui.QVBoxLayout())
54 self.modes = QtGui.QComboBox()
55 self.modes.setEditable(True)
56 for mode in self.settings().value(self.plugin.name() + '/modes').toStringList():
57 self.modes.addItem(mode)
58 self._add_widget(self.modes, 'Modes', 'How should the songs in library be grouped.\n'
59 'Should be written in form tag1/tag2/...,\n'
60 'using tags supported by MPD.')
62 def save_settings(self):
63 modes = []
64 for i in range(0, self.modes.count()):
65 modes.append(self.modes.itemText(i))
66 self.settings().setValue(self.plugin.name() + '/modes', QVariant(modes))
67 self.plugin.o.refresh_modes()
69 def get_settings_widget(self):
70 return self.SettingsWidgetLibrary(self)
73 class LibraryWidget(QtGui.QWidget):
74 library_view = None
75 library_model = None
76 search_txt = None
77 modes = None
78 settings = None
79 plugin = None
80 logger = None
82 class LibraryModel(QtGui.QStandardItemModel):
83 def fill(self, songs, mode):
84 self.clear()
86 tree = [{},self.invisibleRootItem()]
87 for song in songs:
88 cur_item = tree
89 for part in mode.split('/'):
90 tag = song.tag(part)
91 if isinstance(tag, list):
92 tag = tag[0] #FIXME hack to make songs with multiple genres work.
93 if not tag:
94 tag = 'Unknown'
95 if tag in cur_item[0]:
96 cur_item = cur_item[0][tag]
97 else:
98 it = QtGui.QStandardItem(tag)
99 it.setFlags(QtCore.Qt.ItemIsSelectable|QtCore.Qt.ItemIsEnabled)
100 cur_item[1].appendRow(it)
101 cur_item[0][tag] = [{}, it]
102 cur_item = cur_item[0][tag]
103 it = QtGui.QStandardItem('%s%02d %s'%(song.tag('disc') + '/' if song.tag('disc') else '',
104 song.track() if song.track() else 0,
105 song.title() if song.title() else song.filepath()))
106 it.setFlags(QtCore.Qt.ItemIsSelectable|QtCore.Qt.ItemIsEnabled)
107 it.setData(QVariant(song), QtCore.Qt.UserRole)
108 cur_item[1].appendRow(it)
110 self.sort(0, QtCore.Qt.AscendingOrder)
112 class LibraryView(QtGui.QTreeView):
113 def __init__(self):
114 QtGui.QTreeView.__init__(self)
116 self.setAlternatingRowColors(True)
117 self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
118 self.setUniformRowHeights(True)
119 self.setHeaderHidden(True)
121 def selectedItems(self):
122 ret = []
123 for index in self.selectedIndexes():
124 ret.append(self.model().itemFromIndex(index))
126 return ret
128 def __init__(self, plugin):
129 QtGui.QWidget.__init__(self)
130 self.plugin = plugin
131 self.logger = plugin.logger
132 self.settings = QtCore.QSettings()
133 self.settings.beginGroup(self.plugin.name())
135 self.modes = QtGui.QComboBox()
136 self.refresh_modes()
137 self.connect(self.modes, QtCore.SIGNAL('activated(int)'), self.modes_activated)
139 self.search_txt = QtGui.QLineEdit()
140 self.connect(self.search_txt, QtCore.SIGNAL('textChanged(const QString&)'),
141 self.filter_changed)
142 self.connect(self.search_txt, QtCore.SIGNAL('returnPressed()'), self.add_filtered)
144 #construct the library
145 self.library_model = self.LibraryModel()
146 self.fill_library()
148 self.library_view = self.LibraryView()
149 self.library_view.setModel(self.library_model)
150 self.connect(self.library_view, QtCore.SIGNAL('activated(const QModelIndex &)'), self.add_selection)
152 self.setLayout(QtGui.QVBoxLayout())
153 self.layout().setSpacing(2)
154 self.layout().setMargin(0)
155 self.layout().addWidget(self.modes)
156 self.layout().addWidget(self.search_txt)
157 self.layout().addWidget(self.library_view)
159 self.connect(self.plugin.mpclient(), QtCore.SIGNAL('connected'), self.fill_library)
160 self.connect(self.plugin.mpclient(), QtCore.SIGNAL('disconnected'), self.fill_library)
161 self.connect(self.plugin.mpclient(), QtCore.SIGNAL('db_updated'), self.fill_library)
163 def refresh_modes(self):
164 self.modes.clear()
165 for mode in self.settings.value('/modes').toStringList():
166 self.modes.addItem(mode)
167 self.modes.setCurrentIndex(self.settings.value('current_mode').toInt()[0])
169 def fill_library(self):
170 self.logger.info('Refreshing library.')
171 self.library_model.fill(self.plugin.mpclient().library(), str(self.modes.currentText()))
173 def filter_changed(self, text):
174 items = self.library_model.findItems(text, QtCore.Qt.MatchContains|QtCore.Qt.MatchRecursive)
175 for i in range(self.library_model.rowCount()):
176 self.library_view.setRowHidden(i, QtCore.QModelIndex(), True)
177 for item in items:
178 while item.parent():
179 item = item.parent()
180 self.library_view.setRowHidden(item.row(), QtCore.QModelIndex(), False)
181 self.filtered_items = items
183 def add_filtered(self):
184 self.add_items(self.filtered_items)
185 self.search_txt.clear()
187 def add_selection(self):
188 self.add_items(self.library_view.selectedItems())
190 def add_items(self, items):
191 paths = []
192 for item in items:
193 self.item_to_playlist(item, paths)
194 self.plugin.mpclient().add(paths)
196 def item_to_playlist(self, item, add_queue):
197 if not item.hasChildren():
198 add_queue.append(item.data(QtCore.Qt.UserRole).toPyObject().filepath())
199 else:
200 for i in range(item.rowCount()):
201 self.item_to_playlist(item.child(i), add_queue)
203 def modes_activated(self):
204 self.settings.setValue('current_mode', QVariant(self.modes.currentIndex()))
205 self.fill_library()