Merge lp:~trb143/openlp/cleanups2018 into lp:openlp

Proposed by Tim Bentley
Status: Merged
Merged at revision: 2812
Proposed branch: lp:~trb143/openlp/cleanups2018
Merge into: lp:openlp
Diff against target: 2937 lines (+148/-2159)
20 files modified
openlp/core/api/http/wsgiapp.py (+4/-0)
openlp/core/app.py (+2/-1)
openlp/core/common/mixins.py (+11/-1)
openlp/core/common/settings.py (+2/-1)
openlp/core/ui/aboutdialog.py (+1/-1)
openlp/core/ui/mainwindow.py (+16/-22)
openlp/core/ui/servicemanager.py (+27/-46)
openlp/core/ui/slidecontroller.py (+8/-8)
openlp/plugins/bibles/lib/mediaitem.py (+7/-3)
openlp/plugins/presentations/lib/pptviewcontroller.py (+0/-307)
openlp/plugins/presentations/lib/pptviewlib/README.TXT (+0/-121)
openlp/plugins/presentations/lib/pptviewlib/ppttest.py (+0/-210)
openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp (+0/-920)
openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h (+0/-80)
openlp/plugins/presentations/lib/pptviewlib/pptviewlib.vcproj (+0/-202)
openlp/plugins/presentations/presentationplugin.py (+1/-2)
openlp/plugins/songs/lib/mediaitem.py (+14/-7)
tests/functional/openlp_core/api/endpoint/test_controller.py (+54/-0)
tests/functional/openlp_plugins/bibles/test_mediaitem.py (+1/-1)
tests/functional/openlp_plugins/presentations/test_pptviewcontroller.py (+0/-226)
To merge this branch: bzr merge lp:~trb143/openlp/cleanups2018
Reviewer Review Type Date Requested Status
Tomas Groth Approve
Review via email: mp+337120@code.launchpad.net

This proposal supersedes a proposal from 2018-02-03.

To post a comment you must log in.
Revision history for this message
Tomas Groth (tomasgroth) wrote :

