Tim Bentley has proposed merging lp:~trb143/openlp/cleanups2018 into lp:openlp.

Requested reviews:
  OpenLP Core (openlp-core)

For more details, see:
https://code.launchpad.net/~trb143/openlp/cleanups2018/+merge/337118

Remove Powerpoint Viewer
Clean up the logging framework and add to MainWindow
Fix bug in remote API
various minor text fixes. 


lp:~trb143/openlp/cleanups2018 (revision 2825)
https://ci.openlp.io/job/Branch-01-Pull/2440/                          [SUCCESS]
https://ci.openlp.io/job/Branch-02a-Linux-Tests/2341/                  [SUCCESS]
https://ci.openlp.io/job/Branch-02b-macOS-Tests/135/                   [SUCCESS]
https://ci.openlp.io/job/Branch-03a-Build-Source/57/                   [SUCCESS]
https://ci.openlp.io/job/Branch-03b-Build-macOS/55/                    [SUCCESS]
https://ci.openlp.io/job/Branch-04a-Code-Analysis/1519/                [SUCCESS]
https://ci.openlp.io/job/Branch-04b-Test-Coverage/1332/                [SUCCESS]


-- 
Your team OpenLP Core is requested to review the proposed merge of 
lp:~trb143/openlp/cleanups2018 into lp:openlp.
=== modified file 'openlp/core/api/http/wsgiapp.py'
--- openlp/core/api/http/wsgiapp.py	2017-12-29 09:15:48 +0000
+++ openlp/core/api/http/wsgiapp.py	2018-02-03 14:18:52 +0000
@@ -69,6 +69,7 @@
     """
     Create a Response object from response
     """
+    log.debug("in Make response")
     if isinstance(view_result, Response):
         return view_result
     elif isinstance(view_result, tuple):
@@ -88,6 +89,9 @@
     elif isinstance(view_result, str):
         return Response(body=view_result, status=200,
                         content_type='text/html', charset='utf8')
+    else:
+        return Response(body=view_result, status=200,
+                        content_type='text/plain', charset='utf8')
 
 
 def _handle_exception(error):

=== modified file 'openlp/core/app.py'
--- openlp/core/app.py	2018-01-12 18:29:32 +0000
+++ openlp/core/app.py	2018-02-03 14:18:52 +0000
@@ -120,7 +120,8 @@
         self.main_window.show()
         if can_show_splash:
             # now kill the splashscreen
-            self.splash.finish(self.main_window)
+            log.debug('Splashscreen closing')
+            self.splash.close()
             log.debug('Splashscreen closed')
         # make sure Qt really display the splash screen
         self.processEvents()

=== modified file 'openlp/core/common/mixins.py'
--- openlp/core/common/mixins.py	2017-12-29 09:15:48 +0000
+++ openlp/core/common/mixins.py	2018-02-03 14:18:52 +0000
@@ -56,7 +56,10 @@
         def wrapped(*args, **kwargs):
             parent.logger.debug("Entering {function}".format(function=func.__name__))
             try:
-                return func(*args, **kwargs)
+                if len(inspect.signature(func).parameters.values()):
+                    return func(*args, **kwargs)
+                else:
+                    return func(*args)
             except Exception as e:
                 if parent.logger.getEffectiveLevel() <= logging.ERROR:
                     parent.logger.error('Exception in {function} : {error}'.format(function=func.__name__,
@@ -89,6 +92,13 @@
         trace_error_handler(self.logger)
         self.logger.error(message)
 
+    def log_critical(self, message):
+        """
+        Common log critical handler which prints the calling path
+        """
+        trace_error_handler(self.logger)
+        self.logger.critical(message)
+
     def log_exception(self, message):
         """
         Common log exception handler which prints the calling path

=== modified file 'openlp/core/common/settings.py'
--- openlp/core/common/settings.py	2017-12-29 09:15:48 +0000
+++ openlp/core/common/settings.py	2018-02-03 14:18:52 +0000
@@ -259,7 +259,8 @@
         ('media/last directory', 'media/last directory', [(str_to_path, None)]),
         ('songuasge/db password', 'songusage/db password', []),
         ('songuasge/db hostname', 'songusage/db hostname', []),
-        ('songuasge/db database', 'songusage/db database', [])
+        ('songuasge/db database', 'songusage/db database', []),
+        ('presentations / Powerpoint Viewer', '', [])
     ]
 
     @staticmethod

=== modified file 'openlp/core/ui/aboutdialog.py'
--- openlp/core/ui/aboutdialog.py	2017-12-29 09:15:48 +0000
+++ openlp/core/ui/aboutdialog.py	2018-02-03 14:18:52 +0000
@@ -98,7 +98,7 @@
                       'OpenLP is free church presentation software, or lyrics '
                       'projection software, used to display slides of songs, Bible '
                       'verses, videos, images, and even presentations (if '
-                      'Impress, PowerPoint or PowerPoint Viewer is installed) '
+                      'Impress or PowerPoint is installed) '
                       'for church worship using a computer and a data projector.\n'
                       '\n'
                       'Find out more about OpenLP: http://openlp.org/\n'

=== modified file 'openlp/core/ui/mainwindow.py'
--- openlp/core/ui/mainwindow.py	2018-01-20 09:30:30 +0000
+++ openlp/core/ui/mainwindow.py	2018-02-03 14:18:52 +0000
@@ -37,7 +37,7 @@
 from openlp.core.common.actions import ActionList, CategoryOrder
 from openlp.core.common.applocation import AppLocation
 from openlp.core.common.i18n import LanguageManager, UiStrings, translate
-from openlp.core.common.mixins import RegistryProperties
+from openlp.core.common.mixins import LogMixin, RegistryProperties
 from openlp.core.common.path import Path, copyfile, create_paths
 from openlp.core.common.registry import Registry
 from openlp.core.common.settings import Settings
@@ -56,8 +56,6 @@
 from openlp.core.widgets.dialogs import FileDialog
 from openlp.core.widgets.docks import OpenLPDockWidget, MediaDockManager
 
-log = logging.getLogger(__name__)
-
 
 class Ui_MainWindow(object):
     """
@@ -465,12 +463,10 @@
         self.mode_live_item.setStatusTip(translate('OpenLP.MainWindow', 'Use layout that focuses on Live.'))
 
 
-class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, RegistryProperties):
+class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, LogMixin, RegistryProperties):
     """
     The main window.
     """
-    log.info('MainWindow loaded')
-
     def __init__(self):
         """
         This constructor sets up the interface, the various managers, and the plugins.
@@ -557,7 +553,7 @@
         wait_dialog.setCancelButton(None)
         wait_dialog.show()
         for thread_name in self.application.worker_threads.keys():
-            log.debug('Waiting for thread %s', thread_name)
+            self.log_debug('Waiting for thread %s' % thread_name)
             self.application.processEvents()
             thread = self.application.worker_threads[thread_name]['thread']
             worker = self.application.worker_threads[thread_name]['worker']
@@ -595,7 +591,7 @@
         """
         Called on start up to restore the last active media plugin.
         """
-        log.info('Load data from Settings')
+        self.log_info('Load data from Settings')
         if Settings().value('advanced/save current plugin'):
             saved_plugin_id = Settings().value('advanced/current media plugin')
             if saved_plugin_id != -1:
@@ -627,7 +623,6 @@
 
         :param version: The Version to be displayed.
         """
-        log.debug('version_notice')
         version_text = translate('OpenLP.MainWindow', 'Version {new} of OpenLP is now available for download (you are '
                                  'currently running version {current}). \n\nYou can download the latest version from '
                                  'http://openlp.org/.').format(new=version, current=get_version()[u'full'])
@@ -774,7 +769,8 @@
             self.application.splash.close()
         QtWidgets.QMessageBox.information(self, title, message)
 
-    def on_help_web_site_clicked(self):
+    @staticmethod
+    def on_help_web_site_clicked():
         """
         Load the OpenLP website
         """
@@ -891,7 +887,7 @@
         settings = Settings()
         import_settings = Settings(str(temp_config_path), Settings.IniFormat)
 
-        log.info('hook upgrade_plugin_settings')
+        self.log_info('hook upgrade_plugin_settings')
         self.plugin_manager.hook_upgrade_plugin_settings(import_settings)
         # Upgrade settings to prepare the import.
         if import_settings.can_upgrade():
@@ -929,7 +925,8 @@
                 value = import_settings.value(section_key)
             except KeyError:
                 value = None
-                log.warning('The key "{key}" does not exist (anymore), so it will be skipped.'.format(key=section_key))
+                self.log_warning('The key "{key}" does not exist (anymore), so it will be skipped.'.
+                                 format(key=section_key))
             if value is not None:
                 settings.setValue('{key}'.format(key=section_key), value)
         now = datetime.now()
@@ -1013,7 +1010,6 @@
         """
         The screen has changed so we have to update components such as the renderer.
         """
-        log.debug('screen_changed')
         self.application.set_busy_cursor()
         self.image_manager.update_display()
         self.renderer.update_display()
@@ -1076,7 +1072,7 @@
             if Settings().value('advanced/save current plugin'):
                 Settings().setValue('advanced/current media plugin', self.media_tool_box.currentIndex())
         # Call the cleanup method to shutdown plugins.
-        log.info('cleanup plugins')
+        self.log_info('cleanup plugins')
         self.plugin_manager.finalise_plugins()
         if save_settings:
             # Save settings
@@ -1216,7 +1212,6 @@
         """
         Load the main window settings.
         """
-        log.debug('Loading QSettings')
         settings = Settings()
         # Remove obsolete entries.
         settings.remove('custom slide')
@@ -1243,7 +1238,6 @@
         # Exit if we just did a settings import.
         if self.settings_imported:
             return
-        log.debug('Saving QSettings')
         settings = Settings()
         settings.beginGroup(self.general_settings_section)
         settings.setValue('recent files', self.recent_files)
@@ -1268,7 +1262,7 @@
             if not recent_path.is_file():
                 continue
             count += 1
-            log.debug('Recent file name: {name}'.format(name=recent_path))
+            self.log_debug('Recent file name: {name}'.format(name=recent_path))
             action = create_action(self, '',
                                    text='&{n} {name}'.format(n=count, name=recent_path.name),
                                    data=recent_path, triggers=self.service_manager_contents.on_recent_service_clicked)
@@ -1350,21 +1344,21 @@
         """
         Change the data directory.
         """
-        log.info('Changing data path to {newpath}'.format(newpath=self.new_data_path))
+        self.log_info('Changing data path to {newpath}'.format(newpath=self.new_data_path))
         old_data_path = AppLocation.get_data_path()
         # Copy OpenLP data to new location if requested.
         self.application.set_busy_cursor()
         if self.copy_data:
-            log.info('Copying data to new path')
+            self.log_info('Copying data to new path')
             try:
                 self.show_status_message(
                     translate('OpenLP.MainWindow', 'Copying OpenLP data to new data directory location - {path} '
                               '- Please wait for copy to finish').format(path=self.new_data_path))
                 dir_util.copy_tree(str(old_data_path), str(self.new_data_path))
-                log.info('Copy successful')
+                self.log_info('Copy successful')
             except (OSError, DistutilsFileError) as why:
                 self.application.set_normal_cursor()
-                log.exception('Data copy failed {err}'.format(err=str(why)))
+                self.log_exception('Data copy failed {err}'.format(err=str(why)))
                 err_text = translate('OpenLP.MainWindow',
                                      'OpenLP Data directory copy failed\n\n{err}').format(err=str(why)),
                 QtWidgets.QMessageBox.critical(self, translate('OpenLP.MainWindow', 'New Data Directory Error'),
@@ -1372,7 +1366,7 @@
                                                QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok))
                 return False
         else:
-            log.info('No data copy requested')
+            self.log_info('No data copy requested')
         # Change the location of data directory in config file.
         settings = QtCore.QSettings()
         settings.setValue('advanced/data path', self.new_data_path)

=== modified file 'openlp/core/ui/servicemanager.py'
--- openlp/core/ui/servicemanager.py	2018-01-22 21:37:00 +0000
+++ openlp/core/ui/servicemanager.py	2018-02-03 14:18:52 +0000
@@ -302,7 +302,7 @@
 class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixin, RegistryProperties):
     """
     Manages the services. This involves taking text strings from plugins and adding them to the service. This service
-    can then be zipped up with all the resources used into one OSZ or oszl file for use on any OpenLP v2 installation.
+    can then be zipped up with all the resources used into one OSZ or OSZL file for use on any OpenLP installation.
     Also handles the UI tasks of moving things up and down etc.
     """
     servicemanager_set_item = QtCore.pyqtSignal(int)
@@ -415,10 +415,9 @@
                 if suffix not in self.suffixes:
                     self.suffixes.append(suffix)
 
-    def on_new_service_clicked(self, field=None):
+    def on_new_service_clicked(self):
         """
         Create a new service.
-        :param field:
         """
         if self.is_modified():
             result = self.save_modified_service()
