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
):
25 info
= 'Display MPD database as a tree.'
29 DEFAULTS
= {'modes' : QtCore
.QStringList(['artist',
34 'genre/artist/album'])}
37 self
.o
= LibraryWidget(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
):
52 class SettingsWidgetLibrary(Plugin
.SettingsWidget
):
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
):
86 class LibraryModel(QtGui
.QStandardItemModel
):
87 def fill(self
, songs
, mode
):
90 tree
= [{},self
.invisibleRootItem()]
93 for part
in mode
.split('/'):
95 if isinstance(tag
, list):
96 tag
= tag
[0] #FIXME hack to make songs with multiple genres work.
99 if tag
in cur_item
[0]:
100 cur_item
= cur_item
[0][tag
]
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
):
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
):
127 for index
in self
.selectedIndexes():
128 ret
.append(self
.model().itemFromIndex(index
))
132 def __init__(self
, plugin
):
133 QtGui
.QWidget
.__init
__(self
)
135 self
.logger
= plugin
.logger
136 self
.settings
= QtCore
.QSettings()
137 self
.settings
.beginGroup(self
.plugin
.name
)
139 self
.modes
= QtGui
.QComboBox()
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()
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
):
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)
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
):
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())
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()))