forked from openlp/openlp
Head
This commit is contained in:
commit
a071dcc879
@ -199,15 +199,13 @@ def resize_image(image, width, height, background=QtCore.Qt.black):
|
||||
"""
|
||||
preview = QtGui.QImage(image)
|
||||
if not preview.isNull():
|
||||
#Only resize if different size
|
||||
if preview.width() == width and preview.height == height:
|
||||
return preview
|
||||
preview = preview.scaled(width, height, QtCore.Qt.KeepAspectRatio,
|
||||
QtCore.Qt.SmoothTransformation)
|
||||
realw = preview.width()
|
||||
realh = preview.height()
|
||||
#Only resize if different size
|
||||
print realw, realh, width, height
|
||||
if realw == width and realh == height:
|
||||
return image
|
||||
print "different"
|
||||
# and move it to the centre of the preview space
|
||||
new_image = QtGui.QImage(width, height,
|
||||
QtGui.QImage.Format_ARGB32_Premultiplied)
|
||||
|
@ -379,14 +379,17 @@ class MediaManagerItem(QtGui.QWidget):
|
||||
"""
|
||||
Validates to see if the file still exists or thumbnail is up to date
|
||||
"""
|
||||
if os.path.exists(file):
|
||||
if not os.path.exists(file):
|
||||
return False
|
||||
if os.path.exists(thumb):
|
||||
filedate = os.stat(file).st_mtime
|
||||
thumbdate = os.stat(thumb).st_mtime
|
||||
#if file updated rebuild icon
|
||||
if filedate > thumbdate:
|
||||
self.iconFromFile(file, thumb)
|
||||
else:
|
||||
self.iconFromFile(file, thumb)
|
||||
return True
|
||||
return False
|
||||
|
||||
def iconFromFile(self, file, thumb):
|
||||
"""
|
||||
|
@ -37,8 +37,6 @@ import logging
|
||||
import os
|
||||
import time
|
||||
|
||||
from openlp.core.lib import resize_image
|
||||
|
||||
if os.name == u'nt':
|
||||
from win32com.client import Dispatch
|
||||
import pywintypes
|
||||
@ -74,6 +72,7 @@ class ImpressController(PresentationController):
|
||||
self.alsosupports = [u'.ppt', u'.pps', u'.pptx', u'.ppsx']
|
||||
self.process = None
|
||||
self.desktop = None
|
||||
self.manager = None
|
||||
|
||||
def check_available(self):
|
||||
"""
|
||||
@ -104,6 +103,10 @@ class ImpressController(PresentationController):
|
||||
self.process.waitForStarted()
|
||||
|
||||
def get_uno_desktop(self):
|
||||
"""
|
||||
On non-Windows platforms, use Uno. Get the OpenOffice desktop
|
||||
which will be used to manage impress
|
||||
"""
|
||||
log.debug(u'get UNO Desktop Openoffice')
|
||||
ctx = None
|
||||
loop = 0
|
||||
@ -134,10 +137,19 @@ class ImpressController(PresentationController):
|
||||
return None
|
||||
|
||||
def get_com_desktop(self):
|
||||
"""
|
||||
On Windows platforms, use COM. Return the desktop object which
|
||||
will be used to manage Impress
|
||||
"""
|
||||
log.debug(u'get COM Desktop OpenOffice')
|
||||
if not self.manager:
|
||||
return None
|
||||
return self.manager.createInstance(u'com.sun.star.frame.Desktop')
|
||||
|
||||
def get_com_servicemanager(self):
|
||||
"""
|
||||
Return the OOo service manager for windows
|
||||
"""
|
||||
log.debug(u'get_com_servicemanager openoffice')
|
||||
try:
|
||||
return Dispatch(u'com.sun.star.ServiceManager')
|
||||
@ -171,13 +183,23 @@ class ImpressController(PresentationController):
|
||||
log.exception(u'Failed to terminate OpenOffice')
|
||||
|
||||
def add_doc(self, name):
|
||||
"""
|
||||
Called when a new Impress document is opened
|
||||
"""
|
||||
log.debug(u'Add Doc OpenOffice')
|
||||
doc = ImpressDocument(self, name)
|
||||
self.docs.append(doc)
|
||||
return doc
|
||||
|
||||
class ImpressDocument(PresentationDocument):
|
||||
"""
|
||||
Class which holds information and controls a single presentation
|
||||
"""
|
||||
|
||||
def __init__(self, controller, presentation):
|
||||
"""
|
||||
Constructor, store information about the file and initialise
|
||||
"""
|
||||
log.debug(u'Init Presentation OpenOffice')
|
||||
PresentationDocument.__init__(self, controller, presentation)
|
||||
self.document = None
|
||||
@ -208,9 +230,8 @@ class ImpressDocument(PresentationDocument):
|
||||
desktop = self.controller.get_uno_desktop()
|
||||
url = uno.systemPathToFileUrl(self.filepath)
|
||||
if desktop is None:
|
||||
return
|
||||
return False
|
||||
self.desktop = desktop
|
||||
#print "s.dsk2 ", self.desktop
|
||||
properties = []
|
||||
properties.append(self.create_property(u'Minimized', True))
|
||||
properties = tuple(properties)
|
||||
@ -219,12 +240,13 @@ class ImpressDocument(PresentationDocument):
|
||||
0, properties)
|
||||
except:
|
||||
log.exception(u'Failed to load presentation')
|
||||
return
|
||||
return False
|
||||
self.presentation = self.document.getPresentation()
|
||||
self.presentation.Display = \
|
||||
self.controller.plugin.renderManager.screens.current_display + 1
|
||||
self.control = None
|
||||
self.create_thumbnails()
|
||||
return True
|
||||
|
||||
def create_thumbnails(self):
|
||||
"""
|
||||
@ -234,30 +256,36 @@ class ImpressDocument(PresentationDocument):
|
||||
if self.check_thumbnails():
|
||||
return
|
||||
if os.name == u'nt':
|
||||
thumbdir = u'file:///' + self.thumbnailpath.replace(
|
||||
thumbdirurl = u'file:///' + self.get_temp_folder().replace(
|
||||
u'\\', u'/').replace(u':', u'|').replace(u' ', u'%20')
|
||||
else:
|
||||
thumbdir = uno.systemPathToFileUrl(self.thumbnailpath)
|
||||
thumbdirurl = uno.systemPathToFileUrl(self.get_temp_folder())
|
||||
props = []
|
||||
props.append(self.create_property(u'FilterName', u'impress_png_Export'))
|
||||
props = tuple(props)
|
||||
doc = self.document
|
||||
pages = doc.getDrawPages()
|
||||
if not os.path.isdir(self.get_temp_folder()):
|
||||
os.makedirs(self.get_temp_folder())
|
||||
for idx in range(pages.getCount()):
|
||||
page = pages.getByIndex(idx)
|
||||
doc.getCurrentController().setCurrentPage(page)
|
||||
path = u'%s/%s%s.png' % (thumbdir, self.controller.thumbnailprefix,
|
||||
unicode(idx + 1))
|
||||
urlpath = u'%s/%s.png' % (thumbdirurl, unicode(idx + 1))
|
||||
path = os.path.join(self.get_temp_folder(),
|
||||
unicode(idx + 1) + u'.png')
|
||||
try:
|
||||
doc.storeToURL(path , props)
|
||||
preview = resize_image(path, 640, 480)
|
||||
doc.storeToURL(urlpath, props)
|
||||
self.convert_thumbnail(path, idx + 1)
|
||||
if os.path.exists(path):
|
||||
os.remove(path)
|
||||
preview.save(path, u'png')
|
||||
except:
|
||||
log.exception(u'%s - Unable to store openoffice preview' % path)
|
||||
|
||||
def create_property(self, name, value):
|
||||
"""
|
||||
Create an OOo style property object which are passed into some
|
||||
Uno methods
|
||||
"""
|
||||
log.debug(u'create property OpenOffice')
|
||||
if os.name == u'nt':
|
||||
prop = self.controller.manager.\
|
||||
@ -288,6 +316,9 @@ class ImpressDocument(PresentationDocument):
|
||||
self.controller.remove_doc(self)
|
||||
|
||||
def is_loaded(self):
|
||||
"""
|
||||
Returns true if a presentation is loaded
|
||||
"""
|
||||
log.debug(u'is loaded OpenOffice')
|
||||
#print "is_loaded "
|
||||
if self.presentation is None or self.document is None:
|
||||
@ -302,6 +333,9 @@ class ImpressDocument(PresentationDocument):
|
||||
return True
|
||||
|
||||
def is_active(self):
|
||||
"""
|
||||
Returns true if a presentation is active and running
|
||||
"""
|
||||
log.debug(u'is active OpenOffice')
|
||||
#print "is_active "
|
||||
if not self.is_loaded():
|
||||
@ -313,10 +347,16 @@ class ImpressDocument(PresentationDocument):
|
||||
return True
|
||||
|
||||
def unblank_screen(self):
|
||||
"""
|
||||
Unblanks the screen
|
||||
"""
|
||||
log.debug(u'unblank screen OpenOffice')
|
||||
return self.control.resume()
|
||||
|
||||
def blank_screen(self):
|
||||
"""
|
||||
Blanks the screen
|
||||
"""
|
||||
log.debug(u'blank screen OpenOffice')
|
||||
self.control.blankScreen(0)
|
||||
|
||||
@ -331,6 +371,9 @@ class ImpressDocument(PresentationDocument):
|
||||
return False
|
||||
|
||||
def stop_presentation(self):
|
||||
"""
|
||||
Stop the presentation, remove from screen
|
||||
"""
|
||||
log.debug(u'stop presentation OpenOffice')
|
||||
# deactivate should hide the screen according to docs, but doesn't
|
||||
#self.control.deactivate()
|
||||
@ -338,6 +381,9 @@ class ImpressDocument(PresentationDocument):
|
||||
self.control = None
|
||||
|
||||
def start_presentation(self):
|
||||
"""
|
||||
Start the presentation from the beginning
|
||||
"""
|
||||
log.debug(u'start presentation OpenOffice')
|
||||
if self.control is None or not self.control.isRunning():
|
||||
self.presentation.start()
|
||||
@ -354,12 +400,21 @@ class ImpressDocument(PresentationDocument):
|
||||
self.goto_slide(1)
|
||||
|
||||
def get_slide_number(self):
|
||||
"""
|
||||
Return the current slide number on the screen, from 1
|
||||
"""
|
||||
return self.control.getCurrentSlideIndex() + 1
|
||||
|
||||
def get_slide_count(self):
|
||||
"""
|
||||
Return the total number of slides
|
||||
"""
|
||||
return self.document.getDrawPages().getCount()
|
||||
|
||||
def goto_slide(self, slideno):
|
||||
"""
|
||||
Go to a specific slide (from 1)
|
||||
"""
|
||||
self.control.gotoSlideIndex(slideno-1)
|
||||
|
||||
def next_step(self):
|
||||
|
@ -30,14 +30,17 @@ from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.lib import MediaManagerItem, BaseListWithDnD, build_icon, \
|
||||
SettingsManager, translate, check_item_selected
|
||||
from openlp.core.utils import AppLocation
|
||||
from openlp.plugins.presentations.lib import MessageListener
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# We have to explicitly create separate classes for each plugin
|
||||
# in order for DnD to the Service manager to work correctly.
|
||||
class PresentationListView(BaseListWithDnD):
|
||||
"""
|
||||
Class for the list of Presentations
|
||||
|
||||
We have to explicitly create separate classes for each plugin
|
||||
in order for DnD to the Service manager to work correctly.
|
||||
"""
|
||||
def __init__(self, parent=None):
|
||||
self.PluginName = u'Presentations'
|
||||
BaseListWithDnD.__init__(self, parent)
|
||||
@ -45,11 +48,14 @@ class PresentationListView(BaseListWithDnD):
|
||||
class PresentationMediaItem(MediaManagerItem):
|
||||
"""
|
||||
This is the Presentation media manager item for Presentation Items.
|
||||
It can present files using Openoffice
|
||||
It can present files using Openoffice and Powerpoint
|
||||
"""
|
||||
log.info(u'Presentations Media Item loaded')
|
||||
|
||||
def __init__(self, parent, icon, title, controllers):
|
||||
"""
|
||||
Constructor. Setup defaults
|
||||
"""
|
||||
self.controllers = controllers
|
||||
self.PluginNameShort = u'Presentation'
|
||||
self.pluginNameVisible = translate('PresentationPlugin.MediaItem',
|
||||
@ -63,6 +69,9 @@ class PresentationMediaItem(MediaManagerItem):
|
||||
self.message_listener = MessageListener(self)
|
||||
|
||||
def retranslateUi(self):
|
||||
"""
|
||||
The name of the plugin media displayed in UI
|
||||
"""
|
||||
self.OnNewPrompt = translate('PresentationPlugin.MediaItem',
|
||||
'Select Presentation(s)')
|
||||
self.Automatic = translate('PresentationPlugin.MediaItem',
|
||||
@ -80,12 +89,18 @@ class PresentationMediaItem(MediaManagerItem):
|
||||
'Presentations (%s)' % fileType)
|
||||
|
||||
def requiredIcons(self):
|
||||
"""
|
||||
Set which icons the media manager tab should show
|
||||
"""
|
||||
MediaManagerItem.requiredIcons(self)
|
||||
self.hasFileIcon = True
|
||||
self.hasNewIcon = False
|
||||
self.hasEditIcon = False
|
||||
|
||||
def addEndHeaderBar(self):
|
||||
"""
|
||||
Display custom media manager items for presentations
|
||||
"""
|
||||
self.PresentationWidget = QtGui.QWidget(self)
|
||||
sizePolicy = QtGui.QSizePolicy(
|
||||
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
|
||||
@ -109,15 +124,13 @@ class PresentationMediaItem(MediaManagerItem):
|
||||
self.pageLayout.addWidget(self.PresentationWidget)
|
||||
|
||||
def initialise(self):
|
||||
self.servicePath = os.path.join(
|
||||
AppLocation.get_section_data_path(self.settingsSection),
|
||||
u'thumbnails')
|
||||
"""
|
||||
Populate the media manager tab
|
||||
"""
|
||||
self.listView.setIconSize(QtCore.QSize(88, 50))
|
||||
if not os.path.exists(self.servicePath):
|
||||
os.mkdir(self.servicePath)
|
||||
list = SettingsManager.load_list(
|
||||
self.settingsSection, u'presentations')
|
||||
self.loadList(list)
|
||||
self.loadList(list, True)
|
||||
for item in self.controllers:
|
||||
#load the drop down selection
|
||||
if self.controllers[item].enabled:
|
||||
@ -126,7 +139,12 @@ class PresentationMediaItem(MediaManagerItem):
|
||||
self.DisplayTypeComboBox.insertItem(0, self.Automatic)
|
||||
self.DisplayTypeComboBox.setCurrentIndex(0)
|
||||
|
||||
def loadList(self, list):
|
||||
def loadList(self, list, initialLoad=False):
|
||||
"""
|
||||
Add presentations into the media manager
|
||||
This is called both on initial load of the plugin to populate with
|
||||
existing files, and when the user adds new files via the media manager
|
||||
"""
|
||||
currlist = self.getFileList()
|
||||
titles = []
|
||||
for file in currlist:
|
||||
@ -136,36 +154,39 @@ class PresentationMediaItem(MediaManagerItem):
|
||||
continue
|
||||
filename = os.path.split(unicode(file))[1]
|
||||
if titles.count(filename) > 0:
|
||||
if not initialLoad:
|
||||
QtGui.QMessageBox.critical(
|
||||
self, translate('PresentationPlugin.MediaItem',
|
||||
'File exists'),
|
||||
translate('PresentationPlugin.MediaItem',
|
||||
'A presentation with that filename already exists.'),
|
||||
QtGui.QMessageBox.Ok)
|
||||
else:
|
||||
icon = None
|
||||
for controller in self.controllers:
|
||||
thumbPath = os.path.join(
|
||||
AppLocation.get_section_data_path(
|
||||
self.settingsSection),
|
||||
u'thumbnails', controller, filename)
|
||||
thumb = os.path.join(thumbPath, u'slide1.png')
|
||||
preview = os.path.join(
|
||||
AppLocation.get_section_data_path(
|
||||
self.settingsSection),
|
||||
controller, u'thumbnails', filename, u'slide1.png')
|
||||
if os.path.exists(preview):
|
||||
if os.path.exists(thumb):
|
||||
if self.validate(preview, thumb):
|
||||
continue
|
||||
controller_name = self.findControllerByType(filename)
|
||||
if controller_name:
|
||||
controller = self.controllers[controller_name]
|
||||
doc = controller.add_doc(unicode(file))
|
||||
thumb = os.path.join(doc.get_thumbnail_folder(), u'icon.png')
|
||||
preview = doc.get_thumbnail_path(1, True)
|
||||
if not preview and not initialLoad:
|
||||
doc.load_presentation()
|
||||
preview = doc.get_thumbnail_path(1, True)
|
||||
doc.close_presentation()
|
||||
if preview and self.validate(preview, thumb):
|
||||
icon = build_icon(thumb)
|
||||
else:
|
||||
icon = build_icon(
|
||||
u':/general/general_delete.png')
|
||||
else:
|
||||
os.makedirs(thumbPath)
|
||||
icon = self.iconFromFile(preview, thumb)
|
||||
if not icon:
|
||||
icon = build_icon(u':/general/general_delete.png')
|
||||
else:
|
||||
if initialLoad:
|
||||
icon = build_icon(u':/general/general_delete.png')
|
||||
else:
|
||||
QtGui.QMessageBox.critical(
|
||||
self, translate('PresentationPlugin.MediaItem',
|
||||
'Unsupported file'),
|
||||
translate('PresentationPlugin.MediaItem',
|
||||
'This type of presentation is not supported'),
|
||||
QtGui.QMessageBox.Ok)
|
||||
continue
|
||||
item_name = QtGui.QListWidgetItem(filename)
|
||||
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
|
||||
item_name.setIcon(icon)
|
||||
@ -184,8 +205,6 @@ class PresentationMediaItem(MediaManagerItem):
|
||||
for item in items:
|
||||
filepath = unicode(item.data(
|
||||
QtCore.Qt.UserRole).toString())
|
||||
#not sure of this has errors
|
||||
#John please can you look at .
|
||||
for cidx in self.controllers:
|
||||
doc = self.controllers[cidx].add_doc(filepath)
|
||||
doc.presentation_deleted()
|
||||
@ -196,6 +215,11 @@ class PresentationMediaItem(MediaManagerItem):
|
||||
self.settingsSection, self.getFileList())
|
||||
|
||||
def generateSlideData(self, service_item, item=None):
|
||||
"""
|
||||
Load the relevant information for displaying the presentation
|
||||
in the slidecontroller. In the case of powerpoints, an image
|
||||
for each slide
|
||||
"""
|
||||
items = self.listView.selectedIndexes()
|
||||
if len(items) > 1:
|
||||
return False
|
||||
@ -213,20 +237,27 @@ class PresentationMediaItem(MediaManagerItem):
|
||||
controller = self.controllers[service_item.shortname]
|
||||
(path, name) = os.path.split(filename)
|
||||
doc = controller.add_doc(filename)
|
||||
if doc.get_slide_preview_file(1) is None:
|
||||
if doc.get_thumbnail_path(1, True) is None:
|
||||
doc.load_presentation()
|
||||
i = 1
|
||||
img = doc.get_slide_preview_file(i)
|
||||
img = doc.get_thumbnail_path(i, True)
|
||||
while img:
|
||||
service_item.add_from_command(path, name, img)
|
||||
i = i + 1
|
||||
img = doc.get_slide_preview_file(i)
|
||||
img = doc.get_thumbnail_path(i, True)
|
||||
doc.close_presentation()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def findControllerByType(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 "alsosupports" it instead.
|
||||
"""
|
||||
filetype = os.path.splitext(filename)[1]
|
||||
if not filetype:
|
||||
return None
|
||||
|
@ -41,17 +41,28 @@ class Controller(object):
|
||||
log.info(u'Controller loaded')
|
||||
|
||||
def __init__(self, live):
|
||||
"""
|
||||
Constructor
|
||||
"""
|
||||
self.is_live = live
|
||||
self.doc = None
|
||||
log.info(u'%s controller loaded' % live)
|
||||
|
||||
def add_handler(self, controller, file, is_blank):
|
||||
"""
|
||||
Add a handler, which is an instance of a presentation and
|
||||
slidecontroller combination. If the slidecontroller has a display
|
||||
then load the presentation.
|
||||
"""
|
||||
log.debug(u'Live = %s, add_handler %s' % (self.is_live, file))
|
||||
self.controller = controller
|
||||
if self.doc is not None:
|
||||
self.shutdown()
|
||||
self.doc = self.controller.add_doc(file)
|
||||
self.doc.load_presentation()
|
||||
if not self.doc.load_presentation():
|
||||
# Display error message to user
|
||||
# Inform slidecontroller that the action failed?
|
||||
return
|
||||
if self.is_live:
|
||||
self.doc.start_presentation()
|
||||
if is_blank:
|
||||
@ -60,6 +71,10 @@ class Controller(object):
|
||||
self.doc.slidenumber = 0
|
||||
|
||||
def activate(self):
|
||||
"""
|
||||
Active the presentation, and show it on the screen.
|
||||
Use the last slide number.
|
||||
"""
|
||||
log.debug(u'Live = %s, activate' % self.is_live)
|
||||
if self.doc.is_active():
|
||||
return
|
||||
@ -71,6 +86,9 @@ class Controller(object):
|
||||
self.doc.goto_slide(self.doc.slidenumber)
|
||||
|
||||
def slide(self, slide):
|
||||
"""
|
||||
Go to a specific slide
|
||||
"""
|
||||
log.debug(u'Live = %s, slide' % self.is_live)
|
||||
if not self.is_live:
|
||||
return
|
||||
@ -152,6 +170,9 @@ class Controller(object):
|
||||
#self.timer.stop()
|
||||
|
||||
def blank(self):
|
||||
"""
|
||||
Instruct the controller to blank the presentation
|
||||
"""
|
||||
log.debug(u'Live = %s, blank' % self.is_live)
|
||||
if not self.is_live:
|
||||
return
|
||||
@ -162,6 +183,9 @@ class Controller(object):
|
||||
self.doc.blank_screen()
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
Instruct the controller to stop and hide the presentation
|
||||
"""
|
||||
log.debug(u'Live = %s, stop' % self.is_live)
|
||||
if not self.is_live:
|
||||
return
|
||||
@ -172,6 +196,9 @@ class Controller(object):
|
||||
self.doc.stop_presentation()
|
||||
|
||||
def unblank(self):
|
||||
"""
|
||||
Instruct the controller to unblank the presentation
|
||||
"""
|
||||
log.debug(u'Live = %s, unblank' % self.is_live)
|
||||
if not self.is_live:
|
||||
return
|
||||
@ -246,6 +273,9 @@ class MessageListener(object):
|
||||
controller.add_handler(self.controllers[self.handler], file, is_blank)
|
||||
|
||||
def slide(self, message):
|
||||
"""
|
||||
React to the message to move to a specific slide
|
||||
"""
|
||||
is_live = message[1]
|
||||
slide = message[2]
|
||||
if is_live:
|
||||
@ -254,6 +284,9 @@ class MessageListener(object):
|
||||
self.preview_handler.slide(slide)
|
||||
|
||||
def first(self, message):
|
||||
"""
|
||||
React to the message to move to the first slide
|
||||
"""
|
||||
is_live = message[1]
|
||||
if is_live:
|
||||
self.live_handler.first()
|
||||
@ -261,6 +294,9 @@ class MessageListener(object):
|
||||
self.preview_handler.first()
|
||||
|
||||
def last(self, message):
|
||||
"""
|
||||
React to the message to move to the last slide
|
||||
"""
|
||||
is_live = message[1]
|
||||
if is_live:
|
||||
self.live_handler.last()
|
||||
@ -268,6 +304,9 @@ class MessageListener(object):
|
||||
self.preview_handler.last()
|
||||
|
||||
def next(self, message):
|
||||
"""
|
||||
React to the message to move to the next animation/slide
|
||||
"""
|
||||
is_live = message[1]
|
||||
if is_live:
|
||||
self.live_handler.next()
|
||||
@ -275,6 +314,9 @@ class MessageListener(object):
|
||||
self.preview_handler.next()
|
||||
|
||||
def previous(self, message):
|
||||
"""
|
||||
React to the message to move to the previous animation/slide
|
||||
"""
|
||||
is_live = message[1]
|
||||
if is_live:
|
||||
self.live_handler.previous()
|
||||
@ -282,6 +324,10 @@ class MessageListener(object):
|
||||
self.preview_handler.previous()
|
||||
|
||||
def shutdown(self, message):
|
||||
"""
|
||||
React to message to shutdown the presentation. I.e. end the show
|
||||
and close the file
|
||||
"""
|
||||
is_live = message[1]
|
||||
if is_live:
|
||||
Receiver.send_message(u'maindisplay_show')
|
||||
@ -290,19 +336,34 @@ class MessageListener(object):
|
||||
self.preview_handler.shutdown()
|
||||
|
||||
def hide(self, message):
|
||||
"""
|
||||
React to the message to show the desktop
|
||||
"""
|
||||
is_live = message[1]
|
||||
if is_live:
|
||||
self.live_handler.stop()
|
||||
|
||||
def blank(self, message):
|
||||
"""
|
||||
React to the message to blank the display
|
||||
"""
|
||||
is_live = message[1]
|
||||
if is_live:
|
||||
self.live_handler.blank()
|
||||
|
||||
def unblank(self, message):
|
||||
"""
|
||||
React to the message to unblank the display
|
||||
"""
|
||||
is_live = message[1]
|
||||
if is_live:
|
||||
self.live_handler.unblank()
|
||||
|
||||
def timeout(self):
|
||||
"""
|
||||
The presentation may be timed or might be controlled by the
|
||||
application directly, rather than through OpenLP. Poll occassionally
|
||||
to check which slide is currently displayed so the slidecontroller
|
||||
view can be updated
|
||||
"""
|
||||
self.live_handler.poll()
|
||||
|
@ -97,13 +97,23 @@ class PowerpointController(PresentationController):
|
||||
self.process = None
|
||||
|
||||
def add_doc(self, name):
|
||||
"""
|
||||
Called when a new powerpoint document is opened
|
||||
"""
|
||||
log.debug(u'Add Doc PowerPoint')
|
||||
doc = PowerpointDocument(self, name)
|
||||
self.docs.append(doc)
|
||||
return doc
|
||||
|
||||
class PowerpointDocument(PresentationDocument):
|
||||
"""
|
||||
Class which holds information and controls a single presentation
|
||||
"""
|
||||
|
||||
def __init__(self, controller, presentation):
|
||||
"""
|
||||
Constructor, store information about the file and initialise
|
||||
"""
|
||||
log.debug(u'Init Presentation Powerpoint')
|
||||
PresentationDocument.__init__(self, controller, presentation)
|
||||
self.presentation = None
|
||||
@ -111,22 +121,23 @@ class PowerpointDocument(PresentationDocument):
|
||||
def load_presentation(self):
|
||||
"""
|
||||
Called when a presentation is added to the SlideController.
|
||||
It builds the environment, starts communcations with the background
|
||||
OpenOffice task started earlier. If OpenOffice is not present is is
|
||||
started. Once the environment is available the presentation is loaded
|
||||
and started.
|
||||
Opens the PowerPoint file using the process created earlier
|
||||
|
||||
``presentation``
|
||||
The file name of the presentations to run.
|
||||
"""
|
||||
log.debug(u'LoadPresentation')
|
||||
if not self.controller.process.Visible:
|
||||
if not self.controller.process or not self.controller.process.Visible:
|
||||
self.controller.start_process()
|
||||
self.controller.process.Presentations.Open(self.filepath, False, False,
|
||||
True)
|
||||
try:
|
||||
self.controller.process.Presentations.Open(self.filepath, False,
|
||||
False, True)
|
||||
except pywintypes.com_error:
|
||||
return False
|
||||
self.presentation = self.controller.process.Presentations(
|
||||
self.controller.process.Presentations.Count)
|
||||
self.create_thumbnails()
|
||||
return True
|
||||
|
||||
def create_thumbnails(self):
|
||||
"""
|
||||
@ -139,8 +150,8 @@ class PowerpointDocument(PresentationDocument):
|
||||
"""
|
||||
if self.check_thumbnails():
|
||||
return
|
||||
self.presentation.Export(os.path.join(self.thumbnailpath, ''), 'png',
|
||||
320, 240)
|
||||
self.presentation.Export(os.path.join(self.get_thumbnail_folder(), ''),
|
||||
'png', 320, 240)
|
||||
|
||||
def close_presentation(self):
|
||||
"""
|
||||
|
@ -93,13 +93,22 @@ class PptviewController(PresentationController):
|
||||
self.docs[0].close_presentation()
|
||||
|
||||
def add_doc(self, name):
|
||||
"""
|
||||
Called when a new powerpoint document is opened
|
||||
"""
|
||||
log.debug(u'Add Doc PPTView')
|
||||
doc = PptviewDocument(self, name)
|
||||
self.docs.append(doc)
|
||||
return doc
|
||||
|
||||
class PptviewDocument(PresentationDocument):
|
||||
"""
|
||||
Class which holds information and controls a single presentation
|
||||
"""
|
||||
def __init__(self, controller, presentation):
|
||||
"""
|
||||
Constructor, store information about the file and initialise
|
||||
"""
|
||||
log.debug(u'Init Presentation PowerPoint')
|
||||
PresentationDocument.__init__(self, controller, presentation)
|
||||
self.presentation = None
|
||||
@ -117,17 +126,31 @@ class PptviewDocument(PresentationDocument):
|
||||
The file name of the presentations to run.
|
||||
"""
|
||||
log.debug(u'LoadPresentation')
|
||||
#if self.pptid >= 0:
|
||||
# self.close_presentation()
|
||||
rendermanager = self.controller.plugin.renderManager
|
||||
rect = rendermanager.screens.current[u'size']
|
||||
rect = RECT(rect.x(), rect.y(), rect.right(), rect.bottom())
|
||||
filepath = str(self.filepath.replace(u'/', u'\\'))
|
||||
if not os.path.isdir(self.get_temp_folder()):
|
||||
os.makedirs(self.get_temp_folder())
|
||||
self.pptid = self.controller.process.OpenPPT(filepath, None, rect,
|
||||
str(os.path.join(self.thumbnailpath,
|
||||
self.controller.thumbnailprefix)))
|
||||
if self.pptid:
|
||||
str(self.get_temp_folder()) + '\\slide')
|
||||
if self.pptid >= 0:
|
||||
self.create_thumbnails()
|
||||
self.stop_presentation()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def create_thumbnails(self):
|
||||
"""
|
||||
PPTviewLib creates large BMP's, but we want small PNG's for consistency.
|
||||
Convert them here.
|
||||
"""
|
||||
if self.check_thumbnails():
|
||||
return
|
||||
for idx in range(self.get_slide_count()):
|
||||
path = u'%s\\slide%s.bmp' % (self.get_temp_folder(), unicode(idx + 1))
|
||||
self.convert_thumbnail(path, idx + 1)
|
||||
|
||||
def close_presentation(self):
|
||||
"""
|
||||
@ -224,17 +247,3 @@ class PptviewDocument(PresentationDocument):
|
||||
"""
|
||||
self.controller.process.PrevStep(self.pptid)
|
||||
|
||||
def get_slide_preview_file(self, slide_no):
|
||||
"""
|
||||
Returns an image path containing a preview for the requested slide
|
||||
|
||||
``slide_no``
|
||||
The slide an image is required for, starting at 1
|
||||
"""
|
||||
path = os.path.join(self.thumbnailpath,
|
||||
self.controller.thumbnailprefix + unicode(slide_no) + u'.bmp')
|
||||
if os.path.isfile(path):
|
||||
return path
|
||||
else:
|
||||
return None
|
||||
|
||||
|
@ -29,7 +29,7 @@ import shutil
|
||||
|
||||
from PyQt4 import QtCore
|
||||
|
||||
from openlp.core.lib import Receiver
|
||||
from openlp.core.lib import Receiver, resize_image
|
||||
from openlp.core.utils import AppLocation
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -63,6 +63,13 @@ class PresentationController(object):
|
||||
``plugin``
|
||||
The presentationplugin object
|
||||
|
||||
``supports``
|
||||
The primary native file types this application supports
|
||||
|
||||
``alsosupports``
|
||||
Other file types the application can import, although not necessarily
|
||||
the first choice due to potential incompatibilities
|
||||
|
||||
**Hook Functions**
|
||||
|
||||
``kill()``
|
||||
@ -109,12 +116,16 @@ class PresentationController(object):
|
||||
QtCore.Qt.Checked
|
||||
else:
|
||||
self.enabled = False
|
||||
self.thumbnailroot = os.path.join(
|
||||
self.temp_folder = os.path.join(
|
||||
AppLocation.get_section_data_path(self.settings_section), name)
|
||||
self.thumbnail_folder = os.path.join(
|
||||
AppLocation.get_section_data_path(self.settings_section),
|
||||
name, u'thumbnails')
|
||||
self.thumbnailprefix = u'slide'
|
||||
if not os.path.isdir(self.thumbnailroot):
|
||||
os.makedirs(self.thumbnailroot)
|
||||
u'thumbnails')
|
||||
self.thumbnail_prefix = u'slide'
|
||||
if not os.path.isdir(self.thumbnail_folder):
|
||||
os.makedirs(self.thumbnail_folder)
|
||||
if not os.path.isdir(self.temp_folder):
|
||||
os.makedirs(self.temp_folder)
|
||||
|
||||
def check_available(self):
|
||||
"""
|
||||
@ -208,14 +219,19 @@ class PresentationDocument(object):
|
||||
``previous_step()``
|
||||
Triggers the previous slide on the running presentation
|
||||
|
||||
``get_slide_preview_file(slide_no)``
|
||||
``get_thumbnail_path(slide_no, check_exists)``
|
||||
Returns a path to an image containing a preview for the requested slide
|
||||
|
||||
"""
|
||||
def __init__(self, controller, name):
|
||||
"""
|
||||
Constructor for the PresentationController class
|
||||
"""
|
||||
self.slidenumber = 0
|
||||
self.controller = controller
|
||||
self.store_filename(name)
|
||||
self.filepath = name
|
||||
if not os.path.isdir(self.get_thumbnail_folder()):
|
||||
os.mkdir(self.get_thumbnail_folder())
|
||||
|
||||
def load_presentation(self):
|
||||
"""
|
||||
@ -225,8 +241,9 @@ class PresentationDocument(object):
|
||||
``presentation``
|
||||
The file name of the presentations to the run.
|
||||
|
||||
Returns False if the file could not be opened
|
||||
"""
|
||||
pass
|
||||
return False
|
||||
|
||||
def presentation_deleted(self):
|
||||
"""
|
||||
@ -234,33 +251,37 @@ class PresentationDocument(object):
|
||||
a file, e.g. thumbnails
|
||||
"""
|
||||
try:
|
||||
shutil.rmtree(self.thumbnailpath)
|
||||
shutil.rmtree(self.get_thumbnail_folder())
|
||||
shutil.rmtree(self.get_temp_folder())
|
||||
except OSError:
|
||||
log.exception(u'Failed to delete presentation controller files')
|
||||
|
||||
def store_filename(self, presentation):
|
||||
def get_file_name(self):
|
||||
"""
|
||||
Set properties for the filename and thumbnail paths
|
||||
Return just the filename of the presention, without the directory
|
||||
"""
|
||||
self.filepath = presentation
|
||||
self.filename = self.get_file_name(presentation)
|
||||
self.thumbnailpath = self.get_thumbnail_path(presentation)
|
||||
if not os.path.isdir(self.thumbnailpath):
|
||||
os.mkdir(self.thumbnailpath)
|
||||
return os.path.split(self.filepath)[1]
|
||||
|
||||
def get_file_name(self, presentation):
|
||||
return os.path.split(presentation)[1]
|
||||
|
||||
def get_thumbnail_path(self, presentation):
|
||||
def get_thumbnail_folder(self):
|
||||
"""
|
||||
The location where thumbnail images will be stored
|
||||
"""
|
||||
return os.path.join(
|
||||
self.controller.thumbnailroot, self.get_file_name(presentation))
|
||||
self.controller.thumbnail_folder, self.get_file_name())
|
||||
|
||||
def get_temp_folder(self):
|
||||
"""
|
||||
The location where thumbnail images will be stored
|
||||
"""
|
||||
return os.path.join(
|
||||
self.controller.temp_folder, self.get_file_name())
|
||||
|
||||
def check_thumbnails(self):
|
||||
"""
|
||||
Returns true if the thumbnail images look to exist and are more
|
||||
recent than the powerpoint
|
||||
"""
|
||||
lastimage = self.get_slide_preview_file(self.get_slide_count())
|
||||
lastimage = self.get_thumbnail_path(self.get_slide_count(), True)
|
||||
if not (lastimage and os.path.isfile(lastimage)):
|
||||
return False
|
||||
imgdate = os.stat(lastimage).st_mtime
|
||||
@ -350,16 +371,27 @@ class PresentationDocument(object):
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_slide_preview_file(self, slide_no):
|
||||
def convert_thumbnail(self, file, idx):
|
||||
"""
|
||||
Convert the slide image the application made to a standard 320x240
|
||||
.png image.
|
||||
"""
|
||||
if self.check_thumbnails():
|
||||
return
|
||||
if os.path.isfile(file):
|
||||
img = resize_image(file, 320, 240)
|
||||
img.save(self.get_thumbnail_path(idx, False))
|
||||
|
||||
def get_thumbnail_path(self, slide_no, check_exists):
|
||||
"""
|
||||
Returns an image path containing a preview for the requested slide
|
||||
|
||||
``slide_no``
|
||||
The slide an image is required for, starting at 1
|
||||
"""
|
||||
path = os.path.join(self.thumbnailpath,
|
||||
self.controller.thumbnailprefix + unicode(slide_no) + u'.png')
|
||||
if os.path.isfile(path):
|
||||
path = os.path.join(self.get_thumbnail_folder(),
|
||||
self.controller.thumbnail_prefix + unicode(slide_no) + u'.png')
|
||||
if os.path.isfile(path) or not check_exists:
|
||||
return path
|
||||
else:
|
||||
return None
|
||||
|
@ -32,10 +32,16 @@ class PresentationTab(SettingsTab):
|
||||
PresentationsTab is the Presentations settings tab in the settings dialog.
|
||||
"""
|
||||
def __init__(self, title, controllers):
|
||||
"""
|
||||
Constructor
|
||||
"""
|
||||
self.controllers = controllers
|
||||
SettingsTab.__init__(self, title)
|
||||
|
||||
def setupUi(self):
|
||||
"""
|
||||
Create the controls for the settings tab
|
||||
"""
|
||||
self.setObjectName(u'PresentationTab')
|
||||
self.tabTitleVisible = translate('PresentationPlugin.PresentationTab',
|
||||
'Presentations')
|
||||
@ -89,6 +95,9 @@ class PresentationTab(SettingsTab):
|
||||
self.PresentationLayout.addWidget(self.PresentationRightWidget)
|
||||
|
||||
def retranslateUi(self):
|
||||
"""
|
||||
Make any translation changes
|
||||
"""
|
||||
self.VerseDisplayGroupBox.setTitle(
|
||||
translate('PresentationPlugin.PresentationTab',
|
||||
'Available Controllers'))
|
||||
@ -100,6 +109,9 @@ class PresentationTab(SettingsTab):
|
||||
translate('PresentationPlugin.PresentationTab', 'available')))
|
||||
|
||||
def load(self):
|
||||
"""
|
||||
Load the settings.
|
||||
"""
|
||||
for key in self.controllers:
|
||||
controller = self.controllers[key]
|
||||
if controller.available:
|
||||
@ -109,6 +121,9 @@ class PresentationTab(SettingsTab):
|
||||
QtCore.QVariant(0)).toInt()[0])
|
||||
|
||||
def save(self):
|
||||
"""
|
||||
Save the settings.
|
||||
"""
|
||||
for key in self.controllers:
|
||||
controller = self.controllers[key]
|
||||
checkbox = self.PresenterCheckboxes[controller.name]
|
||||
|
@ -33,9 +33,17 @@ from openlp.plugins.presentations.lib import *
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class PresentationPlugin(Plugin):
|
||||
"""
|
||||
This plugin allowed a Presentation to be opened, controlled and displayed
|
||||
on the output display. The plugin controls third party applications such
|
||||
as OpenOffice.org Impress, Microsoft PowerPoint and the PowerPoint viewer
|
||||
"""
|
||||
log = logging.getLogger(u'PresentationPlugin')
|
||||
|
||||
def __init__(self, plugin_helpers):
|
||||
"""
|
||||
PluginPresentation constructor.
|
||||
"""
|
||||
log.debug(u'Initialised')
|
||||
self.controllers = {}
|
||||
Plugin.__init__(self, u'Presentations', u'1.9.2', plugin_helpers)
|
||||
@ -51,6 +59,10 @@ class PresentationPlugin(Plugin):
|
||||
return PresentationTab(self.name, self.controllers)
|
||||
|
||||
def initialise(self):
|
||||
"""
|
||||
Initialise the plugin. Determine which controllers are enabled
|
||||
are start their processes.
|
||||
"""
|
||||
log.info(u'Presentations Initialising')
|
||||
Plugin.initialise(self)
|
||||
self.insertToolboxItem()
|
||||
@ -59,6 +71,10 @@ class PresentationPlugin(Plugin):
|
||||
self.controllers[controller].start_process()
|
||||
|
||||
def finalise(self):
|
||||
"""
|
||||
Finalise the plugin. Ask all the enabled presentation applications
|
||||
to close down their applications and release resources.
|
||||
"""
|
||||
log.info(u'Plugin Finalise')
|
||||
#Ask each controller to tidy up
|
||||
for key in self.controllers:
|
||||
@ -75,6 +91,10 @@ class PresentationPlugin(Plugin):
|
||||
self, self.icon, self.name, self.controllers)
|
||||
|
||||
def registerControllers(self, controller):
|
||||
"""
|
||||
Register each presentation controller (Impress, PPT etc) and
|
||||
store for later use
|
||||
"""
|
||||
self.controllers[controller.name] = controller
|
||||
|
||||
def checkPreConditions(self):
|
||||
@ -109,9 +129,13 @@ class PresentationPlugin(Plugin):
|
||||
return False
|
||||
|
||||
def about(self):
|
||||
"""
|
||||
Return information about this plugin
|
||||
"""
|
||||
about_text = translate('PresentationPlugin',
|
||||
'<b>Presentation Plugin</b> <br> Delivers '
|
||||
'the ability to show presentations using a number of different '
|
||||
'programs. The choice of available presentation programs is '
|
||||
'available to the user in a drop down box.')
|
||||
return about_text
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user