@@ -466,10 +465,9 @@
                                               QtWidgets.QMessageBox.Save | QtWidgets.QMessageBox.Discard |
                                               QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Save)
 
-    def on_recent_service_clicked(self, field=None):
+    def on_recent_service_clicked(self):
         """
         Load a recent file as the service triggered by mainwindow recent service list.
-        :param field:
         """
         if self.is_modified():
             result = self.save_modified_service()
@@ -608,7 +606,7 @@
         self.set_modified(False)
         return True
 
-    def save_file_as(self, field=None):
+    def save_file_as(self):
         """
         Get a file name and then call :func:`ServiceManager.save_file` to save the file.
         """
@@ -660,10 +658,9 @@
         self.set_file_name(file_path)
         self.decide_save_method()
 
-    def decide_save_method(self, field=None):
+    def decide_save_method(self):
         """
         Determine which type of save method to use.
-        :param field:
         """
         if not self.file_name():
             return self.save_file_as()
@@ -824,10 +821,9 @@
                 theme_action.setChecked(True)
         self.menu.exec(self.service_manager_list.mapToGlobal(point))
 
-    def on_service_item_note_form(self, field=None):
+    def on_service_item_note_form(self):
         """
         Allow the service note to be edited
-        :param field:
         """
         item = self.find_service_item()[0]
         self.service_note_form.text_edit.setPlainText(self.service_items[item]['service_item'].notes)
@@ -836,21 +832,18 @@
             self.repaint_service_list(item, -1)
             self.set_modified()
 
-    def on_start_time_form(self, field=None):
+    def on_start_time_form(self):
         """
         Opens a dialog to type in service item notes.
-        :param field:
         """
         item = self.find_service_item()[0]
         self.start_time_form.item = self.service_items[item]
         if self.start_time_form.exec():
             self.repaint_service_list(item, -1)
 
-    def toggle_auto_play_slides_once(self, field=None):
+    def toggle_auto_play_slides_once(self):
         """
         Toggle Auto play slide once. Inverts auto play once option for the item
-
-        :param field:
         """
         item = self.find_service_item()[0]
         service_item = self.service_items[item]['service_item']
@@ -863,11 +856,9 @@
                 self.main_window.general_settings_section + '/loop delay')
         self.set_modified()
 
-    def toggle_auto_play_slides_loop(self, field=None):
+    def toggle_auto_play_slides_loop(self):
         """
         Toggle Auto play slide loop.
-
-        :param field:
         """
         item = self.find_service_item()[0]
         service_item = self.service_items[item]['service_item']
@@ -880,10 +871,9 @@
                 self.main_window.general_settings_section + '/loop delay')
         self.set_modified()
 
-    def on_timed_slide_interval(self, field=None):
+    def on_timed_slide_interval(self):
         """
         Shows input dialog for enter interval in seconds for delay
-        :param field:
         """
         item = self.find_service_item()[0]
         service_item = self.service_items[item]['service_item']
@@ -906,7 +896,7 @@
             service_item.auto_play_slides_once = False
         self.set_modified()
 
-    def on_auto_start(self, field=None):
+    def on_auto_start(self):
         """
         Toggles to Auto Start Setting.
         """
@@ -914,10 +904,9 @@
         self.service_items[item]['service_item'].will_auto_start = \
             not self.service_items[item]['service_item'].will_auto_start
 
-    def on_service_item_edit_form(self, field=None):
+    def on_service_item_edit_form(self):
         """
         Opens a dialog to edit the service item and update the service display if changes are saved.
-        :param field:
         """
         item = self.find_service_item()[0]
         self.service_item_edit_form.set_service_item(self.service_items[item]['service_item'])
@@ -990,11 +979,9 @@
                 prev_item_last_slide = service_iterator.value()
             service_iterator += 1
 
-    def on_set_item(self, message, field=None):
+    def on_set_item(self, message):
         """
         Called by a signal to select a specific item and make it live usually from remote.
-
-        :param field:
         :param message: The data passed in from a remove message
         """
         self.log_debug(message)
@@ -1060,10 +1047,9 @@
             self.service_manager.collapsed(item.parent())
             self.service_manager_list.setCurrentItem(item.parent())
 
-    def on_collapse_all(self, field=None):
+    def on_collapse_all(self):
         """
         Collapse all the service items.
-        :param field:
         """
         for item in self.service_items:
             item['expanded'] = False
@@ -1080,10 +1066,9 @@
         if item.childCount():
             self.service_items[pos - 1]['expanded'] = False
 
-    def on_expand_all(self, field=None):
+    def on_expand_all(self):
         """
         Collapse all the service items.
-        :param field:
         """
         for item in self.service_items:
             item['expanded'] = True
@@ -1100,10 +1085,9 @@
         if item.childCount():
             self.service_items[pos - 1]['expanded'] = True
 
-    def on_service_top(self, field=None):
+    def on_service_top(self):
         """
         Move the current ServiceItem to the top of the list.
-        :param field:
         """
         item, child = self.find_service_item()
         if item < len(self.service_items) and item != -1:
@@ -1113,10 +1097,9 @@
             self.repaint_service_list(0, child)
             self.set_modified()
 
-    def on_service_up(self, field=None):
+    def on_service_up(self):
         """
         Move the current ServiceItem one position up in the list.
-        :param field:
         """
         item, child = self.find_service_item()
         if item > 0:
@@ -1126,10 +1109,9 @@
             self.repaint_service_list(item - 1, child)
             self.set_modified()
 
-    def on_service_down(self, field=None):
+    def on_service_down(self):
         """
         Move the current ServiceItem one position down in the list.
-        :param field:
         """
         item, child = self.find_service_item()
         if item < len(self.service_items) and item != -1:
@@ -1139,10 +1121,9 @@
             self.repaint_service_list(item + 1, child)
             self.set_modified()
 
-    def on_service_end(self, field=None):
+    def on_service_end(self):
         """
         Move the current ServiceItem to the bottom of the list.
-        :param field:
         """
         item, child = self.find_service_item()
         if item < len(self.service_items) and item != -1:
@@ -1152,7 +1133,7 @@
             self.repaint_service_list(len(self.service_items) - 1, child)
             self.set_modified()
 
-    def on_delete_from_service(self, field=None):
+    def on_delete_from_service(self):
         """
         Remove the current ServiceItem from the list.
         :param field:
@@ -1378,7 +1359,7 @@
         self.drop_position = -1
         self.set_modified()
 
-    def make_preview(self, field=None):
+    def make_preview(self):
         """
         Send the current item to the Preview slide controller
         :param field:
@@ -1403,7 +1384,7 @@
         else:
             return self.service_items[item]['service_item']
 
-    def on_double_click_live(self, field=None):
+    def on_double_click_live(self):
         """
         Send the current item to the Live slide controller but triggered by a tablewidget click event.
         :param field:
@@ -1411,7 +1392,7 @@
         self.list_double_clicked = True
         self.make_live()
 
-    def on_single_click_preview(self, field=None):
+    def on_single_click_preview(self):
         """
         If single click previewing is enabled, and triggered by a tablewidget click event,
         start a timeout to verify a double-click hasn't triggered.
@@ -1463,7 +1444,7 @@
                                                  'is missing or inactive'))
         self.application.set_normal_cursor()
 
-    def remote_edit(self, field=None):
+    def remote_edit(self):
         """
         Triggers a remote edit to a plugin to allow item to be edited.
         :param field:
@@ -1475,7 +1456,7 @@
             if new_item:
                 self.add_service_item(new_item, replace=True)
 
-    def on_service_item_rename(self, field=None):
+    def on_service_item_rename(self):
         """
         Opens a dialog to rename the service item.
 
@@ -1493,7 +1474,7 @@
             self.repaint_service_list(item, -1)
             self.set_modified()
 
-    def create_custom(self, field=None):
+    def create_custom(self):
         """
         Saves the current text item as a custom slide
         :param field:
@@ -1613,7 +1594,7 @@
         self.renderer.set_service_theme(self.service_theme)
         self.regenerate_service_items()
 
-    def on_theme_change_action(self, field=None):
+    def on_theme_change_action(self):
         """
         Handles theme change events
 

=== modified file 'openlp/core/ui/slidecontroller.py'
--- openlp/core/ui/slidecontroller.py	2017-12-29 09:15:48 +0000
+++ openlp/core/ui/slidecontroller.py	2018-02-03 14:18:52 +0000
@@ -545,14 +545,14 @@
             self.on_theme_display(False)
             self.on_hide_display(False)
 
-    def service_previous(self, field=None):
+    def service_previous(self):
         """
         Live event to select the previous service item from the service manager.
         """
         self.keypress_queue.append(ServiceItemAction.Previous)
         self._process_queue()
 
-    def service_next(self, field=None):
+    def service_next(self):
         """
         Live event to select the next service item from the service manager.
         """
@@ -1103,7 +1103,7 @@
             else:
                 Registry().execute('live_display_show')
 
-    def on_slide_selected(self, field=None):
+    def on_slide_selected(self):
         """
         Slide selected in controller
         Note for some reason a dummy field is required.  Nothing is passed!
@@ -1244,7 +1244,7 @@
             self.preview_widget.change_slide(row)
             self.slide_selected()
 
-    def on_slide_selected_previous(self, field=None):
+    def on_slide_selected_previous(self):
         """
         Go to the previous slide.
         """
@@ -1372,7 +1372,7 @@
         if event.timerId() == self.timer_id:
             self.on_slide_selected_next(self.play_slides_loop.isChecked())
 
-    def on_edit_song(self, field=None):
+    def on_edit_song(self):
         """
         From the preview display requires the service Item to be editied
         """
@@ -1381,16 +1381,16 @@
         if new_item:
             self.add_service_item(new_item)
 
-    def on_preview_add_to_service(self, field=None):
+    def on_preview_add_to_service(self):
         """
         From the preview display request the Item to be added to service
         """
         if self.service_item:
             self.service_manager.add_service_item(self.service_item)
 
-    def on_preview_double_click(self, field=None):
+    def on_preview_double_click(self):
         """
-        Triggered when a preview slide item is doubleclicked
+        Triggered when a preview slide item is double clicked
         """
         if self.service_item:
             if Settings().value('advanced/double click live') and Settings().value('core/auto unblank'):

=== modified file 'openlp/plugins/bibles/lib/mediaitem.py'
--- openlp/plugins/bibles/lib/mediaitem.py	2017-12-29 09:15:48 +0000
+++ openlp/plugins/bibles/lib/mediaitem.py	2018-02-03 14:18:52 +0000
@@ -384,7 +384,7 @@
         This initialises the given bible, which means that its book names and their chapter numbers is added to the
         combo boxes on the 'Select' Tab. This is not of any importance of the 'Search' Tab.
 
-        :param last_book_id: The "book reference id" of the book which is chosen at the moment. (int)
+        :param last_book: The "book reference id" of the book which is chosen at the moment. (int)
         :return: None
         """
         log.debug('initialise_advanced_bible {bible}, {ref}'.format(bible=self.bible, ref=last_book))
@@ -574,6 +574,7 @@
         Update the second bible. If changing from single to dual bible modes as if the user wants to clear the search
         results, if not revert to the previously selected bible
 
+        :param: selection not required by part of the signature
         :return: None
         """
         new_selection = self.second_combo_box.currentData()
@@ -1005,14 +1006,17 @@
         }[self.settings.display_style]
         return '{{su}}{bracket[0]}{verse_text}{bracket[1]}{{/su}}&nbsp;'.format(verse_text=verse_text, bracket=bracket)
 
-    def search(self, string, showError):
+    def search(self, string, show_error=True):
         """
         Search for some Bible verses (by reference).
