From fe01718d46021b73750a45220ba15d208f29712c Mon Sep 17 00:00:00 2001 From: Jonathan Corwin Date: Wed, 23 Jun 2010 23:26:54 +0100 Subject: [PATCH 1/6] Presentation tidyups --- .../presentations/lib/impresscontroller.py | 5 +- .../presentations/lib/messagelistener.py | 149 +++++++++--------- .../presentations/lib/powerpointcontroller.py | 27 ++-- .../presentations/lib/pptviewcontroller.py | 23 +-- .../presentations/lib/pptviewlib/README.TXT | 2 + .../lib/pptviewlib/pptviewlib.cpp | 4 +- 6 files changed, 111 insertions(+), 99 deletions(-) diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index 10add26b4..6cb8c349c 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -331,7 +331,10 @@ class ImpressDocument(PresentationDocument): def stop_presentation(self): log.debug(u'stop presentation OpenOffice') - self.control.deactivate() + # deactivate should hide the screen according to docs, but doesn't + #self.control.deactivate() + self.presentation.end() + self.control = None def start_presentation(self): log.debug(u'start presentation OpenOffice') diff --git a/openlp/plugins/presentations/lib/messagelistener.py b/openlp/plugins/presentations/lib/messagelistener.py index c6ab1e921..13a589ec3 100644 --- a/openlp/plugins/presentations/lib/messagelistener.py +++ b/openlp/plugins/presentations/lib/messagelistener.py @@ -41,31 +41,31 @@ class Controller(object): log.info(u'Controller loaded') def __init__(self, live): - self.isLive = live + self.is_live = live self.doc = None log.info(u'%s controller loaded' % live) - def addHandler(self, controller, file, isBlank): - log.debug(u'Live = %s, addHandler %s' % (self.isLive, file)) + def add_handler(self, controller, file, is_blank): + log.debug(u'Live = %s, add_handler %s' % (self.is_live, file)) self.controller = controller if self.doc is not None: self.shutdown() self.doc = self.controller.add_doc(file) self.doc.load_presentation() - if self.isLive: + if self.is_live: self.doc.start_presentation() - if isBlank: + if is_blank: self.blank() Receiver.send_message(u'maindisplay_hide', HideMode.Screen) self.doc.slidenumber = 0 def activate(self): - log.debug(u'Live = %s, activate' % self.isLive) + log.debug(u'Live = %s, activate' % self.is_live) if self.doc.is_active(): return if not self.doc.is_loaded(): self.doc.load_presentation() - if self.isLive: + if self.is_live: self.doc.start_presentation() if self.doc.slidenumber > 1: self.doc.goto_slide(self.doc.slidenumber) @@ -85,36 +85,36 @@ class Controller(object): """ Based on the handler passed at startup triggers the first slide """ - log.debug(u'Live = %s, first' % self.isLive) - if not self.isLive: + log.debug(u'Live = %s, first' % self.is_live) + if not self.is_live: return if self.doc.is_blank(): self.doc.slidenumber = 1 return self.activate() self.doc.start_presentation() - self.doc.poll_slidenumber(self.isLive) + self.doc.poll_slidenumber(self.is_live) def last(self): """ Based on the handler passed at startup triggers the first slide """ - log.debug(u'Live = %s, last' % self.isLive) - if not self.isLive: + log.debug(u'Live = %s, last' % self.is_live) + if not self.is_live: return if self.doc.is_blank(): self.doc.slidenumber = self.doc.get_slide_count() return self.activate() self.doc.goto_slide(self.doc.get_slide_count()) - self.doc.poll_slidenumber(self.isLive) + self.doc.poll_slidenumber(self.is_live) def next(self): """ Based on the handler passed at startup triggers the next slide event """ - log.debug(u'Live = %s, next' % self.isLive) - if not self.isLive: + log.debug(u'Live = %s, next' % self.is_live) + if not self.is_live: return if self.doc.is_blank(): if self.doc.slidenumber < self.doc.get_slide_count(): @@ -122,14 +122,14 @@ class Controller(object): return self.activate() self.doc.next_step() - self.doc.poll_slidenumber(self.isLive) + self.doc.poll_slidenumber(self.is_live) def previous(self): """ Based on the handler passed at startup triggers the previous slide event """ - log.debug(u'Live = %s, previous' % self.isLive) - if not self.isLive: + log.debug(u'Live = %s, previous' % self.is_live) + if not self.is_live: return if self.doc.is_blank(): if self.doc.slidenumber > 1: @@ -137,14 +137,14 @@ class Controller(object): return self.activate() self.doc.previous_step() - self.doc.poll_slidenumber(self.isLive) + self.doc.poll_slidenumber(self.is_live) def shutdown(self): """ Based on the handler passed at startup triggers slide show to shut down """ - log.debug(u'Live = %s, shutdown' % self.isLive) - if self.isLive: + log.debug(u'Live = %s, shutdown' % self.is_live) + if self.is_live: Receiver.send_message(u'maindisplay_show') self.doc.close_presentation() self.doc = None @@ -152,8 +152,8 @@ class Controller(object): #self.timer.stop() def blank(self): - log.debug(u'Live = %s, blank' % self.isLive) - if not self.isLive: + log.debug(u'Live = %s, blank' % self.is_live) + if not self.is_live: return if not self.doc.is_loaded(): return @@ -162,8 +162,8 @@ class Controller(object): self.doc.blank_screen() def stop(self): - log.debug(u'Live = %s, stop' % self.isLive) - if not self.isLive: + log.debug(u'Live = %s, stop' % self.is_live) + if not self.is_live: return if not self.doc.is_loaded(): return @@ -172,8 +172,8 @@ class Controller(object): self.doc.stop_presentation() def unblank(self): - log.debug(u'Live = %s, unblank' % self.isLive) - if not self.isLive: + log.debug(u'Live = %s, unblank' % self.is_live) + if not self.is_live: return self.activate() if self.doc.slidenumber and \ @@ -183,7 +183,7 @@ class Controller(object): Receiver.send_message(u'maindisplay_hide', HideMode.Screen) def poll(self): - self.doc.poll_slidenumber(self.isLive) + self.doc.poll_slidenumber(self.is_live) class MessageListener(object): """ @@ -195,8 +195,8 @@ class MessageListener(object): def __init__(self, mediaitem): self.controllers = mediaitem.controllers self.mediaitem = mediaitem - self.previewHandler = Controller(False) - self.liveHandler = Controller(True) + self.preview_handler = Controller(False) + self.live_handler = Controller(True) # messages are sent from core.ui.slidecontroller QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'presentations_start'), self.startup) @@ -228,9 +228,10 @@ class MessageListener(object): Start of new presentation Save the handler as any new presentations start here """ - isLive, item = self.decode_message(message) + is_live = message[1] + item = message[0] log.debug(u'Startup called with message %s' % message) - isBlank = message[2] + is_blank = message[2] file = os.path.join(item.get_frame_path(), item.get_frame_title()) self.handler = item.title @@ -238,75 +239,71 @@ class MessageListener(object): self.handler = self.mediaitem.findControllerByType(file) if not self.handler: return - if isLive: - controller = self.liveHandler + if is_live: + controller = self.live_handler else: - controller = self.previewHandler - controller.addHandler(self.controllers[self.handler], file, isBlank) - - def decode_message(self, message): - if len(message) == 3: - return message[1], message[0], message[2] - else: - return message[1], message[0] + controller = self.preview_handler + controller.add_handler(self.controllers[self.handler], file, is_blank) def slide(self, message): - isLive, item, slide = self.decode_message(message) - if isLive: - self.liveHandler.slide(slide, isLive) + is_live = message[1] + slide = message[2] + item = message[0] + if is_live: + self.live_handler.slide(slide, item) else: - self.previewHandler.slide(slide, isLive) + self.preview_handler.slide(slide, item) def first(self, message): - isLive = self.decode_message(message)[0] - if isLive: - self.liveHandler.first() + is_live = message[1] + if is_live: + self.live_handler.first() else: - self.previewHandler.first() + self.preview_handler.first() def last(self, message): - isLive = self.decode_message(message)[0] - if isLive: - self.liveHandler.last() + is_live = message[1] + if is_live: + self.live_handler.last() else: - self.previewHandler.last() + self.preview_handler.last() def next(self, message): - isLive = self.decode_message(message)[0] - if isLive: - self.liveHandler.next() + is_live = message[1] + if is_live: + self.live_handler.next() else: - self.previewHandler.next() + self.preview_handler.next() def previous(self, message): - isLive = self.decode_message(message)[0] - if isLive: - self.liveHandler.previous() + is_live = message[1] + if is_live: + self.live_handler.previous() else: - self.previewHandler.previous() + self.preview_handler.previous() def shutdown(self, message): - isLive = self.decode_message(message)[0] - if isLive: + is_live = message[1] + if is_live: Receiver.send_message(u'maindisplay_show') - self.liveHandler.shutdown() + self.live_handler.shutdown() else: - self.previewHandler.shutdown() + self.preview_handler.shutdown() def hide(self, message): - isLive = self.decode_message(message)[0] - if isLive: - self.liveHandler.stop() + is_live = message[1] + if is_live: + self.live_handler.stop() def blank(self, message): - isLive = self.decode_message(message)[0] - if isLive: - self.liveHandler.blank() + is_live = message[1] + if is_live: + self.live_handler.blank() def unblank(self, message): - isLive = self.decode_message(message)[0] - if isLive: - self.liveHandler.unblank() + is_live = message[1] + if is_live: + self.live_handler.unblank() def timeout(self): - self.liveHandler.poll() + self.live_handler.poll() diff --git a/openlp/plugins/presentations/lib/powerpointcontroller.py b/openlp/plugins/presentations/lib/powerpointcontroller.py index 93c48e86c..f5a6c1120 100644 --- a/openlp/plugins/presentations/lib/powerpointcontroller.py +++ b/openlp/plugins/presentations/lib/powerpointcontroller.py @@ -30,6 +30,7 @@ if os.name == u'nt': from win32com.client import Dispatch import _winreg import win32ui + import pywintypes from presentationcontroller import PresentationController, PresentationDocument @@ -65,7 +66,7 @@ class PowerpointController(PresentationController): _winreg.OpenKey(_winreg.HKEY_CLASSES_ROOT, u'PowerPoint.Application').Close() return True - except: + except WindowsError: pass return False @@ -91,7 +92,7 @@ class PowerpointController(PresentationController): return try: self.process.Quit() - except: + except pywintypes.com_error: pass self.process = None @@ -121,11 +122,8 @@ class PowerpointDocument(PresentationDocument): log.debug(u'LoadPresentation') if not self.controller.process.Visible: self.controller.start_process() - #try: self.controller.process.Presentations.Open(self.filepath, False, False, True) - #except: - # return self.presentation = self.controller.process.Presentations( self.controller.process.Presentations.Count) self.create_thumbnails() @@ -154,7 +152,7 @@ class PowerpointDocument(PresentationDocument): if self.presentation: try: self.presentation.Close() - except: + except pywintypes.com_error: pass self.presentation = None self.controller.remove_doc(self) @@ -170,7 +168,9 @@ class PowerpointDocument(PresentationDocument): return False if self.controller.process.Presentations.Count == 0: return False - except: + except AttributeError: + return False + except pywintypes.com_error: return False return True @@ -186,7 +186,9 @@ class PowerpointDocument(PresentationDocument): return False if self.presentation.SlideShowWindow.View is None: return False - except: + except AttributeError: + return False + except pywintypes.com_error: return False return True @@ -208,7 +210,10 @@ class PowerpointDocument(PresentationDocument): """ Returns true if screen is blank """ - return self.presentation.SlideShowWindow.View.State == 3 + try: + return self.presentation.SlideShowWindow.View.State == 3 + except pywintypes.com_error: + return False def stop_presentation(self): """ @@ -224,11 +229,11 @@ class PowerpointDocument(PresentationDocument): #SlideShowWindow measures its size/position by points, not pixels try: dpi = win32ui.GetActiveWindow().GetDC().GetDeviceCaps(88) - except: + except win32ui.error: try: dpi = \ win32ui.GetForegroundWindow().GetDC().GetDeviceCaps(88) - except: + except win32ui.error: dpi = 96 self.presentation.SlideShowSettings.Run() self.presentation.SlideShowWindow.View.GotoSlide(1) diff --git a/openlp/plugins/presentations/lib/pptviewcontroller.py b/openlp/plugins/presentations/lib/pptviewcontroller.py index 42a12be1d..bcda545ee 100644 --- a/openlp/plugins/presentations/lib/pptviewcontroller.py +++ b/openlp/plugins/presentations/lib/pptviewcontroller.py @@ -72,7 +72,7 @@ class PptviewController(PresentationController): try: self.start_process() return self.process.CheckInstalled() - except: + except WindowsError: return False def start_process(self): @@ -84,6 +84,7 @@ class PptviewController(PresentationController): log.debug(u'start PPTView') self.process = cdll.LoadLibrary( r'openlp\plugins\presentations\lib\pptviewlib\pptviewlib.dll') + #self.process.SetDebug(1) def kill(self): """ @@ -106,6 +107,7 @@ class PptviewDocument(PresentationDocument): self.presentation = None self.pptid = None self.blanked = False + self.hidden = False def load_presentation(self): """ @@ -123,13 +125,11 @@ class PptviewDocument(PresentationDocument): rect = rendermanager.screens.current[u'size'] rect = RECT(rect.x(), rect.y(), rect.right(), rect.bottom()) filepath = str(self.filepath.replace(u'/', u'\\')) - try: - self.pptid = self.controller.process.OpenPPT(filepath, None, rect, - str(os.path.join(self.thumbnailpath, - self.controller.thumbnailprefix))) + self.pptid = self.controller.process.OpenPPT(filepath, None, rect, + str(os.path.join(self.thumbnailpath, + self.controller.thumbnailprefix))) + if self.pptid: self.stop_presentation() - except: - log.exception(u'Failed to load presentation') def close_presentation(self): """ @@ -156,7 +156,7 @@ class PptviewDocument(PresentationDocument): """ Returns true if a presentation is currently active """ - return self.is_loaded() + return self.is_loaded() and not self.hidden def blank_screen(self): """ @@ -183,13 +183,18 @@ class PptviewDocument(PresentationDocument): """ Stops the current presentation and hides the output """ + self.hidden = True self.controller.process.Stop(self.pptid) def start_presentation(self): """ Starts a presentation from the beginning """ - self.controller.process.RestartShow(self.pptid) + if self.hidden: + self.hidden = False + self.controller.process.Resume(self.pptid) + else: + self.controller.process.RestartShow(self.pptid) def get_slide_number(self): """ diff --git a/openlp/plugins/presentations/lib/pptviewlib/README.TXT b/openlp/plugins/presentations/lib/pptviewlib/README.TXT index 5afcfd3f4..686278729 100644 --- a/openlp/plugins/presentations/lib/pptviewlib/README.TXT +++ b/openlp/plugins/presentations/lib/pptviewlib/README.TXT @@ -23,6 +23,8 @@ This README.TXT must be distributed with the pptviewlib.dll This library has a limit of 50 PowerPoints which can be opened simultaneously. +This project can be built with the free Microsoft Visual C++ 2008 Express Edition. + USAGE ----- BOOL CheckInstalled(void); diff --git a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp index abba3088b..86876a836 100644 --- a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp +++ b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp @@ -150,7 +150,7 @@ DllExport int OpenPPT(char *filename, HWND hParentWnd, RECT rect, char *previewp pptviewobj[id].rect.bottom = rect.bottom; pptviewobj[id].rect.right = rect.right; } - strcat_s(cmdline, MAX_PATH * 2, "/S \""); + strcat_s(cmdline, MAX_PATH * 2, "/F /S \""); strcat_s(cmdline, MAX_PATH * 2, filename); strcat_s(cmdline, MAX_PATH * 2, "\""); memset(&si, 0, sizeof(si)); @@ -211,7 +211,7 @@ DllExport int OpenPPT(char *filename, HWND hParentWnd, RECT rect, char *previewp } DEBUG("OpenPPT: Steps %d, first slide steps %d\n",pptviewobj[id].steps,pptviewobj[id].firstSlideSteps); SavePPTInfo(id); - if(pptviewobj[id].state==PPT_CLOSING){ + if(pptviewobj[id].state==PPT_CLOSING||pptviewobj[id].slideCount<=0){ ClosePPT(id); id=-1; } From b402cc563992183fa3646e7390cbc12a219d61bf Mon Sep 17 00:00:00 2001 From: Jon Tibble Date: Thu, 24 Jun 2010 20:04:18 +0100 Subject: [PATCH 2/6] Fix check_item_selection --- openlp/core/lib/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 6b1a2e67a..5408c611d 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -170,7 +170,7 @@ def check_item_selected(list_widget, message): The message to give the user if no item is selected """ if not list_widget.selectedIndexes(): - QtGui.QMessageBox.information(self, + QtGui.QMessageBox.information(list_widget.parent(), translate('MediaManagerItem', 'No Items Selected'), message) return False return True From 78b1c8d1afa0a35c8b4805f8415d90f2905eec2a Mon Sep 17 00:00:00 2001 From: Jon Tibble Date: Thu, 24 Jun 2010 20:36:33 +0100 Subject: [PATCH 3/6] Do the fix properly --- openlp/core/lib/baselistwithdnd.py | 1 - openlp/plugins/bibles/lib/mediaitem.py | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/core/lib/baselistwithdnd.py b/openlp/core/lib/baselistwithdnd.py index d34eada98..fab27695b 100644 --- a/openlp/core/lib/baselistwithdnd.py +++ b/openlp/core/lib/baselistwithdnd.py @@ -32,7 +32,6 @@ class BaseListWithDnD(QtGui.QListWidget): def __init__(self, parent=None): QtGui.QListWidget.__init__(self, parent) - self.parent = parent # this must be set by the class which is inheriting assert(self.PluginName) diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index d7633066d..6bc6d99d4 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -43,7 +43,8 @@ class BibleListView(BaseListWithDnD): BaseListWithDnD.__init__(self, parent) def resizeEvent(self, event): - self.parent.onListViewResize(event.size().width(), event.size().width()) + self.parent().onListViewResize(event.size().width(), + event.size().width()) class BibleMediaItem(MediaManagerItem): From 30f8441ce9f25830b888d52fdaa938c1d84c01e2 Mon Sep 17 00:00:00 2001 From: Jonathan Corwin Date: Thu, 24 Jun 2010 20:42:15 +0100 Subject: [PATCH 4/6] Merge excepts together --- openlp/plugins/presentations/lib/powerpointcontroller.py | 8 +++----- openlp/plugins/presentations/lib/pptviewcontroller.py | 5 +---- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/openlp/plugins/presentations/lib/powerpointcontroller.py b/openlp/plugins/presentations/lib/powerpointcontroller.py index f5a6c1120..b0b2829d2 100644 --- a/openlp/plugins/presentations/lib/powerpointcontroller.py +++ b/openlp/plugins/presentations/lib/powerpointcontroller.py @@ -186,9 +186,7 @@ class PowerpointDocument(PresentationDocument): return False if self.presentation.SlideShowWindow.View is None: return False - except AttributeError: - return False - except pywintypes.com_error: + except (AttributeError, pywintypes.com_error): return False return True @@ -210,9 +208,9 @@ class PowerpointDocument(PresentationDocument): """ Returns true if screen is blank """ - try: + if self.is_active(): return self.presentation.SlideShowWindow.View.State == 3 - except pywintypes.com_error: + else: return False def stop_presentation(self): diff --git a/openlp/plugins/presentations/lib/pptviewcontroller.py b/openlp/plugins/presentations/lib/pptviewcontroller.py index bcda545ee..10ab41fd0 100644 --- a/openlp/plugins/presentations/lib/pptviewcontroller.py +++ b/openlp/plugins/presentations/lib/pptviewcontroller.py @@ -58,10 +58,7 @@ class PptviewController(PresentationController): log.debug(u'check_available') if os.name != u'nt': return False - try: - return self.check_installed() - except: - return False + return self.check_installed() if os.name == u'nt': def check_installed(self): From 1ea6d1da5076811230246ddf1ef0a892d9cce7b1 Mon Sep 17 00:00:00 2001 From: Jonathan Corwin Date: Thu, 24 Jun 2010 20:58:45 +0100 Subject: [PATCH 5/6] Merge excepts together (again) --- openlp/plugins/presentations/lib/powerpointcontroller.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openlp/plugins/presentations/lib/powerpointcontroller.py b/openlp/plugins/presentations/lib/powerpointcontroller.py index b0b2829d2..477145bb0 100644 --- a/openlp/plugins/presentations/lib/powerpointcontroller.py +++ b/openlp/plugins/presentations/lib/powerpointcontroller.py @@ -168,9 +168,7 @@ class PowerpointDocument(PresentationDocument): return False if self.controller.process.Presentations.Count == 0: return False - except AttributeError: - return False - except pywintypes.com_error: + except (AttributeError, pywintypes.com_error): return False return True From a23a3545323bd7b6917b7d1cb7f63337fa288dde Mon Sep 17 00:00:00 2001 From: Jonathan Corwin Date: Thu, 24 Jun 2010 21:25:35 +0100 Subject: [PATCH 6/6] pptviewlib.dll --- .../lib/pptviewlib/pptviewlib.dll | Bin 47104 -> 47104 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.dll b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.dll index bb8e9d9a47aaf572decc48c3521dc0f61b2df51c..f8a0de0d33e562014629fc97d25cc11103695e55 100644 GIT binary patch delta 1481 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 rqi