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
20 from ..plugin
import Plugin
21 from ..common
import MIMETYPES
, SongsMimeData
22 from ..song
import PlaylistEntryRef
24 class Playlist(Plugin
):
26 info
= 'Shows the playlist.'
32 DEFAULTS
= {'columns': ['track', 'title', 'artist', 'date', 'album', 'length'], 'header_state' : QtCore
.QByteArray()}
35 self
.o
= PlaylistWidget(self
)
40 def _get_dock_widget(self
):
41 return self
._create
_dock
(self
.o
)
43 class PlaylistWidget(QtGui
.QWidget
):
48 def __init__(self
, plugin
):
49 QtGui
.QWidget
.__init
__(self
)
52 self
.playlist
= PlaylistTree(self
.plugin
)
54 self
.toolbar
= QtGui
.QToolBar(self
.plugin
.name
+ ' toolbar', self
)
55 self
.toolbar
.addAction(QtGui
.QIcon(':icons/shuffle.png'), 'Shuffle current playlist.', self
.plugin
.mpclient
.shuffle
)
56 self
.toolbar
.addAction(QtGui
.QIcon(':icons/delete.png'), 'Clear current playlist.', self
.plugin
.mpclient
.clear
)
57 add_url
= PlaylistAddURL(self
.plugin
.mpclient
, self
)
58 add_url
.setToolTip('Add an URL to current playlist.')
59 self
.toolbar
.addWidget(add_url
)
61 self
.setLayout(QtGui
.QVBoxLayout())
62 self
.layout().setSpacing(0)
63 self
.layout().setMargin(0)
64 self
.layout().addWidget(self
.toolbar
)
65 self
.layout().addWidget(self
.playlist
)
67 self
.plugin
.mpclient
.playlist(self
.playlist
.fill
)
69 class PlaylistAddURL(QtGui
.QLineEdit
):
74 def __init__(self
, mpclient
, parent
= None):
75 QtGui
.QLineEdit
.__init
__(self
, parent
)
76 self
._mpclient
= mpclient
77 self
.returnPressed
.connect(self
._return
_pressed
)
79 def _return_pressed(self
):
80 self
._mpclient
.add([self
.text()])
83 class PlaylistTree(QtGui
.QTreeWidget
):
91 # currently playing song item (highlighted
94 def __init__(self
, plugin
):
95 QtGui
.QTreeWidget
.__init
__(self
)
98 self
.setSelectionMode(QtGui
.QTreeWidget
.ExtendedSelection
)
99 self
.setAlternatingRowColors(True)
100 self
.setRootIsDecorated(False)
103 self
.viewport().setAcceptDrops(True)
104 self
.setDropIndicatorShown(True)
105 self
.setDragDropMode(QtGui
.QAbstractItemView
.DragDrop
)
107 columns
= self
.plugin
.settings
.value(self
.plugin
.name
+ '/columns')
108 self
.setColumnCount(len(columns
))
109 self
.setHeaderLabels(columns
)
110 self
.header().restoreState(self
.plugin
.settings
.value(self
.plugin
.name
+ '/header_state'))
113 self
._menu
= QtGui
.QMenu()
114 self
._same
_menu
= self
._menu
.addMenu('Add same...')
115 self
.setContextMenuPolicy(QtCore
.Qt
.CustomContextMenu
)
116 self
.customContextMenuRequested
.connect(self
._show
_context
_menu
)
118 self
.itemActivated
.connect(self
._song
_activated
)
119 self
.header().geometriesChanged
.connect(self
._save
_state
)
120 self
.plugin
.mpclient
.playlist_changed
.connect(lambda :self
.plugin
.mpclient
.playlist(self
.fill
))
121 self
.plugin
.mpclient
.connect_changed
.connect(self
._update
_menu
)
122 self
.plugin
.mpclient
.song_changed
.connect(self
._update
_cur
_song
)
123 self
.plugin
.mpclient
.songpos_changed
.connect(self
._update
_cur
_song
)
125 def _save_state(self
):
126 self
.plugin
.settings
.setValue(self
.plugin
.name
+ '/header_state', self
.header().saveState())
128 def _song_activated(self
, item
):
129 self
.plugin
.mpclient
.play(item
.song
['id'])
131 def _update_cur_song(self
, song
):
133 self
._cur
_song
.set_current(False)
136 self
._cur
_song
= None
139 self
._cur
_song
= self
.topLevelItem(int(song
['pos']))
141 self
._cur
_song
.set_current(True)
143 def fill(self
, songs
):
144 columns
= self
.plugin
.settings
.value(self
.plugin
.name
+ '/columns')
145 self
._cur
_song
= None
148 item
= PlaylistSongItem(PlaylistEntryRef(self
.plugin
.mpclient
, song
['id']))
149 for i
in range(len(columns
)):
150 item
.setText(i
, song
['?' + columns
[i
]])
151 self
.addTopLevelItem(item
)
152 self
._update
_cur
_song
(self
.plugin
.mpclient
.cur_song
)
154 def keyPressEvent(self
, event
):
155 if event
.matches(QtGui
.QKeySequence
.Delete
):
157 for item
in self
.selectedItems():
158 ids
.append(item
.song
['id'])
160 self
.plugin
.mpclient
.delete(ids
)
162 QtGui
.QTreeWidget
.keyPressEvent(self
, event
)
164 def mimeData(self
, items
):
165 data
= SongsMimeData()
166 data
.set_plistsongs([items
[0].song
['id']])
169 def dropMimeData(self
, parent
, index
, data
, action
):
170 if data
.hasFormat(MIMETYPES
['plistsongs']):
172 index
= self
.indexOfTopLevelItem(parent
)
173 elif index
>= self
.topLevelItemCount():
174 index
= self
.topLevelItemCount() - 1
175 self
.plugin
.mpclient
.move(data
.plistsongs()[0], index
)
177 elif data
.hasFormat(MIMETYPES
['songs']):
179 index
= self
.indexOfTopLevelItem(parent
)
180 self
.plugin
.mpclient
.add(data
.songs(), index
)
184 def supportedDropActions(self
):
185 return QtCore
.Qt
.CopyAction | QtCore
.Qt
.MoveAction
188 return [MIMETYPES
['songs'], MIMETYPES
['plistsongs']]
190 def _update_menu(self
):
191 """Update popup menu. Invoked on (dis)connect."""
192 self
._same
_menu
.clear()
193 for tag
in self
.plugin
.mpclient
.tagtypes
:
194 self
._same
_menu
.addAction(tag
, lambda tag
= tag
: self
._add
_selected
_same
(tag
))
196 def _add_selected_same(self
, tag
):
197 """Adds all tracks in DB with tag 'tag' same as selected tracks."""
198 for it
in self
.selectedItems():
199 self
.plugin
.mpclient
.findadd(tag
, it
.song
['?' + tag
])
201 def _show_context_menu(self
, pos
):
202 if not self
.indexAt(pos
).isValid():
204 self
._menu
.popup(self
.mapToGlobal(pos
))
206 class PlaylistSongItem(QtGui
.QTreeWidgetItem
):
210 def __init__(self
, song
):
211 QtGui
.QTreeWidgetItem
.__init
__(self
)
214 def set_current(self
, val
):
220 for i
in xrange(self
.columnCount()):
221 self
.setFont(i
, font
)