+        :param string: search string
+        :param show_error: do we show the error
+        :return: the results of the search
         """
         if self.bible is None:
             return []
         reference = self.plugin.manager.parse_ref(self.bible.name, string)
-        search_results = self.plugin.manager.get_verses(self.bible.name, reference, showError)
+        search_results = self.plugin.manager.get_verses(self.bible.name, reference, show_error)
         if search_results:
             verse_text = ' '.join([verse.text for verse in search_results])
             return [[string, verse_text]]

=== removed file 'openlp/plugins/presentations/lib/pptviewcontroller.py'
--- openlp/plugins/presentations/lib/pptviewcontroller.py	2017-12-29 09:15:48 +0000
+++ openlp/plugins/presentations/lib/pptviewcontroller.py	1970-01-01 00:00:00 +0000
@@ -1,307 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection                                      #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2018 OpenLP Developers                                   #
-# --------------------------------------------------------------------------- #
-# 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                          #
-###############################################################################
-import logging
-import re
-import zipfile
-from xml.etree import ElementTree
-
-from openlp.core.common import is_win
-from openlp.core.common.applocation import AppLocation
-from openlp.core.display.screens import ScreenList
-from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument
-
-if is_win():
-    from ctypes import cdll
-    from ctypes.wintypes import RECT
-
-log = logging.getLogger(__name__)
-
-
-class PptviewController(PresentationController):
-    """
-    Class to control interactions with PowerPoint Viewer Presentations. It creates the runtime Environment , Loads the
-    and Closes the Presentation. As well as triggering the correct activities based on the users input
-    """
-    log.info('PPTViewController loaded')
-
-    def __init__(self, plugin):
-        """
-        Initialise the class
-        """
-        log.debug('Initialising')
-        self.process = None
-        super(PptviewController, self).__init__(plugin, 'Powerpoint Viewer', PptviewDocument)
-        self.supports = ['ppt', 'pps', 'pptx', 'ppsx', 'pptm']
-
-    def check_available(self):
-        """
-        PPT Viewer is able to run on this machine.
-        """
-        log.debug('check_available')
-        if not is_win():
-            return False
-        return self.check_installed()
-
-    if is_win():
-        def check_installed(self):
-            """
-            Check the viewer is installed.
-            """
-            log.debug('Check installed')
-            try:
-                self.start_process()
-                return self.process.CheckInstalled()
-            except OSError:
-                return False
-
-        def start_process(self):
-            """
-            Loads the PPTVIEWLIB library.
-            """
-            if self.process:
-                return
-            log.debug('start PPTView')
-            dll_path = AppLocation.get_directory(AppLocation.AppDir) \
-                / 'plugins' / 'presentations' / 'lib' / 'pptviewlib' / 'pptviewlib.dll'
-            self.process = cdll.LoadLibrary(str(dll_path))
-            if log.isEnabledFor(logging.DEBUG):
-                self.process.SetDebug(1)
-
-        def kill(self):
-            """
-            Called at system exit to clean up any running presentations
-            """
-            log.debug('Kill pptviewer')
-            while self.docs:
-                self.docs[0].close_presentation()
-
-
-class PptviewDocument(PresentationDocument):
-    """
-    Class which holds information and controls a single presentation.
-    """
-    def __init__(self, controller, document_path):
-        """
-        Constructor, store information about the file and initialise.
-
-        :param openlp.core.common.path.Path document_path: File path to the document to load
-        :rtype: None
-        """
-        log.debug('Init Presentation PowerPoint')
-        super().__init__(controller, document_path)
-        self.presentation = None
-        self.ppt_id = None
-        self.blanked = False
-        self.hidden = False
-
-    def load_presentation(self):
-        """
-        Called when a presentation is added to the SlideController. It builds the environment, starts communication with
-        the background PptView task started earlier.
-        """
-        log.debug('LoadPresentation')
-        temp_path = self.get_temp_folder()
-        size = ScreenList().current['size']
-        rect = RECT(size.x(), size.y(), size.right(), size.bottom())
-        preview_path = temp_path / 'slide'
-        # Ensure that the paths are null terminated
-        file_path_utf16 = str(self.file_path).encode('utf-16-le') + b'\0'
-        preview_path_utf16 = str(preview_path).encode('utf-16-le') + b'\0'
-        if not temp_path.is_dir():
-            temp_path.mkdir(parents=True)
-        self.ppt_id = self.controller.process.OpenPPT(file_path_utf16, None, rect, preview_path_utf16)
-        if self.ppt_id >= 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.
-        """
-        log.debug('create_thumbnails')
-        if self.check_thumbnails():
-            return
-        log.debug('create_thumbnails proceeding')
-        for idx in range(self.get_slide_count()):
-            path = self.get_temp_folder() / 'slide{index:d}.bmp'.format(index=idx + 1)
-            self.convert_thumbnail(path, idx + 1)
-
-    def create_titles_and_notes(self):
-        """
-        Extracts the titles and notes from the zipped file
-        and writes the list of titles (one per slide)
-        to 'titles.txt'
-        and the notes to 'slideNotes[x].txt'
-        in the thumbnails directory
-        """
-        titles = None
-        notes = None
-        # let's make sure we have a valid zipped presentation
-        if self.file_path.exists() and zipfile.is_zipfile(str(self.file_path)):
-            namespaces = {"p": "http://schemas.openxmlformats.org/presentationml/2006/main";,
-                          "a": "http://schemas.openxmlformats.org/drawingml/2006/main"}
-            # open the file
-            with zipfile.ZipFile(str(self.file_path)) as zip_file:
-                # find the presentation.xml to get the slide count
-                with zip_file.open('ppt/presentation.xml') as pres:
-                    tree = ElementTree.parse(pres)
-                nodes = tree.getroot().findall(".//p:sldIdLst/p:sldId", namespaces=namespaces)
-                # initialize the lists
-                titles = ['' for i in range(len(nodes))]
-                notes = ['' for i in range(len(nodes))]
-                # loop thru the file list to find slides and notes
-                for zip_info in zip_file.infolist():
-                    node_type = ''
-                    index = -1
-                    list_to_add = None
-                    # check if it is a slide
-                    match = re.search(r'slides/slide(.+)\.xml', zip_info.filename)
-                    if match:
-                        index = int(match.group(1)) - 1
-                        node_type = 'ctrTitle'
-                        list_to_add = titles
-                    # or a note
-                    match = re.search(r'notesSlides/notesSlide(.+)\.xml', zip_info.filename)
-                    if match:
-                        index = int(match.group(1)) - 1
-                        node_type = 'body'
-                        list_to_add = notes
-                    # if it is one of our files, index shouldn't be -1
-                    if index >= 0:
-                        with zip_file.open(zip_info) as zipped_file:
-                            tree = ElementTree.parse(zipped_file)
-                        text = ''
-                        nodes = tree.getroot().findall(".//p:ph[@type='" + node_type + "']../../..//p:txBody//a:t",
-                                                       namespaces=namespaces)
-                        # if we found any content
-                        if nodes and len(nodes) > 0:
-                            for node in nodes:
-                                if len(text) > 0:
-                                    text += '\n'
-                                text += node.text
-                        # Let's remove the \n from the titles and
-                        # just add one at the end
-                        if node_type == 'ctrTitle':
-                            text = text.replace('\n', ' ').replace('\x0b', ' ') + '\n'
-                        list_to_add[index] = text
-        # now let's write the files
-        self.save_titles_and_notes(titles, notes)
-
-    def close_presentation(self):
-        """
-        Close presentation and clean up objects. Triggered by new object being added to SlideController or OpenLP being
-        shut down.
-        """
-        log.debug('ClosePresentation')
-        if self.controller.process:
-            self.controller.process.ClosePPT(self.ppt_id)
-            self.ppt_id = -1
-        self.controller.remove_doc(self)
-
-    def is_loaded(self):
-        """
-        Returns true if a presentation is loaded.
-        """
-        if self.ppt_id < 0:
-            return False
-        if self.get_slide_count() < 0:
-            return False
-        return True
-
-    def is_active(self):
-        """
-        Returns true if a presentation is currently active.
-        """
-        return self.is_loaded() and not self.hidden
-
-    def blank_screen(self):
-        """
-        Blanks the screen.
-        """
-        self.controller.process.Blank(self.ppt_id)
-        self.blanked = True
-
-    def unblank_screen(self):
-        """
-        Unblanks (restores) the presentation.
-        """
-        self.controller.process.Unblank(self.ppt_id)
-        self.blanked = False
-
-    def is_blank(self):
-        """
-        Returns true if screen is blank.
-        """
-        log.debug('is blank OpenOffice')
-        return self.blanked
-
-    def stop_presentation(self):
-        """
-        Stops the current presentation and hides the output.
-        """
-        self.hidden = True
-        self.controller.process.Stop(self.ppt_id)
-
-    def start_presentation(self):
-        """
-        Starts a presentation from the beginning.
-        """
-        if self.hidden:
-            self.hidden = False
-            self.controller.process.Resume(self.ppt_id)
-        else:
-            self.controller.process.RestartShow(self.ppt_id)
-
-    def get_slide_number(self):
-        """
-        Returns the current slide number.
-        """
-        return self.controller.process.GetCurrentSlide(self.ppt_id)
-
-    def get_slide_count(self):
-        """
-        Returns total number of slides.
-        """
-        return self.controller.process.GetSlideCount(self.ppt_id)
-
-    def goto_slide(self, slide_no):
-        """
-        Moves to a specific slide in the presentation.
-
-        :param slide_no: The slide the text is required for, starting at 1
-        """
-        self.controller.process.GotoSlide(self.ppt_id, slide_no)
-
-    def next_step(self):
-        """
-        Triggers the next effect of slide on the running presentation.
-        """
-        self.controller.process.NextStep(self.ppt_id)
-
-    def previous_step(self):
-        """
-        Triggers the previous slide on the running presentation.
-        """
-        self.controller.process.PrevStep(self.ppt_id)

