Merge lp:~trb143/openlp/reporting into lp:openlp

Proposed by Tim Bentley
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
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.

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://ci.openlp.io/job/Branch-01-Pull/1779/
[SUCCESS] https://ci.openlp.io/job/Branch-02-Functional-Tests/1690/
[SUCCESS] https://ci.openlp.io/job/Branch-03-Interface-Tests/1628/
[SUCCESS] https://ci.openlp.io/job/Branch-04a-Windows_Functional_Tests/1384/
[SUCCESS] https://ci.openlp.io/job/Branch-04b-Windows_Interface_Tests/974/
[SUCCESS] https://ci.openlp.io/job/Branch-05a-Code_Analysis/1042/
[SUCCESS] https://ci.openlp.io/job/Branch-05b-Test_Coverage/910/
[SUCCESS] https://ci.openlp.io/job/Branch-05c-Code_Analysis2/73/

To post a comment you must log in.
Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

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.

review: Needs Fixing
Revision history for this message
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://www.python.org/dev/peps/pep-0414/#proposal

Are there any tests for the new module/method you've addded:
reporting.py
on_tools_report_song_list_triggered

Revision history for this message
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

lp:~trb143/openlp/reporting updated
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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'openlp/core/common/settings.py'
--- openlp/core/common/settings.py 2016-07-31 11:58:54 +0000
+++ openlp/core/common/settings.py 2016-09-21 19:04:20 +0000
@@ -379,6 +379,7 @@
379 'shortcuts/themeScreen': [QtGui.QKeySequence(QtCore.Qt.Key_T)],379 'shortcuts/themeScreen': [QtGui.QKeySequence(QtCore.Qt.Key_T)],
380 'shortcuts/toolsReindexItem': [],380 'shortcuts/toolsReindexItem': [],
381 'shortcuts/toolsFindDuplicates': [],381 'shortcuts/toolsFindDuplicates': [],
382 'shortcuts/toolsSongListReport': [],
382 'shortcuts/toolsAlertItem': [QtGui.QKeySequence(QtCore.Qt.Key_F7)],383 'shortcuts/toolsAlertItem': [QtGui.QKeySequence(QtCore.Qt.Key_F7)],
383 'shortcuts/toolsFirstTimeWizard': [],384 'shortcuts/toolsFirstTimeWizard': [],
384 'shortcuts/toolsOpenDataFolder': [],385 'shortcuts/toolsOpenDataFolder': [],
385386
=== modified file 'openlp/plugins/custom/lib/mediaitem.py'
--- openlp/plugins/custom/lib/mediaitem.py 2016-05-21 18:19:18 +0000
+++ openlp/plugins/custom/lib/mediaitem.py 2016-09-21 19:04:20 +0000
@@ -350,7 +350,7 @@
350 :param string: The search string350 :param string: The search string
351 :param show_error: The error string to be show.351 :param show_error: The error string to be show.
352 """352 """
353 search = '%{search}%'.forma(search=string.lower())353 search = '%{search}%'.format(search=string.lower())
354 search_results = self.plugin.db_manager.get_all_objects(CustomSlide,354 search_results = self.plugin.db_manager.get_all_objects(CustomSlide,
355 or_(func.lower(CustomSlide.title).like(search),355 or_(func.lower(CustomSlide.title).like(search),
356 func.lower(CustomSlide.text).like(search)),356 func.lower(CustomSlide.text).like(search)),
357357
=== modified file 'openlp/plugins/songs/forms/editsongform.py'
--- openlp/plugins/songs/forms/editsongform.py 2016-05-27 08:13:14 +0000
+++ openlp/plugins/songs/forms/editsongform.py 2016-09-21 19:04:20 +0000
@@ -317,7 +317,7 @@
317 self.song.verse_order = re.sub('([' + verse.upper() + verse.lower() + '])(\W|$)',317 self.song.verse_order = re.sub('([' + verse.upper() + verse.lower() + '])(\W|$)',
318 r'\g<1>1\2', self.song.verse_order)318 r'\g<1>1\2', self.song.verse_order)
319 except:319 except:
320 log.exception('Problem processing song Lyrics \n{xml}'.forma(xml=sxml.dump_xml()))320 log.exception('Problem processing song Lyrics \n{xml}'.format(xml=sxml.dump_xml()))
321 raise321 raise
322322
323 def keyPressEvent(self, event):323 def keyPressEvent(self, event):
324324
=== modified file 'openlp/plugins/songs/lib/songcompare.py'
--- openlp/plugins/songs/lib/songcompare.py 2015-12-31 22:46:06 +0000
+++ openlp/plugins/songs/lib/songcompare.py 2016-09-21 19:04:20 +0000
@@ -46,13 +46,13 @@
46MAX_TYPO_SIZE = 346MAX_TYPO_SIZE = 3
4747
4848
49def songs_probably_equal(song_tupel):49def songs_probably_equal(song_tuple):
50 """50 """
51 Calculate and return whether two songs are probably equal.51 Calculate and return whether two songs are probably equal.
5252
53 :param song_tupel: A tuple of two songs to compare.53 :param song_tuple: A tuple of two songs to compare.
54 """54 """
55 song1, song2 = song_tupel55 song1, song2 = song_tuple
56 pos1, lyrics1 = song156 pos1, lyrics1 = song1
57 pos2, lyrics2 = song257 pos2, lyrics2 = song2
58 if len(lyrics1) < len(lyrics2):58 if len(lyrics1) < len(lyrics2):
5959
=== added file 'openlp/plugins/songs/reporting.py'
--- openlp/plugins/songs/reporting.py 1970-01-01 00:00:00 +0000
+++ openlp/plugins/songs/reporting.py 2016-09-21 19:04:20 +0000
@@ -0,0 +1,102 @@
1# -*- coding: utf-8 -*-
2# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
3
4###############################################################################
5# OpenLP - Open Source Lyrics Projection #
6# --------------------------------------------------------------------------- #
7# Copyright (c) 2008-2016 OpenLP Developers #
8# --------------------------------------------------------------------------- #
9# This program is free software; you can redistribute it and/or modify it #
10# under the terms of the GNU General Public License as published by the Free #
11# Software Foundation; version 2 of the License. #
12# #
13# This program is distributed in the hope that it will be useful, but WITHOUT #
14# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
15# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
16# more details. #
17# #
18# You should have received a copy of the GNU General Public License along #
19# with this program; if not, write to the Free Software Foundation, Inc., 59 #
20# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
21###############################################################################
22"""
23The :mod:`db` module provides the ability to provide a csv file of all songs
24"""
25import csv
26import logging
27
28from PyQt5 import QtWidgets
29
30from openlp.core.common import Registry, translate
31from openlp.core.lib.ui import critical_error_message_box
32from openlp.plugins.songs.lib.db import Song
33
34
35log = logging.getLogger(__name__)
36
37
38def report_song_list():
39 """
40 Export the song list as a CSV file.
41 :return: Nothing
42 """
43 main_window = Registry().get('main_window')
44 plugin = Registry().get('songs').plugin
45 report_file_name, filter_used = QtWidgets.QFileDialog.getSaveFileName(
46 main_window, translate('SongPlugin.ReportSongList', 'Output File Location'))
47 if not report_file_name:
48 main_window.error_message(
49 translate('SongPlugin.ReportSongList', 'Output Path Not Selected'),
50 translate('SongPlugin.ReportSongList', 'You have not set a valid output location for your '
51 'report. \nPlease select an existing path '
52 'on your computer.')
53 )
54 return
55 if not report_file_name.endswith('csv'):
56 report_file_name += '.csv'
57 file_handle = None
58 Registry().get('application').set_busy_cursor()
59 try:
60 file_handle = open(report_file_name, 'wt')
61 fieldnames = ('Title', 'Alternative Title', 'Copyright', 'Author(s)', 'Song Book', 'Topic')
62 writer = csv.DictWriter(file_handle, fieldnames=fieldnames, quoting=csv.QUOTE_ALL)
63 headers = dict((n, n) for n in fieldnames)
64 writer.writerow(headers)
65 song_list = plugin.manager.get_all_objects(Song)
66 for song in song_list:
67 author_list = []
68 for author_song in song.authors_songs:
69 author_list.append(author_song.author.display_name)
70 author_string = ' | '.join(author_list)
71 book_list = []
72 for book_song in song.songbook_entries:
73 if hasattr(book_song, 'entry') and book_song.entry:
74 book_list.append('{name} #{entry}'.format(name=book_song.songbook.name, entry=book_song.entry))
75 book_string = ' | '.join(book_list)
76 topic_list = []
77 for topic_song in song.topics:
78 if hasattr(topic_song, 'name'):
79 topic_list.append(topic_song.name)
80 topic_string = ' | '.join(topic_list)
81 writer.writerow({'Title': song.title,
82 'Alternative Title': song.alternate_title,
83 'Copyright': song.copyright,
84 'Author(s)': author_string,
85 'Song Book': book_string,
86 'Topic': topic_string})
87 Registry().get('application').set_normal_cursor()
88 main_window.information_message(
89 translate('SongPlugin.ReportSongList', 'Report Creation'),
90 translate('SongPlugin.ReportSongList',
91 'Report \n{name} \nhas been successfully created. ').format(name=report_file_name)
92 )
93 except OSError as ose:
94 Registry().get('application').set_normal_cursor()
95 log.exception('Failed to write out song usage records')
96 critical_error_message_box(translate('SongPlugin.ReportSongList', 'Song Extraction Failed'),
97 translate('SongPlugin.ReportSongList',
98 'An error occurred while extracting: {error}'
99 ).format(error=ose.strerror))
100 finally:
101 if file_handle:
102 file_handle.close()
0103
=== modified file 'openlp/plugins/songs/songsplugin.py'
--- openlp/plugins/songs/songsplugin.py 2016-03-31 16:34:22 +0000
+++ openlp/plugins/songs/songsplugin.py 2016-09-21 19:04:20 +0000
@@ -36,6 +36,7 @@
36from openlp.core.lib import Plugin, StringContent, build_icon36from openlp.core.lib import Plugin, StringContent, build_icon
37from openlp.core.lib.db import Manager37from openlp.core.lib.db import Manager
38from openlp.core.lib.ui import create_action38from openlp.core.lib.ui import create_action
39from openlp.plugins.songs import reporting
39from openlp.plugins.songs.forms.duplicatesongremovalform import DuplicateSongRemovalForm40from openlp.plugins.songs.forms.duplicatesongremovalform import DuplicateSongRemovalForm
40from openlp.plugins.songs.forms.songselectform import SongSelectForm41from openlp.plugins.songs.forms.songselectform import SongSelectForm
41from openlp.plugins.songs.lib import clean_song, upgrade42from openlp.plugins.songs.lib import clean_song, upgrade
@@ -102,13 +103,13 @@
102 self.songselect_form.initialise()103 self.songselect_form.initialise()
103 self.song_import_item.setVisible(True)104 self.song_import_item.setVisible(True)
104 self.song_export_item.setVisible(True)105 self.song_export_item.setVisible(True)
105 self.tools_reindex_item.setVisible(True)106 self.song_tools_menu.menuAction().setVisible(True)
106 self.tools_find_duplicates.setVisible(True)
107 action_list = ActionList.get_instance()107 action_list = ActionList.get_instance()
108 action_list.add_action(self.song_import_item, UiStrings().Import)108 action_list.add_action(self.song_import_item, UiStrings().Import)
109 action_list.add_action(self.song_export_item, UiStrings().Export)109 action_list.add_action(self.song_export_item, UiStrings().Export)
110 action_list.add_action(self.tools_reindex_item, UiStrings().Tools)110 action_list.add_action(self.tools_reindex_item, UiStrings().Tools)
111 action_list.add_action(self.tools_find_duplicates, UiStrings().Tools)111 action_list.add_action(self.tools_find_duplicates, UiStrings().Tools)
112 action_list.add_action(self.tools_report_song_list, UiStrings().Tools)
112113
113 def add_import_menu_item(self, import_menu):114 def add_import_menu_item(self, import_menu):
114 """115 """
@@ -151,19 +152,37 @@
151 :param tools_menu: The actual **Tools** menu item, so that your actions can use it as their parent.152 :param tools_menu: The actual **Tools** menu item, so that your actions can use it as their parent.
152 """153 """
153 log.info('add tools menu')154 log.info('add tools menu')
155 self.tools_menu = tools_menu
156 self.song_tools_menu = QtWidgets.QMenu(tools_menu)
157 self.song_tools_menu.setObjectName('song_tools_menu')
158 self.song_tools_menu.setTitle(translate('SongsPlugin', 'Songs'))
154 self.tools_reindex_item = create_action(159 self.tools_reindex_item = create_action(
155 tools_menu, 'toolsReindexItem',160 tools_menu, 'toolsReindexItem',
156 text=translate('SongsPlugin', '&Re-index Songs'),161 text=translate('SongsPlugin', '&Re-index Songs'),
157 icon=':/plugins/plugin_songs.png',162 icon=':/plugins/plugin_songs.png',
158 statustip=translate('SongsPlugin', 'Re-index the songs database to improve searching and ordering.'),163 statustip=translate('SongsPlugin', 'Re-index the songs database to improve searching and ordering.'),
159 visible=False, triggers=self.on_tools_reindex_item_triggered)164 triggers=self.on_tools_reindex_item_triggered)
160 tools_menu.addAction(self.tools_reindex_item)
161 self.tools_find_duplicates = create_action(165 self.tools_find_duplicates = create_action(
162 tools_menu, 'toolsFindDuplicates',166 tools_menu, 'toolsFindDuplicates',
163 text=translate('SongsPlugin', 'Find &Duplicate Songs'),167 text=translate('SongsPlugin', 'Find &Duplicate Songs'),
164 statustip=translate('SongsPlugin', 'Find and remove duplicate songs in the song database.'),168 statustip=translate('SongsPlugin', 'Find and remove duplicate songs in the song database.'),
165 visible=False, triggers=self.on_tools_find_duplicates_triggered, can_shortcuts=True)169 triggers=self.on_tools_find_duplicates_triggered, can_shortcuts=True)
166 tools_menu.addAction(self.tools_find_duplicates)170 self.tools_report_song_list = create_action(
171 tools_menu, 'toolsSongListReport',
172 text=translate('SongsPlugin', 'Song List Report'),
173 statustip=translate('SongsPlugin', 'Produce a CSV file of all the songs in the database.'),
174 triggers=self.on_tools_report_song_list_triggered)
175
176 self.tools_menu.addAction(self.song_tools_menu.menuAction())
177 self.song_tools_menu.addAction(self.tools_reindex_item)
178 self.song_tools_menu.addAction(self.tools_find_duplicates)
179 self.song_tools_menu.addAction(self.tools_report_song_list)
180
181 self.song_tools_menu.menuAction().setVisible(False)
182
183 @staticmethod
184 def on_tools_report_song_list_triggered():
185 reporting.report_song_list()
167186
168 def on_tools_reindex_item_triggered(self):187 def on_tools_reindex_item_triggered(self):
169 """188 """
@@ -326,13 +345,13 @@
326 self.manager.finalise()345 self.manager.finalise()
327 self.song_import_item.setVisible(False)346 self.song_import_item.setVisible(False)
328 self.song_export_item.setVisible(False)347 self.song_export_item.setVisible(False)
329 self.tools_reindex_item.setVisible(False)
330 self.tools_find_duplicates.setVisible(False)
331 action_list = ActionList.get_instance()348 action_list = ActionList.get_instance()
332 action_list.remove_action(self.song_import_item, UiStrings().Import)349 action_list.remove_action(self.song_import_item, UiStrings().Import)
333 action_list.remove_action(self.song_export_item, UiStrings().Export)350 action_list.remove_action(self.song_export_item, UiStrings().Export)
334 action_list.remove_action(self.tools_reindex_item, UiStrings().Tools)351 action_list.remove_action(self.tools_reindex_item, UiStrings().Tools)
335 action_list.remove_action(self.tools_find_duplicates, UiStrings().Tools)352 action_list.remove_action(self.tools_find_duplicates, UiStrings().Tools)
353 action_list.add_action(self.tools_report_song_list, UiStrings().Tools)
354 self.song_tools_menu.menuAction().setVisible(False)
336 super(SongsPlugin, self).finalise()355 super(SongsPlugin, self).finalise()
337356
338 def new_service_created(self):357 def new_service_created(self):
339358
=== modified file 'tests/functional/openlp_core_ui/test_servicemanager.py'
--- tests/functional/openlp_core_ui/test_servicemanager.py 2016-07-17 19:46:06 +0000
+++ tests/functional/openlp_core_ui/test_servicemanager.py 2016-09-21 19:04:20 +0000
@@ -28,6 +28,7 @@
28import PyQt528import PyQt5
2929
30from openlp.core.common import Registry, ThemeLevel30from openlp.core.common import Registry, ThemeLevel
31from openlp.core.ui.lib.toolbar import OpenLPToolbar
31from openlp.core.lib import ServiceItem, ServiceItemType, ItemCapabilities32from openlp.core.lib import ServiceItem, ServiceItemType, ItemCapabilities
32from openlp.core.ui import ServiceManager33from openlp.core.ui import ServiceManager
3334
@@ -544,8 +545,8 @@
544 self.assertEqual(service_manager.theme_menu.menuAction().setVisible.call_count, 1,545 self.assertEqual(service_manager.theme_menu.menuAction().setVisible.call_count, 1,
545 'Should have be called once')546 'Should have be called once')
546547
547 @patch(u'openlp.core.ui.servicemanager.Settings')548 @patch('openlp.core.ui.servicemanager.Settings')
548 @patch(u'PyQt5.QtCore.QTimer.singleShot')549 @patch('PyQt5.QtCore.QTimer.singleShot')
549 def test_single_click_preview_true(self, mocked_singleShot, MockedSettings):550 def test_single_click_preview_true(self, mocked_singleShot, MockedSettings):
550 """551 """
551 Test that when "Preview items when clicked in Service Manager" enabled the preview timer starts552 Test that when "Preview items when clicked in Service Manager" enabled the preview timer starts
@@ -561,8 +562,8 @@
561 mocked_singleShot.assert_called_with(PyQt5.QtWidgets.QApplication.instance().doubleClickInterval(),562 mocked_singleShot.assert_called_with(PyQt5.QtWidgets.QApplication.instance().doubleClickInterval(),
562 service_manager.on_single_click_preview_timeout)563 service_manager.on_single_click_preview_timeout)
563564
564 @patch(u'openlp.core.ui.servicemanager.Settings')565 @patch('openlp.core.ui.servicemanager.Settings')
565 @patch(u'PyQt5.QtCore.QTimer.singleShot')566 @patch('PyQt5.QtCore.QTimer.singleShot')
566 def test_single_click_preview_false(self, mocked_singleShot, MockedSettings):567 def test_single_click_preview_false(self, mocked_singleShot, MockedSettings):
567 """568 """
568 Test that when "Preview items when clicked in Service Manager" disabled the preview timer doesn't start569 Test that when "Preview items when clicked in Service Manager" disabled the preview timer doesn't start
@@ -577,9 +578,9 @@
577 # THEN: timer should not be started578 # THEN: timer should not be started
578 self.assertEqual(mocked_singleShot.call_count, 0, 'Should not be called')579 self.assertEqual(mocked_singleShot.call_count, 0, 'Should not be called')
579580
580 @patch(u'openlp.core.ui.servicemanager.Settings')581 @patch('openlp.core.ui.servicemanager.Settings')
581 @patch(u'PyQt5.QtCore.QTimer.singleShot')582 @patch('PyQt5.QtCore.QTimer.singleShot')
582 @patch(u'openlp.core.ui.servicemanager.ServiceManager.make_live')583 @patch('openlp.core.ui.servicemanager.ServiceManager.make_live')
583 def test_single_click_preview_double(self, mocked_make_live, mocked_singleShot, MockedSettings):584 def test_single_click_preview_double(self, mocked_make_live, mocked_singleShot, MockedSettings):
584 """585 """
585 Test that when a double click has registered the preview timer doesn't start586 Test that when a double click has registered the preview timer doesn't start
@@ -596,7 +597,7 @@
596 mocked_make_live.assert_called_with()597 mocked_make_live.assert_called_with()
597 self.assertEqual(mocked_singleShot.call_count, 0, 'Should not be called')598 self.assertEqual(mocked_singleShot.call_count, 0, 'Should not be called')
598599
599 @patch(u'openlp.core.ui.servicemanager.ServiceManager.make_preview')600 @patch('openlp.core.ui.servicemanager.ServiceManager.make_preview')
600 def test_single_click_timeout_single(self, mocked_make_preview):601 def test_single_click_timeout_single(self, mocked_make_preview):
601 """602 """
602 Test that when a single click has been registered, the item is sent to preview603 Test that when a single click has been registered, the item is sent to preview
@@ -609,8 +610,8 @@
609 self.assertEqual(mocked_make_preview.call_count, 1,610 self.assertEqual(mocked_make_preview.call_count, 1,
610 'ServiceManager.make_preview() should have been called once')611 'ServiceManager.make_preview() should have been called once')
611612
612 @patch(u'openlp.core.ui.servicemanager.ServiceManager.make_preview')613 @patch('openlp.core.ui.servicemanager.ServiceManager.make_preview')
613 @patch(u'openlp.core.ui.servicemanager.ServiceManager.make_live')614 @patch('openlp.core.ui.servicemanager.ServiceManager.make_live')
614 def test_single_click_timeout_double(self, mocked_make_live, mocked_make_preview):615 def test_single_click_timeout_double(self, mocked_make_live, mocked_make_preview):
615 """616 """
616 Test that when a double click has been registered, the item does not goes to preview617 Test that when a double click has been registered, the item does not goes to preview
@@ -623,9 +624,9 @@
623 # THEN: make_preview() should not have been called624 # THEN: make_preview() should not have been called
624 self.assertEqual(mocked_make_preview.call_count, 0, 'ServiceManager.make_preview() should not be called')625 self.assertEqual(mocked_make_preview.call_count, 0, 'ServiceManager.make_preview() should not be called')
625626
626 @patch(u'openlp.core.ui.servicemanager.shutil.copy')627 @patch('openlp.core.ui.servicemanager.shutil.copy')
627 @patch(u'openlp.core.ui.servicemanager.zipfile')628 @patch('openlp.core.ui.servicemanager.zipfile')
628 @patch(u'openlp.core.ui.servicemanager.ServiceManager.save_file_as')629 @patch('openlp.core.ui.servicemanager.ServiceManager.save_file_as')
629 def test_save_file_raises_permission_error(self, mocked_save_file_as, mocked_zipfile, mocked_shutil_copy):630 def test_save_file_raises_permission_error(self, mocked_save_file_as, mocked_zipfile, mocked_shutil_copy):
630 """631 """
631 Test that when a PermissionError is raised when trying to save a file, it is handled correctly632 Test that when a PermissionError is raised when trying to save a file, it is handled correctly
@@ -652,9 +653,9 @@
652 self.assertTrue(result)653 self.assertTrue(result)
653 mocked_save_file_as.assert_called_with()654 mocked_save_file_as.assert_called_with()
654655
655 @patch(u'openlp.core.ui.servicemanager.shutil.copy')656 @patch('openlp.core.ui.servicemanager.shutil.copy')
656 @patch(u'openlp.core.ui.servicemanager.zipfile')657 @patch('openlp.core.ui.servicemanager.zipfile')
657 @patch(u'openlp.core.ui.servicemanager.ServiceManager.save_file_as')658 @patch('openlp.core.ui.servicemanager.ServiceManager.save_file_as')
658 def test_save_local_file_raises_permission_error(self, mocked_save_file_as, mocked_zipfile, mocked_shutil_copy):659 def test_save_local_file_raises_permission_error(self, mocked_save_file_as, mocked_zipfile, mocked_shutil_copy):
659 """660 """
660 Test that when a PermissionError is raised when trying to save a local file, it is handled correctly661 Test that when a PermissionError is raised when trying to save a local file, it is handled correctly
@@ -679,3 +680,66 @@
679 # THEN: The "save_as" method is called to save the service680 # THEN: The "save_as" method is called to save the service
680 self.assertTrue(result)681 self.assertTrue(result)
681 mocked_save_file_as.assert_called_with()682 mocked_save_file_as.assert_called_with()
683
684 @patch('openlp.core.ui.servicemanager.ServiceManager.regenerate_service_items')
685 def test_theme_change_global(self, mocked_regenerate_service_items):
686 """
687 Test that when a Toolbar theme combobox displays correctly when the theme is set to Global
688 """
689 # GIVEN: A service manager, a service to display with a theme level in the renderer
690 mocked_renderer = MagicMock()
691 service_manager = ServiceManager(None)
692 Registry().register('renderer', mocked_renderer)
693 service_manager.toolbar = OpenLPToolbar(None)
694 service_manager.toolbar.add_toolbar_action('theme_combo_box', triggers=MagicMock())
695 service_manager.toolbar.add_toolbar_action('theme_label', triggers=MagicMock())
696
697 # WHEN: The service manager has a Global theme
698 mocked_renderer.theme_level = ThemeLevel.Global
699 result = service_manager.theme_change()
700
701 # THEN: The the theme toolbar should not be visible
702 self.assertFalse(service_manager.toolbar.actions['theme_combo_box'].isVisible(),
703 'The visibility should be False')
704
705 @patch('openlp.core.ui.servicemanager.ServiceManager.regenerate_service_items')
706 def test_theme_change_service(self, mocked_regenerate_service_items):
707 """
708 Test that when a Toolbar theme combobox displays correctly when the theme is set to Theme
709 """
710 # GIVEN: A service manager, a service to display with a theme level in the renderer
711 mocked_renderer = MagicMock()
712 service_manager = ServiceManager(None)
713 Registry().register('renderer', mocked_renderer)
714 service_manager.toolbar = OpenLPToolbar(None)
715 service_manager.toolbar.add_toolbar_action('theme_combo_box', triggers=MagicMock())
716 service_manager.toolbar.add_toolbar_action('theme_label', triggers=MagicMock())
717
718 # WHEN: The service manager has a Service theme
719 mocked_renderer.theme_level = ThemeLevel.Service
720 result = service_manager.theme_change()
721
722 # THEN: The the theme toolbar should be visible
723 self.assertTrue(service_manager.toolbar.actions['theme_combo_box'].isVisible(),
724 'The visibility should be True')
725
726 @patch('openlp.core.ui.servicemanager.ServiceManager.regenerate_service_items')
727 def test_theme_change_song(self, mocked_regenerate_service_items):
728 """
729 Test that when a Toolbar theme combobox displays correctly when the theme is set to Song
730 """
731 # GIVEN: A service manager, a service to display with a theme level in the renderer
732 mocked_renderer = MagicMock()
733 service_manager = ServiceManager(None)
734 Registry().register('renderer', mocked_renderer)
735 service_manager.toolbar = OpenLPToolbar(None)
736 service_manager.toolbar.add_toolbar_action('theme_combo_box', triggers=MagicMock())
737 service_manager.toolbar.add_toolbar_action('theme_label', triggers=MagicMock())
738
739 # WHEN: The service manager has a Song theme
740 mocked_renderer.theme_level = ThemeLevel.Song
741 result = service_manager.theme_change()
742
743 # THEN: The the theme toolbar should be visible
744 self.assertTrue(service_manager.toolbar.actions['theme_combo_box'].isVisible(),
745 'The visibility should be True')