openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #30395
[Merge] lp:~trb143/openlp/reporting into lp:openlp
Tim Bentley has proposed merging lp:~trb143/openlp/reporting into lp:openlp.
Requested reviews:
OpenLP Core (openlp-core)
For more details, see:
https://code.launchpad.net/~trb143/openlp/reporting/+merge/305167
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
lp:~trb143/openlp/reporting (revision 2698)
[SUCCESS] https://ci.openlp.io/job/Branch-01-Pull/1766/
[SUCCESS] https://ci.openlp.io/job/Branch-02-Functional-Tests/1677/
[SUCCESS] https://ci.openlp.io/job/Branch-03-Interface-Tests/1615/
[SUCCESS] https://ci.openlp.io/job/Branch-04a-Windows_Functional_Tests/1371/
[SUCCESS] https://ci.openlp.io/job/Branch-04b-Windows_Interface_Tests/961/
[SUCCESS] https://ci.openlp.io/job/Branch-05a-Code_Analysis/1029/
[SUCCESS] https://ci.openlp.io/job/Branch-05b-Test_Coverage/897/
[SUCCESS] https://ci.openlp.io/job/Branch-05c-Code_Analysis2/61/
--
Your team OpenLP Core is requested to review the proposed merge of lp:~trb143/openlp/reporting into lp:openlp.
=== 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-08 05:12:22 +0000
@@ -379,6 +379,7 @@
'shortcuts/themeScreen': [QtGui.QKeySequence(QtCore.Qt.Key_T)],
'shortcuts/toolsReindexItem': [],
'shortcuts/toolsFindDuplicates': [],
+ 'shortcuts/ReportSongList': [],
'shortcuts/toolsAlertItem': [QtGui.QKeySequence(QtCore.Qt.Key_F7)],
'shortcuts/toolsFirstTimeWizard': [],
'shortcuts/toolsOpenDataFolder': [],
=== 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-08 05:12:22 +0000
@@ -350,7 +350,7 @@
:param string: The search string
:param show_error: The error string to be show.
"""
- search = '%{search}%'.forma(search=string.lower())
+ search = '%{search}%'.format(search=string.lower())
search_results = self.plugin.db_manager.get_all_objects(CustomSlide,
or_(func.lower(CustomSlide.title).like(search),
func.lower(CustomSlide.text).like(search)),
=== 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-08 05:12:22 +0000
@@ -317,7 +317,7 @@
self.song.verse_order = re.sub('([' + verse.upper() + verse.lower() + '])(\W|$)',
r'\g<1>1\2', self.song.verse_order)
except:
- log.exception('Problem processing song Lyrics \n{xml}'.forma(xml=sxml.dump_xml()))
+ log.exception('Problem processing song Lyrics \n{xml}'.format(xml=sxml.dump_xml()))
raise
def keyPressEvent(self, event):
=== 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-08 05:12:22 +0000
@@ -46,13 +46,13 @@
MAX_TYPO_SIZE = 3
-def songs_probably_equal(song_tupel):
+def songs_probably_equal(song_tuple):
"""
Calculate and return whether two songs are probably equal.
- :param song_tupel: A tuple of two songs to compare.
+ :param song_tuple: A tuple of two songs to compare.
"""
- song1, song2 = song_tupel
+ song1, song2 = song_tuple
pos1, lyrics1 = song1
pos2, lyrics2 = song2
if len(lyrics1) < len(lyrics2):
=== 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-08 05:12:22 +0000
@@ -0,0 +1,97 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2016 OpenLP Developers #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+The :mod:`db` module provides the ability to provide a csv file of all songs
+"""
+import logging
+import os
+
+from PyQt5 import QtWidgets
+
+from openlp.core.common import Registry, check_directory_exists, translate
+from openlp.core.lib.ui import critical_error_message_box
+from openlp.plugins.songs.lib.db import Song
+
+
+log = logging.getLogger(__name__)
+
+
+def report_song_list():
+ """
+ Export the song list as a CSV file.
+ :return: Nothing
+ """
+ main_window = Registry().get('main_window')
+ plugin = Registry().get('songs').plugin
+ path = QtWidgets.QFileDialog.getExistingDirectory(
+ main_window, translate('SongPlugin.ReportSongList', 'Output File Location'))
+ if not path:
+ main_window.error_message(
+ translate('SongPlugin.ReportSongList', 'Output Path Not Selected'),
+ translate('SongPlugin.ReportSongList', 'You have not set a valid output location for your'
+ 'report. \nPlease select an existing path '
+ 'on your computer.')
+ )
+ return
+ check_directory_exists(path)
+ report_file_name = os.path.join(path, 'song_index.csv')
+ file_handle = None
+ try:
+ file_handle = open(report_file_name, 'wb')
+ song_list = plugin.manager.get_all_objects(Song)
+ for song in song_list:
+ record = '\"{title}\",'.format(title=song.title)
+ record += '\"{title}\",'.format(title=song.alternate_title)
+ record += '\"{title}\",'.format(title=song.copyright)
+ author_list = []
+ for author_song in song.authors_songs:
+ author_list.append(author_song.author.display_name)
+ author_string = '\"{name}\"'.format(name=' | '.join(author_list))
+ book_list = []
+ for book_song in song.songbook_entries:
+ if hasattr(book_song, 'entry') and book_song.entry:
+ book_list.append('{name} #{entry}'.format(name=book_song.songbook.name, entry=book_song.entry))
+ book_string = '\"{name}\"'.format(name=' | '.join(book_list))
+ topic_list = []
+ for topic_song in song.topics:
+ if hasattr(topic_song, 'name'):
+ topic_list.append(topic_song.name)
+ topic_string = '\"{name}\"'.format(name=' | '.join(topic_list))
+ record += '{title},'.format(title=author_string)
+ record += '{title},'.format(title=book_string)
+ record += '{title},'.format(title=topic_string)
+ record += '\n'
+ file_handle.write(record.encode('utf-8'))
+ main_window.information_message(
+ translate('SongPlugin.ReportSongList', 'Report Creation'),
+ translate('SongPlugin.ReportSongList',
+ 'Report \n{name} \nhas been successfully created. ').format(name=report_file_name)
+ )
+ except OSError as ose:
+ log.exception('Failed to write out song usage records')
+ critical_error_message_box(translate('SongPlugin.ReportSongList', 'Song Extraction Failed'),
+ translate('SongPlugin.ReportSongList',
+ 'An error occurred while extracting: {error}'
+ ).format(error=ose.strerror))
+ finally:
+ if file_handle:
+ file_handle.close()
=== 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-08 05:12:22 +0000
@@ -36,6 +36,7 @@
from openlp.core.lib import Plugin, StringContent, build_icon
from openlp.core.lib.db import Manager
from openlp.core.lib.ui import create_action
+from openlp.plugins.songs import reporting
from openlp.plugins.songs.forms.duplicatesongremovalform import DuplicateSongRemovalForm
from openlp.plugins.songs.forms.songselectform import SongSelectForm
from openlp.plugins.songs.lib import clean_song, upgrade
@@ -102,13 +103,13 @@
self.songselect_form.initialise()
self.song_import_item.setVisible(True)
self.song_export_item.setVisible(True)
- self.tools_reindex_item.setVisible(True)
- self.tools_find_duplicates.setVisible(True)
+ self.song_tools_menu.menuAction().setVisible(True)
action_list = ActionList.get_instance()
action_list.add_action(self.song_import_item, UiStrings().Import)
action_list.add_action(self.song_export_item, UiStrings().Export)
action_list.add_action(self.tools_reindex_item, UiStrings().Tools)
action_list.add_action(self.tools_find_duplicates, UiStrings().Tools)
+ action_list.add_action(self.tools_report_song_list, UiStrings().Tools)
def add_import_menu_item(self, import_menu):
"""
@@ -151,19 +152,37 @@
:param tools_menu: The actual **Tools** menu item, so that your actions can use it as their parent.
"""
log.info('add tools menu')
+ self.tools_menu = tools_menu
+ self.song_tools_menu = QtWidgets.QMenu(tools_menu)
+ self.song_tools_menu.setObjectName('song_tools_menu')
+ self.song_tools_menu.setTitle(translate('SongsPlugin', 'Song Tools'))
self.tools_reindex_item = create_action(
tools_menu, 'toolsReindexItem',
text=translate('SongsPlugin', '&Re-index Songs'),
icon=':/plugins/plugin_songs.png',
statustip=translate('SongsPlugin', 'Re-index the songs database to improve searching and ordering.'),
- visible=False, triggers=self.on_tools_reindex_item_triggered)
- tools_menu.addAction(self.tools_reindex_item)
+ triggers=self.on_tools_reindex_item_triggered)
self.tools_find_duplicates = create_action(
tools_menu, 'toolsFindDuplicates',
text=translate('SongsPlugin', 'Find &Duplicate Songs'),
statustip=translate('SongsPlugin', 'Find and remove duplicate songs in the song database.'),
- visible=False, triggers=self.on_tools_find_duplicates_triggered, can_shortcuts=True)
- tools_menu.addAction(self.tools_find_duplicates)
+ triggers=self.on_tools_find_duplicates_triggered, can_shortcuts=True)
+ self.tools_report_song_list = create_action(
+ tools_menu, 'ReportSongList',
+ text=translate('SongsPlugin', 'Export List of Songs'),
+ statustip=translate('SongsPlugin', 'Produce a CSV file of all the songs in the database.'),
+ triggers=self.on_tools_report_song_list_triggered)
+
+ self.tools_menu.addAction(self.song_tools_menu.menuAction())
+ self.song_tools_menu.addAction(self.tools_reindex_item)
+ self.song_tools_menu.addAction(self.tools_find_duplicates)
+ self.song_tools_menu.addAction(self.tools_report_song_list)
+
+ self.song_tools_menu.menuAction().setVisible(False)
+
+ @staticmethod
+ def on_tools_report_song_list_triggered():
+ reporting.report_song_list()
def on_tools_reindex_item_triggered(self):
"""
@@ -326,13 +345,13 @@
self.manager.finalise()
self.song_import_item.setVisible(False)
self.song_export_item.setVisible(False)
- self.tools_reindex_item.setVisible(False)
- self.tools_find_duplicates.setVisible(False)
action_list = ActionList.get_instance()
action_list.remove_action(self.song_import_item, UiStrings().Import)
action_list.remove_action(self.song_export_item, UiStrings().Export)
action_list.remove_action(self.tools_reindex_item, UiStrings().Tools)
action_list.remove_action(self.tools_find_duplicates, UiStrings().Tools)
+ action_list.add_action(self.tools_report_song_list, UiStrings().Tools)
+ self.song_tools_menu.menuAction().setVisible(False)
super(SongsPlugin, self).finalise()
def new_service_created(self):
=== 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-08 05:12:22 +0000
@@ -28,6 +28,7 @@
import PyQt5
from openlp.core.common import Registry, ThemeLevel
+from openlp.core.ui.lib.toolbar import OpenLPToolbar
from openlp.core.lib import ServiceItem, ServiceItemType, ItemCapabilities
from openlp.core.ui import ServiceManager
@@ -679,3 +680,72 @@
# THEN: The "save_as" method is called to save the service
self.assertTrue(result)
mocked_save_file_as.assert_called_with()
+
+ @patch(u'openlp.core.ui.servicemanager.ServiceManager.regenerate_service_items')
+ def test_theme_change_global(self, mocked_regenerate_service_items):
+ """
+ Test that when a Toolbar theme combobox displays correctly
+ """
+
+ # GIVEN: A service manager, a service to save with a theme level of the renderer
+ mocked_renderer = MagicMock()
+ service_manager = ServiceManager(None)
+ Registry().register('renderer', mocked_renderer)
+ service_manager.toolbar = OpenLPToolbar(None)
+ service_manager.toolbar.add_toolbar_action('theme_combo_box', triggers=MagicMock())
+ service_manager.toolbar.add_toolbar_action('theme_label', triggers=MagicMock())
+
+ # WHEN: The service manager has a Global theme
+ mocked_renderer.theme_level = ThemeLevel.Global
+ result = service_manager.theme_change()
+
+ # THEN: The the theme toolbar should not be visible
+
+ self.assertFalse(service_manager.toolbar.actions['theme_combo_box'].isVisible(),
+ 'The visibility should be False')
+
+ @patch(u'openlp.core.ui.servicemanager.ServiceManager.regenerate_service_items')
+ def test_theme_change_service(self, mocked_regenerate_service_items):
+ """
+ Test that when a Toolbar theme combobox displays correctly
+ """
+
+ # GIVEN: A service manager, a service to save with a theme level of the renderer
+ mocked_renderer = MagicMock()
+ service_manager = ServiceManager(None)
+ Registry().register('renderer', mocked_renderer)
+ service_manager.toolbar = OpenLPToolbar(None)
+ service_manager.toolbar.add_toolbar_action('theme_combo_box', triggers=MagicMock())
+ service_manager.toolbar.add_toolbar_action('theme_label', triggers=MagicMock())
+
+ # WHEN: The service manager has a Global theme
+ mocked_renderer.theme_level = ThemeLevel.Service
+ result = service_manager.theme_change()
+
+ # THEN: The the theme toolbar should not be visible
+
+ self.assertTrue(service_manager.toolbar.actions['theme_combo_box'].isVisible(),
+ 'The visibility should be True')
+
+ @patch(u'openlp.core.ui.servicemanager.ServiceManager.regenerate_service_items')
+ def test_theme_change_song(self, mocked_regenerate_service_items):
+ """
+ Test that when a Toolbar theme combobox displays correctly
+ """
+
+ # GIVEN: A service manager, a service to save with a theme level of the renderer
+ mocked_renderer = MagicMock()
+ service_manager = ServiceManager(None)
+ Registry().register('renderer', mocked_renderer)
+ service_manager.toolbar = OpenLPToolbar(None)
+ service_manager.toolbar.add_toolbar_action('theme_combo_box', triggers=MagicMock())
+ service_manager.toolbar.add_toolbar_action('theme_label', triggers=MagicMock())
+
+ # WHEN: The service manager has a Global theme
+ mocked_renderer.theme_level = ThemeLevel.Song
+ result = service_manager.theme_change()
+
+ # THEN: The the theme toolbar should not be visible
+
+ self.assertTrue(service_manager.toolbar.actions['theme_combo_box'].isVisible(),
+ 'The visibility should be True')
Follow ups