=== removed directory 'openlp/plugins/presentations/lib/pptviewlib'
=== removed file 'openlp/plugins/presentations/lib/pptviewlib/README.TXT'
--- openlp/plugins/presentations/lib/pptviewlib/README.TXT	2017-12-29 09:15:48 +0000
+++ openlp/plugins/presentations/lib/pptviewlib/README.TXT	1970-01-01 00:00:00 +0000
@@ -1,121 +0,0 @@
-
-PPTVIEWLIB - Control PowerPoint Viewer 2003/2007 (for openlp.org)
-Copyright (C) 2008-2018 Jonathan Corwin (j...@corwin.co.uk)
-
-This library wrappers the free Microsoft PowerPoint Viewer (2003/2007) program,
-allowing it to be more easily controlled from another program.
-
-The PowerPoint Viewer must already be installed on the destination machine, and is
-freely available at microsoft.com.
-
-The full Microsoft Office PowerPoint and PowerPoint Viewer 97 have a COM interface allowing
-automation. This ability was removed from the 2003+ viewer offerings.
-
-To developers: I am not a C/C++ or Win32 API programmer as you can probably tell.
-The code and API of this DLL could certainly do with some tidying up, and the
-error trapping, where it exists, is very basic. I'll happily accept patches!
-
-This library is covered by the GPL (http://www.gnu.org/licenses/)
-It is NOT covered by the LGPL, so can only be used in GPL compatable programs.
-(http://www.gnu.org/licenses/why-not-lgpl.html)
-
-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);
-    Returns TRUE if PowerPointViewer is installed. FALSE if not.
-
-int OpenPPT(char *filename, HWND hParentWnd, RECT rect, char *previewpath);
-
-    Opens the PowerPoint file, counts the number of slides, sizes and positions accordingly
-    and creates preview images of each slide. Note PowerPoint Viewer only allows the
-    slideshow to be resized whilst it is being loaded. It can be moved at any time however.
-
-    The only way to count the number of slides is to step through the entire show. Therefore
-    there will be a delay whilst opening large presentations for the first time.
-    For pre XP/2003 systems, the slideshow will flicker as the screen snapshots are taken.
-
-    filename:    The PowerPoint file to be opened. Full path
-    hParentWnd:  The window which will become the parent of the slideshow window.
-                 Can be NULL.
-    rect:        The location/dimensions of the slideshow window.
-                 If all properties of this structure are zero, the dimensions of the hParentWnd
-                 are used.
-    previewpath  If specified, the prefix to use for snapshot images of each slide, in the
-                 form: previewpath + n + ".bmp", where n is the slide number.
-                 A file called previewpath + "info.txt" will also be created containing information
-                 about the PPT file, to speed up future openings of the unmodified file.
-                 Note it is up the calling program to directly access these images if they
-                 are required.
-
-    RETURNS:     An unique identifier to pass to other methods in this library.
-                 If < 0, then the PPT failed to open.
-                 If >=0, ClosePPT must be called when the PPT is no longer being used
-                 or when the calling program is closed to release resources/hooks.
-
-void ClosePPT(int id);
-     Closes the presentation, releasing any resources and hooks.
-
-     id: The value returned from OpenPPT.
-
-int GetCurrentSlide(int id);
-    Returns the current slide number (from 1)
-
-    id: The value returned from OpenPPT.
-
-int GetSlideCount(int id);
-    Returns the total number of slides.
-
-    id: The value returned from OpenPPT.
-
-void NextStep(int id);
-    Advances one step (animation) through the slideshow.
-
-    id: The value returned from OpenPPT.
-
-void PrevStep(int id);
-    Goes backwards one step (animation) through the slideshow.
-
-    id: The value returned from OpenPPT.
-
-void GotoSlide(int id, int slideno);
-    Goes directly to a specific slide in the slideshow
-
-    id: The value returned from OpenPPT.
-    slideno: The number of the slide (from 1) to go directly to.
-
-    If the slide has already been displayed, then the completed slide with animations performed
-    will be shown. This is how the PowerPoint Viewer works so have no control over this.
-
-void RestartShow(int id);
-    Restarts the show from the beginning. To reset animations, behind the scenes it
-    has to travel to the end and step backwards though the entire show. Therefore
-    for large presentations there might be a delay.
-
-    id: The value returned from OpenPPT.
-
-void Blank(int id);
-    Blanks the screen, colour black.
-
-    id: The value returned from OpenPPT.
-
-void Unblank(int id)
-    Unblanks the screen, restoring it to it's pre-blank state.
-
-    id: The value returned from OpenPPT.
-
-void Stop(int id)
-    Moves the slideshow off the screen. (There is no concept of stop show in the PowerPoint Viewer)
-
-    id: The value returned from OpenPPT.
-
-void Resume(int id)
-    Moves the slideshow display back onto the screen following a Stop()
-
-    id: The value returned from OpenPPT.
-

=== removed file 'openlp/plugins/presentations/lib/pptviewlib/ppttest.py'
--- openlp/plugins/presentations/lib/pptviewlib/ppttest.py	2017-12-29 09:15:48 +0000
+++ openlp/plugins/presentations/lib/pptviewlib/ppttest.py	1970-01-01 00:00:00 +0000
@@ -1,210 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection                                      #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2018 OpenLP Developers                                   #
-# --------------------------------------------------------------------------- #
-# 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                          #
-###############################################################################
-
-import sys
-from ctypes import *
-from ctypes.wintypes import RECT
-
-from PyQt5 import QtWidgets
-
-
-class PPTViewer(QtWidgets.QWidget):
-    """
-    Standalone Test Harness for the pptviewlib library
-    """
-    def __init__(self, parent=None):
-        super(PPTViewer, self).__init__(parent)
-        self.pptid = -1
-        self.setWindowTitle('PowerPoint Viewer Test')
-
-        ppt_label = QtWidgets.QLabel('Open PowerPoint file')
-        slide_label = QtWidgets.QLabel('Go to slide #')
-        self.pptEdit = QtWidgets.QLineEdit()
-        self.slideEdit = QtWidgets.QLineEdit()
-        x_label = QtWidgets.QLabel('X pos')
-        y_label = QtWidgets.QLabel('Y pos')
-        width_label = QtWidgets.QLabel('Width')
-        height_label = QtWidgets.QLabel('Height')
-        self.xEdit = QtWidgets.QLineEdit('100')
-        self.yEdit = QtWidgets.QLineEdit('100')
-        self.widthEdit = QtWidgets.QLineEdit('900')
-        self.heightEdit = QtWidgets.QLineEdit('700')
-        self.total = QtWidgets.QLabel()
-        ppt_btn = QtWidgets.QPushButton('Open')
-        ppt_dlg_btn = QtWidgets.QPushButton('...')
-        folder_label = QtWidgets.QLabel('Slide .bmp path')
-        self.folderEdit = QtWidgets.QLineEdit('slide')
-        slide_btn = QtWidgets.QPushButton('Go')
-        prev = QtWidgets.QPushButton('Prev')
-        next = QtWidgets.QPushButton('Next')
-        blank = QtWidgets.QPushButton('Blank')
-        unblank = QtWidgets.QPushButton('Unblank')
-        restart = QtWidgets.QPushButton('Restart')
-        close = QtWidgets.QPushButton('Close')
-        resume = QtWidgets.QPushButton('Resume')
-        stop = QtWidgets.QPushButton('Stop')
-        grid = QtWidgets.QGridLayout()
-        row = 0
-        grid.addWidget(folder_label, 0, 0)
-        grid.addWidget(self.folderEdit, 0, 1)
-        row += 1
-        grid.addWidget(x_label, row, 0)
-        grid.addWidget(self.xEdit, row, 1)
-        grid.addWidget(y_label, row, 2)
-        grid.addWidget(self.yEdit, row, 3)
-        row += 1
-        grid.addWidget(width_label, row, 0)
-        grid.addWidget(self.widthEdit, row, 1)
-        grid.addWidget(height_label, row, 2)
-        grid.addWidget(self.heightEdit, row, 3)
-        row += 1
-        grid.addWidget(ppt_label, row, 0)
-        grid.addWidget(self.pptEdit, row, 1)
-        grid.addWidget(ppt_dlg_btn, row, 2)
-        grid.addWidget(ppt_btn, row, 3)
-        row += 1
-        grid.addWidget(slide_label, row, 0)
-        grid.addWidget(self.slideEdit, row, 1)
-        grid.addWidget(slide_btn, row, 2)
-        row += 1
-        grid.addWidget(prev, row, 0)
-        grid.addWidget(next, row, 1)
-        row += 1
-        grid.addWidget(blank, row, 0)
-        grid.addWidget(unblank, row, 1)
-        row += 1
-        grid.addWidget(restart, row, 0)
-        grid.addWidget(close, row, 1)
-        row += 1
-        grid.addWidget(stop, row, 0)
-        grid.addWidget(resume, row, 1)
-        ppt_btn.clicked.connect(self.openClick)
-        ppt_dlg_btn.clicked.connect(self.openDialog)
-        slide_btn.clicked.connect(self.gotoClick)
-        prev.clicked.connect(self.prevClick)
-        next.clicked.connect(self.nextClick)
-        blank.clicked.connect(self.blankClick)
-        unblank.clicked.connect(self.unblankClick)
-        restart.clicked.connect(self.restartClick)
-        close.clicked.connect(self.closeClick)
-        stop.clicked.connect(self.stopClick)
-        resume.clicked.connect(self.resumeClick)
-        self.setLayout(grid)
-        self.resize(300, 150)
-
-    def prevClick(self):
-        if self.pptid < 0:
-            return
-        self.pptdll.PrevStep(self.pptid)
-        self.updateCurrSlide()
-        app.processEvents()
-
-    def nextClick(self):
-        if self.pptid < 0:
-            return
-        self.pptdll.NextStep(self.pptid)
-        self.updateCurrSlide()
-        app.processEvents()
-
-    def blankClick(self):
-        if self.pptid < 0:
-            return
-        self.pptdll.Blank(self.pptid)
-        app.processEvents()
-
-    def unblankClick(self):
-        if self.pptid < 0:
-            return
-        self.pptdll.Unblank(self.pptid)
-        app.processEvents()
-
-    def restartClick(self):
-        if self.pptid < 0:
-            return
-        self.pptdll.RestartShow(self.pptid)
-        self.updateCurrSlide()
-        app.processEvents()
-
-    def stopClick(self):
-        if self.pptid < 0:
-            return
-        self.pptdll.Stop(self.pptid)
-        app.processEvents()
-
-    def resumeClick(self):
-        if self.pptid < 0:
-            return
-        self.pptdll.Resume(self.pptid)
-        app.processEvents()
-
-    def closeClick(self):
-        if self.pptid < 0:
-            return
-        self.pptdll.ClosePPT(self.pptid)
-        self.pptid = -1
-        app.processEvents()
-
-    def openClick(self):
-        oldid = self.pptid
-        rect = RECT(int(self.xEdit.text()), int(self.yEdit.text()),
-                    int(self.widthEdit.text()), int(self.heightEdit.text()))
-        filename = str(self.pptEdit.text().replace('/', '\\'))
-        folder = str(self.folderEdit.text().replace('/', '\\'))
-        print(filename, folder)
-        self.pptid = self.pptdll.OpenPPT(filename, None, rect, folder)
-        print('id: ' + str(self.pptid))
-        if oldid >= 0:
-            self.pptdll.ClosePPT(oldid)
-        slides = self.pptdll.GetSlideCount(self.pptid)
-        print('slidecount: ' + str(slides))
-        self.total.setNum(self.pptdll.GetSlideCount(self.pptid))
-        self.updateCurrSlide()
-
-    def updateCurrSlide(self):
-        if self.pptid < 0:
-            return
-        slide = str(self.pptdll.GetCurrentSlide(self.pptid))
-        print('currslide: ' + slide)
-        self.slideEdit.setText(slide)
-        app.processEvents()
-
-    def gotoClick(self):
-        if self.pptid < 0:
-            return
-        print(self.slideEdit.text())
-        self.pptdll.GotoSlide(self.pptid, int(self.slideEdit.text()))
-        self.updateCurrSlide()
-        app.processEvents()
-
-    def openDialog(self):
-        self.pptEdit.setText(QtWidgets.QFileDialog.getOpenFileName(self, 'Open file')[0])
-
-
-if __name__ == '__main__':
-    pptdll = cdll.LoadLibrary(r'pptviewlib.dll')
-    pptdll.SetDebug(1)
-    print('Begin...')
-    app = QtWidgets.QApplication(sys.argv)
-    window = PPTViewer()
-    window.pptdll = pptdll
-    window.show()
-    sys.exit(app.exec())

=== removed file 'openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp'
--- openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp	2017-12-29 09:15:48 +0000
+++ openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp	1970-01-01 00:00:00 +0000
@@ -1,920 +0,0 @@
-/******************************************************************************
-* OpenLP - Open Source Lyrics Projection                                      *
-* --------------------------------------------------------------------------- *
-* Copyright (c) 2008-2018 OpenLP Developers                                   *
-* --------------------------------------------------------------------------- *
-* 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                          *
-******************************************************************************/
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <io.h>
-#include <direct.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include "pptviewlib.h"
-
-// Because of the callbacks used by SetWindowsHookEx, the memory used needs to
-// be sharable across processes (the callbacks are done from a different
-// process) Therefore use data_seg with RWS memory.
-//
-// See http://msdn.microsoft.com/en-us/library/aa366551(VS.85).aspx for
-// alternative method of holding memory, removing fixed limits which would allow
-// dynamic number of items, rather than a fixed number. Use a Local\ mapping,
-// since global has UAC issues in Vista.
-
-#pragma data_seg(".PPTVIEWLIB")
-PPTVIEW pptView[MAX_PPTS] = {NULL};
-HHOOK globalHook = NULL;
-BOOL debug = FALSE;
-#pragma data_seg()
-#pragma comment(linker, "/SECTION:.PPTVIEWLIB,RWS")
-
-HINSTANCE hInstance = NULL;
-
-BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ulReasonForCall,
-    LPVOID lpReserved)
-{
-    hInstance = (HINSTANCE)hModule;
-    switch(ulReasonForCall)
-    {
-        case DLL_PROCESS_ATTACH:
-            DEBUG(L"PROCESS_ATTACH\n");
-            break;
-        case DLL_THREAD_ATTACH:
-            //DEBUG(L"THREAD_ATTACH\n");
-            break;
-        case DLL_THREAD_DETACH:
-            //DEBUG(L"THREAD_DETACH\n");
-            break;
-        case DLL_PROCESS_DETACH:
-            // Clean up... hopefully there is only the one process attached?
-            // We'll find out soon enough during tests!
-            DEBUG(L"PROCESS_DETACH\n");
-            for (int i = 0; i < MAX_PPTS; i++)
-                ClosePPT(i);
-            break;
-    }
-    return TRUE;
-}
-
-DllExport void SetDebug(BOOL onOff)
-{
-    printf("SetDebug\n");
-    debug = onOff;
-    DEBUG(L"enabled\n");
-}
-
-DllExport BOOL CheckInstalled()
-{
-    wchar_t cmdLine[MAX_PATH * 2];
-
-    DEBUG(L"CheckInstalled\n");
-    BOOL found = GetPPTViewerPath(cmdLine, sizeof(cmdLine));
-    if(found)
-    {
-        DEBUG(L"Exe: %s\n", cmdLine);
-    }
-    return found;
-}
-
-// Open the PointPoint, count the slides and take a snapshot of each slide
-// for use in previews
-// previewpath is a prefix for the location to put preview images of each slide.
-// "<n>.bmp" will be appended to complete the path. E.g. "c:\temp\slide" would
-// create "c:\temp\slide1.bmp" slide2.bmp, slide3.bmp etc.
-// It will also create a *info.txt containing information about the ppt
-DllExport int OpenPPT(wchar_t *filename, HWND hParentWnd, RECT rect,
-    wchar_t *previewPath)
-{
-    STARTUPINFO si;
-    PROCESS_INFORMATION pi;
-    wchar_t cmdLine[MAX_PATH * 2];
-    int id;
-
-    DEBUG(L"OpenPPT start: %s; %s\n", filename, previewPath);
-    DEBUG(L"OpenPPT start: %u; %i, %i, %i, %i\n", hParentWnd, rect.top,
-        rect.left, rect.bottom, rect.right);
-    if (GetPPTViewerPath(cmdLine, sizeof(cmdLine)) == FALSE)
-    {
-        DEBUG(L"OpenPPT: GetPPTViewerPath failed\n");
-        return -1;
-    }
-    id = -1;
-    for (int i = 0; i < MAX_PPTS; i++)
-    {
-        if (pptView[i].state == PPT_CLOSED)
-        {
-            id = i;
-            break;
-        }
-    }
-    if (id < 0)
-    {
-        DEBUG(L"OpenPPT: Too many PPTs\n");
-        return -1;
-    }
-    memset(&pptView[id], 0, sizeof(PPTVIEW));
-    wcscpy_s(pptView[id].filename, MAX_PATH, filename);
-    wcscpy_s(pptView[id].previewPath, MAX_PATH, previewPath);
-    pptView[id].state = PPT_CLOSED;
-    pptView[id].slideCount = 0;
-    pptView[id].currentSlide = 0;
-    pptView[id].firstSlideSteps = 0;
-    pptView[id].lastSlideSteps = 0;
-    pptView[id].guess = 0;
-    pptView[id].hParentWnd = hParentWnd;
-    pptView[id].hWnd = NULL;
-    pptView[id].hWnd2 = NULL;
-    for (int i = 0; i < MAX_SLIDES; i++)
-    {
-        pptView[id].slideNos[i] = 0;
-    }
-    if (hParentWnd != NULL && rect.top == 0 && rect.bottom == 0
-        && rect.left == 0 && rect.right == 0)
-    {
-        LPRECT windowRect = NULL;
-        GetWindowRect(hParentWnd, windowRect);
-        pptView[id].rect.top = 0;
-        pptView[id].rect.left = 0;
-        pptView[id].rect.bottom = windowRect->bottom - windowRect->top;
-        pptView[id].rect.right = windowRect->right - windowRect->left;
-    }
-    else
-    {
-        pptView[id].rect.top = rect.top;
-        pptView[id].rect.left = rect.left;
-        pptView[id].rect.bottom = rect.bottom;
-        pptView[id].rect.right = rect.right;
-    }
-    wcscat_s(cmdLine, MAX_PATH * 2, L" /F /S \"");
-    wcscat_s(cmdLine, MAX_PATH * 2, filename);
-    wcscat_s(cmdLine, MAX_PATH * 2, L"\"");
-    memset(&si, 0, sizeof(si));
-    memset(&pi, 0, sizeof(pi));
-    BOOL gotInfo = GetPPTInfo(id);
-    /*
-     * I'd really like to just hook on the new threadid. However this always
-     * gives error 87. Perhaps I'm hooking to soon? No idea... however can't
-     * wait since I need to ensure I pick up the WM_CREATE as this is the only
-     * time the window can be resized in such away the content scales correctly
-     *
-     * hook = SetWindowsHookEx(WH_CBT,CbtProc,hInstance,pi.dwThreadId);
-     */
-    if (globalHook != NULL)
-    {
-        UnhookWindowsHookEx(globalHook);
-    }
-    globalHook = SetWindowsHookEx(WH_CBT, CbtProc, hInstance, NULL);
-    if (globalHook == 0)
-    {
-        DEBUG(L"OpenPPT: SetWindowsHookEx failed\n");
-        ClosePPT(id);
-        return -1;
-    }
-    pptView[id].state = PPT_STARTED;
-    Sleep(10);
-    if (!CreateProcess(NULL, cmdLine, NULL, NULL, FALSE, 0, 0, NULL, &si, &pi))
-    {
-        DEBUG(L"OpenPPT: CreateProcess failed: %s\n", cmdLine);
-        ClosePPT(id);
-        return -1;
-    }
-    pptView[id].dwProcessId = pi.dwProcessId;
-    pptView[id].dwThreadId = pi.dwThreadId;
-    pptView[id].hThread = pi.hThread;
-    pptView[id].hProcess = pi.hProcess;
-    while (pptView[id].state == PPT_STARTED)
-        Sleep(10);
-    if (gotInfo)
-    {
-        DEBUG(L"OpenPPT: Info loaded, no refresh\n");
-        pptView[id].state = PPT_LOADED;
-        Resume(id);
-    }
-    else
-    {
-        DEBUG(L"OpenPPT: Get info\n");
-        pptView[id].steps = 0;
-        int steps = 0;
-        while (pptView[id].state == PPT_OPENED)
-        {
-            if (steps <= pptView[id].steps)
-            {
-                Sleep(100);
-                DEBUG(L"OpenPPT: Step %d/%d\n", steps, pptView[id].steps);
-                steps++;
-                NextStep(id);
-            }
-            Sleep(10);
-        }
-        DEBUG(L"OpenPPT: Slides %d, Steps %d, first slide steps %d\n",
-            pptView[id].slideCount, pptView[id].steps,
-            pptView[id].firstSlideSteps);
-        for(int i = 1; i <= pptView[id].slideCount; i++)
-        {
-            DEBUG(L"OpenPPT: Slide %d = %d\n", i, pptView[id].slideNos[i]);
-        }
-        SavePPTInfo(id);
-        if (pptView[id].state == PPT_CLOSING
-            || pptView[id].slideCount <= 0)
-        {
-            ClosePPT(id);
-            id=-1;
-        }
-        else
-        {
-               RestartShow(id);
-        }
-    }
-    if (id >= 0)
-    {
-        if (pptView[id].msgHook != NULL)
-        {
-            UnhookWindowsHookEx(pptView[id].msgHook);
-        }
-        pptView[id].msgHook = NULL;
-    }
-    DEBUG(L"OpenPPT: Exit: id=%i\n", id);
-    return id;
-}
-// Load information about the ppt from an info.txt file.
-// Format:
-// version
-// filedate
-// filesize
-// slidecount
-// first slide steps
-BOOL GetPPTInfo(int id)
-{
-    struct _stat fileStats;
-    wchar_t info[MAX_PATH];
-    FILE* pFile;
-    wchar_t buf[100];
-
-    DEBUG(L"GetPPTInfo: start\n");
-    if (_wstat(pptView[id].filename, &fileStats) != 0)
-    {
-        return FALSE;
-    }
-    swprintf_s(info, MAX_PATH, L"%sinfo.txt", pptView[id].previewPath);
-    int err = _wfopen_s(&pFile, info, L"r");
-    if (err != 0)
-    {
-        DEBUG(L"GetPPTInfo: file open failed - %d\n", err);
-        return FALSE;
-    }
-    fgetws(buf, 100, pFile); // version == 1
-    fgetws(buf, 100, pFile);
-    if (fileStats.st_mtime != _wtoi(buf))
-    {
-        DEBUG(L"GetPPTInfo: date changed\n");
-        fclose (pFile);
-        return FALSE;
-    }
-    fgetws(buf, 100, pFile);
-    if (fileStats.st_size != _wtoi(buf))
-    {
-        DEBUG(L"GetPPTInfo: size changed\n");
-        fclose (pFile);
-        return FALSE;
-    }
-    fgetws(buf, 100, pFile); // slidecount
-    int slideCount = _wtoi(buf);
-    fgetws(buf, 100, pFile); // first slide steps
-    int firstSlideSteps = _wtoi(buf);
-    // check all the preview images still exist
-    for (int i = 1; i <= slideCount; i++)
-    {
-        swprintf_s(info, MAX_PATH, L"%s%i.bmp", pptView[id].previewPath, i);
-        if (GetFileAttributes(info) == INVALID_FILE_ATTRIBUTES)
-        {
-            DEBUG(L"GetPPTInfo: bmp not found\n");
-            return FALSE;
-        }
-    }
-    fclose(pFile);
-    pptView[id].slideCount = slideCount;
-    pptView[id].firstSlideSteps = firstSlideSteps;
-    DEBUG(L"GetPPTInfo: exit ok\n");
-    return TRUE;
-}
-
-BOOL SavePPTInfo(int id)
-{
-    struct _stat fileStats;
-    wchar_t info[MAX_PATH];
-    FILE* pFile;
-
-    DEBUG(L"SavePPTInfo: start\n");
-    if (_wstat(pptView[id].filename, &fileStats) != 0)
-    {
-        DEBUG(L"SavePPTInfo: stat of %s failed\n", pptView[id].filename);
-        return FALSE;
-    }
-    swprintf_s(info, MAX_PATH, L"%sinfo.txt", pptView[id].previewPath);
-    int err = _wfopen_s(&pFile, info, L"w");
-    if (err != 0)
-    {
-        DEBUG(L"SavePPTInfo: fopen of %s failed%i\n", info, err);
-        return FALSE;
-    }
-    fprintf(pFile, "1\n");
-    fprintf(pFile, "%u\n", fileStats.st_mtime);
-    fprintf(pFile, "%u\n", fileStats.st_size);
-    fprintf(pFile, "%u\n", pptView[id].slideCount);
-    fprintf(pFile, "%u\n", pptView[id].firstSlideSteps);
-    fclose(pFile);
-    DEBUG(L"SavePPTInfo: exit ok\n");
-    return TRUE;
-}
-
-// Get the path of the PowerPoint viewer from the registry
-BOOL GetPPTViewerPath(wchar_t *pptViewerPath, int stringSize)
-{
-    wchar_t cwd[MAX_PATH];
-
-    DEBUG(L"GetPPTViewerPath: start\n");
-    if(GetPPTViewerPathFromReg(pptViewerPath, stringSize))
-    {
-        if(_waccess(pptViewerPath, 0) != -1)
-        {
-            DEBUG(L"GetPPTViewerPath: exit registry\n");
-            return TRUE;
-        }
-    }
-    // This is where it gets ugly. PPT2007 it seems no longer stores its
-    // location in the registry. So we have to use the defaults which will
-    // upset those who like to put things somewhere else
-
-    // Viewer 2007 in 64bit Windows:
-    if(_waccess(L"C:\\Program Files (x86)\\Microsoft Office\\Office12\\PPTVIEW.EXE",
-        0) != -1)
-    {
-        wcscpy_s(
-            L"C:\\Program Files (x86)\\Microsoft Office\\Office12\\PPTVIEW.EXE",
-            stringSize, pptViewerPath);
-        DEBUG(L"GetPPTViewerPath: exit 64bit 2007\n");
-        return TRUE;
-    }
-    // Viewer 2007 in 32bit Windows:
-    if(_waccess(L"C:\\Program Files\\Microsoft Office\\Office12\\PPTVIEW.EXE", 0)
-        != -1)
-    {
-        wcscpy_s(L"C:\\Program Files\\Microsoft Office\\Office12\\PPTVIEW.EXE",
-            stringSize, pptViewerPath);
-        DEBUG(L"GetPPTViewerPath: exit 32bit 2007\n");
-        return TRUE;
-    }
-    // Give them the opportunity to place it in the same folder as the app
-    _wgetcwd(cwd, MAX_PATH);
-    wcscat_s(cwd, MAX_PATH, L"\\PPTVIEW.EXE");
-    if(_waccess(cwd, 0) != -1)
-    {
-        wcscpy_s(pptViewerPath, stringSize, cwd);
-        DEBUG(L"GetPPTViewerPath: exit local\n");
-        return TRUE;
-    }
-    DEBUG(L"GetPPTViewerPath: exit fail\n");
-    return FALSE;
-}
-BOOL GetPPTViewerPathFromReg(wchar_t *pptViewerPath, int stringSize)
-{
-    HKEY hKey;
-    DWORD dwType, dwSize;
-    LRESULT lResult;
-
-    // The following registry settings are for, respectively, (I think)
-    // PPT Viewer 2007 (older versions. Latest not in registry) & PPT Viewer 2010
-    // PPT Viewer 2003 (recent versions)
-    // PPT Viewer 2003 (older versions) 
-    // PPT Viewer 97
-    if ((RegOpenKeyExW(HKEY_CLASSES_ROOT,
-        L"PowerPointViewer.Show.12\\shell\\Show\\command", 0, KEY_READ, &hKey)
-        != ERROR_SUCCESS)
-        && (RegOpenKeyExW(HKEY_CLASSES_ROOT,
-        L"PowerPointViewer.Show.11\\shell\\Show\\command", 0, KEY_READ, &hKey)
-        != ERROR_SUCCESS)
-        && (RegOpenKeyExW(HKEY_CLASSES_ROOT,
-        L"Applications\\PPTVIEW.EXE\\shell\\open\\command", 0, KEY_READ, &hKey)
-        != ERROR_SUCCESS)
-        && (RegOpenKeyExW(HKEY_CLASSES_ROOT,
-        L"Applications\\PPTVIEW.EXE\\shell\\Show\\command", 0, KEY_READ, &hKey)
-        != ERROR_SUCCESS))
-    {
-        return FALSE;
-    }
-    dwType = REG_SZ;
-    dwSize = (DWORD)stringSize;
-    lResult = RegQueryValueEx(hKey, NULL, NULL, &dwType, (LPBYTE)pptViewerPath,
-        &dwSize);
-    RegCloseKey(hKey);
-    if (lResult != ERROR_SUCCESS)
-    {
-        return FALSE;
-    }
-    // remove "%1" from end of key value
-    pptViewerPath[wcslen(pptViewerPath) - 4] = '\0';
-    return TRUE;
-}
-
-// Unhook the Windows hook
-void Unhook(int id)
-{
-    DEBUG(L"Unhook: start %d\n", id);
-    if (pptView[id].hook != NULL)
-    {
-        UnhookWindowsHookEx(pptView[id].hook);
-    }
-    if (pptView[id].msgHook != NULL)
-    {
-        UnhookWindowsHookEx(pptView[id].msgHook);
-    }
-    pptView[id].hook = NULL;
-    pptView[id].msgHook = NULL;
-    DEBUG(L"Unhook: exit ok\n");
-}
-
-// Close the PowerPoint viewer, release resources
-DllExport void ClosePPT(int id)
-{
-    DEBUG(L"ClosePPT: start%d\n", id);
-    pptView[id].state = PPT_CLOSED;
-    Unhook(id);
-    if (pptView[id].hWnd == 0)
-    {
-        TerminateThread(pptView[id].hThread, 0);
-    }
-    else
-    {
-        PostMessage(pptView[id].hWnd, WM_CLOSE, 0, 0);
-    }
-    CloseHandle(pptView[id].hThread);
-    CloseHandle(pptView[id].hProcess);
-    memset(&pptView[id], 0, sizeof(PPTVIEW));
-    DEBUG(L"ClosePPT: exit ok\n");
-    return;
-}
-// Moves the show back onto the display
-DllExport void Resume(int id)
-{
-    DEBUG(L"Resume: %d\n", id);
-    MoveWindow(pptView[id].hWnd, pptView[id].rect.left,
-        pptView[id].rect.top,
-        pptView[id].rect.right - pptView[id].rect.left,
-        pptView[id].rect.bottom - pptView[id].rect.top, TRUE);
-    Unblank(id);
-}
-// Moves the show off the screen so it can't be seen
-DllExport void Stop(int id)
-{
-    DEBUG(L"Stop:%d\n", id);
-    MoveWindow(pptView[id].hWnd, -32000, -32000,
-        pptView[id].rect.right - pptView[id].rect.left,
-        pptView[id].rect.bottom - pptView[id].rect.top, TRUE);
-}
-
-// Return the total number of slides
-DllExport int GetSlideCount(int id)
-{
-    DEBUG(L"GetSlideCount:%d\n", id);
-    if (pptView[id].state == 0)
-    {
-        return -1;
-    }
-    else
-    {
-        return pptView[id].slideCount;
-    }
-}
-
-// Return the number of the slide currently viewing
-DllExport int GetCurrentSlide(int id)
-{
-    DEBUG(L"GetCurrentSlide:%d\n", id);
-    if (pptView[id].state == 0)
-    {
-        return -1;
-    }
-    else
-    {
-        return pptView[id].currentSlide;
-    }
-}
-
-// Take a step forwards through the show
-DllExport void NextStep(int id)
-{
-    DEBUG(L"NextStep:%d (%d)\n", id, pptView[id].currentSlide);
-    if (pptView[id].currentSlide > pptView[id].slideCount) return;
-    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);
-}
-
-// Take a step backwards through the show
-DllExport void PrevStep(int id)
-{
-    DEBUG(L"PrevStep:%d (%d)\n", id, pptView[id].currentSlide);
-    if (pptView[id].currentSlide > 1)
-    {
-        pptView[id].guess = pptView[id].currentSlide - 1;
-    }
-    PostMessage(pptView[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, WHEEL_DELTA),
-        0);
-}
-
-// Blank the show (black screen)
-DllExport void Blank(int id)
-{
-    // B just toggles blank on/off. However pressing any key unblanks.
-    // So send random unmapped letter first (say 'A'), then we can
-    // better guarantee B will blank instead of trying to guess
-    // whether it was already blank or not.
-    DEBUG(L"Blank:%d\n", id);
-    HWND h1 = GetForegroundWindow();
-    HWND h2 = GetFocus();
-    SetForegroundWindow(pptView[id].hWnd);
-    SetFocus(pptView[id].hWnd);
-    // slight pause, otherwise event triggering this call may grab focus back!
-    Sleep(50);
-    keybd_event((int)'A', 0, 0, 0);
-    keybd_event((int)'A', 0, KEYEVENTF_KEYUP, 0);
-    keybd_event((int)'B', 0, 0, 0);
-    keybd_event((int)'B', 0, KEYEVENTF_KEYUP, 0);
-    SetForegroundWindow(h1);
-    SetFocus(h2);
-}
-// Unblank the show
-DllExport void Unblank(int id)
-{
-    DEBUG(L"Unblank:%d\n", id);
-    // Pressing any key resumes.
-    // For some reason SendMessage works for unblanking, but not blanking.
-    SendMessage(pptView[id].hWnd2, WM_CHAR, 'A', 0);
-}
-
-// Go directly to a slide
-DllExport void GotoSlide(int id, int slideNo)
-{
-    DEBUG(L"GotoSlide %i %i:\n", id, slideNo);
-    // Did try WM_KEYDOWN/WM_CHAR/WM_KEYUP with SendMessage but didn't work
-    // perhaps I was sending to the wrong window? No idea.
-    // Anyway fall back to keybd_event, which is OK as long we makesure
-    // the slideshow has focus first
-    char ch[10];
-
-    if (slideNo < 0) return;
-    pptView[id].guess = slideNo;
-    _itoa_s(slideNo, ch, 10, 10);
-    HWND h1 = GetForegroundWindow();
-    HWND h2 = GetFocus();
-    SetForegroundWindow(pptView[id].hWnd);
-    SetFocus(pptView[id].hWnd);
-    // slight pause, otherwise event triggering this call may grab focus back!
-    Sleep(50);
-    for (int i=0; i<10; i++)
-    {
-        if (ch[i] == '\0') break;
-        keybd_event((BYTE)ch[i], 0, 0, 0);
-        keybd_event((BYTE)ch[i], 0, KEYEVENTF_KEYUP, 0);
-    }
-    keybd_event(VK_RETURN, 0, 0, 0);
-    keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
-    SetForegroundWindow(h1);
-    SetFocus(h2);
-}
-
-// Restart the show from the beginning
-DllExport void RestartShow(int id)
-{
-    // If we just go direct to slide one, then it remembers that all other
-    // slides have been animated, so ends up just showing the completed slides
-    // of those slides that have been animated next time we advance.
-    // Only way I've found to get around this is to step backwards all the way
-    // through. Lets move the window out of the way first so the audience
-    // doesn't see this.
-    DEBUG(L"RestartShow:%d\n", id);
-    Stop(id);
-    GotoSlide(id, pptView[id].slideCount);
-    for (int i=0; i <= pptView[id].steps - pptView[id].lastSlideSteps; i++)
-    {
-        PrevStep(id);
-        Sleep(10);
-    }
-    int i = 0;
-    while ((pptView[id].currentSlide > 1) && (i++ < 30000))
-    {
-        Sleep(10);
-    }
-    Resume(id);
-}
-
-// This hook is started with the PPTVIEW.EXE process and waits for the
-// WM_CREATEWND message. At this point (and only this point) can the
-// window be resized to the correct size.
-// Release the hook as soon as we're complete to free up resources
-LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam)
-{
-    HHOOK hook = globalHook;
-    if (nCode == HCBT_CREATEWND)
-    {
-        wchar_t csClassName[32];
-        HWND hCurrWnd = (HWND)wParam;
-        DWORD retProcId = NULL;
-        GetClassName(hCurrWnd, csClassName, sizeof(csClassName));
-        if ((wcscmp(csClassName, L"paneClassDC") == 0)
-          ||(wcscmp(csClassName, L"screenClass") == 0))
-        {
-            int id = -1;
-            DWORD windowThread = GetWindowThreadProcessId(hCurrWnd, NULL);
-            for (int i=0; i < MAX_PPTS; i++)
-            {
-                if (pptView[i].dwThreadId == windowThread)
-                {
-                    id = i;
-                    break;
-                }
-            }
-            if (id >= 0)
-            {
-                if (wcscmp(csClassName, L"paneClassDC") == 0)
-                {
-                    pptView[id].hWnd2 = hCurrWnd;
-                }
-                else
-                {
-                    pptView[id].hWnd = hCurrWnd;
-                    CBT_CREATEWND* cw = (CBT_CREATEWND*)lParam;
-                    if (pptView[id].hParentWnd != NULL)
-                    {
-                        cw->lpcs->hwndParent = pptView[id].hParentWnd;
-                    }
-                    cw->lpcs->cy = pptView[id].rect.bottom
-                        - pptView[id].rect.top;
-                    cw->lpcs->cx = pptView[id].rect.right
-                        - pptView[id].rect.left;
-                    cw->lpcs->y = -32000;
-                    cw->lpcs->x = -32000;
-                }
-                if ((pptView[id].hWnd != NULL) && (pptView[id].hWnd2 != NULL))
-                {
-                    UnhookWindowsHookEx(globalHook);
-                    globalHook = NULL;
-                    pptView[id].hook = SetWindowsHookEx(WH_CALLWNDPROC,
-                        CwpProc, hInstance, pptView[id].dwThreadId);
-                    pptView[id].msgHook = SetWindowsHookEx(WH_GETMESSAGE,
-                        GetMsgProc, hInstance, pptView[id].dwThreadId);
-                    Sleep(10);
-                    pptView[id].state = PPT_OPENED;
-                }
-            }
-        }
-    }
-    return CallNextHookEx(hook, nCode, wParam, lParam);
-}
-
-// This hook exists whilst the slideshow is loading but only listens on the
-// slideshows thread. It listens out for mousewheel events
-LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
-{
-    HHOOK hook = NULL;
-    MSG *pMSG = (MSG *)lParam;
-    DWORD windowThread = GetWindowThreadProcessId(pMSG->hwnd, NULL);
-    int id = -1;
-    for (int i = 0; i < MAX_PPTS; i++)
-    {
-        if (pptView[i].dwThreadId == windowThread)
-        {
-            id = i;
-            hook = pptView[id].msgHook;
-            break;
-        }
-    }
-    if (id >= 0 && nCode == HC_ACTION && wParam == PM_REMOVE
-        && pMSG->message == WM_MOUSEWHEEL)
-    {
-        if (pptView[id].state != PPT_LOADED)
-        {
-            if (pptView[id].currentSlide == 1)
-            {
-                pptView[id].firstSlideSteps++;
-            }
-            pptView[id].steps++;
-            pptView[id].lastSlideSteps++;
-        }
-    }
-    return CallNextHookEx(hook, nCode, wParam, lParam);
-}
-// This hook exists whilst the slideshow is running but only listens on the
-// slideshows thread. It listens out for slide changes, message WM_USER+22.
-LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam){
-    CWPSTRUCT *cwp;
-    cwp = (CWPSTRUCT *)lParam;
-    HHOOK hook = NULL;
-    wchar_t filename[MAX_PATH];
-
-    DWORD windowThread = GetWindowThreadProcessId(cwp->hwnd, NULL);
-    int id = -1;
-    for (int i = 0; i < MAX_PPTS; i++)
-    {
-        if (pptView[i].dwThreadId == windowThread)
-        {
-            id = i;
-            hook = pptView[id].hook;
-            break;
-        }
-    }
-    if ((id >= 0) && (nCode == HC_ACTION))
-    {
-        if (cwp->message == WM_USER + 22)
-        {
-            if (pptView[id].state != PPT_LOADED)
-            {
-                if ((pptView[id].currentSlide > 0)
-                    && (pptView[id].previewPath != NULL
-                    && wcslen(pptView[id].previewPath) > 0))
-                {
-                    swprintf_s(filename, MAX_PATH, L"%s%i.bmp",
-                        pptView[id].previewPath,
-                        pptView[id].currentSlide);
-                    CaptureAndSaveWindow(cwp->hwnd, filename);
-                }
-                if (((cwp->wParam == 0)
-                    || (pptView[id].slideNos[1] == cwp->wParam))
-                    && (pptView[id].currentSlide > 0))
-                {
-                    pptView[id].state = PPT_LOADED;
-                    pptView[id].currentSlide = pptView[id].slideCount + 1;
-                }
-                else
-                {
-                    if (cwp->wParam > 0)
-                    {
-                        pptView[id].currentSlide = pptView[id].currentSlide + 1;
-                        pptView[id].slideNos[pptView[id].currentSlide]
-                            = cwp->wParam;
-                        pptView[id].slideCount = pptView[id].currentSlide;
-                        pptView[id].lastSlideSteps = 0;
-                    }
-                }
-            }
-            else
-            {
-                if (cwp->wParam > 0)
-                {
-                    if(pptView[id].guess > 0
-                        && pptView[id].slideNos[pptView[id].guess] == 0)
-                    {
-                        pptView[id].currentSlide = 0;
-                    }
-                    for(int i = 1; i <= pptView[id].slideCount; i++)
-                    {
-                        if(pptView[id].slideNos[i] == cwp->wParam)
-                        {
-                            pptView[id].currentSlide = i;
-                            break;
-                        }
-                    }
-                    if(pptView[id].currentSlide == 0)
-                    {
-                        pptView[id].slideNos[pptView[id].guess] = cwp->wParam;
-                        pptView[id].currentSlide = pptView[id].guess;
-                    }
-                    pptView[id].guess = 0;
-                }
-            }
-        }
-        if ((pptView[id].state != PPT_CLOSED)
-
-            &&(cwp->message == WM_CLOSE || cwp->message == WM_QUIT))
-        {
-            pptView[id].state = PPT_CLOSING;
-        }
-    }
-    return CallNextHookEx(hook, nCode, wParam, lParam);
-}
-
-VOID CaptureAndSaveWindow(HWND hWnd, wchar_t* filename)
-{
-    HBITMAP hBmp;
-    if ((hBmp = CaptureWindow(hWnd)) == NULL)
-    {
-        return;
-    }
-    RECT client;
-    GetClientRect(hWnd, &client);
-    UINT uiBytesPerRow = 3 * client.right; // RGB takes 24 bits
-    UINT uiRemainderForPadding;
-
-    if ((uiRemainderForPadding = uiBytesPerRow % sizeof(DWORD)) > 0)
-        uiBytesPerRow += (sizeof(DWORD) - uiRemainderForPadding);
-
-    UINT uiBytesPerAllRows = uiBytesPerRow * client.bottom;
-    PBYTE pDataBits;
-
-    if ((pDataBits = new BYTE[uiBytesPerAllRows]) != NULL)
-    {
-        BITMAPINFOHEADER bmi = {0};
-        BITMAPFILEHEADER bmf = {0};
-
-        // Prepare to get the data out of HBITMAP:
-        bmi.biSize = sizeof(bmi);
-        bmi.biPlanes = 1;
-        bmi.biBitCount = 24;
-        bmi.biHeight = client.bottom;
-        bmi.biWidth = client.right;
-
-        // Get it:
-        HDC hDC = GetDC(hWnd);
-        GetDIBits(hDC, hBmp, 0, client.bottom, pDataBits, (BITMAPINFO*) &bmi,
-            DIB_RGB_COLORS);
-        ReleaseDC(hWnd, hDC);
-
-        // Fill the file header:
-        bmf.bfOffBits = sizeof(bmf) + sizeof(bmi);
-        bmf.bfSize = bmf.bfOffBits + uiBytesPerAllRows;
-        bmf.bfType = 0x4D42;
-
-        // Writing:
-        FILE* pFile;
-        int err = _wfopen_s(&pFile, filename, L"wb");
-        if (err == 0)
-        {
-            fwrite(&bmf, sizeof(bmf), 1, pFile);
-            fwrite(&bmi, sizeof(bmi), 1, pFile);
-            fwrite(pDataBits, sizeof(BYTE), uiBytesPerAllRows, pFile);
-            fclose(pFile);
-        }
-        delete [] pDataBits;
-    }
-    DeleteObject(hBmp);
-}
-HBITMAP CaptureWindow(HWND hWnd)
-{
-    HDC hDC;
-    BOOL bOk = FALSE;
-    HBITMAP hImage = NULL;
-
-    hDC = GetDC(hWnd);
-    RECT rcClient;
-    GetClientRect(hWnd, &rcClient);
-    if ((hImage = CreateCompatibleBitmap(hDC, rcClient.right, rcClient.bottom))
-        != NULL)
-    {
-        HDC hMemDC;
-        HBITMAP hDCBmp;
-
-        if ((hMemDC = CreateCompatibleDC(hDC)) != NULL)
-        {
-            hDCBmp = (HBITMAP)SelectObject(hMemDC, hImage);
-			HMODULE hLib = LoadLibrary(L"User32");
-            // PrintWindow works for windows outside displayable area
-            // but was only introduced in WinXP. BitBlt requires the window to
-            // be topmost and within the viewable area of the display
-            if (GetProcAddress(hLib, "PrintWindow") == NULL)
-            {
-                SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE);
-                BitBlt(hMemDC, 0, 0, rcClient.right, rcClient.bottom, hDC, 0,
-                    0, SRCCOPY);
-                SetWindowPos(hWnd, HWND_NOTOPMOST, -32000, -32000, 0, 0,
-                    SWP_NOSIZE);
-            }
-            else
-            {
-                PrintWindow(hWnd, hMemDC, 0);
-            }
-            SelectObject(hMemDC, hDCBmp);
-            DeleteDC(hMemDC);
-            bOk = TRUE;
-        }
-    }
-    ReleaseDC(hWnd, hDC);
-    if (!bOk)
-    {
-        if (hImage)
-        {
-            DeleteObject(hImage);
-            hImage = NULL;
-        }
-    }
-    return hImage;
-}