Looks good to me

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openlp/core/api/http/wsgiapp.py'
2--- openlp/core/api/http/wsgiapp.py 2017-12-29 09:15:48 +0000
3+++ openlp/core/api/http/wsgiapp.py 2018-02-03 15:03:00 +0000
4@@ -69,6 +69,7 @@
5 """
6 Create a Response object from response
7 """
8+ log.debug("in Make response")
9 if isinstance(view_result, Response):
10 return view_result
11 elif isinstance(view_result, tuple):
12@@ -88,6 +89,9 @@
13 elif isinstance(view_result, str):
14 return Response(body=view_result, status=200,
15 content_type='text/html', charset='utf8')
16+ else:
17+ return Response(body=view_result, status=200,
18+ content_type='text/plain', charset='utf8')
19
20
21 def _handle_exception(error):
22
23=== modified file 'openlp/core/app.py'
24--- openlp/core/app.py 2018-01-12 18:29:32 +0000
25+++ openlp/core/app.py 2018-02-03 15:03:00 +0000
26@@ -120,7 +120,8 @@
27 self.main_window.show()
28 if can_show_splash:
29 # now kill the splashscreen
30- self.splash.finish(self.main_window)
31+ log.debug('Splashscreen closing')
32+ self.splash.close()
33 log.debug('Splashscreen closed')
34 # make sure Qt really display the splash screen
35 self.processEvents()
36
37=== modified file 'openlp/core/common/mixins.py'
38--- openlp/core/common/mixins.py 2017-12-29 09:15:48 +0000
39+++ openlp/core/common/mixins.py 2018-02-03 15:03:00 +0000
40@@ -56,7 +56,10 @@
41 def wrapped(*args, **kwargs):
42 parent.logger.debug("Entering {function}".format(function=func.__name__))
43 try:
44- return func(*args, **kwargs)
45+ if len(inspect.signature(func).parameters.values()):
46+ return func(*args, **kwargs)
47+ else:
48+ return func(*args)
49 except Exception as e:
50 if parent.logger.getEffectiveLevel() <= logging.ERROR:
51 parent.logger.error('Exception in {function} : {error}'.format(function=func.__name__,
52@@ -89,6 +92,13 @@
53 trace_error_handler(self.logger)
54 self.logger.error(message)
55
56+ def log_critical(self, message):
57+ """
58+ Common log critical handler which prints the calling path
59+ """
60+ trace_error_handler(self.logger)
61+ self.logger.critical(message)
62+
63 def log_exception(self, message):
64 """
65 Common log exception handler which prints the calling path
66
67=== modified file 'openlp/core/common/settings.py'
68--- openlp/core/common/settings.py 2017-12-29 09:15:48 +0000
69+++ openlp/core/common/settings.py 2018-02-03 15:03:00 +0000
70@@ -259,7 +259,8 @@
71 ('media/last directory', 'media/last directory', [(str_to_path, None)]),
72 ('songuasge/db password', 'songusage/db password', []),
73 ('songuasge/db hostname', 'songusage/db hostname', []),
74- ('songuasge/db database', 'songusage/db database', [])
75+ ('songuasge/db database', 'songusage/db database', []),
76+ ('presentations / Powerpoint Viewer', '', [])
77 ]
78
79 @staticmethod
80
81=== modified file 'openlp/core/ui/aboutdialog.py'
82--- openlp/core/ui/aboutdialog.py 2017-12-29 09:15:48 +0000
83+++ openlp/core/ui/aboutdialog.py 2018-02-03 15:03:00 +0000
84@@ -98,7 +98,7 @@
85 'OpenLP is free church presentation software, or lyrics '
86 'projection software, used to display slides of songs, Bible '
87 'verses, videos, images, and even presentations (if '
88- 'Impress, PowerPoint or PowerPoint Viewer is installed) '
89+ 'Impress or PowerPoint is installed) '
90 'for church worship using a computer and a data projector.\n'
91 '\n'
92 'Find out more about OpenLP: http://openlp.org/\n'
93
94=== modified file 'openlp/core/ui/mainwindow.py'
95--- openlp/core/ui/mainwindow.py 2018-01-20 09:30:30 +0000
96+++ openlp/core/ui/mainwindow.py 2018-02-03 15:03:00 +0000
97@@ -37,7 +37,7 @@
98 from openlp.core.common.actions import ActionList, CategoryOrder
99 from openlp.core.common.applocation import AppLocation
100 from openlp.core.common.i18n import LanguageManager, UiStrings, translate
101-from openlp.core.common.mixins import RegistryProperties
102+from openlp.core.common.mixins import LogMixin, RegistryProperties
103 from openlp.core.common.path import Path, copyfile, create_paths
104 from openlp.core.common.registry import Registry
105 from openlp.core.common.settings import Settings
106@@ -56,8 +56,6 @@
107 from openlp.core.widgets.dialogs import FileDialog
108 from openlp.core.widgets.docks import OpenLPDockWidget, MediaDockManager
109
110-log = logging.getLogger(__name__)
111-
112
113 class Ui_MainWindow(object):
114 """
115@@ -465,12 +463,10 @@
116 self.mode_live_item.setStatusTip(translate('OpenLP.MainWindow', 'Use layout that focuses on Live.'))
117
118
119-class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, RegistryProperties):
120+class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, LogMixin, RegistryProperties):
121 """
122 The main window.
123 """
124- log.info('MainWindow loaded')
125-
126 def __init__(self):
127 """
128 This constructor sets up the interface, the various managers, and the plugins.
129@@ -557,7 +553,7 @@
130 wait_dialog.setCancelButton(None)
131 wait_dialog.show()
132 for thread_name in self.application.worker_threads.keys():
133- log.debug('Waiting for thread %s', thread_name)
134+ self.log_debug('Waiting for thread %s' % thread_name)
135 self.application.processEvents()
136 thread = self.application.worker_threads[thread_name]['thread']
137 worker = self.application.worker_threads[thread_name]['worker']
138@@ -595,7 +591,7 @@
139 """
140 Called on start up to restore the last active media plugin.
141 """
142- log.info('Load data from Settings')
143+ self.log_info('Load data from Settings')
144 if Settings().value('advanced/save current plugin'):
145 saved_plugin_id = Settings().value('advanced/current media plugin')
146 if saved_plugin_id != -1:
147@@ -627,7 +623,6 @@
148
149 :param version: The Version to be displayed.
150 """
151- log.debug('version_notice')
152 version_text = translate('OpenLP.MainWindow', 'Version {new} of OpenLP is now available for download (you are '
153 'currently running version {current}). \n\nYou can download the latest version from '
154 'http://openlp.org/.').format(new=version, current=get_version()[u'full'])
155@@ -774,7 +769,8 @@
156 self.application.splash.close()
157 QtWidgets.QMessageBox.information(self, title, message)
158
159- def on_help_web_site_clicked(self):
160+ @staticmethod
161+ def on_help_web_site_clicked():
162 """
163 Load the OpenLP website
164 """
165@@ -891,7 +887,7 @@
166 settings = Settings()
167 import_settings = Settings(str(temp_config_path), Settings.IniFormat)
168
169- log.info('hook upgrade_plugin_settings')
170+ self.log_info('hook upgrade_plugin_settings')
171 self.plugin_manager.hook_upgrade_plugin_settings(import_settings)
172 # Upgrade settings to prepare the import.
173 if import_settings.can_upgrade():
174@@ -929,7 +925,8 @@
175 value = import_settings.value(section_key)
176 except KeyError:
177 value = None
178- log.warning('The key "{key}" does not exist (anymore), so it will be skipped.'.format(key=section_key))
179+ self.log_warning('The key "{key}" does not exist (anymore), so it will be skipped.'.
180+ format(key=section_key))
181 if value is not None:
182 settings.setValue('{key}'.format(key=section_key), value)
183 now = datetime.now()
184@@ -1013,7 +1010,6 @@
185 """
186 The screen has changed so we have to update components such as the renderer.
187 """
188- log.debug('screen_changed')
189 self.application.set_busy_cursor()
190 self.image_manager.update_display()
191 self.renderer.update_display()
192@@ -1076,7 +1072,7 @@
193 if Settings().value('advanced/save current plugin'):
194 Settings().setValue('advanced/current media plugin', self.media_tool_box.currentIndex())
195 # Call the cleanup method to shutdown plugins.
196- log.info('cleanup plugins')
197+ self.log_info('cleanup plugins')
198 self.plugin_manager.finalise_plugins()
199 if save_settings:
200 # Save settings
201@@ -1216,7 +1212,6 @@
202 """
203 Load the main window settings.
204 """
205- log.debug('Loading QSettings')
206 settings = Settings()
207 # Remove obsolete entries.
208 settings.remove('custom slide')
209@@ -1243,7 +1238,6 @@
210 # Exit if we just did a settings import.
211 if self.settings_imported:
212 return
213- log.debug('Saving QSettings')
214 settings = Settings()
215 settings.beginGroup(self.general_settings_section)
216 settings.setValue('recent files', self.recent_files)
217@@ -1268,7 +1262,7 @@
218 if not recent_path.is_file():
219 continue
220 count += 1
221- log.debug('Recent file name: {name}'.format(name=recent_path))
222+ self.log_debug('Recent file name: {name}'.format(name=recent_path))
223 action = create_action(self, '',
224 text='&{n} {name}'.format(n=count, name=recent_path.name),
225 data=recent_path, triggers=self.service_manager_contents.on_recent_service_clicked)
226@@ -1350,21 +1344,21 @@
227 """
228 Change the data directory.
229 """
230- log.info('Changing data path to {newpath}'.format(newpath=self.new_data_path))
231+ self.log_info('Changing data path to {newpath}'.format(newpath=self.new_data_path))
232 old_data_path = AppLocation.get_data_path()
233 # Copy OpenLP data to new location if requested.
234 self.application.set_busy_cursor()
235 if self.copy_data:
236- log.info('Copying data to new path')
237+ self.log_info('Copying data to new path')
238 try:
239 self.show_status_message(
240 translate('OpenLP.MainWindow', 'Copying OpenLP data to new data directory location - {path} '
241 '- Please wait for copy to finish').format(path=self.new_data_path))
242 dir_util.copy_tree(str(old_data_path), str(self.new_data_path))
243- log.info('Copy successful')
244+ self.log_info('Copy successful')
245 except (OSError, DistutilsFileError) as why:
246 self.application.set_normal_cursor()
247- log.exception('Data copy failed {err}'.format(err=str(why)))
248+ self.log_exception('Data copy failed {err}'.format(err=str(why)))
249 err_text = translate('OpenLP.MainWindow',
250 'OpenLP Data directory copy failed\n\n{err}').format(err=str(why)),
251 QtWidgets.QMessageBox.critical(self, translate('OpenLP.MainWindow', 'New Data Directory Error'),
252@@ -1372,7 +1366,7 @@
253 QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok))
254 return False
255 else:
256- log.info('No data copy requested')
257+ self.log_info('No data copy requested')
258 # Change the location of data directory in config file.
259 settings = QtCore.QSettings()
260 settings.setValue('advanced/data path', self.new_data_path)
261
262=== modified file 'openlp/core/ui/servicemanager.py'
263--- openlp/core/ui/servicemanager.py 2018-01-22 21:37:00 +0000
264+++ openlp/core/ui/servicemanager.py 2018-02-03 15:03:00 +0000
265@@ -302,7 +302,7 @@
266 class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixin, RegistryProperties):
267 """
268 Manages the services. This involves taking text strings from plugins and adding them to the service. This service
269- can then be zipped up with all the resources used into one OSZ or oszl file for use on any OpenLP v2 installation.
270+ can then be zipped up with all the resources used into one OSZ or OSZL file for use on any OpenLP installation.
271 Also handles the UI tasks of moving things up and down etc.
272 """
273 servicemanager_set_item = QtCore.pyqtSignal(int)
274@@ -415,10 +415,9 @@
275 if suffix not in self.suffixes:
276 self.suffixes.append(suffix)
277
278- def on_new_service_clicked(self, field=None):
279+ def on_new_service_clicked(self):
280 """
281 Create a new service.
282- :param field:
283 """
284 if self.is_modified():
285 result = self.save_modified_service()
286@@ -466,10 +465,9 @@
287 QtWidgets.QMessageBox.Save | QtWidgets.QMessageBox.Discard |
288 QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Save)
289
290- def on_recent_service_clicked(self, field=None):
291+ def on_recent_service_clicked(self):
292 """
293 Load a recent file as the service triggered by mainwindow recent service list.
294- :param field:
295 """
296 if self.is_modified():
297 result = self.save_modified_service()
298@@ -608,7 +606,7 @@
299 self.set_modified(False)
300 return True
301
302- def save_file_as(self, field=None):
303+ def save_file_as(self):
304 """
305 Get a file name and then call :func:`ServiceManager.save_file` to save the file.
306 """
307@@ -660,10 +658,9 @@
308 self.set_file_name(file_path)
309 self.decide_save_method()
310
311- def decide_save_method(self, field=None):
312+ def decide_save_method(self):
313 """
314 Determine which type of save method to use.
315- :param field:
316 """
317 if not self.file_name():
318 return self.save_file_as()
319@@ -824,10 +821,9 @@
320 theme_action.setChecked(True)
321 self.menu.exec(self.service_manager_list.mapToGlobal(point))
322
323- def on_service_item_note_form(self, field=None):
324+ def on_service_item_note_form(self):
325 """
326 Allow the service note to be edited
327- :param field:
328 """
329 item = self.find_service_item()[0]
330 self.service_note_form.text_edit.setPlainText(self.service_items[item]['service_item'].notes)
331@@ -836,21 +832,18 @@
332 self.repaint_service_list(item, -1)
333 self.set_modified()
334
335- def on_start_time_form(self, field=None):
336+ def on_start_time_form(self):
337 """
338 Opens a dialog to type in service item notes.
339- :param field:
340 """
341 item = self.find_service_item()[0]
342 self.start_time_form.item = self.service_items[item]
343 if self.start_time_form.exec():
344 self.repaint_service_list(item, -1)
345
346- def toggle_auto_play_slides_once(self, field=None):
347+ def toggle_auto_play_slides_once(self):
348 """
349 Toggle Auto play slide once. Inverts auto play once option for the item
350-
351- :param field:
352 """
353 item = self.find_service_item()[0]
354 service_item = self.service_items[item]['service_item']
355@@ -863,11 +856,9 @@
356 self.main_window.general_settings_section + '/loop delay')
357 self.set_modified()
358
359- def toggle_auto_play_slides_loop(self, field=None):
360+ def toggle_auto_play_slides_loop(self):
361 """
362 Toggle Auto play slide loop.
363-
364- :param field:
365 """
366 item = self.find_service_item()[0]
367 service_item = self.service_items[item]['service_item']
368@@ -880,10 +871,9 @@
369 self.main_window.general_settings_section + '/loop delay')
370 self.set_modified()
371
372- def on_timed_slide_interval(self, field=None):
373+ def on_timed_slide_interval(self):
374 """
375 Shows input dialog for enter interval in seconds for delay
376- :param field:
377 """
378 item = self.find_service_item()[0]
379 service_item = self.service_items[item]['service_item']
380@@ -906,7 +896,7 @@
381 service_item.auto_play_slides_once = False
382 self.set_modified()
383
384- def on_auto_start(self, field=None):
385+ def on_auto_start(self):
386 """
387 Toggles to Auto Start Setting.
388 """
389@@ -914,10 +904,9 @@
390 self.service_items[item]['service_item'].will_auto_start = \
391 not self.service_items[item]['service_item'].will_auto_start
392
393- def on_service_item_edit_form(self, field=None):
394+ def on_service_item_edit_form(self):
395 """
396 Opens a dialog to edit the service item and update the service display if changes are saved.
397- :param field:
398 """
399 item = self.find_service_item()[0]
400 self.service_item_edit_form.set_service_item(self.service_items[item]['service_item'])
401@@ -990,11 +979,9 @@
402 prev_item_last_slide = service_iterator.value()
403 service_iterator += 1
404
405- def on_set_item(self, message, field=None):
406+ def on_set_item(self, message):
407 """
408 Called by a signal to select a specific item and make it live usually from remote.
409-
410- :param field:
411 :param message: The data passed in from a remove message
412 """
413 self.log_debug(message)
414@@ -1060,10 +1047,9 @@
415 self.service_manager.collapsed(item.parent())
416 self.service_manager_list.setCurrentItem(item.parent())
417
418- def on_collapse_all(self, field=None):
419+ def on_collapse_all(self):
420 """
421 Collapse all the service items.
422- :param field:
423 """
424 for item in self.service_items:
425 item['expanded'] = False
426@@ -1080,10 +1066,9 @@
427 if item.childCount():
428 self.service_items[pos - 1]['expanded'] = False
429
430- def on_expand_all(self, field=None):
431+ def on_expand_all(self):
432 """
433 Collapse all the service items.
434- :param field:
435 """
436 for item in self.service_items:
437 item['expanded'] = True
438@@ -1100,10 +1085,9 @@
439 if item.childCount():
440 self.service_items[pos - 1]['expanded'] = True
441
442- def on_service_top(self, field=None):
443+ def on_service_top(self):
444 """
445 Move the current ServiceItem to the top of the list.
446- :param field:
447 """
448 item, child = self.find_service_item()
449 if item < len(self.service_items) and item != -1:
450@@ -1113,10 +1097,9 @@
451 self.repaint_service_list(0, child)
452 self.set_modified()
453
454- def on_service_up(self, field=None):
455+ def on_service_up(self):
456 """
457 Move the current ServiceItem one position up in the list.
458- :param field:
459 """
460 item, child = self.find_service_item()
461 if item > 0:
462@@ -1126,10 +1109,9 @@
463 self.repaint_service_list(item - 1, child)
464 self.set_modified()
465
466- def on_service_down(self, field=None):
467+ def on_service_down(self):
468 """
469 Move the current ServiceItem one position down in the list.
470- :param field:
471 """
472 item, child = self.find_service_item()
473 if item < len(self.service_items) and item != -1:
474@@ -1139,10 +1121,9 @@
475 self.repaint_service_list(item + 1, child)
476 self.set_modified()
477
478- def on_service_end(self, field=None):
479+ def on_service_end(self):
480 """
481 Move the current ServiceItem to the bottom of the list.
482- :param field:
483 """
484 item, child = self.find_service_item()
485 if item < len(self.service_items) and item != -1:
486@@ -1152,7 +1133,7 @@
487 self.repaint_service_list(len(self.service_items) - 1, child)
488 self.set_modified()
489
490- def on_delete_from_service(self, field=None):
491+ def on_delete_from_service(self):
492 """
493 Remove the current ServiceItem from the list.
494 :param field:
495@@ -1378,7 +1359,7 @@
496 self.drop_position = -1
497 self.set_modified()
498
499- def make_preview(self, field=None):
500+ def make_preview(self):
501 """
502 Send the current item to the Preview slide controller
503 :param field:
504@@ -1403,7 +1384,7 @@
505 else:
506 return self.service_items[item]['service_item']
507
508- def on_double_click_live(self, field=None):
509+ def on_double_click_live(self):
510 """
511 Send the current item to the Live slide controller but triggered by a tablewidget click event.
512 :param field:
513@@ -1411,7 +1392,7 @@
514 self.list_double_clicked = True
515 self.make_live()
516
517- def on_single_click_preview(self, field=None):
518+ def on_single_click_preview(self):
519 """
520 If single click previewing is enabled, and triggered by a tablewidget click event,
521 start a timeout to verify a double-click hasn't triggered.
522@@ -1463,7 +1444,7 @@
523 'is missing or inactive'))
524 self.application.set_normal_cursor()
525
526- def remote_edit(self, field=None):
527+ def remote_edit(self):
528 """
529 Triggers a remote edit to a plugin to allow item to be edited.
530 :param field:
531@@ -1475,7 +1456,7 @@
532 if new_item:
533 self.add_service_item(new_item, replace=True)
534
535- def on_service_item_rename(self, field=None):
536+ def on_service_item_rename(self):
537 """
538 Opens a dialog to rename the service item.
539
540@@ -1493,7 +1474,7 @@
541 self.repaint_service_list(item, -1)
542 self.set_modified()
543
544- def create_custom(self, field=None):
545+ def create_custom(self):
546 """
547 Saves the current text item as a custom slide
548 :param field:
549@@ -1613,7 +1594,7 @@
550 self.renderer.set_service_theme(self.service_theme)
551 self.regenerate_service_items()
552
553- def on_theme_change_action(self, field=None):
554+ def on_theme_change_action(self):
555 """
556 Handles theme change events
557
558
559=== modified file 'openlp/core/ui/slidecontroller.py'
560--- openlp/core/ui/slidecontroller.py 2017-12-29 09:15:48 +0000
561+++ openlp/core/ui/slidecontroller.py 2018-02-03 15:03:00 +0000
562@@ -545,14 +545,14 @@
563 self.on_theme_display(False)
564 self.on_hide_display(False)
565
566- def service_previous(self, field=None):
567+ def service_previous(self):
568 """
569 Live event to select the previous service item from the service manager.
570 """
571 self.keypress_queue.append(ServiceItemAction.Previous)
572 self._process_queue()
573
574- def service_next(self, field=None):
575+ def service_next(self):
576 """
577 Live event to select the next service item from the service manager.
578 """
579@@ -1103,7 +1103,7 @@
580 else:
581 Registry().execute('live_display_show')
582
583- def on_slide_selected(self, field=None):
584+ def on_slide_selected(self):
585 """
586 Slide selected in controller
587 Note for some reason a dummy field is required. Nothing is passed!
588@@ -1244,7 +1244,7 @@
589 self.preview_widget.change_slide(row)
590 self.slide_selected()
591
592- def on_slide_selected_previous(self, field=None):
593+ def on_slide_selected_previous(self):
594 """
595 Go to the previous slide.
596 """
597@@ -1372,7 +1372,7 @@
598 if event.timerId() == self.timer_id:
599 self.on_slide_selected_next(self.play_slides_loop.isChecked())
600
601- def on_edit_song(self, field=None):
602+ def on_edit_song(self):
603 """
604 From the preview display requires the service Item to be editied
605 """
606@@ -1381,16 +1381,16 @@
607 if new_item:
608 self.add_service_item(new_item)
609
610- def on_preview_add_to_service(self, field=None):
611+ def on_preview_add_to_service(self):
612 """
613 From the preview display request the Item to be added to service
614 """
615 if self.service_item:
616 self.service_manager.add_service_item(self.service_item)
617
618- def on_preview_double_click(self, field=None):
619+ def on_preview_double_click(self):
620 """
621- Triggered when a preview slide item is doubleclicked
622+ Triggered when a preview slide item is double clicked
623 """
624 if self.service_item:
625 if Settings().value('advanced/double click live') and Settings().value('core/auto unblank'):
626
627=== modified file 'openlp/plugins/bibles/lib/mediaitem.py'
628--- openlp/plugins/bibles/lib/mediaitem.py 2017-12-29 09:15:48 +0000
629+++ openlp/plugins/bibles/lib/mediaitem.py 2018-02-03 15:03:00 +0000
630@@ -384,7 +384,7 @@
631 This initialises the given bible, which means that its book names and their chapter numbers is added to the
632 combo boxes on the 'Select' Tab. This is not of any importance of the 'Search' Tab.
633
634- :param last_book_id: The "book reference id" of the book which is chosen at the moment. (int)
635+ :param last_book: The "book reference id" of the book which is chosen at the moment. (int)
636 :return: None
637 """
638 log.debug('initialise_advanced_bible {bible}, {ref}'.format(bible=self.bible, ref=last_book))
639@@ -574,6 +574,7 @@
640 Update the second bible. If changing from single to dual bible modes as if the user wants to clear the search
641 results, if not revert to the previously selected bible
642
643+ :param: selection not required by part of the signature
644 :return: None
645 """
646 new_selection = self.second_combo_box.currentData()
647@@ -1005,14 +1006,17 @@
648 }[self.settings.display_style]
649 return '{{su}}{bracket[0]}{verse_text}{bracket[1]}{{/su}}&nbsp;'.format(verse_text=verse_text, bracket=bracket)
650
651- def search(self, string, showError):
652+ def search(self, string, show_error=True):
653 """
654 Search for some Bible verses (by reference).
655+ :param string: search string
656+ :param show_error: do we show the error
657+ :return: the results of the search
658 """
659 if self.bible is None:
660 return []
661 reference = self.plugin.manager.parse_ref(self.bible.name, string)
662- search_results = self.plugin.manager.get_verses(self.bible.name, reference, showError)
663+ search_results = self.plugin.manager.get_verses(self.bible.name, reference, show_error)
664 if search_results:
665 verse_text = ' '.join([verse.text for verse in search_results])
666 return [[string, verse_text]]
667
668=== removed file 'openlp/plugins/presentations/lib/pptviewcontroller.py'
669--- openlp/plugins/presentations/lib/pptviewcontroller.py 2017-12-29 09:15:48 +0000
670+++ openlp/plugins/presentations/lib/pptviewcontroller.py 1970-01-01 00:00:00 +0000
671@@ -1,307 +0,0 @@
672-# -*- coding: utf-8 -*-
673-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
674-
675-###############################################################################
676-# OpenLP - Open Source Lyrics Projection #
677-# --------------------------------------------------------------------------- #
678-# Copyright (c) 2008-2018 OpenLP Developers #
679-# --------------------------------------------------------------------------- #
680-# This program is free software; you can redistribute it and/or modify it #
681-# under the terms of the GNU General Public License as published by the Free #
682-# Software Foundation; version 2 of the License. #
683-# #
684-# This program is distributed in the hope that it will be useful, but WITHOUT #
685-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
686-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
687-# more details. #
688-# #
689-# You should have received a copy of the GNU General Public License along #
690-# with this program; if not, write to the Free Software Foundation, Inc., 59 #
691-# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
692-###############################################################################
693-import logging
694-import re
695-import zipfile
696-from xml.etree import ElementTree
697-
698-from openlp.core.common import is_win
699-from openlp.core.common.applocation import AppLocation
700-from openlp.core.display.screens import ScreenList
701-from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument
702-
703-if is_win():
704- from ctypes import cdll
705- from ctypes.wintypes import RECT
706-
707-log = logging.getLogger(__name__)
708-
709-
710-class PptviewController(PresentationController):
711- """
712- Class to control interactions with PowerPoint Viewer Presentations. It creates the runtime Environment , Loads the
713- and Closes the Presentation. As well as triggering the correct activities based on the users input
714- """
715- log.info('PPTViewController loaded')
716-
717- def __init__(self, plugin):
718- """
719- Initialise the class
720- """
721- log.debug('Initialising')
722- self.process = None
723- super(PptviewController, self).__init__(plugin, 'Powerpoint Viewer', PptviewDocument)
724- self.supports = ['ppt', 'pps', 'pptx', 'ppsx', 'pptm']
725-
726- def check_available(self):
727- """
728- PPT Viewer is able to run on this machine.
729- """
730- log.debug('check_available')
731- if not is_win():
732- return False
733- return self.check_installed()
734-
735- if is_win():
736- def check_installed(self):
737- """
738- Check the viewer is installed.
739- """
740- log.debug('Check installed')
741- try:
742- self.start_process()
743- return self.process.CheckInstalled()
744- except OSError:
745- return False
746-
747- def start_process(self):
748- """
749- Loads the PPTVIEWLIB library.
750- """
751- if self.process:
752- return
753- log.debug('start PPTView')
754- dll_path = AppLocation.get_directory(AppLocation.AppDir) \
755- / 'plugins' / 'presentations' / 'lib' / 'pptviewlib' / 'pptviewlib.dll'
756- self.process = cdll.LoadLibrary(str(dll_path))
757- if log.isEnabledFor(logging.DEBUG):
758- self.process.SetDebug(1)
759-
760- def kill(self):
761- """
762- Called at system exit to clean up any running presentations
763- """
764- log.debug('Kill pptviewer')
765- while self.docs:
766- self.docs[0].close_presentation()
767-
768-
769-class PptviewDocument(PresentationDocument):
770- """
771- Class which holds information and controls a single presentation.
772- """
773- def __init__(self, controller, document_path):
774- """
775- Constructor, store information about the file and initialise.
776-
777- :param openlp.core.common.path.Path document_path: File path to the document to load
778- :rtype: None
779- """
780- log.debug('Init Presentation PowerPoint')
781- super().__init__(controller, document_path)
782- self.presentation = None
783- self.ppt_id = None
784- self.blanked = False
785- self.hidden = False
786-
787- def load_presentation(self):
788- """
789- Called when a presentation is added to the SlideController. It builds the environment, starts communication with
790- the background PptView task started earlier.
791- """
792- log.debug('LoadPresentation')
793- temp_path = self.get_temp_folder()
794- size = ScreenList().current['size']
795- rect = RECT(size.x(), size.y(), size.right(), size.bottom())
796- preview_path = temp_path / 'slide'
797- # Ensure that the paths are null terminated
798- file_path_utf16 = str(self.file_path).encode('utf-16-le') + b'\0'
799- preview_path_utf16 = str(preview_path).encode('utf-16-le') + b'\0'
800- if not temp_path.is_dir():
801- temp_path.mkdir(parents=True)
802- self.ppt_id = self.controller.process.OpenPPT(file_path_utf16, None, rect, preview_path_utf16)
803- if self.ppt_id >= 0:
804- self.create_thumbnails()
805- self.stop_presentation()
806- return True
807- else:
808- return False
809-
810- def create_thumbnails(self):
811- """
812- PPTviewLib creates large BMP's, but we want small PNG's for consistency. Convert them here.
813- """
814- log.debug('create_thumbnails')
815- if self.check_thumbnails():
816- return
817- log.debug('create_thumbnails proceeding')
818- for idx in range(self.get_slide_count()):
819- path = self.get_temp_folder() / 'slide{index:d}.bmp'.format(index=idx + 1)
820- self.convert_thumbnail(path, idx + 1)
821-
822- def create_titles_and_notes(self):
823- """
824- Extracts the titles and notes from the zipped file
825- and writes the list of titles (one per slide)
826- to 'titles.txt'
827- and the notes to 'slideNotes[x].txt'
828- in the thumbnails directory
829- """
830- titles = None
831- notes = None
832- # let's make sure we have a valid zipped presentation
833- if self.file_path.exists() and zipfile.is_zipfile(str(self.file_path)):
834- namespaces = {"p": "http://schemas.openxmlformats.org/presentationml/2006/main",
835- "a": "http://schemas.openxmlformats.org/drawingml/2006/main"}
836- # open the file
837- with zipfile.ZipFile(str(self.file_path)) as zip_file:
838- # find the presentation.xml to get the slide count
839- with zip_file.open('ppt/presentation.xml') as pres:
840- tree = ElementTree.parse(pres)
841- nodes = tree.getroot().findall(".//p:sldIdLst/p:sldId", namespaces=namespaces)
842- # initialize the lists
843- titles = ['' for i in range(len(nodes))]
844- notes = ['' for i in range(len(nodes))]
845- # loop thru the file list to find slides and notes
846- for zip_info in zip_file.infolist():
847- node_type = ''
848- index = -1
849- list_to_add = None
850- # check if it is a slide
851- match = re.search(r'slides/slide(.+)\.xml', zip_info.filename)
852- if match:
853- index = int(match.group(1)) - 1
854- node_type = 'ctrTitle'
855- list_to_add = titles
856- # or a note
857- match = re.search(r'notesSlides/notesSlide(.+)\.xml', zip_info.filename)
858- if match:
859- index = int(match.group(1)) - 1
860- node_type = 'body'
861- list_to_add = notes
862- # if it is one of our files, index shouldn't be -1
863- if index >= 0:
864- with zip_file.open(zip_info) as zipped_file:
865- tree = ElementTree.parse(zipped_file)
866- text = ''
867- nodes = tree.getroot().findall(".//p:ph[@type='" + node_type + "']../../..//p:txBody//a:t",
868- namespaces=namespaces)
869- # if we found any content
870- if nodes and len(nodes) > 0:
871- for node in nodes:
872- if len(text) > 0:
873- text += '\n'
874- text += node.text
875- # Let's remove the \n from the titles and
876- # just add one at the end
877- if node_type == 'ctrTitle':
878- text = text.replace('\n', ' ').replace('\x0b', ' ') + '\n'
879- list_to_add[index] = text
880- # now let's write the files
881- self.save_titles_and_notes(titles, notes)
882-
883- def close_presentation(self):
884- """
885- Close presentation and clean up objects. Triggered by new object being added to SlideController or OpenLP being
886- shut down.
887- """
888- log.debug('ClosePresentation')
889- if self.controller.process:
890- self.controller.process.ClosePPT(self.ppt_id)
891- self.ppt_id = -1
892- self.controller.remove_doc(self)
893-
894- def is_loaded(self):
895- """
896- Returns true if a presentation is loaded.
897- """
898- if self.ppt_id < 0:
899- return False
900- if self.get_slide_count() < 0:
901- return False
902- return True
903-
904- def is_active(self):
905- """
906- Returns true if a presentation is currently active.
907- """
908- return self.is_loaded() and not self.hidden
909-
910- def blank_screen(self):
911- """
912- Blanks the screen.
913- """
914- self.controller.process.Blank(self.ppt_id)
915- self.blanked = True
916-
917- def unblank_screen(self):
918- """
919- Unblanks (restores) the presentation.
920- """
921- self.controller.process.Unblank(self.ppt_id)
922- self.blanked = False
923-
924- def is_blank(self):
925- """
926- Returns true if screen is blank.
927- """
928- log.debug('is blank OpenOffice')
929- return self.blanked
930-
931- def stop_presentation(self):
932- """
933- Stops the current presentation and hides the output.
934- """
935- self.hidden = True
936- self.controller.process.Stop(self.ppt_id)
937-
938- def start_presentation(self):
939- """
940- Starts a presentation from the beginning.
941- """
942- if self.hidden:
943- self.hidden = False
944- self.controller.process.Resume(self.ppt_id)
945- else:
946- self.controller.process.RestartShow(self.ppt_id)
947-
948- def get_slide_number(self):
949- """
950- Returns the current slide number.
951- """
952- return self.controller.process.GetCurrentSlide(self.ppt_id)
953-
954- def get_slide_count(self):
955- """
956- Returns total number of slides.
957- """
958- return self.controller.process.GetSlideCount(self.ppt_id)
959-
960- def goto_slide(self, slide_no):
961- """
962- Moves to a specific slide in the presentation.
963-
964- :param slide_no: The slide the text is required for, starting at 1
965- """
966- self.controller.process.GotoSlide(self.ppt_id, slide_no)
967-
968- def next_step(self):
969- """
970- Triggers the next effect of slide on the running presentation.
971- """
972- self.controller.process.NextStep(self.ppt_id)
973-
974- def previous_step(self):
975- """
976- Triggers the previous slide on the running presentation.
977- """
978- self.controller.process.PrevStep(self.ppt_id)
979
980=== removed directory 'openlp/plugins/presentations/lib/pptviewlib'
981=== removed file 'openlp/plugins/presentations/lib/pptviewlib/README.TXT'
982--- openlp/plugins/presentations/lib/pptviewlib/README.TXT 2017-12-29 09:15:48 +0000
983+++ openlp/plugins/presentations/lib/pptviewlib/README.TXT 1970-01-01 00:00:00 +0000
984@@ -1,121 +0,0 @@
985-
986-PPTVIEWLIB - Control PowerPoint Viewer 2003/2007 (for openlp.org)
987-Copyright (C) 2008-2018 Jonathan Corwin (j@corwin.co.uk)
988-
989-This library wrappers the free Microsoft PowerPoint Viewer (2003/2007) program,
990-allowing it to be more easily controlled from another program.
991-
992-The PowerPoint Viewer must already be installed on the destination machine, and is
993-freely available at microsoft.com.
994-
995-The full Microsoft Office PowerPoint and PowerPoint Viewer 97 have a COM interface allowing
996-automation. This ability was removed from the 2003+ viewer offerings.
997-
998-To developers: I am not a C/C++ or Win32 API programmer as you can probably tell.
999-The code and API of this DLL could certainly do with some tidying up, and the
1000-error trapping, where it exists, is very basic. I'll happily accept patches!
1001-
1002-This library is covered by the GPL (http://www.gnu.org/licenses/)
1003-It is NOT covered by the LGPL, so can only be used in GPL compatable programs.
1004-(http://www.gnu.org/licenses/why-not-lgpl.html)
1005-
1006-This README.TXT must be distributed with the pptviewlib.dll
1007-
1008-This library has a limit of 50 PowerPoints which can be opened simultaneously.
1009-
1010-This project can be built with the free Microsoft Visual C++ 2008 Express Edition.
1011-
1012-USAGE
1013------
1014-BOOL CheckInstalled(void);
1015- Returns TRUE if PowerPointViewer is installed. FALSE if not.
1016-
1017-int OpenPPT(char *filename, HWND hParentWnd, RECT rect, char *previewpath);
1018-
1019- Opens the PowerPoint file, counts the number of slides, sizes and positions accordingly
1020- and creates preview images of each slide. Note PowerPoint Viewer only allows the
1021- slideshow to be resized whilst it is being loaded. It can be moved at any time however.
1022-
1023- The only way to count the number of slides is to step through the entire show. Therefore
1024- there will be a delay whilst opening large presentations for the first time.
1025- For pre XP/2003 systems, the slideshow will flicker as the screen snapshots are taken.
1026-
1027- filename: The PowerPoint file to be opened. Full path
1028- hParentWnd: The window which will become the parent of the slideshow window.
1029- Can be NULL.
1030- rect: The location/dimensions of the slideshow window.
1031- If all properties of this structure are zero, the dimensions of the hParentWnd
1032- are used.
1033- previewpath If specified, the prefix to use for snapshot images of each slide, in the
1034- form: previewpath + n + ".bmp", where n is the slide number.
1035- A file called previewpath + "info.txt" will also be created containing information
1036- about the PPT file, to speed up future openings of the unmodified file.
1037- Note it is up the calling program to directly access these images if they
1038- are required.
1039-
1040- RETURNS: An unique identifier to pass to other methods in this library.
1041- If < 0, then the PPT failed to open.
1042- If >=0, ClosePPT must be called when the PPT is no longer being used
1043- or when the calling program is closed to release resources/hooks.
1044-
1045-void ClosePPT(int id);
1046- Closes the presentation, releasing any resources and hooks.
1047-
1048- id: The value returned from OpenPPT.
1049-
1050-int GetCurrentSlide(int id);
1051- Returns the current slide number (from 1)
1052-
1053- id: The value returned from OpenPPT.
1054-
1055-int GetSlideCount(int id);
1056- Returns the total number of slides.
1057-
1058- id: The value returned from OpenPPT.
1059-
1060-void NextStep(int id);
1061- Advances one step (animation) through the slideshow.
1062-
1063- id: The value returned from OpenPPT.
1064-
1065-void PrevStep(int id);
1066- Goes backwards one step (animation) through the slideshow.
1067-
1068- id: The value returned from OpenPPT.
1069-
1070-void GotoSlide(int id, int slideno);
1071- Goes directly to a specific slide in the slideshow
1072-
1073- id: The value returned from OpenPPT.
1074- slideno: The number of the slide (from 1) to go directly to.
1075-
1076- If the slide has already been displayed, then the completed slide with animations performed
1077- will be shown. This is how the PowerPoint Viewer works so have no control over this.
1078-
1079-void RestartShow(int id);
1080- Restarts the show from the beginning. To reset animations, behind the scenes it
1081- has to travel to the end and step backwards though the entire show. Therefore
1082- for large presentations there might be a delay.
1083-
1084- id: The value returned from OpenPPT.
1085-
1086-void Blank(int id);
1087- Blanks the screen, colour black.
1088-
1089- id: The value returned from OpenPPT.
1090-
1091-void Unblank(int id)
1092- Unblanks the screen, restoring it to it's pre-blank state.
1093-
1094- id: The value returned from OpenPPT.
1095-
1096-void Stop(int id)
1097- Moves the slideshow off the screen. (There is no concept of stop show in the PowerPoint Viewer)
1098-
1099- id: The value returned from OpenPPT.
1100-
1101-void Resume(int id)
1102- Moves the slideshow display back onto the screen following a Stop()
1103-
1104- id: The value returned from OpenPPT.
1105-
1106
1107=== removed file 'openlp/plugins/presentations/lib/pptviewlib/ppttest.py'
1108--- openlp/plugins/presentations/lib/pptviewlib/ppttest.py 2017-12-29 09:15:48 +0000
1109+++ openlp/plugins/presentations/lib/pptviewlib/ppttest.py 1970-01-01 00:00:00 +0000
1110@@ -1,210 +0,0 @@
1111-# -*- coding: utf-8 -*-
1112-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
1113-
1114-###############################################################################
1115-# OpenLP - Open Source Lyrics Projection #
1116-# --------------------------------------------------------------------------- #
1117-# Copyright (c) 2008-2018 OpenLP Developers #
1118-# --------------------------------------------------------------------------- #
1119-# This program is free software; you can redistribute it and/or modify it #
1120-# under the terms of the GNU General Public License as published by the Free #
1121-# Software Foundation; version 2 of the License. #
1122-# #
1123-# This program is distributed in the hope that it will be useful, but WITHOUT #
1124-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
1125-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
1126-# more details. #
1127-# #
1128-# You should have received a copy of the GNU General Public License along #
1129-# with this program; if not, write to the Free Software Foundation, Inc., 59 #
1130-# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
1131-###############################################################################
1132-
1133-import sys
1134-from ctypes import *
1135-from ctypes.wintypes import RECT
1136-
1137-from PyQt5 import QtWidgets
1138-
1139-
1140-class PPTViewer(QtWidgets.QWidget):
1141- """
1142- Standalone Test Harness for the pptviewlib library
1143- """
1144- def __init__(self, parent=None):
1145- super(PPTViewer, self).__init__(parent)
1146- self.pptid = -1
1147- self.setWindowTitle('PowerPoint Viewer Test')
1148-
1149- ppt_label = QtWidgets.QLabel('Open PowerPoint file')
1150- slide_label = QtWidgets.QLabel('Go to slide #')
1151- self.pptEdit = QtWidgets.QLineEdit()
1152- self.slideEdit = QtWidgets.QLineEdit()
1153- x_label = QtWidgets.QLabel('X pos')
1154- y_label = QtWidgets.QLabel('Y pos')
1155- width_label = QtWidgets.QLabel('Width')
1156- height_label = QtWidgets.QLabel('Height')
1157- self.xEdit = QtWidgets.QLineEdit('100')
1158- self.yEdit = QtWidgets.QLineEdit('100')
1159- self.widthEdit = QtWidgets.QLineEdit('900')
1160- self.heightEdit = QtWidgets.QLineEdit('700')
1161- self.total = QtWidgets.QLabel()
1162- ppt_btn = QtWidgets.QPushButton('Open')
1163- ppt_dlg_btn = QtWidgets.QPushButton('...')
1164- folder_label = QtWidgets.QLabel('Slide .bmp path')
1165- self.folderEdit = QtWidgets.QLineEdit('slide')
1166- slide_btn = QtWidgets.QPushButton('Go')
1167- prev = QtWidgets.QPushButton('Prev')
1168- next = QtWidgets.QPushButton('Next')
1169- blank = QtWidgets.QPushButton('Blank')
1170- unblank = QtWidgets.QPushButton('Unblank')
1171- restart = QtWidgets.QPushButton('Restart')
1172- close = QtWidgets.QPushButton('Close')
1173- resume = QtWidgets.QPushButton('Resume')
1174- stop = QtWidgets.QPushButton('Stop')
1175- grid = QtWidgets.QGridLayout()
1176- row = 0
1177- grid.addWidget(folder_label, 0, 0)
1178- grid.addWidget(self.folderEdit, 0, 1)
1179- row += 1
1180- grid.addWidget(x_label, row, 0)
1181- grid.addWidget(self.xEdit, row, 1)
1182- grid.addWidget(y_label, row, 2)
1183- grid.addWidget(self.yEdit, row, 3)
1184- row += 1
1185- grid.addWidget(width_label, row, 0)
1186- grid.addWidget(self.widthEdit, row, 1)
1187- grid.addWidget(height_label, row, 2)
1188- grid.addWidget(self.heightEdit, row, 3)
1189- row += 1
1190- grid.addWidget(ppt_label, row, 0)
1191- grid.addWidget(self.pptEdit, row, 1)
1192- grid.addWidget(ppt_dlg_btn, row, 2)
1193- grid.addWidget(ppt_btn, row, 3)
1194- row += 1
1195- grid.addWidget(slide_label, row, 0)
1196- grid.addWidget(self.slideEdit, row, 1)
1197- grid.addWidget(slide_btn, row, 2)
1198- row += 1
1199- grid.addWidget(prev, row, 0)
1200- grid.addWidget(next, row, 1)
1201- row += 1
1202- grid.addWidget(blank, row, 0)
1203- grid.addWidget(unblank, row, 1)
1204- row += 1
1205- grid.addWidget(restart, row, 0)
1206- grid.addWidget(close, row, 1)
1207- row += 1
1208- grid.addWidget(stop, row, 0)
1209- grid.addWidget(resume, row, 1)
1210- ppt_btn.clicked.connect(self.openClick)
1211- ppt_dlg_btn.clicked.connect(self.openDialog)
1212- slide_btn.clicked.connect(self.gotoClick)
1213- prev.clicked.connect(self.prevClick)
1214- next.clicked.connect(self.nextClick)
1215- blank.clicked.connect(self.blankClick)
1216- unblank.clicked.connect(self.unblankClick)
1217- restart.clicked.connect(self.restartClick)
1218- close.clicked.connect(self.closeClick)
1219- stop.clicked.connect(self.stopClick)
1220- resume.clicked.connect(self.resumeClick)
1221- self.setLayout(grid)
1222- self.resize(300, 150)
1223-
1224- def prevClick(self):
1225- if self.pptid < 0:
1226- return
1227- self.pptdll.PrevStep(self.pptid)
1228- self.updateCurrSlide()
1229- app.processEvents()
1230-
1231- def nextClick(self):
1232- if self.pptid < 0:
1233- return
1234- self.pptdll.NextStep(self.pptid)
1235- self.updateCurrSlide()
1236- app.processEvents()
1237-
1238- def blankClick(self):
1239- if self.pptid < 0:
1240- return
1241- self.pptdll.Blank(self.pptid)
1242- app.processEvents()
1243-
1244- def unblankClick(self):
1245- if self.pptid < 0:
1246- return
1247- self.pptdll.Unblank(self.pptid)
1248- app.processEvents()
1249-
1250- def restartClick(self):
1251- if self.pptid < 0:
1252- return
1253- self.pptdll.RestartShow(self.pptid)
1254- self.updateCurrSlide()
1255- app.processEvents()
1256-
1257- def stopClick(self):
1258- if self.pptid < 0:
1259- return
1260- self.pptdll.Stop(self.pptid)
1261- app.processEvents()
1262-
1263- def resumeClick(self):
1264- if self.pptid < 0:
1265- return
1266- self.pptdll.Resume(self.pptid)
1267- app.processEvents()
1268-
1269- def closeClick(self):
1270- if self.pptid < 0:
1271- return
1272- self.pptdll.ClosePPT(self.pptid)
1273- self.pptid = -1
1274- app.processEvents()
1275-
1276- def openClick(self):
1277- oldid = self.pptid
1278- rect = RECT(int(self.xEdit.text()), int(self.yEdit.text()),
1279- int(self.widthEdit.text()), int(self.heightEdit.text()))
1280- filename = str(self.pptEdit.text().replace('/', '\\'))
1281- folder = str(self.folderEdit.text().replace('/', '\\'))
1282- print(filename, folder)
1283- self.pptid = self.pptdll.OpenPPT(filename, None, rect, folder)
1284- print('id: ' + str(self.pptid))
1285- if oldid >= 0:
1286- self.pptdll.ClosePPT(oldid)
1287- slides = self.pptdll.GetSlideCount(self.pptid)
1288- print('slidecount: ' + str(slides))
1289- self.total.setNum(self.pptdll.GetSlideCount(self.pptid))
1290- self.updateCurrSlide()
1291-
1292- def updateCurrSlide(self):
1293- if self.pptid < 0:
1294- return
1295- slide = str(self.pptdll.GetCurrentSlide(self.pptid))
1296- print('currslide: ' + slide)
1297- self.slideEdit.setText(slide)
1298- app.processEvents()
1299-
1300- def gotoClick(self):
1301- if self.pptid < 0:
1302- return
1303- print(self.slideEdit.text())
1304- self.pptdll.GotoSlide(self.pptid, int(self.slideEdit.text()))
1305- self.updateCurrSlide()
1306- app.processEvents()
1307-
1308- def openDialog(self):
1309- self.pptEdit.setText(QtWidgets.QFileDialog.getOpenFileName(self, 'Open file')[0])
1310-
1311-
1312-if __name__ == '__main__':
1313- pptdll = cdll.LoadLibrary(r'pptviewlib.dll')
1314- pptdll.SetDebug(1)
1315- print('Begin...')
1316- app = QtWidgets.QApplication(sys.argv)
1317- window = PPTViewer()
1318- window.pptdll = pptdll
1319- window.show()
1320- sys.exit(app.exec())
1321
1322=== removed file 'openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp'
1323--- openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp 2017-12-29 09:15:48 +0000
1324+++ openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp 1970-01-01 00:00:00 +0000
1325@@ -1,920 +0,0 @@
1326-/******************************************************************************
1327-* OpenLP - Open Source Lyrics Projection *
1328-* --------------------------------------------------------------------------- *
1329-* Copyright (c) 2008-2018 OpenLP Developers *
1330-* --------------------------------------------------------------------------- *
1331-* This program is free software; you can redistribute it and/or modify it *
1332-* under the terms of the GNU General Public License as published by the Free *
1333-* Software Foundation; version 2 of the License. *
1334-* *
1335-* This program is distributed in the hope that it will be useful, but WITHOUT *
1336-* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
1337-* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
1338-* more details. *
1339-* *
1340-* You should have received a copy of the GNU General Public License along *
1341-* with this program; if not, write to the Free Software Foundation, Inc., 59 *
1342-* Temple Place, Suite 330, Boston, MA 02111-1307 USA *
1343-******************************************************************************/
1344-
1345-#define WIN32_LEAN_AND_MEAN
1346-#include <windows.h>
1347-#include <string.h>
1348-#include <stdlib.h>
1349-#include <stdio.h>
1350-#include <io.h>
1351-#include <direct.h>
1352-#include <time.h>
1353-#include <sys/types.h>
1354-#include <sys/stat.h>
1355-#include "pptviewlib.h"
1356-
1357-// Because of the callbacks used by SetWindowsHookEx, the memory used needs to
1358-// be sharable across processes (the callbacks are done from a different
1359-// process) Therefore use data_seg with RWS memory.
1360-//
1361-// See http://msdn.microsoft.com/en-us/library/aa366551(VS.85).aspx for
1362-// alternative method of holding memory, removing fixed limits which would allow
1363-// dynamic number of items, rather than a fixed number. Use a Local\ mapping,
1364-// since global has UAC issues in Vista.
1365-
1366-#pragma data_seg(".PPTVIEWLIB")
1367-PPTVIEW pptView[MAX_PPTS] = {NULL};
1368-HHOOK globalHook = NULL;
1369-BOOL debug = FALSE;
1370-#pragma data_seg()
1371-#pragma comment(linker, "/SECTION:.PPTVIEWLIB,RWS")
1372-
1373-HINSTANCE hInstance = NULL;
1374-
1375-BOOL APIENTRY DllMain(HMODULE hModule, DWORD ulReasonForCall,
1376- LPVOID lpReserved)
1377-{
1378- hInstance = (HINSTANCE)hModule;
1379- switch(ulReasonForCall)
1380- {
1381- case DLL_PROCESS_ATTACH:
1382- DEBUG(L"PROCESS_ATTACH\n");
1383- break;
1384- case DLL_THREAD_ATTACH:
1385- //DEBUG(L"THREAD_ATTACH\n");
1386- break;
1387- case DLL_THREAD_DETACH:
1388- //DEBUG(L"THREAD_DETACH\n");
1389- break;
1390- case DLL_PROCESS_DETACH:
1391- // Clean up... hopefully there is only the one process attached?
1392- // We'll find out soon enough during tests!
1393- DEBUG(L"PROCESS_DETACH\n");
1394- for (int i = 0; i < MAX_PPTS; i++)
1395- ClosePPT(i);
1396- break;
1397- }
1398- return TRUE;
1399-}
1400-
1401-DllExport void SetDebug(BOOL onOff)
1402-{
1403- printf("SetDebug\n");
1404- debug = onOff;
1405- DEBUG(L"enabled\n");
1406-}
1407-
1408-DllExport BOOL CheckInstalled()
1409-{
1410- wchar_t cmdLine[MAX_PATH * 2];
1411-
1412- DEBUG(L"CheckInstalled\n");
1413- BOOL found = GetPPTViewerPath(cmdLine, sizeof(cmdLine));
1414- if(found)
1415- {
1416- DEBUG(L"Exe: %s\n", cmdLine);
1417- }
1418- return found;
1419-}
1420-
1421-// Open the PointPoint, count the slides and take a snapshot of each slide
1422-// for use in previews
1423-// previewpath is a prefix for the location to put preview images of each slide.
1424-// "<n>.bmp" will be appended to complete the path. E.g. "c:\temp\slide" would
1425-// create "c:\temp\slide1.bmp" slide2.bmp, slide3.bmp etc.
1426-// It will also create a *info.txt containing information about the ppt
1427-DllExport int OpenPPT(wchar_t *filename, HWND hParentWnd, RECT rect,
1428- wchar_t *previewPath)
1429-{
1430- STARTUPINFO si;
1431- PROCESS_INFORMATION pi;
1432- wchar_t cmdLine[MAX_PATH * 2];
1433- int id;
1434-
1435- DEBUG(L"OpenPPT start: %s; %s\n", filename, previewPath);
1436- DEBUG(L"OpenPPT start: %u; %i, %i, %i, %i\n", hParentWnd, rect.top,
1437- rect.left, rect.bottom, rect.right);
1438- if (GetPPTViewerPath(cmdLine, sizeof(cmdLine)) == FALSE)
1439- {
1440- DEBUG(L"OpenPPT: GetPPTViewerPath failed\n");
1441- return -1;
1442- }
1443- id = -1;
1444- for (int i = 0; i < MAX_PPTS; i++)
1445- {
1446- if (pptView[i].state == PPT_CLOSED)
1447- {
1448- id = i;
1449- break;
1450- }
1451- }
1452- if (id < 0)
1453- {
1454- DEBUG(L"OpenPPT: Too many PPTs\n");
1455- return -1;
1456- }
1457- memset(&pptView[id], 0, sizeof(PPTVIEW));
1458- wcscpy_s(pptView[id].filename, MAX_PATH, filename);
1459- wcscpy_s(pptView[id].previewPath, MAX_PATH, previewPath);
1460- pptView[id].state = PPT_CLOSED;
1461- pptView[id].slideCount = 0;
1462- pptView[id].currentSlide = 0;
1463- pptView[id].firstSlideSteps = 0;
1464- pptView[id].lastSlideSteps = 0;
1465- pptView[id].guess = 0;
1466- pptView[id].hParentWnd = hParentWnd;
1467- pptView[id].hWnd = NULL;
1468- pptView[id].hWnd2 = NULL;
1469- for (int i = 0; i < MAX_SLIDES; i++)
1470- {
1471- pptView[id].slideNos[i] = 0;
1472- }
1473- if (hParentWnd != NULL && rect.top == 0 && rect.bottom == 0
1474- && rect.left == 0 && rect.right == 0)
1475- {
1476- LPRECT windowRect = NULL;
1477- GetWindowRect(hParentWnd, windowRect);
1478- pptView[id].rect.top = 0;
1479- pptView[id].rect.left = 0;
1480- pptView[id].rect.bottom = windowRect->bottom - windowRect->top;
1481- pptView[id].rect.right = windowRect->right - windowRect->left;
1482- }
1483- else
1484- {
1485- pptView[id].rect.top = rect.top;
1486- pptView[id].rect.left = rect.left;
1487- pptView[id].rect.bottom = rect.bottom;
1488- pptView[id].rect.right = rect.right;
1489- }
1490- wcscat_s(cmdLine, MAX_PATH * 2, L" /F /S \"");
1491- wcscat_s(cmdLine, MAX_PATH * 2, filename);
1492- wcscat_s(cmdLine, MAX_PATH * 2, L"\"");
1493- memset(&si, 0, sizeof(si));
1494- memset(&pi, 0, sizeof(pi));
1495- BOOL gotInfo = GetPPTInfo(id);
1496- /*
1497- * I'd really like to just hook on the new threadid. However this always
1498- * gives error 87. Perhaps I'm hooking to soon? No idea... however can't
1499- * wait since I need to ensure I pick up the WM_CREATE as this is the only
1500- * time the window can be resized in such away the content scales correctly
1501- *
1502- * hook = SetWindowsHookEx(WH_CBT,CbtProc,hInstance,pi.dwThreadId);
1503- */
1504- if (globalHook != NULL)
1505- {
1506- UnhookWindowsHookEx(globalHook);
1507- }
1508- globalHook = SetWindowsHookEx(WH_CBT, CbtProc, hInstance, NULL);
1509- if (globalHook == 0)
1510- {
1511- DEBUG(L"OpenPPT: SetWindowsHookEx failed\n");
1512- ClosePPT(id);
1513- return -1;
1514- }
1515- pptView[id].state = PPT_STARTED;
1516- Sleep(10);
1517- if (!CreateProcess(NULL, cmdLine, NULL, NULL, FALSE, 0, 0, NULL, &si, &pi))
1518- {
1519- DEBUG(L"OpenPPT: CreateProcess failed: %s\n", cmdLine);
1520- ClosePPT(id);
1521- return -1;
1522- }
1523- pptView[id].dwProcessId = pi.dwProcessId;
1524- pptView[id].dwThreadId = pi.dwThreadId;
1525- pptView[id].hThread = pi.hThread;
1526- pptView[id].hProcess = pi.hProcess;
1527- while (pptView[id].state == PPT_STARTED)
1528- Sleep(10);
1529- if (gotInfo)
1530- {
1531- DEBUG(L"OpenPPT: Info loaded, no refresh\n");
1532- pptView[id].state = PPT_LOADED;
1533- Resume(id);
1534- }
1535- else
1536- {
1537- DEBUG(L"OpenPPT: Get info\n");
1538- pptView[id].steps = 0;
1539- int steps = 0;
1540- while (pptView[id].state == PPT_OPENED)
1541- {
1542- if (steps <= pptView[id].steps)
1543- {
1544- Sleep(100);
1545- DEBUG(L"OpenPPT: Step %d/%d\n", steps, pptView[id].steps);
1546- steps++;
1547- NextStep(id);
1548- }
1549- Sleep(10);
1550- }
1551- DEBUG(L"OpenPPT: Slides %d, Steps %d, first slide steps %d\n",
1552- pptView[id].slideCount, pptView[id].steps,
1553- pptView[id].firstSlideSteps);
1554- for(int i = 1; i <= pptView[id].slideCount; i++)
1555- {
1556- DEBUG(L"OpenPPT: Slide %d = %d\n", i, pptView[id].slideNos[i]);
1557- }
1558- SavePPTInfo(id);
1559- if (pptView[id].state == PPT_CLOSING
1560- || pptView[id].slideCount <= 0)
1561- {
1562- ClosePPT(id);
1563- id=-1;
1564- }
1565- else
1566- {
1567- RestartShow(id);
1568- }
1569- }
1570- if (id >= 0)
1571- {
1572- if (pptView[id].msgHook != NULL)
1573- {
1574- UnhookWindowsHookEx(pptView[id].msgHook);
1575- }
1576- pptView[id].msgHook = NULL;
1577- }
1578- DEBUG(L"OpenPPT: Exit: id=%i\n", id);
1579- return id;
1580-}
1581-// Load information about the ppt from an info.txt file.
1582-// Format:
1583-// version
1584-// filedate
1585-// filesize
1586-// slidecount
1587-// first slide steps
1588-BOOL GetPPTInfo(int id)
1589-{
1590- struct _stat fileStats;
1591- wchar_t info[MAX_PATH];
1592- FILE* pFile;
1593- wchar_t buf[100];
1594-
1595- DEBUG(L"GetPPTInfo: start\n");
1596- if (_wstat(pptView[id].filename, &fileStats) != 0)
1597- {
1598- return FALSE;
1599- }
1600- swprintf_s(info, MAX_PATH, L"%sinfo.txt", pptView[id].previewPath);
1601- int err = _wfopen_s(&pFile, info, L"r");
1602- if (err != 0)
1603- {
1604- DEBUG(L"GetPPTInfo: file open failed - %d\n", err);
1605- return FALSE;
1606- }
1607- fgetws(buf, 100, pFile); // version == 1
1608- fgetws(buf, 100, pFile);
1609- if (fileStats.st_mtime != _wtoi(buf))
1610- {
1611- DEBUG(L"GetPPTInfo: date changed\n");
1612- fclose (pFile);
1613- return FALSE;
1614- }
1615- fgetws(buf, 100, pFile);
1616- if (fileStats.st_size != _wtoi(buf))
1617- {
1618- DEBUG(L"GetPPTInfo: size changed\n");
1619- fclose (pFile);
1620- return FALSE;
1621- }
1622- fgetws(buf, 100, pFile); // slidecount
1623- int slideCount = _wtoi(buf);
1624- fgetws(buf, 100, pFile); // first slide steps
1625- int firstSlideSteps = _wtoi(buf);
1626- // check all the preview images still exist
1627- for (int i = 1; i <= slideCount; i++)
1628- {
1629- swprintf_s(info, MAX_PATH, L"%s%i.bmp", pptView[id].previewPath, i);
1630- if (GetFileAttributes(info) == INVALID_FILE_ATTRIBUTES)
1631- {
1632- DEBUG(L"GetPPTInfo: bmp not found\n");
1633- return FALSE;
1634- }
1635- }
1636- fclose(pFile);
1637- pptView[id].slideCount = slideCount;
1638- pptView[id].firstSlideSteps = firstSlideSteps;
1639- DEBUG(L"GetPPTInfo: exit ok\n");
1640- return TRUE;
1641-}
1642-
1643-BOOL SavePPTInfo(int id)
1644-{
1645- struct _stat fileStats;
1646- wchar_t info[MAX_PATH];
1647- FILE* pFile;
1648-
1649- DEBUG(L"SavePPTInfo: start\n");
1650- if (_wstat(pptView[id].filename, &fileStats) != 0)
1651- {
1652- DEBUG(L"SavePPTInfo: stat of %s failed\n", pptView[id].filename);
1653- return FALSE;
1654- }
1655- swprintf_s(info, MAX_PATH, L"%sinfo.txt", pptView[id].previewPath);
1656- int err = _wfopen_s(&pFile, info, L"w");
1657- if (err != 0)
1658- {
1659- DEBUG(L"SavePPTInfo: fopen of %s failed%i\n", info, err);
1660- return FALSE;
1661- }
1662- fprintf(pFile, "1\n");
1663- fprintf(pFile, "%u\n", fileStats.st_mtime);
1664- fprintf(pFile, "%u\n", fileStats.st_size);
1665- fprintf(pFile, "%u\n", pptView[id].slideCount);
1666- fprintf(pFile, "%u\n", pptView[id].firstSlideSteps);
1667- fclose(pFile);
1668- DEBUG(L"SavePPTInfo: exit ok\n");
1669- return TRUE;
1670-}
1671-
1672-// Get the path of the PowerPoint viewer from the registry
1673-BOOL GetPPTViewerPath(wchar_t *pptViewerPath, int stringSize)
1674-{
1675- wchar_t cwd[MAX_PATH];
1676-
1677- DEBUG(L"GetPPTViewerPath: start\n");
1678- if(GetPPTViewerPathFromReg(pptViewerPath, stringSize))
1679- {
1680- if(_waccess(pptViewerPath, 0) != -1)
1681- {
1682- DEBUG(L"GetPPTViewerPath: exit registry\n");
1683- return TRUE;
1684- }
1685- }
1686- // This is where it gets ugly. PPT2007 it seems no longer stores its
1687- // location in the registry. So we have to use the defaults which will
1688- // upset those who like to put things somewhere else
1689-
1690- // Viewer 2007 in 64bit Windows:
1691- if(_waccess(L"C:\\Program Files (x86)\\Microsoft Office\\Office12\\PPTVIEW.EXE",
1692- 0) != -1)
1693- {
1694- wcscpy_s(
1695- L"C:\\Program Files (x86)\\Microsoft Office\\Office12\\PPTVIEW.EXE",
1696- stringSize, pptViewerPath);
1697- DEBUG(L"GetPPTViewerPath: exit 64bit 2007\n");
1698- return TRUE;
1699- }
1700- // Viewer 2007 in 32bit Windows:
1701- if(_waccess(L"C:\\Program Files\\Microsoft Office\\Office12\\PPTVIEW.EXE", 0)
1702- != -1)
1703- {
1704- wcscpy_s(L"C:\\Program Files\\Microsoft Office\\Office12\\PPTVIEW.EXE",
1705- stringSize, pptViewerPath);
1706- DEBUG(L"GetPPTViewerPath: exit 32bit 2007\n");
1707- return TRUE;
1708- }
1709- // Give them the opportunity to place it in the same folder as the app
1710- _wgetcwd(cwd, MAX_PATH);
1711- wcscat_s(cwd, MAX_PATH, L"\\PPTVIEW.EXE");
1712- if(_waccess(cwd, 0) != -1)
1713- {
1714- wcscpy_s(pptViewerPath, stringSize, cwd);
1715- DEBUG(L"GetPPTViewerPath: exit local\n");
1716- return TRUE;
1717- }
1718- DEBUG(L"GetPPTViewerPath: exit fail\n");
1719- return FALSE;
1720-}
1721-BOOL GetPPTViewerPathFromReg(wchar_t *pptViewerPath, int stringSize)
1722-{
1723- HKEY hKey;
1724- DWORD dwType, dwSize;
1725- LRESULT lResult;
1726-
1727- // The following registry settings are for, respectively, (I think)
1728- // PPT Viewer 2007 (older versions. Latest not in registry) & PPT Viewer 2010
1729- // PPT Viewer 2003 (recent versions)
1730- // PPT Viewer 2003 (older versions)
1731- // PPT Viewer 97
1732- if ((RegOpenKeyExW(HKEY_CLASSES_ROOT,
1733- L"PowerPointViewer.Show.12\\shell\\Show\\command", 0, KEY_READ, &hKey)
1734- != ERROR_SUCCESS)
1735- && (RegOpenKeyExW(HKEY_CLASSES_ROOT,
1736- L"PowerPointViewer.Show.11\\shell\\Show\\command", 0, KEY_READ, &hKey)
1737- != ERROR_SUCCESS)
1738- && (RegOpenKeyExW(HKEY_CLASSES_ROOT,
1739- L"Applications\\PPTVIEW.EXE\\shell\\open\\command", 0, KEY_READ, &hKey)
1740- != ERROR_SUCCESS)
1741- && (RegOpenKeyExW(HKEY_CLASSES_ROOT,
1742- L"Applications\\PPTVIEW.EXE\\shell\\Show\\command", 0, KEY_READ, &hKey)
1743- != ERROR_SUCCESS))
1744- {
1745- return FALSE;
1746- }
1747- dwType = REG_SZ;
1748- dwSize = (DWORD)stringSize;
1749- lResult = RegQueryValueEx(hKey, NULL, NULL, &dwType, (LPBYTE)pptViewerPath,
1750- &dwSize);
1751- RegCloseKey(hKey);
1752- if (lResult != ERROR_SUCCESS)
1753- {
1754- return FALSE;
1755- }
1756- // remove "%1" from end of key value
1757- pptViewerPath[wcslen(pptViewerPath) - 4] = '\0';
1758- return TRUE;
1759-}
1760-
1761-// Unhook the Windows hook
1762-void Unhook(int id)
1763-{
1764- DEBUG(L"Unhook: start %d\n", id);
1765- if (pptView[id].hook != NULL)
1766- {
1767- UnhookWindowsHookEx(pptView[id].hook);
1768- }
1769- if (pptView[id].msgHook != NULL)
1770- {
1771- UnhookWindowsHookEx(pptView[id].msgHook);
1772- }
1773- pptView[id].hook = NULL;
1774- pptView[id].msgHook = NULL;
1775- DEBUG(L"Unhook: exit ok\n");
1776-}
1777-
1778-// Close the PowerPoint viewer, release resources
1779-DllExport void ClosePPT(int id)
1780-{
1781- DEBUG(L"ClosePPT: start%d\n", id);
1782- pptView[id].state = PPT_CLOSED;
1783- Unhook(id);
1784- if (pptView[id].hWnd == 0)
1785- {
1786- TerminateThread(pptView[id].hThread, 0);
1787- }
1788- else
1789- {
1790- PostMessage(pptView[id].hWnd, WM_CLOSE, 0, 0);
1791- }
1792- CloseHandle(pptView[id].hThread);
1793- CloseHandle(pptView[id].hProcess);
1794- memset(&pptView[id], 0, sizeof(PPTVIEW));
1795- DEBUG(L"ClosePPT: exit ok\n");
1796- return;
1797-}
1798-// Moves the show back onto the display
1799-DllExport void Resume(int id)
1800-{
1801- DEBUG(L"Resume: %d\n", id);
1802- MoveWindow(pptView[id].hWnd, pptView[id].rect.left,
1803- pptView[id].rect.top,
1804- pptView[id].rect.right - pptView[id].rect.left,
1805- pptView[id].rect.bottom - pptView[id].rect.top, TRUE);
1806- Unblank(id);
1807-}
1808-// Moves the show off the screen so it can't be seen
1809-DllExport void Stop(int id)
1810-{
1811- DEBUG(L"Stop:%d\n", id);
1812- MoveWindow(pptView[id].hWnd, -32000, -32000,
1813- pptView[id].rect.right - pptView[id].rect.left,
1814- pptView[id].rect.bottom - pptView[id].rect.top, TRUE);
1815-}
1816-
1817-// Return the total number of slides
1818-DllExport int GetSlideCount(int id)
1819-{
1820- DEBUG(L"GetSlideCount:%d\n", id);
1821- if (pptView[id].state == 0)
1822- {
1823- return -1;
1824- }
1825- else
1826- {
1827- return pptView[id].slideCount;
1828- }
1829-}
1830-
1831-// Return the number of the slide currently viewing
1832-DllExport int GetCurrentSlide(int id)
1833-{
1834- DEBUG(L"GetCurrentSlide:%d\n", id);
1835- if (pptView[id].state == 0)
1836- {
1837- return -1;
1838- }
1839- else
1840- {
1841- return pptView[id].currentSlide;
1842- }
1843-}
1844-
1845-// Take a step forwards through the show
1846-DllExport void NextStep(int id)
1847-{
1848- DEBUG(L"NextStep:%d (%d)\n", id, pptView[id].currentSlide);
1849- if (pptView[id].currentSlide > pptView[id].slideCount) return;
1850- if (pptView[id].currentSlide < pptView[id].slideCount)
1851- {
1852- pptView[id].guess = pptView[id].currentSlide + 1;
1853- }
1854- PostMessage(pptView[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, -WHEEL_DELTA),
1855- 0);
1856-}
1857-
1858-// Take a step backwards through the show
1859-DllExport void PrevStep(int id)
1860-{
1861- DEBUG(L"PrevStep:%d (%d)\n", id, pptView[id].currentSlide);
1862- if (pptView[id].currentSlide > 1)
1863- {
1864- pptView[id].guess = pptView[id].currentSlide - 1;
1865- }
1866- PostMessage(pptView[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, WHEEL_DELTA),
1867- 0);
1868-}
1869-
1870-// Blank the show (black screen)
1871-DllExport void Blank(int id)
1872-{
1873- // B just toggles blank on/off. However pressing any key unblanks.
1874- // So send random unmapped letter first (say 'A'), then we can
1875- // better guarantee B will blank instead of trying to guess
1876- // whether it was already blank or not.
1877- DEBUG(L"Blank:%d\n", id);
1878- HWND h1 = GetForegroundWindow();
1879- HWND h2 = GetFocus();
1880- SetForegroundWindow(pptView[id].hWnd);
1881- SetFocus(pptView[id].hWnd);
1882- // slight pause, otherwise event triggering this call may grab focus back!
1883- Sleep(50);
1884- keybd_event((int)'A', 0, 0, 0);
1885- keybd_event((int)'A', 0, KEYEVENTF_KEYUP, 0);
1886- keybd_event((int)'B', 0, 0, 0);
1887- keybd_event((int)'B', 0, KEYEVENTF_KEYUP, 0);
1888- SetForegroundWindow(h1);
1889- SetFocus(h2);
1890-}
1891-// Unblank the show
1892-DllExport void Unblank(int id)
1893-{
1894- DEBUG(L"Unblank:%d\n", id);
1895- // Pressing any key resumes.
1896- // For some reason SendMessage works for unblanking, but not blanking.
1897- SendMessage(pptView[id].hWnd2, WM_CHAR, 'A', 0);
1898-}
1899-
1900-// Go directly to a slide
1901-DllExport void GotoSlide(int id, int slideNo)
1902-{
1903- DEBUG(L"GotoSlide %i %i:\n", id, slideNo);
1904- // Did try WM_KEYDOWN/WM_CHAR/WM_KEYUP with SendMessage but didn't work
1905- // perhaps I was sending to the wrong window? No idea.
1906- // Anyway fall back to keybd_event, which is OK as long we makesure
1907- // the slideshow has focus first
1908- char ch[10];
1909-
1910- if (slideNo < 0) return;
1911- pptView[id].guess = slideNo;
1912- _itoa_s(slideNo, ch, 10, 10);
1913- HWND h1 = GetForegroundWindow();
1914- HWND h2 = GetFocus();
1915- SetForegroundWindow(pptView[id].hWnd);
1916- SetFocus(pptView[id].hWnd);
1917- // slight pause, otherwise event triggering this call may grab focus back!
1918- Sleep(50);
1919- for (int i=0; i<10; i++)
1920- {
1921- if (ch[i] == '\0') break;
1922- keybd_event((BYTE)ch[i], 0, 0, 0);
1923- keybd_event((BYTE)ch[i], 0, KEYEVENTF_KEYUP, 0);
1924- }
1925- keybd_event(VK_RETURN, 0, 0, 0);
1926- keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
1927- SetForegroundWindow(h1);
1928- SetFocus(h2);
1929-}
1930-
1931-// Restart the show from the beginning
1932-DllExport void RestartShow(int id)
1933-{
1934- // If we just go direct to slide one, then it remembers that all other
1935- // slides have been animated, so ends up just showing the completed slides
1936- // of those slides that have been animated next time we advance.
1937- // Only way I've found to get around this is to step backwards all the way
1938- // through. Lets move the window out of the way first so the audience
1939- // doesn't see this.
1940- DEBUG(L"RestartShow:%d\n", id);
1941- Stop(id);
1942- GotoSlide(id, pptView[id].slideCount);
1943- for (int i=0; i <= pptView[id].steps - pptView[id].lastSlideSteps; i++)
1944- {
1945- PrevStep(id);
1946- Sleep(10);
1947- }
1948- int i = 0;
1949- while ((pptView[id].currentSlide > 1) && (i++ < 30000))
1950- {
1951- Sleep(10);
1952- }
1953- Resume(id);
1954-}
1955-
1956-// This hook is started with the PPTVIEW.EXE process and waits for the
1957-// WM_CREATEWND message. At this point (and only this point) can the
1958-// window be resized to the correct size.
1959-// Release the hook as soon as we're complete to free up resources
1960-LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam)
1961-{
1962- HHOOK hook = globalHook;
1963- if (nCode == HCBT_CREATEWND)
1964- {
1965- wchar_t csClassName[32];
1966- HWND hCurrWnd = (HWND)wParam;
1967- DWORD retProcId = NULL;
1968- GetClassName(hCurrWnd, csClassName, sizeof(csClassName));
1969- if ((wcscmp(csClassName, L"paneClassDC") == 0)
1970- ||(wcscmp(csClassName, L"screenClass") == 0))
1971- {
1972- int id = -1;
1973- DWORD windowThread = GetWindowThreadProcessId(hCurrWnd, NULL);
1974- for (int i=0; i < MAX_PPTS; i++)
1975- {
1976- if (pptView[i].dwThreadId == windowThread)
1977- {
1978- id = i;
1979- break;
1980- }
1981- }
1982- if (id >= 0)
1983- {
1984- if (wcscmp(csClassName, L"paneClassDC") == 0)
1985- {
1986- pptView[id].hWnd2 = hCurrWnd;
1987- }
1988- else
1989- {
1990- pptView[id].hWnd = hCurrWnd;
1991- CBT_CREATEWND* cw = (CBT_CREATEWND*)lParam;
1992- if (pptView[id].hParentWnd != NULL)
1993- {
1994- cw->lpcs->hwndParent = pptView[id].hParentWnd;
1995- }
1996- cw->lpcs->cy = pptView[id].rect.bottom
1997- - pptView[id].rect.top;
1998- cw->lpcs->cx = pptView[id].rect.right
1999- - pptView[id].rect.left;
2000- cw->lpcs->y = -32000;
2001- cw->lpcs->x = -32000;
2002- }
2003- if ((pptView[id].hWnd != NULL) && (pptView[id].hWnd2 != NULL))
2004- {
2005- UnhookWindowsHookEx(globalHook);
2006- globalHook = NULL;
2007- pptView[id].hook = SetWindowsHookEx(WH_CALLWNDPROC,
2008- CwpProc, hInstance, pptView[id].dwThreadId);
2009- pptView[id].msgHook = SetWindowsHookEx(WH_GETMESSAGE,
2010- GetMsgProc, hInstance, pptView[id].dwThreadId);
2011- Sleep(10);
2012- pptView[id].state = PPT_OPENED;
2013- }
2014- }
2015- }
2016- }
2017- return CallNextHookEx(hook, nCode, wParam, lParam);
2018-}
2019-
2020-// This hook exists whilst the slideshow is loading but only listens on the
2021-// slideshows thread. It listens out for mousewheel events
2022-LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
2023-{
2024- HHOOK hook = NULL;
2025- MSG *pMSG = (MSG *)lParam;
2026- DWORD windowThread = GetWindowThreadProcessId(pMSG->hwnd, NULL);
2027- int id = -1;
2028- for (int i = 0; i < MAX_PPTS; i++)
2029- {
2030- if (pptView[i].dwThreadId == windowThread)
2031- {
2032- id = i;
2033- hook = pptView[id].msgHook;
2034- break;
2035- }
2036- }
2037- if (id >= 0 && nCode == HC_ACTION && wParam == PM_REMOVE
2038- && pMSG->message == WM_MOUSEWHEEL)
2039- {
2040- if (pptView[id].state != PPT_LOADED)
2041- {
2042- if (pptView[id].currentSlide == 1)
2043- {
2044- pptView[id].firstSlideSteps++;
2045- }
2046- pptView[id].steps++;
2047- pptView[id].lastSlideSteps++;
2048- }
2049- }
2050- return CallNextHookEx(hook, nCode, wParam, lParam);
2051-}
2052-// This hook exists whilst the slideshow is running but only listens on the
2053-// slideshows thread. It listens out for slide changes, message WM_USER+22.
2054-LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam){
2055- CWPSTRUCT *cwp;
2056- cwp = (CWPSTRUCT *)lParam;
2057- HHOOK hook = NULL;
2058- wchar_t filename[MAX_PATH];
2059-
2060- DWORD windowThread = GetWindowThreadProcessId(cwp->hwnd, NULL);
2061- int id = -1;
2062- for (int i = 0; i < MAX_PPTS; i++)
2063- {
2064- if (pptView[i].dwThreadId == windowThread)
2065- {
2066- id = i;
2067- hook = pptView[id].hook;
2068- break;
2069- }
2070- }
2071- if ((id >= 0) && (nCode == HC_ACTION))
2072- {
2073- if (cwp->message == WM_USER + 22)
2074- {
2075- if (pptView[id].state != PPT_LOADED)
2076- {
2077- if ((pptView[id].currentSlide > 0)
2078- && (pptView[id].previewPath != NULL
2079- && wcslen(pptView[id].previewPath) > 0))
2080- {
2081- swprintf_s(filename, MAX_PATH, L"%s%i.bmp",
2082- pptView[id].previewPath,
2083- pptView[id].currentSlide);
2084- CaptureAndSaveWindow(cwp->hwnd, filename);
2085- }
2086- if (((cwp->wParam == 0)
2087- || (pptView[id].slideNos[1] == cwp->wParam))
2088- && (pptView[id].currentSlide > 0))
2089- {
2090- pptView[id].state = PPT_LOADED;
2091- pptView[id].currentSlide = pptView[id].slideCount + 1;
2092- }
2093- else
2094- {
2095- if (cwp->wParam > 0)
2096- {
2097- pptView[id].currentSlide = pptView[id].currentSlide + 1;
2098- pptView[id].slideNos[pptView[id].currentSlide]
2099- = cwp->wParam;
2100- pptView[id].slideCount = pptView[id].currentSlide;
2101- pptView[id].lastSlideSteps = 0;
2102- }
2103- }
2104- }
2105- else
2106- {
2107- if (cwp->wParam > 0)
2108- {
2109- if(pptView[id].guess > 0
2110- && pptView[id].slideNos[pptView[id].guess] == 0)
2111- {
2112- pptView[id].currentSlide = 0;
2113- }
2114- for(int i = 1; i <= pptView[id].slideCount; i++)
2115- {
2116- if(pptView[id].slideNos[i] == cwp->wParam)
2117- {
2118- pptView[id].currentSlide = i;
2119- break;
2120- }
2121- }
2122- if(pptView[id].currentSlide == 0)
2123- {
2124- pptView[id].slideNos[pptView[id].guess] = cwp->wParam;
2125- pptView[id].currentSlide = pptView[id].guess;
2126- }
2127- pptView[id].guess = 0;
2128- }
2129- }
2130- }
2131- if ((pptView[id].state != PPT_CLOSED)
2132-
2133- &&(cwp->message == WM_CLOSE || cwp->message == WM_QUIT))
2134- {
2135- pptView[id].state = PPT_CLOSING;
2136- }
2137- }
2138- return CallNextHookEx(hook, nCode, wParam, lParam);
2139-}
2140-
2141-VOID CaptureAndSaveWindow(HWND hWnd, wchar_t* filename)
2142-{
2143- HBITMAP hBmp;
2144- if ((hBmp = CaptureWindow(hWnd)) == NULL)
2145- {
2146- return;
2147- }
2148- RECT client;
2149- GetClientRect(hWnd, &client);
2150- UINT uiBytesPerRow = 3 * client.right; // RGB takes 24 bits
2151- UINT uiRemainderForPadding;
2152-
2153- if ((uiRemainderForPadding = uiBytesPerRow % sizeof(DWORD)) > 0)
2154- uiBytesPerRow += (sizeof(DWORD) - uiRemainderForPadding);
2155-
2156- UINT uiBytesPerAllRows = uiBytesPerRow * client.bottom;
2157- PBYTE pDataBits;
2158-
2159- if ((pDataBits = new BYTE[uiBytesPerAllRows]) != NULL)
2160- {
2161- BITMAPINFOHEADER bmi = {0};
2162- BITMAPFILEHEADER bmf = {0};
2163-
2164- // Prepare to get the data out of HBITMAP:
2165- bmi.biSize = sizeof(bmi);
2166- bmi.biPlanes = 1;
2167- bmi.biBitCount = 24;
2168- bmi.biHeight = client.bottom;
2169- bmi.biWidth = client.right;
2170-
2171- // Get it:
2172- HDC hDC = GetDC(hWnd);
2173- GetDIBits(hDC, hBmp, 0, client.bottom, pDataBits, (BITMAPINFO*) &bmi,
2174- DIB_RGB_COLORS);
2175- ReleaseDC(hWnd, hDC);
2176-
2177- // Fill the file header:
2178- bmf.bfOffBits = sizeof(bmf) + sizeof(bmi);
2179- bmf.bfSize = bmf.bfOffBits + uiBytesPerAllRows;
2180- bmf.bfType = 0x4D42;
2181-
2182- // Writing:
2183- FILE* pFile;
2184- int err = _wfopen_s(&pFile, filename, L"wb");
2185- if (err == 0)
2186- {
2187- fwrite(&bmf, sizeof(bmf), 1, pFile);
2188- fwrite(&bmi, sizeof(bmi), 1, pFile);
2189- fwrite(pDataBits, sizeof(BYTE), uiBytesPerAllRows, pFile);
2190- fclose(pFile);
2191- }
2192- delete [] pDataBits;
2193- }
2194- DeleteObject(hBmp);
2195-}
2196-HBITMAP CaptureWindow(HWND hWnd)
2197-{
2198- HDC hDC;
2199- BOOL bOk = FALSE;
2200- HBITMAP hImage = NULL;
2201-
2202- hDC = GetDC(hWnd);
2203- RECT rcClient;
2204- GetClientRect(hWnd, &rcClient);
2205- if ((hImage = CreateCompatibleBitmap(hDC, rcClient.right, rcClient.bottom))
2206- != NULL)
2207- {
2208- HDC hMemDC;
2209- HBITMAP hDCBmp;
2210-
2211- if ((hMemDC = CreateCompatibleDC(hDC)) != NULL)
2212- {
2213- hDCBmp = (HBITMAP)SelectObject(hMemDC, hImage);
2214- HMODULE hLib = LoadLibrary(L"User32");
2215- // PrintWindow works for windows outside displayable area
2216- // but was only introduced in WinXP. BitBlt requires the window to
2217- // be topmost and within the viewable area of the display
2218- if (GetProcAddress(hLib, "PrintWindow") == NULL)
2219- {
2220- SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE);
2221- BitBlt(hMemDC, 0, 0, rcClient.right, rcClient.bottom, hDC, 0,
2222- 0, SRCCOPY);
2223- SetWindowPos(hWnd, HWND_NOTOPMOST, -32000, -32000, 0, 0,
2224- SWP_NOSIZE);
2225- }
2226- else
2227- {
2228- PrintWindow(hWnd, hMemDC, 0);
2229- }
2230- SelectObject(hMemDC, hDCBmp);
2231- DeleteDC(hMemDC);
2232- bOk = TRUE;
2233- }
2234- }
2235- ReleaseDC(hWnd, hDC);
2236- if (!bOk)
2237- {
2238- if (hImage)
2239- {
2240- DeleteObject(hImage);
2241- hImage = NULL;
2242- }
2243- }
2244- return hImage;
2245-}
2246
2247=== removed file 'openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h'
2248--- openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h 2017-12-29 09:15:48 +0000
2249+++ openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h 1970-01-01 00:00:00 +0000
2250@@ -1,80 +0,0 @@
2251-/******************************************************************************
2252-* OpenLP - Open Source Lyrics Projection *
2253-* --------------------------------------------------------------------------- *
2254-* Copyright (c) 2008-2018 OpenLP Developers *
2255-* --------------------------------------------------------------------------- *
2256-* This program is free software; you can redistribute it and/or modify it *
2257-* under the terms of the GNU General Public License as published by the Free *
2258-* Software Foundation; version 2 of the License. *
2259-* *
2260-* This program is distributed in the hope that it will be useful, but WITHOUT *
2261-* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
2262-* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
2263-* more details. *
2264-* *
2265-* You should have received a copy of the GNU General Public License along *
2266-* with this program; if not, write to the Free Software Foundation, Inc., 59 *
2267-* Temple Place, Suite 330, Boston, MA 02111-1307 USA *
2268-******************************************************************************/
2269-
2270-#define DllExport extern "C" __declspec( dllexport )
2271-
2272-#define DEBUG(...) if (debug) wprintf(__VA_ARGS__)
2273-
2274-enum PPTVIEWSTATE {PPT_CLOSED, PPT_STARTED, PPT_OPENED, PPT_LOADED,
2275- PPT_CLOSING};
2276-
2277-DllExport int OpenPPT(wchar_t *filename, HWND hParentWnd, RECT rect,
2278- wchar_t *previewPath);
2279-DllExport BOOL CheckInstalled();
2280-DllExport void ClosePPT(int id);
2281-DllExport int GetCurrentSlide(int id);
2282-DllExport int GetSlideCount(int id);
2283-DllExport void NextStep(int id);
2284-DllExport void PrevStep(int id);
2285-DllExport void GotoSlide(int id, int slide_no);
2286-DllExport void RestartShow(int id);
2287-DllExport void Blank(int id);
2288-DllExport void Unblank(int id);
2289-DllExport void Stop(int id);
2290-DllExport void Resume(int id);
2291-DllExport void SetDebug(BOOL onOff);
2292-
2293-LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam);
2294-LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam);
2295-LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam);
2296-BOOL GetPPTViewerPath(wchar_t *pptViewerPath, int stringSize);
2297-BOOL GetPPTViewerPathFromReg(wchar_t *pptViewerPath, int stringSize);
2298-HBITMAP CaptureWindow(HWND hWnd);
2299-VOID SaveBitmap(wchar_t* filename, HBITMAP hBmp) ;
2300-VOID CaptureAndSaveWindow(HWND hWnd, wchar_t* filename);
2301-BOOL GetPPTInfo(int id);
2302-BOOL SavePPTInfo(int id);
2303-void Unhook(int id);
2304-
2305-#define MAX_PPTS 16
2306-#define MAX_SLIDES 256
2307-
2308-struct PPTVIEW
2309-{
2310- HHOOK hook;
2311- HHOOK msgHook;
2312- HWND hWnd;
2313- HWND hWnd2;
2314- HWND hParentWnd;
2315- HANDLE hProcess;
2316- HANDLE hThread;
2317- DWORD dwProcessId;
2318- DWORD dwThreadId;
2319- RECT rect;
2320- int slideCount;
2321- int currentSlide;
2322- int firstSlideSteps;
2323- int lastSlideSteps;
2324- int steps;
2325- int guess;
2326- wchar_t filename[MAX_PATH];
2327- wchar_t previewPath[MAX_PATH];
2328- int slideNos[MAX_SLIDES];
2329- PPTVIEWSTATE state;
2330-};
2331
2332=== removed file 'openlp/plugins/presentations/lib/pptviewlib/pptviewlib.vcproj'
2333--- openlp/plugins/presentations/lib/pptviewlib/pptviewlib.vcproj 2013-11-16 10:16:06 +0000
2334+++ openlp/plugins/presentations/lib/pptviewlib/pptviewlib.vcproj 1970-01-01 00:00:00 +0000
2335@@ -1,202 +0,0 @@
2336-<?xml version="1.0" encoding="Windows-1252"?>
2337-<VisualStudioProject
2338- ProjectType="Visual C++"
2339- Version="9.00"
2340- Name="pptviewlib"
2341- ProjectGUID="{04CC20D1-DC5A-4189-8181-4011E3C21DCF}"
2342- RootNamespace="pptviewlib"
2343- Keyword="Win32Proj"
2344- TargetFrameworkVersion="196613"
2345- >
2346- <Platforms>
2347- <Platform
2348- Name="Win32"
2349- />
2350- </Platforms>
2351- <ToolFiles>
2352- </ToolFiles>
2353- <Configurations>
2354- <Configuration
2355- Name="Debug|Win32"
2356- OutputDirectory="$(SolutionDir)$(ConfigurationName)"
2357- IntermediateDirectory="$(ConfigurationName)"
2358- ConfigurationType="2"
2359- CharacterSet="1"
2360- >
2361- <Tool
2362- Name="VCPreBuildEventTool"
2363- />
2364- <Tool
2365- Name="VCCustomBuildTool"
2366- />
2367- <Tool
2368- Name="VCXMLDataGeneratorTool"
2369- />
2370- <Tool
2371- Name="VCWebServiceProxyGeneratorTool"
2372- />
2373- <Tool
2374- Name="VCMIDLTool"
2375- />
2376- <Tool
2377- Name="VCCLCompilerTool"
2378- Optimization="0"
2379- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;PPTVIEWLIB_EXPORTS"
2380- MinimalRebuild="true"
2381- BasicRuntimeChecks="3"
2382- RuntimeLibrary="3"
2383- UsePrecompiledHeader="0"
2384- WarningLevel="3"
2385- DebugInformationFormat="4"
2386- />
2387- <Tool
2388- Name="VCManagedResourceCompilerTool"
2389- />
2390- <Tool
2391- Name="VCResourceCompilerTool"
2392- />
2393- <Tool
2394- Name="VCPreLinkEventTool"
2395- />
2396- <Tool
2397- Name="VCLinkerTool"
2398- LinkIncremental="2"
2399- ModuleDefinitionFile=""
2400- GenerateDebugInformation="true"
2401- SubSystem="2"
2402- TargetMachine="1"
2403- />
2404- <Tool
2405- Name="VCALinkTool"
2406- />
2407- <Tool
2408- Name="VCManifestTool"
2409- />
2410- <Tool
2411- Name="VCXDCMakeTool"
2412- />
2413- <Tool
2414- Name="VCBscMakeTool"
2415- />
2416- <Tool
2417- Name="VCFxCopTool"
2418- />
2419- <Tool
2420- Name="VCAppVerifierTool"
2421- />
2422- <Tool
2423- Name="VCPostBuildEventTool"
2424- />
2425- </Configuration>
2426- <Configuration
2427- Name="Release|Win32"
2428- OutputDirectory="$(SolutionDir)$(ConfigurationName)"
2429- IntermediateDirectory="$(ConfigurationName)"
2430- ConfigurationType="2"
2431- CharacterSet="1"
2432- WholeProgramOptimization="1"
2433- >
2434- <Tool
2435- Name="VCPreBuildEventTool"
2436- />
2437- <Tool
2438- Name="VCCustomBuildTool"
2439- />
2440- <Tool
2441- Name="VCXMLDataGeneratorTool"
2442- />
2443- <Tool
2444- Name="VCWebServiceProxyGeneratorTool"
2445- />
2446- <Tool
2447- Name="VCMIDLTool"
2448- />
2449- <Tool
2450- Name="VCCLCompilerTool"
2451- Optimization="2"
2452- EnableIntrinsicFunctions="true"
2453- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;PPTVIEWLIB_EXPORTS"
2454- RuntimeLibrary="2"
2455- EnableFunctionLevelLinking="true"
2456- UsePrecompiledHeader="0"
2457- WarningLevel="3"
2458- DebugInformationFormat="3"
2459- />
2460- <Tool
2461- Name="VCManagedResourceCompilerTool"
2462- />
2463- <Tool
2464- Name="VCResourceCompilerTool"
2465- />
2466- <Tool
2467- Name="VCPreLinkEventTool"
2468- />
2469- <Tool
2470- Name="VCLinkerTool"
2471- LinkIncremental="1"
2472- GenerateDebugInformation="true"
2473- SubSystem="2"
2474- OptimizeReferences="2"
2475- EnableCOMDATFolding="2"
2476- TargetMachine="1"
2477- />
2478- <Tool
2479- Name="VCALinkTool"
2480- />
2481- <Tool
2482- Name="VCManifestTool"
2483- />
2484- <Tool
2485- Name="VCXDCMakeTool"
2486- />
2487- <Tool
2488- Name="VCBscMakeTool"
2489- />
2490- <Tool
2491- Name="VCFxCopTool"
2492- />
2493- <Tool
2494- Name="VCAppVerifierTool"
2495- />
2496- <Tool
2497- Name="VCPostBuildEventTool"
2498- />
2499- </Configuration>
2500- </Configurations>
2501- <References>
2502- </References>
2503- <Files>
2504- <Filter
2505- Name="Source Files"
2506- Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
2507- UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
2508- >
2509- <File
2510- RelativePath=".\pptviewlib.cpp"
2511- >
2512- </File>
2513- <File
2514- RelativePath=".\README.TXT"
2515- >
2516- </File>
2517- </Filter>
2518- <Filter
2519- Name="Header Files"
2520- Filter="h;hpp;hxx;hm;inl;inc;xsd"
2521- UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
2522- >
2523- <File
2524- RelativePath=".\pptviewlib.h"
2525- >
2526- </File>
2527- </Filter>
2528- <Filter
2529- Name="Resource Files"
2530- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
2531- UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
2532- >
2533- </Filter>
2534- </Files>
2535- <Globals>
2536- </Globals>
2537-</VisualStudioProject>
2538
2539=== removed file 'openlp/plugins/presentations/lib/pptviewlib/test.ppt'
2540Binary 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
2541=== removed file 'openlp/plugins/presentations/lib/pptviewlib/test.pptx'
2542Binary 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
2543=== modified file 'openlp/plugins/presentations/presentationplugin.py'
2544--- openlp/plugins/presentations/presentationplugin.py 2017-12-29 09:15:48 +0000
2545+++ openlp/plugins/presentations/presentationplugin.py 2018-02-03 15:03:00 +0000
2546@@ -44,7 +44,6 @@
2547 'presentations/pdf_program': None,
2548 'presentations/Impress': QtCore.Qt.Checked,
2549 'presentations/Powerpoint': QtCore.Qt.Checked,
2550- 'presentations/Powerpoint Viewer': QtCore.Qt.Checked,
2551 'presentations/Pdf': QtCore.Qt.Checked,
2552 'presentations/presentations files': [],
2553 'presentations/thumbnail_scheme': '',
2554@@ -57,7 +56,7 @@
2555 class PresentationPlugin(Plugin):
2556 """
2557 This plugin allowed a Presentation to be opened, controlled and displayed on the output display. The plugin controls
2558- third party applications such as OpenOffice.org Impress, Microsoft PowerPoint and the PowerPoint viewer.
2559+ third party applications such as OpenOffice.org Impress, and Microsoft PowerPoint.
2560 """
2561 log = logging.getLogger('PresentationPlugin')
2562
2563
2564=== modified file 'openlp/plugins/songs/lib/mediaitem.py'
2565--- openlp/plugins/songs/lib/mediaitem.py 2017-12-29 09:15:48 +0000
2566+++ openlp/plugins/songs/lib/mediaitem.py 2018-02-03 15:03:00 +0000
2567@@ -321,9 +321,12 @@
2568 :param search_results: A tuple containing (songbook entry, book name, song title, song id)
2569 :return: None
2570 """
2571- def get_songbook_key(result):
2572- """Get the key to sort by"""
2573- return (get_natural_key(result[1]), get_natural_key(result[0]), get_natural_key(result[2]))
2574+ def get_songbook_key(text_array):
2575+ """
2576+ Get the key to sort by
2577+ :param text_array: the result text to be processed.
2578+ """
2579+ return get_natural_key(text_array[1]), get_natural_key(text_array[0]), get_natural_key(text_array[2])
2580
2581 log.debug('display results Book')
2582 self.list_view.clear()
2583@@ -373,7 +376,7 @@
2584 """
2585 def get_theme_key(song):
2586 """Get the key to sort by"""
2587- return (get_natural_key(song.theme_name), song.sort_key)
2588+ return get_natural_key(song.theme_name), song.sort_key
2589
2590 log.debug('display results Themes')
2591 self.list_view.clear()
2592@@ -396,7 +399,7 @@
2593 """
2594 def get_cclinumber_key(song):
2595 """Get the key to sort by"""
2596- return (get_natural_key(song.ccli_number), song.sort_key)
2597+ return get_natural_key(song.ccli_number), song.sort_key
2598
2599 log.debug('display results CCLI number')
2600 self.list_view.clear()
2601@@ -460,6 +463,8 @@
2602 """
2603 Called by ServiceManager or SlideController by event passing the Song Id in the payload along with an indicator
2604 to say which type of display is required.
2605+ :param song_id: the id of the song
2606+ :param preview: show we preview after the update
2607 """
2608 log.debug('on_remote_edit for song {song}'.format(song=song_id))
2609 song_id = int(song_id)
2610@@ -721,7 +726,8 @@
2611 self.generate_footer(item, song)
2612 return item
2613
2614- def _authors_match(self, song, authors):
2615+ @staticmethod
2616+ def _authors_match(song, authors):
2617 """
2618 Checks whether authors from a song in the database match the authors of the song to be imported.
2619
2620@@ -738,11 +744,12 @@
2621 # List must be empty at the end
2622 return not author_list
2623
2624- def search(self, string, show_error):
2625+ def search(self, string, show_error=True):
2626 """
2627 Search for some songs
2628 :param string: The string to show
2629 :param show_error: Is this an error?
2630+ :return: the results of the search
2631 """
2632 search_results = self.search_entire(string)
2633 return [[song.id, song.title, song.alternate_title] for song in search_results]
2634
2635=== added file 'tests/functional/openlp_core/api/endpoint/__init__.py'
2636=== added file 'tests/functional/openlp_core/api/endpoint/test_controller.py'
2637--- tests/functional/openlp_core/api/endpoint/test_controller.py 1970-01-01 00:00:00 +0000
2638+++ tests/functional/openlp_core/api/endpoint/test_controller.py 2018-02-03 15:03:00 +0000
2639@@ -0,0 +1,54 @@
2640+# -*- coding: utf-8 -*-
2641+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
2642+
2643+###############################################################################
2644+# OpenLP - Open Source Lyrics Projection #
2645+# --------------------------------------------------------------------------- #
2646+# Copyright (c) 2008-2018 OpenLP Developers #
2647+# --------------------------------------------------------------------------- #
2648+# This program is free software; you can redistribute it and/or modify it #
2649+# under the terms of the GNU General Public License as published by the Free #
2650+# Software Foundation; version 2 of the License. #
2651+# #
2652+# This program is distributed in the hope that it will be useful, but WITHOUT #
2653+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
2654+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
2655+# more details. #
2656+# #
2657+# You should have received a copy of the GNU General Public License along #
2658+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
2659+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
2660+###############################################################################
2661+from unittest import TestCase
2662+from unittest.mock import MagicMock, patch
2663+
2664+from openlp.core.common.registry import Registry
2665+from openlp.core.api.endpoint.controller import controller_text
2666+
2667+
2668+class TestController(TestCase):
2669+ """
2670+ Test the Remote plugin deploy functions
2671+ """
2672+
2673+ def setUp(self):
2674+ """
2675+ Setup for tests
2676+ """
2677+ Registry.create()
2678+ self.registry = Registry()
2679+ self.mocked_live_controller = MagicMock()
2680+ Registry().register('live_controller', self.mocked_live_controller)
2681+
2682+ def test_controller_text(self):
2683+ """
2684+ Remote Deploy tests - test the dummy zip file is processed correctly
2685+ """
2686+ # GIVEN: A mocked service with a dummy service item
2687+ self.mocked_live_controller.service_item = MagicMock()
2688+ # WHEN: I trigger the method
2689+ ret = controller_text("SomeText")
2690+ # THEN: I get a basic set of results
2691+ results = ret['results']
2692+ assert isinstance(results['item'], MagicMock)
2693+ assert len(results['slides']) == 0
2694
2695=== modified file 'tests/functional/openlp_plugins/bibles/test_mediaitem.py'
2696--- tests/functional/openlp_plugins/bibles/test_mediaitem.py 2017-12-29 09:15:48 +0000
2697+++ tests/functional/openlp_plugins/bibles/test_mediaitem.py 2018-02-03 15:03:00 +0000
2698@@ -167,7 +167,7 @@
2699 # THEN: It should be a subclass of :class:`MediaManagerItem`
2700 assert isinstance(self.media_item, MediaManagerItem)
2701
2702- def test_steup_item(self):
2703+ def test_setup_item(self):
2704 """
2705 Test the setup_item method
2706 """
2707
2708=== removed file 'tests/functional/openlp_plugins/presentations/test_pptviewcontroller.py'
2709--- tests/functional/openlp_plugins/presentations/test_pptviewcontroller.py 2017-12-29 10:19:33 +0000
2710+++ tests/functional/openlp_plugins/presentations/test_pptviewcontroller.py 1970-01-01 00:00:00 +0000
2711@@ -1,226 +0,0 @@
2712-# -*- coding: utf-8 -*-
2713-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
2714-
2715-###############################################################################
2716-# OpenLP - Open Source Lyrics Projection #
2717-# --------------------------------------------------------------------------- #
2718-# Copyright (c) 2008-2018 OpenLP Developers #
2719-# --------------------------------------------------------------------------- #
2720-# This program is free software; you can redistribute it and/or modify it #
2721-# under the terms of the GNU General Public License as published by the Free #
2722-# Software Foundation; version 2 of the License. #
2723-# #
2724-# This program is distributed in the hope that it will be useful, but WITHOUT #
2725-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
2726-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
2727-# more details. #
2728-# #
2729-# You should have received a copy of the GNU General Public License along #
2730-# with this program; if not, write to the Free Software Foundation, Inc., 59 #
2731-# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
2732-###############################################################################
2733-"""
2734-This module contains tests for the pptviewcontroller module of the Presentations plugin.
2735-"""
2736-import shutil
2737-from tempfile import mkdtemp
2738-from unittest import TestCase, skipIf
2739-from unittest.mock import MagicMock, patch
2740-
2741-from openlp.core.common import is_win
2742-from openlp.core.common.path import Path
2743-from openlp.plugins.presentations.lib.pptviewcontroller import PptviewDocument, PptviewController
2744-from tests.helpers.testmixin import TestMixin
2745-from tests.utils.constants import RESOURCE_PATH
2746-
2747-
2748-class TestPptviewController(TestCase, TestMixin):
2749- """
2750- Test the PptviewController Class
2751- """
2752- def setUp(self):
2753- """
2754- Set up the patches and mocks need for all tests.
2755- """
2756- self.setup_application()
2757- self.build_settings()
2758- self.mock_plugin = MagicMock()
2759- self.temp_folder = mkdtemp()
2760- self.mock_plugin.settings_section = self.temp_folder
2761-
2762- def tearDown(self):
2763- """
2764- Stop the patches
2765- """
2766- self.destroy_settings()
2767- shutil.rmtree(self.temp_folder)
2768-
2769- def test_constructor(self):
2770- """
2771- Test the Constructor from the PptViewController
2772- """
2773- # GIVEN: No presentation controller
2774- controller = None
2775-
2776- # WHEN: The presentation controller object is created
2777- controller = PptviewController(plugin=self.mock_plugin)
2778-
2779- # THEN: The name of the presentation controller should be correct
2780- assert 'Powerpoint Viewer' == controller.name, 'The name of the presentation controller should be correct'
2781-
2782- def test_check_available(self):
2783- """
2784- Test check_available / check_installed
2785- """
2786- # GIVEN: A mocked dll loader and a controller
2787- with patch('ctypes.cdll.LoadLibrary') as mocked_load_library:
2788- mocked_process = MagicMock()
2789- mocked_process.CheckInstalled.return_value = True
2790- mocked_load_library.return_value = mocked_process
2791- controller = PptviewController(plugin=self.mock_plugin)
2792-
2793- # WHEN: check_available is called
2794- available = controller.check_available()
2795-
2796- # THEN: On windows it should return True, on other platforms False
2797- if is_win():
2798- assert available is True, 'check_available should return True on windows.'
2799- else:
2800- assert available is False, 'check_available should return False when not on windows.'
2801-
2802-
2803-class TestPptviewDocument(TestCase):
2804- """
2805- Test the PptviewDocument Class
2806- """
2807- def setUp(self):
2808- """
2809- Set up the patches and mocks need for all tests.
2810- """
2811- self.pptview_document_create_thumbnails_patcher = patch(
2812- 'openlp.plugins.presentations.lib.pptviewcontroller.PptviewDocument.create_thumbnails')
2813- self.pptview_document_stop_presentation_patcher = patch(
2814- 'openlp.plugins.presentations.lib.pptviewcontroller.PptviewDocument.stop_presentation')
2815- self.presentation_document_get_temp_folder_patcher = patch(
2816- 'openlp.plugins.presentations.lib.pptviewcontroller.PresentationDocument.get_temp_folder')
2817- self.presentation_document_setup_patcher = patch(
2818- 'openlp.plugins.presentations.lib.pptviewcontroller.PresentationDocument._setup')
2819- self.screen_list_patcher = patch('openlp.plugins.presentations.lib.pptviewcontroller.ScreenList')
2820- self.rect_patcher = MagicMock()
2821- self.mock_pptview_document_create_thumbnails = self.pptview_document_create_thumbnails_patcher.start()
2822- self.mock_pptview_document_stop_presentation = self.pptview_document_stop_presentation_patcher.start()
2823- self.mock_presentation_document_get_temp_folder = self.presentation_document_get_temp_folder_patcher.start()
2824- self.mock_presentation_document_setup = self.presentation_document_setup_patcher.start()
2825- self.mock_rect = self.rect_patcher.start()
2826- self.mock_screen_list = self.screen_list_patcher.start()
2827- self.mock_controller = MagicMock()
2828- self.mock_presentation = MagicMock()
2829- self.temp_folder = mkdtemp()
2830- self.mock_presentation_document_get_temp_folder.return_value = self.temp_folder
2831-
2832- def tearDown(self):
2833- """
2834- Stop the patches
2835- """
2836- self.pptview_document_create_thumbnails_patcher.stop()
2837- self.pptview_document_stop_presentation_patcher.stop()
2838- self.presentation_document_get_temp_folder_patcher.stop()
2839- self.presentation_document_setup_patcher.stop()
2840- self.rect_patcher.stop()
2841- self.screen_list_patcher.stop()
2842- shutil.rmtree(self.temp_folder)
2843-
2844- @skipIf(not is_win(), 'Not Windows')
2845- def test_load_presentation_succesful(self):
2846- """
2847- Test the PptviewDocument.load_presentation() method when the PPT is successfully opened
2848- """
2849- # GIVEN: A reset mocked_os
2850- self.mock_controller.process.OpenPPT.return_value = 0
2851- instance = PptviewDocument(self.mock_controller, self.mock_presentation)
2852- instance.file_path = 'test\path.ppt'
2853-
2854- # WHEN: The temporary directory exists and OpenPPT returns successfully (not -1)
2855- result = instance.load_presentation()
2856-
2857- # THEN: PptviewDocument.load_presentation should return True
2858- assert result is True
2859-
2860- @skipIf(not is_win(), 'Not Windows')
2861- def test_load_presentation_un_succesful(self):
2862- """
2863- Test the PptviewDocument.load_presentation() method when the temporary directory does not exist and the PPT is
2864- not successfully opened
2865- """
2866- # GIVEN: A reset mock_os_isdir
2867- self.mock_controller.process.OpenPPT.return_value = -1
2868- instance = PptviewDocument(self.mock_controller, self.mock_presentation)
2869- instance.file_path = 'test\path.ppt'
2870-
2871- # WHEN: The temporary directory does not exist and OpenPPT returns unsuccessfully (-1)
2872- with patch.object(instance, 'get_temp_folder') as mocked_get_folder:
2873- mocked_get_folder.return_value = MagicMock(spec=Path)
2874- result = instance.load_presentation()
2875-
2876- # THEN: The temp folder should be created and PptviewDocument.load_presentation should return False
2877- assert result is False
2878-
2879- def test_create_titles_and_notes(self):
2880- """
2881- Test PowerpointController.create_titles_and_notes
2882- """
2883- # GIVEN: mocked PresentationController.save_titles_and_notes and a pptx file
2884- doc = PptviewDocument(self.mock_controller, self.mock_presentation)
2885- doc.file_path = RESOURCE_PATH / 'presentations' / 'test.pptx'
2886- doc.save_titles_and_notes = MagicMock()
2887-
2888- # WHEN reading the titles and notes
2889- doc.create_titles_and_notes()
2890-
2891- # THEN save_titles_and_notes should have been called once with empty arrays
2892- doc.save_titles_and_notes.assert_called_once_with(['Test 1\n', '\n', 'Test 2\n', 'Test 4\n', 'Test 3\n'],
2893- ['Notes for slide 1', 'Inserted', 'Notes for slide 2',
2894- 'Notes \nfor slide 4', 'Notes for slide 3'])
2895-
2896- def test_create_titles_and_notes_nonexistent_file(self):
2897- """
2898- Test PowerpointController.create_titles_and_notes with nonexistent file
2899- """
2900- # GIVEN: mocked PresentationController.save_titles_and_notes and an nonexistent file
2901- with patch('builtins.open') as mocked_open, \
2902- patch.object(Path, 'exists') as mocked_path_exists, \
2903- patch('openlp.plugins.presentations.lib.presentationcontroller.create_paths') as \
2904- mocked_dir_exists:
2905- mocked_path_exists.return_value = False
2906- mocked_dir_exists.return_value = False
2907- doc = PptviewDocument(self.mock_controller, self.mock_presentation)
2908- doc.file_path = Path('Idontexist.pptx')
2909- doc.save_titles_and_notes = MagicMock()
2910-
2911- # WHEN: Reading the titles and notes
2912- doc.create_titles_and_notes()
2913-
2914- # THEN: File existens should have been checked, and not have been opened.
2915- doc.save_titles_and_notes.assert_called_once_with(None, None)
2916- mocked_path_exists.assert_called_with()
2917- assert mocked_open.call_count == 0, 'There should be no calls to open a file.'
2918-
2919- def test_create_titles_and_notes_invalid_file(self):
2920- """
2921- Test PowerpointController.create_titles_and_notes with invalid file
2922- """
2923- # GIVEN: mocked PresentationController.save_titles_and_notes and an invalid file
2924- with patch('builtins.open') as mocked_open, \
2925- patch('openlp.plugins.presentations.lib.pptviewcontroller.zipfile.is_zipfile') as mocked_is_zf:
2926- mocked_is_zf.return_value = False
2927- mocked_open.filesize = 10
2928- doc = PptviewDocument(self.mock_controller, self.mock_presentation)
2929- doc.file_path = RESOURCE_PATH / 'presentations' / 'test.ppt'
2930- doc.save_titles_and_notes = MagicMock()
2931-
2932- # WHEN: reading the titles and notes
2933- doc.create_titles_and_notes()
2934-
2935- # THEN:
2936- doc.save_titles_and_notes.assert_called_once_with(None, None)
2937- assert mocked_is_zf.call_count == 1, 'is_zipfile should have been called once'