For worshipassistant add a default verse-id for lyrics to use if none is given. Fixes bug 1458056.

Don't import setting keys that does not exists. Fixes bug 1458672.
When going from a theme-blanked item to item which doesn't support theme-blanking, switch to black-blank.
Only use transitions if we are changing slide. Fixes bug 1449064.
Make translation of 'Advanced' specific to the bible plugin.
Many PowerPoint fixes/improvements:
 * Make screenshots for main webview, even on single screen setup. Fixes bug 1449041.
 * Implement workaround for unblanking bug in PowerPoint 2010.
 * Open PowerPoint hidden so the main application window isn't visible.
 * Added support for odp for PowerPoint 2007 and newer.
 * Added support for Powerpoint events, which is used to update the slidecontroller if OpenLP is not in focus.
 * Minimized the flashing of the PowerPoint presentation window in the taskbar.

bzr-revno: 2539
This commit is contained in:
Tomas Groth 2015-05-29 17:22:22 +01:00 committed by Tim Bentley
commit 623a0974a5
13 changed files with 289 additions and 104 deletions

View File

@ -1 +1 @@
2.1.3
2.1.4

View File

@ -900,7 +900,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow, RegistryProperties):
for section_key in import_keys:
if 'eneral' in section_key:
section_key = section_key.lower()
value = import_settings.value(section_key)
try:
value = import_settings.value(section_key)
except KeyError:
log.warning('The key "%s" does not exist (anymore), so it will be skipped.' % section_key)
if value is not None:
settings.setValue('%s' % (section_key), value)
now = datetime.now()

View File

@ -828,8 +828,10 @@ class SlideController(DisplayController, RegistryProperties):
self.selected_row = 0
# take a copy not a link to the servicemanager copy.
self.service_item = copy.copy(service_item)
if old_item and self.is_live and old_item.is_capable(ItemCapabilities.ProvidesOwnDisplay):
self._reset_blank()
# Reset blanking if needed
if old_item and self.is_live and (old_item.is_capable(ItemCapabilities.ProvidesOwnDisplay) or
self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay)):
self._reset_blank(self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay))
if service_item.is_command():
Registry().execute(
'%s_start' % service_item.name.lower(), [self.service_item, self.is_live, self.hide_mode(), slide_no])
@ -1080,6 +1082,7 @@ class SlideController(DisplayController, RegistryProperties):
% timeout)
return
row = self.preview_widget.current_slide_number()
old_selected_row = self.selected_row
self.selected_row = 0
if -1 < row < self.preview_widget.slide_count():
if self.service_item.is_command():
@ -1089,7 +1092,7 @@ class SlideController(DisplayController, RegistryProperties):
else:
to_display = self.service_item.get_rendered_frame(row)
if self.service_item.is_text():
self.display.text(to_display)
self.display.text(to_display, row != old_selected_row)
else:
if start:
self.display.build_html(self.service_item, to_display)
@ -1119,8 +1122,7 @@ class SlideController(DisplayController, RegistryProperties):
This updates the preview frame, for example after changing a slide or using *Blank to Theme*.
"""
self.log_debug('update_preview %s ' % self.screens.current['primary'])
if not self.screens.current['primary'] and self.service_item and \
self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay):
if self.service_item and self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay):
# Grab now, but try again in a couple of seconds if slide change is slow
QtCore.QTimer.singleShot(0.5, self.grab_maindisplay)
QtCore.QTimer.singleShot(2.5, self.grab_maindisplay)
@ -1349,7 +1351,11 @@ class SlideController(DisplayController, RegistryProperties):
:param item: The service item to be processed
"""
self.media_controller.video(self.controller_type, item, self.hide_mode())
if self.is_live and self.hide_mode() == HideMode.Theme:
self.media_controller.video(self.controller_type, item, HideMode.Blank)
self.on_blank_display(True)
else:
self.media_controller.video(self.controller_type, item, self.hide_mode())
if not self.is_live:
self.preview_display.show()
self.slide_preview.hide()
@ -1362,16 +1368,22 @@ class SlideController(DisplayController, RegistryProperties):
self.preview_display.hide()
self.slide_preview.show()
def _reset_blank(self):
def _reset_blank(self, no_theme):
"""
Used by command items which provide their own displays to reset the
screen hide attributes
:param no_theme: Does the new item support theme-blanking.
"""
hide_mode = self.hide_mode()
if hide_mode == HideMode.Blank:
self.on_blank_display(True)
elif hide_mode == HideMode.Theme:
self.on_theme_display(True)
# The new item-type doesn't support theme-blanking, so 'switch' to normal blanking.
if no_theme:
self.on_blank_display(True)
else:
self.on_theme_display(True)
elif hide_mode == HideMode.Screen:
self.on_hide_display(True)
else:

