Example #1
0
    def test_expand_json(self):
        """
        Test the expand_json method
        """
        # GIVEN: A Theme object and some JSON to "expand"
        theme = Theme()
        theme_json = {
            'background': {
                'border_color': '#000000',
                'type': 'solid'
            },
            'display': {
                'vertical_align': 0
            },
            'font': {
                'footer': {
                    'bold': False
                },
                'main': {
                    'name': 'Arial'
                }
            }
        }

        # WHEN: Theme.expand_json() is run
        theme.expand_json(theme_json)

        # THEN: The attributes should be set on the object
        self.check_theme(theme)
Example #2
0
    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)'
Example #3
0
 def on_add_theme(self, field=None):
     """
     Loads a new theme with the default settings and then launches the theme editing form for the user to make
     their customisations.
     :param field:
     """
     theme = Theme()
     theme.set_default_header_footer()
     self.theme_form.theme = theme
     self.theme_form.exec()
     self.load_themes()
Example #4
0
 def load_first_time_themes(self):
     """
     Imports any themes on start up and makes sure there is at least one theme
     """
     self.application.set_busy_cursor()
     theme_paths = AppLocation.get_files(self.settings_section, '.otz')
     for theme_path in theme_paths:
         theme_path = self.theme_path / theme_path
         self.unzip_theme(theme_path, self.theme_path)
         delete_file(theme_path)
     theme_paths = AppLocation.get_files(self.settings_section, '.png')
     # No themes have been found so create one
     if not theme_paths:
         theme = Theme()
         theme.theme_name = UiStrings().Default
         self._write_theme(theme)
         Settings().setValue(self.settings_section + '/global theme', theme.theme_name)
     self.application.set_normal_cursor()
Example #5
0
    def test_new_theme(self):
        """
        Test the Theme constructor
        """
        # GIVEN: The Theme class
        # WHEN: A theme object is created
        default_theme = Theme()

        # THEN: The default values should be correct
        self.check_theme(default_theme)
Example #6
0
 def get_theme_data(self, theme_name):
     """
     Gets a theme given a name, returns the default theme if missing
     """
     theme = Theme()
     if theme_name in self._theme_list:
         theme = self._theme_list[theme_name]
     else:
         self.log_warning(
             'Missing requested theme data for "{}", using default theme'.
             format(theme_name))
     return theme
Example #7
0
    def test_set_text_rectangle(self, mock_build_chords_css, mock_outline_css,
                                mock_lyrics_css, mock_webview):
        """
        Test set_text_rectangle returns a proper html string
        """
        # GIVEN: test object and data
        mock_lyrics_css.return_value = ' FORMAT CSS; '
        mock_outline_css.return_value = ' OUTLINE CSS; '
        mock_build_chords_css.return_value = ' CHORDS CSS; '
        theme_data = Theme()
        theme_data.font_main_name = 'Arial'
        theme_data.font_main_size = 20
        theme_data.font_main_color = '#FFFFFF'
        theme_data.font_main_outline_color = '#FFFFFF'
        main = QtCore.QRect(10, 10, 1280, 900)
        foot = QtCore.QRect(10, 1000, 1260, 24)
        renderer = Renderer()

        # WHEN: Calling method
        renderer._set_text_rectangle(theme_data=theme_data,
                                     rect_main=main,
                                     rect_footer=foot)

        # THEN: QtWebKitWidgets should be called with the proper string
        mock_webview.setHtml.called_with(CSS_TEST_ONE, 'Should be the same')
Example #8
0
 def test_save_retrieve(self):
     """
     Load a dummy theme, save it and reload it
     """
     # GIVEN: The default Theme class
     # WHEN: A theme object is created
     default_theme = Theme()
     # THEN: The default values should be correct
     save_theme_json = default_theme.export_theme()
     lt = Theme()
     lt.load_theme(save_theme_json)
     self.check_theme(lt)
Example #9
0
    def get_theme_data(self, theme_name):
        """
        Returns a theme object from a JSON file

        :param str theme_name: Name of the theme to load from file
        :return:  The theme object.
        :rtype: Theme
        """
        theme_name = str(theme_name)
        theme_file_path = self.theme_path / theme_name / '{file_name}.json'.format(file_name=theme_name)
        theme_data = get_text_file_string(theme_file_path)
        if not theme_data:
            self.log_debug('No theme data - using default theme')
            return Theme()
        return self._create_theme_from_json(theme_data, self.theme_path)
