Common thumbnails for all presentation types and create when presentation first added

bzr-revno: 932
This commit is contained in:
Jonathan Corwin 2010-07-12 08:25:17 +01:00
commit e77d6ec981
10 changed files with 364 additions and 118 deletions

View File

@ -174,6 +174,8 @@ def resize_image(image, width, height):
"""
preview = QtGui.QImage(image)
if not preview.isNull():
if preview.width() == width and preview.height == height:
return preview
preview = preview.scaled(width, height, QtCore.Qt.KeepAspectRatio,
QtCore.Qt.SmoothTransformation)
realw = preview.width()

View File

@ -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)
return True
return False
else:
self.iconFromFile(file, thumb)
return True
def iconFromFile(self, file, thumb):
"""

View File

@ -74,6 +74,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 +105,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 +139,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 +185,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 +232,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 +242,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 +258,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 +318,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 +335,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 +349,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 +373,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 +383,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 +402,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):

View File

@ -35,9 +35,13 @@ 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 +49,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 +70,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 +90,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 +125,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 +140,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,40 +155,43 @@ class PresentationMediaItem(MediaManagerItem):
continue
filename = os.path.split(unicode(file))[1]
if titles.count(filename) > 0:
QtGui.QMessageBox.critical(
self, translate('PresentationPlugin.MediaItem',
'File exists'),
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):
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:
QtGui.QMessageBox.Ok)
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')
item_name = QtGui.QListWidgetItem(filename)
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
item_name.setIcon(icon)
self.listView.addItem(item_name)
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)
self.listView.addItem(item_name)
def onDeleteClick(self):
"""
@ -184,8 +206,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 +216,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 +238,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

View File

@ -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()

View File

@ -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):
"""
@ -298,4 +309,4 @@ class PowerpointDocument(PresentationDocument):
shape = shapes(idx + 1)
if shape.HasTextFrame:
text += shape.TextFrame.TextRange.Text + '\n'
return text
return text

View File

@ -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

View File

@ -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):
"""
@ -224,9 +240,10 @@ 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

View File

@ -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]

View File

@ -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
return about_text