songusage and presentation code standards

This commit is contained in:
Andreas Preikschat 2013-04-19 20:52:39 +02:00
parent 0ceaef7a51
commit dad243dd74
14 changed files with 301 additions and 339 deletions

View File

@ -27,6 +27,6 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
The :mod:`presentations` module provides the Presentations plugin which allows The :mod:`presentations` module provides the Presentations plugin which allows OpenLP to show presentations from most
OpenLP to show presentations from most popular presentation packages. popular presentation packages.
""" """

View File

@ -62,13 +62,14 @@ from openlp.core.lib import ScreenList
from openlp.core.utils import delete_file, get_uno_command, get_uno_instance from openlp.core.utils import delete_file, get_uno_command, get_uno_instance
from presentationcontroller import PresentationController, PresentationDocument from presentationcontroller import PresentationController, PresentationDocument
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class ImpressController(PresentationController): class ImpressController(PresentationController):
""" """
Class to control interactions with Impress presentations. Class to control interactions with Impress presentations. It creates the runtime environment, loads and closes the
It creates the runtime environment, loads and closes the presentation as presentation as well as triggering the correct activities based on the users input.
well as triggering the correct activities based on the users input
""" """
log.info(u'ImpressController loaded') log.info(u'ImpressController loaded')
@ -79,14 +80,14 @@ class ImpressController(PresentationController):
log.debug(u'Initialising') log.debug(u'Initialising')
PresentationController.__init__(self, plugin, u'Impress', ImpressDocument) PresentationController.__init__(self, plugin, u'Impress', ImpressDocument)
self.supports = [u'odp'] self.supports = [u'odp']
self.alsosupports = [u'ppt', u'pps', u'pptx', u'ppsx'] self.also_supports = [u'ppt', u'pps', u'pptx', u'ppsx']
self.process = None self.process = None
self.desktop = None self.desktop = None
self.manager = None self.manager = None
def check_available(self): def check_available(self):
""" """
Impress is able to run on this machine Impress is able to run on this machine.
""" """
log.debug(u'check_available') log.debug(u'check_available')
if os.name == u'nt': if os.name == u'nt':
@ -96,9 +97,8 @@ class ImpressController(PresentationController):
def start_process(self): def start_process(self):
""" """
Loads a running version of OpenOffice in the background. Loads a running version of OpenOffice in the background. It is not displayed to the user but is available to the
It is not displayed to the user but is available to the UNO interface UNO interface when required.
when required.
""" """
log.debug(u'start process Openoffice') log.debug(u'start process Openoffice')
if os.name == u'nt': if os.name == u'nt':
@ -113,8 +113,7 @@ class ImpressController(PresentationController):
def get_uno_desktop(self): def get_uno_desktop(self):
""" """
On non-Windows platforms, use Uno. Get the OpenOffice desktop On non-Windows platforms, use Uno. Get the OpenOffice desktop which will be used to manage impress.
which will be used to manage impress
""" """
log.debug(u'get UNO Desktop Openoffice') log.debug(u'get UNO Desktop Openoffice')
uno_instance = None uno_instance = None
@ -132,8 +131,7 @@ class ImpressController(PresentationController):
loop += 1 loop += 1
try: try:
self.manager = uno_instance.ServiceManager self.manager = uno_instance.ServiceManager
log.debug(u'get UNO Desktop Openoffice - createInstanceWithContext' log.debug(u'get UNO Desktop Openoffice - createInstanceWithContext - Desktop')
u' - Desktop')
desktop = self.manager.createInstanceWithContext("com.sun.star.frame.Desktop", uno_instance) desktop = self.manager.createInstanceWithContext("com.sun.star.frame.Desktop", uno_instance)
return desktop return desktop
except: except:
@ -142,8 +140,7 @@ class ImpressController(PresentationController):
def get_com_desktop(self): def get_com_desktop(self):
""" """
On Windows platforms, use COM. Return the desktop object which On Windows platforms, use COM. Return the desktop object which will be used to manage Impress.
will be used to manage Impress
""" """
log.debug(u'get COM Desktop OpenOffice') log.debug(u'get COM Desktop OpenOffice')
if not self.manager: if not self.manager:
@ -157,7 +154,7 @@ class ImpressController(PresentationController):
def get_com_servicemanager(self): def get_com_servicemanager(self):
""" """
Return the OOo service manager for windows Return the OOo service manager for windows.
""" """
log.debug(u'get_com_servicemanager openoffice') log.debug(u'get_com_servicemanager openoffice')
try: try:
@ -168,7 +165,7 @@ class ImpressController(PresentationController):
def kill(self): def kill(self):
""" """
Called at system exit to clean up any running presentations Called at system exit to clean up any running presentations.
""" """
log.debug(u'Kill OpenOffice') log.debug(u'Kill OpenOffice')
while self.docs: while self.docs:
@ -203,12 +200,12 @@ class ImpressController(PresentationController):
class ImpressDocument(PresentationDocument): class ImpressDocument(PresentationDocument):
""" """
Class which holds information and controls a single presentation 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 Constructor, store information about the file and initialise.
""" """
log.debug(u'Init Presentation OpenOffice') log.debug(u'Init Presentation OpenOffice')
PresentationDocument.__init__(self, controller, presentation) PresentationDocument.__init__(self, controller, presentation)
@ -218,11 +215,9 @@ class ImpressDocument(PresentationDocument):
def load_presentation(self): def load_presentation(self):
""" """
Called when a presentation is added to the SlideController. Called when a presentation is added to the SlideController. It builds the environment, starts communcations with
It builds the environment, starts communcations with the background the background OpenOffice task started earlier. If OpenOffice is not present is is started. Once the environment
OpenOffice task started earlier. If OpenOffice is not present is is is available the presentation is loaded and started.
started. Once the environment is available the presentation is loaded
and started.
""" """
log.debug(u'Load Presentation OpenOffice') log.debug(u'Load Presentation OpenOffice')
if os.name == u'nt': if os.name == u'nt':
@ -239,13 +234,12 @@ class ImpressDocument(PresentationDocument):
self.desktop = desktop self.desktop = desktop
properties = [] properties = []
if os.name != u'nt': if os.name != u'nt':
# Recent versions of Impress on Windows won't start the presentation # Recent versions of Impress on Windows won't start the presentation if it starts as minimized. It seems OK
# if it starts as minimized. It seems OK on Linux though. # on Linux though.
properties.append(self.create_property(u'Minimized', True)) properties.append(self.create_property(u'Minimized', True))
properties = tuple(properties) properties = tuple(properties)
try: try:
self.document = desktop.loadComponentFromURL(url, u'_blank', self.document = desktop.loadComponentFromURL(url, u'_blank', 0, properties)
0, properties)
except: except:
log.warn(u'Failed to load presentation %s' % url) log.warn(u'Failed to load presentation %s' % url)
return False return False
@ -262,33 +256,33 @@ class ImpressDocument(PresentationDocument):
def create_thumbnails(self): def create_thumbnails(self):
""" """
Create thumbnail images for presentation Create thumbnail images for presentation.
""" """
log.debug(u'create thumbnails OpenOffice') log.debug(u'create thumbnails OpenOffice')
if self.check_thumbnails(): if self.check_thumbnails():
return return
if os.name == u'nt': if os.name == u'nt':
thumbdirurl = u'file:///' + self.get_temp_folder().replace(u'\\', u'/') \ thumb_dir_url = u'file:///' + self.get_temp_folder().replace(u'\\', u'/') \
.replace(u':', u'|').replace(u' ', u'%20') .replace(u':', u'|').replace(u' ', u'%20')
else: else:
thumbdirurl = uno.systemPathToFileUrl(self.get_temp_folder()) thumb_dir_url = uno.systemPathToFileUrl(self.get_temp_folder())
props = [] properties = []
props.append(self.create_property(u'FilterName', u'impress_png_Export')) properties.append(self.create_property(u'FilterName', u'impress_png_Export'))
props = tuple(props) properties = tuple(properties)
doc = self.document doc = self.document
pages = doc.getDrawPages() pages = doc.getDrawPages()
if not pages: if not pages:
return return
if not os.path.isdir(self.get_temp_folder()): if not os.path.isdir(self.get_temp_folder()):
os.makedirs(self.get_temp_folder()) os.makedirs(self.get_temp_folder())
for idx in range(pages.getCount()): for index in range(pages.getCount()):
page = pages.getByIndex(idx) page = pages.getByIndex(index)
doc.getCurrentController().setCurrentPage(page) doc.getCurrentController().setCurrentPage(page)
urlpath = u'%s/%s.png' % (thumbdirurl, unicode(idx + 1)) url_path = u'%s/%s.png' % (thumb_dir_url, unicode(index + 1))
path = os.path.join(self.get_temp_folder(), unicode(idx + 1) + u'.png') path = os.path.join(self.get_temp_folder(), unicode(index + 1) + u'.png')
try: try:
doc.storeToURL(urlpath, props) doc.storeToURL(url_path, properties)
self.convert_thumbnail(path, idx + 1) self.convert_thumbnail(path, index + 1)
delete_file(path) delete_file(path)
except ErrorCodeIOException, exception: except ErrorCodeIOException, exception:
log.exception(u'ERROR! ErrorCodeIOException %d' % exception.ErrCode) log.exception(u'ERROR! ErrorCodeIOException %d' % exception.ErrCode)
@ -297,23 +291,21 @@ class ImpressDocument(PresentationDocument):
def create_property(self, name, value): def create_property(self, name, value):
""" """
Create an OOo style property object which are passed into some Create an OOo style property object which are passed into some Uno methods.
Uno methods
""" """
log.debug(u'create property OpenOffice') log.debug(u'create property OpenOffice')
if os.name == u'nt': if os.name == u'nt':
prop = self.controller.manager.Bridge_GetStruct(u'com.sun.star.beans.PropertyValue') property = self.controller.manager.Bridge_GetStruct(u'com.sun.star.beans.PropertyValue')
else: else:
prop = PropertyValue() property = PropertyValue()
prop.Name = name property.Name = name
prop.Value = value property.Value = value
return prop return property
def close_presentation(self): def close_presentation(self):
""" """
Close presentation and clean up objects Close presentation and clean up objects. Triggered by new object being added to SlideController or OpenLP being
Triggered by new object being added to SlideController or OpenLP shutdown.
being shutdown
""" """
log.debug(u'close Presentation OpenOffice') log.debug(u'close Presentation OpenOffice')
if self.document: if self.document:
@ -329,7 +321,7 @@ class ImpressDocument(PresentationDocument):
def is_loaded(self): def is_loaded(self):
""" """
Returns true if a presentation is loaded Returns true if a presentation is loaded.
""" """
log.debug(u'is loaded OpenOffice') log.debug(u'is loaded OpenOffice')
if self.presentation is None or self.document is None: if self.presentation is None or self.document is None:
@ -346,7 +338,7 @@ class ImpressDocument(PresentationDocument):
def is_active(self): def is_active(self):
""" """
Returns true if a presentation is active and running Returns true if a presentation is active and running.
""" """
log.debug(u'is active OpenOffice') log.debug(u'is active OpenOffice')
if not self.is_loaded(): if not self.is_loaded():
@ -355,21 +347,21 @@ class ImpressDocument(PresentationDocument):
def unblank_screen(self): def unblank_screen(self):
""" """
Unblanks the screen Unblanks the screen.
""" """
log.debug(u'unblank screen OpenOffice') log.debug(u'unblank screen OpenOffice')
return self.control.resume() return self.control.resume()
def blank_screen(self): def blank_screen(self):
""" """
Blanks the screen Blanks the screen.
""" """
log.debug(u'blank screen OpenOffice') log.debug(u'blank screen OpenOffice')
self.control.blankScreen(0) self.control.blankScreen(0)
def is_blank(self): def is_blank(self):
""" """
Returns true if screen is blank Returns true if screen is blank.
""" """
log.debug(u'is blank OpenOffice') log.debug(u'is blank OpenOffice')
if self.control and self.control.isRunning(): if self.control and self.control.isRunning():
@ -379,7 +371,7 @@ class ImpressDocument(PresentationDocument):
def stop_presentation(self): def stop_presentation(self):
""" """
Stop the presentation, remove from screen Stop the presentation, remove from screen.
""" """
log.debug(u'stop presentation OpenOffice') log.debug(u'stop presentation OpenOffice')
# deactivate should hide the screen according to docs, but doesn't # deactivate should hide the screen according to docs, but doesn't
@ -389,18 +381,17 @@ class ImpressDocument(PresentationDocument):
def start_presentation(self): def start_presentation(self):
""" """
Start the presentation from the beginning Start the presentation from the beginning.
""" """
log.debug(u'start presentation OpenOffice') log.debug(u'start presentation OpenOffice')
if self.control is None or not self.control.isRunning(): if self.control is None or not self.control.isRunning():
self.presentation.start() self.presentation.start()
self.control = self.presentation.getController() self.control = self.presentation.getController()
# start() returns before the Component is ready. # start() returns before the Component is ready. Try for 15 seconds.
# Try for 15 seconds sleep_count = 1
i = 1 while not self.control and sleep_count < 150:
while not self.control and i < 150:
time.sleep(0.1) time.sleep(0.1)
i += 1 sleep_count += 1
self.control = self.presentation.getController() self.control = self.presentation.getController()
else: else:
self.control.activate() self.control.activate()
@ -408,25 +399,25 @@ class ImpressDocument(PresentationDocument):
def get_slide_number(self): def get_slide_number(self):
""" """
Return the current slide number on the screen, from 1 Return the current slide number on the screen, from 1.
""" """
return self.control.getCurrentSlideIndex() + 1 return self.control.getCurrentSlideIndex() + 1
def get_slide_count(self): def get_slide_count(self):
""" """
Return the total number of slides Return the total number of slides.
""" """
return self.document.getDrawPages().getCount() return self.document.getDrawPages().getCount()
def goto_slide(self, slideno): def goto_slide(self, slideno):
""" """
Go to a specific slide (from 1) Go to a specific slide (from 1).
""" """
self.control.gotoSlideIndex(slideno-1) self.control.gotoSlideIndex(slideno-1)
def next_step(self): def next_step(self):
""" """
Triggers the next effect of slide on the running presentation Triggers the next effect of slide on the running presentation.
""" """
is_paused = self.control.isPaused() is_paused = self.control.isPaused()
self.control.gotoNextEffect() self.control.gotoNextEffect()
@ -436,7 +427,7 @@ class ImpressDocument(PresentationDocument):
def previous_step(self): def previous_step(self):
""" """
Triggers the previous slide on the running presentation Triggers the previous slide on the running presentation.
""" """
self.control.gotoPreviousSlide() self.control.gotoPreviousSlide()
@ -470,8 +461,8 @@ class ImpressDocument(PresentationDocument):
page = pages.getByIndex(slide_no - 1) page = pages.getByIndex(slide_no - 1)
if notes: if notes:
page = page.getNotesPage() page = page.getNotesPage()
for idx in range(page.getCount()): for index in range(page.getCount()):
shape = page.getByIndex(idx) shape = page.getByIndex(index)
if shape.supportsService("com.sun.star.drawing.Text"): if shape.supportsService("com.sun.star.drawing.Text"):
text += shape.getString() + '\n' text += shape.getString() + '\n'
return text return text