View File

@ -193,7 +193,7 @@ class BibleMediaItem(MediaManagerItem):
self.add_search_fields('quick', translate('BiblesPlugin.MediaItem', 'Quick'))
self.quickTab.setVisible(True)
# Add the Advanced Search tab.
self.add_search_tab('advanced', UiStrings().Advanced)
self.add_search_tab('advanced', translate('BiblesPlugin.MediaItem', 'Advanced'))
self.advanced_book_label = QtGui.QLabel(self.advancedTab)
self.advanced_book_label.setObjectName('advanced_book_label')
self.advancedLayout.addWidget(self.advanced_book_label, 0, 0, QtCore.Qt.AlignRight)

View File

@ -243,6 +243,9 @@ class Controller(object):
Instruct the controller to stop and hide the presentation.
"""
log.debug('Live = %s, stop' % self.is_live)
# Save the current slide number to be able to return to this slide if the presentation is activated again.
if self.doc.is_active():
self.doc.slidenumber = self.doc.get_slide_number()
self.hide_mode = HideMode.Screen
if not self.doc:
return
@ -266,8 +269,6 @@ class Controller(object):
return
if not self.activate():
return
if self.doc.slidenumber and self.doc.slidenumber != self.doc.get_slide_number():
self.doc.goto_slide(self.doc.slidenumber)
self.doc.unblank_screen()
Registry().execute('live_display_hide', HideMode.Screen)

View File

@ -32,12 +32,15 @@ import time
from openlp.core.common import is_win, Settings
if is_win():
from win32com.client import Dispatch
from win32com.client import DispatchWithEvents
import win32com
import win32con
import winreg
import win32ui
import win32gui
import pywintypes
from openlp.core.lib import ScreenList
from openlp.core.lib.ui import UiStrings, critical_error_message_box, translate
from openlp.core.common import trace_error_handler, Registry
@ -70,8 +73,18 @@ class PowerpointController(PresentationController):
if is_win():
try:
winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, 'PowerPoint.Application').Close()
try:
# Try to detect if the version is 12 (2007) or above, and if so add 'odp' as a support filetype
version_key = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, 'PowerPoint.Application\\CurVer')
tmp1, app_version_string, tmp2 = winreg.EnumValue(version_key, 0)
version_key.Close()
app_version = int(app_version_string[-2:])
if app_version >= 12:
self.also_supports = ['odp']
except (OSError, ValueError):
log.warning('Detection of powerpoint version using registry failed.')
return True
except WindowsError:
except OSError:
pass
return False
@ -80,12 +93,22 @@ class PowerpointController(PresentationController):
"""
Loads PowerPoint process.
"""
class PowerPointEvents:
"""
Class to catch events from PowerPoint.
"""
def OnSlideShowNextClick(self, slideshow_window, effect):
"""
Occurs on the next click of the slide.
If the main OpenLP window is not in focus force update of the slidecontroller.
"""
if not Registry().get('main_window').isActiveWindow():
log.debug('main window is not in focus - should update slidecontroller')
Registry().execute('slidecontroller_live_change', slideshow_window.View.CurrentShowPosition)
log.debug('start_process')
if not self.process:
self.process = Dispatch('PowerPoint.Application')
self.process.Visible = True
# ppWindowMinimized = 2
self.process.WindowState = 2
self.process = DispatchWithEvents('PowerPoint.Application', PowerPointEvents)
def kill(self):
"""
@ -124,6 +147,9 @@ class PowerpointDocument(PresentationDocument):
self.presentation = None
self.index_map = {}
self.slide_count = 0
self.blank_slide = 1
self.blank_click = None
self.presentation_hwnd = None
def load_presentation(self):
"""
@ -132,23 +158,15 @@ class PowerpointDocument(PresentationDocument):
"""
log.debug('load_presentation')
try:
if not self.controller.process or not self.controller.process.Visible:
if not self.controller.process:
self.controller.start_process()
self.controller.process.Presentations.Open(self.file_path, False, False, True)
self.controller.process.Presentations.Open(os.path.normpath(self.file_path), False, False, False)
self.presentation = self.controller.process.Presentations(self.controller.process.Presentations.Count)
self.create_thumbnails()
self.create_titles_and_notes()
# Powerpoint 2010 and 2013 pops up when loading a file, so we minimize it again
if float(self.presentation.Application.Version) >= 14.0:
try:
# ppWindowMinimized = 2
self.presentation.Application.WindowState = 2
except (AttributeError, pywintypes.com_error) as e:
log.exception('Failed to minimize main powerpoint window')
log.exception(e)
trace_error_handler(log)
# Make sure powerpoint doesn't steal focus
Registry().get('main_window').activateWindow()
# Make sure powerpoint doesn't steal focus, unless we're on a single screen setup
if len(ScreenList().screen_list) > 1:
Registry().get('main_window').activateWindow()
return True
except (AttributeError, pywintypes.com_error) as e:
log.exception('Exception caught while loading Powerpoint presentation')
@ -194,8 +212,9 @@ class PowerpointDocument(PresentationDocument):
trace_error_handler(log)
self.presentation = None
self.controller.remove_doc(self)
# Make sure powerpoint doesn't steal focus
Registry().get('main_window').activateWindow()
# Make sure powerpoint doesn't steal focus, unless we're on a single screen setup
if len(ScreenList().screen_list) > 1:
Registry().get('main_window').activateWindow()
def is_loaded(self):
"""
@ -203,10 +222,6 @@ class PowerpointDocument(PresentationDocument):
"""
log.debug('is_loaded')
try:
if not self.controller.process.Visible:
return False
if self.controller.process.Windows.Count == 0:
return False
if self.controller.process.Presentations.Count == 0:
return False
except (AttributeError, pywintypes.com_error) as e:
@ -241,13 +256,11 @@ class PowerpointDocument(PresentationDocument):
"""
log.debug('unblank_screen')
try:
self.presentation.SlideShowSettings.Run()
# ppSlideShowRunning = 1
self.presentation.SlideShowWindow.View.State = 1
self.presentation.SlideShowWindow.Activate()
# Unblanking is broken in PowerPoint 2010 and 2013, need to redisplay
if float(self.presentation.Application.Version) >= 14.0:
self.presentation.SlideShowWindow.View.GotoSlide(self.blank_slide, False)
self.presentation.SlideShowWindow.View.State = 1
# Unblanking is broken in PowerPoint 2010 (14.0), need to redisplay
if 15.0 > float(self.presentation.Application.Version) >= 14.0:
self.presentation.SlideShowWindow.View.GotoSlide(self.index_map[self.blank_slide], False)
if self.blank_click:
self.presentation.SlideShowWindow.View.GotoClick(self.blank_click)
except (AttributeError, pywintypes.com_error) as e:
@ -255,8 +268,12 @@ class PowerpointDocument(PresentationDocument):
log.exception(e)
trace_error_handler(log)
self.show_error_msg()
# Make sure powerpoint doesn't steal focus
Registry().get('main_window').activateWindow()
# Stop powerpoint from flashing in the taskbar
if self.presentation_hwnd:
win32gui.FlashWindowEx(self.presentation_hwnd, win32con.FLASHW_STOP, 0, 0)
# Make sure powerpoint doesn't steal focus, unless we're on a single screen setup
if len(ScreenList().screen_list) > 1:
Registry().get('main_window').activateWindow()
def blank_screen(self):
"""
@ -264,8 +281,8 @@ class PowerpointDocument(PresentationDocument):
"""
log.debug('blank_screen')
try:
# Unblanking is broken in PowerPoint 2010 and 2013, need to save info for later
if float(self.presentation.Application.Version) >= 14.0:
# Unblanking is broken in PowerPoint 2010 (14.0), need to save info for later
if 15.0 > float(self.presentation.Application.Version) >= 14.0:
self.blank_slide = self.get_slide_number()
self.blank_click = self.presentation.SlideShowWindow.View.GetClickIndex()
# ppSlideShowBlackScreen = 3
@ -295,7 +312,7 @@ class PowerpointDocument(PresentationDocument):
def stop_presentation(self):
"""
Stops the current presentation and hides the output.
Stops the current presentation and hides the output. Used when blanking to desktop.
"""
log.debug('stop_presentation')
try:
@ -321,28 +338,52 @@ class PowerpointDocument(PresentationDocument):
except win32ui.error:
dpi = 96
size = ScreenList().current['size']
ppt_window = self.presentation.SlideShowSettings.Run()
if not ppt_window:
return
ppt_window = None
try:
ppt_window.Top = size.y() * 72 / dpi
ppt_window.Height = size.height() * 72 / dpi
ppt_window.Left = size.x() * 72 / dpi
ppt_window.Width = size.width() * 72 / dpi
except AttributeError as e:
log.exception('AttributeError while in start_presentation')
ppt_window = self.presentation.SlideShowSettings.Run()
except (AttributeError, pywintypes.com_error) as e:
log.exception('Caught exception while in start_presentation')
log.exception(e)
# Powerpoint 2010 and 2013 pops up when starting a file, so we minimize it again
if float(self.presentation.Application.Version) >= 14.0:
trace_error_handler(log)
self.show_error_msg()
if ppt_window and not Settings().value('presentations/powerpoint control window'):
try:
# ppWindowMinimized = 2
self.presentation.Application.WindowState = 2
except (AttributeError, pywintypes.com_error) as e:
log.exception('Failed to minimize main powerpoint window')
ppt_window.Top = size.y() * 72 / dpi
ppt_window.Height = size.height() * 72 / dpi
ppt_window.Left = size.x() * 72 / dpi
ppt_window.Width = size.width() * 72 / dpi
except AttributeError as e:
log.exception('AttributeError while in start_presentation')
log.exception(e)
trace_error_handler(log)
# Make sure powerpoint doesn't steal focus
Registry().get('main_window').activateWindow()
# Find the presentation window and save the handle for later
self.presentation_hwnd = None
if ppt_window:
log.debug('main display size: y=%d, height=%d, x=%d, width=%d'
% (size.y(), size.height(), size.x(), size.width()))
win32gui.EnumWindows(self._window_enum_callback, size)
# Make sure powerpoint doesn't steal focus, unless we're on a single screen setup
if len(ScreenList().screen_list) > 1:
Registry().get('main_window').activateWindow()
def _window_enum_callback(self, hwnd, size):
"""
Method for callback from win32gui.EnumWindows.
Used to find the powerpoint presentation window and stop it flashing in the taskbar.
"""
# Get the size of the current window and if it matches the size of our main display we assume
# it is the powerpoint presentation window.
(left, top, right, bottom) = win32gui.GetWindowRect(hwnd)
window_title = win32gui.GetWindowText(hwnd)
log.debug('window size: left=%d, top=%d, right=%d, width=%d' % (left, top, right, bottom))
log.debug('compare size: %d and %d, %d and %d, %d and %d, %d and %d'
% (size.y(), top, size.height(), (bottom - top), size.x(), left, size.width(), (right - left)))
log.debug('window title: %s' % window_title)
if size.y() == top and size.height() == (bottom - top) and size.x() == left and \
size.width() == (right - left) and os.path.basename(self.file_path) in window_title:
log.debug('Found a match and will save the handle')
self.presentation_hwnd = hwnd
# Stop powerpoint from flashing in the taskbar
win32gui.FlashWindowEx(self.presentation_hwnd, win32con.FLASHW_STOP, 0, 0)
def get_slide_number(self):
"""
@ -384,7 +425,7 @@ class PowerpointDocument(PresentationDocument):
log.debug('goto_slide')
try:
if Settings().value('presentations/powerpoint slide click advance') \
and self.get_slide_number() == self.index_map[slide_no]:
and self.get_slide_number() == slide_no:
click_index = self.presentation.SlideShowWindow.View.GetClickIndex()
click_count = self.presentation.SlideShowWindow.View.GetClickCount()
log.debug('We are already on this slide - go to next effect if any left, idx: %d, count: %d'
@ -405,6 +446,7 @@ class PowerpointDocument(PresentationDocument):
"""
log.debug('next_step')
try:
self.presentation.SlideShowWindow.Activate()
self.presentation.SlideShowWindow.View.Next()
except (AttributeError, pywintypes.com_error) as e:
log.exception('Caught exception while in next_step')
@ -415,6 +457,12 @@ class PowerpointDocument(PresentationDocument):
if self.get_slide_number() > self.get_slide_count():
log.debug('past end, stepping back to previous')
self.previous_step()
# Stop powerpoint from flashing in the taskbar
if self.presentation_hwnd:
win32gui.FlashWindowEx(self.presentation_hwnd, win32con.FLASHW_STOP, 0, 0)
# Make sure powerpoint doesn't steal focus, unless we're on a single screen setup
if len(ScreenList().screen_list) > 1:
Registry().get('main_window').activateWindow()
def previous_step(self):
"""
@ -490,8 +538,12 @@ def _get_text_from_shapes(shapes):
:param shapes: A set of shapes to search for text.
"""
text = ''
for shape in shapes:
if shape.PlaceholderFormat.Type == 2: # 2 from is enum PpPlaceholderType.ppPlaceholderBody
if shape.HasTextFrame and shape.TextFrame.HasText:
text += shape.TextFrame.TextRange.Text + '\n'
try:
for shape in shapes:
if shape.PlaceholderFormat.Type == 2: # 2 from is enum PpPlaceholderType.ppPlaceholderBody
if shape.HasTextFrame and shape.TextFrame.HasText:
text += shape.TextFrame.TextRange.Text + '\n'
except pywintypes.com_error as e:
log.warning('Failed to extract text from powerpoint slide')
log.warning(e)
return text

View File

@ -74,8 +74,11 @@ class PresentationTab(SettingsTab):
self.powerpoint_layout = QtGui.QVBoxLayout(self.powerpoint_group_box)
self.powerpoint_layout.setObjectName('powerpoint_layout')
self.ppt_slide_click_check_box = QtGui.QCheckBox(self.powerpoint_group_box)
self.powerpoint_group_box.setObjectName('ppt_slide_click_check_box')
self.ppt_slide_click_check_box.setObjectName('ppt_slide_click_check_box')
self.powerpoint_layout.addWidget(self.ppt_slide_click_check_box)
self.ppt_window_check_box = QtGui.QCheckBox(self.powerpoint_group_box)
self.ppt_window_check_box.setObjectName('ppt_window_check_box')
self.powerpoint_layout.addWidget(self.ppt_window_check_box)
self.left_layout.addWidget(self.powerpoint_group_box)
# Pdf options
self.pdf_group_box = QtGui.QGroupBox(self.left_column)
@ -123,6 +126,9 @@ class PresentationTab(SettingsTab):
self.ppt_slide_click_check_box.setText(
translate('PresentationPlugin.PresentationTab',
'Clicking on a selected slide in the slidecontroller advances to next effect.'))
self.ppt_window_check_box.setText(
translate('PresentationPlugin.PresentationTab',
'Let PowerPoint control the size and position of the presentation window.'))
self.pdf_program_check_box.setText(
translate('PresentationPlugin.PresentationTab', 'Use given full path for mudraw or ghostscript binary:'))
@ -148,6 +154,8 @@ class PresentationTab(SettingsTab):
self.ppt_slide_click_check_box.setChecked(Settings().value(self.settings_section +
'/powerpoint slide click advance'))
self.ppt_slide_click_check_box.setEnabled(powerpoint_available)
self.ppt_window_check_box.setChecked(Settings().value(self.settings_section + '/powerpoint control window'))
self.ppt_window_check_box.setEnabled(powerpoint_available)
# load pdf-program settings
enable_pdf_program = Settings().value(self.settings_section + '/enable_pdf_program')
self.pdf_program_check_box.setChecked(enable_pdf_program)
@ -186,6 +194,10 @@ class PresentationTab(SettingsTab):
if Settings().value(setting_key) != self.ppt_slide_click_check_box.checkState():
Settings().setValue(setting_key, self.ppt_slide_click_check_box.checkState())
changed = True
setting_key = self.settings_section + '/powerpoint control window'
if Settings().value(setting_key) != self.ppt_window_check_box.checkState():
Settings().setValue(setting_key, self.ppt_window_check_box.checkState())
changed = True
# Save pdf-settings
pdf_program = self.pdf_program_path.text()
enable_pdf_program = self.pdf_program_check_box.checkState()

View File

@ -45,7 +45,8 @@ __default_settings__ = {'presentations/override app': QtCore.Qt.Unchecked,
'presentations/Pdf': QtCore.Qt.Checked,
'presentations/presentations files': [],
'presentations/thumbnail_scheme': '',
'presentations/powerpoint slide click advance': QtCore.Qt.Unchecked
'presentations/powerpoint slide click advance': QtCore.Qt.Unchecked,
'presentations/powerpoint control window': QtCore.Qt.Unchecked
}

View File

@ -131,6 +131,7 @@ class WorshipAssistantImport(SongImport):
return
verse = ''
used_verses = []
verse_id = VerseType.tags[VerseType.Verse] + '1'
for line in lyrics.splitlines():
if line.startswith('['): # verse marker
# Add previous verse

View File

@ -164,45 +164,42 @@ class TestPowerpointDocument(TestCase, TestMixin):
"""
Test creating the titles from PowerPoint
"""
if is_win() and self.real_controller.check_available():
# GIVEN: mocked save_titles_and_notes, _get_text_from_shapes and two mocked slides
self.doc = PowerpointDocument(self.real_controller, self.file_name)
self.doc.save_titles_and_notes = MagicMock()
self.doc._PowerpointDocument__get_text_from_shapes = MagicMock()
slide = MagicMock()
slide.Shapes.Title.TextFrame.TextRange.Text = 'SlideText'
pres = MagicMock()
pres.Slides = [slide, slide]
self.doc.presentation = pres
# GIVEN: mocked save_titles_and_notes, _get_text_from_shapes and two mocked slides
self.doc = PowerpointDocument(self.mock_controller, self.file_name)
self.doc.get_slide_count = MagicMock()
self.doc.get_slide_count.return_value = 2
self.doc.index_map = {1: 1, 2: 2}
self.doc.save_titles_and_notes = MagicMock()
self.doc._PowerpointDocument__get_text_from_shapes = MagicMock()
slide = MagicMock()
slide.Shapes.Title.TextFrame.TextRange.Text = 'SlideText'
pres = MagicMock()
pres.Slides = MagicMock(side_effect=[slide, slide])
self.doc.presentation = pres
# WHEN reading the titles and notes
self.doc.create_titles_and_notes()
# WHEN reading the titles and notes
self.doc.create_titles_and_notes()
# THEN the save should have been called exactly once with 2 titles and 2 notes
self.doc.save_titles_and_notes.assert_called_once_with(['SlideText\n', 'SlideText\n'], [' ', ' '])
else:
self.skipTest('Powerpoint not available, skipping test.')
# THEN the save should have been called exactly once with 2 titles and 2 notes
self.doc.save_titles_and_notes.assert_called_once_with(['SlideText\n', 'SlideText\n'], [' ', ' '])
def create_titles_and_notes_with_no_slides_test(self):
"""
Test creating the titles from PowerPoint when it returns no slides
"""
if is_win() and self.real_controller.check_available():
# GIVEN: mocked save_titles_and_notes, _get_text_from_shapes and two mocked slides
doc = PowerpointDocument(self.real_controller, self.file_name)
doc.save_titles_and_notes = MagicMock()
doc._PowerpointDocument__get_text_from_shapes = MagicMock()
pres = MagicMock()
pres.Slides = []
doc.presentation = pres
# GIVEN: mocked save_titles_and_notes, _get_text_from_shapes and two mocked slides
doc = PowerpointDocument(self.mock_controller, self.file_name)
doc.save_titles_and_notes = MagicMock()
doc._PowerpointDocument__get_text_from_shapes = MagicMock()
pres = MagicMock()
pres.Slides = []
doc.presentation = pres
# WHEN reading the titles and notes
doc.create_titles_and_notes()
# WHEN reading the titles and notes
doc.create_titles_and_notes()
# THEN the save should have been called exactly once with empty titles and notes
doc.save_titles_and_notes.assert_called_once_with([], [])
else:
self.skipTest('Powerpoint not available, skipping test.')
# THEN the save should have been called exactly once with empty titles and notes
doc.save_titles_and_notes.assert_called_once_with([], [])
def get_text_from_shapes_test(self):
"""
@ -253,3 +250,54 @@ class TestPowerpointDocument(TestCase, TestMixin):
# THEN: next_step() should be call to try to advance to the next effect.
self.assertTrue(doc.next_step.called, 'next_step() should have been called!')
def blank_screen_test(self):
"""
Test that blank_screen works as expected
"""
# GIVEN: A Document with mocked controller, presentation, and mocked function get_slide_number
doc = PowerpointDocument(self.mock_controller, self.mock_presentation)
doc.presentation = MagicMock()
doc.presentation.SlideShowWindow.View.GetClickIndex.return_value = 3
doc.presentation.Application.Version = 14.0
doc.get_slide_number = MagicMock()
doc.get_slide_number.return_value = 2
# WHEN: Calling goto_slide
doc.blank_screen()
# THEN: The view state, doc.blank_slide and doc.blank_click should have new values
self.assertEquals(doc.presentation.SlideShowWindow.View.State, 3, 'The View State should be 3')
self.assertEquals(doc.blank_slide, 2, 'doc.blank_slide should be 2 because of the PowerPoint version')
self.assertEquals(doc.blank_click, 3, 'doc.blank_click should be 3 because of the PowerPoint version')
def unblank_screen_test(self):
"""
Test that unblank_screen works as expected
"""
# GIVEN: A Document with mocked controller, presentation, ScreenList, and mocked function get_slide_number
with patch('openlp.plugins.presentations.lib.powerpointcontroller.ScreenList') as mocked_screen_list:
mocked_screen_list_ret = MagicMock()
mocked_screen_list_ret.screen_list = [1]
mocked_screen_list.return_value = mocked_screen_list_ret
doc = PowerpointDocument(self.mock_controller, self.mock_presentation)
doc.presentation = MagicMock()
doc.presentation.SlideShowWindow.View.GetClickIndex.return_value = 3
doc.presentation.Application.Version = 14.0
doc.get_slide_number = MagicMock()
doc.get_slide_number.return_value = 2
doc.index_map[1] = 1
doc.blank_slide = 1
doc.blank_click = 1
# WHEN: Calling goto_slide
doc.unblank_screen()
# THEN: The view state have new value, and several function should have been called
self.assertEquals(doc.presentation.SlideShowWindow.View.State, 1, 'The View State should be 1')
self.assertEquals(doc.presentation.SlideShowWindow.Activate.called, True,
'SlideShowWindow.Activate should have been called')
self.assertEquals(doc.presentation.SlideShowWindow.View.GotoSlide.called, True,
'View.GotoSlide should have been called because of the PowerPoint version')
self.assertEquals(doc.presentation.SlideShowWindow.View.GotoClick.called, True,
'View.GotoClick should have been called because of the PowerPoint version')

View File

@ -49,3 +49,5 @@ class TestWorshipAssistantFileImport(SongImportTestHelper):
self.load_external_result_data(os.path.join(TEST_PATH, 'would_you_be_free.json')))
self.file_import(os.path.join(TEST_PATH, 'would_you_be_free2.csv'),
self.load_external_result_data(os.path.join(TEST_PATH, 'would_you_be_free.json')))
self.file_import(os.path.join(TEST_PATH, 'lift_up_your_heads.csv'),
self.load_external_result_data(os.path.join(TEST_PATH, 'lift_up_your_heads.json')))

