Merge lp:~raoul-snyman/openlp/dark-style into lp:openlp

Proposed by Raoul Snyman
Status: Merged
Merged at revision: 2772
Proposed branch: lp:~raoul-snyman/openlp/dark-style
Merge into: lp:openlp
Diff against target: 500 lines (+280/-92)
6 files modified
openlp/core/__init__.py (+3/-30)
openlp/core/common/settings.py (+1/-0)
openlp/core/ui/advancedtab.py (+54/-41)
openlp/core/ui/mainwindow.py (+2/-21)
openlp/core/ui/style.py (+109/-0)
tests/functional/openlp_core_ui/test_style.py (+111/-0)
To merge this branch: bzr merge lp:~raoul-snyman/openlp/dark-style
Reviewer Review Type Date Requested Status
Tim Bentley Approve
Review via email: mp+331593@code.launchpad.net

This proposal supersedes a proposal from 2017-09-29.

Description of the change

Enable the use of QDarkStyle, if it is installed. This is mainly for those users on Windows and macOS who want a dark theme.

QDarkStyle is only pip-installable at present, but we can include it in the PyInstaller builds.

Add this to your merge proposal:
--------------------------------
lp:~raoul-snyman/openlp/dark-style (revision 2773)
[SUCCESS] https://ci.openlp.io/job/Branch-01-Pull/2224/
[SUCCESS] https://ci.openlp.io/job/Branch-02-Functional-Tests/2127/
[SUCCESS] https://ci.openlp.io/job/Branch-03-Interface-Tests/2010/
[SUCCESS] https://ci.openlp.io/job/Branch-04a-Code_Analysis/1375/
[SUCCESS] https://ci.openlp.io/job/Branch-04b-Test_Coverage/1204/
[SUCCESS] https://ci.openlp.io/job/Branch-04c-Code_Analysis2/334/
[FAILURE] https://ci.openlp.io/job/Branch-05-AppVeyor-Tests/172/
Stopping after failure