View File

@ -38,14 +38,17 @@ from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adj
from openlp.core.utils import get_locale_key from openlp.core.utils import get_locale_key
from openlp.plugins.presentations.lib import MessageListener from openlp.plugins.presentations.lib import MessageListener
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
ERROR = QtGui.QImage(u':/general/general_delete.png')
ERROR_IMAGE = QtGui.QImage(u':/general/general_delete.png')
class PresentationMediaItem(MediaManagerItem): class PresentationMediaItem(MediaManagerItem):
""" """
This is the Presentation media manager item for Presentation Items. This is the Presentation media manager item for Presentation Items. It can present files using Openoffice and
It can present files using Openoffice and Powerpoint Powerpoint
""" """
log.info(u'Presentations Media Item loaded') log.info(u'Presentations Media Item loaded')
@ -71,25 +74,25 @@ class PresentationMediaItem(MediaManagerItem):
""" """
self.on_new_prompt = translate('PresentationPlugin.MediaItem', 'Select Presentation(s)') self.on_new_prompt = translate('PresentationPlugin.MediaItem', 'Select Presentation(s)')
self.Automatic = translate('PresentationPlugin.MediaItem', 'Automatic') self.Automatic = translate('PresentationPlugin.MediaItem', 'Automatic')
self.displayTypeLabel.setText(translate('PresentationPlugin.MediaItem', 'Present using:')) self.display_type_label.setText(translate('PresentationPlugin.MediaItem', 'Present using:'))
def build_file_mask_string(self): def build_file_mask_string(self):
""" """
Build the list of file extensions to be used in the Open file dialog Build the list of file extensions to be used in the Open file dialog.
""" """
fileType = u'' file_type = u''
for controller in self.controllers: for controller in self.controllers:
if self.controllers[controller].enabled(): if self.controllers[controller].enabled():
types = self.controllers[controller].supports + self.controllers[controller].alsosupports file_types = self.controllers[controller].supports + self.controllers[controller].also_supports
for type in types: for file_type in file_types:
if fileType.find(type) == -1: if file_type.find(file_type) == -1:
fileType += u'*.%s ' % type file_type += u'*.%s ' % file_type
self.service_manager.supported_suffixes(type) self.service_manager.supported_suffixes(file_type)
self.on_new_file_masks = translate('PresentationPlugin.MediaItem', 'Presentations (%s)') % fileType self.on_new_file_masks = translate('PresentationPlugin.MediaItem', 'Presentations (%s)') % file_type
def required_icons(self): def required_icons(self):
""" """
Set which icons the media manager tab should show Set which icons the media manager tab should show.
""" """
MediaManagerItem.required_icons(self) MediaManagerItem.required_icons(self)
self.has_file_icon = True self.has_file_icon = True
@ -98,21 +101,21 @@ class PresentationMediaItem(MediaManagerItem):
def add_end_header_bar(self): def add_end_header_bar(self):
""" """
Display custom media manager items for presentations Display custom media manager items for presentations.
""" """
self.presentationWidget = QtGui.QWidget(self) self.presentation_widget = QtGui.QWidget(self)
self.presentationWidget.setObjectName(u'presentationWidget') self.presentation_widget.setObjectName(u'presentation_widget')
self.displayLayout = QtGui.QFormLayout(self.presentationWidget) self.display_layout = QtGui.QFormLayout(self.presentation_widget)
self.displayLayout.setMargin(self.displayLayout.spacing()) self.display_layout.setMargin(self.display_layout.spacing())
self.displayLayout.setObjectName(u'displayLayout') self.display_layout.setObjectName(u'display_layout')
self.displayTypeLabel = QtGui.QLabel(self.presentationWidget) self.display_type_label = QtGui.QLabel(self.presentation_widget)
self.displayTypeLabel.setObjectName(u'displayTypeLabel') self.display_type_label.setObjectName(u'display_type_label')
self.displayTypeComboBox = create_horizontal_adjusting_combo_box(self.presentationWidget, self.displayTypeComboBox = create_horizontal_adjusting_combo_box(self.presentation_widget,
u'displayTypeComboBox') u'displayTypeComboBox')
self.displayTypeLabel.setBuddy(self.displayTypeComboBox) self.display_type_label.setBuddy(self.displayTypeComboBox)
self.displayLayout.addRow(self.displayTypeLabel, self.displayTypeComboBox) self.display_layout.addRow(self.display_type_label, self.displayTypeComboBox)
# Add the Presentation widget to the page layout # Add the Presentation widget to the page layout
self.page_layout.addWidget(self.presentationWidget) self.page_layout.addWidget(self.presentation_widget)
def initialise(self): def initialise(self):
""" """
@ -120,13 +123,13 @@ class PresentationMediaItem(MediaManagerItem):
""" """
self.list_view.setIconSize(QtCore.QSize(88, 50)) self.list_view.setIconSize(QtCore.QSize(88, 50))
files = Settings().value(self.settings_section + u'/presentations files') files = Settings().value(self.settings_section + u'/presentations files')
self.load_list(files, initialLoad=True) self.load_list(files, initial_load=True)
self.populate_display_types() self.populate_display_types()
def populate_display_types(self): def populate_display_types(self):
""" """
Load the combobox with the enabled presentation controllers, Load the combobox with the enabled presentation controllers, allowing user to select a specific app if settings
allowing user to select a specific app if settings allow allow.
""" """
self.displayTypeComboBox.clear() self.displayTypeComboBox.clear()
for item in self.controllers: for item in self.controllers:
@ -137,38 +140,37 @@ class PresentationMediaItem(MediaManagerItem):
self.displayTypeComboBox.insertItem(0, self.Automatic) self.displayTypeComboBox.insertItem(0, self.Automatic)
self.displayTypeComboBox.setCurrentIndex(0) self.displayTypeComboBox.setCurrentIndex(0)
if Settings().value(self.settings_section + u'/override app') == QtCore.Qt.Checked: if Settings().value(self.settings_section + u'/override app') == QtCore.Qt.Checked:
self.presentationWidget.show() self.presentation_widget.show()
else: else:
self.presentationWidget.hide() self.presentation_widget.hide()
def load_list(self, files, target_group=None, initialLoad=False): def load_list(self, files, target_group=None, initial_load=False):
""" """
Add presentations into the media manager Add presentations into the media manager. This is called both on initial load of the plugin to populate with
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.
existing files, and when the user adds new files via the media manager
""" """
currlist = self.get_file_list() current_list = self.get_file_list()
titles = [os.path.split(file)[1] for file in currlist] titles = [os.path.split(file)[1] for file in current_list]
self.application.set_busy_cursor() self.application.set_busy_cursor()
if not initialLoad: if not initial_load:
self.main_window.display_progress_bar(len(files)) self.main_window.display_progress_bar(len(files))
# Sort the presentations by its filename considering language specific characters. # Sort the presentations by its filename considering language specific characters.
files.sort(key=lambda filename: get_locale_key(os.path.split(unicode(filename))[1])) files.sort(key=lambda filename: get_locale_key(os.path.split(unicode(filename))[1]))
for file in files: for file in files:
if not initialLoad: if not initial_load:
self.main_window.increment_progress_bar() self.main_window.increment_progress_bar()
if currlist.count(file) > 0: if current_list.count(file) > 0:
continue continue
filename = os.path.split(unicode(file))[1] filename = os.path.split(unicode(file))[1]
if not os.path.exists(file): if not os.path.exists(file):
item_name = QtGui.QListWidgetItem(filename) item_name = QtGui.QListWidgetItem(filename)
item_name.setIcon(build_icon(ERROR)) item_name.setIcon(build_icon(ERROR_IMAGE))
item_name.setData(QtCore.Qt.UserRole, file) item_name.setData(QtCore.Qt.UserRole, file)
item_name.setToolTip(file) item_name.setToolTip(file)
self.list_view.addItem(item_name) self.list_view.addItem(item_name)
else: else:
if titles.count(filename) > 0: if titles.count(filename) > 0:
if not initialLoad: if not initial_load:
critical_error_message_box(translate('PresentationPlugin.MediaItem', 'File Exists'), critical_error_message_box(translate('PresentationPlugin.MediaItem', 'File Exists'),
translate('PresentationPlugin.MediaItem', translate('PresentationPlugin.MediaItem',
'A presentation with that filename already exists.') 'A presentation with that filename already exists.')
@ -180,7 +182,7 @@ class PresentationMediaItem(MediaManagerItem):
doc = controller.add_document(unicode(file)) doc = controller.add_document(unicode(file))
thumb = os.path.join(doc.get_thumbnail_folder(), u'icon.png') thumb = os.path.join(doc.get_thumbnail_folder(), u'icon.png')
preview = doc.get_thumbnail_path(1, True) preview = doc.get_thumbnail_path(1, True)
if not preview and not initialLoad: if not preview and not initial_load:
doc.load_presentation() doc.load_presentation()
preview = doc.get_thumbnail_path(1, True) preview = doc.get_thumbnail_path(1, True)
doc.close_presentation() doc.close_presentation()
@ -192,7 +194,7 @@ class PresentationMediaItem(MediaManagerItem):
else: else:
icon = create_thumb(preview, thumb) icon = create_thumb(preview, thumb)
else: else:
if initialLoad: if initial_load:
icon = build_icon(u':/general/general_delete.png') icon = build_icon(u':/general/general_delete.png')
else: else:
critical_error_message_box(UiStrings().UnsupportedFile, critical_error_message_box(UiStrings().UnsupportedFile,
@ -203,13 +205,13 @@ class PresentationMediaItem(MediaManagerItem):
item_name.setIcon(icon) item_name.setIcon(icon)
item_name.setToolTip(file) item_name.setToolTip(file)
self.list_view.addItem(item_name) self.list_view.addItem(item_name)
if not initialLoad: if not initial_load:
self.main_window.finished_progress_bar() self.main_window.finished_progress_bar()
self.application.set_normal_cursor() self.application.set_normal_cursor()
def on_delete_click(self): def on_delete_click(self):
""" """
Remove a presentation item from the list Remove a presentation item from the list.
""" """
if check_item_selected(self.list_view, UiStrings().SelectDelete): if check_item_selected(self.list_view, UiStrings().SelectDelete):
items = self.list_view.selectedIndexes() items = self.list_view.selectedIndexes()
@ -230,12 +232,11 @@ class PresentationMediaItem(MediaManagerItem):
self.list_view.takeItem(row) self.list_view.takeItem(row)
Settings().setValue(self.settings_section + u'/presentations files', self.get_file_list()) Settings().setValue(self.settings_section + u'/presentations files', self.get_file_list())
def generate_slide_data(self, service_item, item=None, xmlVersion=False, def generate_slide_data(self, service_item, item=None, xml_version=False,
remote=False, context=ServiceItemContext.Service): remote=False, context=ServiceItemContext.Service):
""" """
Load the relevant information for displaying the presentation Load the relevant information for displaying the presentation in the slidecontroller. In the case of
in the slidecontroller. In the case of powerpoints, an image powerpoints, an image for each slide.
for each slide
""" """
if item: if item:
items = [item] items = [item]
@ -287,26 +288,24 @@ class PresentationMediaItem(MediaManagerItem):
def findControllerByType(self, filename): def findControllerByType(self, filename):
""" """
Determine the default application controller to use for the selected Determine the default application controller to use for the selected file type. This is used if "Automatic" is
file type. This is used if "Automatic" is set as the preferred set as the preferred controller. Find the first (alphabetic) enabled controller which "supports" the extension.
controller. Find the first (alphabetic) enabled controller which If none found, then look for a controller which "also supports" it instead.
"supports" the extension. If none found, then look for a controller
which "also supports" it instead.
""" """
filetype = os.path.splitext(filename)[1][1:] file_type = os.path.splitext(filename)[1][1:]
if not filetype: if not file_type:
return None return None
for controller in self.controllers: for controller in self.controllers:
if self.controllers[controller].enabled(): if self.controllers[controller].enabled():
if filetype in self.controllers[controller].supports: if file_type in self.controllers[controller].supports:
return controller return controller
for controller in self.controllers: for controller in self.controllers:
if self.controllers[controller].enabled(): if self.controllers[controller].enabled():
if filetype in self.controllers[controller].alsosupports: if file_type in self.controllers[controller].also_supports:
return controller return controller
return None return None
def search(self, string, showError): def search(self, string, show_error):
files = Settings().value(self.settings_section + u'/presentations files') files = Settings().value(self.settings_section + u'/presentations files')
results = [] results = []
string = string.lower() string = string.lower()

View File

@ -38,8 +38,8 @@ log = logging.getLogger(__name__)
class Controller(object): class Controller(object):
""" """
This is the Presentation listener who acts on events from the slide This is the Presentation listener who acts on events from the slide controller and passes the messages on the the
controller and passes the messages on the the correct presentation handlers correct presentation handlers.
""" """
log.info(u'Controller loaded') log.info(u'Controller loaded')
@ -54,9 +54,8 @@ class Controller(object):
def add_handler(self, controller, file, hide_mode, slide_no): def add_handler(self, controller, file, hide_mode, slide_no):
""" """
Add a handler, which is an instance of a presentation and Add a handler, which is an instance of a presentation and slidecontroller combination. If the slidecontroller
slidecontroller combination. If the slidecontroller has a display has a display then load the presentation.
then load the presentation.
""" """
log.debug(u'Live = %s, add_handler %s' % (self.is_live, file)) log.debug(u'Live = %s, add_handler %s' % (self.is_live, file))
self.controller = controller self.controller = controller
@ -86,8 +85,7 @@ class Controller(object):
def activate(self): def activate(self):
""" """
Active the presentation, and show it on the screen. Active the presentation, and show it on the screen. Use the last slide number.
Use the last slide number.
""" """
log.debug(u'Live = %s, activate' % self.is_live) log.debug(u'Live = %s, activate' % self.is_live)
if not self.doc: if not self.doc:
@ -130,7 +128,7 @@ class Controller(object):
def first(self): def first(self):
""" """
Based on the handler passed at startup triggers the first slide Based on the handler passed at startup triggers the first slide.
""" """
log.debug(u'Live = %s, first' % self.is_live) log.debug(u'Live = %s, first' % self.is_live)
if not self.doc: if not self.doc:
@ -148,7 +146,7 @@ class Controller(object):
def last(self): def last(self):
""" """
Based on the handler passed at startup triggers the last slide Based on the handler passed at startup triggers the last slide.
""" """
log.debug(u'Live = %s, last' % self.is_live) log.debug(u'Live = %s, last' % self.is_live)
if not self.doc: if not self.doc:
@ -166,7 +164,7 @@ class Controller(object):
def next(self): def next(self):
""" """
Based on the handler passed at startup triggers the next slide event Based on the handler passed at startup triggers the next slide event.
""" """
log.debug(u'Live = %s, next' % self.is_live) log.debug(u'Live = %s, next' % self.is_live)
if not self.doc: if not self.doc:
@ -182,9 +180,8 @@ class Controller(object):
return return
if not self.activate(): if not self.activate():
return return
# The "End of slideshow" screen is after the last slide # The "End of slideshow" screen is after the last slide. Note, we can't just stop on the last slide, since it
# Note, we can't just stop on the last slide, since it may # may contain animations that need to be stepped through.
# contain animations that need to be stepped through.
if self.doc.slidenumber > self.doc.get_slide_count(): if self.doc.slidenumber > self.doc.get_slide_count():
return return
self.doc.next_step() self.doc.next_step()
@ -192,7 +189,7 @@ class Controller(object):
def previous(self): def previous(self):
""" """
Based on the handler passed at startup triggers the previous slide event Based on the handler passed at startup triggers the previous slide event.
""" """
log.debug(u'Live = %s, previous' % self.is_live) log.debug(u'Live = %s, previous' % self.is_live)
if not self.doc: if not self.doc:
@ -213,7 +210,7 @@ class Controller(object):
def shutdown(self): def shutdown(self):
""" """
Based on the handler passed at startup triggers slide show to shut down Based on the handler passed at startup triggers slide show to shut down.
""" """
log.debug(u'Live = %s, shutdown' % self.is_live) log.debug(u'Live = %s, shutdown' % self.is_live)
if not self.doc: if not self.doc:
@ -223,7 +220,7 @@ class Controller(object):
def blank(self, hide_mode): def blank(self, hide_mode):
""" """
Instruct the controller to blank the presentation Instruct the controller to blank the presentation.
""" """
log.debug(u'Live = %s, blank' % self.is_live) log.debug(u'Live = %s, blank' % self.is_live)
self.hide_mode = hide_mode self.hide_mode = hide_mode
@ -244,7 +241,7 @@ class Controller(object):
def stop(self): def stop(self):
""" """
Instruct the controller to stop and hide the presentation Instruct the controller to stop and hide the presentation.
""" """
log.debug(u'Live = %s, stop' % self.is_live) log.debug(u'Live = %s, stop' % self.is_live)
self.hide_mode = HideMode.Screen self.hide_mode = HideMode.Screen
@ -260,7 +257,7 @@ class Controller(object):
def unblank(self): def unblank(self):
""" """
Instruct the controller to unblank the presentation Instruct the controller to unblank the presentation.
""" """
log.debug(u'Live = %s, unblank' % self.is_live) log.debug(u'Live = %s, unblank' % self.is_live)
self.hide_mode = None self.hide_mode = None
@ -283,8 +280,8 @@ class Controller(object):
class MessageListener(object): class MessageListener(object):
""" """
This is the Presentation listener who acts on events from the slide This is the Presentation listener who acts on events from the slide controller and passes the messages on the the
controller and passes the messages on the the correct presentation handlers correct presentation handlers
""" """
log.info(u'Message Listener loaded') log.info(u'Message Listener loaded')
@ -310,12 +307,11 @@ class MessageListener(object):
def startup(self, message): def startup(self, message):
""" """
Start of new presentation Start of new presentation. Save the handler as any new presentations start here
Save the handler as any new presentations start here
""" """
log.debug(u'Startup called with message %s' % message)
is_live = message[1] is_live = message[1]
item = message[0] item = message[0]
log.debug(u'Startup called with message %s' % message)
hide_mode = message[2] hide_mode = message[2]
file = item.get_frame_path() file = item.get_frame_path()
self.handler = item.title self.handler = item.title
@ -331,7 +327,7 @@ class MessageListener(object):
def slide(self, message): def slide(self, message):
""" """
React to the message to move to a specific slide React to the message to move to a specific slide.
""" """
is_live = message[1] is_live = message[1]
slide = message[2] slide = message[2]
@ -342,7 +338,7 @@ class MessageListener(object):
def first(self, message): def first(self, message):
""" """
React to the message to move to the first slide React to the message to move to the first slide.
""" """
is_live = message[1] is_live = message[1]
if is_live: if is_live:
@ -352,7 +348,7 @@ class MessageListener(object):
def last(self, message): def last(self, message):
""" """
React to the message to move to the last slide React to the message to move to the last slide.
""" """
is_live = message[1] is_live = message[1]
if is_live: if is_live:
@ -362,7 +358,7 @@ class MessageListener(object):
def next(self, message): def next(self, message):
""" """
React to the message to move to the next animation/slide React to the message to move to the next animation/slide.
""" """
is_live = message[1] is_live = message[1]
if is_live: if is_live:
@ -372,7 +368,7 @@ class MessageListener(object):
def previous(self, message): def previous(self, message):
""" """
React to the message to move to the previous animation/slide React to the message to move to the previous animation/slide.
""" """
is_live = message[1] is_live = message[1]
if is_live: if is_live:
@ -382,8 +378,7 @@ class MessageListener(object):
def shutdown(self, message): def shutdown(self, message):
""" """
React to message to shutdown the presentation. I.e. end the show React to message to shutdown the presentation. I.e. end the show and close the file.
and close the file
""" """
is_live = message[1] is_live = message[1]
if is_live: if is_live:
@ -393,7 +388,7 @@ class MessageListener(object):
def hide(self, message): def hide(self, message):
""" """
React to the message to show the desktop React to the message to show the desktop.
""" """
is_live = message[1] is_live = message[1]
if is_live: if is_live:
@ -401,7 +396,7 @@ class MessageListener(object):
def blank(self, message): def blank(self, message):
""" """
React to the message to blank the display React to the message to blank the display.
""" """
is_live = message[1] is_live = message[1]
hide_mode = message[2] hide_mode = message[2]
@ -410,7 +405,7 @@ class MessageListener(object):
def unblank(self, message): def unblank(self, message):
""" """
React to the message to unblank the display React to the message to unblank the display.
""" """
is_live = message[1] is_live = message[1]
if is_live: if is_live:
@ -418,9 +413,7 @@ class MessageListener(object):
def timeout(self): def timeout(self):
""" """
The presentation may be timed or might be controlled by the The presentation may be timed or might be controlled by the application directly, rather than through OpenLP.
application directly, rather than through OpenLP. Poll occasionally Poll occasionally to check which slide is currently displayed so the slidecontroller view can be updated.
to check which slide is currently displayed so the slidecontroller
view can be updated
""" """
self.live_handler.poll() self.live_handler.poll()

View File

@ -26,7 +26,10 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 # # with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
"""
This modul is for controlling powerpiont. PPT API documentation:
`http://msdn.microsoft.com/en-us/library/aa269321(office.10).aspx`_
"""
import os import os
import logging import logging
@ -39,16 +42,14 @@ if os.name == u'nt':
from openlp.core.lib import ScreenList from openlp.core.lib import ScreenList
from presentationcontroller import PresentationController, PresentationDocument from presentationcontroller import PresentationController, PresentationDocument
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
# PPT API documentation:
# http://msdn.microsoft.com/en-us/library/aa269321(office.10).aspx
class PowerpointController(PresentationController): class PowerpointController(PresentationController):
""" """
Class to control interactions with PowerPoint Presentations Class to control interactions with PowerPoint Presentations. It creates the runtime Environment , Loads the and
It creates the runtime Environment , Loads the and Closes the Presentation Closes the Presentation. As well as triggering the correct activities based on the users input.
As well as triggering the correct activities based on the users input
""" """
log.info(u'PowerpointController loaded') log.info(u'PowerpointController loaded')
@ -63,7 +64,7 @@ class PowerpointController(PresentationController):
def check_available(self): def check_available(self):
""" """
PowerPoint is able to run on this machine PowerPoint is able to run on this machine.
""" """
log.debug(u'check_available') log.debug(u'check_available')
if os.name == u'nt': if os.name == u'nt':
@ -77,7 +78,7 @@ class PowerpointController(PresentationController):
if os.name == u'nt': if os.name == u'nt':
def start_process(self): def start_process(self):
""" """
Loads PowerPoint process Loads PowerPoint process.
""" """
log.debug(u'start_process') log.debug(u'start_process')
if not self.process: if not self.process:
@ -87,7 +88,7 @@ class PowerpointController(PresentationController):
def kill(self): def kill(self):
""" """
Called at system exit to clean up any running presentations Called at system exit to clean up any running presentations.
""" """
log.debug(u'Kill powerpoint') log.debug(u'Kill powerpoint')
while self.docs: while self.docs:
@ -105,12 +106,12 @@ class PowerpointController(PresentationController):
class PowerpointDocument(PresentationDocument): class PowerpointDocument(PresentationDocument):
""" """
Class which holds information and controls a single presentation 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 Constructor, store information about the file and initialise.
""" """
log.debug(u'Init Presentation Powerpoint') log.debug(u'Init Presentation Powerpoint')
PresentationDocument.__init__(self, controller, presentation) PresentationDocument.__init__(self, controller, presentation)
@ -118,8 +119,8 @@ class PowerpointDocument(PresentationDocument):
def load_presentation(self): def load_presentation(self):
""" """
Called when a presentation is added to the SlideController. Called when a presentation is added to the SlideController. Opens the PowerPoint file using the process created
Opens the PowerPoint file using the process created earlier. earlier.
""" """
log.debug(u'load_presentation') log.debug(u'load_presentation')
if not self.controller.process or not self.controller.process.Visible: if not self.controller.process or not self.controller.process.Visible:
@ -142,20 +143,19 @@ class PowerpointDocument(PresentationDocument):
self.presentation.Slides[n].Copy() self.presentation.Slides[n].Copy()
thumbnail = QApplication.clipboard.image() thumbnail = QApplication.clipboard.image()
However, for the moment, we want a physical file since it makes life However, for the moment, we want a physical file since it makes life easier elsewhere.
easier elsewhere.
""" """
log.debug(u'create_thumbnails') log.debug(u'create_thumbnails')
if self.check_thumbnails(): if self.check_thumbnails():
return return
for num in range(self.presentation.Slides.Count): for num in range(self.presentation.Slides.Count):
self.presentation.Slides(num + 1).Export(os.path.join( self.presentation.Slides(num + 1).Export(
self.get_thumbnail_folder(), 'slide%d.png' % (num + 1)), 'png', 320, 240) os.path.join(self.get_thumbnail_folder(), 'slide%d.png' % (num + 1)), 'png', 320, 240)
def close_presentation(self): def close_presentation(self):
""" """
Close presentation and clean up objects. This is triggered by a new Close presentation and clean up objects. This is triggered by a new object being added to SlideController or
object being added to SlideController or OpenLP being shut down. OpenLP being shut down.
""" """
log.debug(u'ClosePresentation') log.debug(u'ClosePresentation')
if self.presentation: if self.presentation:
@ -182,7 +182,6 @@ class PowerpointDocument(PresentationDocument):
return False return False
return True return True
def is_active(self): def is_active(self):
""" """
Returns ``True`` if a presentation is currently active. Returns ``True`` if a presentation is currently active.
@ -253,15 +252,14 @@ class PowerpointDocument(PresentationDocument):
dpi = win32ui.GetForegroundWindow().GetDC().GetDeviceCaps(88) dpi = win32ui.GetForegroundWindow().GetDC().GetDeviceCaps(88)
except win32ui.error: except win32ui.error:
dpi = 96 dpi = 96
rect = ScreenList().current[u'size'] size = ScreenList().current[u'size']
ppt_window = self.presentation.SlideShowSettings.Run() ppt_window = self.presentation.SlideShowSettings.Run()
if not ppt_window: if not ppt_window:
return return
ppt_window.Top = rect.y() * 72 / dpi ppt_window.Top = size.y() * 72 / dpi
ppt_window.Height = rect.height() * 72 / dpi ppt_window.Height = size.height() * 72 / dpi
ppt_window.Left = rect.x() * 72 / dpi ppt_window.Left = size.x() * 72 / dpi
ppt_window.Width = rect.width() * 72 / dpi ppt_window.Width = size.width() * 72 / dpi
def get_slide_number(self): def get_slide_number(self):
""" """
@ -318,6 +316,7 @@ class PowerpointDocument(PresentationDocument):
""" """
return _get_text_from_shapes(self.presentation.Slides(slide_no).NotesPage.Shapes) return _get_text_from_shapes(self.presentation.Slides(slide_no).NotesPage.Shapes)
def _get_text_from_shapes(shapes): def _get_text_from_shapes(shapes):
""" """
Returns any text extracted from the shapes on a presentation slide. Returns any text extracted from the shapes on a presentation slide.
@ -326,8 +325,8 @@ def _get_text_from_shapes(shapes):
A set of shapes to search for text. A set of shapes to search for text.
""" """
text = '' text = ''
for idx in range(shapes.Count): for index in range(shapes.Count):
shape = shapes(idx + 1) shape = shapes(index + 1)
if shape.HasTextFrame: if shape.HasTextFrame:
text += shape.TextFrame.TextRange.Text + '\n' text += shape.TextFrame.TextRange.Text + '\n'
return text return text

View File

@ -37,13 +37,14 @@ if os.name == u'nt':
from openlp.core.lib import ScreenList from openlp.core.lib import ScreenList
from presentationcontroller import PresentationController, PresentationDocument from presentationcontroller import PresentationController, PresentationDocument
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class PptviewController(PresentationController): class PptviewController(PresentationController):
""" """
Class to control interactions with PowerPoint Viewer Presentations Class to control interactions with PowerPoint Viewer Presentations. It creates the runtime Environment , Loads the
It creates the runtime Environment , Loads the and Closes the Presentation and Closes the Presentation. As well as triggering the correct activities based on the users input
As well as triggering the correct activities based on the users input
""" """
log.info(u'PPTViewController loaded') log.info(u'PPTViewController loaded')
@ -58,7 +59,7 @@ class PptviewController(PresentationController):
def check_available(self): def check_available(self):
""" """
PPT Viewer is able to run on this machine PPT Viewer is able to run on this machine.
""" """
log.debug(u'check_available') log.debug(u'check_available')
if os.name != u'nt': if os.name != u'nt':
@ -68,7 +69,7 @@ class PptviewController(PresentationController):
if os.name == u'nt': if os.name == u'nt':
def check_installed(self): def check_installed(self):
""" """
Check the viewer is installed Check the viewer is installed.
""" """
log.debug(u'Check installed') log.debug(u'Check installed')
try: try:
@ -79,14 +80,14 @@ class PptviewController(PresentationController):
def start_process(self): def start_process(self):
""" """
Loads the PPTVIEWLIB library Loads the PPTVIEWLIB library.
""" """
if self.process: if self.process:
return return
log.debug(u'start PPTView') log.debug(u'start PPTView')
dllpath = os.path.join(self.plugin_manager.base_path, u'presentations', u'lib', u'pptviewlib', dll_path = os.path.join(
u'pptviewlib.dll') self.plugin_manager.base_path, u'presentations', u'lib', u'pptviewlib', u'pptviewlib.dll')
self.process = cdll.LoadLibrary(dllpath) self.process = cdll.LoadLibrary(dll_path)
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
self.process.SetDebug(1) self.process.SetDebug(1)
@ -101,33 +102,32 @@ class PptviewController(PresentationController):
class PptviewDocument(PresentationDocument): class PptviewDocument(PresentationDocument):
""" """
Class which holds information and controls a single presentation 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 Constructor, store information about the file and initialise.
""" """
log.debug(u'Init Presentation PowerPoint') log.debug(u'Init Presentation PowerPoint')
PresentationDocument.__init__(self, controller, presentation) PresentationDocument.__init__(self, controller, presentation)
self.presentation = None self.presentation = None
self.pptid = None self.ppt_id = None
self.blanked = False self.blanked = False
self.hidden = False self.hidden = False
def load_presentation(self): def load_presentation(self):
""" """
Called when a presentation is added to the SlideController. Called when a presentation is added to the SlideController. It builds the environment, starts communication with
It builds the environment, starts communication with the background the background PptView task started earlier.
PptView task started earlier.
""" """
log.debug(u'LoadPresentation') log.debug(u'LoadPresentation')
rect = ScreenList().current[u'size'] size = ScreenList().current[u'size']
rect = RECT(rect.x(), rect.y(), rect.right(), rect.bottom()) rect = RECT(size.x(), size.y(), size.right(), size.bottom())
filepath = str(self.filepath.replace(u'/', u'\\')) filepath = str(self.filepath.replace(u'/', u'\\'))
if not os.path.isdir(self.get_temp_folder()): if not os.path.isdir(self.get_temp_folder()):
os.makedirs(self.get_temp_folder()) os.makedirs(self.get_temp_folder())
self.pptid = self.controller.process.OpenPPT(filepath, None, rect, str(self.get_temp_folder()) + '\\slide') self.ppt_id = self.controller.process.OpenPPT(filepath, None, rect, str(self.get_temp_folder()) + '\\slide')
if self.pptid >= 0: if self.ppt_id >= 0:
self.create_thumbnails() self.create_thumbnails()
self.stop_presentation() self.stop_presentation()
return True return True
@ -136,8 +136,7 @@ class PptviewDocument(PresentationDocument):
def create_thumbnails(self): def create_thumbnails(self):
""" """
PPTviewLib creates large BMP's, but we want small PNG's for consistency. PPTviewLib creates large BMP's, but we want small PNG's for consistency. Convert them here.
Convert them here.
""" """
log.debug(u'create_thumbnails') log.debug(u'create_thumbnails')
if self.check_thumbnails(): if self.check_thumbnails():
@ -149,21 +148,20 @@ class PptviewDocument(PresentationDocument):
def close_presentation(self): def close_presentation(self):
""" """
Close presentation and clean up objects Close presentation and clean up objects. Triggered by new object being added to SlideController or OpenLP being
Triggered by new object being added to SlideController orOpenLP shut down.
being shut down
""" """
log.debug(u'ClosePresentation') log.debug(u'ClosePresentation')
if self.controller.process: if self.controller.process:
self.controller.process.ClosePPT(self.pptid) self.controller.process.ClosePPT(self.ppt_id)
self.pptid = -1 self.ppt_id = -1
self.controller.remove_doc(self) self.controller.remove_doc(self)
def is_loaded(self): def is_loaded(self):
""" """
Returns true if a presentation is loaded Returns true if a presentation is loaded.
""" """
if self.pptid < 0: if self.ppt_id < 0:
return False return False
if self.get_slide_count() < 0: if self.get_slide_count() < 0:
return False return False
@ -171,74 +169,74 @@ class PptviewDocument(PresentationDocument):
def is_active(self): def is_active(self):
""" """
Returns true if a presentation is currently active Returns true if a presentation is currently active.
""" """
return self.is_loaded() and not self.hidden return self.is_loaded() and not self.hidden
def blank_screen(self): def blank_screen(self):
""" """
Blanks the screen Blanks the screen.
""" """
self.controller.process.Blank(self.pptid) self.controller.process.Blank(self.ppt_id)
self.blanked = True self.blanked = True
def unblank_screen(self): def unblank_screen(self):
""" """
Unblanks (restores) the presentation Unblanks (restores) the presentation.
""" """
self.controller.process.Unblank(self.pptid) self.controller.process.Unblank(self.ppt_id)
self.blanked = False self.blanked = False
def is_blank(self): def is_blank(self):
""" """
Returns true if screen is blank Returns true if screen is blank.
""" """
log.debug(u'is blank OpenOffice') log.debug(u'is blank OpenOffice')
return self.blanked return self.blanked
def stop_presentation(self): def stop_presentation(self):
""" """
Stops the current presentation and hides the output Stops the current presentation and hides the output.
""" """
self.hidden = True self.hidden = True
self.controller.process.Stop(self.pptid) self.controller.process.Stop(self.ppt_id)
def start_presentation(self): def start_presentation(self):
""" """
Starts a presentation from the beginning Starts a presentation from the beginning.
""" """
if self.hidden: if self.hidden:
self.hidden = False self.hidden = False
self.controller.process.Resume(self.pptid) self.controller.process.Resume(self.ppt_id)
else: else:
self.controller.process.RestartShow(self.pptid) self.controller.process.RestartShow(self.ppt_id)
def get_slide_number(self): def get_slide_number(self):
""" """
Returns the current slide number Returns the current slide number.
""" """
return self.controller.process.GetCurrentSlide(self.pptid) return self.controller.process.GetCurrentSlide(self.ppt_id)
def get_slide_count(self): def get_slide_count(self):
""" """
Returns total number of slides Returns total number of slides.
""" """
return self.controller.process.GetSlideCount(self.pptid) return self.controller.process.GetSlideCount(self.ppt_id)
def goto_slide(self, slideno): def goto_slide(self, slideno):
""" """
Moves to a specific slide in the presentation Moves to a specific slide in the presentation.
""" """
self.controller.process.GotoSlide(self.pptid, slideno) self.controller.process.GotoSlide(self.ppt_id, slideno)
def next_step(self): def next_step(self):
""" """
Triggers the next effect of slide on the running presentation Triggers the next effect of slide on the running presentation.
""" """
self.controller.process.NextStep(self.pptid) self.controller.process.NextStep(self.ppt_id)
def previous_step(self): def previous_step(self):
""" """
Triggers the previous slide on the running presentation Triggers the previous slide on the running presentation.
""" """
self.controller.process.PrevStep(self.pptid) self.controller.process.PrevStep(self.ppt_id)

View File

@ -40,9 +40,8 @@ log = logging.getLogger(__name__)
class PresentationDocument(object): class PresentationDocument(object):
""" """
Base class for presentation documents to inherit from. Base class for presentation documents to inherit from. Loads and closes the presentation as well as triggering the
Loads and closes the presentation as well as triggering the correct correct activities based on the users input
activities based on the users input
**Hook Functions** **Hook Functions**
@ -131,20 +130,17 @@ class PresentationDocument(object):
""" """
The location where thumbnail images will be stored The location where thumbnail images will be stored
""" """
return os.path.join( return os.path.join(self.controller.thumbnail_folder, self.get_file_name())
self.controller.thumbnail_folder, self.get_file_name())
def get_temp_folder(self): def get_temp_folder(self):
""" """
The location where thumbnail images will be stored The location where thumbnail images will be stored
""" """
return os.path.join( return os.path.join(self.controller.temp_folder, self.get_file_name())
self.controller.temp_folder, self.get_file_name())
def check_thumbnails(self): def check_thumbnails(self):
""" """
Returns ``True`` if the thumbnail images exist and are more recent than Returns ``True`` if the thumbnail images exist and are more recent than the powerpoint file.
the powerpoint file.
""" """
lastimage = self.get_thumbnail_path(self.get_slide_count(), True) lastimage = self.get_thumbnail_path(self.get_slide_count(), True)
if not (lastimage and os.path.isfile(lastimage)): if not (lastimage and os.path.isfile(lastimage)):
@ -153,8 +149,7 @@ class PresentationDocument(object):
def close_presentation(self): def close_presentation(self):
""" """
Close presentation and clean up objects Close presentation and clean up objects. Triggered by new object being added to SlideController
Triggered by new object being added to SlideController
""" """
self.controller.close_presentation() self.controller.close_presentation()
@ -223,8 +218,8 @@ class PresentationDocument(object):
def next_step(self): def next_step(self):
""" """
Triggers the next effect of slide on the running presentation Triggers the next effect of slide on the running presentation. This might be the next animation on the current
This might be the next animation on the current slide, or the next slide slide, or the next slide
""" """
pass pass
@ -236,8 +231,7 @@ class PresentationDocument(object):
def convert_thumbnail(self, file, idx): def convert_thumbnail(self, file, idx):
""" """
Convert the slide image the application made to a standard 320x240 Convert the slide image the application made to a standard 320x240 .png image.
.png image.
""" """
if self.check_thumbnails(): if self.check_thumbnails():
return return
@ -281,7 +275,7 @@ class PresentationDocument(object):
Returns the text on the slide Returns the text on the slide
``slide_no`` ``slide_no``
The slide the text is required for, starting at 1 The slide the text is required for, starting at 1
""" """
return '' return ''
@ -290,24 +284,21 @@ class PresentationDocument(object):
Returns the text on the slide Returns the text on the slide
``slide_no`` ``slide_no``
The slide the notes are required for, starting at 1 The slide the notes are required for, starting at 1
""" """
return '' return ''
class PresentationController(object): class PresentationController(object):
""" """
This class is used to control interactions with presentation applications This class is used to control interactions with presentation applications by creating a runtime environment. This is
by creating a runtime environment. This is a base class for presentation a base class for presentation controllers to inherit from.
controllers to inherit from.
To create a new controller, take a copy of this file and name it so it ends To create a new controller, take a copy of this file and name it so it ends with ``controller.py``, i.e.
with ``controller.py``, i.e. ``foobarcontroller.py``. Make sure it inherits ``foobarcontroller.py``. Make sure it inherits
:class:`~openlp.plugins.presentations.lib.presentationcontroller.PresentationController`, :class:`~openlp.plugins.presentations.lib.presentationcontroller.PresentationController`, and then fill in the
and then fill in the blanks. If possible try to make sure it loads on all blanks. If possible try to make sure it loads on all platforms, usually by using :mod:``os.name`` checks, although
platforms, usually by using :mod:``os.name`` checks, although ``__init__``, ``check_available`` and ``presentation_deleted`` should always be implemented.
``__init__``, ``check_available`` and ``presentation_deleted`` should
always be implemented.
See :class:`~openlp.plugins.presentations.lib.impresscontroller.ImpressController`, See :class:`~openlp.plugins.presentations.lib.impresscontroller.ImpressController`,
:class:`~openlp.plugins.presentations.lib.powerpointcontroller.PowerpointController` or :class:`~openlp.plugins.presentations.lib.powerpointcontroller.PowerpointController` or
@ -317,36 +308,34 @@ class PresentationController(object):
**Basic Attributes** **Basic Attributes**
``name`` ``name``
The name that appears in the options and the media manager The name that appears in the options and the media manager.
``enabled`` ``enabled``
The controller is enabled The controller is enabled.
``available`` ``available``
The controller is available on this machine. Set by init via The controller is available on this machine. Set by init via call to check_available.
call to check_available
``plugin`` ``plugin``
The presentationplugin object The presentationplugin object.
``supports`` ``supports``
The primary native file types this application supports The primary native file types this application supports.
``alsosupports`` ``alsosupports``
Other file types the application can import, although not necessarily Other file types the application can import, although not necessarily the first choice due to potential
the first choice due to potential incompatibilities incompatibilities.
**Hook Functions** **Hook Functions**
``kill()`` ``kill()``
Called at system exit to clean up any running presentations Called at system exit to clean up any running presentations.
``check_available()`` ``check_available()``
Returns True if presentation application is installed/can run on this Returns True if presentation application is installed/can run on this machine.
machine
``presentation_deleted()`` ``presentation_deleted()``
Deletes presentation specific files, e.g. thumbnails Deletes presentation specific files, e.g. thumbnails.
""" """
log.info(u'PresentationController loaded') log.info(u'PresentationController loaded')
@ -354,9 +343,8 @@ class PresentationController(object):
def __init__(self, plugin=None, name=u'PresentationController', def __init__(self, plugin=None, name=u'PresentationController',
document_class=PresentationDocument): document_class=PresentationDocument):
""" """
This is the constructor for the presentationcontroller object. This This is the constructor for the presentationcontroller object. This provides an easy way for descendent plugins
provides an easy way for descendent plugins to populate common data. to populate common data. This method *must* be overridden, like so::
This method *must* be overridden, like so::
class MyPresentationController(PresentationController): class MyPresentationController(PresentationController):
def __init__(self, plugin): def __init__(self, plugin):
@ -399,28 +387,26 @@ class PresentationController(object):
def check_available(self): def check_available(self):
""" """
Presentation app is able to run on this machine Presentation app is able to run on this machine.
""" """
return False return False
def start_process(self): def start_process(self):
""" """
Loads a running version of the presentation application in the Loads a running version of the presentation application in the background.
background.
""" """
pass pass
def kill(self): def kill(self):
""" """
Called at system exit to clean up any running presentations and Called at system exit to clean up any running presentations and close the application.
close the application
""" """
log.debug(u'Kill') log.debug(u'Kill')
self.close_presentation() self.close_presentation()
def add_document(self, name): def add_document(self, name):
""" """
Called when a new presentation document is opened Called when a new presentation document is opened.
""" """
document = self.document_class(self, name) document = self.document_class(self, name)
self.docs.append(document) self.docs.append(document)
@ -428,7 +414,7 @@ class PresentationController(object):
def remove_doc(self, doc=None): def remove_doc(self, doc=None):
""" """
Called to remove an open document from the collection Called to remove an open document from the collection.
""" """
log.debug(u'remove_doc Presentation') log.debug(u'remove_doc Presentation')
if doc is None: if doc is None:

View File

@ -91,8 +91,7 @@ class PresentationTab(SettingsTab):
if checkbox.isEnabled(): if checkbox.isEnabled():
checkbox.setText(controller.name) checkbox.setText(controller.name)
else: else:
checkbox.setText( checkbox.setText(translate('PresentationPlugin.PresentationTab', '%s (unavailable)') % controller.name)
translate('PresentationPlugin.PresentationTab', '%s (unavailable)') % controller.name)
def load(self): def load(self):
""" """
@ -106,8 +105,8 @@ class PresentationTab(SettingsTab):
def save(self): def save(self):
""" """
Save the settings. If the tab hasn't been made visible to the user then there is nothing to do, Save the settings. If the tab hasn't been made visible to the user then there is nothing to do, so exit. This
so exit. This removes the need to start presentation applications unnecessarily. removes the need to start presentation applications unnecessarily.
""" """
if not self.activated: if not self.activated:
return return

View File

@ -27,8 +27,8 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
The :mod:`presentationplugin` module provides the ability for OpenLP to display The :mod:`presentationplugin` module provides the ability for OpenLP to display presentations from a variety of document
presentations from a variety of document formats. formats.
""" """
import os import os
import logging import logging
@ -39,22 +39,23 @@ from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.core.utils import AppLocation from openlp.core.utils import AppLocation
from openlp.plugins.presentations.lib import PresentationController, PresentationMediaItem, PresentationTab from openlp.plugins.presentations.lib import PresentationController, PresentationMediaItem, PresentationTab
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
__default_settings__ = { __default_settings__ = {
u'presentations/override app': QtCore.Qt.Unchecked, u'presentations/override app': QtCore.Qt.Unchecked,
u'presentations/Impress': QtCore.Qt.Checked, u'presentations/Impress': QtCore.Qt.Checked,
u'presentations/Powerpoint': QtCore.Qt.Checked, u'presentations/Powerpoint': QtCore.Qt.Checked,
u'presentations/Powerpoint Viewer': QtCore.Qt.Checked, u'presentations/Powerpoint Viewer': QtCore.Qt.Checked,
u'presentations/presentations files': [] u'presentations/presentations files': []
} }
class PresentationPlugin(Plugin): class PresentationPlugin(Plugin):
""" """
This plugin allowed a Presentation to be opened, controlled and displayed This plugin allowed a Presentation to be opened, controlled and displayed on the output display. The plugin controls
on the output display. The plugin controls third party applications such third party applications such as OpenOffice.org Impress, Microsoft PowerPoint and the PowerPoint viewer.
as OpenOffice.org Impress, Microsoft PowerPoint and the PowerPoint viewer
""" """
log = logging.getLogger(u'PresentationPlugin') log = logging.getLogger(u'PresentationPlugin')
@ -71,16 +72,14 @@ class PresentationPlugin(Plugin):
def create_settings_tab(self, parent): def create_settings_tab(self, parent):
""" """
Create the settings Tab Create the settings Tab.
""" """
visible_name = self.get_string(StringContent.VisibleName) visible_name = self.get_string(StringContent.VisibleName)
self.settings_tab = PresentationTab(parent, self.name, visible_name[u'title'], self.controllers, self.settings_tab = PresentationTab(parent, self.name, visible_name[u'title'], self.controllers, self.icon_path)
self.icon_path)
def initialise(self): def initialise(self):
""" """
Initialise the plugin. Determine which controllers are enabled Initialise the plugin. Determine which controllers are enabled are start their processes.
are start their processes.
""" """
log.info(u'Presentations Initialising') log.info(u'Presentations Initialising')
Plugin.initialise(self) Plugin.initialise(self)
@ -95,8 +94,8 @@ class PresentationPlugin(Plugin):
def finalise(self): def finalise(self):
""" """
Finalise the plugin. Ask all the enabled presentation applications Finalise the plugin. Ask all the enabled presentation applications to close down their applications and release
to close down their applications and release resources. resources.
""" """
log.info(u'Plugin Finalise') log.info(u'Plugin Finalise')
# Ask each controller to tidy up. # Ask each controller to tidy up.
@ -108,26 +107,23 @@ class PresentationPlugin(Plugin):
def create_media_manager_item(self): def create_media_manager_item(self):
""" """
Create the Media Manager List Create the Media Manager List.
""" """
self.media_item = PresentationMediaItem( self.media_item = PresentationMediaItem(
self.main_window.media_dock_manager.media_dock, self, self.icon, self.controllers) self.main_window.media_dock_manager.media_dock, self, self.icon, self.controllers)
def register_controllers(self, controller): def register_controllers(self, controller):
""" """
Register each presentation controller (Impress, PPT etc) and store for later use Register each presentation controller (Impress, PPT etc) and store for later use.
""" """
self.controllers[controller.name] = controller self.controllers[controller.name] = controller
def check_pre_conditions(self): def check_pre_conditions(self):
""" """
Check to see if we have any presentation software available Check to see if we have any presentation software available. If not do not install the plugin.
If Not do not install the plugin.
""" """
log.debug(u'check_pre_conditions') log.debug(u'check_pre_conditions')
controller_dir = os.path.join( controller_dir = os.path.join(AppLocation.get_directory(AppLocation.PluginsDir), u'presentations', u'lib')
AppLocation.get_directory(AppLocation.PluginsDir),
u'presentations', u'lib')
for filename in os.listdir(controller_dir): for filename in os.listdir(controller_dir):
if filename.endswith(u'controller.py') and not filename == 'presentationcontroller.py': if filename.endswith(u'controller.py') and not filename == 'presentationcontroller.py':
path = os.path.join(controller_dir, filename) path = os.path.join(controller_dir, filename)
@ -146,7 +142,7 @@ class PresentationPlugin(Plugin):
def about(self): def about(self):
""" """
Return information about this plugin Return information about this plugin.
""" """
about_text = translate('PresentationPlugin', '<strong>Presentation ' about_text = translate('PresentationPlugin', '<strong>Presentation '
'Plugin</strong><br />The presentation plugin provides the ' 'Plugin</strong><br />The presentation plugin provides the '
@ -157,7 +153,7 @@ class PresentationPlugin(Plugin):
def set_plugin_text_strings(self): def set_plugin_text_strings(self):
""" """
Called to define all translatable texts of the plugin Called to define all translatable texts of the plugin.
""" """
## Name PluginList ## ## Name PluginList ##
self.text_strings[StringContent.Name] = { self.text_strings[StringContent.Name] = {

View File

@ -27,7 +27,6 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
The :mod:`songusage` module contains the Song Usage plugin. The Song Usage The :mod:`songusage` module contains the Song Usage plugin. The Song Usage plugin provides auditing capabilities for
plugin provides auditing capabilities for reporting the songs you are using to reporting the songs you are using to copyright license organisations.
copyright license organisations.
""" """

View File

@ -55,7 +55,8 @@ class Ui_SongUsageDeleteDialog(object):
self.retranslateUi(song_usage_delete_dialog) self.retranslateUi(song_usage_delete_dialog)
def retranslateUi(self, song_usage_delete_dialog): def retranslateUi(self, song_usage_delete_dialog):
song_usage_delete_dialog.setWindowTitle(translate('SongUsagePlugin.SongUsageDeleteForm', 'Delete Song Usage Data')) song_usage_delete_dialog.setWindowTitle(
translate('SongUsagePlugin.SongUsageDeleteForm', 'Delete Song Usage Data'))
self.delete_label.setText( self.delete_label.setText(
translate('SongUsagePlugin.SongUsageDeleteForm', 'Select the date up to which the song usage data ' translate('SongUsagePlugin.SongUsageDeleteForm', 'Select the date up to which the song usage data '
'should be deleted. All data recorded before this date will be permanently deleted.')) 'should be deleted. All data recorded before this date will be permanently deleted.'))

View File

@ -81,7 +81,8 @@ class Ui_SongUsageDetailDialog(object):
self.save_file_push_button.clicked.connect(song_usage_detail_dialog.define_output_location) self.save_file_push_button.clicked.connect(song_usage_detail_dialog.define_output_location)
def retranslateUi(self, song_usage_detail_dialog): def retranslateUi(self, song_usage_detail_dialog):
song_usage_detail_dialog.setWindowTitle(translate('SongUsagePlugin.SongUsageDetailForm', 'Song Usage Extraction')) song_usage_detail_dialog.setWindowTitle(
translate('SongUsagePlugin.SongUsageDetailForm', 'Song Usage Extraction'))
self.date_range_group_box.setTitle(translate('SongUsagePlugin.SongUsageDetailForm', 'Select Date Range')) self.date_range_group_box.setTitle(translate('SongUsagePlugin.SongUsageDetailForm', 'Select Date Range'))
self.to_label.setText(translate('SongUsagePlugin.SongUsageDetailForm', 'to')) self.to_label.setText(translate('SongUsagePlugin.SongUsageDetailForm', 'to'))
self.file_group_box.setTitle(translate('SongUsagePlugin.SongUsageDetailForm', 'Report Location')) self.file_group_box.setTitle(translate('SongUsagePlugin.SongUsageDetailForm', 'Report Location'))

View File

@ -36,12 +36,14 @@ from sqlalchemy.orm import mapper
from openlp.core.lib.db import BaseModel, init_db from openlp.core.lib.db import BaseModel, init_db
class SongUsageItem(BaseModel): class SongUsageItem(BaseModel):
""" """
SongUsageItem model SongUsageItem model
""" """
pass pass
def init_schema(url): def init_schema(url):
""" """
Setup the songusage database connection and initialise the database schema Setup the songusage database connection and initialise the database schema

View File

@ -48,11 +48,11 @@ if QtCore.QDate().currentDate().month() < 9:
__default_settings__ = { __default_settings__ = {
u'songusage/db type': u'sqlite', u'songusage/db type': u'sqlite',
u'songusage/active': False, u'songusage/active': False,
u'songusage/to date': QtCore.QDate(YEAR, 8, 31), u'songusage/to date': QtCore.QDate(YEAR, 8, 31),
u'songusage/from date': QtCore.QDate(YEAR - 1, 9, 1), u'songusage/from date': QtCore.QDate(YEAR - 1, 9, 1),
u'songusage/last directory export': u'' u'songusage/last directory export': u''
} }
@ -76,12 +76,10 @@ class SongUsagePlugin(Plugin):
def add_tools_menu_item(self, tools_menu): def add_tools_menu_item(self, tools_menu):
""" """
Give the SongUsage plugin the opportunity to add items to the Give the SongUsage plugin the opportunity to add items to the **Tools** menu.
**Tools** menu.
``tools_menu`` ``tools_menu``
The actual **Tools** menu item, so that your actions can The actual **Tools** menu item, so that your actions can use it as their parent.
use it as their parent.
""" """
log.info(u'add tools menu') log.info(u'add tools menu')
self.toolsMenu = tools_menu self.toolsMenu = tools_menu
@ -218,8 +216,8 @@ class SongUsagePlugin(Plugin):
self.song_usage_detail_form.exec_() self.song_usage_detail_form.exec_()
def about(self): def about(self):
about_text = translate('SongUsagePlugin', '<strong>SongUsage Plugin' about_text = translate('SongUsagePlugin',
'</strong><br />This plugin tracks the usage of songs in services.') '<strong>SongUsage Plugin</strong><br />This plugin tracks the usage of songs in services.')
return about_text return about_text
def set_plugin_text_strings(self): def set_plugin_text_strings(self):