forked from openlp/openlp
Make it possible to go to next or previous service item when stepping through a presentation. Disables impress and powerpoint presentation console.
bzr-revno: 2875 Fixes: https://launchpad.net/bugs/1165855, https://launchpad.net/bugs/1798651
This commit is contained in:
commit
f2779edcd4
@ -146,7 +146,7 @@ class Registry(object):
|
||||
try:
|
||||
log.debug('Running function {} for {}'.format(function, event))
|
||||
result = function(*args, **kwargs)
|
||||
if result:
|
||||
if result is not None:
|
||||
results.append(result)
|
||||
except TypeError:
|
||||
# Who has called me can help in debugging
|
||||
|
@ -984,8 +984,10 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi
|
||||
prev_item_last_slide = None
|
||||
service_iterator = QtWidgets.QTreeWidgetItemIterator(self.service_manager_list)
|
||||
while service_iterator.value():
|
||||
# Found the selected/current service item
|
||||
if service_iterator.value() == selected:
|
||||
if last_slide and prev_item_last_slide:
|
||||
# Go to the last slide of the previous service item
|
||||
pos = prev_item.data(0, QtCore.Qt.UserRole)
|
||||
check_expanded = self.service_items[pos - 1]['expanded']
|
||||
self.service_manager_list.setCurrentItem(prev_item_last_slide)
|
||||
@ -994,13 +996,17 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi
|
||||
self.make_live()
|
||||
self.service_manager_list.setCurrentItem(prev_item)
|
||||
elif prev_item:
|
||||
# Go to the first slide of the previous service item
|
||||
self.service_manager_list.setCurrentItem(prev_item)
|
||||
self.make_live()
|
||||
return
|
||||
# Found the previous service item root
|
||||
if service_iterator.value().parent() is None:
|
||||
prev_item = service_iterator.value()
|
||||
# Found the last slide of the previous item
|
||||
if service_iterator.value().parent() is prev_item:
|
||||
prev_item_last_slide = service_iterator.value()
|
||||
# Go to next item in the tree
|
||||
service_iterator += 1
|
||||
|
||||
def on_set_item(self, message):
|
||||
|
@ -1261,9 +1261,18 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
|
||||
if not self.service_item:
|
||||
return
|
||||
if self.service_item.is_command():
|
||||
Registry().execute('{text}_next'.format(text=self.service_item.name.lower()),
|
||||
past_end = Registry().execute('{text}_next'.format(text=self.service_item.name.lower()),
|
||||
[self.service_item, self.is_live])
|
||||
if self.is_live:
|
||||
# Check if we have gone past the end of the last slide
|
||||
if self.is_live and past_end and past_end[0]:
|
||||
if wrap is None:
|
||||
if self.slide_limits == SlideLimits.Wrap:
|
||||
self.on_slide_selected_index([0])
|
||||
elif self.is_live and self.slide_limits == SlideLimits.Next:
|
||||
self.service_next()
|
||||
elif wrap:
|
||||
self.on_slide_selected_index([0])
|
||||
elif self.is_live:
|
||||
self.update_preview()
|
||||
else:
|
||||
row = self.preview_widget.current_slide_number() + 1
|
||||
@ -1290,9 +1299,16 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
|
||||
if not self.service_item:
|
||||
return
|
||||
if self.service_item.is_command():
|
||||
Registry().execute('{text}_previous'.format(text=self.service_item.name.lower()),
|
||||
before_start = Registry().execute('{text}_previous'.format(text=self.service_item.name.lower()),
|
||||
[self.service_item, self.is_live])
|
||||
if self.is_live:
|
||||
# Check id we have tried to go before that start slide
|
||||
if self.is_live and before_start and before_start[0]:
|
||||
if self.slide_limits == SlideLimits.Wrap:
|
||||
self.on_slide_selected_index([self.preview_widget.slide_count() - 1])
|
||||
elif self.is_live and self.slide_limits == SlideLimits.Next:
|
||||
self.keypress_queue.append(ServiceItemAction.PreviousLastSlide)
|
||||
self._process_queue()
|
||||
elif self.is_live:
|
||||
self.update_preview()
|
||||
else:
|
||||
row = self.preview_widget.current_slide_number() - 1
|
||||
|
@ -36,31 +36,49 @@ import time
|
||||
|
||||
from PyQt5 import QtCore
|
||||
|
||||
from openlp.core.common import delete_file, get_uno_command, get_uno_instance, is_win
|
||||
from openlp.core.common import delete_file, get_uno_command, get_uno_instance, is_win, trace_error_handler
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument, \
|
||||
TextType
|
||||
|
||||
|
||||
# Load the XSlideShowListener class so we can inherit from it
|
||||
if is_win():
|
||||
from win32com.client import Dispatch
|
||||
import pywintypes
|
||||
uno_available = False
|
||||
# Declare an empty exception to match the exception imported from UNO
|
||||
try:
|
||||
service_manager = Dispatch('com.sun.star.ServiceManager')
|
||||
service_manager._FlagAsMethod('Bridge_GetStruct')
|
||||
XSlideShowListenerObj = service_manager.Bridge_GetStruct('com.sun.star.presentation.XSlideShowListener')
|
||||
|
||||
class SlideShowListenerImport(XSlideShowListenerObj.__class__):
|
||||
pass
|
||||
except (AttributeError, pywintypes.com_error):
|
||||
class SlideShowListenerImport():
|
||||
pass
|
||||
|
||||
# Declare an empty exception to match the exception imported from UNO
|
||||
class ErrorCodeIOException(Exception):
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
import uno
|
||||
import unohelper
|
||||
from com.sun.star.beans import PropertyValue
|
||||
from com.sun.star.task import ErrorCodeIOException
|
||||
from com.sun.star.presentation import XSlideShowListener
|
||||
|
||||
class SlideShowListenerImport(unohelper.Base, XSlideShowListener):
|
||||
pass
|
||||
|
||||
uno_available = True
|
||||
except ImportError:
|
||||
uno_available = False
|
||||
|
||||
class SlideShowListenerImport():
|
||||
pass
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -82,6 +100,8 @@ class ImpressController(PresentationController):
|
||||
self.process = None
|
||||
self.desktop = None
|
||||
self.manager = None
|
||||
self.conf_provider = None
|
||||
self.presenter_screen_disabled_by_openlp = False
|
||||
|
||||
def check_available(self):
|
||||
"""
|
||||
@ -90,7 +110,6 @@ class ImpressController(PresentationController):
|
||||
log.debug('check_available')
|
||||
if is_win():
|
||||
return self.get_com_servicemanager() is not None
|
||||
else:
|
||||
return uno_available
|
||||
|
||||
def start_process(self):
|
||||
@ -131,6 +150,7 @@ class ImpressController(PresentationController):
|
||||
self.manager = uno_instance.ServiceManager
|
||||
log.debug('get UNO Desktop Openoffice - createInstanceWithContext - Desktop')
|
||||
desktop = self.manager.createInstanceWithContext("com.sun.star.frame.Desktop", uno_instance)
|
||||
self.toggle_presentation_screen(False)
|
||||
return desktop
|
||||
except Exception:
|
||||
log.warning('Failed to get UNO desktop')
|
||||
@ -148,6 +168,7 @@ class ImpressController(PresentationController):
|
||||
desktop = self.manager.createInstance('com.sun.star.frame.Desktop')
|
||||
except (AttributeError, pywintypes.com_error):
|
||||
log.warning('Failure to find desktop - Impress may have closed')
|
||||
self.toggle_presentation_screen(False)
|
||||
return desktop if desktop else None
|
||||
|
||||
def get_com_servicemanager(self):
|
||||
@ -166,6 +187,8 @@ class ImpressController(PresentationController):
|
||||
Called at system exit to clean up any running presentations.
|
||||
"""
|
||||
log.debug('Kill OpenOffice')
|
||||
if self.presenter_screen_disabled_by_openlp:
|
||||
self.toggle_presentation_screen(True)
|
||||
while self.docs:
|
||||
self.docs[0].close_presentation()
|
||||
desktop = None
|
||||
@ -195,6 +218,60 @@ class ImpressController(PresentationController):
|
||||
except Exception:
|
||||
log.warning('Failed to terminate OpenOffice')
|
||||
|
||||
def toggle_presentation_screen(self, set_visible):
|
||||
"""
|
||||
Enable or disable the Presentation Screen/Console
|
||||
|
||||
:param bool set_visible: Should the presentation screen/console be set to be visible.
|
||||
:rtype: None
|
||||
"""
|
||||
# Create Instance of ConfigurationProvider
|
||||
if not self.conf_provider:
|
||||
if is_win():
|
||||
self.conf_provider = self.manager.createInstance('com.sun.star.configuration.ConfigurationProvider')
|
||||
else:
|
||||
self.conf_provider = self.manager.createInstanceWithContext(
|
||||
'com.sun.star.configuration.ConfigurationProvider', uno.getComponentContext())
|
||||
# Setup lookup properties to get Impress settings
|
||||
properties = []
|
||||
properties.append(self.create_property('nodepath', 'org.openoffice.Office.Impress'))
|
||||
properties = tuple(properties)
|
||||
try:
|
||||
# Get an updateable configuration view
|
||||
impress_conf_props = self.conf_provider.createInstanceWithArguments(
|
||||
'com.sun.star.configuration.ConfigurationUpdateAccess', properties)
|
||||
# Get the specific setting for presentation screen
|
||||
presenter_screen_enabled = impress_conf_props.getHierarchicalPropertyValue(
|
||||
'Misc/Start/EnablePresenterScreen')
|
||||
# If the presentation screen is enabled we disable it
|
||||
if presenter_screen_enabled != set_visible:
|
||||
impress_conf_props.setHierarchicalPropertyValue('Misc/Start/EnablePresenterScreen', set_visible)
|
||||
impress_conf_props.commitChanges()
|
||||
# if set_visible is False this is an attempt to disable the Presenter Screen
|
||||
# so we make a note that it has been disabled, so it can be enabled again on close.
|
||||
if set_visible is False:
|
||||
self.presenter_screen_disabled_by_openlp = True
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
trace_error_handler(log)
|
||||
|
||||
def create_property(self, name, value):
|
||||
"""
|
||||
Create an OOo style property object which are passed into some Uno methods.
|
||||
|
||||
:param str name: The name of the property
|
||||
:param str value: The value of the property
|
||||
:rtype: com.sun.star.beans.PropertyValue
|
||||
"""
|
||||
log.debug('create property OpenOffice')
|
||||
if is_win():
|
||||
property_object = self.manager.Bridge_GetStruct('com.sun.star.beans.PropertyValue')
|
||||
else:
|
||||
property_object = PropertyValue()
|
||||
property_object.Name = name
|
||||
property_object.Value = value
|
||||
return property_object
|
||||
|
||||
|
||||
class ImpressDocument(PresentationDocument):
|
||||
"""
|
||||
@ -213,6 +290,8 @@ class ImpressDocument(PresentationDocument):
|
||||
self.document = None
|
||||
self.presentation = None
|
||||
self.control = None
|
||||
self.slide_ended = False
|
||||
self.slide_ended_reverse = False
|
||||
|
||||
def load_presentation(self):
|
||||
"""
|
||||
@ -233,13 +312,16 @@ class ImpressDocument(PresentationDocument):
|
||||
return False
|
||||
self.desktop = desktop
|
||||
properties = []
|
||||
properties.append(self.create_property('Hidden', True))
|
||||
properties.append(self.controller.create_property('Hidden', True))
|
||||
properties = tuple(properties)
|
||||
try:
|
||||
self.document = desktop.loadComponentFromURL(url, '_blank', 0, properties)
|
||||
except Exception:
|
||||
log.warning('Failed to load presentation {url}'.format(url=url))
|
||||
return False
|
||||
if self.document is None:
|
||||
log.warning('Presentation {url} could not be loaded'.format(url=url))
|
||||
return False
|
||||
self.presentation = self.document.getPresentation()
|
||||
self.presentation.Display = ScreenList().current.number + 1
|
||||
self.control = None
|
||||
@ -257,7 +339,7 @@ class ImpressDocument(PresentationDocument):
|
||||
temp_folder_path = self.get_temp_folder()
|
||||
thumb_dir_url = temp_folder_path.as_uri()
|
||||
properties = []
|
||||
properties.append(self.create_property('FilterName', 'impress_png_Export'))
|
||||
properties.append(self.controller.create_property('FilterName', 'impress_png_Export'))
|
||||
properties = tuple(properties)
|
||||
doc = self.document
|
||||
pages = doc.getDrawPages()
|
||||
@ -279,19 +361,6 @@ class ImpressDocument(PresentationDocument):
|
||||
except Exception:
|
||||
log.exception('{path} - Unable to store openoffice preview'.format(path=path))
|
||||
|
||||
def create_property(self, name, value):
|
||||
"""
|
||||
Create an OOo style property object which are passed into some Uno methods.
|
||||
"""
|
||||
log.debug('create property OpenOffice')
|
||||
if is_win():
|
||||
property_object = self.controller.manager.Bridge_GetStruct('com.sun.star.beans.PropertyValue')
|
||||
else:
|
||||
property_object = PropertyValue()
|
||||
property_object.Name = name
|
||||
property_object.Value = value
|
||||
return property_object
|
||||
|
||||
def close_presentation(self):
|
||||
"""
|
||||
Close presentation and clean up objects. Triggered by new object being added to SlideController or OpenLP being
|
||||
@ -356,7 +425,6 @@ class ImpressDocument(PresentationDocument):
|
||||
log.debug('is blank OpenOffice')
|
||||
if self.control and self.control.isRunning():
|
||||
return self.control.isPaused()
|
||||
else:
|
||||
return False
|
||||
|
||||
def stop_presentation(self):
|
||||
@ -384,6 +452,8 @@ class ImpressDocument(PresentationDocument):
|
||||
sleep_count += 1
|
||||
self.control = self.presentation.getController()
|
||||
window.setVisible(False)
|
||||
listener = SlideShowListener(self)
|
||||
self.control.getSlideShow().addSlideShowListener(listener)
|
||||
else:
|
||||
self.control.activate()
|
||||
self.goto_slide(1)
|
||||
@ -415,17 +485,33 @@ class ImpressDocument(PresentationDocument):
|
||||
"""
|
||||
Triggers the next effect of slide on the running presentation.
|
||||
"""
|
||||
# if we are at the presentations end don't go further, just return True
|
||||
if self.slide_ended and self.get_slide_count() == self.get_slide_number():
|
||||
return True
|
||||
self.slide_ended = False
|
||||
self.slide_ended_reverse = False
|
||||
past_end = False
|
||||
is_paused = self.control.isPaused()
|
||||
self.control.gotoNextEffect()
|
||||
time.sleep(0.1)
|
||||
# If for some reason the presentation end was not detected above, this will catch it.
|
||||
# The presentation is set to paused when going past the end.
|
||||
if not is_paused and self.control.isPaused():
|
||||
self.control.gotoPreviousEffect()
|
||||
past_end = True
|
||||
return past_end
|
||||
|
||||
def previous_step(self):
|
||||
"""
|
||||
Triggers the previous slide on the running presentation.
|
||||
"""
|
||||
# if we are at the presentations start don't go further back, just return True
|
||||
if self.slide_ended_reverse and self.get_slide_number() == 1:
|
||||
return True
|
||||
self.slide_ended = False
|
||||
self.slide_ended_reverse = False
|
||||
self.control.gotoPreviousEffect()
|
||||
return False
|
||||
|
||||
def get_slide_text(self, slide_no):
|
||||
"""
|
||||
@ -483,3 +569,100 @@ class ImpressDocument(PresentationDocument):
|
||||
note = ' '
|
||||
notes.append(note)
|
||||
self.save_titles_and_notes(titles, notes)
|
||||
|
||||
|
||||
class SlideShowListener(SlideShowListenerImport):
|
||||
"""
|
||||
Listener interface to receive global slide show events.
|
||||
"""
|
||||
|
||||
def __init__(self, document):
|
||||
"""
|
||||
Constructor
|
||||
|
||||
:param document: The ImpressDocument being presented
|
||||
"""
|
||||
self.document = document
|
||||
|
||||
def paused(self):
|
||||
"""
|
||||
Notify that the slide show is paused
|
||||
"""
|
||||
log.debug('LibreOffice SlideShowListener event: paused')
|
||||
|
||||
def resumed(self):
|
||||
"""
|
||||
Notify that the slide show is resumed from a paused state
|
||||
"""
|
||||
log.debug('LibreOffice SlideShowListener event: resumed')
|
||||
|
||||
def slideTransitionStarted(self):
|
||||
"""
|
||||
Notify that a new slide starts to become visible.
|
||||
"""
|
||||
log.debug('LibreOffice SlideShowListener event: slideTransitionStarted')
|
||||
|
||||
def slideTransitionEnded(self):
|
||||
"""
|
||||
Notify that the slide transtion of the current slide ended.
|
||||
"""
|
||||
log.debug('LibreOffice SlideShowListener event: slideTransitionEnded')
|
||||
|
||||
def slideAnimationsEnded(self):
|
||||
"""
|
||||
Notify that the last animation from the main sequence of the current slide has ended.
|
||||
"""
|
||||
log.debug('LibreOffice SlideShowListener event: slideAnimationsEnded')
|
||||
if not Registry().get('main_window').isActiveWindow():
|
||||
log.debug('main window is not in focus - should update slidecontroller')
|
||||
Registry().execute('slidecontroller_live_change', self.document.control.getCurrentSlideIndex() + 1)
|
||||
|
||||
def slideEnded(self, reverse):
|
||||
"""
|
||||
Notify that the current slide has ended, e.g. the user has clicked on the slide. Calling displaySlide()
|
||||
twice will not issue this event.
|
||||
|
||||
:param bool reverse: Whether or not the direction of the "slide movement" is reversed/backwards.
|
||||
:rtype: None
|
||||
"""
|
||||
log.debug('LibreOffice SlideShowListener event: slideEnded %d' % reverse)
|
||||
if reverse:
|
||||
self.document.slide_ended = False
|
||||
self.document.slide_ended_reverse = True
|
||||
else:
|
||||
self.document.slide_ended = True
|
||||
self.document.slide_ended_reverse = False
|
||||
|
||||
def hyperLinkClicked(self, hyperLink):
|
||||
"""
|
||||
Notifies that a hyperlink has been clicked.
|
||||
"""
|
||||
log.debug('LibreOffice SlideShowListener event: hyperLinkClicked %s' % hyperLink)
|
||||
|
||||
def disposing(self, source):
|
||||
"""
|
||||
gets called when the broadcaster is about to be disposed.
|
||||
:param source:
|
||||
"""
|
||||
log.debug('LibreOffice SlideShowListener event: disposing')
|
||||
|
||||
def beginEvent(self, node):
|
||||
"""
|
||||
This event is raised when the element local timeline begins to play.
|
||||
:param node:
|
||||
"""
|
||||
log.debug('LibreOffice SlideShowListener event: beginEvent')
|
||||
|
||||
def endEvent(self, node):
|
||||
"""
|
||||
This event is raised at the active end of the element.
|
||||
:param node:
|
||||
"""
|
||||
log.debug('LibreOffice SlideShowListener event: endEvent')
|
||||
|
||||
def repeat(self, node):
|
||||
"""
|
||||
This event is raised when the element local timeline repeats.
|
||||
:param node:
|
||||
"""
|
||||
log.debug('LibreOffice SlideShowListener event: repeat')
|
||||
|
@ -169,24 +169,21 @@ class Controller(object):
|
||||
"""
|
||||
log.debug('Live = {live}, next'.format(live=self.is_live))
|
||||
if not self.doc:
|
||||
return
|
||||
return False
|
||||
if not self.is_live:
|
||||
return
|
||||
return False
|
||||
if self.hide_mode:
|
||||
if not self.doc.is_active():
|
||||
return
|
||||
return False
|
||||
if self.doc.slidenumber < self.doc.get_slide_count():
|
||||
self.doc.slidenumber += 1
|
||||
self.poll()
|
||||
return
|
||||
return False
|
||||
if not self.activate():
|
||||
return
|
||||
# The "End of slideshow" screen is after the last slide. Note, we can't just stop on the last slide, since it
|
||||
# may contain animations that need to be stepped through.
|
||||
if self.doc.slidenumber > self.doc.get_slide_count():
|
||||
return
|
||||
self.doc.next_step()
|
||||
return False
|
||||
ret = self.doc.next_step()
|
||||
self.poll()
|
||||
return ret
|
||||
|
||||
def previous(self):
|
||||
"""
|
||||
@ -194,20 +191,21 @@ class Controller(object):
|
||||
"""
|
||||
log.debug('Live = {live}, previous'.format(live=self.is_live))
|
||||
if not self.doc:
|
||||
return
|
||||
return False
|
||||
if not self.is_live:
|
||||
return
|
||||
return False
|
||||
if self.hide_mode:
|
||||
if not self.doc.is_active():
|
||||
return
|
||||
return False
|
||||
if self.doc.slidenumber > 1:
|
||||
self.doc.slidenumber -= 1
|
||||
self.poll()
|
||||
return
|
||||
return False
|
||||
if not self.activate():
|
||||
return
|
||||
self.doc.previous_step()
|
||||
return False
|
||||
ret = self.doc.previous_step()
|
||||
self.poll()
|
||||
return ret
|
||||
|
||||
def shutdown(self):
|
||||
"""
|
||||
@ -418,11 +416,12 @@ class MessageListener(object):
|
||||
"""
|
||||
is_live = message[1]
|
||||
if is_live:
|
||||
self.live_handler.next()
|
||||
ret = self.live_handler.next()
|
||||
if Settings().value('core/click live slide to unblank'):
|
||||
Registry().execute('slidecontroller_live_unblank')
|
||||
return ret
|
||||
else:
|
||||
self.preview_handler.next()
|
||||
return self.preview_handler.next()
|
||||
|
||||
def previous(self, message):
|
||||
"""
|
||||
@ -432,11 +431,12 @@ class MessageListener(object):
|
||||
"""
|
||||
is_live = message[1]
|
||||
if is_live:
|
||||
self.live_handler.previous()
|
||||
ret = self.live_handler.previous()
|
||||
if Settings().value('core/click live slide to unblank'):
|
||||
Registry().execute('slidecontroller_live_unblank')
|
||||
return ret
|
||||
else:
|
||||
self.preview_handler.previous()
|
||||
return self.preview_handler.previous()
|
||||
|
||||
def shutdown(self, message):
|
||||
"""
|
||||
|
@ -145,8 +145,8 @@ class PowerpointDocument(PresentationDocument):
|
||||
try:
|
||||
if not self.controller.process:
|
||||
self.controller.start_process()
|
||||
self.controller.process.Presentations.Open(str(self.file_path), False, False, False)
|
||||
self.presentation = self.controller.process.Presentations(self.controller.process.Presentations.Count)
|
||||
self.presentation = self.controller.process.Presentations.Open(str(self.file_path), False, False, False)
|
||||
log.debug('Loaded presentation %s' % self.presentation.FullName)
|
||||
self.create_thumbnails()
|
||||
self.create_titles_and_notes()
|
||||
# Make sure powerpoint doesn't steal focus, unless we're on a single screen setup
|
||||
@ -170,12 +170,15 @@ class PowerpointDocument(PresentationDocument):
|
||||
However, for the moment, we want a physical file since it makes life easier elsewhere.
|
||||
"""
|
||||
log.debug('create_thumbnails')
|
||||
generate_thumbs = True
|
||||
if self.check_thumbnails():
|
||||
return
|
||||
# No need for thumbnails but we still need the index
|
||||
generate_thumbs = False
|
||||
key = 1
|
||||
for num in range(self.presentation.Slides.Count):
|
||||
if not self.presentation.Slides(num + 1).SlideShowTransition.Hidden:
|
||||
self.index_map[key] = num + 1
|
||||
if generate_thumbs:
|
||||
self.presentation.Slides(num + 1).Export(
|
||||
str(self.get_thumbnail_folder() / 'slide{key:d}.png'.format(key=key)), 'png', 320, 240)
|
||||
key += 1
|
||||
@ -318,6 +321,9 @@ class PowerpointDocument(PresentationDocument):
|
||||
size = ScreenList().current.display_geometry
|
||||
ppt_window = None
|
||||
try:
|
||||
# Disable the presentation console
|
||||
self.presentation.SlideShowSettings.ShowPresenterView = 0
|
||||
# Start the presentation
|
||||
ppt_window = self.presentation.SlideShowSettings.Run()
|
||||
except (AttributeError, pywintypes.com_error):
|
||||
log.exception('Caught exception while in start_presentation')
|
||||
@ -437,6 +443,12 @@ class PowerpointDocument(PresentationDocument):
|
||||
Triggers the next effect of slide on the running presentation.
|
||||
"""
|
||||
log.debug('next_step')
|
||||
# if we are at the presentations end don't go further, just return True
|
||||
if self.presentation.SlideShowWindow.View.GetClickCount() == \
|
||||
self.presentation.SlideShowWindow.View.GetClickIndex() \
|
||||
and self.get_slide_number() == self.get_slide_count():
|
||||
return True
|
||||
past_end = False
|
||||
try:
|
||||
self.presentation.SlideShowWindow.Activate()
|
||||
self.presentation.SlideShowWindow.View.Next()
|
||||
@ -444,28 +456,35 @@ class PowerpointDocument(PresentationDocument):
|
||||
log.exception('Caught exception while in next_step')
|
||||
trace_error_handler(log)
|
||||
self.show_error_msg()
|
||||
return
|
||||
return past_end
|
||||
# If for some reason the presentation end was not detected above, this will catch it.
|
||||
if self.get_slide_number() > self.get_slide_count():
|
||||
log.debug('past end, stepping back to previous')
|
||||
self.previous_step()
|
||||
past_end = True
|
||||
# Stop powerpoint from flashing in the taskbar
|
||||
if self.presentation_hwnd:
|
||||
win32gui.FlashWindowEx(self.presentation_hwnd, win32con.FLASHW_STOP, 0, 0)
|
||||
# Make sure powerpoint doesn't steal focus, unless we're on a single screen setup
|
||||
if len(ScreenList()) > 1:
|
||||
Registry().get('main_window').activateWindow()
|
||||
return past_end
|
||||
|
||||
def previous_step(self):
|
||||
"""
|
||||
Triggers the previous slide on the running presentation.
|
||||
"""
|
||||
log.debug('previous_step')
|
||||
# if we are at the presentations start we can't go further back, just return True
|
||||
if self.presentation.SlideShowWindow.View.GetClickIndex() == 0 and self.get_slide_number() == 1:
|
||||
return True
|
||||
try:
|
||||
self.presentation.SlideShowWindow.View.Previous()
|
||||
except (AttributeError, pywintypes.com_error):
|
||||
log.exception('Caught exception while in previous_step')
|
||||
trace_error_handler(log)
|
||||
self.show_error_msg()
|
||||
return False
|
||||
|
||||
def get_slide_text(self, slide_no):
|
||||
"""
|
||||
|
@ -248,15 +248,17 @@ class PresentationDocument(object):
|
||||
def next_step(self):
|
||||
"""
|
||||
Triggers the next effect of slide on the running presentation. This might be the next animation on the current
|
||||
slide, or the next slide
|
||||
slide, or the next slide.
|
||||
:rtype bool: True if we stepped beyond the slides of the presentation
|
||||
"""
|
||||
pass
|
||||
return False
|
||||
|
||||
def previous_step(self):
|
||||
"""
|
||||
Triggers the previous slide on the running presentation
|
||||
:rtype bool: True if we stepped beyond the slides of the presentation
|
||||
"""
|
||||
pass
|
||||
return False
|
||||
|
||||
def convert_thumbnail(self, image_path, index):
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user