To post a comment you must log in.
Revision history for this message
Tim Bentley (trb143) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openlp/core/__init__.py'
2--- openlp/core/__init__.py 2017-09-23 04:04:41 +0000
3+++ openlp/core/__init__.py 2017-09-29 17:16:28 +0000
4@@ -46,34 +46,14 @@
5 from openlp.core.ui.firsttimeform import FirstTimeForm
6 from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm
7 from openlp.core.ui.mainwindow import MainWindow
8+from openlp.core.ui.style import get_application_stylesheet
9+
10
11 __all__ = ['OpenLP', 'main']
12
13
14 log = logging.getLogger()
15
16-WIN_REPAIR_STYLESHEET = """
17-QMainWindow::separator
18-{
19- border: none;
20-}
21-
22-QDockWidget::title
23-{
24- border: 1px solid palette(dark);
25- padding-left: 5px;
26- padding-top: 2px;
27- margin: 1px 0;
28-}
29-
30-QToolBar
31-{
32- border: none;
33- margin: 0;
34- padding: 0;
35-}
36-"""
37-
38
39 class OpenLP(OpenLPMixin, QtWidgets.QApplication):
40 """
41@@ -118,14 +98,7 @@
42 QtCore.QCoreApplication.exit()
43 sys.exit()
44 # Correct stylesheet bugs
45- application_stylesheet = ''
46- if not Settings().value('advanced/alternate rows'):
47- base_color = self.palette().color(QtGui.QPalette.Active, QtGui.QPalette.Base)
48- alternate_rows_repair_stylesheet = \
49- 'QTableWidget, QListWidget, QTreeWidget {alternate-background-color: ' + base_color.name() + ';}\n'
50- application_stylesheet += alternate_rows_repair_stylesheet
51- if is_win():
52- application_stylesheet += WIN_REPAIR_STYLESHEET
53+ application_stylesheet = get_application_stylesheet()
54 if application_stylesheet:
55 self.setStyleSheet(application_stylesheet)
56 can_show_splash = Settings().value('core/show splash')
57
58=== modified file 'openlp/core/common/settings.py'
59--- openlp/core/common/settings.py 2017-09-09 20:00:48 +0000
60+++ openlp/core/common/settings.py 2017-09-29 17:16:28 +0000
61@@ -136,6 +136,7 @@
62 'advanced/single click service preview': False,
63 'advanced/x11 bypass wm': X11_BYPASS_DEFAULT,
64 'advanced/search as type': True,
65+ 'advanced/use_dark_style': False,
66 'api/twelve hour': True,
67 'api/port': 4316,
68 'api/websocket port': 4317,
69
70=== modified file 'openlp/core/ui/advancedtab.py'
71--- openlp/core/ui/advancedtab.py 2017-09-24 20:26:39 +0000
72+++ openlp/core/ui/advancedtab.py 2017-09-29 17:16:28 +0000
73@@ -32,6 +32,7 @@
74 from openlp.core.common.path import path_to_str
75 from openlp.core.lib import SettingsTab, build_icon
76 from openlp.core.ui.lib import PathEdit, PathType
77+from openlp.core.ui.style import HAS_DARK_STYLE
78
79 log = logging.getLogger(__name__)
80
81@@ -109,45 +110,10 @@
82 self.enable_auto_close_check_box.setObjectName('enable_auto_close_check_box')
83 self.ui_layout.addRow(self.enable_auto_close_check_box)
84 self.left_layout.addWidget(self.ui_group_box)
85- # Default service name
86- self.service_name_group_box = QtWidgets.QGroupBox(self.left_column)
87- self.service_name_group_box.setObjectName('service_name_group_box')
88- self.service_name_layout = QtWidgets.QFormLayout(self.service_name_group_box)
89- self.service_name_check_box = QtWidgets.QCheckBox(self.service_name_group_box)
90- self.service_name_check_box.setObjectName('service_name_check_box')
91- self.service_name_layout.setObjectName('service_name_layout')
92- self.service_name_layout.addRow(self.service_name_check_box)
93- self.service_name_time_label = QtWidgets.QLabel(self.service_name_group_box)
94- self.service_name_time_label.setObjectName('service_name_time_label')
95- self.service_name_day = QtWidgets.QComboBox(self.service_name_group_box)
96- self.service_name_day.addItems(['', '', '', '', '', '', '', ''])
97- self.service_name_day.setObjectName('service_name_day')
98- self.service_name_time = QtWidgets.QTimeEdit(self.service_name_group_box)
99- self.service_name_time.setObjectName('service_name_time')
100- self.service_name_time_layout = QtWidgets.QHBoxLayout()
101- self.service_name_time_layout.setObjectName('service_name_time_layout')
102- self.service_name_time_layout.addWidget(self.service_name_day)
103- self.service_name_time_layout.addWidget(self.service_name_time)
104- self.service_name_layout.addRow(self.service_name_time_label, self.service_name_time_layout)
105- self.service_name_label = QtWidgets.QLabel(self.service_name_group_box)
106- self.service_name_label.setObjectName('service_name_label')
107- self.service_name_edit = QtWidgets.QLineEdit(self.service_name_group_box)
108- self.service_name_edit.setObjectName('service_name_edit')
109- self.service_name_edit.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp(r'[^/\\?*|<>\[\]":+]+'), self))
110- self.service_name_revert_button = QtWidgets.QToolButton(self.service_name_group_box)
111- self.service_name_revert_button.setObjectName('service_name_revert_button')
112- self.service_name_revert_button.setIcon(build_icon(':/general/general_revert.png'))
113- self.service_name_button_layout = QtWidgets.QHBoxLayout()
114- self.service_name_button_layout.setObjectName('service_name_button_layout')
115- self.service_name_button_layout.addWidget(self.service_name_edit)
116- self.service_name_button_layout.addWidget(self.service_name_revert_button)
117- self.service_name_layout.addRow(self.service_name_label, self.service_name_button_layout)
118- self.service_name_example_label = QtWidgets.QLabel(self.service_name_group_box)
119- self.service_name_example_label.setObjectName('service_name_example_label')
120- self.service_name_example = QtWidgets.QLabel(self.service_name_group_box)
121- self.service_name_example.setObjectName('service_name_example')
122- self.service_name_layout.addRow(self.service_name_example_label, self.service_name_example)
123- self.left_layout.addWidget(self.service_name_group_box)
124+ if HAS_DARK_STYLE:
125+ self.use_dark_style_checkbox = QtWidgets.QCheckBox(self.ui_group_box)
126+ self.use_dark_style_checkbox.setObjectName('use_dark_style_checkbox')
127+ self.ui_layout.addRow(self.use_dark_style_checkbox)
128 # Data Directory
129 self.data_directory_group_box = QtWidgets.QGroupBox(self.left_column)
130 self.data_directory_group_box.setObjectName('data_directory_group_box')
131@@ -174,7 +140,6 @@
132 self.data_directory_layout.addRow(self.data_directory_copy_check_layout)
133 self.data_directory_layout.addRow(self.new_data_directory_has_files_label)
134 self.left_layout.addWidget(self.data_directory_group_box)
135- self.left_layout.addStretch()
136 # Hide mouse
137 self.hide_mouse_group_box = QtWidgets.QGroupBox(self.right_column)
138 self.hide_mouse_group_box.setObjectName('hide_mouse_group_box')
139@@ -203,7 +168,7 @@
140 self.slide_layout.addWidget(self.next_item_radio_button)
141 self.right_layout.addWidget(self.slide_group_box)
142 # Display Workarounds
143- self.display_workaround_group_box = QtWidgets.QGroupBox(self.left_column)
144+ self.display_workaround_group_box = QtWidgets.QGroupBox(self.right_column)
145 self.display_workaround_group_box.setObjectName('display_workaround_group_box')
146 self.display_workaround_layout = QtWidgets.QVBoxLayout(self.display_workaround_group_box)
147 self.display_workaround_layout.setObjectName('display_workaround_layout')
148@@ -217,7 +182,49 @@
149 self.alternate_rows_check_box.setObjectName('alternate_rows_check_box')
150 self.display_workaround_layout.addWidget(self.alternate_rows_check_box)
151 self.right_layout.addWidget(self.display_workaround_group_box)
152+ # Default service name
153+ self.service_name_group_box = QtWidgets.QGroupBox(self.right_column)
154+ self.service_name_group_box.setObjectName('service_name_group_box')
155+ self.service_name_layout = QtWidgets.QFormLayout(self.service_name_group_box)
156+ self.service_name_check_box = QtWidgets.QCheckBox(self.service_name_group_box)
157+ self.service_name_check_box.setObjectName('service_name_check_box')
158+ self.service_name_layout.setObjectName('service_name_layout')
159+ self.service_name_layout.addRow(self.service_name_check_box)
160+ self.service_name_time_label = QtWidgets.QLabel(self.service_name_group_box)
161+ self.service_name_time_label.setObjectName('service_name_time_label')
162+ self.service_name_day = QtWidgets.QComboBox(self.service_name_group_box)
163+ self.service_name_day.addItems(['', '', '', '', '', '', '', ''])
164+ self.service_name_day.setObjectName('service_name_day')
165+ self.service_name_time = QtWidgets.QTimeEdit(self.service_name_group_box)
166+ self.service_name_time.setObjectName('service_name_time')
167+ self.service_name_time_layout = QtWidgets.QHBoxLayout()
168+ self.service_name_time_layout.setObjectName('service_name_time_layout')
169+ self.service_name_time_layout.addWidget(self.service_name_day)
170+ self.service_name_time_layout.addWidget(self.service_name_time)
171+ self.service_name_layout.addRow(self.service_name_time_label, self.service_name_time_layout)
172+ self.service_name_label = QtWidgets.QLabel(self.service_name_group_box)
173+ self.service_name_label.setObjectName('service_name_label')
174+ self.service_name_edit = QtWidgets.QLineEdit(self.service_name_group_box)
175+ self.service_name_edit.setObjectName('service_name_edit')
176+ self.service_name_edit.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp(r'[^/\\?*|<>\[\]":+]+'), self))
177+ self.service_name_revert_button = QtWidgets.QToolButton(self.service_name_group_box)
178+ self.service_name_revert_button.setObjectName('service_name_revert_button')
179+ self.service_name_revert_button.setIcon(build_icon(':/general/general_revert.png'))
180+ self.service_name_button_layout = QtWidgets.QHBoxLayout()
181+ self.service_name_button_layout.setObjectName('service_name_button_layout')
182+ self.service_name_button_layout.addWidget(self.service_name_edit)
183+ self.service_name_button_layout.addWidget(self.service_name_revert_button)
184+ self.service_name_layout.addRow(self.service_name_label, self.service_name_button_layout)
185+ self.service_name_example_label = QtWidgets.QLabel(self.service_name_group_box)
186+ self.service_name_example_label.setObjectName('service_name_example_label')
187+ self.service_name_example = QtWidgets.QLabel(self.service_name_group_box)
188+ self.service_name_example.setObjectName('service_name_example')
189+ self.service_name_layout.addRow(self.service_name_example_label, self.service_name_example)
190+ self.right_layout.addWidget(self.service_name_group_box)
191+ # After the last item on each side, add some spacing
192+ self.left_layout.addStretch()
193 self.right_layout.addStretch()
194+ # Set up all the connections and things
195 self.should_update_service_name_example = False
196 self.service_name_check_box.toggled.connect(self.service_name_check_box_toggled)
197 self.service_name_day.currentIndexChanged.connect(self.on_service_name_day_changed)
198@@ -282,6 +289,8 @@
199 'Auto-scroll the next slide to bottom'))
200 self.enable_auto_close_check_box.setText(translate('OpenLP.AdvancedTab',
201 'Enable application exit confirmation'))
202+ if HAS_DARK_STYLE:
203+ self.use_dark_style_checkbox.setText(translate('OpenLP.AdvancedTab', 'Use dark style (needs restart)'))
204 self.service_name_group_box.setTitle(translate('OpenLP.AdvancedTab', 'Default Service Name'))
205 self.service_name_check_box.setText(translate('OpenLP.AdvancedTab', 'Enable default service name'))
206 self.service_name_time_label.setText(translate('OpenLP.AdvancedTab', 'Date and Time:'))
207@@ -349,6 +358,8 @@
208 if self.autoscroll_map[i] == autoscroll_value and i < self.autoscroll_combo_box.count():
209 self.autoscroll_combo_box.setCurrentIndex(i)
210 self.enable_auto_close_check_box.setChecked(settings.value('enable exit confirmation'))
211+ if HAS_DARK_STYLE:
212+ self.use_dark_style_checkbox.setChecked(settings.value('use_dark_style'))
213 self.hide_mouse_check_box.setChecked(settings.value('hide mouse'))
214 self.service_name_day.setCurrentIndex(settings.value('default service day'))
215 self.service_name_time.setTime(QtCore.QTime(settings.value('default service hour'),
216@@ -420,6 +431,8 @@
217 self.settings_form.register_post_process('config_screen_changed')
218 self.settings_form.register_post_process('slidecontroller_update_slide_limits')
219 settings.setValue('search as type', self.is_search_as_you_type_enabled)
220+ if HAS_DARK_STYLE:
221+ settings.setValue('use_dark_style', self.use_dark_style_checkbox.isChecked())
222 settings.endGroup()
223
224 def on_search_as_type_check_box_changed(self, check_state):
225
226=== modified file 'openlp/core/ui/mainwindow.py'
227--- openlp/core/ui/mainwindow.py 2017-09-25 19:55:33 +0000
228+++ openlp/core/ui/mainwindow.py 2017-09-29 17:16:28 +0000
229@@ -51,31 +51,12 @@
230 from openlp.core.ui.lib.dockwidget import OpenLPDockWidget
231 from openlp.core.ui.lib.filedialog import FileDialog
232 from openlp.core.ui.lib.mediadockmanager import MediaDockManager
233+from openlp.core.ui.style import PROGRESSBAR_STYLE, get_library_stylesheet
234 from openlp.core.version import get_version
235
236
237 log = logging.getLogger(__name__)
238
239-MEDIA_MANAGER_STYLE = """
240-::tab#media_tool_box {
241- background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
242- stop: 0 palette(button), stop: 1.0 palette(mid));
243- border: 0;
244- border-radius: 2px;
245- margin-top: 0;
246- margin-bottom: 0;
247- text-align: left;
248-}
249-/* This is here to make the tabs on KDE with the Breeze theme work */
250-::tab:selected {}
251-"""
252-
253-PROGRESSBAR_STYLE = """
254-QProgressBar{
255- height: 10px;
256-}
257-"""
258-
259
260 class Ui_MainWindow(object):
261 """
262@@ -155,7 +136,7 @@
263 # Create the MediaManager
264 self.media_manager_dock = OpenLPDockWidget(main_window, 'media_manager_dock',
265 ':/system/system_mediamanager.png')
266- self.media_manager_dock.setStyleSheet(MEDIA_MANAGER_STYLE)
267+ self.media_manager_dock.setStyleSheet(get_library_stylesheet())
268 # Create the media toolbox
269 self.media_tool_box = QtWidgets.QToolBox(self.media_manager_dock)
270 self.media_tool_box.setObjectName('media_tool_box')
271
272=== added file 'openlp/core/ui/style.py'
273--- openlp/core/ui/style.py 1970-01-01 00:00:00 +0000
274+++ openlp/core/ui/style.py 2017-09-29 17:16:28 +0000
275@@ -0,0 +1,109 @@
276+# -*- coding: utf-8 -*-
277+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
278+
279+###############################################################################
280+# OpenLP - Open Source Lyrics Projection #
281+# --------------------------------------------------------------------------- #
282+# Copyright (c) 2008-2017 OpenLP Developers #
283+# --------------------------------------------------------------------------- #
284+# This program is free software; you can redistribute it and/or modify it #
285+# under the terms of the GNU General Public License as published by the Free #
286+# Software Foundation; version 2 of the License. #
287+# #
288+# This program is distributed in the hope that it will be useful, but WITHOUT #
289+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
290+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
291+# more details. #
292+# #
293+# You should have received a copy of the GNU General Public License along #
294+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
295+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
296+###############################################################################
297+"""
298+The :mod:`~openlp.core.ui.dark` module looks for and loads a dark theme
299+"""
300+from PyQt5 import QtGui
301+
302+from openlp.core.common import is_macosx, is_win
303+from openlp.core.common.registry import Registry
304+from openlp.core.common.settings import Settings
305+
306+try:
307+ import qdarkstyle
308+ HAS_DARK_STYLE = True
309+except ImportError:
310+ HAS_DARK_STYLE = False
311+
312+WIN_REPAIR_STYLESHEET = """
313+QMainWindow::separator
314+{
315+ border: none;
316+}
317+
318+QDockWidget::title
319+{
320+ border: 1px solid palette(dark);
321+ padding-left: 5px;
322+ padding-top: 2px;
323+ margin: 1px 0;
324+}
325+
326+QToolBar
327+{
328+ border: none;
329+ margin: 0;
330+ padding: 0;
331+}
332+"""
333+
334+MEDIA_MANAGER_STYLE = """
335+::tab#media_tool_box {
336+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
337+ stop: 0 palette(button), stop: 1.0 palette(mid));
338+ border: 0;
339+ border-radius: 2px;
340+ margin-top: 0;
341+ margin-bottom: 0;
342+ text-align: left;
343+}
344+/* This is here to make the tabs on KDE with the Breeze theme work */
345+::tab:selected {}
346+"""
347+
348+PROGRESSBAR_STYLE = """
349+QProgressBar{
350+ height: 10px;
351+}
352+"""
353+
354+
355+def get_application_stylesheet():
356+ """
357+ Return the correct application stylesheet based on the current style and operating system
358+
359+ :return str: The correct stylesheet as a string
360+ """
361+ stylesheet = ''
362+ if HAS_DARK_STYLE and Settings().value('advanced/use_dark_style'):
363+ stylesheet = qdarkstyle.load_stylesheet_pyqt5()
364+ else:
365+ if not Settings().value('advanced/alternate rows'):
366+ base_color = Registry().get('application').palette().color(QtGui.QPalette.Active, QtGui.QPalette.Base)
367+ alternate_rows_repair_stylesheet = \
368+ 'QTableWidget, QListWidget, QTreeWidget {alternate-background-color: ' + base_color.name() + ';}\n'
369+ stylesheet += alternate_rows_repair_stylesheet
370+ if is_win():
371+ stylesheet += WIN_REPAIR_STYLESHEET
372+ return stylesheet
373+
374+
375+def get_library_stylesheet():
376+ """
377+ Return the correct stylesheet for the main window
378+
379+ :return str: The correct stylesheet as a string
380+ """
381+ if not HAS_DARK_STYLE or not Settings().value('advanced/use_dark_style'):
382+ return MEDIA_MANAGER_STYLE
383+ else:
384+ return ''
385
386=== added file 'tests/functional/openlp_core_ui/test_style.py'
387--- tests/functional/openlp_core_ui/test_style.py 1970-01-01 00:00:00 +0000
388+++ tests/functional/openlp_core_ui/test_style.py 2017-09-29 17:16:28 +0000
389@@ -0,0 +1,111 @@
390+# -*- coding: utf-8 -*-
391+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
392+
393+###############################################################################
394+# OpenLP - Open Source Lyrics Projection #
395+# --------------------------------------------------------------------------- #
396+# Copyright (c) 2008-2017 OpenLP Developers #
397+# --------------------------------------------------------------------------- #
398+# This program is free software; you can redistribute it and/or modify it #
399+# under the terms of the GNU General Public License as published by the Free #
400+# Software Foundation; version 2 of the License. #
401+# #
402+# This program is distributed in the hope that it will be useful, but WITHOUT #
403+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
404+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
405+# more details. #
406+# #
407+# You should have received a copy of the GNU General Public License along #
408+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
409+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
410+###############################################################################
411+"""
412+Package to test the :mod:`~openlp.core.ui.style` module.
413+"""
414+from unittest.mock import MagicMock, patch
415+
416+import openlp.core.ui.style
417+from openlp.core.ui.style import MEDIA_MANAGER_STYLE, WIN_REPAIR_STYLESHEET, get_application_stylesheet, \
418+ get_library_stylesheet
419+
420+
421+@patch('openlp.core.ui.style.HAS_DARK_STYLE', True)
422+@patch('openlp.core.ui.style.Settings')
423+@patch.object(openlp.core.ui.style, 'qdarkstyle')
424+def test_get_application_stylesheet_dark(mocked_qdarkstyle, MockSettings):
425+ """Test that the dark stylesheet is returned when available and enabled"""
426+ # GIVEN: We're on Windows and no dark style is set
427+ mocked_settings = MagicMock()
428+ mocked_settings.value.return_value = True
429+ MockSettings.return_value = mocked_settings
430+ mocked_qdarkstyle.load_stylesheet_pyqt5.return_value = 'dark_style'
431+
432+ # WHEN: can_show_icon() is called
433+ result = get_application_stylesheet()
434+
435+ # THEN: the result should be false
436+ assert result == 'dark_style'
437+
438+
439+@patch('openlp.core.ui.style.HAS_DARK_STYLE', False)
440+@patch('openlp.core.ui.style.is_win')
441+@patch('openlp.core.ui.style.Settings')
442+@patch('openlp.core.ui.style.Registry')
443+def test_get_application_stylesheet_not_alternate_rows(MockRegistry, MockSettings, mocked_is_win):
444+ """Test that the alternate rows stylesheet is returned when enabled in settings"""
445+ # GIVEN: We're on Windows and no dark style is set
446+ mocked_is_win.return_value = False
447+ MockSettings.return_value.value.return_value = False
448+ MockRegistry.return_value.get.return_value.palette.return_value.color.return_value.name.return_value = 'color'
449+
450+ # WHEN: can_show_icon() is called
451+ result = get_application_stylesheet()
452+
453+ # THEN: the result should be false
454+ MockSettings.return_value.value.assert_called_once_with('advanced/alternate rows')
455+ assert result == 'QTableWidget, QListWidget, QTreeWidget {alternate-background-color: color;}\n', result
456+
457+
458+@patch('openlp.core.ui.style.HAS_DARK_STYLE', False)
459+@patch('openlp.core.ui.style.is_win')
460+@patch('openlp.core.ui.style.Settings')
461+def test_get_application_stylesheet_win_repair(MockSettings, mocked_is_win):
462+ """Test that the Windows repair stylesheet is returned when on Windows"""
463+ # GIVEN: We're on Windows and no dark style is set
464+ mocked_is_win.return_value = True
465+ MockSettings.return_value.value.return_value = True
466+
467+ # WHEN: can_show_icon() is called
468+ result = get_application_stylesheet()
469+
470+ # THEN: the result should be false
471+ MockSettings.return_value.value.assert_called_once_with('advanced/alternate rows')
472+ assert result == WIN_REPAIR_STYLESHEET
473+
474+
475+@patch('openlp.core.ui.style.HAS_DARK_STYLE', False)
476+@patch('openlp.core.ui.style.Settings')
477+def test_get_library_stylesheet_no_dark_style(MockSettings):
478+ """Test that the media manager stylesheet is returned when there's no dark theme available"""
479+ # GIVEN: No dark style
480+ MockSettings.return_value.value.return_value = False
481+
482+ # WHEN: get_library_stylesheet() is called
483+ result = get_library_stylesheet()
484+
485+ # THEN: The correct stylesheet should be returned
486+ assert result == MEDIA_MANAGER_STYLE
487+
488+
489+@patch('openlp.core.ui.style.HAS_DARK_STYLE', True)
490+@patch('openlp.core.ui.style.Settings')
491+def test_get_library_stylesheet_dark_style(MockSettings):
492+ """Test that no stylesheet is returned when the dark theme is enabled"""
493+ # GIVEN: No dark style
494+ MockSettings.return_value.value.return_value = True
495+
496+ # WHEN: get_library_stylesheet() is called
497+ result = get_library_stylesheet()
498+
499+ # THEN: The correct stylesheet should be returned
500+ assert result == ''