1
|
|
|
import os |
2
|
|
|
|
3
|
|
|
from appdirs import AppDirs |
4
|
|
|
|
5
|
|
|
from PyQt5.QtCore import Qt |
6
|
|
|
from PyQt5.QtGui import QIcon |
7
|
|
|
from PyQt5.QtWidgets import (QComboBox, QCheckBox, QDialog, QDialogButtonBox, QFileDialog, |
8
|
|
|
QGroupBox, QHBoxLayout, QLabel, QLineEdit, QListWidget, |
9
|
|
|
QListWidgetItem, QPushButton, QRadioButton, QStackedWidget, |
10
|
|
|
QVBoxLayout, QWidget) |
11
|
|
|
|
12
|
|
|
import toml |
13
|
|
|
|
14
|
|
|
from mosaic import utilities |
15
|
|
|
|
16
|
|
|
|
17
|
|
|
class MediaLibrary(QWidget): |
18
|
|
|
"""Contains all of the user configurable options related to the media library.""" |
19
|
|
|
|
20
|
|
View Code Duplication |
def __init__(self, parent=None): |
|
|
|
|
21
|
|
|
"""Initialize a page of options to be shown in the preferences dialog.""" |
22
|
|
|
super(MediaLibrary, self).__init__(parent) |
23
|
|
|
|
24
|
|
|
self.user_config_file = os.path.join(AppDirs('mosaic', 'Mandeep').user_config_dir, |
25
|
|
|
'settings.toml') |
26
|
|
|
|
27
|
|
|
with open(self.user_config_file) as conffile: |
28
|
|
|
config = toml.load(conffile) |
29
|
|
|
|
30
|
|
|
media_library_config = QGroupBox("Media Library Configuration") |
31
|
|
|
|
32
|
|
|
self.media_library_label = QLabel('Media Library', self) |
33
|
|
|
self.media_library_line = QLineEdit() |
34
|
|
|
self.media_library_line.setReadOnly(True) |
35
|
|
|
self.media_library_button = QPushButton('Select Path') |
36
|
|
|
|
37
|
|
|
self.media_library_button.clicked.connect(lambda: self.select_media_library(config)) |
38
|
|
|
|
39
|
|
|
media_library_layout = QVBoxLayout() |
40
|
|
|
|
41
|
|
|
media_library_config_layout = QHBoxLayout() |
42
|
|
|
media_library_config_layout.addWidget(self.media_library_label) |
43
|
|
|
media_library_config_layout.addWidget(self.media_library_line) |
44
|
|
|
media_library_config_layout.addWidget(self.media_library_button) |
45
|
|
|
|
46
|
|
|
media_library_layout.addLayout(media_library_config_layout) |
47
|
|
|
|
48
|
|
|
media_library_config.setLayout(media_library_layout) |
49
|
|
|
|
50
|
|
|
main_layout = QVBoxLayout() |
51
|
|
|
main_layout.addWidget(media_library_config) |
52
|
|
|
main_layout.addStretch(1) |
53
|
|
|
self.setLayout(main_layout) |
54
|
|
|
|
55
|
|
|
self.media_library_settings(config) |
56
|
|
|
|
57
|
|
|
def select_media_library(self, config): |
58
|
|
|
"""Open a file dialog to allow the user to select the media library path. |
59
|
|
|
|
60
|
|
|
The selected path is written to settings.toml. |
61
|
|
|
""" |
62
|
|
|
library = QFileDialog.getExistingDirectory(self, 'Select Media Library Directory') |
63
|
|
|
if library: |
64
|
|
|
self.media_library_line.setText(library) |
65
|
|
|
|
66
|
|
|
config['media_library']['media_library_path'] = library |
67
|
|
|
|
68
|
|
|
with open(self.user_config_file, 'w') as conffile: |
69
|
|
|
toml.dump(config, conffile) |
70
|
|
|
|
71
|
|
|
def media_library_settings(self, config): |
72
|
|
|
"""Set the media library text box to the path of the media library. |
73
|
|
|
|
74
|
|
|
If the user has already defined a media library path that was |
75
|
|
|
previously written to settings.toml, the path is shown when the |
76
|
|
|
preferences dialog is opened. |
77
|
|
|
""" |
78
|
|
|
library = config['media_library']['media_library_path'] |
79
|
|
|
if os.path.isdir(library): |
80
|
|
|
self.media_library_line.setText(library) |
81
|
|
|
|
82
|
|
|
|
83
|
|
|
class Playback(QWidget): |
84
|
|
|
"""Contains all of the user configurable options related to media playback.""" |
85
|
|
|
|
86
|
|
View Code Duplication |
def __init__(self, parent=None): |
|
|
|
|
87
|
|
|
"""Initiate the abstract widget that is displayed in the preferences dialog.""" |
88
|
|
|
super(Playback, self).__init__(parent) |
89
|
|
|
self.user_config_file = os.path.join(AppDirs('mosaic', 'Mandeep').user_config_dir, |
90
|
|
|
'settings.toml') |
91
|
|
|
|
92
|
|
|
with open(self.user_config_file) as conffile: |
93
|
|
|
config = toml.load(conffile) |
94
|
|
|
|
95
|
|
|
playback_config = QGroupBox('Playback Configuration') |
96
|
|
|
playback_config_layout = QVBoxLayout() |
97
|
|
|
playback_config_layout.setAlignment(Qt.AlignTop) |
98
|
|
|
|
99
|
|
|
self.cover_art_playback = QCheckBox('Cover Art Playback') |
100
|
|
|
self.playlist_save_checkbox = QCheckBox('Save Playlist on Close') |
101
|
|
|
|
102
|
|
|
playback_config_layout.addWidget(self.cover_art_playback) |
103
|
|
|
playback_config_layout.addWidget(self.playlist_save_checkbox) |
104
|
|
|
|
105
|
|
|
playback_config.setLayout(playback_config_layout) |
106
|
|
|
|
107
|
|
|
main_layout = QVBoxLayout() |
108
|
|
|
main_layout.addWidget(playback_config) |
109
|
|
|
|
110
|
|
|
self.setLayout(main_layout) |
111
|
|
|
|
112
|
|
|
self.check_playback_setting(config) |
113
|
|
|
self.check_playlist_save(config) |
114
|
|
|
self.cover_art_playback.clicked.connect(lambda: self.cover_art_playback_setting(config)) |
115
|
|
|
self.playlist_save_checkbox.clicked.connect(lambda: self.playlist_save_setting(config)) |
116
|
|
|
|
117
|
|
|
def cover_art_playback_setting(self, config): |
118
|
|
|
"""Change the cover art playback behavior of the music player. |
119
|
|
|
|
120
|
|
|
The default setting allows for the current media |
121
|
|
|
to be paused and played with mouse button clicks on the cover art. |
122
|
|
|
""" |
123
|
|
|
if self.cover_art_playback.isChecked(): |
124
|
|
|
config.setdefault('playback', {})['cover_art'] = True |
125
|
|
|
|
126
|
|
|
elif not self.cover_art_playback.isChecked(): |
127
|
|
|
config.setdefault('playback', {})['cover_art'] = False |
128
|
|
|
|
129
|
|
|
with open(self.user_config_file, 'w') as conffile: |
130
|
|
|
toml.dump(config, conffile) |
131
|
|
|
|
132
|
|
|
def playlist_save_setting(self, config): |
133
|
|
|
"""Change the save playlist on close behavior of the music player.""" |
134
|
|
|
if self.playlist_save_checkbox.isChecked(): |
135
|
|
|
config.setdefault('playlist', {})['save_on_close'] = True |
136
|
|
|
|
137
|
|
|
elif not self.playlist_save_checkbox.isChecked(): |
138
|
|
|
config.setdefault('playlist', {})['save_on_close'] = False |
139
|
|
|
|
140
|
|
|
with open(self.user_config_file, 'w') as conffile: |
141
|
|
|
toml.dump(config, conffile) |
142
|
|
|
|
143
|
|
|
def check_playback_setting(self, config): |
144
|
|
|
"""Set the cover art playback checkbox state from settings.toml.""" |
145
|
|
|
self.cover_art_playback.setChecked(config['playback']['cover_art']) |
146
|
|
|
|
147
|
|
|
def check_playlist_save(self, config): |
148
|
|
|
"""Set the playlist save on close state from settings.toml.""" |
149
|
|
|
self.playlist_save_checkbox.setChecked(config['playlist']['save_on_close']) |
150
|
|
|
|
151
|
|
|
|
152
|
|
|
class ViewOptions(QWidget): |
153
|
|
|
"""Contains all of the user configurable options related to the music player window.""" |
154
|
|
|
|
155
|
|
|
def __init__(self, parent=None): |
156
|
|
|
"""Initiate the View Options page in the preferences dialog.""" |
157
|
|
|
super(ViewOptions, self).__init__(parent) |
158
|
|
|
|
159
|
|
|
self.user_config_file = os.path.join(AppDirs('mosaic', 'Mandeep').user_config_dir, |
160
|
|
|
'settings.toml') |
161
|
|
|
|
162
|
|
|
with open(self.user_config_file) as conffile: |
163
|
|
|
config = toml.load(conffile) |
164
|
|
|
|
165
|
|
|
dock_config = QGroupBox('Dock Configuration') |
166
|
|
|
|
167
|
|
|
self.media_library_view_button = QCheckBox('Show Media Library on Start', self) |
168
|
|
|
self.playlist_view_button = QCheckBox('Show Playlist on Start', self) |
169
|
|
|
|
170
|
|
|
dock_start_layout = QVBoxLayout() |
171
|
|
|
dock_start_layout.addWidget(self.media_library_view_button) |
172
|
|
|
dock_start_layout.addWidget(self.playlist_view_button) |
173
|
|
|
|
174
|
|
|
self.dock_position = QLabel('Dock Position:') |
175
|
|
|
self.dock_left_side = QRadioButton('Left Side') |
176
|
|
|
self.dock_right_side = QRadioButton('Right Side') |
177
|
|
|
|
178
|
|
|
dock_position_layout = QHBoxLayout() |
179
|
|
|
dock_position_layout.addWidget(self.dock_position) |
180
|
|
|
dock_position_layout.addWidget(self.dock_left_side) |
181
|
|
|
dock_position_layout.addWidget(self.dock_right_side) |
182
|
|
|
|
183
|
|
|
main_dock_layout = QVBoxLayout() |
184
|
|
|
main_dock_layout.addLayout(dock_start_layout) |
185
|
|
|
main_dock_layout.addLayout(dock_position_layout) |
186
|
|
|
dock_config.setLayout(main_dock_layout) |
187
|
|
|
|
188
|
|
|
window_config = QGroupBox("Window Configuration") |
189
|
|
|
|
190
|
|
|
size_option = QLabel('Window Size', self) |
191
|
|
|
|
192
|
|
|
self.dropdown_box = QComboBox() |
193
|
|
|
self.dropdown_box.addItem('900 x 900') |
194
|
|
|
self.dropdown_box.addItem('800 x 800') |
195
|
|
|
self.dropdown_box.addItem('700 x 700') |
196
|
|
|
self.dropdown_box.addItem('600 x 600') |
197
|
|
|
self.dropdown_box.addItem('500 x 500') |
198
|
|
|
self.dropdown_box.addItem('400 x 400') |
199
|
|
|
|
200
|
|
|
window_size_layout = QHBoxLayout() |
201
|
|
|
window_size_layout.addWidget(size_option) |
202
|
|
|
window_size_layout.addWidget(self.dropdown_box) |
203
|
|
|
|
204
|
|
|
window_config.setLayout(window_size_layout) |
205
|
|
|
|
206
|
|
|
main_layout = QVBoxLayout() |
207
|
|
|
main_layout.addWidget(dock_config) |
208
|
|
|
main_layout.addWidget(window_config) |
209
|
|
|
main_layout.addStretch(1) |
210
|
|
|
self.setLayout(main_layout) |
211
|
|
|
|
212
|
|
|
self.check_window_size(config) |
213
|
|
|
self.check_media_library(config) |
214
|
|
|
self.check_playlist_dock(config) |
215
|
|
|
self.check_dock_position(config) |
216
|
|
|
|
217
|
|
|
self.dropdown_box.currentIndexChanged.connect(lambda: self.change_size(config)) |
218
|
|
|
self.media_library_view_button.clicked.connect(lambda: self.media_library_view_settings(config)) |
219
|
|
|
self.playlist_view_button.clicked.connect(lambda: self.playlist_view_settings(config)) |
220
|
|
|
self.dock_left_side.clicked.connect(lambda: self.dock_positon_settings(config)) |
221
|
|
|
self.dock_right_side.clicked.connect(lambda: self.dock_positon_settings(config)) |
222
|
|
|
|
223
|
|
|
def change_size(self, config): |
224
|
|
|
"""Record the change in window size to the settings.toml file.""" |
225
|
|
|
if self.dropdown_box.currentIndex() != -1: |
226
|
|
|
config.setdefault('view_options', {})['window_size'] = self.dropdown_box.currentIndex() |
227
|
|
|
|
228
|
|
|
with open(self.user_config_file, 'w') as conffile: |
229
|
|
|
toml.dump(config, conffile) |
230
|
|
|
|
231
|
|
|
def check_window_size(self, config): |
232
|
|
|
"""Set the dropdown box to the current window size provided by settings.toml.""" |
233
|
|
|
self.dropdown_box.setCurrentIndex(config['view_options']['window_size']) |
234
|
|
|
|
235
|
|
|
def media_library_view_settings(self, config): |
236
|
|
|
"""Change the behavior of the Media Library dock widget. |
237
|
|
|
|
238
|
|
|
The default setting hides the dock on application start. With this option |
239
|
|
|
checked, the media library dock will show on start. |
240
|
|
|
""" |
241
|
|
|
if self.media_library_view_button.isChecked(): |
242
|
|
|
config.setdefault('media_library', {})['show_on_start'] = True |
243
|
|
|
|
244
|
|
|
elif not self.media_library_view_button.isChecked(): |
245
|
|
|
config.setdefault('media_library', {})['show_on_start'] = False |
246
|
|
|
|
247
|
|
|
with open(self.user_config_file, 'w') as conffile: |
248
|
|
|
toml.dump(config, conffile) |
249
|
|
|
|
250
|
|
|
def check_media_library(self, config): |
251
|
|
|
"""Set the media library checkbox state from settings.toml.""" |
252
|
|
|
self.media_library_view_button.setChecked(config['media_library']['show_on_start']) |
253
|
|
|
|
254
|
|
|
def playlist_view_settings(self, config): |
255
|
|
|
"""Change the behavior of the Playlist dock widget. |
256
|
|
|
|
257
|
|
|
The default setting hides the dock on application start. With this option |
258
|
|
|
checked, the playlist dock will show on start. |
259
|
|
|
""" |
260
|
|
|
if self.playlist_view_button.isChecked(): |
261
|
|
|
config.setdefault('playlist', {})['show_on_start'] = True |
262
|
|
|
|
263
|
|
|
elif not self.playlist_view_button.isChecked(): |
264
|
|
|
config.setdefault('playlist', {})['show_on_start'] = False |
265
|
|
|
|
266
|
|
|
with open(self.user_config_file, 'w') as conffile: |
267
|
|
|
toml.dump(config, conffile) |
268
|
|
|
|
269
|
|
|
def check_playlist_dock(self, config): |
270
|
|
|
"""Set the playlist dock checkbox state from settings.toml.""" |
271
|
|
|
self.playlist_view_button.setChecked(config['playlist']['show_on_start']) |
272
|
|
|
|
273
|
|
|
def dock_positon_settings(self, config): |
274
|
|
|
"""Write to the settings.toml the radio button chosen by the user.""" |
275
|
|
|
if self.dock_left_side.isChecked(): |
276
|
|
|
config.setdefault('dock', {})['position'] = 'left' |
277
|
|
|
|
278
|
|
|
elif self.dock_right_side.isChecked(): |
279
|
|
|
config.setdefault('dock', {})['position'] = 'right' |
280
|
|
|
|
281
|
|
|
with open(self.user_config_file, 'w') as conffile: |
282
|
|
|
toml.dump(config, conffile) |
283
|
|
|
|
284
|
|
|
def check_dock_position(self, config): |
285
|
|
|
"""Select the radio button previously chosen by the user in the preferences dialog.""" |
286
|
|
|
if config['dock']['position'] == 'left': |
287
|
|
|
self.dock_left_side.setChecked(True) |
288
|
|
|
elif config['dock']['position'] == 'right': |
289
|
|
|
self.dock_right_side.setChecked(True) |
290
|
|
|
|
291
|
|
|
|
292
|
|
|
class PreferencesDialog(QDialog): |
293
|
|
|
"""Creates a dialog that shows the user all of the user configurable options. |
294
|
|
|
|
295
|
|
|
A list on the left shows all of the available pages, with |
296
|
|
|
the page's contents shown on the right. |
297
|
|
|
""" |
298
|
|
|
|
299
|
|
|
def __init__(self, parent=None): |
300
|
|
|
"""Initialize the preferences dialog with a list box and a content layout.""" |
301
|
|
|
super(PreferencesDialog, self).__init__(parent) |
302
|
|
|
self.setWindowTitle('Preferences') |
303
|
|
|
|
304
|
|
|
settings_icon = utilities.resource_filename('mosaic.images', 'md_settings.png') |
305
|
|
|
self.setWindowIcon(QIcon(settings_icon)) |
306
|
|
|
self.resize(600, 450) |
307
|
|
|
|
308
|
|
|
self.contents = QListWidget() |
309
|
|
|
self.contents.setFixedWidth(175) |
310
|
|
|
self.pages = QStackedWidget() |
311
|
|
|
self.button_box = QDialogButtonBox(QDialogButtonBox.Ok) |
312
|
|
|
|
313
|
|
|
self.dialog_media_library = MediaLibrary() |
314
|
|
|
self.dialog_playback = Playback() |
315
|
|
|
self.dialog_view_options = ViewOptions() |
316
|
|
|
self.pages.addWidget(self.dialog_media_library) |
317
|
|
|
self.pages.addWidget(self.dialog_playback) |
318
|
|
|
self.pages.addWidget(self.dialog_view_options) |
319
|
|
|
self.list_items() |
320
|
|
|
|
321
|
|
|
stack_layout = QVBoxLayout() |
322
|
|
|
stack_layout.addWidget(self.pages) |
323
|
|
|
stack_layout.addWidget(self.button_box) |
324
|
|
|
|
325
|
|
|
layout = QHBoxLayout() |
326
|
|
|
layout.addWidget(self.contents) |
327
|
|
|
layout.addLayout(stack_layout) |
328
|
|
|
|
329
|
|
|
self.setLayout(layout) |
330
|
|
|
|
331
|
|
|
self.contents.currentItemChanged.connect(self.change_page) |
332
|
|
|
self.button_box.accepted.connect(self.accept) |
333
|
|
|
|
334
|
|
|
def list_items(self): |
335
|
|
|
"""List all of the pages available to the user.""" |
336
|
|
|
media_library_options = QListWidgetItem(self.contents) |
337
|
|
|
media_library_options.setText('Media Library') |
338
|
|
|
media_library_options.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) |
339
|
|
|
self.contents.setCurrentRow(0) |
340
|
|
|
|
341
|
|
|
playback_options = QListWidgetItem(self.contents) |
342
|
|
|
playback_options.setText('Playback') |
343
|
|
|
playback_options.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) |
344
|
|
|
|
345
|
|
|
view_options = QListWidgetItem(self.contents) |
346
|
|
|
view_options.setText('View Options') |
347
|
|
|
view_options.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) |
348
|
|
|
|
349
|
|
|
def change_page(self, current, previous): |
350
|
|
|
"""Change the page according to the clicked list item.""" |
351
|
|
|
if not current: |
352
|
|
|
current = previous |
353
|
|
|
|
354
|
|
|
self.pages.setCurrentIndex(self.contents.row(current)) |
355
|
|
|
|