Presentations

This commit is contained in:
Tim Bentley 2014-03-08 21:23:47 +00:00
parent 9773afc61c
commit 0da1b7b5f7
8 changed files with 100 additions and 67 deletions

View File

@ -52,6 +52,7 @@ else:
import uno
from com.sun.star.beans import PropertyValue
from com.sun.star.task import ErrorCodeIOException
uno_available = True
except ImportError:
uno_available = False
@ -183,9 +184,9 @@ class ImpressController(PresentationController):
docs = desktop.getComponents()
cnt = 0
if docs.hasElements():
list = docs.createEnumeration()
while list.hasMoreElements():
doc = list.nextElement()
list_elements = docs.createEnumeration()
while list_elements.hasMoreElements():
doc = list_elements.nextElement()
if doc.getImplementationName() != 'com.sun.star.comp.framework.BackingComp':
cnt += 1
if cnt > 0:
@ -203,7 +204,7 @@ class ImpressDocument(PresentationDocument):
Class which holds information and controls a single presentation.
"""
def __init__(self, controller, presentation):
def __init__ (self, controller, presentation):
"""
Constructor, store information about the file and initialise.
"""
@ -225,10 +226,10 @@ class ImpressDocument(PresentationDocument):
if desktop is None:
self.controller.start_process()
desktop = self.controller.get_com_desktop()
url = 'file:///' + self.filepath.replace('\\', '/').replace(':', '|').replace(' ', '%20')
url = 'file:///' + self.file_path.replace('\\', '/').replace(':', '|').replace(' ', '%20')
else:
desktop = self.controller.get_uno_desktop()
url = uno.systemPathToFileUrl(self.filepath)
url = uno.systemPathToFileUrl(self.file_path)
if desktop is None:
return False
self.desktop = desktop
@ -352,7 +353,7 @@ class ImpressDocument(PresentationDocument):
log.debug('unblank screen OpenOffice')
return self.control.resume()
def blank_screen(self):
def blank_screen (self):
"""
Blanks the screen.
"""
@ -409,11 +410,13 @@ class ImpressDocument(PresentationDocument):
"""
return self.document.getDrawPages().getCount()
def goto_slide(self, slideno):
def goto_slide(self, slide_no):
"""
Go to a specific slide (from 1).
:param slide_no: The slide the text is required for, starting at 1
"""
self.control.gotoSlideIndex(slideno-1)
self.control.gotoSlideIndex(slide_no - 1)
def next_step(self):
"""
@ -435,8 +438,7 @@ class ImpressDocument(PresentationDocument):
"""
Returns the text on the slide.
``slide_no``
The slide the text is required for, starting at 1
:param slide_no: The slide the text is required for, starting at 1
"""
return self.__get_text_from_page(slide_no)
@ -444,8 +446,7 @@ class ImpressDocument(PresentationDocument):
"""
Returns the text in the slide notes.
``slide_no``
The slide the notes are required for, starting at 1
:param slide_no: The slide the notes are required for, starting at 1
"""
return self.__get_text_from_page(slide_no, True)
@ -453,8 +454,8 @@ class ImpressDocument(PresentationDocument):
"""
Return any text extracted from the presentation page.
``notes``
A boolean. If set the method searches the notes of the slide.
:param slide_no: The slide the notes are required for, starting at 1
:param notes: A boolean. If set the method searches the notes of the slide.
"""
text = ''
pages = self.document.getDrawPages()

View File

@ -183,7 +183,7 @@ class PresentationMediaItem(MediaManagerItem):
translate('PresentationPlugin.MediaItem',
'A presentation with that filename already exists.'))
continue
controller_name = self.findControllerByType(filename)
controller_name = self.find_controller_by_type(filename)
if controller_name:
controller = self.controllers[controller_name]
doc = controller.add_document(file)
@ -240,11 +240,16 @@ class PresentationMediaItem(MediaManagerItem):
self.list_view.takeItem(row)
Settings().setValue(self.settings_section + '/presentations files', self.get_file_list())
def generate_slide_data(self, service_item, item=None, xml_version=False,
remote=False, context=ServiceItemContext.Service, presentation_file=None):
def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False,
context=ServiceItemContext.Service, presentation_file=None):
"""
Load the relevant information for displaying the presentation in the slidecontroller. In the case of
powerpoints, an image for each slide.
Generate the slide data. Needs to be implemented by the plugin.
:param service_item: The service item to be built on
:param item: The Song item to be used
:param xml_version: The xml version (not used)
:param remote: Triggered from remote
:param context: Why is it being generated
"""
if item:
items = [item]
@ -272,7 +277,7 @@ class PresentationMediaItem(MediaManagerItem):
(path, name) = os.path.split(filename)
service_item.title = name
if os.path.exists(filename):
processor = self.findControllerByType(filename)
processor = self.find_controller_by_type(filename)
if not processor:
return False
controller = self.controllers[processor]
@ -282,13 +287,13 @@ class PresentationMediaItem(MediaManagerItem):
os.path.join(doc.get_temp_folder(), 'mainslide001.png')):
doc.load_presentation()
i = 1
imagefile = 'mainslide%03d.png' % i
image = os.path.join(doc.get_temp_folder(), imagefile)
image_file = 'mainslide%03d.png' % i
image = os.path.join(doc.get_temp_folder(), image_file)
while os.path.isfile(image):
service_item.add_from_image(image, name)
i += 1
imagefile = 'mainslide%03d.png' % i
image = os.path.join(doc.get_temp_folder(), imagefile)
image_file = 'mainslide%03d.png' % i
image = os.path.join(doc.get_temp_folder(), image_file)
doc.close_presentation()
return True
else:
@ -307,7 +312,7 @@ class PresentationMediaItem(MediaManagerItem):
service_item.title = name
if os.path.exists(filename):
if service_item.processor == self.automatic:
service_item.processor = self.findControllerByType(filename)
service_item.processor = self.find_controller_by_type(filename)
if not service_item.processor:
return False
controller = self.controllers[service_item.processor]
@ -340,11 +345,13 @@ class PresentationMediaItem(MediaManagerItem):
'The presentation %s no longer exists.') % filename)
return False
def findControllerByType(self, filename):
def find_controller_by_type(self, filename):
"""
Determine the default application controller to use for the selected file type. This is used if "Automatic" is
set as the preferred controller. Find the first (alphabetic) enabled controller which "supports" the extension.
If none found, then look for a controller which "also supports" it instead.
:param filename: The file name
"""
file_type = os.path.splitext(filename)[1][1:]
if not file_type:
@ -360,6 +367,13 @@ class PresentationMediaItem(MediaManagerItem):
return None
def search(self, string, show_error):
"""
Search in files
:param string: name to be found
:param show_error: not used
:return:
"""
files = Settings().value(self.settings_section + '/presentations files')
results = []
string = string.lower()

View File

@ -71,7 +71,7 @@ class Controller(object):
return
self.doc.slidenumber = slide_no
self.hide_mode = hide_mode
log.debug('add_handler, slidenumber: %d' % slide_no)
log.debug('add_handler, slide_number: %d' % slide_no)
if self.is_live:
if hide_mode == HideMode.Screen:
Registry().execute('live_display_hide', HideMode.Screen)
@ -342,7 +342,7 @@ class MessageListener(object):
# so handler & processor is set to None, and we skip adding the handler.
self.handler = None
if self.handler == self.media_item.automatic:
self.handler = self.media_item.findControllerByType(file)
self.handler = self.media_item.find_controller_by_type(file)
if not self.handler:
return
if is_live:
@ -359,6 +359,8 @@ class MessageListener(object):
def slide(self, message):
"""
React to the message to move to a specific slide.
:param message: The message {1} is_live {2} slide
"""
is_live = message[1]
slide = message[2]
@ -370,6 +372,8 @@ class MessageListener(object):
def first(self, message):
"""
React to the message to move to the first slide.
:param message: The message {1} is_live
"""
is_live = message[1]
if is_live:
@ -380,6 +384,8 @@ class MessageListener(object):
def last(self, message):
"""
React to the message to move to the last slide.
:param message: The message {1} is_live
"""
is_live = message[1]
if is_live:
@ -390,6 +396,8 @@ class MessageListener(object):
def next(self, message):
"""
React to the message to move to the next animation/slide.
:param message: The message {1} is_live
"""
is_live = message[1]
if is_live:
@ -400,6 +408,8 @@ class MessageListener(object):
def previous(self, message):
"""
React to the message to move to the previous animation/slide.
:param message: The message {1} is_live
"""
is_live = message[1]
if is_live:
@ -410,6 +420,8 @@ class MessageListener(object):
def shutdown(self, message):
"""
React to message to shutdown the presentation. I.e. end the show and close the file.
:param message: The message {1} is_live
"""
is_live = message[1]
if is_live:
@ -420,6 +432,8 @@ class MessageListener(object):
def hide(self, message):
"""
React to the message to show the desktop.
:param message: The message {1} is_live
"""
is_live = message[1]
if is_live:
@ -428,6 +442,8 @@ class MessageListener(object):
def blank(self, message):
"""
React to the message to blank the display.
:param message: The message {1} is_live {2} slide
"""
is_live = message[1]
hide_mode = message[2]
@ -437,6 +453,8 @@ class MessageListener(object):
def unblank(self, message):
"""
React to the message to unblank the display.
:param message: The message {1} is_live
"""
is_live = message[1]
if is_live:

View File

@ -113,7 +113,7 @@ class PdfController(PresentationController):
self.gsbin = ''
self.also_supports = []
# Use the user defined program if given
if (Settings().value('presentations/enable_pdf_program')):
if Settings().value('presentations/enable_pdf_program'):
pdf_program = Settings().value('presentations/pdf_program')
program_type = self.check_binary(pdf_program)
if program_type == 'gs':
@ -197,7 +197,7 @@ class PdfDocument(PresentationDocument):
runlog = []
try:
runlog = check_output([self.controller.gsbin, '-dNOPAUSE', '-dNODISPLAY', '-dBATCH',
'-sFile=' + self.filepath, gs_resolution_script])
'-sFile=' + self.file_path, gs_resolution_script])
except CalledProcessError as e:
log.debug(' '.join(e.cmd))
log.debug(e.output)
@ -246,13 +246,13 @@ class PdfDocument(PresentationDocument):
os.makedirs(self.get_temp_folder())
if self.controller.mudrawbin:
runlog = check_output([self.controller.mudrawbin, '-w', str(size.right()), '-h', str(size.bottom()),
'-o', os.path.join(self.get_temp_folder(), 'mainslide%03d.png'), self.filepath])
'-o', os.path.join(self.get_temp_folder(), 'mainslide%03d.png'), self.file_path])
elif self.controller.gsbin:
resolution = self.gs_get_resolution(size)
runlog = check_output([self.controller.gsbin, '-dSAFER', '-dNOPAUSE', '-dBATCH', '-sDEVICE=png16m',
'-r' + str(resolution), '-dTextAlphaBits=4', '-dGraphicsAlphaBits=4',
'-sOutputFile=' + os.path.join(self.get_temp_folder(), 'mainslide%03d.png'),
self.filepath])
self.file_path])
created_files = sorted(os.listdir(self.get_temp_folder()))
for fn in created_files:
if os.path.isfile(os.path.join(self.get_temp_folder(), fn)):

View File

@ -112,6 +112,9 @@ class PowerpointDocument(PresentationDocument):
def __init__(self, controller, presentation):
"""
Constructor, store information about the file and initialise.
:param controller:
:param presentation:
"""
log.debug('Init Presentation Powerpoint')
super(PowerpointDocument, self).__init__(controller, presentation)
@ -126,7 +129,7 @@ class PowerpointDocument(PresentationDocument):
if not self.controller.process or not self.controller.process.Visible:
self.controller.start_process()
try:
self.controller.process.Presentations.Open(self.filepath, False, False, True)
self.controller.process.Presentations.Open(self.file_path, False, False, True)
except pywintypes.com_error:
log.debug('PPT open failed')
return False
@ -275,12 +278,14 @@ class PowerpointDocument(PresentationDocument):
log.debug('get_slide_count')
return self.presentation.Slides.Count
def goto_slide(self, slideno):
def goto_slide(self, slide_no):
"""
Moves to a specific slide in the presentation.
:param slide_no: The slide the text is required for, starting at 1
"""
log.debug('goto_slide')
self.presentation.SlideShowWindow.View.GotoSlide(slideno)
self.presentation.SlideShowWindow.View.GotoSlide(slide_no)
def next_step(self):
"""
@ -302,8 +307,7 @@ class PowerpointDocument(PresentationDocument):
"""
Returns the text on the slide.
``slide_no``
The slide the text is required for, starting at 1.
:param slide_no: The slide the text is required for, starting at 1
"""
return _get_text_from_shapes(self.presentation.Slides(slide_no).Shapes)
@ -311,8 +315,7 @@ class PowerpointDocument(PresentationDocument):
"""
Returns the text on the slide.
``slide_no``
The slide the notes are required for, starting at 1.
:param slide_no: The slide the text is required for, starting at 1
"""
return _get_text_from_shapes(self.presentation.Slides(slide_no).NotesPage.Shapes)
@ -321,8 +324,7 @@ def _get_text_from_shapes(shapes):
"""
Returns any text extracted from the shapes on a presentation slide.
``shapes``
A set of shapes to search for text.
:param shapes: A set of shapes to search for text.
"""
text = ''
for index in range(shapes.Count):