=== removed file 'openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h'
--- openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h	2017-12-29 09:15:48 +0000
+++ openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h	1970-01-01 00:00:00 +0000
@@ -1,80 +0,0 @@
-/******************************************************************************
-* OpenLP - Open Source Lyrics Projection                                      *
-* --------------------------------------------------------------------------- *
-* Copyright (c) 2008-2018 OpenLP Developers                                   *
-* --------------------------------------------------------------------------- *
-* 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                          *
-******************************************************************************/
-
-#define DllExport extern "C"  __declspec( dllexport )
-
-#define DEBUG(...)  if (debug) wprintf(__VA_ARGS__)
-
-enum PPTVIEWSTATE {PPT_CLOSED, PPT_STARTED, PPT_OPENED, PPT_LOADED,
-    PPT_CLOSING};
-
-DllExport int OpenPPT(wchar_t *filename, HWND hParentWnd, RECT rect,
-    wchar_t *previewPath);
-DllExport BOOL CheckInstalled();
-DllExport void ClosePPT(int id);
-DllExport int GetCurrentSlide(int id);
-DllExport int GetSlideCount(int id);
-DllExport void NextStep(int id);
-DllExport void PrevStep(int id);
-DllExport void GotoSlide(int id, int slide_no);
-DllExport void RestartShow(int id);
-DllExport void Blank(int id);
-DllExport void Unblank(int id);
-DllExport void Stop(int id);
-DllExport void Resume(int id);
-DllExport void SetDebug(BOOL onOff);
-
-LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam);
-LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam);
-LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam);
-BOOL GetPPTViewerPath(wchar_t *pptViewerPath, int stringSize);
-BOOL GetPPTViewerPathFromReg(wchar_t *pptViewerPath, int stringSize);
-HBITMAP CaptureWindow(HWND hWnd);
-VOID SaveBitmap(wchar_t* filename, HBITMAP hBmp) ;
-VOID CaptureAndSaveWindow(HWND hWnd, wchar_t* filename);
-BOOL GetPPTInfo(int id);
-BOOL SavePPTInfo(int id);
-void Unhook(int id);
-
-#define MAX_PPTS 16
-#define MAX_SLIDES 256
-
-struct PPTVIEW
-{
-    HHOOK hook;
-    HHOOK msgHook;
-    HWND hWnd;
-    HWND hWnd2;
-    HWND hParentWnd;
-    HANDLE hProcess;
-    HANDLE hThread;
-    DWORD dwProcessId;
-    DWORD dwThreadId;
-    RECT rect;
-    int slideCount;
-    int currentSlide;
-    int firstSlideSteps;
-    int lastSlideSteps;
-    int steps;
-    int guess;
-    wchar_t filename[MAX_PATH];
-    wchar_t previewPath[MAX_PATH];
-    int slideNos[MAX_SLIDES];
-    PPTVIEWSTATE state;
-};