View File

@ -0,0 +1,40 @@
"SongID","SongNr","Title","Author","Copyright","FirstLine","PriKey","AltKey","Tempo","Focus","Theme","Scripture","Active","Songbook","TimeSig","Introduced","LastUsed","TimesUsed","CCLINr","User1","User2","User3","User4","User5","Roadmap","Overmap","FileLink1","FileLink2","Updated","Lyrics","Info","Lyrics2","Background"
"000013ab-0000-0000-0000-000000000000","0","Lift Up Your Heads"," Bryan Mierau","Public Domain","Lift up your heads and the doors","Em","NULL","NULL","NULL","NULL","NULL","1","1","NULL","NULL","NULL","0","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","NULL","2004-04-07 06:36:18.952",".Em D C D
Lift up your heads and the doors of your heart
. Am B7 Em
And the King of glory will come in
(Repeat)
.G Am D
Who is this King of Glory?
. B7 Em
The Lord strong and mighty!
.G Am D
Who is this King of Glory?
. B7
The Lord, mighty in battle!
.G Am D
Who is this King of Glory?
.B7 Em
Jesus our Messiah!
.G Am D
Who is this King of Glory?
.B7 Em
Jesus, Lord of Lords!
","NULL","Lift up your heads and the doors of your heart
And the King of glory will come in
(Repeat)
Who is this King of Glory?
The Lord strong and mighty!
Who is this King of Glory?
The Lord, mighty in battle!
Who is this King of Glory?
Jesus our Messiah!
Who is this King of Glory?
Jesus, Lord of Lords!
","NULL"
1 SongID SongNr Title Author Copyright FirstLine PriKey AltKey Tempo Focus Theme Scripture Active Songbook TimeSig Introduced LastUsed TimesUsed CCLINr User1 User2 User3 User4 User5 Roadmap Overmap FileLink1 FileLink2 Updated Lyrics Info Lyrics2 Background
2 000013ab-0000-0000-0000-000000000000 0 Lift Up Your Heads Bryan Mierau Public Domain Lift up your heads and the doors Em NULL NULL NULL NULL NULL 1 1 NULL NULL NULL 0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 2004-04-07 06:36:18.952 .Em D C D Lift up your heads and the doors of your heart . Am B7 Em And the King of glory will come in (Repeat) .G Am D Who is this King of Glory? . B7 Em The Lord strong and mighty! .G Am D Who is this King of Glory? . B7 The Lord, mighty in battle! .G Am D Who is this King of Glory? .B7 Em Jesus our Messiah! .G Am D Who is this King of Glory? .B7 Em Jesus, Lord of Lords! NULL Lift up your heads and the doors of your heart And the King of glory will come in (Repeat) Who is this King of Glory? The Lord strong and mighty! Who is this King of Glory? The Lord, mighty in battle! Who is this King of Glory? Jesus our Messiah! Who is this King of Glory? Jesus, Lord of Lords! NULL

View File

@ -0,0 +1,13 @@
{
"authors": [
"Bryan Mierau"
],
"title": "Lift Up Your Heads",
"verse_order_list": [],
"verses": [
[
"Lift up your heads and the doors of your heart\nAnd the King of glory will come in\n(Repeat)\n\nWho is this King of Glory?\nThe Lord strong and mighty!\nWho is this King of Glory?\nThe Lord, mighty in battle!\n\nWho is this King of Glory?\nJesus our Messiah!\nWho is this King of Glory?\nJesus, Lord of Lords!\n",
"v1"
]
]
}