View File

@ -124,7 +124,7 @@ class PptviewDocument(PresentationDocument):
temp_folder = self.get_temp_folder()
size = ScreenList().current['size']
rect = RECT(size.x(), size.y(), size.right(), size.bottom())
file_path = os.path.normpath(self.filepath)
file_path = os.path.normpath(self.file_path)
preview_path = os.path.join(temp_folder, 'slide')
# Ensure that the paths are null terminated
file_path = file_path.encode('utf-16-le') + b'\0'
@ -228,11 +228,13 @@ class PptviewDocument(PresentationDocument):
"""
return self.controller.process.GetSlideCount(self.ppt_id)
def goto_slide(self, slideno):
def goto_slide(self, slide_no):
"""
Moves to a specific slide in the presentation.
:param slide_no: The slide the text is required for, starting at 1
"""
self.controller.process.GotoSlide(self.ppt_id, slideno)
self.controller.process.GotoSlide(self.ppt_id, slide_no)
def next_step(self):
"""

View File

@ -103,8 +103,8 @@ class PresentationDocument(object):
"""
Run some initial setup. This method is separate from __init__ in order to mock it out in tests.
"""
self.slidenumber = 0
self.filepath = name
self.slide_number = 0
self.file_path = name
check_directory_exists(self.get_thumbnail_folder())
def load_presentation(self):
@ -131,7 +131,7 @@ class PresentationDocument(object):
"""
Return just the filename of the presentation, without the directory
"""
return os.path.split(self.filepath)[1]
return os.path.split(self.file_path)[1]
def get_thumbnail_folder(self):
"""
@ -149,10 +149,10 @@ class PresentationDocument(object):
"""
Returns ``True`` if the thumbnail images exist and are more recent than the powerpoint file.
"""
lastimage = self.get_thumbnail_path(self.get_slide_count(), True)
if not (lastimage and os.path.isfile(lastimage)):
last_image = self.get_thumbnail_path(self.get_slide_count(), True)
if not (last_image and os.path.isfile(last_image)):
return False
return validate_thumb(self.filepath, lastimage)
return validate_thumb(self.file_path, last_image)
def close_presentation(self):
"""
@ -253,8 +253,7 @@ class PresentationDocument(object):
``slide_no``
The slide an image is required for, starting at 1
"""
path = os.path.join(self.get_thumbnail_folder(),
self.controller.thumbnail_prefix + str(slide_no) + '.png')
path = os.path.join(self.get_thumbnail_folder(), self.controller.thumbnail_prefix + str(slide_no) + '.png')
if os.path.isfile(path) or not check_exists:
return path
else:
@ -268,21 +267,20 @@ class PresentationDocument(object):
return
if not hide_mode:
current = self.get_slide_number()
if current == self.slidenumber:
if current == self.slide_number:
return
self.slidenumber = current
self.slide_number = current
if is_live:
prefix = 'live'
else:
prefix = 'preview'
Registry().execute('slidecontroller_%s_change' % prefix, self.slidenumber - 1)
Registry().execute('slidecontroller_%s_change' % prefix, self.slide_number - 1)
def get_slide_text(self, slide_no):
"""
Returns the text on the slide
``slide_no``
The slide the text is required for, starting at 1
:param slide_no: The slide the text is required for, starting at 1
"""
return ''
@ -290,8 +288,7 @@ class PresentationDocument(object):
"""
Returns the text on the slide
``slide_no``
The slide the notes are required for, starting at 1
:param slide_no: The slide the text is required for, starting at 1
"""
return ''
@ -350,6 +347,7 @@ class PresentationController(object):
def __init__(self, plugin=None, name='PresentationController', document_class=PresentationDocument):
"""
This is the constructor for the presentationcontroller object. This provides an easy way for descendent plugins
to populate common data. This method *must* be overridden, like so::
class MyPresentationController(PresentationController):
@ -357,11 +355,9 @@ class PresentationController(object):
PresentationController.__init(
self, plugin, u'My Presenter App')
``plugin``
Defaults to *None*. The presentationplugin object
``name``
Name of the application, to appear in the application
:param plugin: Defaults to *None*. The presentationplugin object
:param name: Name of the application, to appear in the application
:param document_class:
"""
self.supports = []
self.also_supports = []

View File

@ -118,7 +118,7 @@ class TestPptviewDocument(TestCase):
self.mock_os.path.isdir.return_value = True
self.mock_controller.process.OpenPPT.return_value = 0
instance = PptviewDocument(self.mock_controller, self.mock_presentation)
instance.filepath = 'test\path.ppt'
instance.file_path = 'test\path.ppt'
if os.name == 'nt':
result = instance.load_presentation()
@ -138,7 +138,7 @@ class TestPptviewDocument(TestCase):
self.mock_os.path.isdir.return_value = False
self.mock_controller.process.OpenPPT.return_value = -1
instance = PptviewDocument(self.mock_controller, self.mock_presentation)
instance.filepath = 'test\path.ppt'
instance.file_path = 'test\path.ppt'
if os.name == 'nt':
result = instance.load_presentation()