=== removed file 'openlp/plugins/presentations/lib/pptviewlib/pptviewlib.vcproj'
--- openlp/plugins/presentations/lib/pptviewlib/pptviewlib.vcproj	2013-11-16 10:16:06 +0000
+++ openlp/plugins/presentations/lib/pptviewlib/pptviewlib.vcproj	1970-01-01 00:00:00 +0000
@@ -1,202 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
-	ProjectType="Visual C++"
-	Version="9.00"
-	Name="pptviewlib"
-	ProjectGUID="{04CC20D1-DC5A-4189-8181-4011E3C21DCF}"
-	RootNamespace="pptviewlib"
-	Keyword="Win32Proj"
-	TargetFrameworkVersion="196613"
-	>
-	<Platforms>
-		<Platform
-			Name="Win32"
-		/>
-	</Platforms>
-	<ToolFiles>
-	</ToolFiles>
-	<Configurations>
-		<Configuration
-			Name="Debug|Win32"
-			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
-			IntermediateDirectory="$(ConfigurationName)"
-			ConfigurationType="2"
-			CharacterSet="1"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				Optimization="0"
-				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;PPTVIEWLIB_EXPORTS"
-				MinimalRebuild="true"
-				BasicRuntimeChecks="3"
-				RuntimeLibrary="3"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				DebugInformationFormat="4"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-				LinkIncremental="2"
-				ModuleDefinitionFile=""
-				GenerateDebugInformation="true"
-				SubSystem="2"
-				TargetMachine="1"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-		<Configuration
-			Name="Release|Win32"
-			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
-			IntermediateDirectory="$(ConfigurationName)"
-			ConfigurationType="2"
-			CharacterSet="1"
-			WholeProgramOptimization="1"
-			>
-			<Tool
-				Name="VCPreBuildEventTool"
-			/>
-			<Tool
-				Name="VCCustomBuildTool"
-			/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"
-			/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"
-			/>
-			<Tool
-				Name="VCMIDLTool"
-			/>
-			<Tool
-				Name="VCCLCompilerTool"
-				Optimization="2"
-				EnableIntrinsicFunctions="true"
-				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;PPTVIEWLIB_EXPORTS"
-				RuntimeLibrary="2"
-				EnableFunctionLevelLinking="true"
-				UsePrecompiledHeader="0"
-				WarningLevel="3"
-				DebugInformationFormat="3"
-			/>
-			<Tool
-				Name="VCManagedResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCResourceCompilerTool"
-			/>
-			<Tool
-				Name="VCPreLinkEventTool"
-			/>
-			<Tool
-				Name="VCLinkerTool"
-				LinkIncremental="1"
-				GenerateDebugInformation="true"
-				SubSystem="2"
-				OptimizeReferences="2"
-				EnableCOMDATFolding="2"
-				TargetMachine="1"
-			/>
-			<Tool
-				Name="VCALinkTool"
-			/>
-			<Tool
-				Name="VCManifestTool"
-			/>
-			<Tool
-				Name="VCXDCMakeTool"
-			/>
-			<Tool
-				Name="VCBscMakeTool"
-			/>
-			<Tool
-				Name="VCFxCopTool"
-			/>
-			<Tool
-				Name="VCAppVerifierTool"
-			/>
-			<Tool
-				Name="VCPostBuildEventTool"
-			/>
-		</Configuration>
-	</Configurations>
-	<References>
-	</References>
-	<Files>
-		<Filter
-			Name="Source Files"
-			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
-			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
-			>
-			<File
-				RelativePath=".\pptviewlib.cpp"
-				>
-			</File>
-			<File
-				RelativePath=".\README.TXT"
-				>
-			</File>
-		</Filter>
-		<Filter
-			Name="Header Files"
-			Filter="h;hpp;hxx;hm;inl;inc;xsd"
-			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
-			>
-			<File
-				RelativePath=".\pptviewlib.h"
-				>
-			</File>
-		</Filter>
-		<Filter
-			Name="Resource Files"
-			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
-			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
-			>
-		</Filter>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>

