forked from openlp/openlp
Head
This commit is contained in:
parent
2d2576aa6c
commit
57dd0897ae
@ -1,17 +1,16 @@
|
||||
stages:
|
||||
- lint
|
||||
- test
|
||||
- deploy
|
||||
|
||||
lint-python:
|
||||
stage: lint
|
||||
stage: test
|
||||
image: openlp/debian
|
||||
script:
|
||||
- sh scripts/generate_resources.sh
|
||||
- flake8
|
||||
|
||||
lint-javascript:
|
||||
stage: lint
|
||||
stage: test
|
||||
image: openlp/angular
|
||||
script:
|
||||
- yarn install
|
||||
|
@ -43,6 +43,26 @@ var VerticalAlign = {
|
||||
Bottom: 2
|
||||
};
|
||||
|
||||
/**
|
||||
* Transition type enumeration
|
||||
*/
|
||||
var TransitionType = {
|
||||
Fade: 0,
|
||||
Slide: 1,
|
||||
Convex: 2,
|
||||
Concave: 3,
|
||||
Zoom: 4
|
||||
};
|
||||
|
||||
/**
|
||||
* Transition speed enumeration
|
||||
*/
|
||||
var TransitionSpeed = {
|
||||
Normal: 0,
|
||||
Fast: 1,
|
||||
Slow: 2
|
||||
};
|
||||
|
||||
/**
|
||||
* Audio state enumeration
|
||||
*/
|
||||
@ -329,6 +349,7 @@ var Display = {
|
||||
_alertState: AlertState.NotDisplaying,
|
||||
_transitionState: TransitionState.NoTransition,
|
||||
_animationState: AnimationState.NoAnimation,
|
||||
_doTransitions: false,
|
||||
_revealConfig: {
|
||||
margin: 0.0,
|
||||
minScale: 1.0,
|
||||
@ -348,21 +369,25 @@ var Display = {
|
||||
/**
|
||||
* Start up reveal and do any other initialisation
|
||||
*/
|
||||
init: function () {
|
||||
init: function (doTransitions=false) {
|
||||
Display._doTransitions = doTransitions;
|
||||
Reveal.initialize(Display._revealConfig);
|
||||
},
|
||||
/**
|
||||
* Reinitialise Reveal
|
||||
*/
|
||||
reinit: function () {
|
||||
Reveal.reinitialize();
|
||||
Reveal.sync();
|
||||
// Python expects to be on first page after reinit
|
||||
Reveal.slide(0);
|
||||
},
|
||||
/**
|
||||
* Set the transition type
|
||||
* @param {string} transitionType - Can be one of "none", "fade", "slide", "convex", "concave", "zoom"
|
||||
* @param {string} transitionSpeed - Can be one of "default", "fast", "slow"
|
||||
*/
|
||||
setTransition: function (transitionType) {
|
||||
Reveal.configure({"transition": transitionType});
|
||||
setTransition: function (transitionType, transitionSpeed) {
|
||||
Reveal.configure({"transition": transitionType, "transitionSpeed": transitionSpeed});
|
||||
},
|
||||
/**
|
||||
* Clear the current list of slides
|
||||
@ -639,7 +664,6 @@ var Display = {
|
||||
Display.addTextSlide(slide.verse, slide.text, slide.footer, false);
|
||||
});
|
||||
Display.reinit();
|
||||
Display.goToSlide(0);
|
||||
},
|
||||
/**
|
||||
* Create the <section> that will contain text slides (vertical slides in react)
|
||||
@ -869,6 +893,44 @@ var Display = {
|
||||
},
|
||||
setTheme: function (theme) {
|
||||
Display._theme = theme;
|
||||
// Set slide transitions
|
||||
var new_transition_type = "none",
|
||||
new_transition_speed = "default";
|
||||
if (!!theme.display_slide_transition && Display._doTransitions) {
|
||||
switch (theme.display_slide_transition_type) {
|
||||
case TransitionType.Fade:
|
||||
new_transition_type = "fade";
|
||||
break;
|
||||
case TransitionType.Slide:
|
||||
new_transition_type = "slide";
|
||||
break;
|
||||
case TransitionType.Convex:
|
||||
new_transition_type = "convex";
|
||||
break;
|
||||
case TransitionType.Concave:
|
||||
new_transition_type = "concave";
|
||||
break;
|
||||
case TransitionType.Zoom:
|
||||
new_transition_type = "zoom";
|
||||
break;
|
||||
default:
|
||||
new_transition_type = "fade";
|
||||
}
|
||||
switch (theme.display_slide_transition_speed) {
|
||||
case TransitionSpeed.Normal:
|
||||
new_transition_speed = "default";
|
||||
break;
|
||||
case TransitionSpeed.Fast:
|
||||
new_transition_speed = "fast";
|
||||
break;
|
||||
case TransitionSpeed.Slow:
|
||||
new_transition_speed = "slow";
|
||||
break;
|
||||
default:
|
||||
new_transition_speed = "default";
|
||||
}
|
||||
}
|
||||
Display.setTransition(new_transition_type, new_transition_speed);
|
||||
// Set the background
|
||||
var globalBackground = $("#global-background")[0];
|
||||
var backgroundStyle = {};
|
||||
@ -986,7 +1048,7 @@ var Display = {
|
||||
default:
|
||||
mainStyle["justify-content"] = "center";
|
||||
}
|
||||
if (theme.hasOwnProperty('font_main_shadow_size')) {
|
||||
if (theme.hasOwnProperty('font_main_shadow_size') && !!theme.font_main_shadow) {
|
||||
mainStyle["text-shadow"] = theme.font_main_shadow_color + " " + theme.font_main_shadow_size + "pt " +
|
||||
theme.font_main_shadow_size + "pt";
|
||||
}
|
||||
|
@ -441,14 +441,6 @@
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Restarts up the presentation if the client is capable.
|
||||
*/
|
||||
function reinitialize() {
|
||||
initialized = false;
|
||||
initialize(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspect the client to see what it's capable of, this
|
||||
* should only happens once per runtime.
|
||||
@ -5814,7 +5806,6 @@
|
||||
VERSION: VERSION,
|
||||
|
||||
initialize: initialize,
|
||||
reinitialize: reinitialize,
|
||||
configure: configure,
|
||||
|
||||
sync: sync,
|
||||
|
@ -109,13 +109,17 @@ class DisplayWindow(QtWidgets.QWidget):
|
||||
Create the display window
|
||||
"""
|
||||
super(DisplayWindow, self).__init__(parent)
|
||||
# Gather all flags for the display window
|
||||
flags = QtCore.Qt.FramelessWindowHint | QtCore.Qt.Tool | QtCore.Qt.WindowStaysOnTopHint
|
||||
if Settings().value('advanced/x11 bypass wm'):
|
||||
flags |= QtCore.Qt.X11BypassWindowManagerHint
|
||||
# Need to import this inline to get around a QtWebEngine issue
|
||||
from openlp.core.display.webengine import WebEngineView
|
||||
self._is_initialised = False
|
||||
self._can_show_startup_screen = can_show_startup_screen
|
||||
self._fbo = None
|
||||
self.setWindowTitle(translate('OpenLP.DisplayWindow', 'Display Window'))
|
||||
self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.Tool | QtCore.Qt.WindowStaysOnTopHint)
|
||||
self.setWindowFlags(flags)
|
||||
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
|
||||
self.setAutoFillBackground(True)
|
||||
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
|
||||
@ -198,13 +202,13 @@ class DisplayWindow(QtWidgets.QWidget):
|
||||
"""
|
||||
Add stuff after page initialisation
|
||||
"""
|
||||
self.run_javascript('Display.init();')
|
||||
js_is_display = str(self.is_display).lower()
|
||||
self.run_javascript('Display.init({do_transitions});'.format(do_transitions=js_is_display))
|
||||
self._is_initialised = True
|
||||
if self._can_show_startup_screen:
|
||||
self.set_startup_screen()
|
||||
# Make sure the scale is set if it was attempted set before init
|
||||
if self.scale != 1:
|
||||
self.set_scale(self.scale)
|
||||
if self._can_show_startup_screen:
|
||||
self.set_startup_screen()
|
||||
|
||||
def run_javascript(self, script, is_sync=False):
|
||||
"""
|
||||
|
@ -11,6 +11,8 @@
|
||||
"display" :{
|
||||
"horizontal_align": 0,
|
||||
"slide_transition": false,
|
||||
"slide_transition_type": 0,
|
||||
"slide_transition_speed": 0,
|
||||
"vertical_align": 0
|
||||
},
|
||||
"font": {
|
||||
|
@ -127,6 +127,82 @@ class BackgroundGradientType(object):
|
||||
return BackgroundGradientType.LeftBottom
|
||||
|
||||
|
||||
class TransitionType(object):
|
||||
"""
|
||||
Type enumeration for transition types.
|
||||
"""
|
||||
Fade = 0
|
||||
Slide = 1
|
||||
Convex = 2
|
||||
Concave = 3
|
||||
Zoom = 4
|
||||
|
||||
@staticmethod
|
||||
def to_string(transition_type):
|
||||
"""
|
||||
Return a string representation of a transition type.
|
||||
"""
|
||||
if transition_type == TransitionType.Fade:
|
||||
return 'fade'
|
||||
elif transition_type == TransitionType.Slide:
|
||||
return 'slide'
|
||||
elif transition_type == TransitionType.Convex:
|
||||
return 'convex'
|
||||
elif transition_type == TransitionType.Concave:
|
||||
return 'concave'
|
||||
elif transition_type == TransitionType.Zoom:
|
||||
return 'zoom'
|
||||
|
||||
@staticmethod
|
||||
def from_string(type_string):
|
||||
"""
|
||||
Return a transition type for the given string.
|
||||
"""
|
||||
if type_string == 'fade':
|
||||
return TransitionType.Fade
|
||||
elif type_string == 'slide':
|
||||
return TransitionType.Slide
|
||||
elif type_string == 'convex':
|
||||
return TransitionType.Convex
|
||||
elif type_string == 'concave':
|
||||
return TransitionType.Concave
|
||||
elif type_string == 'zoom':
|
||||
return TransitionType.Zoom
|
||||
|
||||
|
||||
class TransitionSpeed(object):
|
||||
"""
|
||||
Type enumeration for transition types.
|
||||
"""
|
||||
Normal = 0
|
||||
Fast = 1
|
||||
Slow = 2
|
||||
|
||||
@staticmethod
|
||||
def to_string(transition_speed):
|
||||
"""
|
||||
Return a string representation of a transition type.
|
||||
"""
|
||||
if transition_speed == TransitionSpeed.Normal:
|
||||
return 'normal'
|
||||
elif transition_speed == TransitionSpeed.Fast:
|
||||
return 'fast'
|
||||
elif transition_speed == TransitionSpeed.Slow:
|
||||
return 'slow'
|
||||
|
||||
@staticmethod
|
||||
def from_string(type_string):
|
||||
"""
|
||||
Return a transition type for the given string.
|
||||
"""
|
||||
if type_string == 'normal':
|
||||
return TransitionSpeed.Normal
|
||||
if type_string == 'fast':
|
||||
return TransitionSpeed.Fast
|
||||
elif type_string == 'slow':
|
||||
return TransitionSpeed.Slow
|
||||
|
||||
|
||||
class HorizontalType(object):
|
||||
"""
|
||||
Type enumeration for horizontal alignment.
|
||||
@ -153,7 +229,7 @@ class VerticalType(object):
|
||||
BOOLEAN_LIST = ['bold', 'italics', 'override', 'outline', 'shadow', 'slide_transition']
|
||||
|
||||
INTEGER_LIST = ['size', 'line_adjustment', 'x', 'height', 'y', 'width', 'shadow_size', 'outline_size',
|
||||
'horizontal_align', 'vertical_align', 'wrap_style']
|
||||
'horizontal_align', 'vertical_align', 'wrap_style', 'slide_transition_type', 'slide_transition_speed']
|
||||
|
||||
|
||||
class Theme(object):
|
||||
@ -204,12 +280,21 @@ class Theme(object):
|
||||
Set the header and footer size into the current primary screen.
|
||||
10 px on each side is removed to allow for a border.
|
||||
"""
|
||||
self.set_default_header()
|
||||
self.set_default_footer()
|
||||
|
||||
def set_default_header(self):
|
||||
current_screen_geometry = ScreenList().current.display_geometry
|
||||
self.font_main_x = 10
|
||||
self.font_main_y = 0
|
||||
self.font_main_width = current_screen_geometry.width() - 20
|
||||
self.font_main_height = current_screen_geometry.height() * 9 / 10
|
||||
self.font_footer_width = current_screen_geometry.width() - 20
|
||||
|
||||
def set_default_footer(self):
|
||||
current_screen_geometry = ScreenList().current.display_geometry
|
||||
self.font_footer_x = 10
|
||||
self.font_footer_y = current_screen_geometry.height() * 9 / 10
|
||||
self.font_footer_width = current_screen_geometry.width() - 20
|
||||
self.font_footer_height = current_screen_geometry.height() / 10
|
||||
|
||||
def load_theme(self, theme, theme_path=None):
|
||||
|
@ -62,6 +62,7 @@ class UiIcons(metaclass=Singleton):
|
||||
'authentication': {'icon': 'fa.exclamation-triangle', 'attr': 'red'},
|
||||
'address': {'icon': 'fa.book'},
|
||||
'back': {'icon': 'fa.step-backward'},
|
||||
'backspace': {'icon': 'mdi.backspace-outline'},
|
||||
'bible': {'icon': 'fa.book'},
|
||||
'blank': {'icon': 'fa.times-circle'},
|
||||
'blank_theme': {'icon': 'fa.file-image-o'},
|
||||
|
@ -670,6 +670,10 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, LogMixin, RegistryPropert
|
||||
self.application.process_events()
|
||||
plugin.first_time()
|
||||
self.application.process_events()
|
||||
# Load the themes from files
|
||||
self.theme_manager_contents.load_first_time_themes()
|
||||
# Update the theme widget
|
||||
self.theme_manager_contents.load_themes()
|
||||
temp_path = Path(gettempdir(), 'openlp')
|
||||
shutil.rmtree(temp_path, True)
|
||||
|
||||
@ -714,10 +718,6 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, LogMixin, RegistryPropert
|
||||
self.active_plugin.toggle_status(PluginStatus.Inactive)
|
||||
# Set global theme and
|
||||
Registry().execute('theme_update_global')
|
||||
# Load the themes from files
|
||||
self.theme_manager_contents.load_first_time_themes()
|
||||
# Update the theme widget
|
||||
self.theme_manager_contents.load_themes()
|
||||
# Check if any Bibles downloaded. If there are, they will be processed.
|
||||
Registry().execute('bibles_load_list')
|
||||
self.application.set_normal_cursor()
|
||||
|
@ -323,16 +323,23 @@ class ShortcutListForm(QtWidgets.QDialog, Ui_ShortcutListDialog, RegistryPropert
|
||||
if not toggled:
|
||||
return
|
||||
action = self._current_item_action()
|
||||
shortcuts = self._action_shortcuts(action)
|
||||
self.refresh_shortcut_list()
|
||||
primary_button_text = ''
|
||||
alternate_button_text = ''
|
||||
if shortcuts:
|
||||
primary_button_text = self.get_shortcut_string(shortcuts[0], for_display=True)
|
||||
if len(shortcuts) == 2:
|
||||
alternate_button_text = self.get_shortcut_string(shortcuts[1], for_display=True)
|
||||
self.primary_push_button.setText(primary_button_text)
|
||||
self.alternate_push_button.setText(alternate_button_text)
|
||||
if action is None:
|
||||
QtWidgets.QMessageBox.information(self, translate('OpenLP.ShortcutListForm', 'Select an Action'),
|
||||
translate('OpenLP.ShortcutListForm', 'Select an action and click one '
|
||||
'of the buttons below to start '
|
||||
'capturing a new primary or alternate shortcut, respectively.'))
|
||||
|
||||
else:
|
||||
shortcuts = self._action_shortcuts(action)
|
||||
self.refresh_shortcut_list()
|
||||
primary_button_text = ''
|
||||
alternate_button_text = ''
|
||||
if shortcuts:
|
||||
primary_button_text = self.get_shortcut_string(shortcuts[0], for_display=True)
|
||||
if len(shortcuts) == 2:
|
||||
alternate_button_text = self.get_shortcut_string(shortcuts[1], for_display=True)
|
||||
self.primary_push_button.setText(primary_button_text)
|
||||
self.alternate_push_button.setText(alternate_button_text)
|
||||
|
||||
def save(self):
|
||||
"""
|
||||
|
@ -98,6 +98,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
|
||||
self.main_font_combo_box.activated.connect(self.calculate_lines)
|
||||
self.footer_font_combo_box.activated.connect(self.update_theme)
|
||||
self.footer_size_spin_box.valueChanged.connect(self.update_theme)
|
||||
self.transitions_check_box.stateChanged.connect(self.on_transitions_check_box_state_changed)
|
||||
|
||||
def set_defaults(self):
|
||||
"""
|
||||
@ -145,6 +146,8 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
|
||||
self.background_page.registerField('horizontal', self.horizontal_combo_box)
|
||||
self.background_page.registerField('vertical', self.vertical_combo_box)
|
||||
self.background_page.registerField('slide_transition', self.transitions_check_box)
|
||||
self.background_page.registerField('slide_transition_type', self.transition_combo_box)
|
||||
self.background_page.registerField('slide_transition_speed', self.transition_speed_combo_box)
|
||||
self.background_page.registerField('name', self.theme_name_edit)
|
||||
|
||||
def calculate_lines(self):
|
||||
@ -251,10 +254,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
|
||||
Change state as Shadow check box changed
|
||||
"""
|
||||
if self.update_theme_allowed:
|
||||
if state == QtCore.Qt.Checked:
|
||||
self.theme.font_main_shadow = True
|
||||
else:
|
||||
self.theme.font_main_shadow = False
|
||||
self.theme.font_main_shadow = state == QtCore.Qt.Checked
|
||||
self.shadow_color_button.setEnabled(self.theme.font_main_shadow)
|
||||
self.shadow_size_spin_box.setEnabled(self.theme.font_main_shadow)
|
||||
self.calculate_lines()
|
||||
@ -275,6 +275,16 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
|
||||
if self.update_theme_allowed:
|
||||
self.theme.font_footer_override = (value != QtCore.Qt.Checked)
|
||||
|
||||
def on_transitions_check_box_state_changed(self, state):
|
||||
"""
|
||||
Change state as Transitions check box is changed
|
||||
"""
|
||||
if self.update_theme_allowed:
|
||||
self.theme.display_slide_transition = state == QtCore.Qt.Checked
|
||||
self.transition_combo_box.setEnabled(self.theme.display_slide_transition)
|
||||
self.transition_speed_combo_box.setEnabled(self.theme.display_slide_transition)
|
||||
self.calculate_lines()
|
||||
|
||||
def exec(self, edit=False):
|
||||
"""
|
||||
Run the wizard.
|
||||
@ -395,6 +405,8 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
|
||||
self.setField('horizontal', self.theme.display_horizontal_align)
|
||||
self.setField('vertical', self.theme.display_vertical_align)
|
||||
self.setField('slide_transition', self.theme.display_slide_transition)
|
||||
self.setField('slide_transition_type', self.theme.display_slide_transition_type)
|
||||
self.setField('slide_transition_speed', self.theme.display_slide_transition_speed)
|
||||
|
||||
def set_preview_page_values(self):
|
||||
"""
|
||||
@ -525,19 +537,28 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
|
||||
# footer page
|
||||
self.theme.font_footer_name = self.footer_font_combo_box.currentFont().family()
|
||||
self.theme.font_footer_size = self.field('footer_size_spin_box')
|
||||
# position page
|
||||
self.theme.font_main_x = self.field('main_position_x')
|
||||
self.theme.font_main_y = self.field('main_position_y')
|
||||
self.theme.font_main_height = self.field('main_position_height')
|
||||
self.theme.font_main_width = self.field('main_position_width')
|
||||
self.theme.font_footer_x = self.field('footer_position_x')
|
||||
self.theme.font_footer_y = self.field('footer_position_y')
|
||||
self.theme.font_footer_height = self.field('footer_position_height')
|
||||
self.theme.font_footer_width = self.field('footer_position_width')
|
||||
# position page (main)
|
||||
if self.theme.font_main_override:
|
||||
self.theme.font_main_x = self.field('main_position_x')
|
||||
self.theme.font_main_y = self.field('main_position_y')
|
||||
self.theme.font_main_height = self.field('main_position_height')
|
||||
self.theme.font_main_width = self.field('main_position_width')
|
||||
else:
|
||||
self.theme.set_default_header()
|
||||
# position page (footer)
|
||||
if self.theme.font_footer_override:
|
||||
self.theme.font_footer_x = self.field('footer_position_x')
|
||||
self.theme.font_footer_y = self.field('footer_position_y')
|
||||
self.theme.font_footer_height = self.field('footer_position_height')
|
||||
self.theme.font_footer_width = self.field('footer_position_width')
|
||||
else:
|
||||
self.theme.set_default_footer()
|
||||
# position page
|
||||
self.theme.display_horizontal_align = self.horizontal_combo_box.currentIndex()
|
||||
self.theme.display_vertical_align = self.vertical_combo_box.currentIndex()
|
||||
self.theme.display_slide_transition = self.field('slide_transition')
|
||||
self.theme.display_slide_transition_type = self.field('slide_transition_type')
|
||||
self.theme.display_slide_transition_speed = self.field('slide_transition_speed')
|
||||
|
||||
def accept(self):
|
||||
"""
|
||||
|
@ -149,16 +149,15 @@ class ThemeManager(QtWidgets.QWidget, RegistryBase, Ui_ThemeManager, LogMixin, R
|
||||
process the bootstrap initialise setup request
|
||||
"""
|
||||
self.setup_ui(self)
|
||||
self.progress_form = ThemeProgressForm(self)
|
||||
self.global_theme = Settings().value(self.settings_section + '/global theme')
|
||||
self.build_theme_path()
|
||||
self.load_first_time_themes()
|
||||
self.upgrade_themes() # TODO: Can be removed when upgrade path from OpenLP 2.4 no longer needed
|
||||
|
||||
def bootstrap_post_set_up(self):
|
||||
"""
|
||||
process the bootstrap post setup request
|
||||
"""
|
||||
self.progress_form = ThemeProgressForm(self)
|
||||
self.theme_form = ThemeForm(self)
|
||||
self.theme_form.path = self.theme_path
|
||||
self.file_rename_form = FileRenameForm()
|
||||
@ -481,7 +480,8 @@ class ThemeManager(QtWidgets.QWidget, RegistryBase, Ui_ThemeManager, LogMixin, R
|
||||
self.save_theme(theme)
|
||||
Settings().setValue(self.settings_section + '/global theme', theme.theme_name)
|
||||
new_themes = [theme.theme_name]
|
||||
self.update_preview_images(new_themes)
|
||||
if new_themes:
|
||||
self.update_preview_images(new_themes)
|
||||
self.application.set_normal_cursor()
|
||||
|
||||
def load_themes(self):
|
||||
|
@ -36,6 +36,8 @@ class ThemeProgressForm(QtWidgets.QDialog, UiThemeProgressDialog, RegistryProper
|
||||
super().__init__(parent)
|
||||
self.setup_ui(self)
|
||||
self._theme_list = []
|
||||
|
||||
def show(self):
|
||||
self.progress_bar.setMinimum(0)
|
||||
self.progress_bar.setMaximum(0)
|
||||
self.progress_bar.setValue(0)
|
||||
@ -45,6 +47,7 @@ class ThemeProgressForm(QtWidgets.QDialog, UiThemeProgressDialog, RegistryProper
|
||||
except ZeroDivisionError:
|
||||
self.ratio = 16 / 9
|
||||
self.theme_preview_layout.aspect_ratio = self.ratio
|
||||
return super().show()
|
||||
|
||||
def get_preview(self, theme_name, theme_data):
|
||||
self.label.setText(theme_name)
|
||||
|
@ -25,7 +25,13 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from openlp.core.common import is_macosx
|
||||
from openlp.core.common.i18n import UiStrings, translate
|
||||
from openlp.core.lib.theme import BackgroundGradientType, BackgroundType, HorizontalType
|
||||
from openlp.core.lib.theme import (
|
||||
BackgroundGradientType,
|
||||
BackgroundType,
|
||||
HorizontalType,
|
||||
TransitionType,
|
||||
TransitionSpeed
|
||||
)
|
||||
from openlp.core.lib.ui import add_welcome_page, create_valign_selection_widgets
|
||||
from openlp.core.ui.icons import UiIcons
|
||||
from openlp.core.widgets.buttons import ColorButton
|
||||
@ -271,12 +277,22 @@ class Ui_ThemeWizard(object):
|
||||
self.vertical_label.setObjectName('vertical_label')
|
||||
self.vertical_combo_box.setObjectName('vertical_combo_box')
|
||||
self.alignment_layout.addRow(self.vertical_label, self.vertical_combo_box)
|
||||
self.transitions_label = QtWidgets.QLabel(self.alignment_page)
|
||||
self.transitions_label.setObjectName('transitions_label')
|
||||
self.transitions_check_box = QtWidgets.QCheckBox(self.alignment_page)
|
||||
self.transitions_check_box.setObjectName('transitions_check_box')
|
||||
self.alignment_layout.addRow(self.transitions_label, self.transitions_check_box)
|
||||
self.alignment_layout.setItem(3, QtWidgets.QFormLayout.LabelRole, self.spacer)
|
||||
self.transition_layout = QtWidgets.QHBoxLayout()
|
||||
self.transition_layout.setObjectName("transition_layout")
|
||||
self.transition_combo_box = QtWidgets.QComboBox(self.alignment_page)
|
||||
self.transition_combo_box.setObjectName("transition_combo_box")
|
||||
self.transition_combo_box.addItems(['', '', '', '', ''])
|
||||
self.transition_layout.addWidget(self.transition_combo_box)
|
||||
self.transition_speed_label = QtWidgets.QLabel(self.alignment_page)
|
||||
self.transition_speed_label.setObjectName("transition_speed_label")
|
||||
self.transition_layout.addWidget(self.transition_speed_label)
|
||||
self.transition_speed_combo_box = QtWidgets.QComboBox(self.alignment_page)
|
||||
self.transition_speed_combo_box.setObjectName("transition_speed_combo_box")
|
||||
self.transition_speed_combo_box.addItems(['', '', ''])
|
||||
self.transition_layout.addWidget(self.transition_speed_combo_box)
|
||||
self.alignment_layout.addRow(self.transitions_check_box, self.transition_layout)
|
||||
theme_wizard.addPage(self.alignment_page)
|
||||
# Area Position Page
|
||||
self.area_position_page = QtWidgets.QWizardPage()
|
||||
@ -460,7 +476,16 @@ class Ui_ThemeWizard(object):
|
||||
self.horizontal_combo_box.setItemText(HorizontalType.Right, translate('OpenLP.ThemeWizard', 'Right'))
|
||||
self.horizontal_combo_box.setItemText(HorizontalType.Center, translate('OpenLP.ThemeWizard', 'Center'))
|
||||
self.horizontal_combo_box.setItemText(HorizontalType.Justify, translate('OpenLP.ThemeWizard', 'Justify'))
|
||||
self.transitions_label.setText(translate('OpenLP.ThemeWizard', 'Transitions:'))
|
||||
self.transitions_check_box.setText(translate('OpenLP.ThemeWizard', 'Transitions:'))
|
||||
self.transition_combo_box.setItemText(TransitionType.Fade, translate('OpenLP.ThemeWizard', 'Fade'))
|
||||
self.transition_combo_box.setItemText(TransitionType.Slide, translate('OpenLP.ThemeWizard', 'Slide'))
|
||||
self.transition_combo_box.setItemText(TransitionType.Concave, translate('OpenLP.ThemeWizard', 'Concave'))
|
||||
self.transition_combo_box.setItemText(TransitionType.Convex, translate('OpenLP.ThemeWizard', 'Convex'))
|
||||
self.transition_combo_box.setItemText(TransitionType.Zoom, translate('OpenLP.ThemeWizard', 'Zoom'))
|
||||
self.transition_speed_label.setText(translate('OpenLP.ThemeWizard', 'Speed:'))
|
||||
self.transition_speed_combo_box.setItemText(TransitionSpeed.Normal, translate('OpenLP.ThemeWizard', 'Normal'))
|
||||
self.transition_speed_combo_box.setItemText(TransitionSpeed.Fast, translate('OpenLP.ThemeWizard', 'Fast'))
|
||||
self.transition_speed_combo_box.setItemText(TransitionSpeed.Slow, translate('OpenLP.ThemeWizard', 'Slow'))
|
||||
self.area_position_page.setTitle(translate('OpenLP.ThemeWizard', 'Output Area Locations'))
|
||||
self.area_position_page.setSubTitle(translate('OpenLP.ThemeWizard', 'Allows you to change and move the'
|
||||
' Main and Footer areas.'))
|
||||
|
@ -64,7 +64,7 @@ class SearchEdit(QtWidgets.QLineEdit):
|
||||
self.settings_section = settings_section
|
||||
self._current_search_type = -1
|
||||
self.clear_button = QtWidgets.QToolButton(self)
|
||||
self.clear_button.setIcon(UiIcons().shortcuts)
|
||||
self.clear_button.setIcon(UiIcons().backspace)
|
||||
self.clear_button.setCursor(QtCore.Qt.ArrowCursor)
|
||||
self.clear_button.setStyleSheet('QToolButton { border: none; padding: 0px; }')
|
||||
self.clear_button.resize(18, 18)
|
||||
|
@ -765,13 +765,72 @@ p, li { white-space: pre-wrap; }
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="transitionsCheckBox">
|
||||
<property name="text">
|
||||
<string>Transitions</string>
|
||||
<string>Transitions:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="transitionLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="transitionComboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Fade</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Slide</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Convex</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Concave</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Zoom</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="transitionSpeedLabel">
|
||||
<property name="text">
|
||||
<string>Speed:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="transitionSpeedComboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Normal</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Fast</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Slow</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWizardPage" name="areaPositionPage">
|
||||
|
@ -1,25 +0,0 @@
|
||||
--- reveal.js.orig 2018-08-01 10:37:51.000000000 +0200
|
||||
+++ reveal.js 2019-02-11 21:25:39.396198927 +0100
|
||||
@@ -383,6 +383,14 @@
|
||||
}
|
||||
|
||||
/**
|
||||
+ * Restarts up the presentation if the client is capable.
|
||||
+ */
|
||||
+ function reinitialize() {
|
||||
+ initialized = false;
|
||||
+ initialize(config);
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
* Inspect the client to see what it's capable of, this
|
||||
* should only happens once per runtime.
|
||||
*/
|
||||
@@ -5372,6 +5380,7 @@
|
||||
VERSION: VERSION,
|
||||
|
||||
initialize: initialize,
|
||||
+ reinitialize: reinitialize,
|
||||
configure: configure,
|
||||
|
||||
sync: sync,
|
@ -144,6 +144,23 @@ class TestInit(TestCase, TestMixin):
|
||||
# THEN: the result will be as expected - try again
|
||||
assert str(value) == 'called'
|
||||
|
||||
def test_requires_auth_missing_credentials(self):
|
||||
"""
|
||||
Test the requires_auth wrapper with enabled security and authorization taken place and and error
|
||||
:return:
|
||||
"""
|
||||
# GIVEN: An enabled security and a known user
|
||||
Settings().setValue('api/authentication enabled', True)
|
||||
Settings().setValue('api/user id', 'superfly')
|
||||
Settings().setValue('api/password', 'lamas')
|
||||
|
||||
# WHEN: I call the function with no password
|
||||
wrapped_function = requires_auth(func)
|
||||
value = wrapped_function(0)
|
||||
|
||||
# THEN: the result will be as expected (unauthorized)
|
||||
assert str(value) == str(authenticate())
|
||||
|
||||
|
||||
def func(field=None):
|
||||
return 'called'
|
||||
|
76
tests/functional/openlp_core/display/test_window.py
Normal file
76
tests/functional/openlp_core/display/test_window.py
Normal file
@ -0,0 +1,76 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
##########################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# ---------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2019 OpenLP Developers #
|
||||
# ---------------------------------------------------------------------- #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||
##########################################################################
|
||||
"""
|
||||
Package to test the openlp.core.display.window package.
|
||||
"""
|
||||
import sys
|
||||
|
||||
from unittest import TestCase
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from PyQt5 import QtCore
|
||||
|
||||
# Mock QtWebEngineWidgets
|
||||
sys.modules['PyQt5.QtWebEngineWidgets'] = MagicMock()
|
||||
|
||||
from openlp.core.display.window import DisplayWindow
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
|
||||
|
||||
@patch('PyQt5.QtWidgets.QVBoxLayout')
|
||||
@patch('openlp.core.display.webengine.WebEngineView')
|
||||
@patch('openlp.core.display.window.Settings')
|
||||
class TestDisplayWindow(TestCase, TestMixin):
|
||||
"""
|
||||
A test suite to test the functions in DisplayWindow
|
||||
"""
|
||||
|
||||
def test_x11_override_on(self, MockSettings, mocked_webengine, mocked_addWidget):
|
||||
"""
|
||||
Test that the x11 override option bit is set
|
||||
"""
|
||||
# GIVEN: x11 bypass is on
|
||||
mocked_settings = MagicMock()
|
||||
mocked_settings.value.return_value = True
|
||||
MockSettings.return_value = mocked_settings
|
||||
|
||||
# WHEN: A DisplayWindow is generated
|
||||
display_window = DisplayWindow()
|
||||
|
||||
# THEN: The x11 override flag should be set
|
||||
x11_bit = display_window.windowFlags() & QtCore.Qt.X11BypassWindowManagerHint
|
||||
assert x11_bit == QtCore.Qt.X11BypassWindowManagerHint
|
||||
|
||||
def test_x11_override_off(self, MockSettings, mocked_webengine, mocked_addWidget):
|
||||
"""
|
||||
Test that the x11 override option bit is not set when setting if off
|
||||
"""
|
||||
# GIVEN: x11 bypass is off
|
||||
mocked_settings = MagicMock()
|
||||
mocked_settings.value.return_value = False
|
||||
MockSettings.return_value = mocked_settings
|
||||
|
||||
# WHEN: A DisplayWindow is generated
|
||||
display_window = DisplayWindow()
|
||||
|
||||
# THEN: The x11 override flag should not be set
|
||||
x11_bit = display_window.windowFlags() & QtCore.Qt.X11BypassWindowManagerHint
|
||||
assert x11_bit != QtCore.Qt.X11BypassWindowManagerHint
|
@ -23,6 +23,7 @@ Package to test the openlp.core.lib.theme package.
|
||||
"""
|
||||
from pathlib import Path
|
||||
from unittest import TestCase
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from openlp.core.lib.theme import BackgroundType, Theme
|
||||
|
||||
@ -175,10 +176,83 @@ class TestTheme(TestCase):
|
||||
lt.load_theme(save_theme_json)
|
||||
self.check_theme(lt)
|
||||
|
||||
@patch('openlp.core.display.screens.ScreenList.current')
|
||||
def test_set_default_footer(self, mock_geometry):
|
||||
"""
|
||||
Test the set_default_footer function sets the footer back to default
|
||||
(reletive to the screen)
|
||||
"""
|
||||
# GIVEN: A screen geometry object and a Theme footer with a strange area
|
||||
mock_geometry.display_geometry = MagicMock()
|
||||
mock_geometry.display_geometry.height.return_value = 600
|
||||
mock_geometry.display_geometry.width.return_value = 400
|
||||
theme = Theme()
|
||||
theme.font_main_x = 20
|
||||
theme.font_footer_x = 207
|
||||
theme.font_footer_y = 25
|
||||
theme.font_footer_width = 4253
|
||||
theme.font_footer_height = 5423
|
||||
|
||||
# WHEN: set_default_footer is called
|
||||
theme.set_default_footer()
|
||||
|
||||
# THEN: footer should be set, header should not have changed
|
||||
assert theme.font_main_x == 20, 'header should not have been changed'
|
||||
assert theme.font_footer_x == 10, 'x pos should be reset to default of 10'
|
||||
assert theme.font_footer_y == 540, 'y pos should be reset to (screen_size_height * 9 / 10)'
|
||||
assert theme.font_footer_width == 380, 'width should have been reset to (screen_size_width - 20)'
|
||||
assert theme.font_footer_height == 60, 'height should have been reset to (screen_size_height / 10)'
|
||||
|
||||
@patch('openlp.core.display.screens.ScreenList.current')
|
||||
def test_set_default_header(self, mock_geometry):
|
||||
"""
|
||||
Test the set_default_header function sets the header back to default
|
||||
(reletive to the screen)
|
||||
"""
|
||||
# GIVEN: A screen geometry object and a Theme header with a strange area
|
||||
mock_geometry.display_geometry = MagicMock()
|
||||
mock_geometry.display_geometry.height.return_value = 600
|
||||
mock_geometry.display_geometry.width.return_value = 400
|
||||
theme = Theme()
|
||||
theme.font_footer_x = 200
|
||||
theme.font_main_x = 687
|
||||
theme.font_main_y = 546
|
||||
theme.font_main_width = 345
|
||||
theme.font_main_height = 653
|
||||
|
||||
# WHEN: set_default_header is called
|
||||
theme.set_default_header()
|
||||
|
||||
# THEN: footer should be set, header should not have changed
|
||||
assert theme.font_footer_x == 200, 'footer should not have been changed'
|
||||
assert theme.font_main_x == 10, 'x pos should be reset to default of 10'
|
||||
assert theme.font_main_y == 0, 'y pos should be reset to 0'
|
||||
assert theme.font_main_width == 380, 'width should have been reset to (screen_size_width - 20)'
|
||||
assert theme.font_main_height == 540, 'height should have been reset to (screen_size_height * 9 / 10)'
|
||||
|
||||
@patch('openlp.core.display.screens.ScreenList.current')
|
||||
def test_set_default_header_footer(self, mock_geometry):
|
||||
"""
|
||||
Test the set_default_header_footer function sets the header and footer back to default
|
||||
(reletive to the screen)
|
||||
"""
|
||||
# GIVEN: A screen geometry object and a Theme header with a strange area
|
||||
mock_geometry.display_geometry = MagicMock()
|
||||
theme = Theme()
|
||||
theme.font_footer_x = 200
|
||||
theme.font_main_x = 687
|
||||
|
||||
# WHEN: set_default_header is called
|
||||
theme.set_default_header_footer()
|
||||
|
||||
# THEN: footer should be set, header should not have changed
|
||||
assert theme.font_footer_x == 10, 'footer x pos should be reset to default of 10'
|
||||
assert theme.font_main_x == 10, 'header x pos should be reset to default of 10'
|
||||
|
||||
def check_theme(self, theme):
|
||||
assert '#000000' == theme.background_border_color, 'background_border_color should be "#000000"'
|
||||
assert 'solid' == theme.background_type, 'background_type should be "solid"'
|
||||
assert 0 == theme.display_vertical_align, 'display_vertical_align should be 0'
|
||||
assert theme.font_footer_bold is False, 'font_footer_bold should be False'
|
||||
assert 'Arial' == theme.font_main_name, 'font_main_name should be "Arial"'
|
||||
assert 49 == len(theme.__dict__), 'The theme should have 49 attributes'
|
||||
assert 51 == len(theme.__dict__), 'The theme should have 51 attributes'
|
||||
|
@ -941,10 +941,8 @@ class TestInfoLabel(TestCase):
|
||||
"""
|
||||
Test the paintEvent method when text fits the label
|
||||
"""
|
||||
font = QtGui.QFont()
|
||||
metrics = QtGui.QFontMetrics(font)
|
||||
|
||||
with patch('openlp.core.ui.slidecontroller.QtWidgets.QLabel'), \
|
||||
patch('openlp.core.ui.slidecontroller.QtGui.QFontMetrics') as MockFontMetrics, \
|
||||
patch('openlp.core.ui.slidecontroller.QtGui.QPainter') as mocked_qpainter:
|
||||
|
||||
# GIVEN: An instance of InfoLabel, with mocked text return, width and rect methods
|
||||
@ -957,9 +955,11 @@ class TestInfoLabel(TestCase):
|
||||
info_label.rect = mocked_rect
|
||||
info_label.text = mocked_text
|
||||
info_label.width = mocked_width
|
||||
mocked_font_metrics = MagicMock()
|
||||
mocked_font_metrics.elidedText.return_value = test_string
|
||||
MockFontMetrics.return_value = mocked_font_metrics
|
||||
|
||||
# WHEN: The instance is wider than its text, and the paintEvent method is called
|
||||
info_label.width.return_value = metrics.boundingRect(test_string).width() + 10
|
||||
info_label.paintEvent(MagicMock())
|
||||
|
||||
# THEN: The text should be drawn centered with the complete test_string
|
||||
@ -969,15 +969,14 @@ class TestInfoLabel(TestCase):
|
||||
"""
|
||||
Test the paintEvent method when text fits the label
|
||||
"""
|
||||
font = QtGui.QFont()
|
||||
metrics = QtGui.QFontMetrics(font)
|
||||
|
||||
with patch('openlp.core.ui.slidecontroller.QtWidgets.QLabel'), \
|
||||
patch('openlp.core.ui.slidecontroller.QtGui.QFontMetrics') as MockFontMetrics, \
|
||||
patch('openlp.core.ui.slidecontroller.QtGui.QPainter') as mocked_qpainter:
|
||||
|
||||
# GIVEN: An instance of InfoLabel, with mocked text return, width and rect methods
|
||||
info_label = InfoLabel()
|
||||
test_string = 'Label Text'
|
||||
elided_test_string = test_string[0:5] + '...'
|
||||
mocked_rect = MagicMock()
|
||||
mocked_text = MagicMock()
|
||||
mocked_width = MagicMock()
|
||||
@ -985,14 +984,14 @@ class TestInfoLabel(TestCase):
|
||||
info_label.rect = mocked_rect
|
||||
info_label.text = mocked_text
|
||||
info_label.width = mocked_width
|
||||
mocked_font_metrics = MagicMock()
|
||||
mocked_font_metrics.elidedText.return_value = elided_test_string
|
||||
MockFontMetrics.return_value = mocked_font_metrics
|
||||
|
||||
# WHEN: The instance is narrower than its text, and the paintEvent method is called
|
||||
label_width = metrics.boundingRect(test_string).width() - 10
|
||||
info_label.width.return_value = label_width
|
||||
info_label.paintEvent(MagicMock())
|
||||
|
||||
# THEN: The text should be drawn aligned left with an elided test_string
|
||||
elided_test_string = metrics.elidedText(test_string, QtCore.Qt.ElideRight, label_width)
|
||||
mocked_qpainter().drawText.assert_called_once_with(mocked_rect(), QtCore.Qt.AlignLeft, elided_test_string)
|
||||
|
||||
@patch('builtins.super')
|
||||
|
46
tests/functional/openlp_core/ui/test_splashscreen.py
Normal file
46
tests/functional/openlp_core/ui/test_splashscreen.py
Normal file
@ -0,0 +1,46 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
##########################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# ---------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2019 OpenLP Developers #
|
||||
# ---------------------------------------------------------------------- #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||
##########################################################################
|
||||
"""
|
||||
Package to test the openlp.core.ui package.
|
||||
"""
|
||||
from PyQt5 import QtCore
|
||||
|
||||
from openlp.core.ui.splashscreen import SplashScreen
|
||||
|
||||
|
||||
class TestSplashScreen():
|
||||
"""
|
||||
This will test the SplachScreen.py file
|
||||
"""
|
||||
def test_SplashScreen(self):
|
||||
"""
|
||||
Test that the SpashScreen is created correctly
|
||||
"""
|
||||
# GIVEN: the SplashScreen class
|
||||
# WHEN: An object is created
|
||||
|
||||
ss = SplashScreen()
|
||||
# THEN: Nothing should go wrong and the instance should have the correct values
|
||||
assert ss.objectName() == 'splashScreen', 'The ObjectName should have be ' \
|
||||
'splashScreen'
|
||||
assert ss.frameSize() == QtCore.QSize(370, 370), 'The frameSize should be (370, 370)'
|
||||
assert ss.contextMenuPolicy() == QtCore.Qt.PreventContextMenu, 'The ContextMenuPolicy ' \
|
||||
'should have been QtCore.Qt.PreventContextMenu or 4'
|
@ -28,9 +28,9 @@ from unittest.mock import MagicMock, patch
|
||||
from openlp.core.ui.themeform import ThemeForm
|
||||
|
||||
|
||||
class TestThemeManager(TestCase):
|
||||
class TestThemeForm(TestCase):
|
||||
"""
|
||||
Test the functions in the ThemeManager Class
|
||||
Test the functions in the ThemeForm Class
|
||||
"""
|
||||
def setUp(self):
|
||||
with patch('openlp.core.ui.themeform.ThemeForm._setup'):
|
||||
|
@ -58,19 +58,16 @@ class TestThemeManager(TestCase, TestMixin):
|
||||
# GIVEN: A new a call to initialise
|
||||
self.theme_manager.setup_ui = MagicMock()
|
||||
self.theme_manager.build_theme_path = MagicMock()
|
||||
self.theme_manager.load_first_time_themes = MagicMock()
|
||||
self.theme_manager.upgrade_themes = MagicMock()
|
||||
Settings().setValue('themes/global theme', 'my_theme')
|
||||
|
||||
# WHEN: the initialisation is run
|
||||
with patch('openlp.core.ui.thememanager.ThemeProgressForm'):
|
||||
self.theme_manager.bootstrap_initialise()
|
||||
self.theme_manager.bootstrap_initialise()
|
||||
|
||||
# THEN:
|
||||
self.theme_manager.setup_ui.assert_called_once_with(self.theme_manager)
|
||||
assert self.theme_manager.global_theme == 'my_theme'
|
||||
self.theme_manager.build_theme_path.assert_called_once_with()
|
||||
self.theme_manager.load_first_time_themes.assert_called_once_with()
|
||||
self.theme_manager.upgrade_themes.assert_called_once_with()
|
||||
|
||||
@patch('openlp.core.ui.thememanager.create_paths')
|
||||
@ -117,7 +114,8 @@ class TestThemeManager(TestCase, TestMixin):
|
||||
self.theme_manager.theme_path = MagicMock()
|
||||
|
||||
# WHEN:
|
||||
self.theme_manager.bootstrap_post_set_up()
|
||||
with patch('openlp.core.ui.thememanager.ThemeProgressForm'):
|
||||
self.theme_manager.bootstrap_post_set_up()
|
||||
|
||||
# THEN:
|
||||
assert 1 == self.theme_manager.load_themes.call_count, "load_themes should have been called once"
|
||||
|
@ -113,22 +113,18 @@ describe("The Display object", function () {
|
||||
expect(Display.reinit).toBeDefined();
|
||||
});
|
||||
|
||||
it("should re-initialise Reveal when reinit is called", function () {
|
||||
spyOn(Reveal, "reinitialize");
|
||||
it("should sync Reveal and set to first slide when reinit is called", function () {
|
||||
spyOn(Reveal, "sync");
|
||||
spyOn(Reveal, "slide");
|
||||
Display.reinit();
|
||||
expect(Reveal.reinitialize).toHaveBeenCalled();
|
||||
expect(Reveal.sync).toHaveBeenCalled();
|
||||
expect(Reveal.slide).toHaveBeenCalledWith(0);
|
||||
});
|
||||
|
||||
it("should have a setTransition() method", function () {
|
||||
expect(Display.setTransition).toBeDefined();
|
||||
});
|
||||
|
||||
it("should have a correctly functioning setTransition() method", function () {
|
||||
spyOn(Reveal, "configure");
|
||||
Display.setTransition("fade");
|
||||
expect(Reveal.configure).toHaveBeenCalledWith({"transition": "fade"});
|
||||
});
|
||||
|
||||
it("should have a correctly functioning clearSlides() method", function () {
|
||||
expect(Display.clearSlides).toBeDefined();
|
||||
|
||||
@ -156,6 +152,55 @@ describe("The Display object", function () {
|
||||
|
||||
});
|
||||
|
||||
describe("Transitions", function () {
|
||||
beforeEach(function() {
|
||||
document.body.innerHTML = "";
|
||||
_createDiv({"class": "slides"});
|
||||
_createDiv({"class": "footer"});
|
||||
_createDiv({"id": "global-background"});
|
||||
Display._slides = {};
|
||||
});
|
||||
afterEach(function() {
|
||||
// Reset theme
|
||||
Display._theme = null;
|
||||
});
|
||||
|
||||
it("should have a correctly functioning setTransition() method", function () {
|
||||
spyOn(Reveal, "configure");
|
||||
Display.setTransition("fade", "slow");
|
||||
expect(Reveal.configure).toHaveBeenCalledWith({"transition": "fade", "transitionSpeed": "slow"});
|
||||
});
|
||||
|
||||
it("should have enabled transitions when _doTransitions is true and setTheme is run", function () {
|
||||
spyOn(Display, "setTransition");
|
||||
Display._doTransitions = true;
|
||||
var theme = {
|
||||
"display_slide_transition": true,
|
||||
"display_slide_transition_type": TransitionType.Slide,
|
||||
"display_slide_transition_speed": TransitionSpeed.Fast
|
||||
}
|
||||
|
||||
Display.setTheme(theme);
|
||||
|
||||
expect(Display.setTransition).toHaveBeenCalledWith("slide", "fast");
|
||||
});
|
||||
|
||||
it("should have not enabled transitions when init() with no transitions and setTheme is run", function () {
|
||||
spyOn(Display, "setTransition");
|
||||
Display._doTransitions = false;
|
||||
var theme = {
|
||||
"display_slide_transition": true,
|
||||
"display_slide_transition_type": TransitionType.Slide,
|
||||
"display_slide_transition_speed": TransitionSpeed.Fast,
|
||||
}
|
||||
|
||||
Display.setTheme(theme);
|
||||
|
||||
expect(Display.setTransition).toHaveBeenCalledWith("none", "default");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("Display.alert", function () {
|
||||
var alertContainer, alertBackground, alertText, settings, text;
|
||||
|
||||
@ -519,7 +564,6 @@ describe("Display.setTextSlides", function () {
|
||||
];
|
||||
spyOn(Display, "clearSlides");
|
||||
spyOn(Display, "reinit");
|
||||
spyOn(Reveal, "slide");
|
||||
|
||||
Display.setTextSlides(slides);
|
||||
|
||||
@ -528,7 +572,6 @@ describe("Display.setTextSlides", function () {
|
||||
expect(Display._slides["v2"]).toEqual(1);
|
||||
expect($(".slides > section > section").length).toEqual(2);
|
||||
expect(Display.reinit).toHaveBeenCalledTimes(1);
|
||||
expect(Reveal.slide).toHaveBeenCalledWith(0, 0);
|
||||
});
|
||||
|
||||
it("should correctly set outline width", function () {
|
||||
@ -583,6 +626,56 @@ describe("Display.setTextSlides", function () {
|
||||
expect(slidesDiv.style['justify-content']).toEqual('center');
|
||||
})
|
||||
|
||||
it("should enable shadows", function () {
|
||||
const slides = [
|
||||
{
|
||||
"verse": "v1",
|
||||
"text": "Amazing grace, how sweet the sound\nThat saved a wretch like me\n" +
|
||||
"I once was lost, but now I'm found\nWas blind but now I see",
|
||||
"footer": "Public Domain"
|
||||
}
|
||||
];
|
||||
//
|
||||
const theme = {
|
||||
'font_main_shadow': true,
|
||||
'font_main_shadow_color': "#000",
|
||||
'font_main_shadow_size': 5
|
||||
};
|
||||
spyOn(Display, "reinit");
|
||||
spyOn(Reveal, "slide");
|
||||
|
||||
Display.setTheme(theme);
|
||||
Display.setTextSlides(slides);
|
||||
|
||||
const slidesDiv = $(".text-slides")[0];
|
||||
expect(slidesDiv.style['text-shadow']).not.toEqual('');
|
||||
})
|
||||
|
||||
it("should not enable shadows", function () {
|
||||
const slides = [
|
||||
{
|
||||
"verse": "v1",
|
||||
"text": "Amazing grace, how sweet the sound\nThat saved a wretch like me\n" +
|
||||
"I once was lost, but now I'm found\nWas blind but now I see",
|
||||
"footer": "Public Domain"
|
||||
}
|
||||
];
|
||||
//
|
||||
const theme = {
|
||||
'font_main_shadow': false,
|
||||
'font_main_shadow_color': "#000",
|
||||
'font_main_shadow_size': 5
|
||||
};
|
||||
spyOn(Display, "reinit");
|
||||
spyOn(Reveal, "slide");
|
||||
|
||||
Display.setTheme(theme);
|
||||
Display.setTextSlides(slides);
|
||||
|
||||
const slidesDiv = $(".text-slides")[0];
|
||||
expect(slidesDiv.style['text-shadow']).toEqual('');
|
||||
})
|
||||
|
||||
it("should correctly set slide size position to theme size when adding a text slide", function () {
|
||||
const slides = [
|
||||
{
|
||||
|
142
tests/openlp_core/ui/test_themeprogressform.py
Normal file
142
tests/openlp_core/ui/test_themeprogressform.py
Normal file
@ -0,0 +1,142 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
##########################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# ---------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2019 OpenLP Developers #
|
||||
# ---------------------------------------------------------------------- #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||
##########################################################################
|
||||
"""
|
||||
Package to test the openlp.core.ui.themeform package.
|
||||
"""
|
||||
# from pathlib import Path
|
||||
from unittest import TestCase
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from openlp.core.ui.themeprogressform import ThemeProgressForm
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
|
||||
|
||||
class TestThemeProgressForm(TestCase, TestMixin):
|
||||
"""
|
||||
Test the functions in the ThemeProgressForm class
|
||||
"""
|
||||
def setUp(self):
|
||||
self.setup_application()
|
||||
|
||||
def tearDown(self):
|
||||
del self.app
|
||||
|
||||
def _get_theme_progress_form(self):
|
||||
"""Common code used to create the ThemeProgressForm object"""
|
||||
with patch('openlp.core.ui.themeprogressdialog.ThemePreviewRenderer'), \
|
||||
patch('openlp.core.ui.themeprogressdialog.UiThemeProgressDialog.setup_ui'):
|
||||
form = ThemeProgressForm()
|
||||
return form
|
||||
|
||||
def test_init(self):
|
||||
"""Test that the ThemeProgressForm is created without problems"""
|
||||
# GIVEN: ThemeProgressForm class
|
||||
# WHEN: An object is instatiated
|
||||
# THEN: There is no problem
|
||||
self._get_theme_progress_form()
|
||||
|
||||
@patch('openlp.core.ui.themeprogressform.ScreenList')
|
||||
@patch('openlp.core.ui.themeprogressform.QtWidgets.QDialog.show')
|
||||
def test_show(self, mocked_show, MockScreenList):
|
||||
"""Test that the ThemeProgressForm is created without problems"""
|
||||
# GIVEN: ThemeProgressForm object
|
||||
form = self._get_theme_progress_form()
|
||||
mocked_screen_list = MagicMock()
|
||||
mocked_screen_list.current.display_geometry.width.return_value = 1920
|
||||
mocked_screen_list.current.display_geometry.height.return_value = 1080
|
||||
MockScreenList.return_value = mocked_screen_list
|
||||
form.progress_bar = MagicMock()
|
||||
form.theme_preview_layout = MagicMock()
|
||||
|
||||
# WHEN: The show() method is called
|
||||
form.show()
|
||||
|
||||
# THEN: The correct display ratio is calculated and the form is shown
|
||||
expected_ratio = 16 / 9
|
||||
form.progress_bar.setMinimum.assert_called_once_with(0)
|
||||
form.progress_bar.setMaximum.assert_called_once_with(0)
|
||||
form.progress_bar.setValue.assert_called_once_with(0)
|
||||
assert form.ratio == expected_ratio
|
||||
assert form.theme_preview_layout.aspect_ratio == expected_ratio
|
||||
mocked_show.assert_called_once()
|
||||
|
||||
@patch('openlp.core.ui.themeprogressform.ScreenList')
|
||||
@patch('openlp.core.ui.themeprogressform.QtWidgets.QDialog.show')
|
||||
def test_show_divide_by_zero(self, mocked_show, MockScreenList):
|
||||
"""Test that the ThemeProgressForm is created without problems even if there's a divide by zero exception"""
|
||||
# GIVEN: ThemeProgressForm object
|
||||
form = self._get_theme_progress_form()
|
||||
mocked_screen_list = MagicMock()
|
||||
mocked_screen_list.current.display_geometry.width.return_value = 1920
|
||||
mocked_screen_list.current.display_geometry.height.return_value = 0
|
||||
MockScreenList.return_value = mocked_screen_list
|
||||
form.progress_bar = MagicMock()
|
||||
form.theme_preview_layout = MagicMock()
|
||||
|
||||
# WHEN: The show() method is called
|
||||
form.show()
|
||||
|
||||
# THEN: The correct display ratio is calculated and the form is shown
|
||||
expected_ratio = 16 / 9
|
||||
form.progress_bar.setMinimum.assert_called_once_with(0)
|
||||
form.progress_bar.setMaximum.assert_called_once_with(0)
|
||||
form.progress_bar.setValue.assert_called_once_with(0)
|
||||
assert form.ratio == expected_ratio
|
||||
assert form.theme_preview_layout.aspect_ratio == expected_ratio
|
||||
mocked_show.assert_called_once()
|
||||
|
||||
def test_get_preview(self):
|
||||
"""Test that the get_preview() method returns a preview image"""
|
||||
# GIVEN: ThemeProgressForm object
|
||||
test_theme_name = 'Test Theme'
|
||||
test_theme_data = {'name': test_theme_name}
|
||||
form = self._get_theme_progress_form()
|
||||
form.progress_bar = MagicMock(**{'value.return_value': 0})
|
||||
form.label = MagicMock()
|
||||
form.theme_display = MagicMock(**{'width.return_value': 192, 'generate_preview.return_value': 'preview'})
|
||||
form.renderer.width = MagicMock(return_value=1920)
|
||||
|
||||
# WHEN: get_preview() is called
|
||||
preview = form.get_preview(test_theme_name, test_theme_data)
|
||||
|
||||
# THEN: All the correct methods should be called and the correct results should be returned
|
||||
form.label.setText.assert_called_once_with(test_theme_name)
|
||||
form.progress_bar.value.assert_called_once()
|
||||
form.progress_bar.setValue.assert_called_once_with(1)
|
||||
form.theme_display.width.assert_called_once()
|
||||
form.renderer.width.assert_called_once()
|
||||
form.theme_display.set_scale.assert_called_once_with(0.1)
|
||||
form.theme_display.generate_preview.assert_called_once_with(test_theme_data, generate_screenshot=True)
|
||||
assert preview == 'preview'
|
||||
|
||||
def test_theme_list(self):
|
||||
# GIVEN: ThemeProgressForm object and theme list
|
||||
test_theme_list = ['Theme 1', 'Theme 2']
|
||||
form = self._get_theme_progress_form()
|
||||
form.progress_bar = MagicMock()
|
||||
|
||||
# WHEN: theme_list is set and get'ed
|
||||
form.theme_list = test_theme_list
|
||||
theme_list = form.theme_list
|
||||
|
||||
# THEN: The theme list should be correct
|
||||
form.progress_bar.setMaximum.assert_called_once_with(2)
|
||||
assert theme_list == test_theme_list
|
Loading…
Reference in New Issue
Block a user