← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~j-corwin/openlp/present into lp:openlp

 

Jonathan Corwin has proposed merging lp:~j-corwin/openlp/present into lp:openlp.

Requested reviews:
  OpenLP Core (openlp-core)
Related bugs:
  #598361 AttributeError: 'NoneType' object has no attribute 'isPaused'
  https://bugs.launchpad.net/bugs/598361


Common thumbnail folder for all presentation types, and create icons/thumbnails when presentation is added to media manager.
-- 
https://code.launchpad.net/~j-corwin/openlp/present/+merge/29659
Your team OpenLP Core is requested to review the proposed merge of lp:~j-corwin/openlp/present into lp:openlp.
=== modified file 'openlp/core/lib/__init__.py'
--- openlp/core/lib/__init__.py	2010-07-03 13:26:29 +0000
+++ openlp/core/lib/__init__.py	2010-07-11 20:27:44 +0000
@@ -174,6 +174,8 @@
     """
     preview = QtGui.QImage(image)
     if not preview.isNull():
+        if(preview.width() == width and preview.height == height):
+            return preview
         preview = preview.scaled(width, height, QtCore.Qt.KeepAspectRatio,
             QtCore.Qt.SmoothTransformation)
     realw = preview.width()

=== modified file 'openlp/core/lib/mediamanageritem.py'
--- openlp/core/lib/mediamanageritem.py	2010-07-10 01:01:14 +0000
+++ openlp/core/lib/mediamanageritem.py	2010-07-11 20:27:44 +0000
@@ -379,14 +379,17 @@
         """
         Validates to see if the file still exists or thumbnail is up to date
         """
-        if os.path.exists(file):
+        if not os.path.exists(file):
+            return False
+        if os.path.exists(thumb):
             filedate = os.stat(file).st_mtime
             thumbdate = os.stat(thumb).st_mtime
             #if file updated rebuild icon
             if filedate > thumbdate:
                 self.iconFromFile(file, thumb)
-            return True
-        return False
+        else:
+            self.iconFromFile(file, thumb)
+        return True
 
     def iconFromFile(self, file, thumb):
         """