=== removed file 'openlp/plugins/presentations/lib/pptviewlib/test.ppt'
Binary files openlp/plugins/presentations/lib/pptviewlib/test.ppt	2010-09-14 18:18:47 +0000 and openlp/plugins/presentations/lib/pptviewlib/test.ppt	1970-01-01 00:00:00 +0000 differ
=== removed file 'openlp/plugins/presentations/lib/pptviewlib/test.pptx'
Binary files openlp/plugins/presentations/lib/pptviewlib/test.pptx	2013-10-17 19:31:17 +0000 and openlp/plugins/presentations/lib/pptviewlib/test.pptx	1970-01-01 00:00:00 +0000 differ
=== modified file 'openlp/plugins/presentations/presentationplugin.py'
--- openlp/plugins/presentations/presentationplugin.py	2017-12-29 09:15:48 +0000
+++ openlp/plugins/presentations/presentationplugin.py	2018-02-03 14:18:52 +0000
@@ -44,7 +44,6 @@
                         'presentations/pdf_program': None,
                         'presentations/Impress': QtCore.Qt.Checked,
                         'presentations/Powerpoint': QtCore.Qt.Checked,
-                        'presentations/Powerpoint Viewer': QtCore.Qt.Checked,
                         'presentations/Pdf': QtCore.Qt.Checked,
                         'presentations/presentations files': [],
                         'presentations/thumbnail_scheme': '',
@@ -57,7 +56,7 @@
 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.
