From d28d75a2ce8a6d77ab577212da9c8457b2da308f Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sun, 4 Aug 2013 20:51:22 +0100 Subject: [PATCH] Added possible to point to a binary to use for pdf-processing. --- openlp/plugins/presentations/lib/mediaitem.py | 14 ++- .../presentations/lib/messagelistener.py | 7 +- .../presentations/lib/pdfcontroller.py | 49 ++++++++- .../presentations/lib/presentationtab.py | 101 +++++++++++++++++- .../presentations/presentationplugin.py | 2 + 5 files changed, 158 insertions(+), 15 deletions(-) diff --git a/openlp/plugins/presentations/lib/mediaitem.py b/openlp/plugins/presentations/lib/mediaitem.py index 577f0cf62..dabab5c04 100644 --- a/openlp/plugins/presentations/lib/mediaitem.py +++ b/openlp/plugins/presentations/lib/mediaitem.py @@ -249,8 +249,6 @@ class PresentationMediaItem(MediaManagerItem): file_type = os.path.splitext(filename)[1][1:] if not self.display_type_combo_box.currentText(): return False - - service_item.processor = self.display_type_combo_box.currentText() if context == ServiceItemContext.Live and (file_type == u'pdf' or file_type == u'xps'): service_item.add_capability(ItemCapabilities.CanMaintain) @@ -266,12 +264,11 @@ class PresentationMediaItem(MediaManagerItem): (path, name) = os.path.split(filename) service_item.title = name if os.path.exists(filename): - if service_item.processor == self.Automatic: - service_item.processor = self.findControllerByType(filename) - if not service_item.processor: - return False - controller = self.controllers[service_item.processor] - #service_item.processor = None + processor = self.findControllerByType(filename) + if not processor: + return False + controller = self.controllers[processor] + service_item.processor = None doc = controller.add_document(filename) if doc.get_thumbnail_path(1, True) is None: doc.load_presentation() @@ -300,6 +297,7 @@ class PresentationMediaItem(MediaManagerItem): translate('PresentationPlugin.MediaItem', 'The presentation %s no longer exists.') % filename) return False else: + service_item.processor = self.display_type_combo_box.currentText() service_item.add_capability(ItemCapabilities.ProvidesOwnDisplay) # Why the loop when we above return False if len(items) is > 1? diff --git a/openlp/plugins/presentations/lib/messagelistener.py b/openlp/plugins/presentations/lib/messagelistener.py index cd7c654a2..5df013c2e 100644 --- a/openlp/plugins/presentations/lib/messagelistener.py +++ b/openlp/plugins/presentations/lib/messagelistener.py @@ -324,7 +324,12 @@ class MessageListener(object): controller = self.live_handler else: controller = self.preview_handler - controller.add_handler(self.controllers[self.handler], file, hide_mode, message[3]) + # when presenting PDF, we're using the image presentation code, + # so handler & processor is set to None, and we skip adding the handler. + if self.handler == None: + self.controller = controller + else: + controller.add_handler(self.controllers[self.handler], file, hide_mode, message[3]) def slide(self, message): """ diff --git a/openlp/plugins/presentations/lib/pdfcontroller.py b/openlp/plugins/presentations/lib/pdfcontroller.py index ff79c6231..d2ba47bef 100644 --- a/openlp/plugins/presentations/lib/pdfcontroller.py +++ b/openlp/plugins/presentations/lib/pdfcontroller.py @@ -31,16 +31,40 @@ import os import logging from tempfile import NamedTemporaryFile import re -from subprocess import check_output, CalledProcessError +from subprocess import check_output, CalledProcessError, STDOUT from PyQt4 import QtCore, QtGui from openlp.core.utils import AppLocation -from openlp.core.lib import ScreenList +from openlp.core.lib import ScreenList, Settings from presentationcontroller import PresentationController, PresentationDocument log = logging.getLogger(__name__) +def check_binary(program_path): + """ + Function that checks whether a binary is either ghostscript or mudraw or neither. + """ + program_type = None + runlog = u'' + try: + runlog = check_output([program_path, u'--help'], stderr=STDOUT) + except CalledProcessError as e: + runlog = e.output + except Exception: + runlog = u'' + + # Analyse the output to see it the program is mudraw, ghostscript or neither + for line in runlog.splitlines(): + found_mudraw = re.search(u'usage: mudraw.*', line) + if found_mudraw: + program_type = u'mudraw' + break + found_gs = re.search(u'GPL Ghostscript.*', line) + if found_gs: + program_type = u'gs' + break + return program_type class PdfController(PresentationController): """ @@ -72,8 +96,20 @@ class PdfController(PresentationController): """ Check the viewer is installed. """ - application_path = AppLocation.get_directory(AppLocation.AppDir) log.debug(u'check_installed Pdf') + # Use the user defined program if given + if (Settings().value(u'presentations/enable_given_pdf_program')): + given_pdf_program = Settings().value(u'presentations/given_pdf_program') + type = check_binary(given_pdf_program) + if type == u'gs': + self.gsbin = given_pdf_program + return True + elif type == u'mudraw': + self.mudrawbin = given_pdf_program + return True + + # Fallback to autodetection + application_path = AppLocation.get_directory(AppLocation.AppDir) if os.name != u'nt': # First try to find mupdf try: @@ -153,7 +189,12 @@ quit \n\ tmpfile.close() # Run the script on the pdf to get the size - runlog = check_output([self.controller.gsbin, u'-dNOPAUSE', u'-dNODISPLAY', u'-dBATCH', u'-sFile=' + self.filepath, tmpfile.name]) + runlog = [] + try: + runlog = check_output([self.controller.gsbin, u'-dNOPAUSE', u'-dNODISPLAY', u'-dBATCH', u'-sFile=' + self.filepath, tmpfile.name]) + except CalledProcessError as e: + log.debug(u' '.join(e.cmd)) + log.debug(e.output) os.unlink(tmpfile.name) # Extract the pdf resolution from output, the format is " Size: x: , y: " diff --git a/openlp/plugins/presentations/lib/presentationtab.py b/openlp/plugins/presentations/lib/presentationtab.py index e46467403..6ada5d496 100644 --- a/openlp/plugins/presentations/lib/presentationtab.py +++ b/openlp/plugins/presentations/lib/presentationtab.py @@ -29,8 +29,9 @@ from PyQt4 import QtGui -from openlp.core.lib import Settings, SettingsTab, UiStrings, translate - +from openlp.core.lib import Settings, SettingsTab, UiStrings, translate, build_icon +from openlp.core.lib.ui import critical_error_message_box +from pdfcontroller import check_binary class PresentationTab(SettingsTab): """ @@ -63,6 +64,7 @@ class PresentationTab(SettingsTab): self.presenter_check_boxes[controller.name] = checkbox self.controllers_layout.addWidget(checkbox) self.left_layout.addWidget(self.controllers_group_box) + # Advanced self.advanced_group_box = QtGui.QGroupBox(self.left_column) self.advanced_group_box.setObjectName(u'advanced_group_box') self.advanced_layout = QtGui.QVBoxLayout(self.advanced_group_box) @@ -70,7 +72,33 @@ class PresentationTab(SettingsTab): self.override_app_check_box = QtGui.QCheckBox(self.advanced_group_box) self.override_app_check_box.setObjectName(u'override_app_check_box') self.advanced_layout.addWidget(self.override_app_check_box) + + # Pdf options + self.pdf_group_box = QtGui.QGroupBox(self.left_column) + self.pdf_group_box.setObjectName(u'pdf_group_box') + self.pdf_layout = QtGui.QFormLayout(self.pdf_group_box) + self.pdf_layout.setObjectName(u'pdf_layout') + self.pdf_program_check_box = QtGui.QCheckBox(self.pdf_group_box) + self.pdf_program_check_box.setObjectName(u'pdf_program_check_box') + self.pdf_layout.addWidget(self.pdf_program_check_box) + self.pdf_program_path_layout = QtGui.QHBoxLayout() + self.pdf_program_path_layout.setObjectName(u'pdf_program_path_layout') + self.pdf_program_path = QtGui.QLineEdit(self.pdf_group_box) + self.pdf_program_path.setObjectName(u'pdf_program_path') + self.pdf_program_path.setReadOnly(True) + self.pdf_program_path.setPalette(self.get_grey_text_palette(True)) + self.pdf_program_path_layout.addWidget(self.pdf_program_path) + self.pdf_program_browse_button = QtGui.QToolButton(self.pdf_group_box) + self.pdf_program_browse_button.setObjectName(u'pdf_program_browse_button') + self.pdf_program_browse_button.setIcon(build_icon(u':/general/general_open.png')) + self.pdf_program_browse_button.setEnabled(False) + self.pdf_program_path_layout.addWidget(self.pdf_program_browse_button) + self.pdf_layout.addRow(self.pdf_program_path_layout) + self.pdf_program_path.editingFinished.connect(self.on_pdf_program_path_edit_finished) + self.pdf_program_browse_button.clicked.connect(self.on_pdf_program_browse_button_clicked) + self.pdf_program_check_box.clicked.connect(self.on_pdf_program_check_box_clicked) self.left_layout.addWidget(self.advanced_group_box) + self.left_layout.addWidget(self.pdf_group_box) self.left_layout.addStretch() self.right_layout.addStretch() @@ -84,8 +112,12 @@ class PresentationTab(SettingsTab): checkbox = self.presenter_check_boxes[controller.name] self.set_controller_text(checkbox, controller) self.advanced_group_box.setTitle(UiStrings().Advanced) + self.pdf_group_box.setTitle(translate('PresentationPlugin.PresentationTab', 'PDF options')) self.override_app_check_box.setText( translate('PresentationPlugin.PresentationTab', 'Allow presentation application to be overridden')) + self.pdf_program_check_box.setText( + translate('PresentationPlugin.PresentationTab', 'Use given full path for mudraw or ghostscript binary:')) + def set_controller_text(self, checkbox, controller): if checkbox.isEnabled(): @@ -102,6 +134,15 @@ class PresentationTab(SettingsTab): checkbox = self.presenter_check_boxes[controller.name] checkbox.setChecked(Settings().value(self.settings_section + u'/' + controller.name)) self.override_app_check_box.setChecked(Settings().value(self.settings_section + u'/override app')) + # load pdf-program settings + enable_given_pdf_program = Settings().value(self.settings_section + u'/enable_given_pdf_program') + self.pdf_program_check_box.setChecked(enable_given_pdf_program) + self.pdf_program_path.setReadOnly(not enable_given_pdf_program) + self.pdf_program_path.setPalette(self.get_grey_text_palette(not enable_given_pdf_program)) + self.pdf_program_browse_button.setEnabled(enable_given_pdf_program) + pdf_program = Settings().value(self.settings_section + u'/given_pdf_program') + if pdf_program: + self.pdf_program_path.setText(pdf_program) def save(self): """ @@ -127,10 +168,25 @@ class PresentationTab(SettingsTab): if Settings().value(setting_key) != self.override_app_check_box.checkState(): Settings().setValue(setting_key, self.override_app_check_box.checkState()) changed = True + + # Save pdf-settings + pdf_program = self.pdf_program_path.text() + enable_given_pdf_program = self.pdf_program_check_box.checkState() + # If the given program is blank disable using the program + if pdf_program == u'': + enable_given_pdf_program = 0 + if pdf_program != Settings().value(self.settings_section + u'/given_pdf_program'): + Settings().setValue(self.settings_section + u'/given_pdf_program', pdf_program) + changed = True + if enable_given_pdf_program != Settings().value(self.settings_section + u'/enable_given_pdf_program'): + Settings().setValue(self.settings_section + u'/enable_given_pdf_program', enable_given_pdf_program) + changed = True + if changed: self.settings_form.register_post_process(u'mediaitem_suffix_reset') self.settings_form.register_post_process(u'mediaitem_presentation_rebuild') self.settings_form.register_post_process(u'mediaitem_suffixes') + def tab_visible(self): """ @@ -142,3 +198,44 @@ class PresentationTab(SettingsTab): checkbox = self.presenter_check_boxes[controller.name] checkbox.setEnabled(controller.is_available()) self.set_controller_text(checkbox, controller) + + def on_pdf_program_path_edit_finished(self): + """ + After selecting/typing in a program it is validated that it is a actually ghostscript or mudraw + """ + type = None + if self.pdf_program_path.text() != u'': + type = check_binary(self.pdf_program_path.text()) + if not type: + critical_error_message_box(UiStrings().Error, + translate('PresentationPlugin.PresentationTab', 'The program is not ghostscript or mudraw which is required.')) + self.pdf_program_path.setFocus() + + def on_pdf_program_browse_button_clicked(self): + """ + Select the mudraw or ghostscript binary that should be used. + """ + filename = QtGui.QFileDialog.getOpenFileName(self, translate('PresentationPlugin.PresentationTab', 'Select mudraw or ghostscript binary.')) + if filename: + self.pdf_program_path.setText(filename) + self.pdf_program_path.setFocus() + + def on_pdf_program_check_box_clicked(self, checked): + """ + When checkbox for manual entering pdf-program is clicked, + enable or disable the textbox for the programpath and the browse-button. + """ + self.pdf_program_path.setReadOnly(not checked) + self.pdf_program_path.setPalette(self.get_grey_text_palette(not checked)) + self.pdf_program_browse_button.setEnabled(checked) + + def get_grey_text_palette(self, greyed): + """ + Returns a QPalette with greyed out text as used for placeholderText. + """ + palette = QtGui.QPalette() + color = self.palette().color(QtGui.QPalette.Active, QtGui.QPalette.Text) + if greyed: + color.setAlpha(128) + palette.setColor(QtGui.QPalette.Active, QtGui.QPalette.Text, color) + return palette diff --git a/openlp/plugins/presentations/presentationplugin.py b/openlp/plugins/presentations/presentationplugin.py index b11975591..d6019a46b 100644 --- a/openlp/plugins/presentations/presentationplugin.py +++ b/openlp/plugins/presentations/presentationplugin.py @@ -45,6 +45,8 @@ log = logging.getLogger(__name__) __default_settings__ = { u'presentations/override app': QtCore.Qt.Unchecked, + u'presentations/enable_given_pdf_program': QtCore.Qt.Unchecked, + u'presentations/given_pdf_program': u'', u'presentations/Impress': QtCore.Qt.Checked, u'presentations/Powerpoint': QtCore.Qt.Checked, u'presentations/Powerpoint Viewer': QtCore.Qt.Checked,