=== modified file 'openlp/plugins/presentations/lib/impresscontroller.py'
--- openlp/plugins/presentations/lib/impresscontroller.py	2010-07-05 22:17:14 +0000
+++ openlp/plugins/presentations/lib/impresscontroller.py	2010-07-11 20:27:44 +0000
@@ -1,411 +1,468 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection                                      #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2010 Raoul Snyman                                        #
-# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael      #
-# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin      #
-# Thompson, Jon Tibble, Carsten Tinggaard                                     #
-# --------------------------------------------------------------------------- #
-# This program is free software; you can redistribute it and/or modify it     #
-# under the terms of the GNU General Public License as published by the Free  #
-# Software Foundation; version 2 of the License.                              #
-#                                                                             #
-# This program is distributed in the hope that it will be useful, but WITHOUT #
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
-# more details.                                                               #
-#                                                                             #
-# You should have received a copy of the GNU General Public License along     #
-# with this program; if not, write to the Free Software Foundation, Inc., 59  #
-# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
-###############################################################################
-
-# OOo API documentation:
-# http://api.openoffice.org/docs/common/ref/com/sun/star/presentation/XSlideShowController.html
-# http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/ProUNO/Basic/Getting_Information_about_UNO_Objects#Inspecting_interfaces_during_debugging
-# http://docs.go-oo.org/sd/html/classsd_1_1SlideShow.html
-# http://www.oooforum.org/forum/viewtopic.phtml?t=5252
-# http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/Working_with_Presentations
-# http://mail.python.org/pipermail/python-win32/2008-January/006676.html
-# http://www.linuxjournal.com/content/starting-stopping-and-connecting-openoffice-python
-# http://nxsy.org/comparing-documents-with-openoffice-and-python
-
-import logging
-import os
-import time
-
-from openlp.core.lib import resize_image
-
-if os.name == u'nt':
-    from win32com.client import Dispatch
-    import pywintypes
-else:
-    try:
-        import uno
-        from com.sun.star.beans import PropertyValue
-        uno_available = True
-    except ImportError:
-        uno_available = False
-        
-from PyQt4 import QtCore
-
-from presentationcontroller import PresentationController, PresentationDocument
-
-log = logging.getLogger(__name__)
-
-class ImpressController(PresentationController):
-    """
-    Class to control interactions with Impress presentations.
-    It creates the runtime environment, loads and closes the presentation as
-    well as triggering the correct activities based on the users input
-    """
-    log.info(u'ImpressController loaded')
-
-    def __init__(self, plugin):
-        """
-        Initialise the class
-        """
-        log.debug(u'Initialising')
-        PresentationController.__init__(self, plugin, u'Impress')
-        self.supports = [u'.odp']
-        self.alsosupports = [u'.ppt', u'.pps', u'.pptx', u'.ppsx']
-        self.process = None
-        self.desktop = None
-
-    def check_available(self):
-        """
-        Impress is able to run on this machine
-        """
-        log.debug(u'check_available')
-        if os.name == u'nt':
-            return self.get_com_servicemanager() is not None
-        else:
-            return uno_available
-
-    def start_process(self):
-        """
-        Loads a running version of OpenOffice in the background.
-        It is not displayed to the user but is available to the UNO interface
-        when required.
-        """
-        log.debug(u'start process Openoffice')
-        if os.name == u'nt':
-            self.manager = self.get_com_servicemanager()
-            self.manager._FlagAsMethod(u'Bridge_GetStruct')
-            self.manager._FlagAsMethod(u'Bridge_GetValueObject')
-        else:
-            # -headless
-            cmd = u'openoffice.org -nologo -norestore -minimized -invisible -nofirststartwizard -accept="socket,host=localhost,port=2002;urp;"'
-            self.process = QtCore.QProcess()
-            self.process.startDetached(cmd)
-            self.process.waitForStarted()
-
-    def get_uno_desktop(self):
-        log.debug(u'get UNO Desktop Openoffice')
-        ctx = None
-        loop = 0
-        log.debug(u'get UNO Desktop Openoffice - getComponentContext')
-        context = uno.getComponentContext()
-        log.debug(u'get UNO Desktop Openoffice - createInstaneWithContext - '
-            u'UnoUrlResolver')
-        resolver = context.ServiceManager.createInstanceWithContext(
-            u'com.sun.star.bridge.UnoUrlResolver', context)
-        while ctx is None and loop < 3:
-            try:
-                log.debug(u'get UNO Desktop Openoffice - resolve')
-                ctx = resolver.resolve(u'uno:socket,host=localhost,port=2002;'
-                    u'urp;StarOffice.ComponentContext')
-            except:
-                log.exception(u'Unable to find running instance ')
-                self.start_process()
-                loop += 1
-        try:
-            self.manager = ctx.ServiceManager
-            log.debug(u'get UNO Desktop Openoffice - createInstanceWithContext'
-                u' - Desktop')
-            desktop = self.manager.createInstanceWithContext(
-                "com.sun.star.frame.Desktop", ctx )
-            return desktop
-        except:
-            log.exception(u'Failed to get UNO desktop')
-            return None
-
-    def get_com_desktop(self):
-        log.debug(u'get COM Desktop OpenOffice')
-        return self.manager.createInstance(u'com.sun.star.frame.Desktop')
-
-    def get_com_servicemanager(self):
-        log.debug(u'get_com_servicemanager openoffice')
-        try:
-            return Dispatch(u'com.sun.star.ServiceManager')
-        except pywintypes.com_error:
-            log.exception(u'Failed to get COM service manager')
-            return None
-
-    def kill(self):
-        """
-        Called at system exit to clean up any running presentations
-        """
-        log.debug(u'Kill OpenOffice')
-        while self.docs:
-            self.docs[0].close_presentation()
-        if os.name != u'nt':
-            desktop = self.get_uno_desktop()
-        else:
-            desktop = self.get_com_desktop()
-        #Sometimes we get a failure and desktop is None
-        if not desktop:
-            log.exception(u'Failed to terminate OpenOffice')
-            return
-        docs = desktop.getComponents()
-        if docs.hasElements():
-            log.debug(u'OpenOffice not terminated')
-        else:
-            try:
-                desktop.terminate()
-                log.debug(u'OpenOffice killed')
-            except:
-                log.exception(u'Failed to terminate OpenOffice')
-
-    def add_doc(self, name):
-        log.debug(u'Add Doc OpenOffice')
-        doc = ImpressDocument(self, name)
-        self.docs.append(doc)
-        return doc
-
-class ImpressDocument(PresentationDocument):
-    def __init__(self, controller, presentation):
-        log.debug(u'Init Presentation OpenOffice')
-        PresentationDocument.__init__(self, controller, presentation)
-        self.document = None
-        self.presentation = None
-        self.control = None
-
-    def load_presentation(self):
-        """
-        Called when a presentation is added to the SlideController.
-        It builds the environment, starts communcations with the background
-        OpenOffice task started earlier.  If OpenOffice is not present is is
-        started.  Once the environment is available the presentation is loaded
-        and started.
-
-        ``presentation``
-        The file name of the presentatios to the run.
-        """
-        log.debug(u'Load Presentation OpenOffice')
-        #print "s.dsk1 ", self.desktop
-        if os.name == u'nt':
-            desktop = self.controller.get_com_desktop()
-            if desktop is None:
-                self.controller.start_process()
-                desktop = self.controller.get_com_desktop()
-            url = u'file:///' + self.filepath.replace(u'\\', u'/').replace(
-                u':', u'|').replace(u' ', u'%20')
-        else:
-            desktop = self.controller.get_uno_desktop()
-            url = uno.systemPathToFileUrl(self.filepath)
-        if desktop is None:
-            return
-        self.desktop = desktop
-        #print "s.dsk2 ", self.desktop
-        properties = []
-        properties.append(self.create_property(u'Minimized', True))
-        properties = tuple(properties)
-        try:
-            self.document = desktop.loadComponentFromURL(url, u'_blank',
-                0, properties)
-        except:
-            log.exception(u'Failed to load presentation')
-            return
-        self.presentation = self.document.getPresentation()
-        self.presentation.Display = \
-            self.controller.plugin.renderManager.screens.current_display + 1
-        self.control = None
-        self.create_thumbnails()
-
-    def create_thumbnails(self):
-        """
-        Create thumbnail images for presentation
-        """
-        log.debug(u'create thumbnails OpenOffice')
-        if self.check_thumbnails():
-            return
-        if os.name == u'nt':
-            thumbdir = u'file:///' + self.thumbnailpath.replace(
-                u'\\', u'/').replace(u':', u'|').replace(u' ', u'%20')
-        else:
-            thumbdir = uno.systemPathToFileUrl(self.thumbnailpath)
-        props = []
-        props.append(self.create_property(u'FilterName', u'impress_png_Export'))
-        props = tuple(props)
-        doc = self.document
-        pages = doc.getDrawPages()
-        for idx in range(pages.getCount()):
-            page = pages.getByIndex(idx)
-            doc.getCurrentController().setCurrentPage(page)
-            path = u'%s/%s%s.png' % (thumbdir, self.controller.thumbnailprefix,
-                    unicode(idx + 1))
-            try:
-                doc.storeToURL(path , props)
-                preview = resize_image(path, 640, 480)
-                if os.path.exists(path):
-                    os.remove(path)
-                preview.save(path, u'png')
-            except:
-                log.exception(u'%s - Unable to store openoffice preview' % path)
-
-    def create_property(self, name, value):
-        log.debug(u'create property OpenOffice')
-        if os.name == u'nt':
-            prop = self.controller.manager.\
-                Bridge_GetStruct(u'com.sun.star.beans.PropertyValue')
-        else:
-            prop = PropertyValue()
-        prop.Name = name
-        prop.Value = value
-        return prop
-
-    def close_presentation(self):
-        """
-        Close presentation and clean up objects
-        Triggered by new object being added to SlideController or OpenLP
-        being shutdown
-        """
-        log.debug(u'close Presentation OpenOffice')
-        if self.document:
-            if self.presentation:
-                try:
-                    self.presentation.end()
-                    self.presentation = None
-                    self.document.dispose()
-                except:
-                    #We tried!
-                    pass
-            self.document = None
-        self.controller.remove_doc(self)
-
-    def is_loaded(self):
-        log.debug(u'is loaded OpenOffice')
-        #print "is_loaded "
-        if self.presentation is None or self.document is None:
-            #print "no present or document"
-            return False
-        try:
-            if self.document.getPresentation() is None:
-                #print "no getPresentation"
-                return False
-        except:
-            return False
-        return True
-
-    def is_active(self):
-        log.debug(u'is active OpenOffice')
-        #print "is_active "
-        if not self.is_loaded():
-            #print "False "
-            return False
-        #print "self.con ", self.control
-        if self.control is None:
-            return False
-        return True
-
-    def unblank_screen(self):
-        log.debug(u'unblank screen OpenOffice')
-        return self.control.resume()
-
-    def blank_screen(self):
-        log.debug(u'blank screen OpenOffice')
-        self.control.blankScreen(0)
-
-    def is_blank(self):
-        """
-        Returns true if screen is blank
-        """
-        log.debug(u'is blank OpenOffice')
-        if self.control:
-            return self.control.isPaused()
-        else:
-            return False
-
-    def stop_presentation(self):
-        log.debug(u'stop presentation OpenOffice')
-        # 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')
-        if self.control is None or not self.control.isRunning():
-            self.presentation.start()
-            # start() returns before the getCurrentComponent is ready.
-            # Try for 5 seconds
-            i = 1
-            while self.desktop.getCurrentComponent() is None and i < 50:
-                time.sleep(0.1)
-                i = i + 1
-            self.control = \
-                self.desktop.getCurrentComponent().Presentation.getController()
-        else:
-            self.control.activate()
-            self.goto_slide(1)
-
-    def get_slide_number(self):
-        return self.control.getCurrentSlideIndex() + 1
-
-    def get_slide_count(self):
-        return self.document.getDrawPages().getCount()
-
-    def goto_slide(self, slideno):
-        self.control.gotoSlideIndex(slideno-1)
-
-    def next_step(self):
-        """
-        Triggers the next effect of slide on the running presentation
-        """
-        self.control.gotoNextEffect()
-
-    def previous_step(self):
-        """
-        Triggers the previous slide on the running presentation
-        """
-        self.control.gotoPreviousSlide()
-
-    def get_slide_text(self, slide_no):
-        """
-        Returns the text on the slide
-
-        ``slide_no``
-        The slide the text is required for, starting at 1
-        """
-        doc = self.document
-        pages = doc.getDrawPages()
-        text = ''
-        page = pages.getByIndex(slide_no - 1)
-        for idx in range(page.getCount()):
-            shape = page.getByIndex(idx)
-            if shape.supportsService("com.sun.star.drawing.Text"):
-                text += shape.getString() + '\n'
-        return text
-
-    def get_slide_notes(self, slide_no):
-        """
-        Returns the text on the slide
-
-        ``slide_no``
-        The slide the notes are required for, starting at 1
-        """
-        doc = self.document
-        pages = doc.getDrawPages()
-        text = ''
-        page = pages.getByIndex(slide_no - 1)
-        notes = page.getNotesPage()
-        for idx in range(notes.getCount()):
-            shape = notes.getByIndex(idx)
-            if shape.supportsService("com.sun.star.drawing.Text"):
-                text += shape.getString() + '\n'
-        return text
-
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2010 Raoul Snyman                                        #
+# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael      #
+# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin      #
+# Thompson, Jon Tibble, Carsten Tinggaard                                     #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it     #
+# under the terms of the GNU General Public License as published by the Free  #
+# Software Foundation; version 2 of the License.                              #
+#                                                                             #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
+# more details.                                                               #
+#                                                                             #
+# You should have received a copy of the GNU General Public License along     #
+# with this program; if not, write to the Free Software Foundation, Inc., 59  #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
+###############################################################################
+
+# OOo API documentation:
+# http://api.openoffice.org/docs/common/ref/com/sun/star/presentation/XSlideShowController.html
+# http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/ProUNO/Basic/Getting_Information_about_UNO_Objects#Inspecting_interfaces_during_debugging
+# http://docs.go-oo.org/sd/html/classsd_1_1SlideShow.html
+# http://www.oooforum.org/forum/viewtopic.phtml?t=5252
+# http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/Working_with_Presentations
+# http://mail.python.org/pipermail/python-win32/2008-January/006676.html
+# http://www.linuxjournal.com/content/starting-stopping-and-connecting-openoffice-python
+# http://nxsy.org/comparing-documents-with-openoffice-and-python
+
+import logging
+import os
+import time
+
+from openlp.core.lib import resize_image
+
+if os.name == u'nt':
+    from win32com.client import Dispatch
+    import pywintypes
+else:
+    try:
+        import uno
+        from com.sun.star.beans import PropertyValue
+        uno_available = True
+    except ImportError:
+        uno_available = False
+        
+from PyQt4 import QtCore
+
+from presentationcontroller import PresentationController, PresentationDocument
+
+log = logging.getLogger(__name__)
+
+class ImpressController(PresentationController):
+    """
+    Class to control interactions with Impress presentations.
+    It creates the runtime environment, loads and closes the presentation as
+    well as triggering the correct activities based on the users input
+    """
+    log.info(u'ImpressController loaded')
+
+    def __init__(self, plugin):
+        """
+        Initialise the class
+        """
+        log.debug(u'Initialising')
+        PresentationController.__init__(self, plugin, u'Impress')
+        self.supports = [u'.odp']
+        self.alsosupports = [u'.ppt', u'.pps', u'.pptx', u'.ppsx']
+        self.process = None
+        self.desktop = None
+        self.manager = None
+
+    def check_available(self):
+        """
+        Impress is able to run on this machine
+        """
+        log.debug(u'check_available')
+        if os.name == u'nt':
+            return self.get_com_servicemanager() is not None
+        else:
+            return uno_available
+
+    def start_process(self):
+        """
+        Loads a running version of OpenOffice in the background.
+        It is not displayed to the user but is available to the UNO interface
+        when required.
+        """
+        log.debug(u'start process Openoffice')
+        if os.name == u'nt':
+            self.manager = self.get_com_servicemanager()
+            self.manager._FlagAsMethod(u'Bridge_GetStruct')
+            self.manager._FlagAsMethod(u'Bridge_GetValueObject')
+        else:
+            # -headless
+            cmd = u'openoffice.org -nologo -norestore -minimized -invisible -nofirststartwizard -accept="socket,host=localhost,port=2002;urp;"'
+            self.process = QtCore.QProcess()
+            self.process.startDetached(cmd)
+            self.process.waitForStarted()
+
+    def get_uno_desktop(self):
+        """
+        On non-Windows platforms, use Uno. Get the OpenOffice desktop
+        which will be used to manage impress
+        """
+        log.debug(u'get UNO Desktop Openoffice')
+        ctx = None
+        loop = 0
+        log.debug(u'get UNO Desktop Openoffice - getComponentContext')
+        context = uno.getComponentContext()
+        log.debug(u'get UNO Desktop Openoffice - createInstaneWithContext - '
+            u'UnoUrlResolver')
+        resolver = context.ServiceManager.createInstanceWithContext(
+            u'com.sun.star.bridge.UnoUrlResolver', context)
+        while ctx is None and loop < 3:
+            try:
+                log.debug(u'get UNO Desktop Openoffice - resolve')
+                ctx = resolver.resolve(u'uno:socket,host=localhost,port=2002;'
+                    u'urp;StarOffice.ComponentContext')
+            except:
+                log.exception(u'Unable to find running instance ')
+                self.start_process()
+                loop += 1
+        try:
+            self.manager = ctx.ServiceManager
+            log.debug(u'get UNO Desktop Openoffice - createInstanceWithContext'
+                u' - Desktop')
+            desktop = self.manager.createInstanceWithContext(
+                "com.sun.star.frame.Desktop", ctx )
+            return desktop
+        except:
+            log.exception(u'Failed to get UNO desktop')
+            return None
+
+    def get_com_desktop(self):
+        """
+        On Windows platforms, use COM. Return the desktop object which
+        will be used to manage Impress
+        """
+        log.debug(u'get COM Desktop OpenOffice')
+        if not self.manager:
+            return None
+        return self.manager.createInstance(u'com.sun.star.frame.Desktop')
+
+    def get_com_servicemanager(self):
+        """
+        Return the OOo service manager for windows
+        """
+        log.debug(u'get_com_servicemanager openoffice')
+        try:
+            return Dispatch(u'com.sun.star.ServiceManager')
+        except pywintypes.com_error:
+            log.exception(u'Failed to get COM service manager')
+            return None
+
+    def kill(self):
+        """
+        Called at system exit to clean up any running presentations
+        """
+        log.debug(u'Kill OpenOffice')
+        while self.docs:
+            self.docs[0].close_presentation()
+        if os.name != u'nt':
+            desktop = self.get_uno_desktop()
+        else:
+            desktop = self.get_com_desktop()
+        #Sometimes we get a failure and desktop is None
+        if not desktop:
+            log.exception(u'Failed to terminate OpenOffice')
+            return
+        docs = desktop.getComponents()
+        if docs.hasElements():
+            log.debug(u'OpenOffice not terminated')
+        else:
+            try:
+                desktop.terminate()
+                log.debug(u'OpenOffice killed')
+            except:
+                log.exception(u'Failed to terminate OpenOffice')
+
+    def add_doc(self, name):
+        """
+        Called when a new Impress document is opened
+        """
+        log.debug(u'Add Doc OpenOffice')
+        doc = ImpressDocument(self, name)
+        self.docs.append(doc)
+        return doc
+
+class ImpressDocument(PresentationDocument):
+    """
+    Class which holds information and controls a single presentation
+    """    
+    
+    def __init__(self, controller, presentation):
+        """
+        Constructor, store information about the file and initialise 
+        """        
+        log.debug(u'Init Presentation OpenOffice')
+        PresentationDocument.__init__(self, controller, presentation)
+        self.document = None
+        self.presentation = None
+        self.control = None
+
+    def load_presentation(self):
+        """
+        Called when a presentation is added to the SlideController.
+        It builds the environment, starts communcations with the background
+        OpenOffice task started earlier.  If OpenOffice is not present is is
+        started.  Once the environment is available the presentation is loaded
+        and started.
+
+        ``presentation``
+        The file name of the presentatios to the run.
+        """
+        log.debug(u'Load Presentation OpenOffice')
+        #print "s.dsk1 ", self.desktop
+        if os.name == u'nt':
+            desktop = self.controller.get_com_desktop()
+            if desktop is None:
+                self.controller.start_process()
+                desktop = self.controller.get_com_desktop()
+            url = u'file:///' + self.filepath.replace(u'\\', u'/').replace(
+                u':', u'|').replace(u' ', u'%20')
+        else:
+            desktop = self.controller.get_uno_desktop()
+            url = uno.systemPathToFileUrl(self.filepath)
+        if desktop is None:
+            return False
+        self.desktop = desktop
+        properties = []
+        properties.append(self.create_property(u'Minimized', True))
+        properties = tuple(properties)
+        try:
+            self.document = desktop.loadComponentFromURL(url, u'_blank',
+                0, properties)
+        except:
+            log.exception(u'Failed to load presentation')
+            return False
+        self.presentation = self.document.getPresentation()
+        self.presentation.Display = \
+            self.controller.plugin.renderManager.screens.current_display + 1
+        self.control = None
+        self.create_thumbnails()
+        return True
+
+    def create_thumbnails(self):
+        """
+        Create thumbnail images for presentation
+        """
+        log.debug(u'create thumbnails OpenOffice')
+        if self.check_thumbnails():
+            return
+        if os.name == u'nt':
+            thumbdirurl = u'file:///' + self.get_temp_folder().replace(
+                u'\\', u'/').replace(u':', u'|').replace(u' ', u'%20')
+        else:
+            thumbdirurl = uno.systemPathToFileUrl(self.get_temp_folder())
+        props = []
+        props.append(self.create_property(u'FilterName', u'impress_png_Export'))
+        props = tuple(props)
+        doc = self.document
+        pages = doc.getDrawPages()
+        if not os.path.isdir(self.get_temp_folder()):
+            os.makedirs(self.get_temp_folder())
+        for idx in range(pages.getCount()):
+            page = pages.getByIndex(idx)
+            doc.getCurrentController().setCurrentPage(page)
+            urlpath = u'%s/%s.png' % (thumbdirurl, unicode(idx + 1))
+            path = os.path.join(self.get_temp_folder(), 
+                unicode(idx + 1) + u'.png')
+            try:
+                doc.storeToURL(urlpath, props)
+                self.convert_thumbnail(path, idx + 1)
+                if os.path.exists(path):
+                    os.remove(path)
+            except:
+                log.exception(u'%s - Unable to store openoffice preview' % path)
+
+    def create_property(self, name, value):
+        """
+        Create an OOo style property object which are passed into some
+        Uno methods
+        """
+        log.debug(u'create property OpenOffice')
+        if os.name == u'nt':
+            prop = self.controller.manager.\
+                Bridge_GetStruct(u'com.sun.star.beans.PropertyValue')
+        else:
+            prop = PropertyValue()
+        prop.Name = name
+        prop.Value = value
+        return prop
+
+    def close_presentation(self):
+        """
+        Close presentation and clean up objects
+        Triggered by new object being added to SlideController or OpenLP
+        being shutdown
+        """
+        log.debug(u'close Presentation OpenOffice')
+        if self.document:
+            if self.presentation:
+                try:
+                    self.presentation.end()
+                    self.presentation = None
+                    self.document.dispose()
+                except:
+                    #We tried!
+                    pass
+            self.document = None
+        self.controller.remove_doc(self)
+
+    def is_loaded(self):
+        """
+        Returns true if a presentation is loaded
+        """
+        log.debug(u'is loaded OpenOffice')
+        #print "is_loaded "
+        if self.presentation is None or self.document is None:
+            #print "no present or document"
+            return False
+        try:
+            if self.document.getPresentation() is None:
+                #print "no getPresentation"
+                return False
+        except:
+            return False
+        return True
+
+    def is_active(self):
+        """
+        Returns true if a presentation is active and running
+        """
+        log.debug(u'is active OpenOffice')
+        #print "is_active "
+        if not self.is_loaded():
+            #print "False "
+            return False
+        #print "self.con ", self.control
+        if self.control is None:
+            return False
+        return True
+
+    def unblank_screen(self):
+        """
+        Unblanks the screen
+        """
+        log.debug(u'unblank screen OpenOffice')
+        return self.control.resume()
+
+    def blank_screen(self):
+        """
+        Blanks the screen
+        """
+        log.debug(u'blank screen OpenOffice')
+        self.control.blankScreen(0)
+
+    def is_blank(self):
+        """
+        Returns true if screen is blank
+        """
+        log.debug(u'is blank OpenOffice')
+        if self.control:
+            return self.control.isPaused()
+        else:
+            return False
+
+    def stop_presentation(self):
+        """
+        Stop the presentation, remove from screen
+        """
+        log.debug(u'stop presentation OpenOffice')
+        # deactivate should hide the screen according to docs, but doesn't
+        #self.control.deactivate()
+        self.presentation.end()
+        self.control = None
+
+    def start_presentation(self):
+        """
+        Start the presentation from the beginning
+        """
+        log.debug(u'start presentation OpenOffice')
+        if self.control is None or not self.control.isRunning():
+            self.presentation.start()
+            # start() returns before the getCurrentComponent is ready.
+            # Try for 5 seconds
+            i = 1
+            while self.desktop.getCurrentComponent() is None and i < 50:
+                time.sleep(0.1)
+                i = i + 1
+            self.control = \
+                self.desktop.getCurrentComponent().Presentation.getController()
+        else:
+            self.control.activate()
+            self.goto_slide(1)
+
+    def get_slide_number(self):
+        """
+        Return the current slide number on the screen, from 1
+        """
+        return self.control.getCurrentSlideIndex() + 1
+
+    def get_slide_count(self):
+        """
+        Return the total number of slides
+        """
+        return self.document.getDrawPages().getCount()
+
+    def goto_slide(self, slideno):
+        """
+        Go to a specific slide (from 1)
+        """
+        self.control.gotoSlideIndex(slideno-1)
+
+    def next_step(self):
+        """
+        Triggers the next effect of slide on the running presentation
+        """
+        self.control.gotoNextEffect()
+
+    def previous_step(self):
+        """
+        Triggers the previous slide on the running presentation
+        """
+        self.control.gotoPreviousSlide()
+
+    def get_slide_text(self, slide_no):
+        """
+        Returns the text on the slide
+
+        ``slide_no``
+        The slide the text is required for, starting at 1
+        """
+        doc = self.document
+        pages = doc.getDrawPages()
+        text = ''
+        page = pages.getByIndex(slide_no - 1)
+        for idx in range(page.getCount()):
+            shape = page.getByIndex(idx)
+            if shape.supportsService("com.sun.star.drawing.Text"):
+                text += shape.getString() + '\n'
+        return text
+
+    def get_slide_notes(self, slide_no):
+        """
+        Returns the text on the slide
+
+        ``slide_no``
+        The slide the notes are required for, starting at 1
+        """
+        doc = self.document
+        pages = doc.getDrawPages()
+        text = ''
+        page = pages.getByIndex(slide_no - 1)
+        notes = page.getNotesPage()
+        for idx in range(notes.getCount()):
+            shape = notes.getByIndex(idx)
+            if shape.supportsService("com.sun.star.drawing.Text"):
+                text += shape.getString() + '\n'
+        return text
+

