forked from openlp/openlp
Various fixes for beta1
This commit is contained in:
parent
d41e0316f4
commit
3e8d57db6a
@ -54,12 +54,6 @@ after_test:
|
|||||||
# This is where we create a package using PyInstaller
|
# This is where we create a package using PyInstaller
|
||||||
# Install PyInstaller
|
# Install PyInstaller
|
||||||
python -m pip install --no-warn-script-location pyinstaller
|
python -m pip install --no-warn-script-location pyinstaller
|
||||||
# Patch pyinstaller to fix a webengine bundle issue
|
|
||||||
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/pyinstaller/pyinstaller/d08a42c612a91cc320c54f9e812fe967b9c8594a/PyInstaller/hooks/hook-PyQt5.QtWebEngineWidgets.py" -OutFile "hook-PyQt5.QtWebEngineWidgets.py"
|
|
||||||
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/pyinstaller/pyinstaller/91481570517707fc70aa70dca9eb986c61eac35d/PyInstaller/hooks/hook-pkg_resources.py" -OutFile hook-pkg_resources.py
|
|
||||||
$sitePkgFolder = python -c "import sys; site_pkg_folder = next(p for p in sys.path if 'site-packages' in p); print(site_pkg_folder.replace('\\', '/'))"
|
|
||||||
cp hook-PyQt5.QtWebEngineWidgets.py "${sitePkgFolder}/PyInstaller/hooks/hook-PyQt5.QtWebEngineWidgets.py"
|
|
||||||
cp hook-pkg_resources.py "${sitePkgFolder}/PyInstaller/hooks/hook-pkg_resources.py"
|
|
||||||
# Some windows only stuff...
|
# Some windows only stuff...
|
||||||
If ($isWindows) {
|
If ($isWindows) {
|
||||||
# Disabled portable installers - can't figure out how to make them silent
|
# Disabled portable installers - can't figure out how to make them silent
|
||||||
|
@ -280,8 +280,6 @@ class Settings(QtCore.QSettings):
|
|||||||
'planningcenter/secret': '',
|
'planningcenter/secret': '',
|
||||||
'presentations/status': PluginStatus.Inactive,
|
'presentations/status': PluginStatus.Inactive,
|
||||||
'presentations/override app': QtCore.Qt.Unchecked,
|
'presentations/override app': QtCore.Qt.Unchecked,
|
||||||
'presentations/enable_pdf_program': QtCore.Qt.Unchecked,
|
|
||||||
'presentations/pdf_program': None,
|
|
||||||
'presentations/maclo': QtCore.Qt.Checked,
|
'presentations/maclo': QtCore.Qt.Checked,
|
||||||
'presentations/Impress': QtCore.Qt.Checked,
|
'presentations/Impress': QtCore.Qt.Checked,
|
||||||
'presentations/Powerpoint': QtCore.Qt.Checked,
|
'presentations/Powerpoint': QtCore.Qt.Checked,
|
||||||
@ -406,7 +404,8 @@ class Settings(QtCore.QSettings):
|
|||||||
('projector/last directory import', 'projector/last directory import', [(str_to_path, None)]),
|
('projector/last directory import', 'projector/last directory import', [(str_to_path, None)]),
|
||||||
('projector/last directory export', 'projector/last directory export', [(str_to_path, None)]),
|
('projector/last directory export', 'projector/last directory export', [(str_to_path, None)]),
|
||||||
('bibles/last directory import', 'bibles/last directory import', [(str_to_path, None)]),
|
('bibles/last directory import', 'bibles/last directory import', [(str_to_path, None)]),
|
||||||
('presentations/pdf_program', 'presentations/pdf_program', [(str_to_path, None)]),
|
('presentations/enable_pdf_program', '', []),
|
||||||
|
('presentations/pdf_program', '', []),
|
||||||
('songs/last directory import', 'songs/last directory import', [(str_to_path, None)]),
|
('songs/last directory import', 'songs/last directory import', [(str_to_path, None)]),
|
||||||
('songs/last directory export', 'songs/last directory export', [(str_to_path, None)]),
|
('songs/last directory export', 'songs/last directory export', [(str_to_path, None)]),
|
||||||
('songusage/last directory export', 'songusage/last directory export', [(str_to_path, None)]),
|
('songusage/last directory export', 'songusage/last directory export', [(str_to_path, None)]),
|
||||||
|
@ -340,7 +340,6 @@ class MessageListener(object):
|
|||||||
item.footer = item_cpy.footer
|
item.footer = item_cpy.footer
|
||||||
item.from_service = item_cpy.from_service
|
item.from_service = item_cpy.from_service
|
||||||
item.iconic_representation = item_cpy.icon
|
item.iconic_representation = item_cpy.icon
|
||||||
item.image_border = item_cpy.image_border
|
|
||||||
item.main = item_cpy.main
|
item.main = item_cpy.main
|
||||||
item.theme = item_cpy.theme
|
item.theme = item_cpy.theme
|
||||||
# When presenting PDF/XPS/OXPS, we are using the image presentation code,
|
# When presenting PDF/XPS/OXPS, we are using the image presentation code,
|
||||||
|
@ -19,13 +19,8 @@
|
|||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||||
##########################################################################
|
##########################################################################
|
||||||
import logging
|
import logging
|
||||||
import re
|
|
||||||
from shutil import which
|
|
||||||
from subprocess import CalledProcessError, check_output
|
|
||||||
|
|
||||||
from openlp.core.common import check_binary_exists, is_win
|
from openlp.core.common import is_win
|
||||||
from openlp.core.common.registry import Registry
|
|
||||||
from openlp.core.common.applocation import AppLocation
|
|
||||||
from openlp.core.display.screens import ScreenList
|
from openlp.core.display.screens import ScreenList
|
||||||
from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument
|
from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument
|
||||||
|
|
||||||
@ -64,38 +59,6 @@ class PdfController(PresentationController):
|
|||||||
# Determine whether mudraw or ghostscript is used
|
# Determine whether mudraw or ghostscript is used
|
||||||
self.check_installed()
|
self.check_installed()
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def process_check_binary(program_path):
|
|
||||||
"""
|
|
||||||
Function that checks whether a binary is either ghostscript or mudraw or neither.
|
|
||||||
Is also used from presentationtab.py
|
|
||||||
|
|
||||||
:param pathlib.Path program_path: The full path to the binary to check.
|
|
||||||
:return: Type of the binary, 'gs' if ghostscript, 'mudraw' if mudraw, None if invalid.
|
|
||||||
:rtype: str | None
|
|
||||||
"""
|
|
||||||
program_type = None
|
|
||||||
runlog = check_binary_exists(program_path)
|
|
||||||
# Analyse the output to see it the program is mudraw, ghostscript or neither
|
|
||||||
for line in runlog.splitlines():
|
|
||||||
decoded_line = line.decode()
|
|
||||||
found_mudraw = re.search('usage: mudraw.*', decoded_line, re.IGNORECASE)
|
|
||||||
if found_mudraw:
|
|
||||||
program_type = 'mudraw'
|
|
||||||
break
|
|
||||||
found_mutool = re.search('usage: mutool.*', decoded_line, re.IGNORECASE)
|
|
||||||
if found_mutool:
|
|
||||||
# Test that mutool contains mudraw
|
|
||||||
if re.search(r'draw\s+--\s+convert document.*', runlog.decode(), re.IGNORECASE | re.MULTILINE):
|
|
||||||
program_type = 'mutool'
|
|
||||||
break
|
|
||||||
found_gs = re.search('GPL Ghostscript.*', decoded_line, re.IGNORECASE)
|
|
||||||
if found_gs:
|
|
||||||
program_type = 'gs'
|
|
||||||
break
|
|
||||||
log.debug('in check_binary, found: {text}'.format(text=program_type))
|
|
||||||
return program_type
|
|
||||||
|
|
||||||
def check_available(self):
|
def check_available(self):
|
||||||
"""
|
"""
|
||||||
PdfController is able to run on this machine.
|
PdfController is able to run on this machine.
|
||||||
@ -112,53 +75,10 @@ class PdfController(PresentationController):
|
|||||||
:return: True if program to open PDF-files was found, otherwise False.
|
:return: True if program to open PDF-files was found, otherwise False.
|
||||||
"""
|
"""
|
||||||
log.debug('check_installed Pdf')
|
log.debug('check_installed Pdf')
|
||||||
self.mudrawbin = None
|
|
||||||
self.mutoolbin = None
|
|
||||||
self.gsbin = None
|
|
||||||
self.also_supports = []
|
self.also_supports = []
|
||||||
# Use the user defined program if given
|
if PYMUPDF_AVAILABLE:
|
||||||
if Registry().get('settings').value('presentations/enable_pdf_program'):
|
|
||||||
program_path = Registry().get('settings').value('presentations/pdf_program')
|
|
||||||
program_type = self.process_check_binary(program_path)
|
|
||||||
if program_type == 'gs':
|
|
||||||
self.gsbin = program_path
|
|
||||||
elif program_type == 'mudraw':
|
|
||||||
self.mudrawbin = program_path
|
|
||||||
elif program_type == 'mutool':
|
|
||||||
self.mutoolbin = program_path
|
|
||||||
elif PYMUPDF_AVAILABLE:
|
|
||||||
self.also_supports = ['xps', 'oxps', 'epub', 'cbz', 'fb2']
|
self.also_supports = ['xps', 'oxps', 'epub', 'cbz', 'fb2']
|
||||||
return True
|
return True
|
||||||
else:
|
|
||||||
# Fallback to autodetection
|
|
||||||
application_path = AppLocation.get_directory(AppLocation.AppDir)
|
|
||||||
if is_win():
|
|
||||||
# for windows we only accept mudraw.exe or mutool.exe in the base folder
|
|
||||||
if (application_path / 'mudraw.exe').is_file():
|
|
||||||
self.mudrawbin = application_path / 'mudraw.exe'
|
|
||||||
elif (application_path / 'mutool.exe').is_file():
|
|
||||||
self.mutoolbin = application_path / 'mutool.exe'
|
|
||||||
else:
|
|
||||||
# First try to find mudraw
|
|
||||||
self.mudrawbin = which('mudraw')
|
|
||||||
# if mudraw isn't installed, try mutool
|
|
||||||
if not self.mudrawbin:
|
|
||||||
self.mutoolbin = which('mutool')
|
|
||||||
# Check we got a working mutool
|
|
||||||
if not self.mutoolbin or self.process_check_binary(self.mutoolbin) != 'mutool':
|
|
||||||
self.gsbin = which('gs')
|
|
||||||
# Last option: check if mudraw or mutool is placed in OpenLP base folder
|
|
||||||
if not self.mudrawbin and not self.mutoolbin and not self.gsbin:
|
|
||||||
application_path = AppLocation.get_directory(AppLocation.AppDir)
|
|
||||||
if (application_path / 'mudraw').is_file():
|
|
||||||
self.mudrawbin = application_path / 'mudraw'
|
|
||||||
elif (application_path / 'mutool').is_file():
|
|
||||||
self.mutoolbin = application_path / 'mutool'
|
|
||||||
if self.mudrawbin or self.mutoolbin:
|
|
||||||
self.also_supports = ['xps', 'oxps', 'epub', 'cbz', 'fb2']
|
|
||||||
return True
|
|
||||||
elif self.gsbin:
|
|
||||||
return True
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def kill(self):
|
def kill(self):
|
||||||
@ -198,49 +118,6 @@ class PdfDocument(PresentationDocument):
|
|||||||
else:
|
else:
|
||||||
self.startupinfo = None
|
self.startupinfo = None
|
||||||
|
|
||||||
def gs_get_resolution(self, size):
|
|
||||||
"""
|
|
||||||
Only used when using ghostscript
|
|
||||||
Ghostscript can't scale automatically while keeping aspect like mupdf, so we need
|
|
||||||
to get the ratio between the screen size and the PDF to scale
|
|
||||||
|
|
||||||
:param size: Size struct containing the screen size.
|
|
||||||
:return: The resolution dpi to be used.
|
|
||||||
"""
|
|
||||||
# Use a postscript script to get size of the pdf. It is assumed that all pages have same size
|
|
||||||
gs_resolution_script = AppLocation.get_directory(
|
|
||||||
AppLocation.PluginsDir) / 'presentations' / 'lib' / 'ghostscript_get_resolution.ps'
|
|
||||||
# Run the script on the pdf to get the size
|
|
||||||
runlog = []
|
|
||||||
try:
|
|
||||||
runlog = check_output([str(self.controller.gsbin), '-dNOPAUSE', '-dNODISPLAY', '-dBATCH',
|
|
||||||
'-sFile={file_path}'.format(file_path=self.file_path), str(gs_resolution_script)],
|
|
||||||
startupinfo=self.startupinfo)
|
|
||||||
except CalledProcessError as e:
|
|
||||||
log.debug(' '.join(e.cmd))
|
|
||||||
log.debug(e.output)
|
|
||||||
# Extract the pdf resolution from output, the format is " Size: x: <width>, y: <height>"
|
|
||||||
width = 0.0
|
|
||||||
height = 0.0
|
|
||||||
for line in runlog.splitlines():
|
|
||||||
try:
|
|
||||||
width = float(re.search(r'.*Size: x: (\d+\.?\d*), y: \d+.*', line.decode()).group(1))
|
|
||||||
height = float(re.search(r'.*Size: x: \d+\.?\d*, y: (\d+\.?\d*).*', line.decode()).group(1))
|
|
||||||
break
|
|
||||||
except AttributeError:
|
|
||||||
continue
|
|
||||||
# Calculate the ratio from pdf to screen
|
|
||||||
if width > 0 and height > 0:
|
|
||||||
width_ratio = size.width() / width
|
|
||||||
height_ratio = size.height() / height
|
|
||||||
# return the resolution that should be used. 72 is default.
|
|
||||||
if width_ratio > height_ratio:
|
|
||||||
return int(height_ratio * 72)
|
|
||||||
else:
|
|
||||||
return int(width_ratio * 72)
|
|
||||||
else:
|
|
||||||
return 72
|
|
||||||
|
|
||||||
def load_presentation(self):
|
def load_presentation(self):
|
||||||
"""
|
"""
|
||||||
Called when a presentation is added to the SlideController. It generates images from the PDF.
|
Called when a presentation is added to the SlideController. It generates images from the PDF.
|
||||||
@ -260,30 +137,9 @@ class PdfDocument(PresentationDocument):
|
|||||||
size = ScreenList().current.display_geometry
|
size = ScreenList().current.display_geometry
|
||||||
# Generate images from PDF that will fit the frame.
|
# Generate images from PDF that will fit the frame.
|
||||||
runlog = ''
|
runlog = ''
|
||||||
try:
|
|
||||||
if not temp_dir_path.is_dir():
|
if not temp_dir_path.is_dir():
|
||||||
temp_dir_path.mkdir(parents=True)
|
temp_dir_path.mkdir(parents=True)
|
||||||
# The %03d in the file name is handled by each binary
|
try:
|
||||||
if self.controller.mudrawbin:
|
|
||||||
log.debug('loading presentation using mudraw')
|
|
||||||
runlog = check_output([str(self.controller.mudrawbin), '-w', str(size.width()),
|
|
||||||
'-h', str(size.height()),
|
|
||||||
'-o', str(temp_dir_path / 'mainslide%03d.png'), str(self.file_path)],
|
|
||||||
startupinfo=self.startupinfo)
|
|
||||||
elif self.controller.mutoolbin:
|
|
||||||
log.debug('loading presentation using mutool')
|
|
||||||
runlog = check_output([str(self.controller.mutoolbin), 'draw', '-w', str(size.width()),
|
|
||||||
'-h', str(size.height()), '-o', str(temp_dir_path / 'mainslide%03d.png'),
|
|
||||||
str(self.file_path)],
|
|
||||||
startupinfo=self.startupinfo)
|
|
||||||
elif self.controller.gsbin:
|
|
||||||
log.debug('loading presentation using gs')
|
|
||||||
resolution = self.gs_get_resolution(size)
|
|
||||||
runlog = check_output([str(self.controller.gsbin), '-dSAFER', '-dNOPAUSE', '-dBATCH', '-sDEVICE=png16m',
|
|
||||||
'-r{res}'.format(res=resolution), '-dTextAlphaBits=4', '-dGraphicsAlphaBits=4',
|
|
||||||
'-sOutputFile={output}'.format(output=temp_dir_path / 'mainslide%03d.png'),
|
|
||||||
str(self.file_path)], startupinfo=self.startupinfo)
|
|
||||||
elif PYMUPDF_AVAILABLE:
|
|
||||||
log.debug('loading presentation using PyMuPDF')
|
log.debug('loading presentation using PyMuPDF')
|
||||||
pdf = fitz.open(str(self.file_path))
|
pdf = fitz.open(str(self.file_path))
|
||||||
for i, page in enumerate(pdf, start=1):
|
for i, page in enumerate(pdf, start=1):
|
||||||
|
@ -23,9 +23,6 @@ from PyQt5 import QtWidgets
|
|||||||
|
|
||||||
from openlp.core.common.i18n import UiStrings, translate
|
from openlp.core.common.i18n import UiStrings, translate
|
||||||
from openlp.core.lib.settingstab import SettingsTab
|
from openlp.core.lib.settingstab import SettingsTab
|
||||||
from openlp.core.lib.ui import critical_error_message_box
|
|
||||||
from openlp.core.widgets.edits import PathEdit
|
|
||||||
from openlp.plugins.presentations.lib.pdfcontroller import PdfController
|
|
||||||
|
|
||||||
|
|
||||||
class PresentationTab(SettingsTab):
|
class PresentationTab(SettingsTab):
|
||||||
@ -79,23 +76,10 @@ class PresentationTab(SettingsTab):
|
|||||||
self.ppt_window_check_box.setObjectName('ppt_window_check_box')
|
self.ppt_window_check_box.setObjectName('ppt_window_check_box')
|
||||||
self.powerpoint_layout.addWidget(self.ppt_window_check_box)
|
self.powerpoint_layout.addWidget(self.ppt_window_check_box)
|
||||||
self.left_layout.addWidget(self.powerpoint_group_box)
|
self.left_layout.addWidget(self.powerpoint_group_box)
|
||||||
# Pdf options
|
# setup layout
|
||||||
self.pdf_group_box = QtWidgets.QGroupBox(self.left_column)
|
|
||||||
self.pdf_group_box.setObjectName('pdf_group_box')
|
|
||||||
self.pdf_layout = QtWidgets.QFormLayout(self.pdf_group_box)
|
|
||||||
self.pdf_layout.setObjectName('pdf_layout')
|
|
||||||
self.pdf_program_check_box = QtWidgets.QCheckBox(self.pdf_group_box)
|
|
||||||
self.pdf_program_check_box.setObjectName('pdf_program_check_box')
|
|
||||||
self.pdf_layout.addRow(self.pdf_program_check_box)
|
|
||||||
self.program_path_edit = PathEdit(self.pdf_group_box)
|
|
||||||
self.pdf_layout.addRow(self.program_path_edit)
|
|
||||||
self.left_layout.addWidget(self.pdf_group_box)
|
|
||||||
self.left_layout.addStretch()
|
self.left_layout.addStretch()
|
||||||
self.right_column.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
|
self.right_column.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
|
||||||
self.right_layout.addStretch()
|
self.right_layout.addStretch()
|
||||||
# Signals and slots
|
|
||||||
self.program_path_edit.pathChanged.connect(self.on_program_path_edit_path_changed)
|
|
||||||
self.pdf_program_check_box.clicked.connect(self.program_path_edit.setEnabled)
|
|
||||||
|
|
||||||
def retranslate_ui(self):
|
def retranslate_ui(self):
|
||||||
"""
|
"""
|
||||||
@ -107,7 +91,6 @@ class PresentationTab(SettingsTab):
|
|||||||
checkbox = self.presenter_check_boxes[controller.name]
|
checkbox = self.presenter_check_boxes[controller.name]
|
||||||
self.set_controller_text(checkbox, controller)
|
self.set_controller_text(checkbox, controller)
|
||||||
self.advanced_group_box.setTitle(UiStrings().Advanced)
|
self.advanced_group_box.setTitle(UiStrings().Advanced)
|
||||||
self.pdf_group_box.setTitle(translate('PresentationPlugin.PresentationTab', 'PDF options'))
|
|
||||||
self.powerpoint_group_box.setTitle(translate('PresentationPlugin.PresentationTab', 'PowerPoint options'))
|
self.powerpoint_group_box.setTitle(translate('PresentationPlugin.PresentationTab', 'PowerPoint options'))
|
||||||
self.override_app_check_box.setText(
|
self.override_app_check_box.setText(
|
||||||
translate('PresentationPlugin.PresentationTab', 'Allow presentation application to be overridden'))
|
translate('PresentationPlugin.PresentationTab', 'Allow presentation application to be overridden'))
|
||||||
@ -118,10 +101,6 @@ class PresentationTab(SettingsTab):
|
|||||||
translate('PresentationPlugin.PresentationTab',
|
translate('PresentationPlugin.PresentationTab',
|
||||||
'Let PowerPoint control the size and monitor of the presentations\n'
|
'Let PowerPoint control the size and monitor of the presentations\n'
|
||||||
'(This may fix PowerPoint scaling issues in Windows 8 and 10)'))
|
'(This may fix PowerPoint scaling issues in Windows 8 and 10)'))
|
||||||
self.pdf_program_check_box.setText(
|
|
||||||
translate('PresentationPlugin.PresentationTab', 'Use given full path for mudraw or ghostscript binary:'))
|
|
||||||
self.program_path_edit.dialog_caption = translate('PresentationPlugin.PresentationTab',
|
|
||||||
'Select mudraw or ghostscript binary')
|
|
||||||
|
|
||||||
def set_controller_text(self, checkbox, controller):
|
def set_controller_text(self, checkbox, controller):
|
||||||
if checkbox.isEnabled():
|
if checkbox.isEnabled():
|
||||||
@ -147,11 +126,6 @@ class PresentationTab(SettingsTab):
|
|||||||
self.ppt_slide_click_check_box.setEnabled(powerpoint_available)
|
self.ppt_slide_click_check_box.setEnabled(powerpoint_available)
|
||||||
self.ppt_window_check_box.setChecked(self.settings.value('presentations/powerpoint control window'))
|
self.ppt_window_check_box.setChecked(self.settings.value('presentations/powerpoint control window'))
|
||||||
self.ppt_window_check_box.setEnabled(powerpoint_available)
|
self.ppt_window_check_box.setEnabled(powerpoint_available)
|
||||||
# load pdf-program settings
|
|
||||||
enable_pdf_program = self.settings.value('presentations/enable_pdf_program')
|
|
||||||
self.pdf_program_check_box.setChecked(enable_pdf_program)
|
|
||||||
self.program_path_edit.setEnabled(enable_pdf_program)
|
|
||||||
self.program_path_edit.path = self.settings.value('presentations/pdf_program')
|
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
"""
|
"""
|
||||||
@ -186,18 +160,6 @@ class PresentationTab(SettingsTab):
|
|||||||
if self.settings.value(setting_key) != self.ppt_window_check_box.checkState():
|
if self.settings.value(setting_key) != self.ppt_window_check_box.checkState():
|
||||||
self.settings.setValue(setting_key, self.ppt_window_check_box.checkState())
|
self.settings.setValue(setting_key, self.ppt_window_check_box.checkState())
|
||||||
changed = True
|
changed = True
|
||||||
# Save pdf-settings
|
|
||||||
pdf_program_path = self.program_path_edit.path
|
|
||||||
enable_pdf_program = self.pdf_program_check_box.checkState()
|
|
||||||
# If the given program is blank disable using the program
|
|
||||||
if pdf_program_path is None:
|
|
||||||
enable_pdf_program = 0
|
|
||||||
if pdf_program_path != self.settings.value('presentations/pdf_program'):
|
|
||||||
self.settings.setValue('presentations/pdf_program', pdf_program_path)
|
|
||||||
changed = True
|
|
||||||
if enable_pdf_program != self.settings.value('presentations/enable_pdf_program'):
|
|
||||||
self.settings.setValue('presentations/enable_pdf_program', enable_pdf_program)
|
|
||||||
changed = True
|
|
||||||
if changed:
|
if changed:
|
||||||
self.settings_form.register_post_process('mediaitem_suffix_reset')
|
self.settings_form.register_post_process('mediaitem_suffix_reset')
|
||||||
self.settings_form.register_post_process('mediaitem_presentation_rebuild')
|
self.settings_form.register_post_process('mediaitem_presentation_rebuild')
|
||||||
@ -213,16 +175,3 @@ class PresentationTab(SettingsTab):
|
|||||||
checkbox = self.presenter_check_boxes[controller.name]
|
checkbox = self.presenter_check_boxes[controller.name]
|
||||||
checkbox.setEnabled(controller.is_available())
|
checkbox.setEnabled(controller.is_available())
|
||||||
self.set_controller_text(checkbox, controller)
|
self.set_controller_text(checkbox, controller)
|
||||||
|
|
||||||
def on_program_path_edit_path_changed(self, new_path):
|
|
||||||
"""
|
|
||||||
Handle the `pathEditChanged` signal from program_path_edit
|
|
||||||
|
|
||||||
:param pathlib.Path new_path: File path to the new program
|
|
||||||
:rtype: None
|
|
||||||
"""
|
|
||||||
if new_path:
|
|
||||||
if not PdfController.process_check_binary(new_path):
|
|
||||||
critical_error_message_box(UiStrings().Error,
|
|
||||||
translate('PresentationPlugin.PresentationTab',
|
|
||||||
'The program is not ghostscript or mudraw which is required.'))
|
|
||||||
|
@ -24,10 +24,10 @@ This module contains tests for the PdfController
|
|||||||
import os
|
import os
|
||||||
import pytest
|
import pytest
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from shutil import rmtree, which
|
from shutil import rmtree
|
||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
from unittest import skipIf
|
from unittest import skipIf
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtGui
|
from PyQt5 import QtCore, QtGui
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ def test_constructor(settings, mock_plugin):
|
|||||||
assert 'Pdf' == controller.name, 'The name of the presentation controller should be correct'
|
assert 'Pdf' == controller.name, 'The name of the presentation controller should be correct'
|
||||||
|
|
||||||
|
|
||||||
def load_pdf(exe_path, pdf_env):
|
def load_pdf(pdf_env):
|
||||||
"""
|
"""
|
||||||
Test loading a Pdf using the PdfController
|
Test loading a Pdf using the PdfController
|
||||||
"""
|
"""
|
||||||
@ -104,11 +104,9 @@ def load_pdf(exe_path, pdf_env):
|
|||||||
test_file_path = RESOURCE_PATH / 'presentations' / 'pdf_test1.pdf'
|
test_file_path = RESOURCE_PATH / 'presentations' / 'pdf_test1.pdf'
|
||||||
|
|
||||||
# WHEN: The Pdf is loaded
|
# WHEN: The Pdf is loaded
|
||||||
settings = pdf_env[0]
|
|
||||||
mock_plugin = pdf_env[1]
|
mock_plugin = pdf_env[1]
|
||||||
temp_folder_path = pdf_env[2]
|
temp_folder_path = pdf_env[2]
|
||||||
thumbnail_folder_path = pdf_env[3]
|
thumbnail_folder_path = pdf_env[3]
|
||||||
settings.setValue('presentations/pdf_program', exe_path)
|
|
||||||
controller = PdfController(plugin=mock_plugin)
|
controller = PdfController(plugin=mock_plugin)
|
||||||
controller.temp_folder = temp_folder_path
|
controller.temp_folder = temp_folder_path
|
||||||
controller.thumbnail_folder = thumbnail_folder_path
|
controller.thumbnail_folder = thumbnail_folder_path
|
||||||
@ -121,7 +119,7 @@ def load_pdf(exe_path, pdf_env):
|
|||||||
|
|
||||||
|
|
||||||
@skipIf(IS_QT_QPA_PLATFORM_OFFSCREEN, 'This test fails when QT_QPA_PLATFORM is set to "offscreen".')
|
@skipIf(IS_QT_QPA_PLATFORM_OFFSCREEN, 'This test fails when QT_QPA_PLATFORM is set to "offscreen".')
|
||||||
def load_pdf_pictures(exe_path, pdf_env):
|
def load_pdf_pictures(pdf_env):
|
||||||
"""
|
"""
|
||||||
Test loading a Pdf and check the generated pictures' size
|
Test loading a Pdf and check the generated pictures' size
|
||||||
"""
|
"""
|
||||||
@ -129,11 +127,9 @@ def load_pdf_pictures(exe_path, pdf_env):
|
|||||||
test_file_path = RESOURCE_PATH / 'presentations' / 'pdf_test1.pdf'
|
test_file_path = RESOURCE_PATH / 'presentations' / 'pdf_test1.pdf'
|
||||||
|
|
||||||
# WHEN: The Pdf is loaded
|
# WHEN: The Pdf is loaded
|
||||||
settings = pdf_env[0]
|
|
||||||
mock_plugin = pdf_env[1]
|
mock_plugin = pdf_env[1]
|
||||||
temp_folder_path = pdf_env[2]
|
temp_folder_path = pdf_env[2]
|
||||||
thumbnail_folder_path = pdf_env[3]
|
thumbnail_folder_path = pdf_env[3]
|
||||||
settings.setValue('presentations/pdf_program', exe_path)
|
|
||||||
controller = PdfController(plugin=mock_plugin)
|
controller = PdfController(plugin=mock_plugin)
|
||||||
controller.temp_folder = temp_folder_path
|
controller.temp_folder = temp_folder_path
|
||||||
controller.thumbnail_folder = thumbnail_folder_path
|
controller.thumbnail_folder = thumbnail_folder_path
|
||||||
@ -144,10 +140,6 @@ def load_pdf_pictures(exe_path, pdf_env):
|
|||||||
assert loaded is True, 'The loading of the PDF should succeed.'
|
assert loaded is True, 'The loading of the PDF should succeed.'
|
||||||
image = QtGui.QImage(os.path.join(str(temp_folder_path), 'pdf_test1.pdf', 'mainslide001.png'))
|
image = QtGui.QImage(os.path.join(str(temp_folder_path), 'pdf_test1.pdf', 'mainslide001.png'))
|
||||||
# Based on the converter used the resolution will differ a bit
|
# Based on the converter used the resolution will differ a bit
|
||||||
if controller.gsbin:
|
|
||||||
assert 1076 == image.height(), 'The height should be 1076'
|
|
||||||
assert 760 == image.width(), 'The width should be 760'
|
|
||||||
else:
|
|
||||||
width, height = get_screen_resolution()
|
width, height = get_screen_resolution()
|
||||||
# Calculate the width of the PDF based on the aspect ratio of the PDF
|
# Calculate the width of the PDF based on the aspect ratio of the PDF
|
||||||
width = int(round(height * 0.70703125, 0))
|
width = int(round(height * 0.70703125, 0))
|
||||||
@ -155,97 +147,11 @@ def load_pdf_pictures(exe_path, pdf_env):
|
|||||||
assert image.width() == width, 'The width should be {width}'.format(width=width)
|
assert image.width() == width, 'The width should be {width}'.format(width=width)
|
||||||
|
|
||||||
|
|
||||||
def test_load_pdf(pdf_env):
|
|
||||||
"""
|
|
||||||
Test loading a Pdf with each of the installed backends
|
|
||||||
"""
|
|
||||||
for exe_name in ['gs', 'mutool', 'mudraw']:
|
|
||||||
exe_path = which(exe_name)
|
|
||||||
if exe_path:
|
|
||||||
load_pdf(exe_path, pdf_env)
|
|
||||||
load_pdf_pictures(exe_path, pdf_env)
|
|
||||||
|
|
||||||
|
|
||||||
def test_loading_pdf_using_pymupdf(pdf_env):
|
def test_loading_pdf_using_pymupdf(pdf_env):
|
||||||
try:
|
try:
|
||||||
import fitz # noqa: F401
|
import fitz # noqa: F401
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pytest.skip('PyMuPDF is not installed')
|
pytest.skip('PyMuPDF is not installed')
|
||||||
|
|
||||||
load_pdf(None, pdf_env)
|
load_pdf(pdf_env)
|
||||||
load_pdf_pictures(None, pdf_env)
|
load_pdf_pictures(pdf_env)
|
||||||
|
|
||||||
|
|
||||||
@patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists')
|
|
||||||
def test_process_check_binary_mudraw(mocked_check_binary_exists):
|
|
||||||
"""
|
|
||||||
Test that the correct output from mudraw is detected
|
|
||||||
"""
|
|
||||||
# GIVEN: A mocked check_binary_exists that returns mudraw output
|
|
||||||
mudraw_output = (b'usage: mudraw [options] input [pages]\n\t-o -\toutput filename (%d for page number)n\t\tsupp'
|
|
||||||
b'orted formats: pgm, ppm, pam, png, pbmn\t-p -\tpasswordn\t-r -\tresolution in dpi (default: '
|
|
||||||
b'72)n\t-w -\twidth (in pixels) (maximum width if -r is specified)n\t-h -\theight (in pixels) '
|
|
||||||
b'(maximum height if -r is specified)')
|
|
||||||
mocked_check_binary_exists.return_value = mudraw_output
|
|
||||||
|
|
||||||
# WHEN: Calling process_check_binary
|
|
||||||
ret = PdfController.process_check_binary('test')
|
|
||||||
|
|
||||||
# THEN: mudraw should be detected
|
|
||||||
assert 'mudraw' == ret, 'mudraw should have been detected'
|
|
||||||
|
|
||||||
|
|
||||||
@patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists')
|
|
||||||
def test_process_check_binary_new_motool(mocked_check_binary_exists):
|
|
||||||
"""
|
|
||||||
Test that the correct output from the new mutool is detected
|
|
||||||
"""
|
|
||||||
# GIVEN: A mocked check_binary_exists that returns new mutool output
|
|
||||||
new_mutool_output = (b'usage: mutool <command> [options]\n\tdraw\t-- convert document\n\trun\t-- run javascript'
|
|
||||||
b'\n\tclean\t-- rewrite pdf file\n\textract\t-- extract font and image resources\n\tinfo\t'
|
|
||||||
b'-- show information about pdf resources\n\tpages\t-- show information about pdf pages\n'
|
|
||||||
b'\tposter\t-- split large page into many tiles\n\tshow\t-- show internal pdf objects\n\t'
|
|
||||||
b'create\t-- create pdf document\n\tmerge\t-- merge pages from multiple pdf sources into a'
|
|
||||||
b'new pdf\n')
|
|
||||||
mocked_check_binary_exists.return_value = new_mutool_output
|
|
||||||
|
|
||||||
# WHEN: Calling process_check_binary
|
|
||||||
ret = PdfController.process_check_binary('test')
|
|
||||||
|
|
||||||
# THEN: mutool should be detected
|
|
||||||
assert 'mutool' == ret, 'mutool should have been detected'
|
|
||||||
|
|
||||||
|
|
||||||
@patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists')
|
|
||||||
def test_process_check_binary_old_motool(mocked_check_binary_exists):
|
|
||||||
"""
|
|
||||||
Test that the output from the old mutool is not accepted
|
|
||||||
"""
|
|
||||||
# GIVEN: A mocked check_binary_exists that returns old mutool output
|
|
||||||
old_mutool_output = (b'usage: mutool <command> [options]\n\tclean\t-- rewrite pdf file\n\textract\t-- extract '
|
|
||||||
b'font and image resources\n\tinfo\t-- show information about pdf resources\n\tposter\t-- '
|
|
||||||
b'split large page into many tiles\n\tshow\t-- show internal pdf objects')
|
|
||||||
mocked_check_binary_exists.return_value = old_mutool_output
|
|
||||||
|
|
||||||
# WHEN: Calling process_check_binary
|
|
||||||
ret = PdfController.process_check_binary('test')
|
|
||||||
|
|
||||||
# THEN: mutool should be detected
|
|
||||||
assert ret is None, 'old mutool should not be accepted!'
|
|
||||||
|
|
||||||
|
|
||||||
@patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists')
|
|
||||||
def test_process_check_binary_gs(mocked_check_binary_exists):
|
|
||||||
"""
|
|
||||||
Test that the correct output from gs is detected
|
|
||||||
"""
|
|
||||||
# GIVEN: A mocked check_binary_exists that returns gs output
|
|
||||||
gs_output = (b'GPL Ghostscript 9.19 (2016-03-23)\nCopyright (C) 2016 Artifex Software, Inc. All rights reserv'
|
|
||||||
b'ed.\nUsage: gs [switches] [file1.ps file2.ps ...]')
|
|
||||||
mocked_check_binary_exists.return_value = gs_output
|
|
||||||
|
|
||||||
# WHEN: Calling process_check_binary
|
|
||||||
ret = PdfController.process_check_binary('test')
|
|
||||||
|
|
||||||
# THEN: mutool should be detected
|
|
||||||
assert 'gs' == ret, 'mutool should have been detected'
|
|
||||||
|
Loading…
Reference in New Issue
Block a user