From cb3ef2f7c855cb40cec900a98cbfd8e59e9161d3 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Thu, 21 Apr 2016 22:09:42 +0200 Subject: [PATCH 01/27] Make it possible for presentations to wrap or go to next item, like native openlp-items. Fixes bug 1165855. Fixes: https://launchpad.net/bugs/1165855 --- openlp/core/common/registry.py | 2 +- openlp/core/ui/slidecontroller.py | 13 +++++++++++-- .../presentations/lib/impresscontroller.py | 3 +++ .../presentations/lib/messagelistener.py | 19 ++++++++++--------- .../presentations/lib/powerpointcontroller.py | 5 ++++- .../presentations/lib/pptviewcontroller.py | 5 ++++- .../lib/pptviewlib/pptviewlib.cpp | 6 ++++-- .../presentations/lib/pptviewlib/pptviewlib.h | 2 +- .../lib/presentationcontroller.py | 2 +- 9 files changed, 39 insertions(+), 18 deletions(-) diff --git a/openlp/core/common/registry.py b/openlp/core/common/registry.py index adf495a36..005f284ad 100644 --- a/openlp/core/common/registry.py +++ b/openlp/core/common/registry.py @@ -135,7 +135,7 @@ class Registry(object): for function in self.functions_list[event]: try: result = function(*args, **kwargs) - if result: + if result is not None: results.append(result) except TypeError: # Who has called me can help in debugging diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 96ce82868..6e198dd30 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -1170,8 +1170,17 @@ class SlideController(DisplayController, RegistryProperties): if not self.service_item: return if self.service_item.is_command(): - Registry().execute('%s_next' % self.service_item.name.lower(), [self.service_item, self.is_live]) - if self.is_live: + past_end = Registry().execute('%s_next' % self.service_item.name.lower(), [self.service_item, self.is_live]) + # Check if we have gone past the end of the last slide + if self.is_live and past_end and past_end[0]: + if wrap is None: + if self.slide_limits == SlideLimits.Wrap: + self.on_slide_selected_index([0]) + elif self.is_live and self.slide_limits == SlideLimits.Next: + self.service_next() + elif wrap: + self.on_slide_selected_index([0]) + else: self.update_preview() else: row = self.preview_widget.current_slide_number() + 1 diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index 29af3a375..5442ad6e3 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -416,11 +416,14 @@ class ImpressDocument(PresentationDocument): """ Triggers the next effect of slide on the running presentation. """ + past_end = False is_paused = self.control.isPaused() self.control.gotoNextEffect() time.sleep(0.1) if not is_paused and self.control.isPaused(): self.control.gotoPreviousEffect() + past_end = True + return past_end def previous_step(self): """ diff --git a/openlp/plugins/presentations/lib/messagelistener.py b/openlp/plugins/presentations/lib/messagelistener.py index cc5a6f05e..ee25c2efc 100644 --- a/openlp/plugins/presentations/lib/messagelistener.py +++ b/openlp/plugins/presentations/lib/messagelistener.py @@ -168,24 +168,25 @@ class Controller(object): """ log.debug('Live = %s, next' % self.is_live) if not self.doc: - return + return False if not self.is_live: - return + return False if self.hide_mode: if not self.doc.is_active(): - return + return False if self.doc.slidenumber < self.doc.get_slide_count(): self.doc.slidenumber += 1 self.poll() - return + return False if not self.activate(): - return + return False # The "End of slideshow" screen is after the last slide. Note, we can't just stop on the last slide, since it # may contain animations that need to be stepped through. if self.doc.slidenumber > self.doc.get_slide_count(): - return - self.doc.next_step() + return True + ret = self.doc.next_step() self.poll() + return ret def previous(self): """ @@ -418,9 +419,9 @@ class MessageListener(object): """ is_live = message[1] if is_live: - self.live_handler.next() + return self.live_handler.next() else: - self.preview_handler.next() + return self.preview_handler.next() def previous(self, message): """ diff --git a/openlp/plugins/presentations/lib/powerpointcontroller.py b/openlp/plugins/presentations/lib/powerpointcontroller.py index 6cc6a8450..3b20207a3 100644 --- a/openlp/plugins/presentations/lib/powerpointcontroller.py +++ b/openlp/plugins/presentations/lib/powerpointcontroller.py @@ -433,6 +433,7 @@ class PowerpointDocument(PresentationDocument): Triggers the next effect of slide on the running presentation. """ log.debug('next_step') + past_end = False try: self.presentation.SlideShowWindow.Activate() self.presentation.SlideShowWindow.View.Next() @@ -441,16 +442,18 @@ class PowerpointDocument(PresentationDocument): log.exception(e) trace_error_handler(log) self.show_error_msg() - return + return past_end if self.get_slide_number() > self.get_slide_count(): log.debug('past end, stepping back to previous') self.previous_step() + past_end = True # Stop powerpoint from flashing in the taskbar if self.presentation_hwnd: win32gui.FlashWindowEx(self.presentation_hwnd, win32con.FLASHW_STOP, 0, 0) # Make sure powerpoint doesn't steal focus, unless we're on a single screen setup if len(ScreenList().screen_list) > 1: Registry().get('main_window').activateWindow() + return past_end def previous_step(self): """ diff --git a/openlp/plugins/presentations/lib/pptviewcontroller.py b/openlp/plugins/presentations/lib/pptviewcontroller.py index c5e1b351f..9fbb23cc7 100644 --- a/openlp/plugins/presentations/lib/pptviewcontroller.py +++ b/openlp/plugins/presentations/lib/pptviewcontroller.py @@ -302,7 +302,10 @@ class PptviewDocument(PresentationDocument): """ Triggers the next effect of slide on the running presentation. """ - self.controller.process.NextStep(self.ppt_id) + if self.controller.process.NextStep(self.ppt_id) == 0: + return False + else: + return True def previous_step(self): """ diff --git a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp index 22b46f760..ee1dac08c 100644 --- a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp +++ b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp @@ -518,16 +518,18 @@ DllExport int GetCurrentSlide(int id) } // Take a step forwards through the show -DllExport void NextStep(int id) +DllExport int NextStep(int id) { DEBUG(L"NextStep:%d (%d)\n", id, pptView[id].currentSlide); - if (pptView[id].currentSlide > pptView[id].slideCount) return; + // Return 1 to signal that the slideshow has gone past the end + if (pptView[id].currentSlide > pptView[id].slideCount) return 1; if (pptView[id].currentSlide < pptView[id].slideCount) { pptView[id].guess = pptView[id].currentSlide + 1; } PostMessage(pptView[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, -WHEEL_DELTA), 0); + return 0; } // Take a step backwards through the show diff --git a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h index e54c95537..66df0e0b1 100644 --- a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h +++ b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h @@ -30,7 +30,7 @@ DllExport BOOL CheckInstalled(); DllExport void ClosePPT(int id); DllExport int GetCurrentSlide(int id); DllExport int GetSlideCount(int id); -DllExport void NextStep(int id); +DllExport int NextStep(int id); DllExport void PrevStep(int id); DllExport void GotoSlide(int id, int slide_no); DllExport void RestartShow(int id); diff --git a/openlp/plugins/presentations/lib/presentationcontroller.py b/openlp/plugins/presentations/lib/presentationcontroller.py index abc71f867..0b62ee485 100644 --- a/openlp/plugins/presentations/lib/presentationcontroller.py +++ b/openlp/plugins/presentations/lib/presentationcontroller.py @@ -232,7 +232,7 @@ class PresentationDocument(object): Triggers the next effect of slide on the running presentation. This might be the next animation on the current slide, or the next slide """ - pass + return False def previous_step(self): """ From 89a68f9e6bf3808578490c2233d42fec0e1f77b0 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 10 Oct 2017 21:29:03 +0200 Subject: [PATCH 02/27] Fixed a typo and added a SlideShowListener for event handling. --- .../presentations/lib/impresscontroller.py | 110 ++++++++++++++++++ .../presentations/lib/messagelistener.py | 2 +- 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index d89c6c8f1..0e57f9577 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -51,8 +51,10 @@ if is_win(): else: try: import uno + import unohelper from com.sun.star.beans import PropertyValue from com.sun.star.task import ErrorCodeIOException + from com.sun.star.presentation import XSlideShowListener uno_available = True except ImportError: @@ -210,6 +212,8 @@ class ImpressDocument(PresentationDocument): self.document = None self.presentation = None self.control = None + self.slide_ended = False + self.slide_ended_reverse = False def load_presentation(self): """ @@ -381,6 +385,8 @@ class ImpressDocument(PresentationDocument): sleep_count += 1 self.control = self.presentation.getController() window.setVisible(False) + listener = SlideShowListener(self) + self.control.getSlideShow().addSlideShowListener(listener) else: self.control.activate() self.goto_slide(1) @@ -412,10 +418,19 @@ class ImpressDocument(PresentationDocument): """ Triggers the next effect of slide on the running presentation. """ + # if we are at the presentations end don't go further, just return True + if self.slide_ended and self.get_slide_count() == self.get_slide_number(): + print('detected presentation end!') + return True + self.slide_ended = False + self.slide_ended_reverse = False past_end = False is_paused = self.control.isPaused() + print('going to next effect') self.control.gotoNextEffect() time.sleep(0.1) + # If for some reason the presentation end was not detected above, this will catch it. + # The presentation is set to paused when going past the end. if not is_paused and self.control.isPaused(): self.control.gotoPreviousEffect() past_end = True @@ -425,6 +440,8 @@ class ImpressDocument(PresentationDocument): """ Triggers the previous slide on the running presentation. """ + self.slide_ended = False + self.slide_ended_reverse = False self.control.gotoPreviousEffect() def get_slide_text(self, slide_no): @@ -482,3 +499,96 @@ class ImpressDocument(PresentationDocument): note = ' ' notes.append(note) self.save_titles_and_notes(titles, notes) + + +class SlideShowListener(unohelper.Base, XSlideShowListener): + """ + Listener interface to receive global slide show events. + """ + + def __init__(self, document): + """ + + :param control: SlideShowController + """ + self.document = document + + def paused(self): + """ + Notify that the slide show is paused + """ + log.debug('LibreOffice SlideShowListener event: paused') + + def resumed(self): + """ + Notify that the slide show is resumed from a paused state + """ + log.debug('LibreOffice SlideShowListener event: resumed') + + def slideTransitionStarted(self): + """ + Notify that a new slide starts to become visible. + """ + log.debug('LibreOffice SlideShowListener event: slideTransitionStarted') + + def slideTransitionEnded(self): + """ + Notify that the slide transtion of the current slide ended. + """ + log.debug('LibreOffice SlideShowListener event: slideTransitionEnded') + + def slideAnimationsEnded(self): + """ + Notify that the last animation from the main sequence of the current slide has ended. + """ + log.debug('LibreOffice SlideShowListener event: slideAnimationsEnded') + #if not Registry().get('main_window').isActiveWindow(): + # log.debug('main window is not in focus - should update slidecontroller') + # Registry().execute('slidecontroller_live_change', self.document.control.getCurrentSlideIndex() + 1) + + def slideEnded(self, reverse): + """ + Notify that the current slide has ended, e.g. the user has clicked on the slide. Calling displaySlide() + twice will not issue this event. + """ + print('LibreOffice SlideShowListener event: slideEnded %d' % reverse) + if reverse: + self.document.slide_ended = False + self.document.slide_ended_reverse = True + else: + self.document.slide_ended = True + self.document.slide_ended_reverse = False + + def hyperLinkClicked(self, hyperLink): + """ + Notifies that a hyperlink has been clicked. + """ + log.debug('LibreOffice SlideShowListener event: hyperLinkClicked %s' % hyperLink) + + def disposing(self, source): + """ + gets called when the broadcaster is about to be disposed. + :param source: + """ + log.debug('LibreOffice SlideShowListener event: disposing') + + def beginEvent(self, node): + """ + This event is raised when the element local timeline begins to play. + :param node: + """ + log.debug('LibreOffice SlideShowListener event: beginEvent') + + def endEvent(self, node): + """ + This event is raised at the active end of the element. + :param node: + """ + log.debug('LibreOffice SlideShowListener event: endEvent') + + def repeat(self, node): + """ + This event is raised when the element local timeline repeats. + :param node: + """ + log.debug('LibreOffice SlideShowListener event: repeat') diff --git a/openlp/plugins/presentations/lib/messagelistener.py b/openlp/plugins/presentations/lib/messagelistener.py index fe00c65e0..ef4a0bdc0 100644 --- a/openlp/plugins/presentations/lib/messagelistener.py +++ b/openlp/plugins/presentations/lib/messagelistener.py @@ -191,7 +191,7 @@ class Controller(object): """ Based on the handler passed at startup triggers the previous slide event. """ - log.debug('Live = {live}, previous'.formta(live=self.is_live)) + log.debug('Live = {live}, previous'.format(live=self.is_live)) if not self.doc: return if not self.is_live: From 9cac014cefc69a495b94ee5f3813b3633a51f5cf Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 10 Oct 2017 22:12:56 +0200 Subject: [PATCH 03/27] Improving past-end. --- openlp/plugins/presentations/lib/impresscontroller.py | 4 +--- openlp/plugins/presentations/lib/messagelistener.py | 5 ----- openlp/plugins/presentations/lib/powerpointcontroller.py | 5 +++++ 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index cb1d7ec0e..64561fbec 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -421,13 +421,11 @@ class ImpressDocument(PresentationDocument): """ # if we are at the presentations end don't go further, just return True if self.slide_ended and self.get_slide_count() == self.get_slide_number(): - print('detected presentation end!') return True self.slide_ended = False self.slide_ended_reverse = False past_end = False is_paused = self.control.isPaused() - print('going to next effect') self.control.gotoNextEffect() time.sleep(0.1) # If for some reason the presentation end was not detected above, this will catch it. @@ -552,7 +550,7 @@ class SlideShowListener(unohelper.Base, XSlideShowListener): Notify that the current slide has ended, e.g. the user has clicked on the slide. Calling displaySlide() twice will not issue this event. """ - print('LibreOffice SlideShowListener event: slideEnded %d' % reverse) + log.debug('LibreOffice SlideShowListener event: slideEnded %d' % reverse) if reverse: self.document.slide_ended = False self.document.slide_ended_reverse = True diff --git a/openlp/plugins/presentations/lib/messagelistener.py b/openlp/plugins/presentations/lib/messagelistener.py index 53674f84b..bb09b5592 100644 --- a/openlp/plugins/presentations/lib/messagelistener.py +++ b/openlp/plugins/presentations/lib/messagelistener.py @@ -180,10 +180,6 @@ class Controller(object): return False if not self.activate(): return False - # The "End of slideshow" screen is after the last slide. Note, we can't just stop on the last slide, since it - # may contain animations that need to be stepped through. - if self.doc.slidenumber > self.doc.get_slide_count(): - return True ret = self.doc.next_step() self.poll() return ret @@ -424,7 +420,6 @@ class MessageListener(object): is_live = message[1] if is_live: ret = self.live_handler.next() - self.live_handler.next() if Settings().value('core/click live slide to unblank'): Registry().execute('slidecontroller_live_unblank') return ret diff --git a/openlp/plugins/presentations/lib/powerpointcontroller.py b/openlp/plugins/presentations/lib/powerpointcontroller.py index b01c90700..fb3d8b2cb 100644 --- a/openlp/plugins/presentations/lib/powerpointcontroller.py +++ b/openlp/plugins/presentations/lib/powerpointcontroller.py @@ -427,6 +427,10 @@ class PowerpointDocument(PresentationDocument): Triggers the next effect of slide on the running presentation. """ log.debug('next_step') + # if we are at the presentations end don't go further, just return True + if self.presentation.SlideShowWindow.View.GetClickCount() == self.presentation.SlideShowWindow.View.GetClickIndex()\ + and self.get_slide_number() == self.get_slide_count(): + return True past_end = False try: self.presentation.SlideShowWindow.Activate() @@ -436,6 +440,7 @@ class PowerpointDocument(PresentationDocument): trace_error_handler(log) self.show_error_msg() return past_end + # If for some reason the presentation end was not detected above, this will catch it. if self.get_slide_number() > self.get_slide_count(): log.debug('past end, stepping back to previous') self.previous_step() From b819e79a7052ae1f5d3d4244a587fa3aa4ad5d00 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sun, 4 Feb 2018 21:47:24 +0100 Subject: [PATCH 04/27] Added extra error check --- openlp/plugins/presentations/lib/impresscontroller.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index ee54d6337..2c78b2b28 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -242,6 +242,9 @@ class ImpressDocument(PresentationDocument): except: log.warning('Failed to load presentation {url}'.format(url=url)) return False + if self.document is None: + log.warning('Presentation {url} could not be loaded'.format(url=url)) + return False self.presentation = self.document.getPresentation() self.presentation.Display = ScreenList().current['number'] + 1 self.control = None From aa982492e45ab72da279e43fb7589e319968fcae Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 15 Feb 2019 20:33:43 +0100 Subject: [PATCH 05/27] Implement going to the previous serviceitem. --- openlp/core/ui/slidecontroller.py | 17 +++++++++++++---- .../presentations/lib/impresscontroller.py | 19 ++++++++++++++++++- .../presentations/lib/messagelistener.py | 9 ++++++--- .../presentations/lib/powerpointcontroller.py | 4 ++++ .../lib/presentationcontroller.py | 6 ++++-- 5 files changed, 45 insertions(+), 10 deletions(-) diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 79a34b33e..2f3ebb6d8 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -1174,7 +1174,8 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties): if not self.service_item: return if self.service_item.is_command(): - past_end = Registry().execute('%s_next' % self.service_item.name.lower(), [self.service_item, self.is_live]) + past_end = Registry().execute('{text}_next'.format(text=self.service_item.name.lower()), + [self.service_item, self.is_live]) # Check if we have gone past the end of the last slide if self.is_live and past_end and past_end[0]: if wrap is None: @@ -1211,9 +1212,17 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties): if not self.service_item: return if self.service_item.is_command(): - Registry().execute('{text}_previous'.format(text=self.service_item.name.lower()), - [self.service_item, self.is_live]) - if self.is_live: + before_start = Registry().execute('{text}_previous'.format(text=self.service_item.name.lower()), + [self.service_item, self.is_live]) + # Check id we have tried to go before that start slide + if self.is_live and before_start and before_start[0]: + print('detected before start!') + if self.slide_limits == SlideLimits.Wrap: + self.on_slide_selected_index([self.preview_widget.slide_count() - 1]) + elif self.is_live and self.slide_limits == SlideLimits.Next: + self.keypress_queue.append(ServiceItemAction.PreviousLastSlide) + self._process_queue() + elif self.is_live: self.update_preview() else: row = self.preview_widget.current_slide_number() - 1 diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index dac8122d8..b868023c4 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -46,6 +46,18 @@ from openlp.plugins.presentations.lib.presentationcontroller import Presentation if is_win(): from win32com.client import Dispatch import pywintypes + uno_available = False + try: + service_manager = Dispatch('com.sun.star.ServiceManager') + service_manager._FlagAsMethod('Bridge_GetStruct') + XSlideShowListenerObj = service_manager.Bridge_GetStruct('com.sun.star.presentation.XSlideShowListener') + + class SlideShowListenerImport(XSlideShowListenerObj.__class__): + pass + except (AttributeError, pywintypes.com_error): + class SlideShowListenerImport(object): + pass + # Declare an empty exception to match the exception imported from UNO class ErrorCodeIOException(Exception): @@ -58,6 +70,9 @@ else: from com.sun.star.task import ErrorCodeIOException from com.sun.star.presentation import XSlideShowListener + class SlideShowListenerImport(unohelper.Base, XSlideShowListener): + pass + uno_available = True except ImportError: uno_available = False @@ -504,8 +519,10 @@ class ImpressDocument(PresentationDocument): notes.append(note) self.save_titles_and_notes(titles, notes) + if is_win(): + property_object = self.controller.manager.Bridge_GetStruct('com.sun.star.beans.PropertyValue') -class SlideShowListener(unohelper.Base, XSlideShowListener): +class SlideShowListener(SlideShowListenerImport): """ Listener interface to receive global slide show events. """ diff --git a/openlp/plugins/presentations/lib/messagelistener.py b/openlp/plugins/presentations/lib/messagelistener.py index c816142af..358eeea76 100644 --- a/openlp/plugins/presentations/lib/messagelistener.py +++ b/openlp/plugins/presentations/lib/messagelistener.py @@ -203,8 +203,10 @@ class Controller(object): return if not self.activate(): return - self.doc.previous_step() + ret = self.doc.previous_step() self.poll() + print('previous returning: %d' % ret) + return ret def shutdown(self): """ @@ -435,11 +437,12 @@ class MessageListener(object): """ is_live = message[1] if is_live: - self.live_handler.previous() + ret = self.live_handler.previous() if Settings().value('core/click live slide to unblank'): Registry().execute('slidecontroller_live_unblank') + return ret else: - self.preview_handler.previous() + return self.preview_handler.previous() def shutdown(self, message): """ diff --git a/openlp/plugins/presentations/lib/powerpointcontroller.py b/openlp/plugins/presentations/lib/powerpointcontroller.py index a3a0360b8..034991b33 100644 --- a/openlp/plugins/presentations/lib/powerpointcontroller.py +++ b/openlp/plugins/presentations/lib/powerpointcontroller.py @@ -468,12 +468,16 @@ class PowerpointDocument(PresentationDocument): Triggers the previous slide on the running presentation. """ log.debug('previous_step') + # if we are at the presentations start we can't go further back, just return True + if self.presentation.SlideShowWindow.View.GetClickIndex() == 0 and self.get_slide_number() == 1: + return True try: self.presentation.SlideShowWindow.View.Previous() except (AttributeError, pywintypes.com_error): log.exception('Caught exception while in previous_step') trace_error_handler(log) self.show_error_msg() + return False def get_slide_text(self, slide_no): """ diff --git a/openlp/plugins/presentations/lib/presentationcontroller.py b/openlp/plugins/presentations/lib/presentationcontroller.py index 196813631..a52c1c2e7 100644 --- a/openlp/plugins/presentations/lib/presentationcontroller.py +++ b/openlp/plugins/presentations/lib/presentationcontroller.py @@ -246,15 +246,17 @@ class PresentationDocument(object): def next_step(self): """ Triggers the next effect of slide on the running presentation. This might be the next animation on the current - slide, or the next slide + slide, or the next slide. + Returns True if we stepped beyond the slides of the presentation """ return False def previous_step(self): """ Triggers the previous slide on the running presentation + Returns True if we stepped beyond the slides of the presentation """ - pass + return False def convert_thumbnail(self, image_path, index): """ From 4e739a3ed9b5c409cbc2790b874319bc68ff1988 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Wed, 27 Mar 2019 21:29:19 +0100 Subject: [PATCH 06/27] Disable the presentation console --- openlp/plugins/presentations/lib/powerpointcontroller.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openlp/plugins/presentations/lib/powerpointcontroller.py b/openlp/plugins/presentations/lib/powerpointcontroller.py index 034991b33..6d610c2b9 100644 --- a/openlp/plugins/presentations/lib/powerpointcontroller.py +++ b/openlp/plugins/presentations/lib/powerpointcontroller.py @@ -318,6 +318,9 @@ class PowerpointDocument(PresentationDocument): size = ScreenList().current.display_geometry ppt_window = None try: + # Disable the presentation console + self.presentation.SlideShowSettings.ShowPresenterView = 0 + # Start the presentation ppt_window = self.presentation.SlideShowSettings.Run() except (AttributeError, pywintypes.com_error): log.exception('Caught exception while in start_presentation') From 52bdb8db02a3641fb4af5b537d9b4e0e2df89ad1 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 2 Apr 2019 22:22:05 +0200 Subject: [PATCH 07/27] Added support for disabling Impress Presentation Screen. Fixes bug 1798651 Fixes: https://launchpad.net/bugs/1798651 --- .../presentations/lib/impresscontroller.py | 80 ++++++++++++++----- 1 file changed, 58 insertions(+), 22 deletions(-) diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index c1ea3d407..458643bcb 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -36,7 +36,7 @@ import time from PyQt5 import QtCore -from openlp.core.common import delete_file, get_uno_command, get_uno_instance, is_win +from openlp.core.common import delete_file, get_uno_command, get_uno_instance, is_win, trace_error_handler from openlp.core.common.registry import Registry from openlp.core.display.screens import ScreenList from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument, \ @@ -55,7 +55,7 @@ if is_win(): class SlideShowListenerImport(XSlideShowListenerObj.__class__): pass except (AttributeError, pywintypes.com_error): - class SlideShowListenerImport(object): + class SlideShowListenerImport(): pass # Declare an empty exception to match the exception imported from UNO @@ -97,6 +97,8 @@ class ImpressController(PresentationController): self.process = None self.desktop = None self.manager = None + self.conf_provider = None + self.presenter_screen_disabled_by_openlp = False def check_available(self): """ @@ -105,8 +107,7 @@ class ImpressController(PresentationController): log.debug('check_available') if is_win(): return self.get_com_servicemanager() is not None - else: - return uno_available + return uno_available def start_process(self): """ @@ -146,6 +147,7 @@ class ImpressController(PresentationController): self.manager = uno_instance.ServiceManager log.debug('get UNO Desktop Openoffice - createInstanceWithContext - Desktop') desktop = self.manager.createInstanceWithContext("com.sun.star.frame.Desktop", uno_instance) + self.toggle_presentation_screen(False) return desktop except Exception: log.warning('Failed to get UNO desktop') @@ -163,6 +165,7 @@ class ImpressController(PresentationController): desktop = self.manager.createInstance('com.sun.star.frame.Desktop') except (AttributeError, pywintypes.com_error): log.warning('Failure to find desktop - Impress may have closed') + self.toggle_presentation_screen(False) return desktop if desktop else None def get_com_servicemanager(self): @@ -181,6 +184,8 @@ class ImpressController(PresentationController): Called at system exit to clean up any running presentations. """ log.debug('Kill OpenOffice') + if self.presenter_screen_disabled_by_openlp: + self._toggle_presentation_screen(True) while self.docs: self.docs[0].close_presentation() desktop = None @@ -210,6 +215,51 @@ class ImpressController(PresentationController): except Exception: log.warning('Failed to terminate OpenOffice') + def toggle_presentation_screen(self, target_value): + """ + Enable or disable the Presentation Screen/Console + """ + # Create Instance of ConfigurationProvider + if not self.conf_provider: + if is_win(): + self.conf_provider = self.manager.createInstance("com.sun.star.configuration.ConfigurationProvider") + else: + self.conf_provider = self.manager.createInstanceWithContext("com.sun.star.configuration.ConfigurationProvider", uno.getComponentContext()) + # Setup lookup properties to get Impress settings + properties = [] + properties.append(self.create_property('nodepath', 'org.openoffice.Office.Impress')) + properties = tuple(properties) + try: + # Get an updateable configuration view + impress_conf_props = self.conf_provider.createInstanceWithArguments('com.sun.star.configuration.ConfigurationUpdateAccess', properties) + # Get the specific setting for presentation screen + presenter_screen_enabled = impress_conf_props.getHierarchicalPropertyValue('Misc/Start/EnablePresenterScreen') + # If the presentation screen is enabled we disable it + if presenter_screen_enabled != target_value: + impress_conf_props.setHierarchicalPropertyValue('Misc/Start/EnablePresenterScreen', target_value) + impress_conf_props.commitChanges() + # if target_value is False this is an attempt to disable the Presenter Screen + # so we make a note that it has been disabled, so it can be enabled again on close. + if target_value == False: + self.presenter_screen_disabled_by_openlp = True + except Exception as e: + log.exception(e) + trace_error_handler(log) + return + + def create_property(self, name, value): + """ + Create an OOo style property object which are passed into some Uno methods. + """ + log.debug('create property OpenOffice') + if is_win(): + property_object = self.manager.Bridge_GetStruct('com.sun.star.beans.PropertyValue') + else: + property_object = PropertyValue() + property_object.Name = name + property_object.Value = value + return property_object + class ImpressDocument(PresentationDocument): """ @@ -250,7 +300,7 @@ class ImpressDocument(PresentationDocument): return False self.desktop = desktop properties = [] - properties.append(self.create_property('Hidden', True)) + properties.append(self.controller.create_property('Hidden', True)) properties = tuple(properties) try: self.document = desktop.loadComponentFromURL(url, '_blank', 0, properties) @@ -277,7 +327,7 @@ class ImpressDocument(PresentationDocument): temp_folder_path = self.get_temp_folder() thumb_dir_url = temp_folder_path.as_uri() properties = [] - properties.append(self.create_property('FilterName', 'impress_png_Export')) + properties.append(self.controller.create_property('FilterName', 'impress_png_Export')) properties = tuple(properties) doc = self.document pages = doc.getDrawPages() @@ -299,19 +349,6 @@ class ImpressDocument(PresentationDocument): except Exception: log.exception('{path} - Unable to store openoffice preview'.format(path=path)) - def create_property(self, name, value): - """ - Create an OOo style property object which are passed into some Uno methods. - """ - log.debug('create property OpenOffice') - if is_win(): - property_object = self.controller.manager.Bridge_GetStruct('com.sun.star.beans.PropertyValue') - else: - property_object = PropertyValue() - property_object.Name = name - property_object.Value = value - return property_object - def close_presentation(self): """ Close presentation and clean up objects. Triggered by new object being added to SlideController or OpenLP being @@ -376,8 +413,7 @@ class ImpressDocument(PresentationDocument): log.debug('is blank OpenOffice') if self.control and self.control.isRunning(): return self.control.isPaused() - else: - return False + return False def stop_presentation(self): """ @@ -513,7 +549,7 @@ class ImpressDocument(PresentationDocument): titles.append(self.__get_text_from_page(slide_no, TextType.Title).replace('\r\n', ' ') .replace('\n', ' ').strip()) note = self.__get_text_from_page(slide_no, TextType.Notes) - if len(note) == 0: + if not note: note = ' ' notes.append(note) self.save_titles_and_notes(titles, notes) From 685e46f6239e4f87df1bd4ac353dd98c741a0352 Mon Sep 17 00:00:00 2001 From: Bastian Germann Date: Wed, 15 May 2019 22:46:10 +0200 Subject: [PATCH 08/27] Synchronize setup.py with check_dependencies --- scripts/check_dependencies.py | 1 + setup.py | 1 + 2 files changed, 2 insertions(+) diff --git a/scripts/check_dependencies.py b/scripts/check_dependencies.py index 2fbddd69f..5b66c5ab9 100755 --- a/scripts/check_dependencies.py +++ b/scripts/check_dependencies.py @@ -100,6 +100,7 @@ OPTIONAL_MODULES = [ ('pyodbc', '(ODBC support)'), ('psycopg2', '(PostgreSQL support)'), ('enchant', '(spell checker)'), + ('fitz', '(executable-independent PDF support)'), ('pysword', '(import SWORD bibles)'), ('uno', '(LibreOffice/OpenOffice support)'), # development/testing modules diff --git a/setup.py b/setup.py index 90cef4885..3c408bb64 100644 --- a/setup.py +++ b/setup.py @@ -178,6 +178,7 @@ using a computer and a data projector.""", 'pyobjc-framework-Cocoa; platform_system=="Darwin"', 'PyQt5 >= 5.12', 'PyQtWebEngine', + 'python-vlc', 'pywin32; platform_system=="Windows"', 'QtAwesome', 'requests', From df538b1d70356b3943a7f0459b70cead0f58d346 Mon Sep 17 00:00:00 2001 From: Bastian Germann Date: Thu, 16 May 2019 00:36:16 +0200 Subject: [PATCH 09/27] Remove nose2 references --- nose2.cfg | 27 --------------------------- scripts/check_dependencies.py | 1 - setup.py | 3 +-- 3 files changed, 1 insertion(+), 30 deletions(-) delete mode 100644 nose2.cfg diff --git a/nose2.cfg b/nose2.cfg deleted file mode 100644 index 451737d6c..000000000 --- a/nose2.cfg +++ /dev/null @@ -1,27 +0,0 @@ -[unittest] -verbose = true -plugins = nose2.plugins.mp - -[log-capture] -always-on = true -clear-handlers = true -filter = -nose -log-level = ERROR - -[test-result] -always-on = true -descriptions = true - -[coverage] -always-on = true -coverage = openlp -coverage-report = html - -[multiprocess] -always-on = false -processes = 4 - -[output-buffer] -always-on = true -stderr = true -stdout = true diff --git a/scripts/check_dependencies.py b/scripts/check_dependencies.py index 5b66c5ab9..a49149f40 100755 --- a/scripts/check_dependencies.py +++ b/scripts/check_dependencies.py @@ -106,7 +106,6 @@ OPTIONAL_MODULES = [ # development/testing modules ('jenkins', '(access jenkins api)'), ('launchpadlib', '(launchpad script support)'), - ('nose2', '(testing framework)'), ('pylint', '(linter)') ] diff --git a/setup.py b/setup.py index 3c408bb64..dcf430d4c 100644 --- a/setup.py +++ b/setup.py @@ -200,13 +200,12 @@ using a computer and a data projector.""", 'launchpad': ['launchpadlib'] }, tests_require=[ - 'nose2', 'pylint', 'PyMuPDF', 'pyodbc', 'pysword', 'python-xlib; platform_system=="Linux"' ], - test_suite='nose2.collector.collector', + test_suite='tests', entry_points={'gui_scripts': ['openlp = run_openlp:start']} ) From 89ecdf2a965ec29a3cce5729465cfae9b9c27cc8 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 20 May 2019 22:35:48 +0200 Subject: [PATCH 10/27] try to make impress support going before start --- openlp/plugins/presentations/lib/impresscontroller.py | 4 ++++ openlp/plugins/presentations/lib/messagelistener.py | 10 +++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index 03a69493d..081a06478 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -493,9 +493,13 @@ class ImpressDocument(PresentationDocument): """ Triggers the previous slide on the running presentation. """ + # if we are at the presentations start don't go further back, just return True + if self.slide_ended_reverse and self.get_slide_number() == 1: + return True self.slide_ended = False self.slide_ended_reverse = False self.control.gotoPreviousEffect() + return False def get_slide_text(self, slide_no): """ diff --git a/openlp/plugins/presentations/lib/messagelistener.py b/openlp/plugins/presentations/lib/messagelistener.py index 82f7559e5..0cea6949b 100644 --- a/openlp/plugins/presentations/lib/messagelistener.py +++ b/openlp/plugins/presentations/lib/messagelistener.py @@ -191,18 +191,18 @@ class Controller(object): """ log.debug('Live = {live}, previous'.format(live=self.is_live)) if not self.doc: - return + return False if not self.is_live: - return + return False if self.hide_mode: if not self.doc.is_active(): - return + return False if self.doc.slidenumber > 1: self.doc.slidenumber -= 1 self.poll() - return + return False if not self.activate(): - return + return False ret = self.doc.previous_step() self.poll() print('previous returning: %d' % ret) From 3d8d573389af510d17f67202edb008ef71836edf Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 21 May 2019 22:07:25 +0200 Subject: [PATCH 11/27] Always make sure the powerpoint slide index map is created --- openlp/core/ui/servicemanager.py | 6 ++++++ openlp/plugins/presentations/lib/powerpointcontroller.py | 9 ++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index b18f2f9d8..18b5b6f04 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -975,8 +975,10 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi prev_item_last_slide = None service_iterator = QtWidgets.QTreeWidgetItemIterator(self.service_manager_list) while service_iterator.value(): + # Found the selected/current service item if service_iterator.value() == selected: if last_slide and prev_item_last_slide: + # Go to the last slide of the previous service item pos = prev_item.data(0, QtCore.Qt.UserRole) check_expanded = self.service_items[pos - 1]['expanded'] self.service_manager_list.setCurrentItem(prev_item_last_slide) @@ -985,13 +987,17 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi self.make_live() self.service_manager_list.setCurrentItem(prev_item) elif prev_item: + # Go to the first slide of the previous service item self.service_manager_list.setCurrentItem(prev_item) self.make_live() return + # Found the previous service item root if service_iterator.value().parent() is None: prev_item = service_iterator.value() + # Found the last slide of the previous item if service_iterator.value().parent() is prev_item: prev_item_last_slide = service_iterator.value() + # Go to next item in the tree service_iterator += 1 def on_set_item(self, message): diff --git a/openlp/plugins/presentations/lib/powerpointcontroller.py b/openlp/plugins/presentations/lib/powerpointcontroller.py index 7645a277a..fd5772e88 100644 --- a/openlp/plugins/presentations/lib/powerpointcontroller.py +++ b/openlp/plugins/presentations/lib/powerpointcontroller.py @@ -170,14 +170,17 @@ class PowerpointDocument(PresentationDocument): However, for the moment, we want a physical file since it makes life easier elsewhere. """ log.debug('create_thumbnails') + generate_thumbs = True if self.check_thumbnails(): - return + # No need for thumbnails but we still need the index + generate_thumbs = False key = 1 for num in range(self.presentation.Slides.Count): if not self.presentation.Slides(num + 1).SlideShowTransition.Hidden: self.index_map[key] = num + 1 - self.presentation.Slides(num + 1).Export( - str(self.get_thumbnail_folder() / 'slide{key:d}.png'.format(key=key)), 'png', 320, 240) + if generate_thumbs: + self.presentation.Slides(num + 1).Export( + str(self.get_thumbnail_folder() / 'slide{key:d}.png'.format(key=key)), 'png', 320, 240) key += 1 self.slide_count = key - 1 From a3fdaff2c4c622197f27d622971784d812f8af27 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Thu, 23 May 2019 21:41:00 +0200 Subject: [PATCH 12/27] Fix test and remove debug prints --- openlp/core/ui/slidecontroller.py | 1 - openlp/plugins/presentations/lib/impresscontroller.py | 2 +- openlp/plugins/presentations/lib/messagelistener.py | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 5caf33b7a..2d419d6f2 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -1303,7 +1303,6 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties): [self.service_item, self.is_live]) # Check id we have tried to go before that start slide if self.is_live and before_start and before_start[0]: - print('detected before start!') if self.slide_limits == SlideLimits.Wrap: self.on_slide_selected_index([self.preview_widget.slide_count() - 1]) elif self.is_live and self.slide_limits == SlideLimits.Next: diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index 081a06478..0f773b98a 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -553,7 +553,7 @@ class ImpressDocument(PresentationDocument): titles.append(self.__get_text_from_page(slide_no, TextType.Title).replace('\r\n', ' ') .replace('\n', ' ').strip()) note = self.__get_text_from_page(slide_no, TextType.Notes) - if not note: + if len(note) == 0: note = ' ' notes.append(note) self.save_titles_and_notes(titles, notes) diff --git a/openlp/plugins/presentations/lib/messagelistener.py b/openlp/plugins/presentations/lib/messagelistener.py index 0cea6949b..9237f6a40 100644 --- a/openlp/plugins/presentations/lib/messagelistener.py +++ b/openlp/plugins/presentations/lib/messagelistener.py @@ -205,7 +205,6 @@ class Controller(object): return False ret = self.doc.previous_step() self.poll() - print('previous returning: %d' % ret) return ret def shutdown(self): From e6baed110561468c2e135dcf7760ff66fa8cf32b Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Thu, 23 May 2019 22:30:46 +0200 Subject: [PATCH 13/27] pep8 fixes --- openlp/core/ui/servicemanager.py | 2 +- .../presentations/lib/impresscontroller.py | 19 ++++++++++++------- .../presentations/lib/powerpointcontroller.py | 3 ++- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 18b5b6f04..33dd5c845 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -987,7 +987,7 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi self.make_live() self.service_manager_list.setCurrentItem(prev_item) elif prev_item: - # Go to the first slide of the previous service item + # Go to the first slide of the previous service item self.service_manager_list.setCurrentItem(prev_item) self.make_live() return diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index 0f773b98a..fb5254a05 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -222,25 +222,28 @@ class ImpressController(PresentationController): # Create Instance of ConfigurationProvider if not self.conf_provider: if is_win(): - self.conf_provider = self.manager.createInstance("com.sun.star.configuration.ConfigurationProvider") + self.conf_provider = self.manager.createInstance('com.sun.star.configuration.ConfigurationProvider') else: - self.conf_provider = self.manager.createInstanceWithContext("com.sun.star.configuration.ConfigurationProvider", uno.getComponentContext()) + self.conf_provider = self.manager.createInstanceWithContext( + 'com.sun.star.configuration.ConfigurationProvider', uno.getComponentContext()) # Setup lookup properties to get Impress settings properties = [] properties.append(self.create_property('nodepath', 'org.openoffice.Office.Impress')) properties = tuple(properties) try: # Get an updateable configuration view - impress_conf_props = self.conf_provider.createInstanceWithArguments('com.sun.star.configuration.ConfigurationUpdateAccess', properties) + impress_conf_props = self.conf_provider.createInstanceWithArguments( + 'com.sun.star.configuration.ConfigurationUpdateAccess', properties) # Get the specific setting for presentation screen - presenter_screen_enabled = impress_conf_props.getHierarchicalPropertyValue('Misc/Start/EnablePresenterScreen') + presenter_screen_enabled = impress_conf_props.getHierarchicalPropertyValue( + 'Misc/Start/EnablePresenterScreen') # If the presentation screen is enabled we disable it if presenter_screen_enabled != target_value: impress_conf_props.setHierarchicalPropertyValue('Misc/Start/EnablePresenterScreen', target_value) impress_conf_props.commitChanges() # if target_value is False this is an attempt to disable the Presenter Screen # so we make a note that it has been disabled, so it can be enabled again on close. - if target_value == False: + if target_value is False: self.presenter_screen_disabled_by_openlp = True except Exception as e: log.exception(e) @@ -561,6 +564,7 @@ class ImpressDocument(PresentationDocument): if is_win(): property_object = self.controller.manager.Bridge_GetStruct('com.sun.star.beans.PropertyValue') + class SlideShowListener(SlideShowListenerImport): """ Listener interface to receive global slide show events. @@ -568,8 +572,9 @@ class SlideShowListener(SlideShowListenerImport): def __init__(self, document): """ + Constructor - :param control: SlideShowController + :param document: The ImpressDocument being presented """ self.document = document @@ -602,7 +607,7 @@ class SlideShowListener(SlideShowListenerImport): Notify that the last animation from the main sequence of the current slide has ended. """ log.debug('LibreOffice SlideShowListener event: slideAnimationsEnded') - #if not Registry().get('main_window').isActiveWindow(): + # if not Registry().get('main_window').isActiveWindow(): # log.debug('main window is not in focus - should update slidecontroller') # Registry().execute('slidecontroller_live_change', self.document.control.getCurrentSlideIndex() + 1) diff --git a/openlp/plugins/presentations/lib/powerpointcontroller.py b/openlp/plugins/presentations/lib/powerpointcontroller.py index fd5772e88..a01470855 100644 --- a/openlp/plugins/presentations/lib/powerpointcontroller.py +++ b/openlp/plugins/presentations/lib/powerpointcontroller.py @@ -444,7 +444,8 @@ class PowerpointDocument(PresentationDocument): """ log.debug('next_step') # if we are at the presentations end don't go further, just return True - if self.presentation.SlideShowWindow.View.GetClickCount() == self.presentation.SlideShowWindow.View.GetClickIndex()\ + if self.presentation.SlideShowWindow.View.GetClickCount() == \ + self.presentation.SlideShowWindow.View.GetClickIndex() \ and self.get_slide_number() == self.get_slide_count(): return True past_end = False From 6e03382f1ff02ac8da3d3ed3b131e0008da75b8d Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 24 May 2019 21:21:19 +0200 Subject: [PATCH 14/27] Reenable setting slidecontroller index when openlp is not in focus. --- openlp/plugins/presentations/lib/impresscontroller.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index fb5254a05..426e8f2fc 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -607,9 +607,9 @@ class SlideShowListener(SlideShowListenerImport): Notify that the last animation from the main sequence of the current slide has ended. """ log.debug('LibreOffice SlideShowListener event: slideAnimationsEnded') - # if not Registry().get('main_window').isActiveWindow(): - # log.debug('main window is not in focus - should update slidecontroller') - # Registry().execute('slidecontroller_live_change', self.document.control.getCurrentSlideIndex() + 1) + if not Registry().get('main_window').isActiveWindow(): + log.debug('main window is not in focus - should update slidecontroller') + Registry().execute('slidecontroller_live_change', self.document.control.getCurrentSlideIndex() + 1) def slideEnded(self, reverse): """ From c901ec3d75ed82c12870ff300860c058fcabf5e0 Mon Sep 17 00:00:00 2001 From: Phill Date: Fri, 24 May 2019 23:11:11 +0100 Subject: [PATCH 15/27] Move suffixes from list to set, remove VlcPlayer.is_active as it was never ser --- openlp/core/lib/serviceitem.py | 8 +++++--- openlp/core/ui/media/mediacontroller.py | 18 ++++++++---------- openlp/core/ui/media/mediaplayer.py | 1 - openlp/core/ui/servicemanager.py | 16 ++++++++-------- .../ui/media/test_mediacontroller.py | 1 - 5 files changed, 21 insertions(+), 23 deletions(-) diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index f284f59bb..3366cd858 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -593,9 +593,11 @@ class ServiceItem(RegistryProperties): """ return not bool(self.slides) - def validate_item(self, suffix_list=None): + def validate_item(self, suffixes=None): """ Validates a service item to make sure it is valid + + :param set[str] suffixes: A set of vaild suffixes """ self.is_valid = True for slide in self.slides: @@ -612,8 +614,8 @@ class ServiceItem(RegistryProperties): if not os.path.exists(file_name): self.is_valid = False break - if suffix_list and not self.is_text(): + if suffixes and not self.is_text(): file_suffix = slide['title'].split('.')[-1] - if file_suffix.lower() not in suffix_list: + if file_suffix.lower() not in suffixes: self.is_valid = False break diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index 69fee7189..4cb2a8e79 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -104,17 +104,15 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): """ suffix_list = [] self.audio_extensions_list = [] - if self.vlc_player.is_active: - for item in self.vlc_player.audio_extensions_list: - if item not in self.audio_extensions_list: - self.audio_extensions_list.append(item) - suffix_list.append(item[2:]) + for item in self.vlc_player.audio_extensions_list: + if item not in self.audio_extensions_list: + self.audio_extensions_list.append(item) + suffix_list.append(item[2:]) self.video_extensions_list = [] - if self.vlc_player.is_active: - for item in self.vlc_player.video_extensions_list: - if item not in self.video_extensions_list: - self.video_extensions_list.append(item) - suffix_list.append(item[2:]) + for item in self.vlc_player.video_extensions_list: + if item not in self.video_extensions_list: + self.video_extensions_list.append(item) + suffix_list.append(item[2:]) self.service_manager.supported_suffixes(suffix_list) def bootstrap_initialise(self): diff --git a/openlp/core/ui/media/mediaplayer.py b/openlp/core/ui/media/mediaplayer.py index f4bc4a1df..9eb186665 100644 --- a/openlp/core/ui/media/mediaplayer.py +++ b/openlp/core/ui/media/mediaplayer.py @@ -38,7 +38,6 @@ class MediaPlayer(RegistryProperties): self.parent = parent self.name = name self.available = self.check_available() - self.is_active = False self.can_background = False self.can_folder = False self.state = {0: MediaState.Off, 1: MediaState.Off} diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 5e8b3e0cd..9e8b915fb 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -320,7 +320,7 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi """ super().__init__(parent) self.service_items = [] - self.suffixes = [] + self.suffixes = set() self.drop_position = -1 self.service_id = 0 # is a new service and has not been saved @@ -403,20 +403,18 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi Resets the Suffixes list. """ - self.suffixes = [] + self.suffixes.clear() def supported_suffixes(self, suffix_list): """ Adds Suffixes supported to the master list. Called from Plugins. - :param suffix_list: New Suffix's to be supported + :param list[str] | str suffix_list: New suffix(s) to be supported """ if isinstance(suffix_list, str): - self.suffixes.append(suffix_list) + self.suffixes.add(suffix_list) else: - for suffix in suffix_list: - if suffix not in self.suffixes: - self.suffixes.append(suffix) + self.suffixes.update(suffix_list) def on_new_service_clicked(self): """ @@ -475,9 +473,11 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi QtWidgets.QMessageBox.Save | QtWidgets.QMessageBox.Discard | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Save) - def on_recent_service_clicked(self): + def on_recent_service_clicked(self, checked): """ Load a recent file as the service triggered by mainwindow recent service list. + + :param bool checked: Not used """ if self.is_modified(): result = self.save_modified_service() diff --git a/tests/functional/openlp_core/ui/media/test_mediacontroller.py b/tests/functional/openlp_core/ui/media/test_mediacontroller.py index e6209cd37..a1a1122a1 100644 --- a/tests/functional/openlp_core/ui/media/test_mediacontroller.py +++ b/tests/functional/openlp_core/ui/media/test_mediacontroller.py @@ -50,7 +50,6 @@ class TestMediaController(TestCase, TestMixin): # GIVEN: A MediaController and an active player with audio and video extensions media_controller = MediaController() media_controller.vlc_player = VlcPlayer(None) - media_controller.vlc_player.is_active = True media_controller.vlc_player.audio_extensions_list = ['*.mp3', '*.wav', '*.wma', '*.ogg'] media_controller.vlc_player.video_extensions_list = ['*.mp4', '*.mov', '*.avi', '*.ogm'] From 7288336ad4d757f932c1c67d705280de39d4fb6b Mon Sep 17 00:00:00 2001 From: Bastian Germann Date: Sat, 25 May 2019 16:43:43 +0200 Subject: [PATCH 16/27] Replace native test runner with pytest --- setup.cfg | 3 +++ setup.py | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 5b443dcf7..27af3897d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,6 +2,9 @@ # E722 do not use bare except, specify exception instead # F841 local variable '' is assigned to but never used +[aliases] +test=pytest + [pep8] exclude=resources.py,vlc.py max-line-length = 120 diff --git a/setup.py b/setup.py index dcf430d4c..260f0f8be 100644 --- a/setup.py +++ b/setup.py @@ -204,8 +204,9 @@ using a computer and a data projector.""", 'PyMuPDF', 'pyodbc', 'pysword', + 'pytest', 'python-xlib; platform_system=="Linux"' ], - test_suite='tests', + setup_requires=['pytest-runner'], entry_points={'gui_scripts': ['openlp = run_openlp:start']} ) From 9caffa028b21850fb612b49521d31b93e0bb516f Mon Sep 17 00:00:00 2001 From: Bastian Germann Date: Sat, 25 May 2019 16:47:10 +0200 Subject: [PATCH 17/27] Add pytest to check_dependencies --- scripts/check_dependencies.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/check_dependencies.py b/scripts/check_dependencies.py index a49149f40..19325fbb8 100755 --- a/scripts/check_dependencies.py +++ b/scripts/check_dependencies.py @@ -106,6 +106,7 @@ OPTIONAL_MODULES = [ # development/testing modules ('jenkins', '(access jenkins api)'), ('launchpadlib', '(launchpad script support)'), + ('pytest', '(testing framework)'), ('pylint', '(linter)') ] From 38a310a1aa0e27468a4c42157238e1b2d03e09ce Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sat, 25 May 2019 21:21:19 +0200 Subject: [PATCH 18/27] Remove unused code --- openlp/plugins/presentations/lib/impresscontroller.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index 426e8f2fc..9dd1a776a 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -561,9 +561,6 @@ class ImpressDocument(PresentationDocument): notes.append(note) self.save_titles_and_notes(titles, notes) - if is_win(): - property_object = self.controller.manager.Bridge_GetStruct('com.sun.star.beans.PropertyValue') - class SlideShowListener(SlideShowListenerImport): """ From c2550777c3f8f9940e75977c7d268445939898e3 Mon Sep 17 00:00:00 2001 From: Phill Date: Sun, 26 May 2019 11:30:37 +0100 Subject: [PATCH 19/27] VLC extension tidyups --- openlp/core/common/json.py | 1 - openlp/core/lib/mediamanageritem.py | 4 +-- openlp/core/ui/media/mediacontroller.py | 32 +++---------------- openlp/core/ui/media/mediaplayer.py | 2 -- openlp/core/ui/media/vlcplayer.py | 2 -- openlp/core/ui/themeform.py | 1 - openlp/plugins/media/lib/mediaitem.py | 10 +++--- openlp/plugins/songs/lib/openlyricsexport.py | 2 +- .../openlp_core/common/test_path.py | 1 - .../ui/media/test_mediacontroller.py | 19 ----------- .../openlp_core/ui/media/test_vlcplayer.py | 2 -- 11 files changed, 13 insertions(+), 63 deletions(-) diff --git a/openlp/core/common/json.py b/openlp/core/common/json.py index 6f815aefa..4a54e41b3 100644 --- a/openlp/core/common/json.py +++ b/openlp/core/common/json.py @@ -23,7 +23,6 @@ from contextlib import suppress from json import JSONDecoder, JSONEncoder from pathlib import Path - _registered_classes = {} diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index 59cb1cdcf..eee11b970 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -589,7 +589,7 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties): """ Add this item to the current service. - :param item: Item to be processed + :param QtWidgets.QListWidgetItem | QtWidgets.QTreeWidgetItem | None item: Item to be processed :param replace: Replace the existing item :param remote: Triggered from remote :param position: Position to place item @@ -627,7 +627,7 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties): def build_service_item(self, item=None, remote=False, context=ServiceItemContext.Live): """ Common method for generating a service item - :param item: Service Item to be built. + :param QtWidgets.QListWidgetItem | QtWidgets.QTreeWidgetItem | None item: Service Item to be built. :param remote: Remote triggered (False) :param context: The context on which this is called """ diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index 4cb2a8e79..4f4400f81 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -44,7 +44,7 @@ from openlp.core.lib.ui import critical_error_message_box from openlp.core.ui import DisplayControllerType from openlp.core.ui.media import MediaState, ItemMediaInfo, MediaType, parse_optical_path from openlp.core.ui.media.endpoint import media_endpoint -from openlp.core.ui.media.vlcplayer import VlcPlayer, get_vlc +from openlp.core.ui.media.vlcplayer import AUDIO_EXT, VIDEO_EXT, VlcPlayer, get_vlc log = logging.getLogger(__name__) @@ -65,11 +65,6 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): current_media_players is an array of player instances keyed on ControllerType. """ - def __init__(self, parent=None): - """ - Constructor - """ - super(MediaController, self).__init__(parent) def setup(self): self.vlc_player = None @@ -95,26 +90,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): Registry().register_function('songs_hide', self.media_hide) Registry().register_function('songs_blank', self.media_blank) Registry().register_function('songs_unblank', self.media_unblank) - Registry().register_function('mediaitem_suffixes', self._generate_extensions_lists) register_endpoint(media_endpoint) - def _generate_extensions_lists(self): - """ - Set the active players and available media files - """ - suffix_list = [] - self.audio_extensions_list = [] - for item in self.vlc_player.audio_extensions_list: - if item not in self.audio_extensions_list: - self.audio_extensions_list.append(item) - suffix_list.append(item[2:]) - self.video_extensions_list = [] - for item in self.vlc_player.video_extensions_list: - if item not in self.video_extensions_list: - self.video_extensions_list.append(item) - suffix_list.append(item[2:]) - self.service_manager.supported_suffixes(suffix_list) - def bootstrap_initialise(self): """ Check to see if we have any media Player's available. @@ -129,7 +106,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): else: State().missing_text('media_live', translate('OpenLP.SlideController', 'VLC or pymediainfo are missing, so you are unable to play any media')) - self._generate_extensions_lists() + self.service_manager.supported_suffixes(ext[2:] for ext in AUDIO_EXT) + self.service_manager.supported_suffixes(ext[2:] for ext in VIDEO_EXT) return True def bootstrap_post_set_up(self): @@ -379,7 +357,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): if file.is_file: suffix = '*%s' % file.suffix.lower() file = str(file) - if suffix in self.vlc_player.video_extensions_list: + if suffix in VIDEO_EXT: if not controller.media_info.is_background or controller.media_info.is_background and \ self.vlc_player.can_background: self.resize(display, self.vlc_player) @@ -387,7 +365,7 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): self.current_media_players[controller.controller_type] = self.vlc_player controller.media_info.media_type = MediaType.Video return True - if suffix in self.vlc_player.audio_extensions_list: + if suffix in AUDIO_EXT: if self.vlc_player.load(display, file): self.current_media_players[controller.controller_type] = self.vlc_player controller.media_info.media_type = MediaType.Audio diff --git a/openlp/core/ui/media/mediaplayer.py b/openlp/core/ui/media/mediaplayer.py index 9eb186665..3c0b7e873 100644 --- a/openlp/core/ui/media/mediaplayer.py +++ b/openlp/core/ui/media/mediaplayer.py @@ -42,8 +42,6 @@ class MediaPlayer(RegistryProperties): self.can_folder = False self.state = {0: MediaState.Off, 1: MediaState.Off} self.has_own_widget = False - self.audio_extensions_list = [] - self.video_extensions_list = [] def check_available(self): """ diff --git a/openlp/core/ui/media/vlcplayer.py b/openlp/core/ui/media/vlcplayer.py index 6ba27998b..3f7deac75 100644 --- a/openlp/core/ui/media/vlcplayer.py +++ b/openlp/core/ui/media/vlcplayer.py @@ -109,8 +109,6 @@ class VlcPlayer(MediaPlayer): self.display_name = '&VLC' self.parent = parent self.can_folder = True - self.audio_extensions_list = AUDIO_EXT - self.video_extensions_list = VIDEO_EXT def setup(self, output_display, live_display): """ diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index 0dfb53aab..7394409fa 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -32,7 +32,6 @@ from openlp.core.common.mixins import RegistryProperties from openlp.core.common.registry import Registry from openlp.core.lib.theme import BackgroundGradientType, BackgroundType from openlp.core.lib.ui import critical_error_message_box -# TODO: Fix this. Use a "get_video_extensions" method which uses the current media player from openlp.core.ui.media.vlcplayer import VIDEO_EXT from openlp.core.ui.themelayoutform import ThemeLayoutForm from openlp.core.ui.themewizard import Ui_ThemeWizard diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 658773b99..2d66eabe9 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -38,7 +38,7 @@ from openlp.core.lib.serviceitem import ItemCapabilities from openlp.core.lib.ui import critical_error_message_box from openlp.core.ui.icons import UiIcons from openlp.core.ui.media import parse_optical_path, format_milliseconds -from openlp.core.ui.media.vlcplayer import get_vlc +from openlp.core.ui.media.vlcplayer import AUDIO_EXT, VIDEO_EXT, get_vlc if get_vlc() is not None: @@ -233,8 +233,8 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): # self.populate_display_types() self.on_new_file_masks = translate('MediaPlugin.MediaItem', 'Videos ({video});;Audio ({audio});;{files} ' - '(*)').format(video=' '.join(self.media_controller.video_extensions_list), - audio=' '.join(self.media_controller.audio_extensions_list), + '(*)').format(video=' '.join(VIDEO_EXT), + audio=' '.join(AUDIO_EXT), files=UiStrings().AllFiles) def on_delete_click(self): @@ -301,9 +301,9 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): media_file_paths = Settings().value(self.settings_section + '/media files') media_file_paths.sort(key=lambda file_path: get_natural_key(file_path.name)) if media_type == MediaType.Audio: - extension = self.media_controller.audio_extensions_list + extension = AUDIO_EXT else: - extension = self.media_controller.video_extensions_list + extension = VIDEO_EXT # TODO: Rename extension to extensions extension = [x[1:] for x in extension] media = [x for x in media_file_paths if x.suffix in extension] return media diff --git a/openlp/plugins/songs/lib/openlyricsexport.py b/openlp/plugins/songs/lib/openlyricsexport.py index 311bfa711..37a64162f 100644 --- a/openlp/plugins/songs/lib/openlyricsexport.py +++ b/openlp/plugins/songs/lib/openlyricsexport.py @@ -43,7 +43,7 @@ class OpenLyricsExport(RegistryProperties): """ def __init__(self, parent, songs, save_path): """ - Initialise the export. + Initialise the export :param pathlib.Path save_path: The directory to save the exported songs in :rtype: None diff --git a/tests/functional/openlp_core/common/test_path.py b/tests/functional/openlp_core/common/test_path.py index 55b5b70de..5b983bc20 100644 --- a/tests/functional/openlp_core/common/test_path.py +++ b/tests/functional/openlp_core/common/test_path.py @@ -22,7 +22,6 @@ """ Package to test the openlp.core.common.path package. """ -# TODO: fix patches import os from pathlib import Path from unittest import TestCase diff --git a/tests/functional/openlp_core/ui/media/test_mediacontroller.py b/tests/functional/openlp_core/ui/media/test_mediacontroller.py index a1a1122a1..2389d8a34 100644 --- a/tests/functional/openlp_core/ui/media/test_mediacontroller.py +++ b/tests/functional/openlp_core/ui/media/test_mediacontroller.py @@ -43,25 +43,6 @@ class TestMediaController(TestCase, TestMixin): Registry.create() Registry().register('service_manager', MagicMock()) - def test_generate_extensions_lists(self): - """ - Test that the extensions are create correctly - """ - # GIVEN: A MediaController and an active player with audio and video extensions - media_controller = MediaController() - media_controller.vlc_player = VlcPlayer(None) - media_controller.vlc_player.audio_extensions_list = ['*.mp3', '*.wav', '*.wma', '*.ogg'] - media_controller.vlc_player.video_extensions_list = ['*.mp4', '*.mov', '*.avi', '*.ogm'] - - # WHEN: calling _generate_extensions_lists - media_controller._generate_extensions_lists() - - # THEN: extensions list should have been copied from the player to the mediacontroller - assert media_controller.video_extensions_list == media_controller.video_extensions_list, \ - 'Video extensions should be the same' - assert media_controller.audio_extensions_list == media_controller.audio_extensions_list, \ - 'Audio extensions should be the same' - def test_resize(self): """ Test that the resize method is called correctly diff --git a/tests/functional/openlp_core/ui/media/test_vlcplayer.py b/tests/functional/openlp_core/ui/media/test_vlcplayer.py index d3de03758..75828de8d 100644 --- a/tests/functional/openlp_core/ui/media/test_vlcplayer.py +++ b/tests/functional/openlp_core/ui/media/test_vlcplayer.py @@ -95,8 +95,6 @@ class TestVLCPlayer(TestCase, TestMixin): assert '&VLC' == vlc_player.display_name assert vlc_player.parent is None assert vlc_player.can_folder is True - assert AUDIO_EXT == vlc_player.audio_extensions_list - assert VIDEO_EXT == vlc_player.video_extensions_list @patch('openlp.core.ui.media.vlcplayer.is_win') @patch('openlp.core.ui.media.vlcplayer.is_macosx') From cdf29876e25792150b5b11b359128033544ff656 Mon Sep 17 00:00:00 2001 From: Phill Date: Sun, 26 May 2019 21:53:54 +0100 Subject: [PATCH 20/27] More media clean-up --- openlp/core/ui/media/mediacontroller.py | 4 +-- openlp/core/ui/media/mediaplayer.py | 6 ---- openlp/core/ui/media/vlcplayer.py | 33 ++++++------------- openlp/core/ui/themeform.py | 5 ++- .../openlp_core/ui/media/test_vlcplayer.py | 17 ---------- 5 files changed, 14 insertions(+), 51 deletions(-) diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index 4f4400f81..a17e48ea9 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -106,8 +106,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): else: State().missing_text('media_live', translate('OpenLP.SlideController', 'VLC or pymediainfo are missing, so you are unable to play any media')) - self.service_manager.supported_suffixes(ext[2:] for ext in AUDIO_EXT) - self.service_manager.supported_suffixes(ext[2:] for ext in VIDEO_EXT) + self.service_manager.supported_suffixes(AUDIO_EXT) + self.service_manager.supported_suffixes(VIDEO_EXT) return True def bootstrap_post_set_up(self): diff --git a/openlp/core/ui/media/mediaplayer.py b/openlp/core/ui/media/mediaplayer.py index 3c0b7e873..be88ab549 100644 --- a/openlp/core/ui/media/mediaplayer.py +++ b/openlp/core/ui/media/mediaplayer.py @@ -163,12 +163,6 @@ class MediaPlayer(RegistryProperties): """ return '' - def get_info(self): - """ - Returns Information about the player - """ - return '' - def get_live_state(self): """ Get the state of the live player diff --git a/openlp/core/ui/media/vlcplayer.py b/openlp/core/ui/media/vlcplayer.py index 3f7deac75..da4036bda 100644 --- a/openlp/core/ui/media/vlcplayer.py +++ b/openlp/core/ui/media/vlcplayer.py @@ -42,20 +42,18 @@ from openlp.core.ui.media.mediaplayer import MediaPlayer log = logging.getLogger(__name__) # Audio and video extensions copied from 'include/vlc_interface.h' from vlc 2.2.0 source -AUDIO_EXT = ['*.3ga', '*.669', '*.a52', '*.aac', '*.ac3', '*.adt', '*.adts', '*.aif', '*.aifc', '*.aiff', '*.amr', - '*.aob', '*.ape', '*.awb', '*.caf', '*.dts', '*.flac', '*.it', '*.kar', '*.m4a', '*.m4b', '*.m4p', '*.m5p', - '*.mid', '*.mka', '*.mlp', '*.mod', '*.mpa', '*.mp1', '*.mp2', '*.mp3', '*.mpc', '*.mpga', '*.mus', - '*.oga', '*.ogg', '*.oma', '*.opus', '*.qcp', '*.ra', '*.rmi', '*.s3m', '*.sid', '*.spx', '*.thd', '*.tta', - '*.voc', '*.vqf', '*.w64', '*.wav', '*.wma', '*.wv', '*.xa', '*.xm'] +AUDIO_EXT = ('3ga', '669', 'a52', 'aac', 'ac3', 'adt', 'adts', 'aif', 'aifc', 'aiff', 'amr', 'aob', 'ape', 'awb', 'caf', + 'dts', 'flac', 'it', 'kar', 'm4a', 'm4b', 'm4p', 'm5p', 'mid', 'mka', 'mlp', 'mod', 'mpa', 'mp1', 'mp2', + 'mp3', 'mpc', 'mpga', 'mus', 'oga', 'ogg', 'oma', 'opus', 'qcp', 'ra', 'rmi', 's3m', 'sid', 'spx', 'thd', + 'tta', 'voc', 'vqf', 'w64', 'wav', 'wma', 'wv', 'xa', 'xm') -VIDEO_EXT = ['*.3g2', '*.3gp', '*.3gp2', '*.3gpp', '*.amv', '*.asf', '*.avi', '*.bik', '*.divx', '*.drc', '*.dv', - '*.f4v', '*.flv', '*.gvi', '*.gxf', '*.iso', '*.m1v', '*.m2v', '*.m2t', '*.m2ts', '*.m4v', '*.mkv', - '*.mov', '*.mp2', '*.mp2v', '*.mp4', '*.mp4v', '*.mpe', '*.mpeg', '*.mpeg1', '*.mpeg2', '*.mpeg4', '*.mpg', - '*.mpv2', '*.mts', '*.mtv', '*.mxf', '*.mxg', '*.nsv', '*.nuv', '*.ogg', '*.ogm', '*.ogv', '*.ogx', '*.ps', - '*.rec', '*.rm', '*.rmvb', '*.rpl', '*.thp', '*.tod', '*.ts', '*.tts', '*.txd', '*.vob', '*.vro', '*.webm', - '*.wm', '*.wmv', '*.wtv', '*.xesc', +VIDEO_EXT = ('3g2', '3gp', '3gp2', '3gpp', 'amv', 'asf', 'avi', 'bik', 'divx', 'drc', 'dv', 'f4v', 'flv', 'gvi', 'gxf', + 'iso', 'm1v', 'm2v', 'm2t', 'm2ts', 'm4v', 'mkv', 'mov', 'mp2', 'mp2v', 'mp4', 'mp4v', 'mpe', 'mpeg', + 'mpeg1', 'mpeg2', 'mpeg4', 'mpg', 'mpv2', 'mts', 'mtv', 'mxf', 'mxg', 'nsv', 'nuv', 'ogg', 'ogm', 'ogv', + 'ogx', 'ps', 'rec', 'rm', 'rmvb', 'rpl', 'thp', 'tod', 'ts', 'tts', 'txd', 'vob', 'vro', 'webm', 'wm', + 'wmv', 'wtv', 'xesc', # These extensions was not in the official list, added manually. - '*.nut', '*.rv', '*.xvid'] + 'nut', 'rv', 'xvid') def get_vlc(): @@ -372,14 +370,3 @@ class VlcPlayer(MediaPlayer): else: controller.seek_slider.setSliderPosition(output_display.vlc_media_player.get_time()) controller.seek_slider.blockSignals(False) - - def get_info(self): - """ - Return some information about this player - """ - return(translate('Media.player', 'VLC is an external player which ' - 'supports a number of different formats.') + - '
' + translate('Media.player', 'Audio') + - '
' + str(AUDIO_EXT) + '
' + - translate('Media.player', 'Video') + '
' + - str(VIDEO_EXT) + '
') diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index 7394409fa..f165d32dc 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -75,9 +75,8 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties): self.image_path_edit.filters = \ '{name};;{text} (*)'.format(name=get_images_filter(), text=UiStrings().AllFiles) self.image_path_edit.pathChanged.connect(self.on_image_path_edit_path_changed) - # TODO: Should work - visible_formats = '({name})'.format(name='; '.join(VIDEO_EXT)) - actual_formats = '({name})'.format(name=' '.join(VIDEO_EXT)) + visible_formats = '(*.{name})'.format(name='; *.'.join(VIDEO_EXT)) + actual_formats = '(*.{name})'.format(name=' *.'.join(VIDEO_EXT)) video_filter = '{trans} {visible} {actual}'.format(trans=translate('OpenLP', 'Video Files'), visible=visible_formats, actual=actual_formats) self.video_path_edit.filters = '{video};;{ui} (*)'.format(video=video_filter, ui=UiStrings().AllFiles) diff --git a/tests/functional/openlp_core/ui/media/test_vlcplayer.py b/tests/functional/openlp_core/ui/media/test_vlcplayer.py index 75828de8d..ace896066 100644 --- a/tests/functional/openlp_core/ui/media/test_vlcplayer.py +++ b/tests/functional/openlp_core/ui/media/test_vlcplayer.py @@ -956,20 +956,3 @@ class TestVLCPlayer(TestCase, TestMixin): mocked_controller.seek_slider.setSliderPosition.assert_called_with(300) expected_calls = [call(True), call(False)] assert expected_calls == mocked_controller.seek_slider.blockSignals.call_args_list - - @patch('openlp.core.ui.media.vlcplayer.translate') - def test_get_info(self, mocked_translate): - """ - Test that get_info() returns some information about the VLC player - """ - # GIVEN: A VlcPlayer - mocked_translate.side_effect = lambda *x: x[1] - vlc_player = VlcPlayer(None) - - # WHEN: get_info() is run - info = vlc_player.get_info() - - # THEN: The information should be correct - assert 'VLC is an external player which supports a number of different formats.
' \ - 'Audio
' + str(AUDIO_EXT) + '
Video
' + \ - str(VIDEO_EXT) + '
' == info From 949231a35f7352adbc09991d04168cca5c0dc63e Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Wed, 29 May 2019 21:18:25 +0200 Subject: [PATCH 21/27] Fix traceback on Mac tests --- openlp/plugins/presentations/lib/impresscontroller.py | 4 +++- openlp/plugins/presentations/lib/powerpointcontroller.py | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index 9dd1a776a..b64973c33 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -42,7 +42,7 @@ from openlp.core.display.screens import ScreenList from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument, \ TextType - +# Load the XSlideShowListener class so we can inherit from it if is_win(): from win32com.client import Dispatch import pywintypes @@ -75,6 +75,8 @@ else: uno_available = True except ImportError: uno_available = False + class SlideShowListenerImport(): + pass log = logging.getLogger(__name__) diff --git a/openlp/plugins/presentations/lib/powerpointcontroller.py b/openlp/plugins/presentations/lib/powerpointcontroller.py index a01470855..763be4560 100644 --- a/openlp/plugins/presentations/lib/powerpointcontroller.py +++ b/openlp/plugins/presentations/lib/powerpointcontroller.py @@ -145,8 +145,8 @@ class PowerpointDocument(PresentationDocument): try: if not self.controller.process: self.controller.start_process() - self.controller.process.Presentations.Open(str(self.file_path), False, False, False) - self.presentation = self.controller.process.Presentations(self.controller.process.Presentations.Count) + self.presentation = self.controller.process.Presentations.Open(str(self.file_path), False, False, False) + log.debug('Loaded presentation %s' % self.presentation.FullName) self.create_thumbnails() self.create_titles_and_notes() # Make sure powerpoint doesn't steal focus, unless we're on a single screen setup From 2efaffec7ad5921ff32d6164c177078c57e37d89 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Wed, 29 May 2019 21:22:12 +0200 Subject: [PATCH 22/27] pep8 --- openlp/plugins/presentations/lib/impresscontroller.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index b64973c33..5a5e81cd3 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -75,6 +75,7 @@ else: uno_available = True except ImportError: uno_available = False + class SlideShowListenerImport(): pass From f4111e4431edad7122ae33c56a4049edd0cf44c4 Mon Sep 17 00:00:00 2001 From: Phill Date: Fri, 31 May 2019 20:59:38 +0100 Subject: [PATCH 23/27] Fix up filters --- openlp/plugins/media/lib/mediaitem.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 2d66eabe9..f1801b7a2 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -232,9 +232,9 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): """ # self.populate_display_types() self.on_new_file_masks = translate('MediaPlugin.MediaItem', - 'Videos ({video});;Audio ({audio});;{files} ' - '(*)').format(video=' '.join(VIDEO_EXT), - audio=' '.join(AUDIO_EXT), + 'Videos (*.{video});;Audio (*.{audio});;{files} ' + '(*)').format(video=' *.'.join(VIDEO_EXT), + audio=' *.'.join(AUDIO_EXT), files=UiStrings().AllFiles) def on_delete_click(self): From 8fe469aca3c4c2ccebcf6d94f01f2b3c5159f004 Mon Sep 17 00:00:00 2001 From: Phill Date: Fri, 31 May 2019 21:04:51 +0100 Subject: [PATCH 24/27] Re-add period --- openlp/plugins/songs/lib/openlyricsexport.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/songs/lib/openlyricsexport.py b/openlp/plugins/songs/lib/openlyricsexport.py index 37a64162f..311bfa711 100644 --- a/openlp/plugins/songs/lib/openlyricsexport.py +++ b/openlp/plugins/songs/lib/openlyricsexport.py @@ -43,7 +43,7 @@ class OpenLyricsExport(RegistryProperties): """ def __init__(self, parent, songs, save_path): """ - Initialise the export + Initialise the export. :param pathlib.Path save_path: The directory to save the exported songs in :rtype: None From 52eb196e5b08d02bda775ccc7b84cf7ed4a6e565 Mon Sep 17 00:00:00 2001 From: Phill Date: Fri, 31 May 2019 21:19:15 +0100 Subject: [PATCH 25/27] PEP8 --- openlp/core/ui/media/vlcplayer.py | 5 ++--- .../functional/openlp_core/ui/media/test_mediacontroller.py | 1 - tests/functional/openlp_core/ui/media/test_vlcplayer.py | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/openlp/core/ui/media/vlcplayer.py b/openlp/core/ui/media/vlcplayer.py index da4036bda..3904b63ae 100644 --- a/openlp/core/ui/media/vlcplayer.py +++ b/openlp/core/ui/media/vlcplayer.py @@ -33,7 +33,6 @@ import vlc from PyQt5 import QtWidgets from openlp.core.common import is_linux, is_macosx, is_win -from openlp.core.common.i18n import translate from openlp.core.common.settings import Settings from openlp.core.ui.media import MediaState, MediaType from openlp.core.ui.media.mediaplayer import MediaPlayer @@ -49,8 +48,8 @@ AUDIO_EXT = ('3ga', '669', 'a52', 'aac', 'ac3', 'adt', 'adts', 'aif', 'aifc', 'a VIDEO_EXT = ('3g2', '3gp', '3gp2', '3gpp', 'amv', 'asf', 'avi', 'bik', 'divx', 'drc', 'dv', 'f4v', 'flv', 'gvi', 'gxf', 'iso', 'm1v', 'm2v', 'm2t', 'm2ts', 'm4v', 'mkv', 'mov', 'mp2', 'mp2v', 'mp4', 'mp4v', 'mpe', 'mpeg', - 'mpeg1', 'mpeg2', 'mpeg4', 'mpg', 'mpv2', 'mts', 'mtv', 'mxf', 'mxg', 'nsv', 'nuv', 'ogg', 'ogm', 'ogv', - 'ogx', 'ps', 'rec', 'rm', 'rmvb', 'rpl', 'thp', 'tod', 'ts', 'tts', 'txd', 'vob', 'vro', 'webm', 'wm', + 'mpeg1', 'mpeg2', 'mpeg4', 'mpg', 'mpv2', 'mts', 'mtv', 'mxf', 'mxg', 'nsv', 'nuv', 'ogg', 'ogm', 'ogv', + 'ogx', 'ps', 'rec', 'rm', 'rmvb', 'rpl', 'thp', 'tod', 'ts', 'tts', 'txd', 'vob', 'vro', 'webm', 'wm', 'wmv', 'wtv', 'xesc', # These extensions was not in the official list, added manually. 'nut', 'rv', 'xvid') diff --git a/tests/functional/openlp_core/ui/media/test_mediacontroller.py b/tests/functional/openlp_core/ui/media/test_mediacontroller.py index 2389d8a34..b0e41c19c 100644 --- a/tests/functional/openlp_core/ui/media/test_mediacontroller.py +++ b/tests/functional/openlp_core/ui/media/test_mediacontroller.py @@ -27,7 +27,6 @@ from unittest.mock import MagicMock, patch from openlp.core.common.registry import Registry from openlp.core.ui.media.mediacontroller import MediaController -from openlp.core.ui.media.vlcplayer import VlcPlayer from tests.helpers.testmixin import TestMixin from tests.utils.constants import RESOURCE_PATH diff --git a/tests/functional/openlp_core/ui/media/test_vlcplayer.py b/tests/functional/openlp_core/ui/media/test_vlcplayer.py index ace896066..9eaeb21a6 100644 --- a/tests/functional/openlp_core/ui/media/test_vlcplayer.py +++ b/tests/functional/openlp_core/ui/media/test_vlcplayer.py @@ -30,7 +30,7 @@ from unittest.mock import MagicMock, call, patch from openlp.core.common.registry import Registry from openlp.core.ui.media import MediaState, MediaType -from openlp.core.ui.media.vlcplayer import AUDIO_EXT, VIDEO_EXT, VlcPlayer, get_vlc +from openlp.core.ui.media.vlcplayer import VlcPlayer, get_vlc from tests.helpers import MockDateTime from tests.helpers.testmixin import TestMixin From aaaab9bf43a4e4d59bac4d941bab8286ad29871e Mon Sep 17 00:00:00 2001 From: Phill Date: Sat, 1 Jun 2019 07:59:45 +0100 Subject: [PATCH 26/27] Add media extensions in the service manager --- openlp/core/ui/media/mediacontroller.py | 2 -- openlp/core/ui/servicemanager.py | 10 +++++++++- openlp/plugins/media/lib/mediaitem.py | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index a17e48ea9..27164a06a 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -106,8 +106,6 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): else: State().missing_text('media_live', translate('OpenLP.SlideController', 'VLC or pymediainfo are missing, so you are unable to play any media')) - self.service_manager.supported_suffixes(AUDIO_EXT) - self.service_manager.supported_suffixes(VIDEO_EXT) return True def bootstrap_post_set_up(self): diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 9e8b915fb..220998c59 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -48,6 +48,7 @@ from openlp.core.lib.plugin import PluginStatus from openlp.core.lib.serviceitem import ItemCapabilities, ServiceItem from openlp.core.lib.ui import create_widget_action, critical_error_message_box, find_and_set_in_combo_box from openlp.core.ui.icons import UiIcons +from openlp.core.ui.media.vlcplayer import AUDIO_EXT, VIDEO_EXT from openlp.core.ui.serviceitemeditform import ServiceItemEditForm from openlp.core.ui.servicenoteform import ServiceNoteForm from openlp.core.ui.starttimeform import StartTimeForm @@ -321,6 +322,7 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi super().__init__(parent) self.service_items = [] self.suffixes = set() + self.add_media_suffixes() self.drop_position = -1 self.service_id = 0 # is a new service and has not been saved @@ -347,6 +349,13 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi self.service_item_edit_form = ServiceItemEditForm() self.start_time_form = StartTimeForm() + def add_media_suffixes(self): + """ + Add the suffixes supported by :mod:`openlp.core.ui.media.vlcplayer` + """ + self.suffixes.update(AUDIO_EXT) + self.suffixes.update(VIDEO_EXT) + def set_modified(self, modified=True): """ Setter for property "modified". Sets whether or not the current service has been modified. @@ -401,7 +410,6 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi def reset_supported_suffixes(self): """ Resets the Suffixes list. - """ self.suffixes.clear() diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index f1801b7a2..58994a909 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -303,7 +303,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): if media_type == MediaType.Audio: extension = AUDIO_EXT else: - extension = VIDEO_EXT # TODO: Rename extension to extensions + extension = VIDEO_EXT extension = [x[1:] for x in extension] media = [x for x in media_file_paths if x.suffix in extension] return media From 3963923e2d9ede2ff0057038401e160feeff6d30 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 4 Jun 2019 22:03:19 +0200 Subject: [PATCH 27/27] Fix as suggested --- .../presentations/lib/impresscontroller.py | 23 +++++++++++++------ .../lib/presentationcontroller.py | 4 ++-- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index ffbb79d04..873e91b86 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -188,7 +188,7 @@ class ImpressController(PresentationController): """ log.debug('Kill OpenOffice') if self.presenter_screen_disabled_by_openlp: - self._toggle_presentation_screen(True) + self.toggle_presentation_screen(True) while self.docs: self.docs[0].close_presentation() desktop = None @@ -218,9 +218,12 @@ class ImpressController(PresentationController): except Exception: log.warning('Failed to terminate OpenOffice') - def toggle_presentation_screen(self, target_value): + def toggle_presentation_screen(self, set_visible): """ Enable or disable the Presentation Screen/Console + + :param bool set_visible: Should the presentation screen/console be set to be visible. + :rtype: None """ # Create Instance of ConfigurationProvider if not self.conf_provider: @@ -241,21 +244,24 @@ class ImpressController(PresentationController): presenter_screen_enabled = impress_conf_props.getHierarchicalPropertyValue( 'Misc/Start/EnablePresenterScreen') # If the presentation screen is enabled we disable it - if presenter_screen_enabled != target_value: - impress_conf_props.setHierarchicalPropertyValue('Misc/Start/EnablePresenterScreen', target_value) + if presenter_screen_enabled != set_visible: + impress_conf_props.setHierarchicalPropertyValue('Misc/Start/EnablePresenterScreen', set_visible) impress_conf_props.commitChanges() - # if target_value is False this is an attempt to disable the Presenter Screen + # if set_visible is False this is an attempt to disable the Presenter Screen # so we make a note that it has been disabled, so it can be enabled again on close. - if target_value is False: + if set_visible is False: self.presenter_screen_disabled_by_openlp = True except Exception as e: log.exception(e) trace_error_handler(log) - return def create_property(self, name, value): """ Create an OOo style property object which are passed into some Uno methods. + + :param str name: The name of the property + :param str value: The value of the property + :rtype: com.sun.star.beans.PropertyValue """ log.debug('create property OpenOffice') if is_win(): @@ -615,6 +621,9 @@ class SlideShowListener(SlideShowListenerImport): """ Notify that the current slide has ended, e.g. the user has clicked on the slide. Calling displaySlide() twice will not issue this event. + + :param bool reverse: Whether or not the direction of the "slide movement" is reversed/backwards. + :rtype: None """ log.debug('LibreOffice SlideShowListener event: slideEnded %d' % reverse) if reverse: diff --git a/openlp/plugins/presentations/lib/presentationcontroller.py b/openlp/plugins/presentations/lib/presentationcontroller.py index cb827cc5c..ac25fa9a4 100644 --- a/openlp/plugins/presentations/lib/presentationcontroller.py +++ b/openlp/plugins/presentations/lib/presentationcontroller.py @@ -249,14 +249,14 @@ class PresentationDocument(object): """ Triggers the next effect of slide on the running presentation. This might be the next animation on the current slide, or the next slide. - Returns True if we stepped beyond the slides of the presentation + :rtype bool: True if we stepped beyond the slides of the presentation """ return False def previous_step(self): """ Triggers the previous slide on the running presentation - Returns True if we stepped beyond the slides of the presentation + :rtype bool: True if we stepped beyond the slides of the presentation """ return False