Example #10
0
    def _create_theme_from_json(self, theme_json, image_path):
        """
        Return a theme object using information parsed from JSON

        :param theme_json: The Theme data object.
        :param Path image_path: Where the theme image is stored
        :return: Theme data.
        :rtype: Theme
        """
        theme = Theme()
        theme.load_theme(theme_json, self.theme_path)
        theme.extend_image_filename(image_path)
        return theme
Example #11
0
    def _create_theme_from_xml(theme_xml, image_path):
        """
        Return a theme object using information parsed from XML

        :param theme_xml: The Theme data object.
        :param Path image_path: Where the theme image is stored
        :return: Theme data.
        :rtype: Theme
        """
        theme = Theme()
        theme.parse(theme_xml)
        theme.extend_image_filename(image_path)
        return theme
Example #12
0
    def test_extend_image_filename(self):
        """
        Test the extend_image_filename method
        """
        # GIVEN: A theme object
        theme = Theme()
        theme.theme_name = 'MyBeautifulTheme'
        theme.background_filename = Path('video.mp4')
        theme.background_type = 'video'
        path = Path.home()

        # WHEN: Theme.extend_image_filename is run
        theme.extend_image_filename(path)

        # THEN: The filename of the background should be correct
        expected_filename = path / 'MyBeautifulTheme' / 'video.mp4'
        assert expected_filename == theme.background_filename
        assert 'MyBeautifulTheme' == theme.theme_name
Example #13
0
    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'
Example #14
0
 def unzip_theme(self, file_path, directory_path):
     """
     Unzip the theme, remove the preview file if stored. Generate a new preview file. Check the XML theme version
     and upgrade if necessary.
     :param Path file_path:
     :param Path directory_path:
     """
     self.log_debug('Unzipping theme {name}'.format(name=file_path))
     file_xml = None
     abort_import = True
     json_theme = False
     theme_name = ""
     try:
         with zipfile.ZipFile(file_path) as theme_zip:
             json_file = [
                 name for name in theme_zip.namelist()
                 if os.path.splitext(name)[1].lower() == '.json'
             ]
             if len(json_file) != 1:
                 # TODO: remove XML handling after once the upgrade path from 2.4 is no longer required
                 xml_file = [
                     name for name in theme_zip.namelist()
                     if os.path.splitext(name)[1].lower() == '.xml'
                 ]
                 if len(xml_file) != 1:
                     self.log_error(
                         'Theme contains "{val:d}" theme files'.format(
                             val=len(xml_file)))
                     raise ValidationError
                 xml_tree = ElementTree(
                     element=XML(theme_zip.read(xml_file[0]))).getroot()
                 theme_version = xml_tree.get('version', default=None)
                 if not theme_version or float(theme_version) < 2.0:
                     self.log_error('Theme version is less than 2.0')
                     raise ValidationError
                 theme_name = xml_tree.find('name').text.strip()
             else:
                 new_theme = Theme()
                 new_theme.load_theme(
                     theme_zip.read(json_file[0]).decode("utf-8"))
                 theme_name = new_theme.theme_name
                 json_theme = True
             theme_folder = directory_path / theme_name
             if theme_folder.exists(
             ) and not self.over_write_message_box(theme_name):
                 abort_import = True
                 return
             else:
                 abort_import = False
             for zipped_file in theme_zip.namelist():
                 zipped_file_rel_path = Path(zipped_file)
                 split_name = zipped_file_rel_path.parts
                 if split_name[-1] == '' or len(split_name) == 1:
                     # is directory or preview file
                     continue
                 full_name = directory_path / zipped_file_rel_path
                 create_paths(full_name.parent)
                 if zipped_file_rel_path.suffix.lower(
                 ) == '.xml' or zipped_file_rel_path.suffix.lower(
                 ) == '.json':
                     file_xml = str(theme_zip.read(zipped_file), 'utf-8')
                     with full_name.open('w', encoding='utf-8') as out_file:
                         out_file.write(file_xml)
                 else:
                     with full_name.open('wb') as out_file:
                         out_file.write(theme_zip.read(zipped_file))
     except (OSError, ValidationError, zipfile.BadZipFile):
         self.log_exception('Importing theme from zip failed {name}'.format(
             name=file_path))
         critical_error_message_box(
             translate('OpenLP.ThemeManager', 'Import Error'),
             translate(
                 'OpenLP.ThemeManager',
                 'There was a problem importing {file_name}.\n\nIt is corrupt, '
                 'inaccessible or not a valid theme.').format(
                     file_name=file_path))
     finally:
         if not abort_import:
             # As all files are closed, we can create the Theme.
             if file_xml:
                 if json_theme:
                     self._create_theme_from_json(file_xml, self.theme_path)
                 else:
                     self._create_theme_from_xml(file_xml, self.theme_path)
             return theme_name
         else:
             return None