2 # Copyright (C) 2008 jerous <jerous@gmail.com>
3 # Copyright (C) 2009 Anton Khirnov <wyskas@gmail.com>
5 # Nephilim is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # Nephilim is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with Nephilim. If not, see <http://www.gnu.org/licenses/>.
19 from PyQt4
import QtGui
, QtCore
20 from PyQt4
.QtCore
import QVariant
23 from misc
import APPNAME
, sec2min
, appIcon
24 from connect_wg
import ConnectWidget
26 DEFAULT_LAYOUT_FILE
= 'default_layout'
28 class winMain(QtGui
.QMainWindow
):
29 """The winMain class is mpc's main window, showing the playlists and control-interface"""
48 QtGui
.QWidget
.__init
__(self
)
49 self
.settings
= QtCore
.QSettings()
50 self
.mpclient
= QtGui
.QApplication
.instance().mpclient
52 self
.wConnect
= ConnectWidget(self
)
56 self
.statuslabel
= QtGui
.QLabel()
57 self
.time_slider
= QtGui
.QSlider(QtCore
.Qt
.Horizontal
, self
)
58 self
.time_slider
.setMaximumWidth(self
.width()/4)
59 self
.connect(self
.time_slider
, QtCore
.SIGNAL('sliderReleased()'), self
.on_time_slider_change
)
60 self
.time_label
= QtGui
.QLabel()
61 self
.time_label
.duration
= '0:00'
63 self
.statusBar().addWidget(self
.statuslabel
)
64 self
.statusBar().addPermanentWidget(self
.time_label
)
65 self
.statusBar().addPermanentWidget(self
.time_slider
)
67 mBar
= QtGui
.QMenuBar() # create a menubar
69 m
= mBar
.addMenu("File")
70 m
.setTearOffEnabled(True)
72 self
.mConnect
=m
.addAction('Connect ...', self
.wConnect
.monitor
)
73 self
.mConnect
.setIcon(QtGui
.QIcon(appIcon
))
75 self
.mDisconnect
=m
.addAction('Disconnect', self
.mpclient
.disconnect_mpd
)
76 self
.mDisconnect
.setIcon(QtGui
.QIcon('gfx/disconnect.png'))
80 m
.addAction("Quit", QtGui
.QApplication
.instance().quit
).setIcon(QtGui
.QIcon('gfx/gtk-quit.svg'))
83 m
=mBar
.addMenu("Options")
84 m
.setTearOffEnabled(True)
86 m
.addAction("Settings", QtGui
.QApplication
.instance().show_settings_win
).setIcon(QtGui
.QIcon('gfx/gtk-preferences.svg'))
89 self
.mLayout
=mBar
.addMenu("Layout")
90 self
.mLayout
.setTearOffEnabled(True)
92 # create a toolbar for the main menu
93 menu_toolbar
= QtGui
.QToolBar('Main menu', self
)
94 menu_toolbar
.addWidget(mBar
)
95 self
.addToolBar(QtCore
.Qt
.TopToolBarArea
, menu_toolbar
)
97 self
.updateLayoutMenu()
98 self
.setDockOptions(QtGui
.QMainWindow
.AllowNestedDocks \
99 |QtGui
.QMainWindow
.AllowTabbedDocks \
100 |QtGui
.QMainWindow
.VerticalTabs
)
101 self
.setDockNestingEnabled(True)
102 self
.restoreGeometry(self
.settings
.value('geometry').toByteArray())
104 " add event handlers"
105 self
.connect(self
.mpclient
, QtCore
.SIGNAL('connected'), self
.onConnected
)
106 self
.connect(self
.mpclient
, QtCore
.SIGNAL('disconnected'), self
.onDisconnect
)
107 self
.connect(self
.mpclient
, QtCore
.SIGNAL('song_changed'), self
.on_song_change
)
108 self
.connect(self
.mpclient
, QtCore
.SIGNAL('state_changed'), self
.update_state_messages
)
109 self
.connect(self
.mpclient
, QtCore
.SIGNAL('time_changed'), self
.on_time_change
)
111 self
.wConnect
.monitor()
113 self
.update_state_messages()
117 self
.settings
.setValue('geometry', QVariant(self
.saveGeometry()))
119 def updateLayoutMenu(self
):
121 self
.mLayout
.addAction('Save layout', self
.saveLayout
)
122 self
.mLayout
.addAction('Restore layout', self
.restore_layout
)
123 self
.mLayout
.addSeparator()
124 # create checkable menu
125 a
=QtGui
.QAction('Show titlebars', self
)
127 a
.setChecked(self
.settings
.value('show_titlebars', QVariant(True)).toBool())
128 self
.toggleTitleBars(a
.isChecked())
129 self
.connect(a
, QtCore
.SIGNAL('toggled(bool)'), self
.toggleTitleBars
)
130 self
.mLayout
.addAction(a
)
131 self
.mLayout
.addSeparator()
132 # can not use iterators, as that gives some creepy error 'bout c++
133 actions
=self
.createPopupMenu().actions()
134 for i
in xrange(len(actions
)):
135 self
.mLayout
.addAction(actions
[i
])
137 def toggleTitleBars(self
, val
):
139 self
.settings
.setValue('show_titlebars', QVariant(True))
141 self
.settings
.setValue('show_titlebars', QVariant(False))
142 for dock
in self
.docks
:
144 dock
.setTitleBarWidget(None)
146 dock
.setTitleBarWidget(QtGui
.QWidget())
147 def addDock(self
, dock
):
149 self
.docks
.append(dock
)
150 self
.addDockWidget(QtCore
.Qt
.TopDockWidgetArea
, dock
)
151 self
.updateLayoutMenu()
152 def removeDock(self
, dock
):
154 if dock
in self
.docks
:
155 self
.docks
.remove(dock
)
156 self
.removeDockWidget(dock
)
157 self
.updateLayoutMenu()
160 def createPopupMenu(self
):
161 ret
=QtGui
.QMenu('Test', self
)
162 if self
.mMenuVisible
==None:
163 # create checkable menu
164 a
=QtGui
.QAction('Menubar', self
)
167 self
.connect(a
, QtCore
.SIGNAL('toggled(bool)'), self
.switchMenubar
)
170 ret
.addAction(self
.mMenuVisible
)
172 menu
= QtGui
.QMainWindow
.createPopupMenu(self
)
174 actions
= menu
.actions()
175 for i
in xrange(len(actions
)-1):
176 ret
.addAction(actions
[i
])
178 def switchMenubar(self
, val
):
179 self
.menuBar().setVisible(val
)
180 def setStatus(self
, status
):
181 """Set the text of the statusbar."""
182 self
.statusBar().showMessage(status
, 5000)
185 def saveLayout(self
):
186 self
.settings
.setValue('layout', QVariant(self
.saveState()))
187 def restore_layout(self
):
188 layout
= self
.settings
.value('layout').toByteArray()
191 layout
= open(DEFAULT_LAYOUT_FILE
, 'rb').read()
193 logging
.error("Error reading default layout.")
195 self
.restoreState(layout
)
198 def onConnected(self
):
199 self
.mDisconnect
.setEnabled(True)
200 self
.mConnect
.setEnabled(False)
202 def onDisconnect(self
):
203 logging
.info("Disconnected from MPD")
204 self
.mDisconnect
.setEnabled(False)
205 self
.mConnect
.setEnabled(True)
206 self
.setStatus("You are disconnected. Choose File->Connect to reconnect!")
208 def update_state_messages(self
):
209 song
= self
.mpclient
.current_song()
210 state
= self
.mpclient
.status()['state']
211 state
= 'playing' if state
== 'play' else 'paused' if state
== 'pause' else 'stopped'
213 self
.setWindowTitle('%s by %s - %s [%s]'%(song
.title(), song
.artist(), APPNAME
, state
))
214 self
.statuslabel
.setText('%s by %s on %s [%s]'%(song
.title(), song
.artist(),song
.album(), state
))
216 self
.setWindowTitle(APPNAME
)
217 self
.statuslabel
.setText('')
219 def on_time_slider_change(self
):
220 self
.mpclient
.seek(self
.time_slider
.value())
222 def on_song_change(self
):
223 status
= self
.mpclient
.status()
224 self
.time_slider
.setMaximum(status
['length'])
225 self
.time_slider
.setEnabled(True)
226 self
.time_label
.duration
= sec2min(status
['length'])
227 self
.update_state_messages()
229 def on_time_change(self
, new_time
):
230 if not self
.time_slider
.isSliderDown():
231 self
.time_slider
.setValue(new_time
)
232 self
.time_label
.setText(sec2min(new_time
) + '/' + self
.time_label
.duration
)