diff --git a/openlp/core/common/uistrings.py b/openlp/core/common/uistrings.py index 3f221ab08..33ebb0a5b 100644 --- a/openlp/core/common/uistrings.py +++ b/openlp/core/common/uistrings.py @@ -122,8 +122,8 @@ class UiStrings(object): self.Projectors = translate('OpenLP.Ui', 'Projectors', 'Plural') self.ReplaceBG = translate('OpenLP.Ui', 'Replace Background') self.ReplaceLiveBG = translate('OpenLP.Ui', 'Replace live background.') - self.ReplaceLiveBGDisabled = translate('OpenLP.Ui', 'Replace live background is not available on this ' - 'platform in this version of OpenLP.') + self.ReplaceLiveBGDisabled = translate('OpenLP.Ui', 'Replace live background is not available when the WebKit ' + 'player is disabled.') self.ResetBG = translate('OpenLP.Ui', 'Reset Background') self.ResetLiveBG = translate('OpenLP.Ui', 'Reset live background.') self.Seconds = translate('OpenLP.Ui', 's', 'The abbreviated unit for seconds') diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 0513b70e4..f76d28853 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -20,6 +20,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### +import re from PyQt5 import QtGui, QtCore, QtWebKitWidgets @@ -441,7 +442,7 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties): previous_raw = line + line_end continue # Figure out how many words of the line will fit on screen as the line will not fit as a whole. - raw_words = Renderer.words_split(line) + raw_words = words_split(line) html_words = list(map(expand_tags, raw_words)) previous_html, previous_raw = \ self._binary_chop(formatted, previous_html, previous_raw, html_words, raw_words, ' ', line_end) @@ -528,8 +529,7 @@ def words_split(line): :param line: Line to be split """ # this parse we are to be wordy - line = line.replace('\n', ' ') - return line.split(' ') + return re.split('\s+', line) def get_start_tags(raw_text): diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index e22b8f2ba..a16c7c6c0 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -86,12 +86,6 @@ class Display(QtWidgets.QGraphicsView): super(Display, self).__init__() self.controller = parent self.screen = {} - # FIXME: On Mac OS X (tested on 10.7) the display screen is corrupt with - # OpenGL. Only white blank screen is shown on the 2nd monitor all the - # time. We need to investigate more how to use OpenGL properly on Mac OS - # X. - if not is_macosx() and not is_win(): - self.setViewport(QtOpenGL.QGLWidget()) def setup(self): """ @@ -559,6 +553,13 @@ class MainDisplay(OpenLPMixin, Display, RegistryProperties): if window_id == main_window_id: self.main_window.raise_() + def shake_web_view(self): + """ + Resizes the web_view a bit to force an update. Workaround for bug #1531319, should not be needed with PyQt 5.6. + """ + self.web_view.setGeometry(0, 0, self.width(), self.height() - 1) + self.web_view.setGeometry(0, 0, self.width(), self.height()) + class AudioPlayer(OpenLPMixin, QtCore.QObject): """ @@ -576,6 +577,7 @@ class AudioPlayer(OpenLPMixin, QtCore.QObject): self.player = QtMultimedia.QMediaPlayer() self.playlist = QtMultimedia.QMediaPlaylist(self.player) self.volume_slider = None + self.player.setPlaylist(self.playlist) self.player.positionChanged.connect(self._on_position_changed) def __del__(self): @@ -643,7 +645,7 @@ class AudioPlayer(OpenLPMixin, QtCore.QObject): if not isinstance(file_names, list): file_names = [file_names] for file_name in file_names: - self.playlist.addMedia(QtCore.QUrl(file_name)) + self.playlist.addMedia(QtMultimedia.QMediaContent(QtCore.QUrl.fromLocalFile(file_name))) def next(self): """ diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 37c4836b9..bed5d07c4 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -31,7 +31,7 @@ from threading import Lock from PyQt5 import QtCore, QtGui, QtWidgets from openlp.core.common import Registry, RegistryProperties, Settings, SlideLimits, UiStrings, translate, \ - RegistryMixin, OpenLPMixin + RegistryMixin, OpenLPMixin, is_win from openlp.core.lib import OpenLPToolbar, ItemCapabilities, ServiceItem, ImageSource, ServiceItemAction, \ ScreenList, build_icon, build_html from openlp.core.ui import HideMode, MainDisplay, Display, DisplayControllerType @@ -1101,6 +1101,9 @@ class SlideController(DisplayController, RegistryProperties): self.display.image(to_display) # reset the store used to display first image self.service_item.bg_image_bytes = None + # Workaround for bug #1531319, should not be needed with PyQt 5.6. + if self.is_live and is_win(): + self.display.shake_web_view() self.selected_row = row self.update_preview() self.preview_widget.change_slide(row) @@ -1421,7 +1424,7 @@ class SlideController(DisplayController, RegistryProperties): :param time: the time remaining """ - seconds = self.display.audio_player.media_object.remainingTime() // 1000 + seconds = (self.display.audio_player.player.duration() - self.display.audio_player.player.position()) // 1000 minutes = seconds // 60 seconds %= 60 self.audio_time_label.setText(' %02d:%02d ' % (minutes, seconds)) diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index 4bc77c65c..b422d6018 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -843,7 +843,9 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): :param text: The text of the verse order edit (ignored). """ # First make sure that all letters entered in the verse order field are uppercase + pos = self.verse_order_edit.cursorPosition() self.verse_order_edit.setText(text.upper()) + self.verse_order_edit.setCursorPosition(pos) # Extract all verses which were used in the order. verses_in_order = self._extract_verse_order(self.verse_order_edit.text()) # Find the verses which were not used in the order. diff --git a/openlp/plugins/songs/lib/importers/opensong.py b/openlp/plugins/songs/lib/importers/opensong.py index b051af914..3c0644ff6 100644 --- a/openlp/plugins/songs/lib/importers/opensong.py +++ b/openlp/plugins/songs/lib/importers/opensong.py @@ -157,6 +157,7 @@ class OpenSongImport(SongImport): if isinstance(fn_or_string, str): if attr in ['ccli']: if ustring: + ustring = ''.join(re.findall('\d+', ustring)) setattr(self, fn_or_string, int(ustring)) else: setattr(self, fn_or_string, None) diff --git a/tests/functional/openlp_core_lib/test_renderer.py b/tests/functional/openlp_core_lib/test_renderer.py index 2c1273480..697c8ae85 100644 --- a/tests/functional/openlp_core_lib/test_renderer.py +++ b/tests/functional/openlp_core_lib/test_renderer.py @@ -27,9 +27,10 @@ from unittest import TestCase from PyQt5 import QtCore from openlp.core.common import Registry -from openlp.core.lib import Renderer, ScreenList, ServiceItem +from openlp.core.lib import Renderer, ScreenList, ServiceItem, FormattingTags +from openlp.core.lib.renderer import words_split, get_start_tags -from tests.functional import MagicMock +from tests.functional import MagicMock, patch SCREEN = { 'primary': False, @@ -71,34 +72,39 @@ class TestRenderer(TestCase): self.assertEqual(renderer.screen_ratio, 0.75, 'The base renderer should be a live controller') self.assertEqual(renderer.footer_start, 691, 'The base renderer should be a live controller') - def _get_start_tags_test(self): + @patch('openlp.core.lib.renderer.FormattingTags.get_html_tags') + def get_start_tags_test(self, mocked_get_html_tags): """ - Test the _get_start_tags() method + Test the get_start_tags() method """ # GIVEN: A new renderer instance. Broken raw_text (missing closing tags). - renderer = Renderer() given_raw_text = '{st}{r}Text text text' expected_tuple = ('{st}{r}Text text text{/r}{/st}', '{st}{r}', '') + mocked_get_html_tags.return_value = [{'temporary': False, 'end tag': '{/r}', 'desc': 'Red', + 'start html': '', + 'end html': '', 'start tag': '{r}', 'protected': True}, + {'temporary': False, 'end tag': '{/st}', 'desc': 'Bold', + 'start html': '', 'end html': '', 'start tag': '{st}', + 'protected': True}] # WHEN: The renderer converts the start tags - result = renderer._get_start_tags(given_raw_text) + result = get_start_tags(given_raw_text) # THEN: Check if the correct tuple is returned. self.assertEqual(result, expected_tuple), 'A tuple should be returned containing the text with correct ' \ 'tags, the opening tags, and the opening html tags.' - def _word_split_test(self): + def word_split_test(self): """ - Test the _word_split() method + Test the word_split() method """ # GIVEN: A line of text - renderer = Renderer() given_line = 'beginning asdf \n end asdf' expected_words = ['beginning', 'asdf', 'end', 'asdf'] # WHEN: Split the line based on word split rules - result_words = renderer._words_split(given_line) + result_words = words_split(given_line) # THEN: The word lists should be the same. self.assertListEqual(result_words, expected_words) diff --git a/tests/functional/openlp_plugins/songs/test_opensongimport.py b/tests/functional/openlp_plugins/songs/test_opensongimport.py index 43eb89f01..b6514532c 100644 --- a/tests/functional/openlp_plugins/songs/test_opensongimport.py +++ b/tests/functional/openlp_plugins/songs/test_opensongimport.py @@ -52,6 +52,8 @@ class TestOpenSongFileImport(SongImportTestHelper): self.load_external_result_data(os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.json'))) self.file_import([os.path.join(TEST_PATH, 'One, Two, Three, Four, Five')], self.load_external_result_data(os.path.join(TEST_PATH, 'One, Two, Three, Four, Five.json'))) + self.file_import([os.path.join(TEST_PATH, 'Amazing Grace2')], + self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json'))) class TestOpenSongImport(TestCase): diff --git a/tests/resources/opensongsongs/Amazing Grace2 b/tests/resources/opensongsongs/Amazing Grace2 new file mode 100644 index 000000000..c14ba8fa9 --- /dev/null +++ b/tests/resources/opensongsongs/Amazing Grace2 @@ -0,0 +1,56 @@ + + + Amazing Grace (Demonstration) + John Newton, Edwin Excell & John P. Rees + Public Domain + V1 V2 V3 V4 V5 + + + CC: 22025 number + God: Assurance/Grace/Salvation + Worship: Praise + + + + [V] +;Test the chords format +;Chords beging with . +;Verses begin with their verse number +;Link words with _ +;Comments begin with ; +. D D7 G D +1A______ma________zing grace! How sweet the sound! +2'Twas grace that taught my heart to fear, +3The Lord has pro____mised good to me, +4Thro' ma________ny dan____gers, toils and snares +5When we've been there ten thou__sand years, + +. Bm E A A7 +1That saved a wretch like me! +2And grace my fears re___lieved. +3His Word my hope se___cures. +4I have al___rea____dy come. +5Bright shi___ning as the sun, + +. D D7 G D +1I once was lost, but now am found; +2How pre___cious did that grace ap____pear, +3He will my shield and por___tion be +4'Tis grace that brought me safe thus far, +5We've no less days to sing God's praise, + +. Bm A G D +1Was blind, but now I see. +2The hour I first be_lieved. +3As long as life en_dures. +4And grace will lead me home. +5Than when we first be_gun. + + + Demonstration Songs 0 + + + + + + \ No newline at end of file