Status: | Superseded | ||||
---|---|---|---|---|---|
Proposed branch: | lp:~trb143/openlp/reporting | ||||
Merge into: | lp:openlp | ||||
Diff against target: |
411 lines (+215/-29) 7 files modified
openlp/core/common/settings.py (+1/-0) openlp/plugins/custom/lib/mediaitem.py (+1/-1) openlp/plugins/songs/forms/editsongform.py (+1/-1) openlp/plugins/songs/lib/songcompare.py (+3/-3) openlp/plugins/songs/reporting.py (+102/-0) openlp/plugins/songs/songsplugin.py (+27/-8) tests/functional/openlp_core_ui/test_servicemanager.py (+80/-16) |
||||
To merge this branch: | bzr merge lp:~trb143/openlp/reporting | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Raoul Snyman | Pending | ||
Review via email: mp+306259@code.launchpad.net |
This proposal supersedes a proposal from 2016-09-08.
This proposal has been superseded by a proposal from 2016-09-21.
Commit message
Description of the change
My dad needed a report of all the songs on their database, they had 1800.
Made this into a reporting option and cleaned up the menu.
Fixed some errors spotted as well
Fixed issues and comments
1800 songs takes about 3 secs to run on my i7
lp:~trb143/openlp/reporting (revision 2699)
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal | # |
Phill (phill-ridout) wrote : Posted in a previous version of this proposal | # |
See my inline comments about your test doc stings and comments.
And also see my inline comments with regard to the Unicode literals. They're not required, and seem only to be implemented to ease porting from py2! https:/
Are there any tests for the new module/method you've addded:
reporting.py
on_tools_
Phill (phill-ridout) wrote : | # |
Still missing tests for your new module. Guess its up to superfly if he's happy with that.
Also, just a few inline comments
- 2700. By Tim Bentley
-
minor updates
- 2701. By Tim Bentley
-
head
- 2702. By Tim Bentley
-
Fix song bug with formatting
- 2703. By Tim Bentley
-
Fix titles
Unmerged revisions
Preview Diff
1 | === modified file 'openlp/core/common/settings.py' |
2 | --- openlp/core/common/settings.py 2016-07-31 11:58:54 +0000 |
3 | +++ openlp/core/common/settings.py 2016-09-21 19:04:20 +0000 |
4 | @@ -379,6 +379,7 @@ |
5 | 'shortcuts/themeScreen': [QtGui.QKeySequence(QtCore.Qt.Key_T)], |
6 | 'shortcuts/toolsReindexItem': [], |
7 | 'shortcuts/toolsFindDuplicates': [], |
8 | + 'shortcuts/toolsSongListReport': [], |
9 | 'shortcuts/toolsAlertItem': [QtGui.QKeySequence(QtCore.Qt.Key_F7)], |
10 | 'shortcuts/toolsFirstTimeWizard': [], |
11 | 'shortcuts/toolsOpenDataFolder': [], |
12 | |
13 | === modified file 'openlp/plugins/custom/lib/mediaitem.py' |
14 | --- openlp/plugins/custom/lib/mediaitem.py 2016-05-21 18:19:18 +0000 |
15 | +++ openlp/plugins/custom/lib/mediaitem.py 2016-09-21 19:04:20 +0000 |
16 | @@ -350,7 +350,7 @@ |
17 | :param string: The search string |
18 | :param show_error: The error string to be show. |
19 | """ |
20 | - search = '%{search}%'.forma(search=string.lower()) |
21 | + search = '%{search}%'.format(search=string.lower()) |
22 | search_results = self.plugin.db_manager.get_all_objects(CustomSlide, |
23 | or_(func.lower(CustomSlide.title).like(search), |
24 | func.lower(CustomSlide.text).like(search)), |
25 | |
26 | === modified file 'openlp/plugins/songs/forms/editsongform.py' |
27 | --- openlp/plugins/songs/forms/editsongform.py 2016-05-27 08:13:14 +0000 |
28 | +++ openlp/plugins/songs/forms/editsongform.py 2016-09-21 19:04:20 +0000 |
29 | @@ -317,7 +317,7 @@ |
30 | self.song.verse_order = re.sub('([' + verse.upper() + verse.lower() + '])(\W|$)', |
31 | r'\g<1>1\2', self.song.verse_order) |
32 | except: |
33 | - log.exception('Problem processing song Lyrics \n{xml}'.forma(xml=sxml.dump_xml())) |
34 | + log.exception('Problem processing song Lyrics \n{xml}'.format(xml=sxml.dump_xml())) |
35 | raise |
36 | |
37 | def keyPressEvent(self, event): |
38 | |
39 | === modified file 'openlp/plugins/songs/lib/songcompare.py' |
40 | --- openlp/plugins/songs/lib/songcompare.py 2015-12-31 22:46:06 +0000 |
41 | +++ openlp/plugins/songs/lib/songcompare.py 2016-09-21 19:04:20 +0000 |
42 | @@ -46,13 +46,13 @@ |
43 | MAX_TYPO_SIZE = 3 |
44 | |
45 | |
46 | -def songs_probably_equal(song_tupel): |
47 | +def songs_probably_equal(song_tuple): |
48 | """ |
49 | Calculate and return whether two songs are probably equal. |
50 | |
51 | - :param song_tupel: A tuple of two songs to compare. |
52 | + :param song_tuple: A tuple of two songs to compare. |
53 | """ |
54 | - song1, song2 = song_tupel |
55 | + song1, song2 = song_tuple |
56 | pos1, lyrics1 = song1 |
57 | pos2, lyrics2 = song2 |
58 | if len(lyrics1) < len(lyrics2): |
59 | |
60 | === added file 'openlp/plugins/songs/reporting.py' |
61 | --- openlp/plugins/songs/reporting.py 1970-01-01 00:00:00 +0000 |
62 | +++ openlp/plugins/songs/reporting.py 2016-09-21 19:04:20 +0000 |
63 | @@ -0,0 +1,102 @@ |
64 | +# -*- coding: utf-8 -*- |
65 | +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 |
66 | + |
67 | +############################################################################### |
68 | +# OpenLP - Open Source Lyrics Projection # |
69 | +# --------------------------------------------------------------------------- # |
70 | +# Copyright (c) 2008-2016 OpenLP Developers # |
71 | +# --------------------------------------------------------------------------- # |
72 | +# This program is free software; you can redistribute it and/or modify it # |
73 | +# under the terms of the GNU General Public License as published by the Free # |
74 | +# Software Foundation; version 2 of the License. # |
75 | +# # |
76 | +# This program is distributed in the hope that it will be useful, but WITHOUT # |
77 | +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # |
78 | +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # |
79 | +# more details. # |
80 | +# # |
81 | +# You should have received a copy of the GNU General Public License along # |
82 | +# with this program; if not, write to the Free Software Foundation, Inc., 59 # |
83 | +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
84 | +############################################################################### |
85 | +""" |
86 | +The :mod:`db` module provides the ability to provide a csv file of all songs |
87 | +""" |
88 | +import csv |
89 | +import logging |
90 | + |
91 | +from PyQt5 import QtWidgets |
92 | + |
93 | +from openlp.core.common import Registry, translate |
94 | +from openlp.core.lib.ui import critical_error_message_box |
95 | +from openlp.plugins.songs.lib.db import Song |
96 | + |
97 | + |
98 | +log = logging.getLogger(__name__) |
99 | + |
100 | + |
101 | +def report_song_list(): |
102 | + """ |
103 | + Export the song list as a CSV file. |
104 | + :return: Nothing |
105 | + """ |
106 | + main_window = Registry().get('main_window') |
107 | + plugin = Registry().get('songs').plugin |
108 | + report_file_name, filter_used = QtWidgets.QFileDialog.getSaveFileName( |
109 | + main_window, translate('SongPlugin.ReportSongList', 'Output File Location')) |
110 | + if not report_file_name: |
111 | + main_window.error_message( |
112 | + translate('SongPlugin.ReportSongList', 'Output Path Not Selected'), |
113 | + translate('SongPlugin.ReportSongList', 'You have not set a valid output location for your ' |
114 | + 'report. \nPlease select an existing path ' |
115 | + 'on your computer.') |
116 | + ) |
117 | + return |
118 | + if not report_file_name.endswith('csv'): |
119 | + report_file_name += '.csv' |
120 | + file_handle = None |
121 | + Registry().get('application').set_busy_cursor() |
122 | + try: |
123 | + file_handle = open(report_file_name, 'wt') |
124 | + fieldnames = ('Title', 'Alternative Title', 'Copyright', 'Author(s)', 'Song Book', 'Topic') |
125 | + writer = csv.DictWriter(file_handle, fieldnames=fieldnames, quoting=csv.QUOTE_ALL) |
126 | + headers = dict((n, n) for n in fieldnames) |
127 | + writer.writerow(headers) |
128 | + song_list = plugin.manager.get_all_objects(Song) |
129 | + for song in song_list: |
130 | + author_list = [] |
131 | + for author_song in song.authors_songs: |
132 | + author_list.append(author_song.author.display_name) |
133 | + author_string = ' | '.join(author_list) |
134 | + book_list = [] |
135 | + for book_song in song.songbook_entries: |
136 | + if hasattr(book_song, 'entry') and book_song.entry: |
137 | + book_list.append('{name} #{entry}'.format(name=book_song.songbook.name, entry=book_song.entry)) |
138 | + book_string = ' | '.join(book_list) |
139 | + topic_list = [] |
140 | + for topic_song in song.topics: |
141 | + if hasattr(topic_song, 'name'): |
142 | + topic_list.append(topic_song.name) |
143 | + topic_string = ' | '.join(topic_list) |
144 | + writer.writerow({'Title': song.title, |
145 | + 'Alternative Title': song.alternate_title, |
146 | + 'Copyright': song.copyright, |
147 | + 'Author(s)': author_string, |
148 | + 'Song Book': book_string, |
149 | + 'Topic': topic_string}) |
150 | + Registry().get('application').set_normal_cursor() |
151 | + main_window.information_message( |
152 | + translate('SongPlugin.ReportSongList', 'Report Creation'), |
153 | + translate('SongPlugin.ReportSongList', |
154 | + 'Report \n{name} \nhas been successfully created. ').format(name=report_file_name) |
155 | + ) |
156 | + except OSError as ose: |
157 | + Registry().get('application').set_normal_cursor() |
158 | + log.exception('Failed to write out song usage records') |
159 | + critical_error_message_box(translate('SongPlugin.ReportSongList', 'Song Extraction Failed'), |
160 | + translate('SongPlugin.ReportSongList', |
161 | + 'An error occurred while extracting: {error}' |
162 | + ).format(error=ose.strerror)) |
163 | + finally: |
164 | + if file_handle: |
165 | + file_handle.close() |
166 | |
167 | === modified file 'openlp/plugins/songs/songsplugin.py' |
168 | --- openlp/plugins/songs/songsplugin.py 2016-03-31 16:34:22 +0000 |
169 | +++ openlp/plugins/songs/songsplugin.py 2016-09-21 19:04:20 +0000 |
170 | @@ -36,6 +36,7 @@ |
171 | from openlp.core.lib import Plugin, StringContent, build_icon |
172 | from openlp.core.lib.db import Manager |
173 | from openlp.core.lib.ui import create_action |
174 | +from openlp.plugins.songs import reporting |
175 | from openlp.plugins.songs.forms.duplicatesongremovalform import DuplicateSongRemovalForm |
176 | from openlp.plugins.songs.forms.songselectform import SongSelectForm |
177 | from openlp.plugins.songs.lib import clean_song, upgrade |
178 | @@ -102,13 +103,13 @@ |
179 | self.songselect_form.initialise() |
180 | self.song_import_item.setVisible(True) |
181 | self.song_export_item.setVisible(True) |
182 | - self.tools_reindex_item.setVisible(True) |
183 | - self.tools_find_duplicates.setVisible(True) |
184 | + self.song_tools_menu.menuAction().setVisible(True) |
185 | action_list = ActionList.get_instance() |
186 | action_list.add_action(self.song_import_item, UiStrings().Import) |
187 | action_list.add_action(self.song_export_item, UiStrings().Export) |
188 | action_list.add_action(self.tools_reindex_item, UiStrings().Tools) |
189 | action_list.add_action(self.tools_find_duplicates, UiStrings().Tools) |
190 | + action_list.add_action(self.tools_report_song_list, UiStrings().Tools) |
191 | |
192 | def add_import_menu_item(self, import_menu): |
193 | """ |
194 | @@ -151,19 +152,37 @@ |
195 | :param tools_menu: The actual **Tools** menu item, so that your actions can use it as their parent. |
196 | """ |
197 | log.info('add tools menu') |
198 | + self.tools_menu = tools_menu |
199 | + self.song_tools_menu = QtWidgets.QMenu(tools_menu) |
200 | + self.song_tools_menu.setObjectName('song_tools_menu') |
201 | + self.song_tools_menu.setTitle(translate('SongsPlugin', 'Songs')) |
202 | self.tools_reindex_item = create_action( |
203 | tools_menu, 'toolsReindexItem', |
204 | text=translate('SongsPlugin', '&Re-index Songs'), |
205 | icon=':/plugins/plugin_songs.png', |
206 | statustip=translate('SongsPlugin', 'Re-index the songs database to improve searching and ordering.'), |
207 | - visible=False, triggers=self.on_tools_reindex_item_triggered) |
208 | - tools_menu.addAction(self.tools_reindex_item) |
209 | + triggers=self.on_tools_reindex_item_triggered) |
210 | self.tools_find_duplicates = create_action( |
211 | tools_menu, 'toolsFindDuplicates', |
212 | text=translate('SongsPlugin', 'Find &Duplicate Songs'), |
213 | statustip=translate('SongsPlugin', 'Find and remove duplicate songs in the song database.'), |
214 | - visible=False, triggers=self.on_tools_find_duplicates_triggered, can_shortcuts=True) |
215 | - tools_menu.addAction(self.tools_find_duplicates) |
216 | + triggers=self.on_tools_find_duplicates_triggered, can_shortcuts=True) |
217 | + self.tools_report_song_list = create_action( |
218 | + tools_menu, 'toolsSongListReport', |
219 | + text=translate('SongsPlugin', 'Song List Report'), |
220 | + statustip=translate('SongsPlugin', 'Produce a CSV file of all the songs in the database.'), |
221 | + triggers=self.on_tools_report_song_list_triggered) |
222 | + |
223 | + self.tools_menu.addAction(self.song_tools_menu.menuAction()) |
224 | + self.song_tools_menu.addAction(self.tools_reindex_item) |
225 | + self.song_tools_menu.addAction(self.tools_find_duplicates) |
226 | + self.song_tools_menu.addAction(self.tools_report_song_list) |
227 | + |
228 | + self.song_tools_menu.menuAction().setVisible(False) |
229 | + |
230 | + @staticmethod |
231 | + def on_tools_report_song_list_triggered(): |
232 | + reporting.report_song_list() |
233 | |
234 | def on_tools_reindex_item_triggered(self): |
235 | """ |
236 | @@ -326,13 +345,13 @@ |
237 | self.manager.finalise() |
238 | self.song_import_item.setVisible(False) |
239 | self.song_export_item.setVisible(False) |
240 | - self.tools_reindex_item.setVisible(False) |
241 | - self.tools_find_duplicates.setVisible(False) |
242 | action_list = ActionList.get_instance() |
243 | action_list.remove_action(self.song_import_item, UiStrings().Import) |
244 | action_list.remove_action(self.song_export_item, UiStrings().Export) |
245 | action_list.remove_action(self.tools_reindex_item, UiStrings().Tools) |
246 | action_list.remove_action(self.tools_find_duplicates, UiStrings().Tools) |
247 | + action_list.add_action(self.tools_report_song_list, UiStrings().Tools) |
248 | + self.song_tools_menu.menuAction().setVisible(False) |
249 | super(SongsPlugin, self).finalise() |
250 | |
251 | def new_service_created(self): |
252 | |
253 | === modified file 'tests/functional/openlp_core_ui/test_servicemanager.py' |
254 | --- tests/functional/openlp_core_ui/test_servicemanager.py 2016-07-17 19:46:06 +0000 |
255 | +++ tests/functional/openlp_core_ui/test_servicemanager.py 2016-09-21 19:04:20 +0000 |
256 | @@ -28,6 +28,7 @@ |
257 | import PyQt5 |
258 | |
259 | from openlp.core.common import Registry, ThemeLevel |
260 | +from openlp.core.ui.lib.toolbar import OpenLPToolbar |
261 | from openlp.core.lib import ServiceItem, ServiceItemType, ItemCapabilities |
262 | from openlp.core.ui import ServiceManager |
263 | |
264 | @@ -544,8 +545,8 @@ |
265 | self.assertEqual(service_manager.theme_menu.menuAction().setVisible.call_count, 1, |
266 | 'Should have be called once') |
267 | |
268 | - @patch(u'openlp.core.ui.servicemanager.Settings') |
269 | - @patch(u'PyQt5.QtCore.QTimer.singleShot') |
270 | + @patch('openlp.core.ui.servicemanager.Settings') |
271 | + @patch('PyQt5.QtCore.QTimer.singleShot') |
272 | def test_single_click_preview_true(self, mocked_singleShot, MockedSettings): |
273 | """ |
274 | Test that when "Preview items when clicked in Service Manager" enabled the preview timer starts |
275 | @@ -561,8 +562,8 @@ |
276 | mocked_singleShot.assert_called_with(PyQt5.QtWidgets.QApplication.instance().doubleClickInterval(), |
277 | service_manager.on_single_click_preview_timeout) |
278 | |
279 | - @patch(u'openlp.core.ui.servicemanager.Settings') |
280 | - @patch(u'PyQt5.QtCore.QTimer.singleShot') |
281 | + @patch('openlp.core.ui.servicemanager.Settings') |
282 | + @patch('PyQt5.QtCore.QTimer.singleShot') |
283 | def test_single_click_preview_false(self, mocked_singleShot, MockedSettings): |
284 | """ |
285 | Test that when "Preview items when clicked in Service Manager" disabled the preview timer doesn't start |
286 | @@ -577,9 +578,9 @@ |
287 | # THEN: timer should not be started |
288 | self.assertEqual(mocked_singleShot.call_count, 0, 'Should not be called') |
289 | |
290 | - @patch(u'openlp.core.ui.servicemanager.Settings') |
291 | - @patch(u'PyQt5.QtCore.QTimer.singleShot') |
292 | - @patch(u'openlp.core.ui.servicemanager.ServiceManager.make_live') |
293 | + @patch('openlp.core.ui.servicemanager.Settings') |
294 | + @patch('PyQt5.QtCore.QTimer.singleShot') |
295 | + @patch('openlp.core.ui.servicemanager.ServiceManager.make_live') |
296 | def test_single_click_preview_double(self, mocked_make_live, mocked_singleShot, MockedSettings): |
297 | """ |
298 | Test that when a double click has registered the preview timer doesn't start |
299 | @@ -596,7 +597,7 @@ |
300 | mocked_make_live.assert_called_with() |
301 | self.assertEqual(mocked_singleShot.call_count, 0, 'Should not be called') |
302 | |
303 | - @patch(u'openlp.core.ui.servicemanager.ServiceManager.make_preview') |
304 | + @patch('openlp.core.ui.servicemanager.ServiceManager.make_preview') |
305 | def test_single_click_timeout_single(self, mocked_make_preview): |
306 | """ |
307 | Test that when a single click has been registered, the item is sent to preview |
308 | @@ -609,8 +610,8 @@ |
309 | self.assertEqual(mocked_make_preview.call_count, 1, |
310 | 'ServiceManager.make_preview() should have been called once') |
311 | |
312 | - @patch(u'openlp.core.ui.servicemanager.ServiceManager.make_preview') |
313 | - @patch(u'openlp.core.ui.servicemanager.ServiceManager.make_live') |
314 | + @patch('openlp.core.ui.servicemanager.ServiceManager.make_preview') |
315 | + @patch('openlp.core.ui.servicemanager.ServiceManager.make_live') |
316 | def test_single_click_timeout_double(self, mocked_make_live, mocked_make_preview): |
317 | """ |
318 | Test that when a double click has been registered, the item does not goes to preview |
319 | @@ -623,9 +624,9 @@ |
320 | # THEN: make_preview() should not have been called |
321 | self.assertEqual(mocked_make_preview.call_count, 0, 'ServiceManager.make_preview() should not be called') |
322 | |
323 | - @patch(u'openlp.core.ui.servicemanager.shutil.copy') |
324 | - @patch(u'openlp.core.ui.servicemanager.zipfile') |
325 | - @patch(u'openlp.core.ui.servicemanager.ServiceManager.save_file_as') |
326 | + @patch('openlp.core.ui.servicemanager.shutil.copy') |
327 | + @patch('openlp.core.ui.servicemanager.zipfile') |
328 | + @patch('openlp.core.ui.servicemanager.ServiceManager.save_file_as') |
329 | def test_save_file_raises_permission_error(self, mocked_save_file_as, mocked_zipfile, mocked_shutil_copy): |
330 | """ |
331 | Test that when a PermissionError is raised when trying to save a file, it is handled correctly |
332 | @@ -652,9 +653,9 @@ |
333 | self.assertTrue(result) |
334 | mocked_save_file_as.assert_called_with() |
335 | |
336 | - @patch(u'openlp.core.ui.servicemanager.shutil.copy') |
337 | - @patch(u'openlp.core.ui.servicemanager.zipfile') |
338 | - @patch(u'openlp.core.ui.servicemanager.ServiceManager.save_file_as') |
339 | + @patch('openlp.core.ui.servicemanager.shutil.copy') |
340 | + @patch('openlp.core.ui.servicemanager.zipfile') |
341 | + @patch('openlp.core.ui.servicemanager.ServiceManager.save_file_as') |
342 | def test_save_local_file_raises_permission_error(self, mocked_save_file_as, mocked_zipfile, mocked_shutil_copy): |
343 | """ |
344 | Test that when a PermissionError is raised when trying to save a local file, it is handled correctly |
345 | @@ -679,3 +680,66 @@ |
346 | # THEN: The "save_as" method is called to save the service |
347 | self.assertTrue(result) |
348 | mocked_save_file_as.assert_called_with() |
349 | + |
350 | + @patch('openlp.core.ui.servicemanager.ServiceManager.regenerate_service_items') |
351 | + def test_theme_change_global(self, mocked_regenerate_service_items): |
352 | + """ |
353 | + Test that when a Toolbar theme combobox displays correctly when the theme is set to Global |
354 | + """ |
355 | + # GIVEN: A service manager, a service to display with a theme level in the renderer |
356 | + mocked_renderer = MagicMock() |
357 | + service_manager = ServiceManager(None) |
358 | + Registry().register('renderer', mocked_renderer) |
359 | + service_manager.toolbar = OpenLPToolbar(None) |
360 | + service_manager.toolbar.add_toolbar_action('theme_combo_box', triggers=MagicMock()) |
361 | + service_manager.toolbar.add_toolbar_action('theme_label', triggers=MagicMock()) |
362 | + |
363 | + # WHEN: The service manager has a Global theme |
364 | + mocked_renderer.theme_level = ThemeLevel.Global |
365 | + result = service_manager.theme_change() |
366 | + |
367 | + # THEN: The the theme toolbar should not be visible |
368 | + self.assertFalse(service_manager.toolbar.actions['theme_combo_box'].isVisible(), |
369 | + 'The visibility should be False') |
370 | + |
371 | + @patch('openlp.core.ui.servicemanager.ServiceManager.regenerate_service_items') |
372 | + def test_theme_change_service(self, mocked_regenerate_service_items): |
373 | + """ |
374 | + Test that when a Toolbar theme combobox displays correctly when the theme is set to Theme |
375 | + """ |
376 | + # GIVEN: A service manager, a service to display with a theme level in the renderer |
377 | + mocked_renderer = MagicMock() |
378 | + service_manager = ServiceManager(None) |
379 | + Registry().register('renderer', mocked_renderer) |
380 | + service_manager.toolbar = OpenLPToolbar(None) |
381 | + service_manager.toolbar.add_toolbar_action('theme_combo_box', triggers=MagicMock()) |
382 | + service_manager.toolbar.add_toolbar_action('theme_label', triggers=MagicMock()) |
383 | + |
384 | + # WHEN: The service manager has a Service theme |
385 | + mocked_renderer.theme_level = ThemeLevel.Service |
386 | + result = service_manager.theme_change() |
387 | + |
388 | + # THEN: The the theme toolbar should be visible |
389 | + self.assertTrue(service_manager.toolbar.actions['theme_combo_box'].isVisible(), |
390 | + 'The visibility should be True') |
391 | + |
392 | + @patch('openlp.core.ui.servicemanager.ServiceManager.regenerate_service_items') |
393 | + def test_theme_change_song(self, mocked_regenerate_service_items): |
394 | + """ |
395 | + Test that when a Toolbar theme combobox displays correctly when the theme is set to Song |
396 | + """ |
397 | + # GIVEN: A service manager, a service to display with a theme level in the renderer |
398 | + mocked_renderer = MagicMock() |
399 | + service_manager = ServiceManager(None) |
400 | + Registry().register('renderer', mocked_renderer) |
401 | + service_manager.toolbar = OpenLPToolbar(None) |
402 | + service_manager.toolbar.add_toolbar_action('theme_combo_box', triggers=MagicMock()) |
403 | + service_manager.toolbar.add_toolbar_action('theme_label', triggers=MagicMock()) |
404 | + |
405 | + # WHEN: The service manager has a Song theme |
406 | + mocked_renderer.theme_level = ThemeLevel.Song |
407 | + result = service_manager.theme_change() |
408 | + |
409 | + # THEN: The the theme toolbar should be visible |
410 | + self.assertTrue(service_manager.toolbar.actions['theme_combo_box'].isVisible(), |
411 | + 'The visibility should be True') |
1. There's a "csv" module, use it.
2. I should be able to specify the file name, not just where to save it to.
3. Have you tested this with > 1000 songs? How long does it take? Some sort of progress window necessary?
4. You call it a report internally, but you're not very specific for the user. Rather call it a "Song List Report".
More comments inline.