Merge lp:~tomasgroth/openlp/presentation-beyond-last into lp:openlp
- presentation-beyond-last
- Merge into trunk
Proposed by
Tomas Groth
Status: | Superseded |
---|---|
Proposed branch: | lp:~tomasgroth/openlp/presentation-beyond-last |
Merge into: | lp:openlp |
Diff against target: |
649 lines (+272/-55) 7 files modified
openlp/core/common/registry.py (+1/-1) openlp/core/ui/servicemanager.py (+6/-0) openlp/core/ui/slidecontroller.py (+22/-6) openlp/plugins/presentations/lib/impresscontroller.py (+195/-21) openlp/plugins/presentations/lib/messagelistener.py (+20/-20) openlp/plugins/presentations/lib/powerpointcontroller.py (+23/-4) openlp/plugins/presentations/lib/presentationcontroller.py (+5/-3) |
To merge this branch: | bzr merge lp:~tomasgroth/openlp/presentation-beyond-last |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
OpenLP Core | Pending | ||
Review via email: mp+367863@code.launchpad.net |
This proposal supersedes a proposal from 2019-05-21.
This proposal has been superseded by a proposal from 2019-05-24.
Commit message
Make it possible to go to next or previous service item when stepping through a presentation.
Disables impress and powerpoint presentation console.
Description of the change
To post a comment you must log in.
Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal | # |
Revision history for this message
Raoul Snyman (raoul-snyman) wrote : | # |
Linux tests passed!
Revision history for this message
Raoul Snyman (raoul-snyman) wrote : | # |
Linting failed, please see https:/
- 2670. By Tomas Groth
-
pep8 fixes
Revision history for this message
Phill (phill-ridout) wrote : | # |
Whats happrning with the commented out code?
- 2671. By Tomas Groth
-
Reenable setting slidecontroller index when openlp is not in focus.
- 2672. By Tomas Groth
-
Remove unused code
- 2673. By Tomas Groth
-
Fix traceback on Mac tests
- 2674. By Tomas Groth
-
pep8
- 2675. By Tomas Groth
-
trunk
- 2676. By Tomas Groth
-
Fix as suggested
- 2677. By Tomas Groth
-
merge trunk
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'openlp/core/common/registry.py' |
2 | --- openlp/core/common/registry.py 2019-04-13 13:00:22 +0000 |
3 | +++ openlp/core/common/registry.py 2019-05-24 19:21:37 +0000 |
4 | @@ -146,7 +146,7 @@ |
5 | try: |
6 | log.debug('Running function {} for {}'.format(function, event)) |
7 | result = function(*args, **kwargs) |
8 | - if result: |
9 | + if result is not None: |
10 | results.append(result) |
11 | except TypeError: |
12 | # Who has called me can help in debugging |
13 | |
14 | === modified file 'openlp/core/ui/servicemanager.py' |
15 | --- openlp/core/ui/servicemanager.py 2019-05-24 18:50:51 +0000 |
16 | +++ openlp/core/ui/servicemanager.py 2019-05-24 19:21:37 +0000 |
17 | @@ -976,8 +976,10 @@ |
18 | prev_item_last_slide = None |
19 | service_iterator = QtWidgets.QTreeWidgetItemIterator(self.service_manager_list) |
20 | while service_iterator.value(): |
21 | + # Found the selected/current service item |
22 | if service_iterator.value() == selected: |
23 | if last_slide and prev_item_last_slide: |
24 | + # Go to the last slide of the previous service item |
25 | pos = prev_item.data(0, QtCore.Qt.UserRole) |
26 | check_expanded = self.service_items[pos - 1]['expanded'] |
27 | self.service_manager_list.setCurrentItem(prev_item_last_slide) |
28 | @@ -986,13 +988,17 @@ |
29 | self.make_live() |
30 | self.service_manager_list.setCurrentItem(prev_item) |
31 | elif prev_item: |
32 | + # Go to the first slide of the previous service item |
33 | self.service_manager_list.setCurrentItem(prev_item) |
34 | self.make_live() |
35 | return |
36 | + # Found the previous service item root |
37 | if service_iterator.value().parent() is None: |
38 | prev_item = service_iterator.value() |
39 | + # Found the last slide of the previous item |
40 | if service_iterator.value().parent() is prev_item: |
41 | prev_item_last_slide = service_iterator.value() |
42 | + # Go to next item in the tree |
43 | service_iterator += 1 |
44 | |
45 | def on_set_item(self, message): |
46 | |
47 | === modified file 'openlp/core/ui/slidecontroller.py' |
48 | --- openlp/core/ui/slidecontroller.py 2019-05-22 06:47:00 +0000 |
49 | +++ openlp/core/ui/slidecontroller.py 2019-05-24 19:21:37 +0000 |
50 | @@ -1261,9 +1261,18 @@ |
51 | if not self.service_item: |
52 | return |
53 | if self.service_item.is_command(): |
54 | - Registry().execute('{text}_next'.format(text=self.service_item.name.lower()), |
55 | - [self.service_item, self.is_live]) |
56 | - if self.is_live: |
57 | + past_end = Registry().execute('{text}_next'.format(text=self.service_item.name.lower()), |
58 | + [self.service_item, self.is_live]) |
59 | + # Check if we have gone past the end of the last slide |
60 | + if self.is_live and past_end and past_end[0]: |
61 | + if wrap is None: |
62 | + if self.slide_limits == SlideLimits.Wrap: |
63 | + self.on_slide_selected_index([0]) |
64 | + elif self.is_live and self.slide_limits == SlideLimits.Next: |
65 | + self.service_next() |
66 | + elif wrap: |
67 | + self.on_slide_selected_index([0]) |
68 | + elif self.is_live: |
69 | self.update_preview() |
70 | else: |
71 | row = self.preview_widget.current_slide_number() + 1 |
72 | @@ -1290,9 +1299,16 @@ |
73 | if not self.service_item: |
74 | return |
75 | if self.service_item.is_command(): |
76 | - Registry().execute('{text}_previous'.format(text=self.service_item.name.lower()), |
77 | - [self.service_item, self.is_live]) |
78 | - if self.is_live: |
79 | + before_start = Registry().execute('{text}_previous'.format(text=self.service_item.name.lower()), |
80 | + [self.service_item, self.is_live]) |
81 | + # Check id we have tried to go before that start slide |
82 | + if self.is_live and before_start and before_start[0]: |
83 | + if self.slide_limits == SlideLimits.Wrap: |
84 | + self.on_slide_selected_index([self.preview_widget.slide_count() - 1]) |
85 | + elif self.is_live and self.slide_limits == SlideLimits.Next: |
86 | + self.keypress_queue.append(ServiceItemAction.PreviousLastSlide) |
87 | + self._process_queue() |
88 | + elif self.is_live: |
89 | self.update_preview() |
90 | else: |
91 | row = self.preview_widget.current_slide_number() - 1 |
92 | |
93 | === modified file 'openlp/plugins/presentations/lib/impresscontroller.py' |
94 | --- openlp/plugins/presentations/lib/impresscontroller.py 2019-05-22 06:47:00 +0000 |
95 | +++ openlp/plugins/presentations/lib/impresscontroller.py 2019-05-24 19:21:37 +0000 |
96 | @@ -36,7 +36,7 @@ |
97 | |
98 | from PyQt5 import QtCore |
99 | |
100 | -from openlp.core.common import delete_file, get_uno_command, get_uno_instance, is_win |
101 | +from openlp.core.common import delete_file, get_uno_command, get_uno_instance, is_win, trace_error_handler |
102 | from openlp.core.common.registry import Registry |
103 | from openlp.core.display.screens import ScreenList |
104 | from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument, \ |
105 | @@ -47,15 +47,30 @@ |
106 | from win32com.client import Dispatch |
107 | import pywintypes |
108 | uno_available = False |
109 | + try: |
110 | + service_manager = Dispatch('com.sun.star.ServiceManager') |
111 | + service_manager._FlagAsMethod('Bridge_GetStruct') |
112 | + XSlideShowListenerObj = service_manager.Bridge_GetStruct('com.sun.star.presentation.XSlideShowListener') |
113 | + |
114 | + class SlideShowListenerImport(XSlideShowListenerObj.__class__): |
115 | + pass |
116 | + except (AttributeError, pywintypes.com_error): |
117 | + class SlideShowListenerImport(): |
118 | + pass |
119 | + |
120 | # Declare an empty exception to match the exception imported from UNO |
121 | - |
122 | class ErrorCodeIOException(Exception): |
123 | pass |
124 | else: |
125 | try: |
126 | import uno |
127 | + import unohelper |
128 | from com.sun.star.beans import PropertyValue |
129 | from com.sun.star.task import ErrorCodeIOException |
130 | + from com.sun.star.presentation import XSlideShowListener |
131 | + |
132 | + class SlideShowListenerImport(unohelper.Base, XSlideShowListener): |
133 | + pass |
134 | |
135 | uno_available = True |
136 | except ImportError: |
137 | @@ -82,6 +97,8 @@ |
138 | self.process = None |
139 | self.desktop = None |
140 | self.manager = None |
141 | + self.conf_provider = None |
142 | + self.presenter_screen_disabled_by_openlp = False |
143 | |
144 | def check_available(self): |
145 | """ |
146 | @@ -90,8 +107,7 @@ |
147 | log.debug('check_available') |
148 | if is_win(): |
149 | return self.get_com_servicemanager() is not None |
150 | - else: |
151 | - return uno_available |
152 | + return uno_available |
153 | |
154 | def start_process(self): |
155 | """ |
156 | @@ -131,6 +147,7 @@ |
157 | self.manager = uno_instance.ServiceManager |
158 | log.debug('get UNO Desktop Openoffice - createInstanceWithContext - Desktop') |
159 | desktop = self.manager.createInstanceWithContext("com.sun.star.frame.Desktop", uno_instance) |
160 | + self.toggle_presentation_screen(False) |
161 | return desktop |
162 | except Exception: |
163 | log.warning('Failed to get UNO desktop') |
164 | @@ -148,6 +165,7 @@ |
165 | desktop = self.manager.createInstance('com.sun.star.frame.Desktop') |
166 | except (AttributeError, pywintypes.com_error): |
167 | log.warning('Failure to find desktop - Impress may have closed') |
168 | + self.toggle_presentation_screen(False) |
169 | return desktop if desktop else None |
170 | |
171 | def get_com_servicemanager(self): |
172 | @@ -166,6 +184,8 @@ |
173 | Called at system exit to clean up any running presentations. |
174 | """ |
175 | log.debug('Kill OpenOffice') |
176 | + if self.presenter_screen_disabled_by_openlp: |
177 | + self._toggle_presentation_screen(True) |
178 | while self.docs: |
179 | self.docs[0].close_presentation() |
180 | desktop = None |
181 | @@ -195,6 +215,54 @@ |
182 | except Exception: |
183 | log.warning('Failed to terminate OpenOffice') |
184 | |
185 | + def toggle_presentation_screen(self, target_value): |
186 | + """ |
187 | + Enable or disable the Presentation Screen/Console |
188 | + """ |
189 | + # Create Instance of ConfigurationProvider |
190 | + if not self.conf_provider: |
191 | + if is_win(): |
192 | + self.conf_provider = self.manager.createInstance('com.sun.star.configuration.ConfigurationProvider') |
193 | + else: |
194 | + self.conf_provider = self.manager.createInstanceWithContext( |
195 | + 'com.sun.star.configuration.ConfigurationProvider', uno.getComponentContext()) |
196 | + # Setup lookup properties to get Impress settings |
197 | + properties = [] |
198 | + properties.append(self.create_property('nodepath', 'org.openoffice.Office.Impress')) |
199 | + properties = tuple(properties) |
200 | + try: |
201 | + # Get an updateable configuration view |
202 | + impress_conf_props = self.conf_provider.createInstanceWithArguments( |
203 | + 'com.sun.star.configuration.ConfigurationUpdateAccess', properties) |
204 | + # Get the specific setting for presentation screen |
205 | + presenter_screen_enabled = impress_conf_props.getHierarchicalPropertyValue( |
206 | + 'Misc/Start/EnablePresenterScreen') |
207 | + # If the presentation screen is enabled we disable it |
208 | + if presenter_screen_enabled != target_value: |
209 | + impress_conf_props.setHierarchicalPropertyValue('Misc/Start/EnablePresenterScreen', target_value) |
210 | + impress_conf_props.commitChanges() |
211 | + # if target_value is False this is an attempt to disable the Presenter Screen |
212 | + # so we make a note that it has been disabled, so it can be enabled again on close. |
213 | + if target_value is False: |
214 | + self.presenter_screen_disabled_by_openlp = True |
215 | + except Exception as e: |
216 | + log.exception(e) |
217 | + trace_error_handler(log) |
218 | + return |
219 | + |
220 | + def create_property(self, name, value): |
221 | + """ |
222 | + Create an OOo style property object which are passed into some Uno methods. |
223 | + """ |
224 | + log.debug('create property OpenOffice') |
225 | + if is_win(): |
226 | + property_object = self.manager.Bridge_GetStruct('com.sun.star.beans.PropertyValue') |
227 | + else: |
228 | + property_object = PropertyValue() |
229 | + property_object.Name = name |
230 | + property_object.Value = value |
231 | + return property_object |
232 | + |
233 | |
234 | class ImpressDocument(PresentationDocument): |
235 | """ |
236 | @@ -213,6 +281,8 @@ |
237 | self.document = None |
238 | self.presentation = None |
239 | self.control = None |
240 | + self.slide_ended = False |
241 | + self.slide_ended_reverse = False |
242 | |
243 | def load_presentation(self): |
244 | """ |
245 | @@ -233,13 +303,16 @@ |
246 | return False |
247 | self.desktop = desktop |
248 | properties = [] |
249 | - properties.append(self.create_property('Hidden', True)) |
250 | + properties.append(self.controller.create_property('Hidden', True)) |
251 | properties = tuple(properties) |
252 | try: |
253 | self.document = desktop.loadComponentFromURL(url, '_blank', 0, properties) |
254 | except Exception: |
255 | log.warning('Failed to load presentation {url}'.format(url=url)) |
256 | return False |
257 | + if self.document is None: |
258 | + log.warning('Presentation {url} could not be loaded'.format(url=url)) |
259 | + return False |
260 | self.presentation = self.document.getPresentation() |
261 | self.presentation.Display = ScreenList().current.number + 1 |
262 | self.control = None |
263 | @@ -257,7 +330,7 @@ |
264 | temp_folder_path = self.get_temp_folder() |
265 | thumb_dir_url = temp_folder_path.as_uri() |
266 | properties = [] |
267 | - properties.append(self.create_property('FilterName', 'impress_png_Export')) |
268 | + properties.append(self.controller.create_property('FilterName', 'impress_png_Export')) |
269 | properties = tuple(properties) |
270 | doc = self.document |
271 | pages = doc.getDrawPages() |
272 | @@ -279,19 +352,6 @@ |
273 | except Exception: |
274 | log.exception('{path} - Unable to store openoffice preview'.format(path=path)) |
275 | |
276 | - def create_property(self, name, value): |
277 | - """ |
278 | - Create an OOo style property object which are passed into some Uno methods. |
279 | - """ |
280 | - log.debug('create property OpenOffice') |
281 | - if is_win(): |
282 | - property_object = self.controller.manager.Bridge_GetStruct('com.sun.star.beans.PropertyValue') |
283 | - else: |
284 | - property_object = PropertyValue() |
285 | - property_object.Name = name |
286 | - property_object.Value = value |
287 | - return property_object |
288 | - |
289 | def close_presentation(self): |
290 | """ |
291 | Close presentation and clean up objects. Triggered by new object being added to SlideController or OpenLP being |
292 | @@ -356,8 +416,7 @@ |
293 | log.debug('is blank OpenOffice') |
294 | if self.control and self.control.isRunning(): |
295 | return self.control.isPaused() |
296 | - else: |
297 | - return False |
298 | + return False |
299 | |
300 | def stop_presentation(self): |
301 | """ |
302 | @@ -384,6 +443,8 @@ |
303 | sleep_count += 1 |
304 | self.control = self.presentation.getController() |
305 | window.setVisible(False) |
306 | + listener = SlideShowListener(self) |
307 | + self.control.getSlideShow().addSlideShowListener(listener) |
308 | else: |
309 | self.control.activate() |
310 | self.goto_slide(1) |
311 | @@ -415,17 +476,33 @@ |
312 | """ |
313 | Triggers the next effect of slide on the running presentation. |
314 | """ |
315 | + # if we are at the presentations end don't go further, just return True |
316 | + if self.slide_ended and self.get_slide_count() == self.get_slide_number(): |
317 | + return True |
318 | + self.slide_ended = False |
319 | + self.slide_ended_reverse = False |
320 | + past_end = False |
321 | is_paused = self.control.isPaused() |
322 | self.control.gotoNextEffect() |
323 | time.sleep(0.1) |
324 | + # If for some reason the presentation end was not detected above, this will catch it. |
325 | + # The presentation is set to paused when going past the end. |
326 | if not is_paused and self.control.isPaused(): |
327 | self.control.gotoPreviousEffect() |
328 | + past_end = True |
329 | + return past_end |
330 | |
331 | def previous_step(self): |
332 | """ |
333 | Triggers the previous slide on the running presentation. |
334 | """ |
335 | + # if we are at the presentations start don't go further back, just return True |
336 | + if self.slide_ended_reverse and self.get_slide_number() == 1: |
337 | + return True |
338 | + self.slide_ended = False |
339 | + self.slide_ended_reverse = False |
340 | self.control.gotoPreviousEffect() |
341 | + return False |
342 | |
343 | def get_slide_text(self, slide_no): |
344 | """ |
345 | @@ -483,3 +560,100 @@ |
346 | note = ' ' |
347 | notes.append(note) |
348 | self.save_titles_and_notes(titles, notes) |
349 | + |
350 | + if is_win(): |
351 | + property_object = self.controller.manager.Bridge_GetStruct('com.sun.star.beans.PropertyValue') |
352 | + |
353 | + |
354 | +class SlideShowListener(SlideShowListenerImport): |
355 | + """ |
356 | + Listener interface to receive global slide show events. |
357 | + """ |
358 | + |
359 | + def __init__(self, document): |
360 | + """ |
361 | + Constructor |
362 | + |
363 | + :param document: The ImpressDocument being presented |
364 | + """ |
365 | + self.document = document |
366 | + |
367 | + def paused(self): |
368 | + """ |
369 | + Notify that the slide show is paused |
370 | + """ |
371 | + log.debug('LibreOffice SlideShowListener event: paused') |
372 | + |
373 | + def resumed(self): |
374 | + """ |
375 | + Notify that the slide show is resumed from a paused state |
376 | + """ |
377 | + log.debug('LibreOffice SlideShowListener event: resumed') |
378 | + |
379 | + def slideTransitionStarted(self): |
380 | + """ |
381 | + Notify that a new slide starts to become visible. |
382 | + """ |
383 | + log.debug('LibreOffice SlideShowListener event: slideTransitionStarted') |
384 | + |
385 | + def slideTransitionEnded(self): |
386 | + """ |
387 | + Notify that the slide transtion of the current slide ended. |
388 | + """ |
389 | + log.debug('LibreOffice SlideShowListener event: slideTransitionEnded') |
390 | + |
391 | + def slideAnimationsEnded(self): |
392 | + """ |
393 | + Notify that the last animation from the main sequence of the current slide has ended. |
394 | + """ |
395 | + log.debug('LibreOffice SlideShowListener event: slideAnimationsEnded') |
396 | + if not Registry().get('main_window').isActiveWindow(): |
397 | + log.debug('main window is not in focus - should update slidecontroller') |
398 | + Registry().execute('slidecontroller_live_change', self.document.control.getCurrentSlideIndex() + 1) |
399 | + |
400 | + def slideEnded(self, reverse): |
401 | + """ |
402 | + Notify that the current slide has ended, e.g. the user has clicked on the slide. Calling displaySlide() |
403 | + twice will not issue this event. |
404 | + """ |
405 | + log.debug('LibreOffice SlideShowListener event: slideEnded %d' % reverse) |
406 | + if reverse: |
407 | + self.document.slide_ended = False |
408 | + self.document.slide_ended_reverse = True |
409 | + else: |
410 | + self.document.slide_ended = True |
411 | + self.document.slide_ended_reverse = False |
412 | + |
413 | + def hyperLinkClicked(self, hyperLink): |
414 | + """ |
415 | + Notifies that a hyperlink has been clicked. |
416 | + """ |
417 | + log.debug('LibreOffice SlideShowListener event: hyperLinkClicked %s' % hyperLink) |
418 | + |
419 | + def disposing(self, source): |
420 | + """ |
421 | + gets called when the broadcaster is about to be disposed. |
422 | + :param source: |
423 | + """ |
424 | + log.debug('LibreOffice SlideShowListener event: disposing') |
425 | + |
426 | + def beginEvent(self, node): |
427 | + """ |
428 | + This event is raised when the element local timeline begins to play. |
429 | + :param node: |
430 | + """ |
431 | + log.debug('LibreOffice SlideShowListener event: beginEvent') |
432 | + |
433 | + def endEvent(self, node): |
434 | + """ |
435 | + This event is raised at the active end of the element. |
436 | + :param node: |
437 | + """ |
438 | + log.debug('LibreOffice SlideShowListener event: endEvent') |
439 | + |
440 | + def repeat(self, node): |
441 | + """ |
442 | + This event is raised when the element local timeline repeats. |
443 | + :param node: |
444 | + """ |
445 | + log.debug('LibreOffice SlideShowListener event: repeat') |
446 | |
447 | === modified file 'openlp/plugins/presentations/lib/messagelistener.py' |
448 | --- openlp/plugins/presentations/lib/messagelistener.py 2019-05-22 06:47:00 +0000 |
449 | +++ openlp/plugins/presentations/lib/messagelistener.py 2019-05-24 19:21:37 +0000 |
450 | @@ -169,24 +169,21 @@ |
451 | """ |
452 | log.debug('Live = {live}, next'.format(live=self.is_live)) |
453 | if not self.doc: |
454 | - return |
455 | + return False |
456 | if not self.is_live: |
457 | - return |
458 | + return False |
459 | if self.hide_mode: |
460 | if not self.doc.is_active(): |
461 | - return |
462 | + return False |
463 | if self.doc.slidenumber < self.doc.get_slide_count(): |
464 | self.doc.slidenumber += 1 |
465 | self.poll() |
466 | - return |
467 | + return False |
468 | if not self.activate(): |
469 | - return |
470 | - # The "End of slideshow" screen is after the last slide. Note, we can't just stop on the last slide, since it |
471 | - # may contain animations that need to be stepped through. |
472 | - if self.doc.slidenumber > self.doc.get_slide_count(): |
473 | - return |
474 | - self.doc.next_step() |
475 | + return False |
476 | + ret = self.doc.next_step() |
477 | self.poll() |
478 | + return ret |
479 | |
480 | def previous(self): |
481 | """ |
482 | @@ -194,20 +191,21 @@ |
483 | """ |
484 | log.debug('Live = {live}, previous'.format(live=self.is_live)) |
485 | if not self.doc: |
486 | - return |
487 | + return False |
488 | if not self.is_live: |
489 | - return |
490 | + return False |
491 | if self.hide_mode: |
492 | if not self.doc.is_active(): |
493 | - return |
494 | + return False |
495 | if self.doc.slidenumber > 1: |
496 | self.doc.slidenumber -= 1 |
497 | self.poll() |
498 | - return |
499 | + return False |
500 | if not self.activate(): |
501 | - return |
502 | - self.doc.previous_step() |
503 | + return False |
504 | + ret = self.doc.previous_step() |
505 | self.poll() |
506 | + return ret |
507 | |
508 | def shutdown(self): |
509 | """ |
510 | @@ -418,11 +416,12 @@ |
511 | """ |
512 | is_live = message[1] |
513 | if is_live: |
514 | - self.live_handler.next() |
515 | + ret = self.live_handler.next() |
516 | if Settings().value('core/click live slide to unblank'): |
517 | Registry().execute('slidecontroller_live_unblank') |
518 | + return ret |
519 | else: |
520 | - self.preview_handler.next() |
521 | + return self.preview_handler.next() |
522 | |
523 | def previous(self, message): |
524 | """ |
525 | @@ -432,11 +431,12 @@ |
526 | """ |
527 | is_live = message[1] |
528 | if is_live: |
529 | - self.live_handler.previous() |
530 | + ret = self.live_handler.previous() |
531 | if Settings().value('core/click live slide to unblank'): |
532 | Registry().execute('slidecontroller_live_unblank') |
533 | + return ret |
534 | else: |
535 | - self.preview_handler.previous() |
536 | + return self.preview_handler.previous() |
537 | |
538 | def shutdown(self, message): |
539 | """ |
540 | |
541 | === modified file 'openlp/plugins/presentations/lib/powerpointcontroller.py' |
542 | --- openlp/plugins/presentations/lib/powerpointcontroller.py 2019-05-22 06:47:00 +0000 |
543 | +++ openlp/plugins/presentations/lib/powerpointcontroller.py 2019-05-24 19:21:37 +0000 |
544 | @@ -170,14 +170,17 @@ |
545 | However, for the moment, we want a physical file since it makes life easier elsewhere. |
546 | """ |
547 | log.debug('create_thumbnails') |
548 | + generate_thumbs = True |
549 | if self.check_thumbnails(): |
550 | - return |
551 | + # No need for thumbnails but we still need the index |
552 | + generate_thumbs = False |
553 | key = 1 |
554 | for num in range(self.presentation.Slides.Count): |
555 | if not self.presentation.Slides(num + 1).SlideShowTransition.Hidden: |
556 | self.index_map[key] = num + 1 |
557 | - self.presentation.Slides(num + 1).Export( |
558 | - str(self.get_thumbnail_folder() / 'slide{key:d}.png'.format(key=key)), 'png', 320, 240) |
559 | + if generate_thumbs: |
560 | + self.presentation.Slides(num + 1).Export( |
561 | + str(self.get_thumbnail_folder() / 'slide{key:d}.png'.format(key=key)), 'png', 320, 240) |
562 | key += 1 |
563 | self.slide_count = key - 1 |
564 | |
565 | @@ -318,6 +321,9 @@ |
566 | size = ScreenList().current.display_geometry |
567 | ppt_window = None |
568 | try: |
569 | + # Disable the presentation console |
570 | + self.presentation.SlideShowSettings.ShowPresenterView = 0 |
571 | + # Start the presentation |
572 | ppt_window = self.presentation.SlideShowSettings.Run() |
573 | except (AttributeError, pywintypes.com_error): |
574 | log.exception('Caught exception while in start_presentation') |
575 | @@ -437,6 +443,12 @@ |
576 | Triggers the next effect of slide on the running presentation. |
577 | """ |
578 | log.debug('next_step') |
579 | + # if we are at the presentations end don't go further, just return True |
580 | + if self.presentation.SlideShowWindow.View.GetClickCount() == \ |
581 | + self.presentation.SlideShowWindow.View.GetClickIndex() \ |
582 | + and self.get_slide_number() == self.get_slide_count(): |
583 | + return True |
584 | + past_end = False |
585 | try: |
586 | self.presentation.SlideShowWindow.Activate() |
587 | self.presentation.SlideShowWindow.View.Next() |
588 | @@ -444,28 +456,35 @@ |
589 | log.exception('Caught exception while in next_step') |
590 | trace_error_handler(log) |
591 | self.show_error_msg() |
592 | - return |
593 | + return past_end |
594 | + # If for some reason the presentation end was not detected above, this will catch it. |
595 | if self.get_slide_number() > self.get_slide_count(): |
596 | log.debug('past end, stepping back to previous') |
597 | self.previous_step() |
598 | + past_end = True |
599 | # Stop powerpoint from flashing in the taskbar |
600 | if self.presentation_hwnd: |
601 | win32gui.FlashWindowEx(self.presentation_hwnd, win32con.FLASHW_STOP, 0, 0) |
602 | # Make sure powerpoint doesn't steal focus, unless we're on a single screen setup |
603 | if len(ScreenList()) > 1: |
604 | Registry().get('main_window').activateWindow() |
605 | + return past_end |
606 | |
607 | def previous_step(self): |
608 | """ |
609 | Triggers the previous slide on the running presentation. |
610 | """ |
611 | log.debug('previous_step') |
612 | + # if we are at the presentations start we can't go further back, just return True |
613 | + if self.presentation.SlideShowWindow.View.GetClickIndex() == 0 and self.get_slide_number() == 1: |
614 | + return True |
615 | try: |
616 | self.presentation.SlideShowWindow.View.Previous() |
617 | except (AttributeError, pywintypes.com_error): |
618 | log.exception('Caught exception while in previous_step') |
619 | trace_error_handler(log) |
620 | self.show_error_msg() |
621 | + return False |
622 | |
623 | def get_slide_text(self, slide_no): |
624 | """ |
625 | |
626 | === modified file 'openlp/plugins/presentations/lib/presentationcontroller.py' |
627 | --- openlp/plugins/presentations/lib/presentationcontroller.py 2019-05-22 06:47:00 +0000 |
628 | +++ openlp/plugins/presentations/lib/presentationcontroller.py 2019-05-24 19:21:37 +0000 |
629 | @@ -248,15 +248,17 @@ |
630 | def next_step(self): |
631 | """ |
632 | Triggers the next effect of slide on the running presentation. This might be the next animation on the current |
633 | - slide, or the next slide |
634 | + slide, or the next slide. |
635 | + Returns True if we stepped beyond the slides of the presentation |
636 | """ |
637 | - pass |
638 | + return False |
639 | |
640 | def previous_step(self): |
641 | """ |
642 | Triggers the previous slide on the running presentation |
643 | + Returns True if we stepped beyond the slides of the presentation |
644 | """ |
645 | - pass |
646 | + return False |
647 | |
648 | def convert_thumbnail(self, image_path, index): |
649 | """ |
Linux tests failed, please see https:/ /ci.openlp. io/job/ MP-02-Linux_ Tests/158/ for more details