+    third party applications such as OpenOffice.org Impress, and Microsoft PowerPoint.
     """
     log = logging.getLogger('PresentationPlugin')
 

=== modified file 'openlp/plugins/songs/lib/mediaitem.py'
--- openlp/plugins/songs/lib/mediaitem.py	2017-12-29 09:15:48 +0000
+++ openlp/plugins/songs/lib/mediaitem.py	2018-02-03 14:18:52 +0000
@@ -321,9 +321,12 @@
         :param search_results: A tuple containing (songbook entry, book name, song title, song id)
         :return: None
         """
-        def get_songbook_key(result):
-            """Get the key to sort by"""
-            return (get_natural_key(result[1]), get_natural_key(result[0]), get_natural_key(result[2]))
+        def get_songbook_key(text_array):
+            """
+            Get the key to sort by
+            :param text_array: the result text to be processed.
+            """
+            return get_natural_key(text_array[1]), get_natural_key(text_array[0]), get_natural_key(text_array[2])
 
         log.debug('display results Book')
         self.list_view.clear()
@@ -373,7 +376,7 @@
         """
         def get_theme_key(song):
             """Get the key to sort by"""
-            return (get_natural_key(song.theme_name), song.sort_key)
+            return get_natural_key(song.theme_name), song.sort_key
 
         log.debug('display results Themes')
         self.list_view.clear()
@@ -396,7 +399,7 @@
         """
         def get_cclinumber_key(song):
             """Get the key to sort by"""
-            return (get_natural_key(song.ccli_number), song.sort_key)
+            return get_natural_key(song.ccli_number), song.sort_key
 
         log.debug('display results CCLI number')
         self.list_view.clear()
@@ -460,6 +463,8 @@
         """
         Called by ServiceManager or SlideController by event passing the Song Id in the payload along with an indicator
         to say which type of display is required.
+        :param song_id: the id of the song
+        :param preview: show we preview after the update
         """
         log.debug('on_remote_edit for song {song}'.format(song=song_id))
         song_id = int(song_id)
@@ -721,7 +726,8 @@
         self.generate_footer(item, song)
         return item
 
-    def _authors_match(self, song, authors):
+    @staticmethod
+    def _authors_match(song, authors):
         """
         Checks whether authors from a song in the database match the authors of the song to be imported.
 
@@ -738,11 +744,12 @@
         # List must be empty at the end
         return not author_list
 
-    def search(self, string, show_error):
+    def search(self, string, show_error=True):
         """
         Search for some songs
         :param string: The string to show
         :param show_error: Is this an error?
+        :return: the results of the search
         """
         search_results = self.search_entire(string)
         return [[song.id, song.title, song.alternate_title] for song in search_results]

=== modified file 'tests/functional/openlp_plugins/bibles/test_mediaitem.py'
--- tests/functional/openlp_plugins/bibles/test_mediaitem.py	2017-12-29 09:15:48 +0000
+++ tests/functional/openlp_plugins/bibles/test_mediaitem.py	2018-02-03 14:18:52 +0000
@@ -167,7 +167,7 @@
         # THEN: It should be a subclass of :class:`MediaManagerItem`
         assert isinstance(self.media_item, MediaManagerItem)
 
-    def test_steup_item(self):
+    def test_setup_item(self):
         """
         Test the setup_item method
         """

=== removed file 'tests/functional/openlp_plugins/presentations/test_pptviewcontroller.py'
--- tests/functional/openlp_plugins/presentations/test_pptviewcontroller.py	2017-12-29 10:19:33 +0000
+++ tests/functional/openlp_plugins/presentations/test_pptviewcontroller.py	1970-01-01 00:00:00 +0000
@@ -1,226 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection                                      #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2018 OpenLP Developers                                   #
-# --------------------------------------------------------------------------- #
-# 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                          #
-###############################################################################
-"""
-This module contains tests for the pptviewcontroller module of the Presentations plugin.
-"""
-import shutil
-from tempfile import mkdtemp
-from unittest import TestCase, skipIf
-from unittest.mock import MagicMock, patch
-
-from openlp.core.common import is_win
-from openlp.core.common.path import Path
-from openlp.plugins.presentations.lib.pptviewcontroller import PptviewDocument, PptviewController
-from tests.helpers.testmixin import TestMixin
-from tests.utils.constants import RESOURCE_PATH
-
-
-class TestPptviewController(TestCase, TestMixin):
-    """
-    Test the PptviewController Class
-    """
-    def setUp(self):
-        """
-        Set up the patches and mocks need for all tests.
-        """
-        self.setup_application()
-        self.build_settings()
-        self.mock_plugin = MagicMock()
-        self.temp_folder = mkdtemp()
-        self.mock_plugin.settings_section = self.temp_folder
-
-    def tearDown(self):
-        """
-        Stop the patches
-        """
-        self.destroy_settings()
-        shutil.rmtree(self.temp_folder)
-
-    def test_constructor(self):
-        """
-        Test the Constructor from the PptViewController
-        """
-        # GIVEN: No presentation controller
-        controller = None
-
-        # WHEN: The presentation controller object is created
-        controller = PptviewController(plugin=self.mock_plugin)
-
-        # THEN: The name of the presentation controller should be correct
-        assert 'Powerpoint Viewer' == controller.name, 'The name of the presentation controller should be correct'
-
-    def test_check_available(self):
-        """
-        Test check_available / check_installed
-        """
-        # GIVEN: A mocked dll loader and a controller
-        with patch('ctypes.cdll.LoadLibrary') as mocked_load_library:
-            mocked_process = MagicMock()
-            mocked_process.CheckInstalled.return_value = True
-            mocked_load_library.return_value = mocked_process
-            controller = PptviewController(plugin=self.mock_plugin)
-
-            # WHEN: check_available is called
-            available = controller.check_available()
-
-            # THEN: On windows it should return True, on other platforms False
-            if is_win():
-                assert available is True, 'check_available should return True on windows.'
-            else:
-                assert available is False, 'check_available should return False when not on windows.'
-
-
-class TestPptviewDocument(TestCase):
-    """
-    Test the PptviewDocument Class
-    """
-    def setUp(self):
-        """
-        Set up the patches and mocks need for all tests.
-        """
-        self.pptview_document_create_thumbnails_patcher = patch(
-            'openlp.plugins.presentations.lib.pptviewcontroller.PptviewDocument.create_thumbnails')
-        self.pptview_document_stop_presentation_patcher = patch(
-            'openlp.plugins.presentations.lib.pptviewcontroller.PptviewDocument.stop_presentation')
-        self.presentation_document_get_temp_folder_patcher = patch(
-            'openlp.plugins.presentations.lib.pptviewcontroller.PresentationDocument.get_temp_folder')
-        self.presentation_document_setup_patcher = patch(
-            'openlp.plugins.presentations.lib.pptviewcontroller.PresentationDocument._setup')
-        self.screen_list_patcher = patch('openlp.plugins.presentations.lib.pptviewcontroller.ScreenList')
-        self.rect_patcher = MagicMock()
-        self.mock_pptview_document_create_thumbnails = self.pptview_document_create_thumbnails_patcher.start()
-        self.mock_pptview_document_stop_presentation = self.pptview_document_stop_presentation_patcher.start()
-        self.mock_presentation_document_get_temp_folder = self.presentation_document_get_temp_folder_patcher.start()
-        self.mock_presentation_document_setup = self.presentation_document_setup_patcher.start()
-        self.mock_rect = self.rect_patcher.start()
-        self.mock_screen_list = self.screen_list_patcher.start()
-        self.mock_controller = MagicMock()
-        self.mock_presentation = MagicMock()
-        self.temp_folder = mkdtemp()
-        self.mock_presentation_document_get_temp_folder.return_value = self.temp_folder
-
-    def tearDown(self):
-        """
-        Stop the patches
-        """
-        self.pptview_document_create_thumbnails_patcher.stop()
-        self.pptview_document_stop_presentation_patcher.stop()
-        self.presentation_document_get_temp_folder_patcher.stop()
-        self.presentation_document_setup_patcher.stop()
-        self.rect_patcher.stop()
-        self.screen_list_patcher.stop()
-        shutil.rmtree(self.temp_folder)
-
-    @skipIf(not is_win(), 'Not Windows')
-    def test_load_presentation_succesful(self):
-        """
-        Test the PptviewDocument.load_presentation() method when the PPT is successfully opened
-        """
-        # GIVEN: A reset mocked_os
-        self.mock_controller.process.OpenPPT.return_value = 0
-        instance = PptviewDocument(self.mock_controller, self.mock_presentation)
-        instance.file_path = 'test\path.ppt'
-
-        # WHEN: The temporary directory exists and OpenPPT returns successfully (not -1)
-        result = instance.load_presentation()
-
-        # THEN: PptviewDocument.load_presentation should return True
-        assert result is True
-
-    @skipIf(not is_win(), 'Not Windows')
-    def test_load_presentation_un_succesful(self):
-        """
-        Test the PptviewDocument.load_presentation() method when the temporary directory does not exist and the PPT is
-        not successfully opened
-        """
-        # GIVEN: A reset mock_os_isdir
-        self.mock_controller.process.OpenPPT.return_value = -1
-        instance = PptviewDocument(self.mock_controller, self.mock_presentation)
-        instance.file_path = 'test\path.ppt'
-
-        # WHEN: The temporary directory does not exist and OpenPPT returns unsuccessfully (-1)
-        with patch.object(instance, 'get_temp_folder') as mocked_get_folder:
-            mocked_get_folder.return_value = MagicMock(spec=Path)
-            result = instance.load_presentation()
-
-        # THEN: The temp folder should be created and PptviewDocument.load_presentation should return False
-        assert result is False
-
-    def test_create_titles_and_notes(self):
-        """
-        Test PowerpointController.create_titles_and_notes
-        """
-        # GIVEN: mocked PresentationController.save_titles_and_notes and a pptx file
-        doc = PptviewDocument(self.mock_controller, self.mock_presentation)
-        doc.file_path = RESOURCE_PATH / 'presentations' / 'test.pptx'
-        doc.save_titles_and_notes = MagicMock()
-
-        # WHEN reading the titles and notes
-        doc.create_titles_and_notes()
-
-        # THEN save_titles_and_notes should have been called once with empty arrays
-        doc.save_titles_and_notes.assert_called_once_with(['Test 1\n', '\n', 'Test 2\n', 'Test 4\n', 'Test 3\n'],
-                                                          ['Notes for slide 1', 'Inserted', 'Notes for slide 2',
-                                                           'Notes \nfor slide 4', 'Notes for slide 3'])
-
-    def test_create_titles_and_notes_nonexistent_file(self):
-        """
-        Test PowerpointController.create_titles_and_notes with nonexistent file
-        """
-        # GIVEN: mocked PresentationController.save_titles_and_notes and an nonexistent file
-        with patch('builtins.open') as mocked_open, \
-                patch.object(Path, 'exists') as mocked_path_exists, \
-                patch('openlp.plugins.presentations.lib.presentationcontroller.create_paths') as \
-                mocked_dir_exists:
-            mocked_path_exists.return_value = False
-            mocked_dir_exists.return_value = False
-            doc = PptviewDocument(self.mock_controller, self.mock_presentation)
-            doc.file_path = Path('Idontexist.pptx')
-            doc.save_titles_and_notes = MagicMock()
-
-            # WHEN: Reading the titles and notes
-            doc.create_titles_and_notes()
-
-            # THEN: File existens should have been checked, and not have been opened.
-            doc.save_titles_and_notes.assert_called_once_with(None, None)
-            mocked_path_exists.assert_called_with()
-            assert mocked_open.call_count == 0, 'There should be no calls to open a file.'
-
-    def test_create_titles_and_notes_invalid_file(self):
-        """
-        Test PowerpointController.create_titles_and_notes with invalid file
-        """
-        # GIVEN: mocked PresentationController.save_titles_and_notes and an invalid file
-        with patch('builtins.open') as mocked_open, \
-                patch('openlp.plugins.presentations.lib.pptviewcontroller.zipfile.is_zipfile') as mocked_is_zf:
-            mocked_is_zf.return_value = False
-            mocked_open.filesize = 10
-            doc = PptviewDocument(self.mock_controller, self.mock_presentation)
-            doc.file_path = RESOURCE_PATH / 'presentations' / 'test.ppt'
-            doc.save_titles_and_notes = MagicMock()
-
-            # WHEN: reading the titles and notes
-            doc.create_titles_and_notes()
-
-            # THEN:
-            doc.save_titles_and_notes.assert_called_once_with(None, None)
-            assert mocked_is_zf.call_count == 1, 'is_zipfile should have been called once'

_______________________________________________
Mailing list: https://launchpad.net/~openlp-core
Post to     : openlp-core@lists.launchpad.net
Unsubscribe : https://launchpad.net/~openlp-core
More help   : https://help.launchpad.net/ListHelp

Reply via email to