From 7558fb6e64d3e6488c036513057f3681a0aea53f Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 28 May 2019 22:37:50 +0200 Subject: [PATCH 1/8] Use a live webengine widget when previwing themes. --- openlp/core/display/render.py | 55 +++++++++++++++++++++------------- openlp/core/ui/themeform.py | 33 ++++++++++---------- openlp/core/ui/thememanager.py | 24 +++++++-------- openlp/core/ui/themewizard.py | 20 ++++++------- 4 files changed, 72 insertions(+), 60 deletions(-) diff --git a/openlp/core/display/render.py b/openlp/core/display/render.py index 05b7b97fc..f90bcebca 100644 --- a/openlp/core/display/render.py +++ b/openlp/core/display/render.py @@ -425,7 +425,7 @@ def get_start_tags(raw_text): return raw_text + ''.join(end_tags), ''.join(start_tags), ''.join(html_tags) -class Renderer(RegistryBase, LogMixin, RegistryProperties, DisplayWindow): +class ThemePreviewRenderer(LogMixin, DisplayWindow): """ A virtual display used for rendering thumbnails and other offscreen tasks """ @@ -435,24 +435,6 @@ class Renderer(RegistryBase, LogMixin, RegistryProperties, DisplayWindow): """ super().__init__(*args, **kwargs) self.force_page = False - for screen in ScreenList(): - if screen.is_display: - self.setGeometry(screen.display_geometry.x(), screen.display_geometry.y(), - screen.display_geometry.width(), screen.display_geometry.height()) - break - # If the display is not show'ed and hidden like this webegine will not render - self.show() - self.hide() - self.theme_height = 0 - self.theme_level = ThemeLevel.Global - - def set_theme_level(self, theme_level): - """ - Sets the theme level. - - :param theme_level: The theme level to be used. - """ - self.theme_level = theme_level def calculate_line_count(self): """ @@ -466,7 +448,7 @@ class Renderer(RegistryBase, LogMixin, RegistryProperties, DisplayWindow): """ return self.run_javascript('Display.clearSlides();') - def generate_preview(self, theme_data, force_page=False): + def generate_preview(self, theme_data, force_page=False, generate_screenshot=True): """ Generate a preview of a theme. @@ -486,7 +468,8 @@ class Renderer(RegistryBase, LogMixin, RegistryProperties, DisplayWindow): verses['verse'] = 'V1' self.load_verses([verses]) self.force_page = False - return self.save_screenshot() + if generate_screenshot: + return self.save_screenshot() self.force_page = False return None @@ -745,3 +728,33 @@ class Renderer(RegistryBase, LogMixin, RegistryProperties, DisplayWindow): pixmap.save(fname, ext) else: return pixmap + + +class Renderer(RegistryBase, RegistryProperties, ThemePreviewRenderer): + """ + A virtual display used for rendering thumbnails and other offscreen tasks + """ + def __init__(self, *args, **kwargs): + """ + Constructor + """ + super().__init__(*args, **kwargs) + self.force_page = False + for screen in ScreenList(): + if screen.is_display: + self.setGeometry(screen.display_geometry.x(), screen.display_geometry.y(), + screen.display_geometry.width(), screen.display_geometry.height()) + break + # If the display is not show'ed and hidden like this webegine will not render + self.show() + self.hide() + self.theme_height = 0 + self.theme_level = ThemeLevel.Global + + def set_theme_level(self, theme_level): + """ + Sets the theme level. + + :param theme_level: The theme level to be used. + """ + self.theme_level = theme_level diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index 0dfb53aab..1e6dd54b1 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -174,16 +174,12 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties): if not event: event = QtGui.QResizeEvent(self.size(), self.size()) QtWidgets.QWizard.resizeEvent(self, event) - if hasattr(self, 'preview_page') and self.currentPage() == self.preview_page: - frame_width = self.preview_box_label.lineWidth() - pixmap_width = self.preview_area.width() - 2 * frame_width - pixmap_height = self.preview_area.height() - 2 * frame_width - aspect_ratio = float(pixmap_width) / pixmap_height - if aspect_ratio < self.display_aspect_ratio: - pixmap_height = int(pixmap_width / self.display_aspect_ratio + 0.5) - else: - pixmap_width = int(pixmap_height * self.display_aspect_ratio + 0.5) - self.preview_box_label.setFixedSize(pixmap_width + 2 * frame_width, pixmap_height + 2 * frame_width) + try: + self.display_aspect_ratio = self.renderer.width() / self.renderer.height() + except ZeroDivisionError: + self.display_aspect_ratio = 1 + self.preview_area_layout.set_aspect_ratio(self.display_aspect_ratio) + self.preview_box.set_scale(float(self.preview_box.width()) / self.renderer.width()) def validateCurrentPage(self): """ @@ -208,10 +204,16 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties): self.setOption(QtWidgets.QWizard.HaveCustomButton1, enabled) if self.page(page_id) == self.preview_page: self.update_theme() - frame = self.theme_manager.generate_image(self.theme) - frame.setDevicePixelRatio(self.devicePixelRatio()) - self.preview_box_label.setPixmap(frame) - self.display_aspect_ratio = float(frame.width()) / frame.height() + self.preview_box.set_theme(self.theme) + self.preview_box.clear_slides() + self.preview_box.set_scale(float(self.preview_box.width()) / self.renderer.width()) + try: + self.display_aspect_ratio = self.renderer.width() / self.renderer.height() + except ZeroDivisionError: + self.display_aspect_ratio = 1 + self.preview_area_layout.set_aspect_ratio(self.display_aspect_ratio) + self.preview_box.generate_preview(self.theme, False, False) + self.preview_box.show() self.resizeEvent() def on_custom_1_button_clicked(self, number): @@ -400,6 +402,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties): Handle the display and state of the Preview page. """ self.setField('name', self.theme.theme_name) + self.preview_box.set_theme(self.theme) def on_background_combo_box_current_index_changed(self, index): """ @@ -560,5 +563,5 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties): source_path = self.theme.background_filename if not self.edit_mode and not self.theme_manager.check_if_theme_exists(self.theme.theme_name): return - self.theme_manager.save_theme(self.theme, source_path, destination_path) + self.theme_manager.save_theme(self.theme, source_path, destination_path, self.preview_box.save_screenshot()) return QtWidgets.QDialog.accept(self) diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index fd003ed2e..3c8aee1e6 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -639,24 +639,14 @@ class ThemeManager(QtWidgets.QWidget, RegistryBase, Ui_ThemeManager, LogMixin, R return False return True - def save_theme(self, theme, image_source_path, image_destination_path): - """ - Called by theme maintenance Dialog to save the theme and to trigger the reload of the theme list - - :param Theme theme: The theme data object. - :param Path image_source_path: Where the theme image is currently located. - :param Path image_destination_path: Where the Theme Image is to be saved to - :rtype: None - """ - self._write_theme(theme, image_source_path, image_destination_path) - - def _write_theme(self, theme, image_source_path=None, image_destination_path=None): + def save_theme(self, theme, image_source_path, image_destination_path, image=None): """ Writes the theme to the disk and handles the background image if necessary :param Theme theme: The theme data object. :param Path image_source_path: Where the theme image is currently located. :param Path image_destination_path: Where the Theme Image is to be saved to + :param image: The example image of the theme. Optionally. :rtype: None """ name = theme.theme_name @@ -676,7 +666,15 @@ class ThemeManager(QtWidgets.QWidget, RegistryBase, Ui_ThemeManager, LogMixin, R shutil.copyfile(image_source_path, image_destination_path) except OSError: self.log_exception('Failed to save theme image') - self.generate_and_save_image(name, theme) + if image: + sample_path_name = self.theme_path / '{file_name}.png'.format(file_name=name) + if sample_path_name.exists(): + sample_path_name.unlink() + image.save(str(sample_path_name), 'png') + thumb_path = self.thumb_path / '{name}.png'.format(name=name) + create_thumb(sample_path_name, thumb_path, False) + else: + self.generate_and_save_image(name, theme) def generate_and_save_image(self, theme_name, theme): """ diff --git a/openlp/core/ui/themewizard.py b/openlp/core/ui/themewizard.py index e6a7ac2c5..1414e3f46 100644 --- a/openlp/core/ui/themewizard.py +++ b/openlp/core/ui/themewizard.py @@ -31,7 +31,8 @@ from openlp.core.lib.ui import add_welcome_page, create_valign_selection_widgets from openlp.core.ui.icons import UiIcons from openlp.core.widgets.buttons import ColorButton from openlp.core.widgets.edits import PathEdit - +from openlp.core.widgets.layouts import AspectRatioLayout +from openlp.core.display.render import ThemePreviewRenderer class Ui_ThemeWizard(object): """ @@ -363,16 +364,13 @@ class Ui_ThemeWizard(object): self.preview_layout.addLayout(self.theme_name_layout) self.preview_area = QtWidgets.QWidget(self.preview_page) self.preview_area.setObjectName('PreviewArea') - self.preview_area_layout = QtWidgets.QGridLayout(self.preview_area) - self.preview_area_layout.setContentsMargins(0, 0, 0, 0) - self.preview_area_layout.setColumnStretch(0, 1) - self.preview_area_layout.setRowStretch(0, 1) - self.preview_area_layout.setObjectName('preview_area_layout') - self.preview_box_label = QtWidgets.QLabel(self.preview_area) - self.preview_box_label.setFrameShape(QtWidgets.QFrame.Box) - self.preview_box_label.setScaledContents(True) - self.preview_box_label.setObjectName('preview_box_label') - self.preview_area_layout.addWidget(self.preview_box_label) + self.preview_area_layout = AspectRatioLayout(self.preview_area, 0.75) # Dummy ratio, will be update + self.preview_area_layout.margin = 8 + self.preview_area_layout.setSpacing(0) + self.preview_area_layout.setObjectName('preview_web_layout') + self.preview_box = ThemePreviewRenderer(self) + self.preview_box.setObjectName('preview_box') + self.preview_area_layout.addWidget(self.preview_box) self.preview_layout.addWidget(self.preview_area) theme_wizard.addPage(self.preview_page) self.retranslate_ui(theme_wizard) From 8b489de9541631fe08204311a72b9cccc7135b05 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 3 Jun 2019 22:11:19 +0200 Subject: [PATCH 2/8] Generate a real footer --- openlp/core/display/render.py | 35 +++++++++++++++++++++++++--- openlp/plugins/songs/lib/songstab.py | 2 +- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/openlp/core/display/render.py b/openlp/core/display/render.py index f90bcebca..b437d7aee 100644 --- a/openlp/core/display/render.py +++ b/openlp/core/display/render.py @@ -24,6 +24,7 @@ The :mod:`~openlp.display.render` module contains functions for rendering. """ import html import logging +import mako import math import os import re @@ -32,8 +33,10 @@ import time from PyQt5 import QtWidgets, QtGui from openlp.core.common import ThemeLevel +from openlp.core.common.i18n import UiStrings, translate from openlp.core.common.mixins import LogMixin, RegistryProperties from openlp.core.common.registry import Registry, RegistryBase +from openlp.core.common.settings import Settings from openlp.core.display.screens import ScreenList from openlp.core.display.window import DisplayWindow from openlp.core.lib import ItemCapabilities @@ -58,8 +61,11 @@ VERSE = 'The Lord said to {r}Noah{/r}: \n' \ '{r}C{/r}{b}h{/b}{bl}i{/bl}{y}l{/y}{g}d{/g}{pk}' \ 'r{/pk}{o}e{/o}{pp}n{/pp} of the Lord\n' VERSE_FOR_LINE_COUNT = '\n'.join(map(str, range(100))) -TITLE = 'Arky Arky (Unknown)' -FOOTER = ['Public Domain', 'CCLI 123456'] +TITLE = 'Arky Arky' +AUTHOR = 'John Doe' +FOOTER_COPYRIGHT = 'Public Domain' +CCLI_NO = '123456' + def remove_tags(text, can_remove_chords=False): @@ -448,6 +454,28 @@ class ThemePreviewRenderer(LogMixin, DisplayWindow): """ return self.run_javascript('Display.clearSlides();') + def generate_footer(self): + """ + """ + footer_template = Settings().value('songs/footer template') + # Keep this in sync with the list in songstab.py + vars = { + 'title': TITLE, + 'authors_none_label': translate('OpenLP.Ui', 'Written by'), + 'authors_words_label': translate('SongsPlugin.AuthorType', 'Words', 'Author who wrote the lyrics of a song'), + 'authors_words': AUTHOR, + 'copyright': FOOTER_COPYRIGHT, + 'ccli_license': Settings().value('core/ccli number'), + 'ccli_license_label': translate('SongsPlugin.MediaItem', 'CCLI License'), + 'ccli_number': CCLI_NO, + } + try: + footer_html = mako.template.Template(footer_template).render_unicode(**vars).replace('\n', '') + except mako.exceptions.SyntaxException: + log.error('Failed to render Song footer html:\n' + mako.exceptions.text_error_template().render()) + footer_html = 'Dummy footer text' + return footer_html + def generate_preview(self, theme_data, force_page=False, generate_screenshot=True): """ Generate a preview of a theme. @@ -466,6 +494,7 @@ class ThemePreviewRenderer(LogMixin, DisplayWindow): verses['title'] = TITLE verses['text'] = slides[0] verses['verse'] = 'V1' + verses['footer'] = self.generate_footer() self.load_verses([verses]) self.force_page = False if generate_screenshot: @@ -498,7 +527,7 @@ class ThemePreviewRenderer(LogMixin, DisplayWindow): if item and item.is_capable(ItemCapabilities.CanWordSplit): pages = self._paginate_slide_words(text.split('\n'), line_end) # Songs and Custom - elif item is None or item.is_capable(ItemCapabilities.CanSoftBreak): + elif item is None or (item and item.is_capable(ItemCapabilities.CanSoftBreak)): pages = [] if '[---]' in text: # Remove Overflow split if at start of the text diff --git a/openlp/plugins/songs/lib/songstab.py b/openlp/plugins/songs/lib/songstab.py index 34b83a8e5..0abd6edda 100644 --- a/openlp/plugins/songs/lib/songstab.py +++ b/openlp/plugins/songs/lib/songstab.py @@ -88,7 +88,7 @@ class SongsTab(SettingsTab): self.footer_group_box = QtWidgets.QGroupBox(self.left_column) self.footer_group_box.setObjectName('footer_group_box') self.footer_layout = QtWidgets.QVBoxLayout(self.footer_group_box) - self.footer_layout.setObjectName('chords_layout') + self.footer_layout.setObjectName('footer_layout') self.footer_info_label = QtWidgets.QLabel(self.footer_group_box) self.footer_layout.addWidget(self.footer_info_label) self.footer_placeholder_info = QtWidgets.QTextEdit(self.footer_group_box) From f27fded597e35333ce42eafc9c653b1144d93b40 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Thu, 6 Jun 2019 22:10:39 +0200 Subject: [PATCH 3/8] Fix line calculation for the theme preview. Try to make VLC loading more robust. --- openlp/core/display/render.py | 8 ++++---- openlp/core/ui/media/vlcplayer.py | 27 ++++++++++++++------------- openlp/core/ui/themeform.py | 10 ++++++---- openlp/core/ui/thememanager.py | 2 +- openlp/plugins/media/lib/mediaitem.py | 21 +++++++++++---------- 5 files changed, 36 insertions(+), 32 deletions(-) diff --git a/openlp/core/display/render.py b/openlp/core/display/render.py index b437d7aee..cc252494f 100644 --- a/openlp/core/display/render.py +++ b/openlp/core/display/render.py @@ -463,7 +463,7 @@ class ThemePreviewRenderer(LogMixin, DisplayWindow): 'title': TITLE, 'authors_none_label': translate('OpenLP.Ui', 'Written by'), 'authors_words_label': translate('SongsPlugin.AuthorType', 'Words', 'Author who wrote the lyrics of a song'), - 'authors_words': AUTHOR, + 'authors_words': [AUTHOR], 'copyright': FOOTER_COPYRIGHT, 'ccli_license': Settings().value('core/ccli number'), 'ccli_license_label': translate('SongsPlugin.MediaItem', 'CCLI License'), @@ -489,10 +489,10 @@ class ThemePreviewRenderer(LogMixin, DisplayWindow): if not self.force_page: self.set_theme(theme_data) self.theme_height = theme_data.font_main_height - slides = self.format_slide(render_tags(VERSE), None) + slides = self.format_slide(VERSE, None) verses = dict() verses['title'] = TITLE - verses['text'] = slides[0] + verses['text'] = render_tags(slides[0]) verses['verse'] = 'V1' verses['footer'] = self.generate_footer() self.load_verses([verses]) @@ -734,7 +734,7 @@ class ThemePreviewRenderer(LogMixin, DisplayWindow): :param text: The text to check. It may contain HTML tags. """ self.clear_slides() - self.run_javascript('Display.addTextSlide("v1", "{text}", "Dummy Footer");'.format(text=text), is_sync=True) + self.run_javascript('Display.addTextSlide("v1", "{text}", "Dummy Footer");'.format(text=text.replace('"', '\\"')), is_sync=True) does_text_fits = self.run_javascript('Display.doesContentFit();', is_sync=True) return does_text_fits diff --git a/openlp/core/ui/media/vlcplayer.py b/openlp/core/ui/media/vlcplayer.py index 6ba27998b..96cc5b3ab 100644 --- a/openlp/core/ui/media/vlcplayer.py +++ b/openlp/core/ui/media/vlcplayer.py @@ -28,7 +28,6 @@ import os import sys import threading from datetime import datetime -import vlc from PyQt5 import QtWidgets @@ -65,25 +64,27 @@ def get_vlc(): :return: The "vlc" module, or None """ - if 'vlc' in sys.modules: - # If VLC has already been imported, no need to do all the stuff below again - is_vlc_available = False + # Import the VLC module if not already done + if 'vlc' not in sys.modules: try: - is_vlc_available = bool(sys.modules['vlc'].get_default_instance()) - except Exception: - pass - if is_vlc_available: - return sys.modules['vlc'] - else: + import vlc + except ImportError: return None - else: - return vlc + # Verify that VLC is also loadable + is_vlc_available = False + try: + is_vlc_available = bool(sys.modules['vlc'].get_default_instance()) + except Exception: + pass + if is_vlc_available: + return sys.modules['vlc'] + return None # On linux we need to initialise X threads, but not when running tests. # This needs to happen on module load and not in get_vlc(), otherwise it can cause crashes on some DE on some setups # (reported on Gnome3, Unity, Cinnamon, all GTK+ based) when using native filedialogs... -if is_linux() and 'nose' not in sys.argv[0] and get_vlc(): +if is_linux() and 'pytest' not in sys.argv[0] and get_vlc(): try: try: x11 = ctypes.cdll.LoadLibrary('libX11.so.6') diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index 1e6dd54b1..00f2548c7 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -178,8 +178,10 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties): self.display_aspect_ratio = self.renderer.width() / self.renderer.height() except ZeroDivisionError: self.display_aspect_ratio = 1 - self.preview_area_layout.set_aspect_ratio(self.display_aspect_ratio) - self.preview_box.set_scale(float(self.preview_box.width()) / self.renderer.width()) + # Make sure we don't resize before the widgets are actually created + if hasattr(self, 'preview_area_layout'): + self.preview_area_layout.set_aspect_ratio(self.display_aspect_ratio) + self.preview_box.set_scale(float(self.preview_box.width()) / self.renderer.width()) def validateCurrentPage(self): """ @@ -212,9 +214,9 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties): except ZeroDivisionError: self.display_aspect_ratio = 1 self.preview_area_layout.set_aspect_ratio(self.display_aspect_ratio) - self.preview_box.generate_preview(self.theme, False, False) - self.preview_box.show() self.resizeEvent() + self.preview_box.show() + self.preview_box.generate_preview(self.theme, False, False) def on_custom_1_button_clicked(self, number): """ diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index 3c8aee1e6..986a38135 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -476,7 +476,7 @@ class ThemeManager(QtWidgets.QWidget, RegistryBase, Ui_ThemeManager, LogMixin, R if not theme_paths: theme = Theme() theme.theme_name = UiStrings().Default - self._write_theme(theme) + self.save_theme(theme) Settings().setValue(self.settings_section + '/global theme', theme.theme_name) self.application.set_normal_cursor() diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 658773b99..5b33b3836 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -259,35 +259,36 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): # TODO needs to be fixed as no idea why this fails # media.sort(key=lambda file_path: get_natural_key(file_path.name)) for track in media: - track_info = QtCore.QFileInfo(track) + track_str = str(track) + track_info = QtCore.QFileInfo(track_str) item_name = None - if track.startswith('optical:'): + if track_str.startswith('optical:'): # Handle optical based item - (file_name, title, audio_track, subtitle_track, start, end, clip_name) = parse_optical_path(track) + (file_name, title, audio_track, subtitle_track, start, end, clip_name) = parse_optical_path(track_str) item_name = QtWidgets.QListWidgetItem(clip_name) item_name.setIcon(UiIcons().optical) - item_name.setData(QtCore.Qt.UserRole, track) + item_name.setData(QtCore.Qt.UserRole, track_str) item_name.setToolTip('{name}@{start}-{end}'.format(name=file_name, start=format_milliseconds(start), end=format_milliseconds(end))) elif not os.path.exists(track): # File doesn't exist, mark as error. - file_name = os.path.split(str(track))[1] + file_name = os.path.split(track_str)[1] item_name = QtWidgets.QListWidgetItem(file_name) item_name.setIcon(UiIcons().error) - item_name.setData(QtCore.Qt.UserRole, track) - item_name.setToolTip(track) + item_name.setData(QtCore.Qt.UserRole, track_str) + item_name.setToolTip(track_str) elif track_info.isFile(): # Normal media file handling. - file_name = os.path.split(str(track))[1] + file_name = os.path.split(track_str)[1] item_name = QtWidgets.QListWidgetItem(file_name) search = file_name.split('.')[-1].lower() if '*.{text}'.format(text=search) in self.media_controller.audio_extensions_list: item_name.setIcon(UiIcons().audio) else: item_name.setIcon(UiIcons().video) - item_name.setData(QtCore.Qt.UserRole, track) - item_name.setToolTip(track) + item_name.setData(QtCore.Qt.UserRole, track_str) + item_name.setToolTip(track_str) if item_name: self.list_view.addItem(item_name) From 4074d110ffb7e854234e3758b7ca60f38419ca6a Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 7 Jun 2019 22:46:51 +0200 Subject: [PATCH 4/8] some path/str fixes --- openlp/plugins/media/lib/mediaitem.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 27ad92936..30962967a 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -173,7 +173,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): item = self.list_view.currentItem() if item is None: return False - filename = item.data(QtCore.Qt.UserRole) + filename = str(item.data(QtCore.Qt.UserRole)) # Special handling if the filename is a optical clip if filename.startswith('optical:'): (name, title, audio_track, subtitle_track, start, end, clip_name) = parse_optical_path(filename) @@ -267,7 +267,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): (file_name, title, audio_track, subtitle_track, start, end, clip_name) = parse_optical_path(track_str) item_name = QtWidgets.QListWidgetItem(clip_name) item_name.setIcon(UiIcons().optical) - item_name.setData(QtCore.Qt.UserRole, track_str) + item_name.setData(QtCore.Qt.UserRole, track) item_name.setToolTip('{name}@{start}-{end}'.format(name=file_name, start=format_milliseconds(start), end=format_milliseconds(end))) @@ -276,18 +276,18 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): file_name = os.path.split(track_str)[1] item_name = QtWidgets.QListWidgetItem(file_name) item_name.setIcon(UiIcons().error) - item_name.setData(QtCore.Qt.UserRole, track_str) + item_name.setData(QtCore.Qt.UserRole, track) item_name.setToolTip(track_str) elif track_info.isFile(): # Normal media file handling. file_name = os.path.split(track_str)[1] item_name = QtWidgets.QListWidgetItem(file_name) search = file_name.split('.')[-1].lower() - if '*.{text}'.format(text=search) in self.media_controller.audio_extensions_list: + if search in AUDIO_EXT: item_name.setIcon(UiIcons().audio) else: item_name.setIcon(UiIcons().video) - item_name.setData(QtCore.Qt.UserRole, track_str) + item_name.setData(QtCore.Qt.UserRole, track) item_name.setToolTip(track_str) if item_name: self.list_view.addItem(item_name) From ad9d1df172f60f66721331d067dd8aae822bd94c Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 7 Jun 2019 22:51:19 +0200 Subject: [PATCH 5/8] pep8 --- openlp/core/display/render.py | 7 ++++--- openlp/core/ui/themewizard.py | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/openlp/core/display/render.py b/openlp/core/display/render.py index cc252494f..0002d26e1 100644 --- a/openlp/core/display/render.py +++ b/openlp/core/display/render.py @@ -67,7 +67,6 @@ FOOTER_COPYRIGHT = 'Public Domain' CCLI_NO = '123456' - def remove_tags(text, can_remove_chords=False): """ Remove Tags from text for display @@ -462,7 +461,8 @@ class ThemePreviewRenderer(LogMixin, DisplayWindow): vars = { 'title': TITLE, 'authors_none_label': translate('OpenLP.Ui', 'Written by'), - 'authors_words_label': translate('SongsPlugin.AuthorType', 'Words', 'Author who wrote the lyrics of a song'), + 'authors_words_label': translate('SongsPlugin.AuthorType', 'Words', + 'Author who wrote the lyrics of a song'), 'authors_words': [AUTHOR], 'copyright': FOOTER_COPYRIGHT, 'ccli_license': Settings().value('core/ccli number'), @@ -734,7 +734,8 @@ class ThemePreviewRenderer(LogMixin, DisplayWindow): :param text: The text to check. It may contain HTML tags. """ self.clear_slides() - self.run_javascript('Display.addTextSlide("v1", "{text}", "Dummy Footer");'.format(text=text.replace('"', '\\"')), is_sync=True) + self.run_javascript('Display.addTextSlide("v1", "{text}", "Dummy Footer");' + .format(text=text.replace('"', '\\"')), is_sync=True) does_text_fits = self.run_javascript('Display.doesContentFit();', is_sync=True) return does_text_fits diff --git a/openlp/core/ui/themewizard.py b/openlp/core/ui/themewizard.py index 1414e3f46..a60e0dc7f 100644 --- a/openlp/core/ui/themewizard.py +++ b/openlp/core/ui/themewizard.py @@ -34,6 +34,7 @@ from openlp.core.widgets.edits import PathEdit from openlp.core.widgets.layouts import AspectRatioLayout from openlp.core.display.render import ThemePreviewRenderer + class Ui_ThemeWizard(object): """ The Create/Edit theme wizard From 04d3efef9e182a028d8c6c465270a0ddf10429b5 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 7 Jun 2019 23:05:02 +0200 Subject: [PATCH 6/8] fix some broken tests --- openlp/core/ui/thememanager.py | 2 +- .../openlp_core/ui/test_thememanager.py | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index 986a38135..46d067970 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -639,7 +639,7 @@ class ThemeManager(QtWidgets.QWidget, RegistryBase, Ui_ThemeManager, LogMixin, R return False return True - def save_theme(self, theme, image_source_path, image_destination_path, image=None): + def save_theme(self, theme, image_source_path=None, image_destination_path=None, image=None): """ Writes the theme to the disk and handles the background image if necessary diff --git a/tests/functional/openlp_core/ui/test_thememanager.py b/tests/functional/openlp_core/ui/test_thememanager.py index b4d50331b..3b015f238 100644 --- a/tests/functional/openlp_core/ui/test_thememanager.py +++ b/tests/functional/openlp_core/ui/test_thememanager.py @@ -83,7 +83,7 @@ class TestThemeManager(TestCase): @patch('openlp.core.ui.thememanager.shutil') @patch('openlp.core.ui.thememanager.create_paths') - def test_write_theme_same_image(self, mocked_create_paths, mocked_shutil): + def test_save_theme_same_image(self, mocked_create_paths, mocked_shutil): """ Test that we don't try to overwrite a theme background image with itself """ @@ -98,16 +98,16 @@ class TestThemeManager(TestCase): mocked_theme.extract_formatted_xml = MagicMock() mocked_theme.extract_formatted_xml.return_value = 'fake_theme_xml'.encode() - # WHEN: Calling _write_theme with path to the same image, but the path written slightly different + # WHEN: Calling save_theme with path to the same image, but the path written slightly different file_path_1 = RESOURCE_PATH / 'church.jpg' - theme_manager._write_theme(mocked_theme, file_path_1, file_path_1) + theme_manager.save_theme(mocked_theme, file_path_1, file_path_1) # THEN: The mocked_copyfile should not have been called assert mocked_shutil.copyfile.called is False, 'copyfile should not be called' @patch('openlp.core.ui.thememanager.shutil') @patch('openlp.core.ui.thememanager.create_paths') - def test_write_theme_diff_images(self, mocked_create_paths, mocked_shutil): + def test_save_theme_diff_images(self, mocked_create_paths, mocked_shutil): """ Test that we do overwrite a theme background image when a new is submitted """ @@ -121,15 +121,15 @@ class TestThemeManager(TestCase): mocked_theme.theme_name = 'themename' mocked_theme.filename = "filename" - # WHEN: Calling _write_theme with path to different images + # WHEN: Calling save_theme with path to different images file_path_1 = RESOURCE_PATH / 'church.jpg' file_path_2 = RESOURCE_PATH / 'church2.jpg' - theme_manager._write_theme(mocked_theme, file_path_1, file_path_2) + theme_manager.save_theme(mocked_theme, file_path_1, file_path_2) # THEN: The mocked_copyfile should not have been called assert mocked_shutil.copyfile.called is True, 'copyfile should be called' - def test_write_theme_special_char_name(self): + def test_save_theme_special_char_name(self): """ Test that we can save themes with special characters in the name """ @@ -142,8 +142,8 @@ class TestThemeManager(TestCase): mocked_theme.theme_name = 'theme 愛 name' mocked_theme.export_theme.return_value = "{}" - # WHEN: Calling _write_theme with a theme with a name with special characters in it - theme_manager._write_theme(mocked_theme) + # WHEN: Calling save_theme with a theme with a name with special characters in it + theme_manager.save_theme(mocked_theme) # THEN: It should have been created assert os.path.exists(os.path.join(self.temp_folder, 'theme 愛 name', 'theme 愛 name.json')) is True, \ From 0c7fe8d97c963f978804e0959bf20f1d01f68c19 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sun, 9 Jun 2019 22:06:20 +0200 Subject: [PATCH 7/8] fix test --- tests/openlp_core/ui/test_themeform.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/openlp_core/ui/test_themeform.py b/tests/openlp_core/ui/test_themeform.py index 87a5f3bf6..02a7d0589 100644 --- a/tests/openlp_core/ui/test_themeform.py +++ b/tests/openlp_core/ui/test_themeform.py @@ -23,6 +23,7 @@ Interface tests to test the ThemeWizard class and related methods. """ from unittest import TestCase +from unittest.mock import patch from openlp.core.common.registry import Registry from openlp.core.ui.themeform import ThemeForm @@ -39,7 +40,8 @@ class TestThemeManager(TestCase, TestMixin): """ Registry.create() - def test_create_theme_wizard(self): + @patch('openlp.core.display.window.QtWidgets.QVBoxLayout') + def test_create_theme_wizard(self, mocked_qvboxlayout): """ Test creating a ThemeForm instance """ From 31f6779d3fc67187688c473595e19ca9b8bc140a Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sun, 9 Jun 2019 22:22:43 +0200 Subject: [PATCH 8/8] fix pep8 --- openlp/core/display/render.py | 2 +- openlp/core/ui/media/vlcplayer.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/core/display/render.py b/openlp/core/display/render.py index 0002d26e1..1097b5ac0 100644 --- a/openlp/core/display/render.py +++ b/openlp/core/display/render.py @@ -33,7 +33,7 @@ import time from PyQt5 import QtWidgets, QtGui from openlp.core.common import ThemeLevel -from openlp.core.common.i18n import UiStrings, translate +from openlp.core.common.i18n import translate from openlp.core.common.mixins import LogMixin, RegistryProperties from openlp.core.common.registry import Registry, RegistryBase from openlp.core.common.settings import Settings diff --git a/openlp/core/ui/media/vlcplayer.py b/openlp/core/ui/media/vlcplayer.py index 85f1cb799..244916d24 100644 --- a/openlp/core/ui/media/vlcplayer.py +++ b/openlp/core/ui/media/vlcplayer.py @@ -64,7 +64,7 @@ def get_vlc(): # Import the VLC module if not already done if 'vlc' not in sys.modules: try: - import vlc + import vlc # noqa module is not used directly, but is used via sys.modules['vlc'] except ImportError: return None # Verify that VLC is also loadable