diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index dc196fb59..00fccb657 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -150,7 +150,8 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): triggers=self.on_replace_click) if 'webkit' not in get_media_players()[0]: self.replace_action.setDisabled(True) - self.replace_action_context.setDisabled(True) + if hasattr(self, 'replace_action_context'): + self.replace_action_context.setDisabled(True) self.reset_action = self.toolbar.add_toolbar_action('reset_action', icon=':/system/system_close.png', visible=False, triggers=self.on_reset_click) self.media_widget = QtWidgets.QWidget(self) diff --git a/openlp/plugins/presentations/lib/libreofficeserver.py b/openlp/plugins/presentations/lib/libreofficeserver.py index 6d2b5752c..10504e29e 100644 --- a/openlp/plugins/presentations/lib/libreofficeserver.py +++ b/openlp/plugins/presentations/lib/libreofficeserver.py @@ -9,10 +9,10 @@ import logging # Add the vendor directory to sys.path so that we can load Pyro4 sys.path.append(os.path.join(os.path.dirname(__file__), 'vendor')) -from Pyro4 import Daemon, expose, locateNS +import uno from com.sun.star.beans import PropertyValue from com.sun.star.task import ErrorCodeIOException -import uno +from Pyro4 import Daemon, expose, locateNS logging.basicConfig(filename=os.path.dirname(__file__) + '/libreofficeserver.log', level=logging.INFO) log = logging.getLogger(__name__) @@ -34,11 +34,15 @@ class LibreOfficeServer(object): """ def __init__(self): """ - Set up the LibreOffice server + Set up the server """ - self._init_impress() + self._desktop = None + self._document = None + self._control = None + self._presentation = None + self._process = None - def _init_impress(self) + def start_process(self): """ Initialise Impress """ @@ -49,23 +53,31 @@ class LibreOfficeServer(object): '--minimized', '--nodefault', '--nofirststartwizard', - '"--accept=pipe,name=openlp_pipe;urp;"' + '--accept=socket,port=2002;urp;' ] self._process = Popen(uno_command) + + def setup_desktop(self): + """ + Set up an UNO desktop instance + """ + if self.has_desktop(): + return uno_instance = None context = uno.getComponentContext() resolver = context.ServiceManager.createInstanceWithContext('com.sun.star.bridge.UnoUrlResolver', context) + loop = 0 while uno_instance is None and loop < 3: try: - uno_instance = resolver.resolve('uno:pipe,name=openlp_pipe;urp;StarOffice.ComponentContext') - except: + uno_instance = resolver.resolve('uno:socket,port=2002;urp;StarOffice.ComponentContext') + except Exception as e: log.warning('Unable to find running instance ') loop += 1 try: self._manager = uno_instance.ServiceManager log.debug('get UNO Desktop Openoffice - createInstanceWithContext - Desktop') - self._desktop = self.manager.createInstanceWithContext("com.sun.star.frame.Desktop", uno_instance) - except: + self._desktop = self._manager.createInstanceWithContext("com.sun.star.frame.Desktop", uno_instance) + except Exception as e: log.warning('Failed to get UNO desktop') def _create_property(self, name, value): @@ -106,32 +118,35 @@ class LibreOfficeServer(object): """ Say if we have a desktop object """ - return self._desktop is not None + return hasattr(self, '_desktop') and self._desktop is not None def shutdown(self): """ Shut down the server """ - while self._docs: - self._docs[0].close_presentation() - if not self._desktop: - return - docs = self._desktop.getComponents() - count = 0 - if docs.hasElements(): - list_elements = docs.createEnumeration() - while list_elements.hasMoreElements(): - doc = list_elements.nextElement() - if doc.getImplementationName() != 'com.sun.star.comp.framework.BackingComp': - count += 1 - if count > 0: - log.debug('LibreOffice not terminated as docs are still open') - else: - try: - self._desktop.terminate() - log.debug('LibreOffice killed') - except: - log.warning('Failed to terminate LibreOffice') + if hasattr(self, '_docs'): + while self._docs: + self._docs[0].close_presentation() + if self.has_desktop(): + docs = self._desktop.getComponents() + count = 0 + if docs.hasElements(): + list_elements = docs.createEnumeration() + while list_elements.hasMoreElements(): + doc = list_elements.nextElement() + if doc.getImplementationName() != 'com.sun.star.comp.framework.BackingComp': + count += 1 + if count > 0: + log.debug('LibreOffice not terminated as docs are still open') + else: + try: + self._desktop.terminate() + log.debug('LibreOffice killed') + except: + log.warning('Failed to terminate LibreOffice') + if getattr(self, '_process'): + self._process.kill() + def load_presentation(self, file_path, screen_number): """ @@ -148,35 +163,33 @@ class LibreOfficeServer(object): self._presentation = self._document.getPresentation() self._presentation.Display = screen_number self._control = None - self.create_thumbnails() - self.create_titles_and_notes() return True - def create_thumbnails(self, temp_folder): + def extract_thumbnails(self, temp_folder): """ Create thumbnails for the presentation """ + thumbnails = [] thumb_dir_url = uno.systemPathToFileUrl(temp_folder) properties = (self._create_property('FilterName', 'impress_png_Export'),) - doc = self.document - pages = doc.getDrawPages() + pages = self._document.getDrawPages() if not pages: return if not os.path.isdir(temp_folder): os.makedirs(temp_folder) for index in range(pages.getCount()): page = pages.getByIndex(index) - doc.getCurrentController().setCurrentPage(page) + self._document.getCurrentController().setCurrentPage(page) url_path = '{path}/{name}.png'.format(path=thumb_dir_url, name=str(index + 1)) - path = os.path.join(self.get_temp_folder(), str(index + 1) + '.png') + path = os.path.join(temp_folder, str(index + 1) + '.png') try: - doc.storeToURL(url_path, properties) - self.convert_thumbnail(path, index + 1) - delete_file(path) + self._document.storeToURL(url_path, properties) + thumbnails.append(path) except ErrorCodeIOException as exception: log.exception('ERROR! ErrorCodeIOException {error:d}'.format(error=exception.ErrCode)) except: log.exception('{path} - Unable to store openoffice preview'.format(path=path)) + return thumbnails def get_title_and_notes(self): """ @@ -346,10 +359,8 @@ def main(): """ The main function which runs the server """ - daemon = Daemon() - ns = locateNS() - uri = daemon.register(LibreOfficeServer) - ns.register('openlp.libreofficeserver', uri) + daemon = Daemon(host='localhost', port=4310) + uri = daemon.register(LibreOfficeServer, 'openlp.libreofficeserver') try: daemon.requestLoop() finally: diff --git a/openlp/plugins/presentations/lib/maclocontroller.py b/openlp/plugins/presentations/lib/maclocontroller.py index 8083d379d..85df2178f 100644 --- a/openlp/plugins/presentations/lib/maclocontroller.py +++ b/openlp/plugins/presentations/lib/maclocontroller.py @@ -35,18 +35,16 @@ import logging import os import time from subprocess import Popen -from multiprocessing import Process -from openlp.core.common import is_mac, Registry, delete_file +from openlp.core.common import is_macosx, Registry, delete_file -if is_mac() and os.path.exists('/Applications/LibreOffice.app'): +if is_macosx() and os.path.exists('/Applications/LibreOffice.app'): macuno_available = True else: macuno_available = False from PyQt5 import QtCore from Pyro4 import Proxy -from Pyro4.naming import NameServerDaemon from openlp.core.lib import ScreenList from .presentationcontroller import PresentationController, PresentationDocument, TextType @@ -55,18 +53,6 @@ from .presentationcontroller import PresentationController, PresentationDocument log = logging.getLogger(__name__) -def run_nameserver(): - """ - Run a Pyro4 nameserver - """ - ns_daemon = NameServerDaemon() - ns_daemon._pyroHmacKey = 'openlp-libreoffice' - try: - ns_daemon.requestLoop() - finally: - ns_daemon.close() - - class MacLOController(PresentationController): """ Class to control interactions with MacLO presentations on Mac OS X via Pyro4. It starts the Pyro4 nameserver, @@ -83,18 +69,8 @@ class MacLOController(PresentationController): self.supports = ['odp'] self.also_supports = ['ppt', 'pps', 'pptx', 'ppsx', 'pptm'] self.server_process = None - self.nameserver_process = None - self.client = None - self._start_nameserver() + self._client = None self._start_server() - self._setup_client() - - def _start_nameserver(self): - """ - Start the Pyro4 nameserver - """ - self.nameserver_process = Process(run_nameserver) - self.nameserver_process.start() def _start_server(self): """ @@ -104,11 +80,16 @@ class MacLOController(PresentationController): libreoffice_server = os.path.join(os.path.dirname(__file__), 'libreofficeserver.py') self.server_process = Popen([libreoffice_python, libreoffice_server]) - def _setup_client(self): + @property + def client(self): """ Set up a Pyro4 client so that we can talk to the LibreOfficeServer """ - self.client = Proxy('PYRONAME:openlp.libreofficeserver') + if not self._client: + self._client = Proxy('PYRO:openlp.libreofficeserver@localhost:4310') + if not self._client._pyroConnection: + self._client._pyroReconnect() + return self._client def check_available(self): """ @@ -119,19 +100,11 @@ class MacLOController(PresentationController): def start_process(self): """ - Loads a running version of LibreOffice in the background. It is not displayed to the user but is available to the - UNO interface when required. + Loads a running version of LibreOffice in the background. It is not displayed to the user but is available to + the UNO interface when required. """ - log.debug('start process Openoffice') - if is_win(): - self.manager = self.get_com_servicemanager() - self.manager._FlagAsMethod('Bridge_GetStruct') - self.manager._FlagAsMethod('Bridge_GetValueObject') - else: - # -headless - cmd = get_uno_command() - self.process = QtCore.QProcess() - self.process.startDetached(cmd) + log.debug('Started automatically by the Pyro server') + self.client.start_process() def kill(self): """ @@ -139,8 +112,7 @@ class MacLOController(PresentationController): """ log.debug('Kill LibreOffice') self.client.shutdown() - self.server_process.terminate() - self.nameserver_process.terminate() + self.server_process.kill() class MacLODocument(PresentationDocument): @@ -155,9 +127,6 @@ class MacLODocument(PresentationDocument): log.debug('Init Presentation LibreOffice') super(MacLODocument, self).__init__(controller, presentation) self.client = controller.client - self.document = None - self.presentation = None - self.control = None def load_presentation(self): """ @@ -166,12 +135,13 @@ class MacLODocument(PresentationDocument): is available the presentation is loaded and started. """ log.debug('Load Presentation LibreOffice') + self.client.setup_desktop() if not self.client.has_desktop(): return False if not self.client.load_presentation(self.file_path, ScreenList().current['number'] + 1): return False self.create_thumbnails() - self.client.create_titles_and_notes() + self.create_titles_and_notes() return True def create_thumbnails(self): @@ -181,7 +151,10 @@ class MacLODocument(PresentationDocument): log.debug('create thumbnails LibreOffice') if self.check_thumbnails(): return - self.client.create_thumbnails(self.get_temp_folder()) + temp_thumbnails = self.client.extract_thumbnails(self.get_temp_folder()) + for index, temp_thumb in enumerate(temp_thumbnails): + self.convert_thumbnail(temp_thumb, index + 1) + delete_file(temp_thumb) def create_titles_and_notes(self): """ diff --git a/openlp/plugins/presentations/presentationplugin.py b/openlp/plugins/presentations/presentationplugin.py index ca0ecba82..505f0dbb7 100644 --- a/openlp/plugins/presentations/presentationplugin.py +++ b/openlp/plugins/presentations/presentationplugin.py @@ -36,18 +36,20 @@ from openlp.plugins.presentations.lib import PresentationController, Presentatio log = logging.getLogger(__name__) -__default_settings__ = {'presentations/override app': QtCore.Qt.Unchecked, - 'presentations/enable_pdf_program': QtCore.Qt.Unchecked, - 'presentations/pdf_program': '', - 'presentations/Impress': QtCore.Qt.Checked, - 'presentations/Powerpoint': QtCore.Qt.Checked, - 'presentations/Powerpoint Viewer': QtCore.Qt.Checked, - 'presentations/Pdf': QtCore.Qt.Checked, - 'presentations/presentations files': [], - 'presentations/thumbnail_scheme': '', - 'presentations/powerpoint slide click advance': QtCore.Qt.Unchecked, - 'presentations/powerpoint control window': QtCore.Qt.Unchecked - } +__default_settings__ = { + 'presentations/override app': QtCore.Qt.Unchecked, + 'presentations/enable_pdf_program': QtCore.Qt.Unchecked, + 'presentations/pdf_program': '', + 'presentations/MacLO': QtCore.Qt.Checked, + 'presentations/Impress': QtCore.Qt.Checked, + 'presentations/Powerpoint': QtCore.Qt.Checked, + 'presentations/Powerpoint Viewer': QtCore.Qt.Checked, + 'presentations/Pdf': QtCore.Qt.Checked, + 'presentations/presentations files': [], + 'presentations/thumbnail_scheme': '', + 'presentations/powerpoint slide click advance': QtCore.Qt.Unchecked, + 'presentations/powerpoint control window': QtCore.Qt.Unchecked +} class PresentationPlugin(Plugin): @@ -87,7 +89,7 @@ class PresentationPlugin(Plugin): try: self.controllers[controller].start_process() except Exception: - log.warning('Failed to start controller process') + log.exception('Failed to start controller process') self.controllers[controller].available = False self.media_item.build_file_mask_string() @@ -132,7 +134,7 @@ class PresentationPlugin(Plugin): try: __import__(module_name, globals(), locals(), []) except ImportError: - log.warning('Failed to import {name} on path {path}'.format(name=module_name, path=path)) + log.exception('Failed to import {name} on path {path}'.format(name=module_name, path=path)) controller_classes = PresentationController.__subclasses__() for controller_class in controller_classes: controller = controller_class(self)