=== modified file 'openlp/plugins/presentations/lib/mediaitem.py'
--- openlp/plugins/presentations/lib/mediaitem.py	2010-07-08 09:14:00 +0000
+++ openlp/plugins/presentations/lib/mediaitem.py	2010-07-11 20:27:44 +0000
@@ -35,9 +35,13 @@
 
 log = logging.getLogger(__name__)
 
-# We have to explicitly create separate classes for each plugin
-# in order for DnD to the Service manager to work correctly.
 class PresentationListView(BaseListWithDnD):
+    """
+    Class for the list of Presentations
+    
+    We have to explicitly create separate classes for each plugin
+    in order for DnD to the Service manager to work correctly.
+    """
     def __init__(self, parent=None):
         self.PluginName = u'Presentations'
         BaseListWithDnD.__init__(self, parent)
@@ -45,11 +49,14 @@
 class PresentationMediaItem(MediaManagerItem):
     """
     This is the Presentation media manager item for Presentation Items.
-    It can present files using Openoffice
+    It can present files using Openoffice and Powerpoint
     """
     log.info(u'Presentations Media Item loaded')
 
     def __init__(self, parent, icon, title, controllers):
+        """
+        Constructor. Setup defaults
+        """
         self.controllers = controllers
         self.PluginNameShort = u'Presentation'
         self.pluginNameVisible = translate('PresentationPlugin.MediaItem',
@@ -63,6 +70,9 @@
         self.message_listener = MessageListener(self)
 
     def retranslateUi(self):
+        """
+        The name of the plugin media displayed in UI
+        """
         self.OnNewPrompt = translate('PresentationPlugin.MediaItem',
             'Select Presentation(s)')
         self.Automatic = translate('PresentationPlugin.MediaItem',
@@ -80,12 +90,18 @@
             'Presentations (%s)' % fileType)
 
     def requiredIcons(self):
+        """
+        Set which icons the media manager tab should show
+        """
         MediaManagerItem.requiredIcons(self)
         self.hasFileIcon = True
         self.hasNewIcon = False
         self.hasEditIcon = False
 
     def addEndHeaderBar(self):
+        """
+        Display custom media manager items for presentations
+        """
         self.PresentationWidget = QtGui.QWidget(self)
         sizePolicy = QtGui.QSizePolicy(
             QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
@@ -109,15 +125,13 @@
         self.pageLayout.addWidget(self.PresentationWidget)
 
     def initialise(self):
-        self.servicePath = os.path.join(
-            AppLocation.get_section_data_path(self.settingsSection),
-            u'thumbnails')
+        """
+        Populate the media manager tab
+        """
         self.listView.setIconSize(QtCore.QSize(88, 50))
-        if not os.path.exists(self.servicePath):
-            os.mkdir(self.servicePath)
         list = SettingsManager.load_list(
             self.settingsSection, u'presentations')
-        self.loadList(list)
+        self.loadList(list, True)
         for item in self.controllers:
             #load the drop down selection
             if self.controllers[item].enabled:
@@ -126,7 +140,12 @@
             self.DisplayTypeComboBox.insertItem(0, self.Automatic)
             self.DisplayTypeComboBox.setCurrentIndex(0)
 
-    def loadList(self, list):
+    def loadList(self, list, initialLoad=False):
+        """
+        Add presentations into the media manager
+        This is called both on initial load of the plugin to populate with
+        existing files, and when the user adds new files via the media manager
+        """
         currlist = self.getFileList()
         titles = []
         for file in currlist:
@@ -136,40 +155,43 @@
                 continue
             filename = os.path.split(unicode(file))[1]
             if titles.count(filename) > 0:
-                QtGui.QMessageBox.critical(
-                    self, translate('PresentationPlugin.MediaItem',
-                    'File exists'),
+                if not initialLoad:
+                    QtGui.QMessageBox.critical(
+                        self, translate('PresentationPlugin.MediaItem',
+                        'File exists'),
                         translate('PresentationPlugin.MediaItem',
                         'A presentation with that filename already exists.'),
-                    QtGui.QMessageBox.Ok)
+                        QtGui.QMessageBox.Ok)
+                continue
+            controller_name = self.findControllerByType(filename)
+            if controller_name:
+                controller = self.controllers[controller_name]
+                doc = controller.add_doc(unicode(file))
+                thumb = os.path.join(doc.get_thumbnail_folder(), u'icon.png')
+                preview = doc.get_thumbnail_path(1, True)
+                if not preview and not initialLoad:
+                    doc.load_presentation()
+                    preview = doc.get_thumbnail_path(1, True)
+                doc.close_presentation()
+                if preview and self.validate(preview, thumb):
+                    icon = build_icon(thumb)
+                else:
+                    icon = build_icon(u':/general/general_delete.png')
             else:
-                icon = None
-                for controller in self.controllers:
-                    thumbPath = os.path.join(
-                        AppLocation.get_section_data_path(
-                            self.settingsSection),
-                        u'thumbnails', controller, filename)
-                    thumb = os.path.join(thumbPath, u'slide1.png')
-                    preview = os.path.join(
-                        AppLocation.get_section_data_path(
-                            self.settingsSection),
-                        controller, u'thumbnails', filename, u'slide1.png')
-                    if os.path.exists(preview):
-                        if os.path.exists(thumb):
-                            if self.validate(preview, thumb):
-                                icon = build_icon(thumb)
-                            else:
-                                icon = build_icon(
-                                    u':/general/general_delete.png')
-                        else:
-                            os.makedirs(thumbPath)
-                            icon = self.iconFromFile(preview, thumb)
-                if not icon:
+                if initialLoad:
                     icon = build_icon(u':/general/general_delete.png')
-                item_name = QtGui.QListWidgetItem(filename)
-                item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
-                item_name.setIcon(icon)
-                self.listView.addItem(item_name)
+                else:
+                    QtGui.QMessageBox.critical(
+                        self, translate('PresentationPlugin.MediaItem',
+                        'Unsupported file'),
+                        translate('PresentationPlugin.MediaItem',
+                        'This type of presentation is not supported'),
+                        QtGui.QMessageBox.Ok)
+                    continue
+            item_name = QtGui.QListWidgetItem(filename)
+            item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
+            item_name.setIcon(icon)
+            self.listView.addItem(item_name)
 
     def onDeleteClick(self):
         """
@@ -184,8 +206,6 @@
             for item in items:
                 filepath = unicode(item.data(
                     QtCore.Qt.UserRole).toString())
-                #not sure of this has errors
-                #John please can you look at .
                 for cidx in self.controllers:
                     doc = self.controllers[cidx].add_doc(filepath)
                     doc.presentation_deleted()
@@ -196,6 +216,11 @@
                 self.settingsSection, self.getFileList())
 
     def generateSlideData(self, service_item, item=None):
+        """
+        Load the relevant information for displaying the presentation
+        in the slidecontroller. In the case of powerpoints, an image
+        for each slide
+        """
         items = self.listView.selectedIndexes()
         if len(items) > 1:
             return False
@@ -213,20 +238,27 @@
                 controller = self.controllers[service_item.shortname]
                 (path, name) = os.path.split(filename)
                 doc = controller.add_doc(filename)
-                if doc.get_slide_preview_file(1) is None:
+                if doc.get_thumbnail_path(1, True) is None:
                     doc.load_presentation()
                 i = 1
-                img = doc.get_slide_preview_file(i)
+                img = doc.get_thumbnail_path(i, True)
                 while img:
                     service_item.add_from_command(path, name, img)
                     i = i + 1
-                    img = doc.get_slide_preview_file(i)
+                    img = doc.get_thumbnail_path(i, True)
                 doc.close_presentation()
             return True
         else:
             return False
 
     def findControllerByType(self, filename):
+        """
+        Determine the default application controller to use for the selected
+        file type. This is used if "Automatic" is set as the preferred 
+        controller. Find the first (alphabetic) enabled controller which
+        "supports" the extension. If none found, then look for a controller
+        which "alsosupports" it instead.
+        """
         filetype = os.path.splitext(filename)[1]
         if not filetype:
             return None

=== modified file 'openlp/plugins/presentations/lib/messagelistener.py'
--- openlp/plugins/presentations/lib/messagelistener.py	2010-06-25 20:20:03 +0000
+++ openlp/plugins/presentations/lib/messagelistener.py	2010-07-11 20:27:44 +0000
@@ -41,17 +41,28 @@
     log.info(u'Controller loaded')
 
     def __init__(self, live):
+        """
+        Constructor
+        """
         self.is_live = live
         self.doc = None
         log.info(u'%s controller loaded' % live)
 
     def add_handler(self, controller, file, is_blank):
+        """
+        Add a handler, which is an instance of a presentation and 
+        slidecontroller combination. If the slidecontroller has a display
+        then load the presentation.
+        """
         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 not self.doc.load_presentation():
+            # Display error message to user
+            # Inform slidecontroller that the action failed?
+            return
         if self.is_live:
             self.doc.start_presentation()
             if is_blank:
@@ -60,6 +71,10 @@
         self.doc.slidenumber = 0
 
     def activate(self):
+        """
+        Active the presentation, and show it on the screen.
+        Use the last slide number.
+        """
         log.debug(u'Live = %s, activate' % self.is_live)
         if self.doc.is_active():
             return
@@ -71,6 +86,9 @@
                 self.doc.goto_slide(self.doc.slidenumber)
 
     def slide(self, slide):
+        """
+        Go to a specific slide
+        """
         log.debug(u'Live = %s, slide' %  self.is_live)
         if not self.is_live:
             return
@@ -152,6 +170,9 @@
         #self.timer.stop()
 
     def blank(self):
+        """
+        Instruct the controller to blank the presentation
+        """
         log.debug(u'Live = %s, blank' % self.is_live)
         if not self.is_live:
             return
@@ -162,6 +183,9 @@
         self.doc.blank_screen()
 
     def stop(self):
+        """
+        Instruct the controller to stop and hide the presentation
+        """
         log.debug(u'Live = %s, stop' % self.is_live)
         if not self.is_live:
             return
@@ -172,6 +196,9 @@
         self.doc.stop_presentation()
 
     def unblank(self):
+        """
+        Instruct the controller to unblank the presentation
+        """
         log.debug(u'Live = %s, unblank' % self.is_live)
         if not self.is_live:
             return
@@ -246,6 +273,9 @@
         controller.add_handler(self.controllers[self.handler], file, is_blank)
 
     def slide(self, message):
+        """
+        React to the message to move to a specific slide
+        """
         is_live = message[1]
         slide = message[2]
         if is_live:
@@ -254,6 +284,9 @@
             self.preview_handler.slide(slide)
 
     def first(self, message):
+        """
+        React to the message to move to the first slide
+        """
         is_live = message[1]
         if is_live:
             self.live_handler.first()
@@ -261,6 +294,9 @@
             self.preview_handler.first()
 
     def last(self, message):
+        """
+        React to the message to move to the last slide
+        """
         is_live = message[1]
         if is_live:
             self.live_handler.last()
@@ -268,6 +304,9 @@
             self.preview_handler.last()
 
     def next(self, message):
+        """
+        React to the message to move to the next animation/slide
+        """
         is_live = message[1]
         if is_live:
             self.live_handler.next()
@@ -275,6 +314,9 @@
             self.preview_handler.next()
 
     def previous(self, message):
+        """
+        React to the message to move to the previous animation/slide
+        """
         is_live = message[1]
         if is_live:
             self.live_handler.previous()
@@ -282,6 +324,10 @@
             self.preview_handler.previous()
 
     def shutdown(self, message):
+        """
+        React to message to shutdown the presentation. I.e. end the show
+        and close the file
+        """
         is_live = message[1]
         if is_live:
             Receiver.send_message(u'maindisplay_show')
@@ -290,19 +336,34 @@
             self.preview_handler.shutdown()
 
     def hide(self, message):
+        """
+        React to the message to show the desktop
+        """
         is_live = message[1]
         if is_live:
             self.live_handler.stop()
 
     def blank(self, message):
+        """
+        React to the message to blank the display
+        """
         is_live = message[1]
         if is_live:
             self.live_handler.blank()
 
     def unblank(self, message):
+        """
+        React to the message to unblank the display
+        """
         is_live = message[1]
         if is_live:
             self.live_handler.unblank()
 
     def timeout(self):
+        """
+        The presentation may be timed or might be controlled by the 
+        application directly, rather than through OpenLP. Poll occassionally
+        to check which slide is currently displayed so the slidecontroller
+        view can be updated
+        """
         self.live_handler.poll()

=== modified file 'openlp/plugins/presentations/lib/powerpointcontroller.py'
--- openlp/plugins/presentations/lib/powerpointcontroller.py	2010-07-05 22:17:14 +0000
+++ openlp/plugins/presentations/lib/powerpointcontroller.py	2010-07-11 20:27:44 +0000
@@ -97,13 +97,23 @@
             self.process = None
 
         def add_doc(self, name):
+            """
+            Called when a new powerpoint document is opened
+            """
             log.debug(u'Add Doc PowerPoint')
             doc = PowerpointDocument(self, name)
             self.docs.append(doc)
             return doc
 
 class PowerpointDocument(PresentationDocument):
+    """
+    Class which holds information and controls a single presentation
+    """
+    
     def __init__(self, controller, presentation):
+        """
+        Constructor, store information about the file and initialise 
+        """
         log.debug(u'Init Presentation Powerpoint')
         PresentationDocument.__init__(self, controller, presentation)
         self.presentation = None
@@ -111,22 +121,23 @@
     def load_presentation(self):
         """
         Called when a presentation is added to the SlideController.
-        It builds the environment, starts communcations with the background
-        OpenOffice task started earlier.  If OpenOffice is not present is is
-        started.  Once the environment is available the presentation is loaded
-        and started.
+        Opens the PowerPoint file using the process created earlier
 
         ``presentation``
         The file name of the presentations to run.
         """
         log.debug(u'LoadPresentation')
-        if not self.controller.process.Visible:
+        if not self.controller.process or not self.controller.process.Visible:
             self.controller.start_process()
-        self.controller.process.Presentations.Open(self.filepath, False, False,
-            True)
+        try:
+            self.controller.process.Presentations.Open(self.filepath, False, 
+                False, True)
+        except pywintypes.com_error:
+            return False
         self.presentation = self.controller.process.Presentations(
             self.controller.process.Presentations.Count)
         self.create_thumbnails()
+        return True
 
     def create_thumbnails(self):
         """
@@ -139,8 +150,8 @@
         """
         if self.check_thumbnails():
             return
-        self.presentation.Export(os.path.join(self.thumbnailpath, ''), 'png',
-            320, 240)
+        self.presentation.Export(os.path.join(self.get_thumbnail_folder(), ''), 
+            'png', 320, 240)
 
     def close_presentation(self):
         """
@@ -298,4 +309,4 @@
             shape = shapes(idx + 1)
             if shape.HasTextFrame:
                 text += shape.TextFrame.TextRange.Text + '\n'
-        return text
\ No newline at end of file
+        return text

=== modified file 'openlp/plugins/presentations/lib/pptviewcontroller.py'
--- openlp/plugins/presentations/lib/pptviewcontroller.py	2010-07-02 22:18:54 +0000
+++ openlp/plugins/presentations/lib/pptviewcontroller.py	2010-07-11 20:27:44 +0000
@@ -93,13 +93,22 @@
                 self.docs[0].close_presentation()
 
         def add_doc(self, name):
+            """
+            Called when a new powerpoint document is opened
+            """
             log.debug(u'Add Doc PPTView')
             doc = PptviewDocument(self, name)
             self.docs.append(doc)
             return doc
 
 class PptviewDocument(PresentationDocument):
+    """
+    Class which holds information and controls a single presentation
+    """
     def __init__(self, controller, presentation):
+        """
+        Constructor, store information about the file and initialise 
+        """
         log.debug(u'Init Presentation PowerPoint')
         PresentationDocument.__init__(self, controller, presentation)
         self.presentation = None
@@ -117,17 +126,31 @@
         The file name of the presentations to run.
         """
         log.debug(u'LoadPresentation')
-        #if self.pptid >= 0:
-        #    self.close_presentation()
         rendermanager = self.controller.plugin.renderManager
         rect = rendermanager.screens.current[u'size']
         rect = RECT(rect.x(), rect.y(), rect.right(), rect.bottom())
         filepath = str(self.filepath.replace(u'/', u'\\'))
+        if not os.path.isdir(self.get_temp_folder()):
+            os.makedirs(self.get_temp_folder())
         self.pptid = self.controller.process.OpenPPT(filepath, None, rect,
-            str(os.path.join(self.thumbnailpath,
-            self.controller.thumbnailprefix)))
-        if self.pptid:
+            str(self.get_temp_folder()) + '\\slide')
+        if self.pptid >= 0:
+            self.create_thumbnails()
             self.stop_presentation()
+            return True
+        else:
+            return False
+
+    def create_thumbnails(self):
+        """
+        PPTviewLib creates large BMP's, but we want small PNG's for consistency.
+        Convert them here.
+        """
+        if self.check_thumbnails():
+            return
+        for idx in range(self.get_slide_count()):
+            path = u'%s\\slide%s.bmp' % (self.get_temp_folder(), unicode(idx + 1))            
+            self.convert_thumbnail(path, idx + 1)
 
     def close_presentation(self):
         """
@@ -224,17 +247,3 @@
         """
         self.controller.process.PrevStep(self.pptid)
 
-    def get_slide_preview_file(self, slide_no):
-        """
-        Returns an image path containing a preview for the requested slide
-
-        ``slide_no``
-            The slide an image is required for, starting at 1
-        """
-        path = os.path.join(self.thumbnailpath,
-            self.controller.thumbnailprefix + unicode(slide_no) + u'.bmp')
-        if os.path.isfile(path):
-            return path
-        else:
-            return None
-

=== modified file 'openlp/plugins/presentations/lib/presentationcontroller.py'
--- openlp/plugins/presentations/lib/presentationcontroller.py	2010-06-10 13:28:41 +0000
+++ openlp/plugins/presentations/lib/presentationcontroller.py	2010-07-11 20:27:44 +0000
@@ -29,7 +29,7 @@
 
 from PyQt4 import QtCore
 
-from openlp.core.lib import Receiver
+from openlp.core.lib import Receiver, resize_image
 from openlp.core.utils import AppLocation
 
 log = logging.getLogger(__name__)
@@ -63,6 +63,13 @@
     ``plugin``
         The presentationplugin object
 
+    ``supports``
+        The primary native file types this application supports
+
+    ``alsosupports``
+        Other file types the application can import, although not necessarily
+        the first choice due to potential incompatibilities
+        
     **Hook Functions**
 
     ``kill()``
@@ -109,12 +116,16 @@
                     QtCore.Qt.Checked
         else:
             self.enabled = False
-        self.thumbnailroot = os.path.join(
+        self.temp_folder = os.path.join(
+            AppLocation.get_section_data_path(self.settings_section), name)
+        self.thumbnail_folder = os.path.join(
             AppLocation.get_section_data_path(self.settings_section),
-            name, u'thumbnails')
-        self.thumbnailprefix = u'slide'
-        if not os.path.isdir(self.thumbnailroot):
-            os.makedirs(self.thumbnailroot)
+            u'thumbnails')
+        self.thumbnail_prefix = u'slide'
+        if not os.path.isdir(self.thumbnail_folder):
+            os.makedirs(self.thumbnail_folder)
+        if not os.path.isdir(self.temp_folder):
+            os.makedirs(self.temp_folder)
 
     def check_available(self):
         """
@@ -208,14 +219,19 @@
     ``previous_step()``
         Triggers the previous slide on the running presentation
 
-    ``get_slide_preview_file(slide_no)``
+    ``get_thumbnail_path(slide_no, check_exists)``
         Returns a path to an image containing a preview for the requested slide
 
     """
     def __init__(self, controller, name):
+        """
+        Constructor for the PresentationController class
+        """
         self.slidenumber = 0
         self.controller = controller
-        self.store_filename(name)
+        self.filepath = name
+        if not os.path.isdir(self.get_thumbnail_folder()):
+            os.mkdir(self.get_thumbnail_folder())
 
     def load_presentation(self):
         """
@@ -224,9 +240,10 @@
 
         ``presentation``
         The file name of the presentations to the run.
-
+        
+        Returns False if the file could not be opened
         """
-        pass
+        return False
 
     def presentation_deleted(self):
         """
@@ -234,33 +251,37 @@
         a file, e.g. thumbnails
         """
         try:
-            shutil.rmtree(self.thumbnailpath)
+            shutil.rmtree(self.get_thumbnail_folder())
+            shutil.rmtree(self.get_temp_folder())
         except OSError:
             log.exception(u'Failed to delete presentation controller files')
 
-    def store_filename(self, presentation):
-        """
-        Set properties for the filename and thumbnail paths
-        """
-        self.filepath = presentation
-        self.filename = self.get_file_name(presentation)
-        self.thumbnailpath = self.get_thumbnail_path(presentation)
-        if not os.path.isdir(self.thumbnailpath):
-            os.mkdir(self.thumbnailpath)
-
-    def get_file_name(self, presentation):
-        return os.path.split(presentation)[1]
-
-    def get_thumbnail_path(self, presentation):
-        return os.path.join(
-            self.controller.thumbnailroot, self.get_file_name(presentation))
+    def get_file_name(self):
+        """
+        Return just the filename of the presention, without the directory
+        """
+        return os.path.split(self.filepath)[1]
+
+    def get_thumbnail_folder(self):
+        """
+        The location where thumbnail images will be stored
+        """
+        return os.path.join(
+            self.controller.thumbnail_folder, self.get_file_name())
+
+    def get_temp_folder(self):
+        """
+        The location where thumbnail images will be stored
+        """
+        return os.path.join(
+            self.controller.temp_folder, self.get_file_name())
 
     def check_thumbnails(self):
         """
         Returns true if the thumbnail images look to exist and are more
         recent than the powerpoint
         """
-        lastimage = self.get_slide_preview_file(self.get_slide_count())
+        lastimage = self.get_thumbnail_path(self.get_slide_count(), True)
         if not (lastimage and os.path.isfile(lastimage)):
             return False
         imgdate = os.stat(lastimage).st_mtime
@@ -350,16 +371,27 @@
         """
         pass
 
-    def get_slide_preview_file(self, slide_no):
+    def convert_thumbnail(self, file, idx):
+        """
+        Convert the slide image the application made to a standard 320x240
+        .png image.
+        """
+        if self.check_thumbnails():
+            return
+        if os.path.isfile(file):
+            img = resize_image(file, 320, 240)
+            img.save(self.get_thumbnail_path(idx, False))
+            
+    def get_thumbnail_path(self, slide_no, check_exists):
         """
         Returns an image path containing a preview for the requested slide
 
         ``slide_no``
             The slide an image is required for, starting at 1
         """
-        path = os.path.join(self.thumbnailpath,
-            self.controller.thumbnailprefix + unicode(slide_no) + u'.png')
-        if os.path.isfile(path):
+        path = os.path.join(self.get_thumbnail_folder(),
+            self.controller.thumbnail_prefix + unicode(slide_no) + u'.png')
+        if os.path.isfile(path) or not check_exists:
             return path
         else:
             return None

=== modified file 'openlp/plugins/presentations/lib/presentationtab.py'
--- openlp/plugins/presentations/lib/presentationtab.py	2010-06-21 18:28:36 +0000
+++ openlp/plugins/presentations/lib/presentationtab.py	2010-07-11 20:27:44 +0000
@@ -32,10 +32,16 @@
     PresentationsTab is the Presentations settings tab in the settings dialog.
     """
     def __init__(self, title, controllers):
+        """
+        Constructor
+        """
         self.controllers = controllers
         SettingsTab.__init__(self, title)
 
     def setupUi(self):
+        """
+        Create the controls for the settings tab
+        """
         self.setObjectName(u'PresentationTab')
         self.tabTitleVisible = translate('PresentationPlugin.PresentationTab',
             'Presentations')
@@ -89,6 +95,9 @@
         self.PresentationLayout.addWidget(self.PresentationRightWidget)
 
     def retranslateUi(self):
+        """
+        Make any translation changes
+        """
         self.VerseDisplayGroupBox.setTitle(
             translate('PresentationPlugin.PresentationTab',
             'Available Controllers'))
@@ -100,6 +109,9 @@
                 translate('PresentationPlugin.PresentationTab', 'available')))
 
     def load(self):
+        """
+        Load the settings.
+        """
         for key in self.controllers:
             controller = self.controllers[key]
             if controller.available:
@@ -109,6 +121,9 @@
                     QtCore.QVariant(0)).toInt()[0])
 
     def save(self):
+        """
+        Save the settings.
+        """
         for key in self.controllers:
             controller = self.controllers[key]
             checkbox = self.PresenterCheckboxes[controller.name]

=== modified file 'openlp/plugins/presentations/presentationplugin.py'
--- openlp/plugins/presentations/presentationplugin.py	2010-07-10 01:01:14 +0000
+++ openlp/plugins/presentations/presentationplugin.py	2010-07-11 20:27:44 +0000
@@ -33,9 +33,17 @@
 log = logging.getLogger(__name__)
 
 class PresentationPlugin(Plugin):
+    """
+    This plugin allowed a Presentation to be opened, controlled and displayed
+    on the output display. The plugin controls third party applications such
+    as OpenOffice.org Impress, Microsoft PowerPoint and the PowerPoint viewer
+    """
     log = logging.getLogger(u'PresentationPlugin')
 
     def __init__(self, plugin_helpers):
+        """
+        PluginPresentation constructor. 
+        """
         log.debug(u'Initialised')
         self.controllers = {}
         Plugin.__init__(self, u'Presentations', u'1.9.2', plugin_helpers)
@@ -51,6 +59,10 @@
         return PresentationTab(self.name, self.controllers)
 
     def initialise(self):
+        """
+        Initialise the plugin. Determine which controllers are enabled
+        are start their processes.
+        """
         log.info(u'Presentations Initialising')
         Plugin.initialise(self)
         self.insertToolboxItem()
@@ -59,6 +71,10 @@
                 self.controllers[controller].start_process()
 
     def finalise(self):
+        """
+        Finalise the plugin. Ask all the enabled presentation applications
+        to close down their applications and release resources.
+        """
         log.info(u'Plugin Finalise')
         #Ask each controller to tidy up
         for key in self.controllers:
@@ -75,6 +91,10 @@
             self, self.icon, self.name, self.controllers)
 
     def registerControllers(self, controller):
+        """
+        Register each presentation controller (Impress, PPT etc) and
+        store for later use
+        """
         self.controllers[controller.name] = controller
 
     def checkPreConditions(self):
@@ -109,9 +129,12 @@
             return False
 
     def about(self):
+        """
+        Return information about this plugin
+        """
         about_text = translate('PresentationPlugin',
             '<b>Presentation Plugin</b> <br> Delivers '
             'the ability to show presentations using a number of different '
             'programs. The choice of available presentation programs is '
             'available to the user in a drop down box.')
-        return about_text
\ No newline at end of file
+        return about_text


Follow ups