mirror of https://gitlab.com/openlp/openlp.git
348 lines
13 KiB
Python
348 lines
13 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
##########################################################################
|
|
# OpenLP - Open Source Lyrics Projection #
|
|
# ---------------------------------------------------------------------- #
|
|
# Copyright (c) 2008-2020 OpenLP Developers #
|
|
# ---------------------------------------------------------------------- #
|
|
# This program is free software: you can redistribute it and/or modify #
|
|
# it under the terms of the GNU General Public License as published by #
|
|
# the Free Software Foundation, either version 3 of the License, or #
|
|
# (at your option) any later version. #
|
|
# #
|
|
# This program is distributed in the hope that it will be useful, #
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
|
# GNU General Public License for more details. #
|
|
# #
|
|
# You should have received a copy of the GNU General Public License #
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
|
##########################################################################
|
|
"""
|
|
This module is for controlling keynote.
|
|
"""
|
|
import logging
|
|
import applescript
|
|
|
|
try:
|
|
import fitz
|
|
PYMUPDF_AVAILABLE = True
|
|
except ImportError:
|
|
PYMUPDF_AVAILABLE = False
|
|
|
|
from openlp.plugins.presentations.lib.applescriptbasecontroller import AppleScriptBaseController,\
|
|
AppleScriptBaseDocument
|
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
POWERPOINT_MAC_APPLESCRIPT = """
|
|
on check_available()
|
|
set appID to "com.microsoft.PowerPoint"
|
|
set doesExist to false
|
|
try
|
|
tell application "Finder" to get application file id appID
|
|
set doesExist to true
|
|
end try
|
|
return doesExist
|
|
end check_available
|
|
|
|
on get_version()
|
|
return (version of application "Microsoft PowerPoint")
|
|
end get_version
|
|
|
|
on start_application()
|
|
tell application "Microsoft PowerPoint"
|
|
launch
|
|
-- Wait for powerpoint to start
|
|
tell application "System Events"
|
|
repeat while true
|
|
set PowerPointUp to (count of (every process whose name is "Microsoft PowerPoint")) > 0
|
|
if PowerPointUp then
|
|
exit repeat
|
|
else
|
|
delay 0.2
|
|
end if
|
|
end repeat
|
|
end tell
|
|
end tell
|
|
end start_application
|
|
|
|
-- helper function to write text to files
|
|
on write_file(fileName, theData)
|
|
set fileDescriptor to open for access the fileName with write permission
|
|
write theData to fileDescriptor as «class utf8»
|
|
close access fileDescriptor
|
|
end write_file
|
|
|
|
-- helper function to create empty file
|
|
on create_empty_file(f)
|
|
write_file(f, "")
|
|
return (POSIX path of f) as POSIX file
|
|
end create_empty_file
|
|
|
|
on create_thumbs(documentName, outputPath)
|
|
tell application "Microsoft PowerPoint"
|
|
-- Open document
|
|
open documentName
|
|
-- wait for document to load
|
|
repeat until document window 1 exists
|
|
delay 0.2
|
|
end repeat
|
|
-- Export slides to jpg
|
|
--save active presentation in outputPath as save as PNG
|
|
-- Export slides to pdf
|
|
save active presentation in my create_empty_file(outputPath & "/tmp.pdf") as save as PDF
|
|
-- Get the Presentation Notes and slide title
|
|
set the slideTitles to ""
|
|
set titleTypes to {placeholder type title placeholder, placeholder type center title placeholder, ¬
|
|
placeholder type vertical title placeholder}
|
|
repeat with tSlide in (get slides of active presentation)
|
|
-- Only handle non-hidden slides
|
|
if hidden of slide show transition of tSlide is false then
|
|
--text = slide.Shapes.Title.TextFrame.TextRange.Text
|
|
-- Get the title of the current slide
|
|
repeat with currentShape in (get shapes of tSlide)
|
|
tell currentShape to if has text frame then tell its text frame to if has text then
|
|
set aType to placeholder type of currentShape
|
|
if aType is not missing value and aType is in titleTypes then
|
|
set slideTitles to slideTitles & (content of its text range) & return
|
|
exit repeat
|
|
end if
|
|
end if
|
|
end repeat
|
|
set the noteText to ""
|
|
repeat with t_shape in (get shapes of notes page of tSlide)
|
|
tell t_shape to if has text frame then tell its text frame to if has text then
|
|
-- get the note of this slide
|
|
set the noteText to (content of its text range)
|
|
exit repeat
|
|
end if
|
|
end repeat
|
|
-- Save note to file
|
|
set noteFilename to outputPath & "/slideNotes" & (slide index of tSlide as string) & ".txt"
|
|
my write_file(noteFilename, noteText)
|
|
end if
|
|
end repeat
|
|
-- Save the titles to file
|
|
set titlesFilename to outputPath & "/titles.txt"
|
|
my write_file(titlesFilename, slideTitles)
|
|
close active presentation
|
|
end tell
|
|
end create_thumbs
|
|
|
|
on close_presentation()
|
|
tell application "Microsoft PowerPoint"
|
|
-- close presentation
|
|
close active presentation
|
|
-- Hide powerpoint
|
|
tell application "System Events"
|
|
set visible of application process "Microsoft PowerPoint" to false
|
|
end tell
|
|
end tell
|
|
end close_presentation
|
|
|
|
on start_presentation(documentName, new_top, new_left_pos, new_width, new_height, fullscreen)
|
|
tell application "Microsoft PowerPoint"
|
|
-- Open document
|
|
open documentName
|
|
-- wait for document to load
|
|
repeat until document window 1 exists
|
|
delay 0.2
|
|
end repeat
|
|
-- disable presenter console
|
|
set showpresenterview of slide show settings of active presentation to 0
|
|
-- set presentation to show presentation in window
|
|
set show type of slide show settings of active presentation to slide show type window
|
|
-- start presentation
|
|
run slide show slide show settings of active presentation
|
|
-- set the size and postion on presentation window
|
|
set top of slide show window of active presentation to new_top
|
|
set left position of slide show window of active presentation to new_left_pos
|
|
if fullscreen is true then
|
|
-- put it in fullscreen mode
|
|
tell application "System Events" to tell process "Microsoft PowerPoint"
|
|
set value of attribute "AXFullScreen" of front window to true
|
|
end tell
|
|
else
|
|
set height of slide show window of active presentation to new_height
|
|
set width of slide show window of active presentation to new_width
|
|
end if
|
|
-- move to the front
|
|
activate
|
|
end tell
|
|
end start_presentation
|
|
|
|
on stop_presentation()
|
|
tell application "Microsoft PowerPoint"
|
|
-- stop presenting - self.presentation.SlideShowWindow.View.Exit()
|
|
exit slide show slide show view of slide show window 1
|
|
-- close presentation
|
|
close active presentation
|
|
-- Hide powerpoint
|
|
tell application "System Events"
|
|
set visible of application process "Microsoft PowerPoint" to false
|
|
end tell
|
|
end tell
|
|
end stop_presentation
|
|
|
|
on is_loaded(documentPath)
|
|
tell application "Microsoft PowerPoint"
|
|
return (full name of active presentation is (documentPath as string))
|
|
end tell
|
|
end is_loaded
|
|
|
|
on is_active()
|
|
tell application "Microsoft PowerPoint"
|
|
-- when the presentation window is out of focus it is paused, so check for both paused and running
|
|
return (slide state of slide show view of slide show window of active presentation is ¬
|
|
slide show state running) ¬
|
|
or (slide state of slide show view of slide show window of active presentation is ¬
|
|
slide show state paused)
|
|
end tell
|
|
end is_active
|
|
|
|
on next_slide()
|
|
tell application "Microsoft PowerPoint"
|
|
--activate
|
|
-- self.presentation.SlideShowWindow.View.Next()
|
|
go to next slide slide show view of slide show window 1
|
|
-- Print(?) slide number
|
|
-- slide number of slide of slideshow view of slide show window of active presentation
|
|
end tell
|
|
end next_slide
|
|
|
|
on previous_slide()
|
|
tell application "Microsoft PowerPoint"
|
|
--activate
|
|
go to previous slide slide show view of slide show window 1
|
|
-- Print(?) slide number
|
|
-- self.presentation.SlideShowWindow.View.Slide.SlideNumber
|
|
-- slide number of slide of view of slide show window of active presentation
|
|
end tell
|
|
end previous_slide
|
|
|
|
on goto_slide(slideNumber)
|
|
tell application "Microsoft PowerPoint"
|
|
activate
|
|
-- self.presentation.SlideShowWindow.View.GotoSlide(slideNumber)
|
|
--go to slide slideNumber of slide show window of active presentation
|
|
-- there seems to be no applescipt-way of going to a specific slide, so send keystroke
|
|
tell application "System Events"
|
|
keystroke (slideNumber as string)
|
|
key code 36
|
|
end tell
|
|
end tell
|
|
end goto_slide
|
|
|
|
on get_current_slide()
|
|
tell application "Microsoft PowerPoint"
|
|
--activate
|
|
-- Print(?) slide number
|
|
return slide number of slide of slide show view of slide show window of active presentation
|
|
end tell
|
|
end get_current_slide
|
|
|
|
on blank()
|
|
tell application "Microsoft PowerPoint"
|
|
--activate
|
|
-- self.presentation.SlideShowWindow.View.State = 3
|
|
--set state of slide of view of slide show window of active presentation to 3
|
|
set slide state of slide show view of slide show window 1 to slide show state black screen
|
|
end tell
|
|
end blank
|
|
|
|
on unblank()
|
|
tell application "Microsoft PowerPoint"
|
|
--activate
|
|
-- self.presentation.SlideShowWindow.View.State = 1
|
|
set slide state of slide show view of slide show window 1 to slide show state running
|
|
end tell
|
|
end unblank
|
|
"""
|
|
|
|
|
|
class PowerPointMacController(AppleScriptBaseController):
|
|
"""
|
|
Class to control interactions with a Powerpoint for Mac.
|
|
As well as triggering the correct activities based on the users input.
|
|
"""
|
|
log.info('PowerPointMacController loaded')
|
|
base_class = False
|
|
|
|
def __init__(self, plugin):
|
|
"""
|
|
Initialise the class
|
|
"""
|
|
log.debug('Initialising')
|
|
super(PowerPointMacController, self).__init__(plugin, 'PowerPointMac', PowerPointMacDocument)
|
|
# Compiled script expected to be set by subclasses
|
|
try:
|
|
self.applescript = applescript.AppleScript(POWERPOINT_MAC_APPLESCRIPT)
|
|
except applescript.ScriptError:
|
|
log.exception('Compilation of Powerpoint applescript failed')
|
|
self.supports = ['ppt', 'pps', 'pptx', 'ppsx', 'pptm']
|
|
self.also_supports = ['odp']
|
|
|
|
def check_available(self):
|
|
"""
|
|
Program is able to run on this machine.
|
|
"""
|
|
ret = super().check_available()
|
|
if ret:
|
|
# Powerpoint is available! now check if the version is 15 (Powerpoint 2016) or above
|
|
try:
|
|
version = self.applescript.call('get_version')
|
|
except Exception:
|
|
log.exception('script execution failed')
|
|
return False
|
|
try:
|
|
major_version = int(version.split('.')[0])
|
|
except ValueError:
|
|
return False
|
|
if major_version >= 15:
|
|
return True
|
|
|
|
|
|
class PowerPointMacDocument(AppleScriptBaseDocument):
|
|
"""
|
|
Class which holds information and controls a single presentation.
|
|
"""
|
|
|
|
def __init__(self, controller, document_path):
|
|
"""
|
|
Constructor, store information about the file and initialise.
|
|
|
|
:param controller:
|
|
:param pathlib.Path document_path: Path to the document to load
|
|
:rtype: None
|
|
"""
|
|
log.debug('Init Presentation Applescript')
|
|
super().__init__(controller, document_path)
|
|
self.presentation_loaded = False
|
|
self.is_blank = False
|
|
|
|
def load_presentation(self):
|
|
ret = super().load_presentation()
|
|
if ret:
|
|
# we make powerpoint export to PDF and then convert the pdf to thumbnails
|
|
if PYMUPDF_AVAILABLE:
|
|
pdf_file = self.get_thumbnail_folder() / 'tmp.pdf'
|
|
# if the pdf file does not exists anymore it is assume the convertion has been done
|
|
if not pdf_file.exists():
|
|
return True
|
|
log.debug('converting pdf to png thumbnails using PyMuPDF')
|
|
pdf = fitz.open(str(pdf_file))
|
|
for i, page in enumerate(pdf, start=1):
|
|
src_size = page.bound().round()
|
|
# keep aspect ratio
|
|
scale = min(640 / src_size.width, 480 / src_size.height)
|
|
m = fitz.Matrix(scale, scale)
|
|
page.getPixmap(m, alpha=False).writeImage(str(self.get_thumbnail_folder() /
|
|
'slide{num}.png'.format(num=i)))
|
|
pdf.close()
|
|
# delete pdf
|
|
pdf_file.unlink()
|
|
return ret
|