From 73ec92ae13632028196eeef547228f7527593519 Mon Sep 17 00:00:00 2001 From: Stewart Becker Date: Mon, 21 Jul 2014 07:37:41 +0100 Subject: [PATCH 1/6] Added option to wrap footer text --- openlp/core/common/settings.py | 1 + openlp/core/lib/htmlbuilder.py | 6 ++++-- openlp/core/ui/themestab.py | 14 ++++++++++++++ openlp/plugins/songs/lib/__init__.py | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/openlp/core/common/settings.py b/openlp/core/common/settings.py index 3b7b31ca1..634bc5ced 100644 --- a/openlp/core/common/settings.py +++ b/openlp/core/common/settings.py @@ -286,6 +286,7 @@ class Settings(QtCore.QSettings): 'themes/last directory export': '', 'themes/last directory import': '', 'themes/theme level': ThemeLevel.Song, + 'themes/wrap footer': False, 'user interface/live panel': True, 'user interface/live splitter geometry': QtCore.QByteArray(), 'user interface/lock panel': False, diff --git a/openlp/core/lib/htmlbuilder.py b/openlp/core/lib/htmlbuilder.py index 473aa9d7d..058e5a2a1 100644 --- a/openlp/core/lib/htmlbuilder.py +++ b/openlp/core/lib/htmlbuilder.py @@ -398,6 +398,7 @@ import logging from PyQt4 import QtWebKit +from openlp.core.common import Settings from openlp.core.lib.theme import BackgroundType, BackgroundGradientType, VerticalType, HorizontalType log = logging.getLogger(__name__) @@ -750,12 +751,13 @@ def build_footer_css(item, height): font-size: %spt; color: %s; text-align: left; - white-space: nowrap; + white-space: %s; """ theme = item.theme_data if not theme or not item.footer: return '' bottom = height - int(item.footer.y()) - int(item.footer.height()) + whitespace = 'normal' if Settings().value('themes/wrap footer') else 'nowrap' lyrics_html = style % (item.footer.x(), bottom, item.footer.width(), - theme.font_footer_name, theme.font_footer_size, theme.font_footer_color) + theme.font_footer_name, theme.font_footer_size, theme.font_footer_color, whitespace) return lyrics_html diff --git a/openlp/core/ui/themestab.py b/openlp/core/ui/themestab.py index 0478f0ed0..230439566 100644 --- a/openlp/core/ui/themestab.py +++ b/openlp/core/ui/themestab.py @@ -69,6 +69,14 @@ class ThemesTab(SettingsTab): self.default_list_view.setObjectName('default_list_view') self.global_group_box_layout.addWidget(self.default_list_view) self.left_layout.addWidget(self.global_group_box) + self.universal_group_box = QtGui.QGroupBox(self.left_column) + self.universal_group_box.setObjectName('universal_group_box') + self.universal_group_box_layout = QtGui.QVBoxLayout(self.universal_group_box) + self.universal_group_box_layout.setObjectName('universal_group_box_layout') + self.wrap_footer_check_box = QtGui.QCheckBox(self.universal_group_box) + self.wrap_footer_check_box.setObjectName('wrap_footer_check_box') + self.universal_group_box_layout.addWidget(self.wrap_footer_check_box) + self.left_layout.addWidget(self.universal_group_box) self.left_layout.addStretch() self.level_group_box = QtGui.QGroupBox(self.right_column) self.level_group_box.setObjectName('level_group_box') @@ -112,6 +120,8 @@ class ThemesTab(SettingsTab): """ self.tab_title_visible = UiStrings().Themes self.global_group_box.setTitle(translate('OpenLP.ThemesTab', 'Global Theme')) + self.universal_group_box.setTitle(translate('OpenLP.ThemesTab', 'Universal Settings')) + self.wrap_footer_check_box.setText(translate('OpenLP.ThemesTab', '&Wrap footer text')) self.level_group_box.setTitle(translate('OpenLP.ThemesTab', 'Theme Level')) self.song_level_radio_button.setText(translate('OpenLP.ThemesTab', 'S&ong Level')) self.song_level_label.setText( @@ -136,6 +146,7 @@ class ThemesTab(SettingsTab): settings.beginGroup(self.settings_section) self.theme_level = settings.value('theme level') self.global_theme = settings.value('global theme') + wrap_footer = settings.value('wrap footer') settings.endGroup() if self.theme_level == ThemeLevel.Global: self.global_level_radio_button.setChecked(True) @@ -143,15 +154,18 @@ class ThemesTab(SettingsTab): self.service_level_radio_button.setChecked(True) else: self.song_level_radio_button.setChecked(True) + self.wrap_footer_check_box.setChecked(wrap_footer) def save(self): """ Save the settings """ + wrap_footer = self.wrap_footer_check_box.isChecked() settings = Settings() settings.beginGroup(self.settings_section) settings.setValue('theme level', self.theme_level) settings.setValue('global theme', self.global_theme) + settings.setValue('wrap footer', wrap_footer) settings.endGroup() self.renderer.set_theme_level(self.theme_level) if self.tab_visited: diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index d03bdefd6..999f51fad 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -374,7 +374,7 @@ def clean_song(manager, song): :param manager: The song database manager object. :param song: The song object. """ - from .xml import SongXML + from .openlyricsxml import SongXML if song.title: song.title = clean_title(song.title) From 2555bc50d4ed202b13a5d0c60ead773b8a4e3b21 Mon Sep 17 00:00:00 2001 From: Stewart Becker Date: Mon, 21 Jul 2014 18:13:20 +0100 Subject: [PATCH 2/6] Add test for wrap footer setting --- .../openlp_core_lib/test_htmlbuilder.py | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/tests/functional/openlp_core_lib/test_htmlbuilder.py b/tests/functional/openlp_core_lib/test_htmlbuilder.py index ef5ffdf43..a68e14061 100644 --- a/tests/functional/openlp_core_lib/test_htmlbuilder.py +++ b/tests/functional/openlp_core_lib/test_htmlbuilder.py @@ -6,10 +6,12 @@ from unittest import TestCase from PyQt4 import QtCore +from openlp.core.common import Settings from openlp.core.lib.htmlbuilder import build_html, build_background_css, build_lyrics_css, build_lyrics_outline_css, \ build_lyrics_format_css, build_footer_css from openlp.core.lib.theme import HorizontalType, VerticalType from tests.functional import MagicMock, patch +from tests.helpers.testmixin import TestMixin HTML = """ @@ -184,7 +186,7 @@ LYRICS_OUTLINE_CSS = ' -webkit-text-stroke: 0.125em #000000; -webkit-text-fill-c LYRICS_FORMAT_CSS = ' word-wrap: break-word; text-align: justify; vertical-align: bottom; ' + \ 'font-family: Arial; font-size: 40pt; color: #FFFFFF; line-height: 108%; margin: 0;padding: 0; ' + \ 'padding-bottom: 0.5em; padding-left: 2px; width: 1580px; height: 810px; font-style:italic; font-weight:bold; ' -FOOTER_CSS = """ +FOOTER_CSS_BASE = """ left: 10px; bottom: 0px; width: 1260px; @@ -192,11 +194,29 @@ FOOTER_CSS = """ font-size: 12pt; color: #FFFFFF; text-align: left; - white-space: nowrap; + white-space: %s; """ +FOOTER_CSS = FOOTER_CSS_BASE % ('nowrap') +FOOTER_CSS_WRAP = FOOTER_CSS_BASE % ('normal') + + +class Htmbuilder(TestCase, TestMixin): + """ + Test the functions in the Htmlbuilder module + """ + def setUp(self): + """ + Create the UI + """ + self.build_settings() + + def tearDown(self): + """ + Delete all the C++ objects at the end so that we don't have a segfault + """ + self.destroy_settings() -class Htmbuilder(TestCase): def build_html_test(self): """ Test the build_html() function @@ -316,8 +336,15 @@ class Htmbuilder(TestCase): item.theme_data.font_footer_color = '#FFFFFF' height = 1024 - # WHEN: create the css. + # WHEN: create the css with default settings. css = build_footer_css(item, height) # THEN: THE css should be the same. assert FOOTER_CSS == css, 'The footer strings should be equal.' + + # WHEN: Settings say that footer should wrap + Settings().setValue('themes/wrap footer', True) + css = build_footer_css(item, height) + + # THEN: Footer should wrap + assert FOOTER_CSS_WRAP == css, 'The footer strings should be equal.' From 9a1ce000b7bfa79216d6aa6eb5ba767c9a7f6194 Mon Sep 17 00:00:00 2001 From: Stewart Becker Date: Mon, 21 Jul 2014 22:45:27 +0100 Subject: [PATCH 3/6] Patch Registry.execute so that it is undoen at end of test --- .../openlp_core_ui/test_slidecontroller.py | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/tests/functional/openlp_core_ui/test_slidecontroller.py b/tests/functional/openlp_core_ui/test_slidecontroller.py index ed237d424..ea68b8ae9 100644 --- a/tests/functional/openlp_core_ui/test_slidecontroller.py +++ b/tests/functional/openlp_core_ui/test_slidecontroller.py @@ -508,18 +508,18 @@ class TestSlideController(TestCase): mocked_update_preview = MagicMock() mocked_preview_widget = MagicMock() mocked_slide_selected = MagicMock() - Registry.execute = mocked_execute - Registry.create() - slide_controller = SlideController(None) - slide_controller.service_item = mocked_item - slide_controller.update_preview = mocked_update_preview - slide_controller.preview_widget = mocked_preview_widget - slide_controller.slide_selected = mocked_slide_selected - slide_controller.is_live = True - - # WHEN: The method is called - slide_controller.on_slide_selected_index([9]) - + with patch.object(Registry, 'execute') as mocked_execute: + Registry.create() + slide_controller = SlideController(None) + slide_controller.service_item = mocked_item + slide_controller.update_preview = mocked_update_preview + slide_controller.preview_widget = mocked_preview_widget + slide_controller.slide_selected = mocked_slide_selected + slide_controller.is_live = True + + # WHEN: The method is called + slide_controller.on_slide_selected_index([9]) + # THEN: It should have sent a notification mocked_item.is_command.assert_called_once_with() mocked_execute.assert_called_once_with('mocked item_slide', [mocked_item, True, 9]) @@ -539,16 +539,16 @@ class TestSlideController(TestCase): mocked_update_preview = MagicMock() mocked_preview_widget = MagicMock() mocked_slide_selected = MagicMock() - Registry.execute = mocked_execute - Registry.create() - slide_controller = SlideController(None) - slide_controller.service_item = mocked_item - slide_controller.update_preview = mocked_update_preview - slide_controller.preview_widget = mocked_preview_widget - slide_controller.slide_selected = mocked_slide_selected - - # WHEN: The method is called - slide_controller.on_slide_selected_index([7]) + with patch.object(Registry, 'execute') as mocked_execute: + Registry.create() + slide_controller = SlideController(None) + slide_controller.service_item = mocked_item + slide_controller.update_preview = mocked_update_preview + slide_controller.preview_widget = mocked_preview_widget + slide_controller.slide_selected = mocked_slide_selected + + # WHEN: The method is called + slide_controller.on_slide_selected_index([7]) # THEN: It should have sent a notification mocked_item.is_command.assert_called_once_with() @@ -556,3 +556,5 @@ class TestSlideController(TestCase): self.assertEqual(0, mocked_update_preview.call_count, 'Update preview should not have been called') mocked_preview_widget.change_slide.assert_called_once_with(7) mocked_slide_selected.assert_called_once_with() + + From 668864c38d474ca3e56c7e984f0553f9a44d8027 Mon Sep 17 00:00:00 2001 From: Stewart Becker Date: Tue, 22 Jul 2014 21:06:48 +0100 Subject: [PATCH 4/6] Tidy up tests and formatting --- .../functional/openlp_core_lib/test_htmlbuilder.py | 14 ++++++++++++-- .../openlp_core_ui/test_slidecontroller.py | 10 +++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/tests/functional/openlp_core_lib/test_htmlbuilder.py b/tests/functional/openlp_core_lib/test_htmlbuilder.py index a68e14061..e98dfc687 100644 --- a/tests/functional/openlp_core_lib/test_htmlbuilder.py +++ b/tests/functional/openlp_core_lib/test_htmlbuilder.py @@ -13,7 +13,6 @@ from openlp.core.lib.theme import HorizontalType, VerticalType from tests.functional import MagicMock, patch from tests.helpers.testmixin import TestMixin - HTML = """ @@ -216,7 +215,6 @@ class Htmbuilder(TestCase, TestMixin): """ self.destroy_settings() - def build_html_test(self): """ Test the build_html() function @@ -342,6 +340,18 @@ class Htmbuilder(TestCase, TestMixin): # THEN: THE css should be the same. assert FOOTER_CSS == css, 'The footer strings should be equal.' + def build_footer_css_wrap_test(self): + """ + Test the build_footer_css() function + """ + # GIVEN: Create a theme. + item = MagicMock() + item.footer = QtCore.QRect(10, 921, 1260, 103) + item.theme_data.font_footer_name = 'Arial' + item.theme_data.font_footer_size = 12 + item.theme_data.font_footer_color = '#FFFFFF' + height = 1024 + # WHEN: Settings say that footer should wrap Settings().setValue('themes/wrap footer', True) css = build_footer_css(item, height) diff --git a/tests/functional/openlp_core_ui/test_slidecontroller.py b/tests/functional/openlp_core_ui/test_slidecontroller.py index ea68b8ae9..1d241a317 100644 --- a/tests/functional/openlp_core_ui/test_slidecontroller.py +++ b/tests/functional/openlp_core_ui/test_slidecontroller.py @@ -504,7 +504,6 @@ class TestSlideController(TestCase): mocked_item = MagicMock() mocked_item.is_command.return_value = True mocked_item.name = 'Mocked Item' - mocked_execute = MagicMock() mocked_update_preview = MagicMock() mocked_preview_widget = MagicMock() mocked_slide_selected = MagicMock() @@ -516,10 +515,10 @@ class TestSlideController(TestCase): slide_controller.preview_widget = mocked_preview_widget slide_controller.slide_selected = mocked_slide_selected slide_controller.is_live = True - + # WHEN: The method is called slide_controller.on_slide_selected_index([9]) - + # THEN: It should have sent a notification mocked_item.is_command.assert_called_once_with() mocked_execute.assert_called_once_with('mocked item_slide', [mocked_item, True, 9]) @@ -535,7 +534,6 @@ class TestSlideController(TestCase): mocked_item = MagicMock() mocked_item.is_command.return_value = False mocked_item.name = 'Mocked Item' - mocked_execute = MagicMock() mocked_update_preview = MagicMock() mocked_preview_widget = MagicMock() mocked_slide_selected = MagicMock() @@ -546,7 +544,7 @@ class TestSlideController(TestCase): slide_controller.update_preview = mocked_update_preview slide_controller.preview_widget = mocked_preview_widget slide_controller.slide_selected = mocked_slide_selected - + # WHEN: The method is called slide_controller.on_slide_selected_index([7]) @@ -556,5 +554,3 @@ class TestSlideController(TestCase): self.assertEqual(0, mocked_update_preview.call_count, 'Update preview should not have been called') mocked_preview_widget.change_slide.assert_called_once_with(7) mocked_slide_selected.assert_called_once_with() - - From d90fcface2853d0d6d0f4abc18168e20eb317f97 Mon Sep 17 00:00:00 2001 From: Stewart Becker Date: Thu, 24 Jul 2014 20:28:57 +0100 Subject: [PATCH 5/6] Style fixes for Tim --- openlp/core/ui/themestab.py | 6 ++---- tests/functional/openlp_core_lib/test_htmlbuilder.py | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/openlp/core/ui/themestab.py b/openlp/core/ui/themestab.py index 230439566..4b3f8b6eb 100644 --- a/openlp/core/ui/themestab.py +++ b/openlp/core/ui/themestab.py @@ -146,7 +146,7 @@ class ThemesTab(SettingsTab): settings.beginGroup(self.settings_section) self.theme_level = settings.value('theme level') self.global_theme = settings.value('global theme') - wrap_footer = settings.value('wrap footer') + self.wrap_footer_check_box.setChecked(settings.value('wrap footer')) settings.endGroup() if self.theme_level == ThemeLevel.Global: self.global_level_radio_button.setChecked(True) @@ -154,18 +154,16 @@ class ThemesTab(SettingsTab): self.service_level_radio_button.setChecked(True) else: self.song_level_radio_button.setChecked(True) - self.wrap_footer_check_box.setChecked(wrap_footer) def save(self): """ Save the settings """ - wrap_footer = self.wrap_footer_check_box.isChecked() settings = Settings() settings.beginGroup(self.settings_section) settings.setValue('theme level', self.theme_level) settings.setValue('global theme', self.global_theme) - settings.setValue('wrap footer', wrap_footer) + settings.setValue('wrap footer', self.wrap_footer_check_box.isChecked()) settings.endGroup() self.renderer.set_theme_level(self.theme_level) if self.tab_visited: diff --git a/tests/functional/openlp_core_lib/test_htmlbuilder.py b/tests/functional/openlp_core_lib/test_htmlbuilder.py index e98dfc687..4563c98b4 100644 --- a/tests/functional/openlp_core_lib/test_htmlbuilder.py +++ b/tests/functional/openlp_core_lib/test_htmlbuilder.py @@ -320,7 +320,7 @@ class Htmbuilder(TestCase, TestMixin): css = build_lyrics_format_css(theme_data, width, height) # THEN: They should be equal. - assert LYRICS_FORMAT_CSS == css, 'The lyrics format css should be equal.' + self.assertEqual(LYRICS_FORMAT_CSS, css, 'The lyrics format css should be equal.') def build_footer_css_test(self): """ @@ -357,4 +357,4 @@ class Htmbuilder(TestCase, TestMixin): css = build_footer_css(item, height) # THEN: Footer should wrap - assert FOOTER_CSS_WRAP == css, 'The footer strings should be equal.' + self.assertEqual(FOOTER_CSS_WRAP, css, 'The footer strings should be equal.') From 2f984c45c48f7857ec57758dc6b32ee09a19ff51 Mon Sep 17 00:00:00 2001 From: Stewart Becker Date: Thu, 24 Jul 2014 22:57:16 +0100 Subject: [PATCH 6/6] Style fixes for Tim --- tests/functional/openlp_core_lib/test_htmlbuilder.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/functional/openlp_core_lib/test_htmlbuilder.py b/tests/functional/openlp_core_lib/test_htmlbuilder.py index 4563c98b4..7ba63a792 100644 --- a/tests/functional/openlp_core_lib/test_htmlbuilder.py +++ b/tests/functional/openlp_core_lib/test_htmlbuilder.py @@ -243,7 +243,7 @@ class Htmbuilder(TestCase, TestMixin): html = build_html(item, screen, is_live, background, plugins=plugins) # THEN: The returned html should match. - assert html == HTML + self.assertEqual(html, HTML, 'The returned html should match') def build_background_css_radial_test(self): """ @@ -259,7 +259,7 @@ class Htmbuilder(TestCase, TestMixin): css = build_background_css(item, width) # THEN: The returned css should match. - assert BACKGROUND_CSS_RADIAL == css, 'The background css should be equal.' + self.assertEqual(BACKGROUND_CSS_RADIAL, css, 'The background css should be equal.') def build_lyrics_css_test(self): """ @@ -280,7 +280,7 @@ class Htmbuilder(TestCase, TestMixin): css = build_lyrics_css(item) # THEN: The css should be equal. - assert LYRICS_CSS == css, 'The lyrics css should be equal.' + self.assertEqual(LYRICS_CSS, css, 'The lyrics css should be equal.') def build_lyrics_outline_css_test(self): """ @@ -297,7 +297,7 @@ class Htmbuilder(TestCase, TestMixin): css = build_lyrics_outline_css(theme_data) # THEN: The css should be equal. - assert LYRICS_OUTLINE_CSS == css, 'The outline css should be equal.' + self.assertEqual(LYRICS_OUTLINE_CSS, css, 'The outline css should be equal.') def build_lyrics_format_css_test(self): """ @@ -338,7 +338,7 @@ class Htmbuilder(TestCase, TestMixin): css = build_footer_css(item, height) # THEN: THE css should be the same. - assert FOOTER_CSS == css, 'The footer strings should be equal.' + self.assertEqual(FOOTER_CSS, css, 'The footer strings should be equal.') def build_footer_css_wrap_test(self): """