def validate_and_load(self, file_paths, target_group=None): """ Process a list for files either from the File Dialog or from Drag and Drop :param list[openlp.core.common.path.Path] file_paths: The files to be loaded. :param target_group: The QTreeWidgetItem of the group that will be the parent of the added files """ full_list = [] for count in range(self.list_view.count()): full_list.append( self.list_view.item(count).data(QtCore.Qt.UserRole)) duplicates_found = False files_added = False for file_path in file_paths: if path_to_str(file_path) in full_list: duplicates_found = True else: files_added = True full_list.append(path_to_str(file_path)) if full_list and files_added: if target_group is None: self.list_view.clear() self.load_list(full_list, target_group) Settings().setValue(self.settings_section + '/last directory', file_paths[0].parent) Settings().setValue( '{section}/{section} files'.format( section=self.settings_section), self.get_file_list()) if duplicates_found: critical_error_message_box( UiStrings().Duplicate, translate( 'OpenLP.MediaManagerItem', 'Duplicate files were found on import and were ignored.'))
def test_path_to_str_type_error(self): """ Test that `path_to_str` raises a type error when called with an invalid type """ # GIVEN: The `path_to_str` function # WHEN: Calling `path_to_str` with an invalid Type # THEN: A TypeError should have been raised with self.assertRaises(TypeError): path_to_str(str())
def generate_preview(self, theme_data, force_page=False): """ Generate a preview of a theme. :param theme_data: The theme to generated a preview for. :param force_page: Flag to tell message lines per page need to be generated. :rtype: QtGui.QPixmap """ # save value for use in format_slide self.force_page = force_page # build a service item to generate preview service_item = ServiceItem() if self.force_page: # make big page for theme edit dialog to get line count service_item.add_from_text(VERSE_FOR_LINE_COUNT) else: service_item.add_from_text(VERSE) service_item.raw_footer = FOOTER # if No file do not update cache if theme_data.background_filename: self.image_manager.add_image( path_to_str(theme_data.background_filename), ImageSource.Theme, QtGui.QColor(theme_data.background_border_color)) theme_data, main, footer = self.pre_render(theme_data) service_item.theme_data = theme_data service_item.main = main service_item.footer = footer service_item.render(True) if not self.force_page: self.display.build_html(service_item) raw_html = service_item.get_rendered_frame(0) self.display.text(raw_html, False) return self.display.preview() self.force_page = False
def set_startup_screen(self): bg_color = self.settings.value('core/logo background color') image = self.settings.value('core/logo file') if path_to_str(image).startswith(':'): image = self.openlp_splash_screen_path image_uri = image.as_uri() self.run_javascript('Display.setStartupSplashScreen("{bg_color}", "{image}");'.format(bg_color=bg_color, image=image_uri))
def initialise(self): """ Initialize media item. """ self.list_view.clear() self.service_path = AppLocation.get_section_data_path(self.settings_section) / 'thumbnails' create_paths(self.service_path) self.load_list([path_to_str(file) for file in Settings().value(self.settings_section + '/media files')]) self.rebuild_players()
def initialise(self): """ Populate the media manager tab """ self.list_view.setIconSize(QtCore.QSize(88, 50)) file_paths = Settings().value(self.settings_section + '/presentations files') self.load_list([path_to_str(path) for path in file_paths], initial_load=True) self.populate_display_types()
def test_path_to_str_path_object(self): """ Test that `path_to_str` correctly converts the path parameter when passed a Path object """ # GIVEN: The `path_to_str` function # WHEN: Calling the `path_to_str` function with a Path object result = path_to_str(Path('test/path')) # THEN: `path_to_str` should return a string representation of the Path object assert result == os.path.join('test', 'path')
def test_path_to_str_wth_str(self): """ Test that `path_to_str` just returns a str when given a str """ # GIVEN: The `path_to_str` function # WHEN: Calling `path_to_str` with a str result = path_to_str('/usr/bin') # THEN: The string should be returned assert result == '/usr/bin'
def test_path_to_str_none(self): """ Test that `path_to_str` correctly converts the path parameter when passed with None """ # GIVEN: The `path_to_str` function # WHEN: Calling the `path_to_str` function with None result = path_to_str(None) # THEN: `path_to_str` should return an empty string assert result == ''
def path(self, path): """ A Property setter method to set the selected path :param openlp.core.common.path.Path path: The path to set the widget to :rtype: None """ self._path = path text = path_to_str(path) self.line_edit.setText(text) self.line_edit.setToolTip(text)
def __init__(self, parent=None, screen=None, can_show_startup_screen=True): """ 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 self.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(flags) self.setAttribute(QtCore.Qt.WA_TranslucentBackground) self.setAutoFillBackground(True) self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.layout = QtWidgets.QVBoxLayout(self) self.layout.setContentsMargins(0, 0, 0, 0) self.webview = WebEngineView(self) self.webview.setAttribute(QtCore.Qt.WA_TranslucentBackground) self.webview.page().setBackgroundColor(QtCore.Qt.transparent) self.layout.addWidget(self.webview) self.webview.loadFinished.connect(self.after_loaded) display_base_path = AppLocation.get_directory(AppLocation.AppDir) / 'core' / 'display' / 'html' self.display_path = display_base_path / 'display.html' self.checkerboard_path = display_base_path / 'checkerboard.png' self.openlp_splash_screen_path = display_base_path / 'openlp-splash-screen.png' self.set_url(QtCore.QUrl.fromLocalFile(path_to_str(self.display_path))) self.channel = QtWebChannel.QWebChannel(self) self.media_watcher = MediaWatcher(self) self.channel.registerObject('mediaWatcher', self.media_watcher) self.display_watcher = DisplayWatcher(self) self.channel.registerObject('displayWatcher', self.display_watcher) self.webview.page().setWebChannel(self.channel) self.display_watcher.initialised.connect(self.on_initialised) self.is_display = False self.scale = 1 self.hide_mode = None self.__script_done = True self.__script_result = None if screen and screen.is_display: Registry().register_function('live_display_hide', self.hide_display) Registry().register_function('live_display_show', self.show_display) self.update_from_screen(screen) self.is_display = True # Only make visible on single monitor setup if setting enabled. if len(ScreenList()) > 1 or self.settings.value('core/display on monitor'): self.show()
def save_theme(self, theme, image_source_path, image_destination_path): """ Called by theme maintenance Dialog to save the theme and to trigger the reload of the theme list :param Theme theme: The theme data object. :param openlp.core.common.path.Path image_source_path: Where the theme image is currently located. :param openlp.core.common.path.Path image_destination_path: Where the Theme Image is to be saved to :rtype: None """ self._write_theme(theme, image_source_path, image_destination_path) if theme.background_type == BackgroundType.to_string(BackgroundType.Image): self.image_manager.update_image_border(path_to_str(theme.background_filename), ImageSource.Theme, QtGui.QColor(theme.background_border_color)) self.image_manager.process_updates()
def search(self, string, show_error): """ Search in files :param string: name to be found :param show_error: not used :return: """ file_paths = self.settings.value(self.settings_section + '/presentations files') results = [] string = string.lower() for file_path in file_paths: file_name = file_path.name if file_name.lower().find(string) > -1: results.append([path_to_str(file_path), file_name]) return results
def direct_image(self, path, background): """ API for replacement backgrounds so Images are added directly to cache. :param path: Path to Image :param background: The background color """ self.image_manager.add_image(path, ImageSource.ImagePlugin, background) if not hasattr(self, 'service_item'): return False self.override['image'] = path self.override['theme'] = path_to_str( self.service_item.theme_data.background_filename) self.image(path) # Update the preview frame. if self.is_live: self.live_controller.update_preview() return True
def _set_theme(self, theme_name): """ Helper method to save theme names and theme data. :param theme_name: The theme name """ self.log_debug( "_set_theme with theme {theme}".format(theme=theme_name)) if theme_name not in self._theme_dimensions: theme_data = self.theme_manager.get_theme_data(theme_name) main_rect = self.get_main_rectangle(theme_data) footer_rect = self.get_footer_rectangle(theme_data) self._theme_dimensions[theme_name] = [ theme_data, main_rect, footer_rect ] else: theme_data, main_rect, footer_rect = self._theme_dimensions[ theme_name] # if No file do not update cache if theme_data.background_filename: self.image_manager.add_image( path_to_str(theme_data.background_filename), ImageSource.Theme, QtGui.QColor(theme_data.background_border_color))
def setup(self): """ Set up and build the output screen """ self.log_debug('Start MainDisplay setup (live = {islive})'.format( islive=self.is_live)) self.screen = self.screens.current self.setVisible(False) Display.setup(self) if self.is_live: # Build the initial frame. background_color = QtGui.QColor() background_color.setNamedColor( Settings().value('core/logo background color')) if not background_color.isValid(): background_color = QtCore.Qt.white image_file = path_to_str(Settings().value('core/logo file')) splash_image = QtGui.QImage(image_file) self.initial_fame = QtGui.QImage( self.screen['size'].width(), self.screen['size'].height(), QtGui.QImage.Format_ARGB32_Premultiplied) painter_image = QtGui.QPainter() painter_image.begin(self.initial_fame) painter_image.fillRect(self.initial_fame.rect(), background_color) painter_image.drawImage( (self.screen['size'].width() - splash_image.width()) // 2, (self.screen['size'].height() - splash_image.height()) // 2, splash_image) service_item = ServiceItem() service_item.bg_image_bytes = image_to_byte(self.initial_fame) self.web_view.setHtml( build_html(service_item, self.screen, self.is_live, None, plugins=self.plugin_manager.plugins)) self._hide_mouse()
def load_list(self, file_paths, target_group=None, initial_load=False): """ Add presentations into the media manager. This is called both on initial load of the plugin to populate with existing files, and when the user adds new files via the media manager. :param list[openlp.core.common.path.Path] file_paths: List of file paths to add to the media manager. """ file_paths = [str_to_path(filename) for filename in file_paths] current_paths = self.get_file_list() titles = [file_path.name for file_path in current_paths] self.application.set_busy_cursor() if not initial_load: self.main_window.display_progress_bar(len(file_paths)) # Sort the presentations by its filename considering language specific characters. file_paths.sort(key=lambda file_path: get_natural_key(file_path.name)) for file_path in file_paths: if not initial_load: self.main_window.increment_progress_bar() if current_paths.count(file_path) > 0: continue file_name = file_path.name if not file_path.exists(): item_name = QtWidgets.QListWidgetItem(file_name) item_name.setIcon(UiIcons().delete) item_name.setData(QtCore.Qt.UserRole, path_to_str(file_path)) item_name.setToolTip(str(file_path)) self.list_view.addItem(item_name) else: if titles.count(file_name) > 0: if not initial_load: critical_error_message_box( translate('PresentationPlugin.MediaItem', 'File Exists'), translate( 'PresentationPlugin.MediaItem', 'A presentation with that filename already exists.' )) continue controller_name = self.find_controller_by_type(file_path) if controller_name: controller = self.controllers[controller_name] doc = controller.add_document(file_path) thumbnail_path = doc.get_thumbnail_folder() / 'icon.png' preview_path = doc.get_thumbnail_path(1, True) if not preview_path and not initial_load: doc.load_presentation() preview_path = doc.get_thumbnail_path(1, True) doc.close_presentation() if not (preview_path and preview_path.exists()): icon = UiIcons().delete else: if validate_thumb(preview_path, thumbnail_path): icon = build_icon(thumbnail_path) else: icon = create_thumb(preview_path, thumbnail_path) else: if initial_load: icon = UiIcons().delete else: critical_error_message_box( UiStrings().UnsupportedFile, translate( 'PresentationPlugin.MediaItem', 'This type of presentation is not supported.')) continue item_name = QtWidgets.QListWidgetItem(file_name) item_name.setData(QtCore.Qt.UserRole, path_to_str(file_path)) item_name.setIcon(icon) item_name.setToolTip(str(file_path)) self.list_view.addItem(item_name) if not initial_load: self.main_window.finished_progress_bar() self.application.set_normal_cursor()
def build_html(self, service_item, image_path=''): """ Store the service_item and build the new HTML from it. Add the HTML to the display :param service_item: The Service item to be used :param image_path: Where the image resides. """ self.web_loaded = False self.initial_fame = None self.service_item = service_item background = None # We have an image override so keep the image till the theme changes. if self.override: # We have an video override so allow it to be stopped. if 'video' in self.override: Registry().execute('video_background_replaced') self.override = {} # We have a different theme. elif self.override['theme'] != path_to_str( service_item.theme_data.background_filename): Registry().execute('live_theme_changed') self.override = {} else: # replace the background background = self.image_manager.get_image_bytes( self.override['image'], ImageSource.ImagePlugin) self.set_transparency( self.service_item.theme_data.background_type == BackgroundType.to_string(BackgroundType.Transparent)) image_bytes = None if self.service_item.theme_data.background_type == 'image': if self.service_item.theme_data.background_filename: self.service_item.bg_image_bytes = self.image_manager.get_image_bytes( path_to_str( self.service_item.theme_data.background_filename), ImageSource.Theme) if image_path: image_bytes = self.image_manager.get_image_bytes( image_path, ImageSource.ImagePlugin) created_html = build_html(self.service_item, self.screen, self.is_live, background, image_bytes, plugins=self.plugin_manager.plugins) self.web_view.setHtml(created_html) if service_item.foot_text: self.footer(service_item.foot_text) # if was hidden keep it hidden if self.hide_mode and self.is_live and not service_item.is_media(): if Settings().value('core/auto unblank'): Registry().execute('slidecontroller_live_unblank') else: self.hide_display(self.hide_mode) if self.service_item.theme_data.background_type == 'video' and self.is_live: if self.service_item.theme_data.background_filename: service_item = ServiceItem() service_item.title = 'webkit' service_item.processor = 'webkit' path = str( AppLocation.get_section_data_path('themes') / self.service_item.theme_data.theme_name) service_item.add_from_command( path, path_to_str( self.service_item.theme_data.background_filename), UiIcons().media) self.media_controller.video(DisplayControllerType.Live, service_item, video_behind_text=True) self._hide_mouse()
def load_video(self, source, service_item, hidden=False): """ Loads and starts a video to run and sets the stored sound value. :param source: Where the call originated form :param service_item: The player which is doing the playing :param hidden: The player which is doing the playing """ is_valid = True controller = self.display_controllers(source) # stop running videos self.media_reset(controller) controller.media_info = ItemMediaInfo() if controller.is_live: controller.media_info.volume = self.settings.value( 'media/live volume') else: controller.media_info.volume = self.settings.value( 'media/preview volume') # background will always loop video. if service_item.is_capable(ItemCapabilities.HasBackgroundAudio): controller.media_info.file_info = service_item.background_audio else: if service_item.is_capable(ItemCapabilities.HasBackgroundVideo): controller.media_info.file_info = [ service_item.video_file_name ] service_item.media_length = self.media_length( path_to_str(service_item.video_file_name)) controller.media_info.is_looping_playback = True controller.media_info.is_background = True elif service_item.is_capable(ItemCapabilities.CanStream): controller.media_info.file_info = [] controller.media_info.is_background = True else: controller.media_info.file_info = [ service_item.get_frame_path() ] display = self._define_display(controller) if controller.is_live: # if this is an optical device use special handling if service_item.is_capable(ItemCapabilities.CanStream): is_valid = self._check_file_type(controller, display, True) controller.media_info.media_type = MediaType.Stream elif service_item.is_capable(ItemCapabilities.IsOptical): log.debug('video is optical and live') path = service_item.get_frame_path() (name, title, audio_track, subtitle_track, start, end, clip_name) = parse_optical_path(path) is_valid = self.media_setup_optical(name, title, audio_track, subtitle_track, start, end, display, controller) else: log.debug('video is not optical and live') controller.media_info.length = service_item.media_length is_valid = self._check_file_type(controller, display) controller.media_info.start_time = service_item.start_time controller.media_info.end_time = service_item.end_time elif controller.preview_display: if service_item.is_capable(ItemCapabilities.CanStream): controller.media_info.media_type = MediaType.Stream is_valid = self._check_file_type(controller, display, True) elif service_item.is_capable(ItemCapabilities.IsOptical): log.debug('video is optical and preview') path = service_item.get_frame_path() (name, title, audio_track, subtitle_track, start, end, clip_name) = parse_optical_path(path) is_valid = self.media_setup_optical(name, title, audio_track, subtitle_track, start, end, display, controller) else: log.debug('video is not optical and preview') controller.media_info.length = service_item.media_length is_valid = self._check_file_type(controller, display) if not is_valid: # Media could not be loaded correctly critical_error_message_box( translate('MediaPlugin.MediaItem', 'Unsupported File'), translate('MediaPlugin.MediaItem', 'Unsupported File')) return False log.debug('video media type: {tpe} '.format( tpe=str(controller.media_info.media_type))) autoplay = False if service_item.requires_media(): autoplay = True # Preview requested if not controller.is_live: autoplay = True # Visible or background requested or Service Item wants to autostart elif not hidden or service_item.will_auto_start: autoplay = True # Unblank on load set elif self.settings.value('core/auto unblank'): autoplay = True if autoplay: if not self.media_play(controller): critical_error_message_box( translate('MediaPlugin.MediaItem', 'Unsupported File'), translate('MediaPlugin.MediaItem', 'Unsupported File')) return False self.set_controls_visible(controller, True) log.debug('use {nm} controller'.format(nm=self.current_media_players[ controller.controller_type].display_name)) return True