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