class MediaManagerItem(QtWidgets.QWidget, RegistryProperties): """ MediaManagerItem is a helper widget for plugins. None of the following *need* to be used, feel free to override them completely in your plugin's implementation. Alternatively, call them from your plugin before or after you've done extra things that you need to. **Constructor Parameters** ``parent`` The parent widget. Usually this will be the *Media Manager* itself. This needs to be a class descended from ``QWidget``. ``plugin`` The plugin widget. Usually this will be the *Plugin* itself. This needs to be a class descended from ``Plugin``. **Member Variables** When creating a descendant class from this class for your plugin, the following member variables should be set. ``self.on_new_prompt`` Defaults to *'Select Image(s)'*. ``self.on_new_file_masks`` Defaults to *'Images (*.jpg *jpeg *.gif *.png *.bmp)'*. This assumes that the new action is to load a file. If not, you need to override the ``OnNew`` method. ``self.PreviewFunction`` This must be a method which returns a QImage to represent the item (usually a preview). No scaling is required, that is performed automatically by OpenLP when necessary. If this method is not defined, a default will be used (treat the filename as an image). """ log.info('Media Item loaded') def __init__(self, parent=None, plugin=None): """ Constructor to create the media manager item. """ super(MediaManagerItem, self).__init__(parent) self.plugin = plugin self._setup() self.setup_item() def _setup(self): """ Run some initial setup. This method is separate from __init__ in order to mock it out in tests. """ self.hide() self.whitespace = re.compile(r'[\W_]+', re.UNICODE) visible_title = self.plugin.get_string(StringContent.VisibleName) self.title = str(visible_title['title']) Registry().register(self.plugin.name, self) self.settings_section = self.plugin.name self.toolbar = None self.remote_triggered = None self.single_service_item = True self.quick_preview_allowed = False self.has_search = False self.page_layout = QtWidgets.QVBoxLayout(self) self.page_layout.setSpacing(0) self.page_layout.setContentsMargins(0, 0, 0, 0) self.required_icons() self.setupUi() self.retranslateUi() self.auto_select_id = -1 def setup_item(self): """ Override this for additional Plugin setup """ pass def required_icons(self): """ This method is called to define the icons for the plugin. It provides a default set and the plugin is able to override the if required. """ self.has_import_icon = False self.has_new_icon = True self.has_edit_icon = True self.has_file_icon = False self.has_delete_icon = True self.add_to_service_item = False def retranslateUi(self): """ This method is called automatically to provide OpenLP with the opportunity to translate the ``MediaManagerItem`` to another language. """ pass def add_toolbar(self): """ A method to help developers easily add a toolbar to the media manager item. """ if self.toolbar is None: self.toolbar = OpenLPToolbar(self) self.page_layout.addWidget(self.toolbar) def setupUi(self): """ This method sets up the interface on the button. Plugin developers use this to add and create toolbars, and the rest of the interface of the media manager item. """ # Add a toolbar self.add_toolbar() # Allow the plugin to define buttons at start of bar self.add_start_header_bar() # Add the middle of the tool bar (pre defined) self.add_middle_header_bar() # Allow the plugin to define buttons at end of bar self.add_end_header_bar() # Add the list view self.add_list_view_to_toolbar() def add_middle_header_bar(self): """ Create buttons for the media item toolbar """ toolbar_actions = [] # Import Button if self.has_import_icon: toolbar_actions.append([ 'Import', StringContent.Import, ':/general/general_import.png', self.on_import_click ]) # Load Button if self.has_file_icon: toolbar_actions.append([ 'Load', StringContent.Load, ':/general/general_open.png', self.on_file_click ]) # New Button if self.has_new_icon: toolbar_actions.append([ 'New', StringContent.New, ':/general/general_new.png', self.on_new_click ]) # Edit Button if self.has_edit_icon: toolbar_actions.append([ 'Edit', StringContent.Edit, ':/general/general_edit.png', self.on_edit_click ]) # Delete Button if self.has_delete_icon: toolbar_actions.append([ 'Delete', StringContent.Delete, ':/general/general_delete.png', self.on_delete_click ]) # Preview toolbar_actions.append([ 'Preview', StringContent.Preview, ':/general/general_preview.png', self.on_preview_click ]) # Live Button toolbar_actions.append([ 'Live', StringContent.Live, ':/general/general_live.png', self.on_live_click ]) # Add to service Button toolbar_actions.append([ 'Service', StringContent.Service, ':/general/general_add.png', self.on_add_click ]) for action in toolbar_actions: if action[0] == StringContent.Preview: self.toolbar.addSeparator() self.toolbar.add_toolbar_action( '%s%sAction' % (self.plugin.name, action[0]), text=self.plugin.get_string(action[1])['title'], icon=action[2], tooltip=self.plugin.get_string(action[1])['tooltip'], triggers=action[3]) def add_list_view_to_toolbar(self): """ Creates the main widget for listing items the media item is tracking """ # Add the List widget self.list_view = ListWidgetWithDnD(self, self.plugin.name) self.list_view.setSpacing(1) self.list_view.setSelectionMode( QtWidgets.QAbstractItemView.ExtendedSelection) self.list_view.setAlternatingRowColors(True) self.list_view.setObjectName('%sListView' % self.plugin.name) # Add to page_layout self.page_layout.addWidget(self.list_view) # define and add the context menu self.list_view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) if self.has_edit_icon: create_widget_action(self.list_view, text=self.plugin.get_string( StringContent.Edit)['title'], icon=':/general/general_edit.png', triggers=self.on_edit_click) create_widget_action(self.list_view, separator=True) create_widget_action( self.list_view, 'listView%s%sItem' % (self.plugin.name.title(), StringContent.Preview.title()), text=self.plugin.get_string(StringContent.Preview)['title'], icon=':/general/general_preview.png', can_shortcuts=True, triggers=self.on_preview_click) create_widget_action( self.list_view, 'listView%s%sItem' % (self.plugin.name.title(), StringContent.Live.title()), text=self.plugin.get_string(StringContent.Live)['title'], icon=':/general/general_live.png', can_shortcuts=True, triggers=self.on_live_click) create_widget_action( self.list_view, 'listView%s%sItem' % (self.plugin.name.title(), StringContent.Service.title()), can_shortcuts=True, text=self.plugin.get_string(StringContent.Service)['title'], icon=':/general/general_add.png', triggers=self.on_add_click) if self.has_delete_icon: create_widget_action(self.list_view, separator=True) create_widget_action( self.list_view, 'listView%s%sItem' % (self.plugin.name.title(), StringContent.Delete.title()), text=self.plugin.get_string(StringContent.Delete)['title'], icon=':/general/general_delete.png', can_shortcuts=True, triggers=self.on_delete_click) if self.add_to_service_item: create_widget_action(self.list_view, separator=True) create_widget_action(self.list_view, text=translate( 'OpenLP.MediaManagerItem', '&Add to selected Service Item'), icon=':/general/general_add.png', triggers=self.on_add_edit_click) self.add_custom_context_actions() # Create the context menu and add all actions from the list_view. self.menu = QtWidgets.QMenu() self.menu.addActions(self.list_view.actions()) self.list_view.doubleClicked.connect(self.on_double_clicked) self.list_view.itemSelectionChanged.connect(self.on_selection_change) self.list_view.customContextMenuRequested.connect(self.context_menu) def add_search_to_toolbar(self): """ Creates a search field with button and related signal handling. """ self.search_widget = QtWidgets.QWidget(self) self.search_widget.setObjectName('search_widget') self.search_layout = QtWidgets.QVBoxLayout(self.search_widget) self.search_layout.setObjectName('search_layout') self.search_text_layout = QtWidgets.QFormLayout() self.search_text_layout.setObjectName('search_text_layout') self.search_text_label = QtWidgets.QLabel(self.search_widget) self.search_text_label.setObjectName('search_text_label') self.search_text_edit = SearchEdit(self.search_widget) self.search_text_edit.setObjectName('search_text_edit') self.search_text_label.setBuddy(self.search_text_edit) self.search_text_layout.addRow(self.search_text_label, self.search_text_edit) self.search_layout.addLayout(self.search_text_layout) self.search_button_layout = QtWidgets.QHBoxLayout() self.search_button_layout.setObjectName('search_button_layout') self.search_button_layout.addStretch() self.search_text_button = QtWidgets.QPushButton(self.search_widget) self.search_text_button.setObjectName('search_text_button') self.search_button_layout.addWidget(self.search_text_button) self.search_layout.addLayout(self.search_button_layout) self.page_layout.addWidget(self.search_widget) # Signals and slots self.search_text_edit.returnPressed.connect( self.on_search_text_button_clicked) self.search_text_button.clicked.connect( self.on_search_text_button_clicked) self.search_text_edit.textChanged.connect( self.on_search_text_edit_changed) def add_custom_context_actions(self): """ Implement this method in your descendant media manager item to add any context menu items. This method is called automatically. """ pass def initialise(self): """ Implement this method in your descendant media manager item to do any UI or other initialisation. This method is called automatically. """ pass def add_start_header_bar(self): """ Slot at start of toolbar for plugin to add widgets """ pass def add_end_header_bar(self): """ Slot at end of toolbar for plugin to add widgets """ pass def on_file_click(self): """ Add a file to the list widget to make it available for showing """ files = FileDialog.getOpenFileNames( self, self.on_new_prompt, Settings().value(self.settings_section + '/last directory'), self.on_new_file_masks) log.info('New files(s) %s' % files) if files: self.application.set_busy_cursor() self.validate_and_load(files) self.application.set_normal_cursor() def load_file(self, data): """ Turn file from Drag and Drop into an array so the Validate code can run it. :param data: A dictionary containing the list of files to be loaded and the target """ new_files = [] error_shown = False for file_name in data['files']: file_type = file_name.split('.')[-1] if file_type.lower() not in self.on_new_file_masks: if not error_shown: critical_error_message_box( translate('OpenLP.MediaManagerItem', 'Invalid File Type'), translate('OpenLP.MediaManagerItem', 'Invalid File %s.\nSuffix not supported') % file_name) error_shown = True else: new_files.append(file_name) if new_files: self.validate_and_load(new_files, data['target']) def dnd_move_internal(self, target): """ Handle internal moving of media manager items :param target: The target of the DnD action """ pass def validate_and_load(self, files, target_group=None): """ Process a list for files either from the File Dialog or from Drag and Drop :param files: The files to be loaded. :param target_group: The QTreeWidgetItem of the group that will be the parent of the added files """ names = [] full_list = [] for count in range(self.list_view.count()): names.append(self.list_view.item(count).text()) full_list.append( self.list_view.item(count).data(QtCore.Qt.UserRole)) duplicates_found = False files_added = False for file_path in files: if file_path in full_list: duplicates_found = True else: files_added = True full_list.append(file_path) if full_list and files_added: if target_group is None: self.list_view.clear() self.load_list(full_list, target_group) last_dir = os.path.split(files[0])[0] Settings().setValue(self.settings_section + '/last directory', last_dir) Settings().setValue( '%s/%s files' % (self.settings_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 context_menu(self, point): """ Display a context menu :param point: The point the cursor was at """ item = self.list_view.itemAt(point) # Decide if we have to show the context menu or not. if item is None: return if not item.flags() & QtCore.Qt.ItemIsSelectable: return self.menu.exec(self.list_view.mapToGlobal(point)) def get_file_list(self): """ Return the current list of files """ file_list = [] for index in range(self.list_view.count()): list_item = self.list_view.item(index) filename = list_item.data(QtCore.Qt.UserRole) file_list.append(filename) return file_list def load_list(self, load_list, target_group): """ Load a list. Needs to be implemented by the plugin. :param load_list: List object to load :param target_group: Group to load """ raise NotImplementedError( 'MediaManagerItem.loadList needs to be defined by the plugin') def on_new_click(self): """ Hook for plugins to define behaviour for adding new items. """ pass def on_edit_click(self): """ Hook for plugins to define behaviour for editing items. """ pass def on_delete_click(self): """ Delete an item. Needs to be implemented by the plugin. """ raise NotImplementedError( 'MediaManagerItem.on_delete_click needs to be defined by the plugin' ) def on_focus(self): """ Run when a tab in the media manager gains focus. This gives the media item a chance to focus any elements it wants to. """ pass def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False, context=ServiceItemContext.Live): """ Generate the slide data. Needs to be implemented by the plugin. :param service_item: The service Item to be processed :param item: The database item to be used to build the service item :param xml_version: :param remote: Was this remote triggered (False) :param context: The service context """ raise NotImplementedError( 'MediaManagerItem.generate_slide_data needs to be defined by the plugin' ) def on_double_clicked(self): """ Allows the list click action to be determined dynamically """ if Settings().value('advanced/double click live'): self.on_live_click() elif not Settings().value('advanced/single click preview'): # NOTE: The above check is necessary to prevent bug #1419300 self.on_preview_click() def on_selection_change(self): """ Allows the change of current item in the list to be actioned """ if Settings().value('advanced/single click preview') and self.quick_preview_allowed \ and self.list_view.selectedIndexes() and self.auto_select_id == -1: self.on_preview_click(True) def on_preview_click(self, keep_focus=False): """ Preview an item by building a service item then adding that service item to the preview slide controller. :param keep_focus: Do we keep focus (False) """ if not self.list_view.selectedIndexes() and not self.remote_triggered: QtWidgets.QMessageBox.information( self, UiStrings().NISp, translate('OpenLP.MediaManagerItem', 'You must select one or more items to preview.')) else: log.debug('%s Preview requested' % self.plugin.name) service_item = self.build_service_item() if service_item: service_item.from_plugin = True self.preview_controller.add_service_item(service_item) if not keep_focus: self.preview_controller.preview_widget.setFocus() def on_live_click(self): """ Send an item live by building a service item then adding that service item to the live slide controller. """ if not self.list_view.selectedIndexes(): QtWidgets.QMessageBox.information( self, UiStrings().NISp, translate('OpenLP.MediaManagerItem', 'You must select one or more items to send live.')) else: self.go_live() def go_live_remote(self, message): """ Remote Call wrapper :param message: The passed data item_id:Remote. """ self.go_live(message[0], remote=message[1]) def go_live(self, item_id=None, remote=False): """ Make the currently selected item go live. :param item_id: item to make live :param remote: From Remote """ log.debug('%s Live requested', self.plugin.name) item = None if item_id: item = self.create_item_from_id(item_id) service_item = self.build_service_item(item, remote=remote) if service_item: if not item_id: service_item.from_plugin = True if remote: service_item.will_auto_start = True self.live_controller.add_service_item(service_item) self.live_controller.preview_widget.setFocus() def create_item_from_id(self, item_id): """ Create a media item from an item id. :param item_id: Id to make live """ item = QtWidgets.QListWidgetItem() item.setData(QtCore.Qt.UserRole, item_id) return item def on_add_click(self): """ Add a selected item to the current service """ if not self.list_view.selectedIndexes(): QtWidgets.QMessageBox.information( self, UiStrings().NISp, translate('OpenLP.MediaManagerItem', 'You must select one or more items to add.')) else: # Is it possible to process multiple list items to generate # multiple service items? if self.single_service_item: log.debug('%s Add requested', self.plugin.name) self.add_to_service(replace=self.remote_triggered) else: items = self.list_view.selectedIndexes() drop_position = self.service_manager.get_drop_position() for item in items: self.add_to_service(item, position=drop_position) if drop_position != -1: drop_position += 1 def add_to_service_remote(self, message): """ Remote Call wrapper :param message: The passed data item:Remote. """ self.add_to_service(message[0], remote=message[1]) def add_to_service(self, item=None, replace=None, remote=False, position=-1): """ Add this item to the current service. :param item: Item to be processed :param replace: Replace the existing item :param remote: Triggered from remote :param position: Position to place item """ service_item = self.build_service_item( item, True, remote=remote, context=ServiceItemContext.Service) if service_item: service_item.from_plugin = False self.service_manager.add_service_item(service_item, replace=replace, position=position) def on_add_edit_click(self): """ Add a selected item to an existing item in the current service. """ if not self.list_view.selectedIndexes() and not self.remote_triggered: QtWidgets.QMessageBox.information( self, UiStrings().NISp, translate('OpenLP.MediaManagerItem', 'You must select one or more items.')) else: log.debug('%s Add requested', self.plugin.name) service_item = self.service_manager.get_service_item() if not service_item: QtWidgets.QMessageBox.information( self, UiStrings().NISs, translate( 'OpenLP.MediaManagerItem', 'You must select an existing service item to add to.')) elif self.plugin.name == service_item.name: self.generate_slide_data(service_item) self.service_manager.add_service_item(service_item, replace=True) else: # Turn off the remote edit update message indicator QtWidgets.QMessageBox.information( self, translate('OpenLP.MediaManagerItem', 'Invalid Service Item'), translate('OpenLP.MediaManagerItem', 'You must select a %s service item.') % self.title) def build_service_item(self, item=None, xml_version=False, remote=False, context=ServiceItemContext.Live): """ Common method for generating a service item :param item: Service Item to be built. :param xml_version: version of XML (False) :param remote: Remote triggered (False) :param context: The context on which this is called """ service_item = ServiceItem(self.plugin) service_item.add_icon(self.plugin.icon_path) if self.generate_slide_data(service_item, item, xml_version, remote, context): return service_item else: return None def service_load(self, item): """ Method to add processing when a service has been loaded and individual service items need to be processed by the plugins. :param item: The item to be processed and returned. """ return item def check_search_result(self): """ Checks if the list_view is empty and adds a "No Search Results" item. """ if self.list_view.count(): return message = translate('OpenLP.MediaManagerItem', 'No Search Results') item = QtWidgets.QListWidgetItem(message) item.setFlags(QtCore.Qt.NoItemFlags) font = QtGui.QFont() font.setItalic(True) item.setFont(font) self.list_view.addItem(item) def _get_id_of_item_to_generate(self, item, remote_item): """ Utility method to check items being submitted for slide generation. :param item: The item to check. :param remote_item: The id to assign if the slide generation was remotely triggered. """ if item is None: if self.remote_triggered is None: item = self.list_view.currentItem() if item is None: return False item_id = item.data(QtCore.Qt.UserRole) else: item_id = remote_item else: item_id = item.data(QtCore.Qt.UserRole) return item_id def save_auto_select_id(self): """ Sorts out, what item to select after loading a list. """ # The item to select has not been set. if self.auto_select_id == -1: item = self.list_view.currentItem() if item: self.auto_select_id = item.data(QtCore.Qt.UserRole) def search(self, string, show_error=True): """ Performs a plugin specific search for items containing ``string`` :param string: String to be displayed :param show_error: Should the error be shown (True) """ raise NotImplementedError( 'Plugin.search needs to be defined by the plugin')
class Ui_ThemeManager(object): """ UI part of the Theme Manager """ def setup_ui(self, widget): """ Define the UI :param widget: The screen object the the dialog is to be attached to. """ # start with the layout self.layout = QtWidgets.QVBoxLayout(widget) self.layout.setSpacing(0) self.layout.setContentsMargins(0, 0, 0, 0) self.layout.setObjectName('layout') self.toolbar = OpenLPToolbar(widget) self.toolbar.setObjectName('toolbar') self.toolbar.add_toolbar_action('newTheme', text=UiStrings().NewTheme, icon=':/themes/theme_new.png', tooltip=translate( 'OpenLP.ThemeManager', 'Create a new theme.'), triggers=self.on_add_theme) self.toolbar.add_toolbar_action( 'editTheme', text=translate('OpenLP.ThemeManager', 'Edit Theme'), icon=':/themes/theme_edit.png', tooltip=translate('OpenLP.ThemeManager', 'Edit a theme.'), triggers=self.on_edit_theme) self.delete_toolbar_action = self.toolbar.add_toolbar_action( 'delete_theme', text=translate('OpenLP.ThemeManager', 'Delete Theme'), icon=':/general/general_delete.png', tooltip=translate('OpenLP.ThemeManager', 'Delete a theme.'), triggers=self.on_delete_theme) self.toolbar.addSeparator() self.toolbar.add_toolbar_action( 'importTheme', text=translate('OpenLP.ThemeManager', 'Import Theme'), icon=':/general/general_import.png', tooltip=translate('OpenLP.ThemeManager', 'Import a theme.'), triggers=self.on_import_theme) self.toolbar.add_toolbar_action( 'exportTheme', text=translate('OpenLP.ThemeManager', 'Export Theme'), icon=':/general/general_export.png', tooltip=translate('OpenLP.ThemeManager', 'Export a theme.'), triggers=self.on_export_theme) self.layout.addWidget(self.toolbar) self.theme_widget = QtWidgets.QWidgetAction(self.toolbar) self.theme_widget.setObjectName('theme_widget') # create theme manager list self.theme_list_widget = QtWidgets.QListWidget(widget) self.theme_list_widget.setAlternatingRowColors(True) self.theme_list_widget.setIconSize(QtCore.QSize(88, 50)) self.theme_list_widget.setContextMenuPolicy( QtCore.Qt.CustomContextMenu) self.theme_list_widget.setObjectName('theme_list_widget') self.layout.addWidget(self.theme_list_widget) self.theme_list_widget.customContextMenuRequested.connect( self.context_menu) # build the context menu self.menu = QtWidgets.QMenu() self.edit_action = create_widget_action(self.menu, text=translate( 'OpenLP.ThemeManager', '&Edit Theme'), icon=':/themes/theme_edit.png', triggers=self.on_edit_theme) self.copy_action = create_widget_action(self.menu, text=translate( 'OpenLP.ThemeManager', '&Copy Theme'), icon=':/themes/theme_edit.png', triggers=self.on_copy_theme) self.rename_action = create_widget_action( self.menu, text=translate('OpenLP.ThemeManager', '&Rename Theme'), icon=':/themes/theme_edit.png', triggers=self.on_rename_theme) self.delete_action = create_widget_action( self.menu, text=translate('OpenLP.ThemeManager', '&Delete Theme'), icon=':/general/general_delete.png', triggers=self.on_delete_theme) self.menu.addSeparator() self.global_action = create_widget_action( self.menu, text=translate('OpenLP.ThemeManager', 'Set As &Global Default'), icon=':/general/general_export.png', triggers=self.change_global_from_screen) self.export_action = create_widget_action( self.menu, text=translate('OpenLP.ThemeManager', '&Export Theme'), icon=':/general/general_export.png', triggers=self.on_export_theme) # Signals self.theme_list_widget.doubleClicked.connect( self.change_global_from_screen) self.theme_list_widget.currentItemChanged.connect( self.check_list_state)
class Ui_LoopManager(object): """ UI part of the Loop Manager """ def setup_ui(self, widget): """ Define the UI :param widget: The screen object the the dialog is to be attached to. """ # start with the layout self.layout = QtGui.QVBoxLayout(widget) self.layout.setSpacing(0) self.layout.setMargin(0) self.layout.setObjectName('layout') self.toolbar = OpenLPToolbar(widget) self.toolbar.setObjectName('toolbar') self.add_toolbar_action = self.toolbar.add_toolbar_action('add_loop', text=translate('OpenLP.LoopManager', 'Add Loop'), icon=':/general/general_add.png', tooltip=translate('OpenLP.LoopManager', 'Add a loop.'), triggers=self.on_add_loop) self.delete_toolbar_action = self.toolbar.add_toolbar_action('delete_loop', text=translate('OpenLP.LoopManager', 'Delete Loop'), icon=':/general/general_delete.png', tooltip=translate('OpenLP.LoopManager', 'Delete a loop.'), triggers=self.on_delete_loop) self.toolbar.addSeparator() self.play_toolbar_action = self.toolbar.add_toolbar_action('play_loop', text=translate('OpenLP.LoopManager', 'Play Loop'), icon=':/slides/media_playback_start.png', tooltip=translate('OpenLP.LoopManager', 'Play a loop.'), triggers=self.on_display_loop) self.stop_toolbar_action = self.toolbar.add_toolbar_action('stop_loop', text=translate('OpenLP.LoopManager', 'Stop Active Loop'), icon=':/slides/media_playback_stop.png', tooltip=translate('OpenLP.LoopManager', 'Stop playback of active loop.'), triggers=self.on_stop_loop) self.layout.addWidget(self.toolbar) self.loop_widget = QtGui.QWidgetAction(self.toolbar) self.loop_widget.setObjectName('loop_widget') # create loop manager list self.loop_list_widget = QtGui.QListWidget(widget) self.loop_list_widget.setAlternatingRowColors(True) self.loop_list_widget.setIconSize(QtCore.QSize(88, 50)) self.loop_list_widget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.loop_list_widget.setObjectName('loop_list_widget') self.layout.addWidget(self.loop_list_widget) self.loop_list_widget.customContextMenuRequested.connect(self.context_menu) # build the context menu self.menu = QtGui.QMenu() self.rename_action = create_widget_action(self.menu, text=translate('OpenLP.LoopManager', '&Rename Loop'), icon=':/general/general_edit.png', triggers=self.on_rename_loop) self.delete_action = create_widget_action(self.menu, text=translate('OpenLP.LoopManager', '&Delete Loop'), icon=':/general/general_delete.png', triggers=self.on_delete_loop) self.menu.addSeparator() self.display_action = create_widget_action(self.menu, text=translate('OpenLP.LoopManager', 'Dis&play Loop'), icon=':/slides/media_playback_start.png', triggers=self.on_display_loop) # Signals self.loop_list_widget.doubleClicked.connect(self.on_display_loop)
class Ui_ProjectorManager(object): """ UI part of the Projector Manager """ def setup_ui(self, widget): """ Define the UI :param widget: The screen object the dialog is to be attached to. """ log.debug('setup_ui()') # Create ProjectorManager box self.layout = QtGui.QVBoxLayout(widget) self.layout.setSpacing(0) self.layout.setMargin(0) self.layout.setObjectName('layout') # Add one selection toolbar self.one_toolbar = OpenLPToolbar(widget) self.one_toolbar.add_toolbar_action( 'new_projector', text=translate('OpenLP.ProjectorManager', 'Add Projector'), icon=':/projector/projector_new.png', tooltip=translate('OpenLP.ProjectorManager', 'Add a new projector'), triggers=self.on_add_projector) # Show edit/delete when projector not connected self.one_toolbar.add_toolbar_action( 'edit_projector', text=translate('OpenLP.ProjectorManager', 'Edit Projector'), icon=':/general/general_edit.png', tooltip=translate('OpenLP.ProjectorManager', 'Edit selected projector'), triggers=self.on_edit_projector) self.one_toolbar.add_toolbar_action( 'delete_projector', text=translate('OpenLP.ProjectorManager', 'Delete Projector'), icon=':/general/general_delete.png', tooltip=translate('OpenLP.ProjectorManager', 'Delete selected projector'), triggers=self.on_delete_projector) # Show source/view when projector connected self.one_toolbar.add_toolbar_action( 'source_view_projector', text=translate('OpenLP.ProjectorManager', 'Select Input Source'), icon=':/projector/projector_hdmi.png', tooltip=translate('OpenLP.ProjectorManager', 'Choose input source on selected projector'), triggers=self.on_select_input) self.one_toolbar.add_toolbar_action( 'view_projector', text=translate('OpenLP.ProjectorManager', 'View Projector'), icon=':/system/system_about.png', tooltip=translate('OpenLP.ProjectorManager', 'View selected projector information'), triggers=self.on_status_projector) self.one_toolbar.addSeparator() self.one_toolbar.add_toolbar_action( 'connect_projector', text=translate('OpenLP.ProjectorManager', 'Connect to selected projector'), icon=':/projector/projector_connect.png', tooltip=translate('OpenLP.ProjectorManager', 'Connect to selected projector'), triggers=self.on_connect_projector) self.one_toolbar.add_toolbar_action( 'connect_projector_multiple', text=translate('OpenLP.ProjectorManager', 'Connect to selected projectors'), icon=':/projector/projector_connect_tiled.png', tooltip=translate('OpenLP.ProjectorManager', 'Connect to selected projector'), triggers=self.on_connect_projector) self.one_toolbar.add_toolbar_action( 'disconnect_projector', text=translate('OpenLP.ProjectorManager', 'Disconnect from selected projectors'), icon=':/projector/projector_disconnect.png', tooltip=translate('OpenLP.ProjectorManager', 'Disconnect from selected projector'), triggers=self.on_disconnect_projector) self.one_toolbar.add_toolbar_action( 'disconnect_projector_multiple', text=translate('OpenLP.ProjectorManager', 'Disconnect from selected projector'), icon=':/projector/projector_disconnect_tiled.png', tooltip=translate('OpenLP.ProjectorManager', 'Disconnect from selected projector'), triggers=self.on_disconnect_projector) self.one_toolbar.addSeparator() self.one_toolbar.add_toolbar_action( 'poweron_projector', text=translate('OpenLP.ProjectorManager', 'Power on selected projector'), icon=':/projector/projector_power_on.png', tooltip=translate('OpenLP.ProjectorManager', 'Power on selected projector'), triggers=self.on_poweron_projector) self.one_toolbar.add_toolbar_action( 'poweron_projector_multiple', text=translate('OpenLP.ProjectorManager', 'Power on selected projector'), icon=':/projector/projector_power_on_tiled.png', tooltip=translate('OpenLP.ProjectorManager', 'Power on selected projector'), triggers=self.on_poweron_projector) self.one_toolbar.add_toolbar_action( 'poweroff_projector', text=translate('OpenLP.ProjectorManager', 'Standby selected projector'), icon=':/projector/projector_power_off.png', tooltip=translate('OpenLP.ProjectorManager', 'Put selected projector in standby'), triggers=self.on_poweroff_projector) self.one_toolbar.add_toolbar_action( 'poweroff_projector_multiple', text=translate('OpenLP.ProjectorManager', 'Standby selected projector'), icon=':/projector/projector_power_off_tiled.png', tooltip=translate('OpenLP.ProjectorManager', 'Put selected projector in standby'), triggers=self.on_poweroff_projector) self.one_toolbar.addSeparator() self.one_toolbar.add_toolbar_action( 'blank_projector', text=translate('OpenLP.ProjectorManager', 'Blank selected projector screen'), icon=':/projector/projector_blank.png', tooltip=translate('OpenLP.ProjectorManager', 'Blank selected projector screen'), triggers=self.on_blank_projector) self.one_toolbar.add_toolbar_action( 'blank_projector_multiple', text=translate('OpenLP.ProjectorManager', 'Blank selected projector screen'), icon=':/projector/projector_blank_tiled.png', tooltip=translate('OpenLP.ProjectorManager', 'Blank selected projector screen'), triggers=self.on_blank_projector) self.one_toolbar.add_toolbar_action( 'show_projector', text=translate('OpenLP.ProjectorManager', 'Show selected projector screen'), icon=':/projector/projector_show.png', tooltip=translate('OpenLP.ProjectorManager', 'Show selected projector screen'), triggers=self.on_show_projector) self.one_toolbar.add_toolbar_action( 'show_projector_multiple', text=translate('OpenLP.ProjectorManager', 'Show selected projector screen'), icon=':/projector/projector_show_tiled.png', tooltip=translate('OpenLP.ProjectorManager', 'Show selected projector screen'), triggers=self.on_show_projector) self.layout.addWidget(self.one_toolbar) self.projector_one_widget = QtGui.QWidgetAction(self.one_toolbar) self.projector_one_widget.setObjectName('projector_one_toolbar_widget') # Create projector manager list self.projector_list_widget = QtGui.QListWidget(widget) self.projector_list_widget.setSelectionMode( QtGui.QAbstractItemView.ExtendedSelection) self.projector_list_widget.setAlternatingRowColors(True) self.projector_list_widget.setIconSize(QtCore.QSize(90, 50)) self.projector_list_widget.setContextMenuPolicy( QtCore.Qt.CustomContextMenu) self.projector_list_widget.setObjectName('projector_list_widget') self.layout.addWidget(self.projector_list_widget) self.projector_list_widget.customContextMenuRequested.connect( self.context_menu) self.projector_list_widget.itemDoubleClicked.connect( self.on_doubleclick_item) # Build the context menu self.menu = QtGui.QMenu() self.status_action = create_widget_action( self.menu, text=translate('OpenLP.ProjectorManager', '&View Projector Information'), icon=':/system/system_about.png', triggers=self.on_status_projector) self.edit_action = create_widget_action( self.menu, text=translate('OpenLP.ProjectorManager', '&Edit Projector'), icon=':/projector/projector_edit.png', triggers=self.on_edit_projector) self.menu.addSeparator() self.connect_action = create_widget_action( self.menu, text=translate('OpenLP.ProjectorManager', '&Connect Projector'), icon=':/projector/projector_connect.png', triggers=self.on_connect_projector) self.disconnect_action = create_widget_action( self.menu, text=translate('OpenLP.ProjectorManager', 'D&isconnect Projector'), icon=':/projector/projector_disconnect.png', triggers=self.on_disconnect_projector) self.menu.addSeparator() self.poweron_action = create_widget_action( self.menu, text=translate('OpenLP.ProjectorManager', 'Power &On Projector'), icon=':/projector/projector_power_on.png', triggers=self.on_poweron_projector) self.poweroff_action = create_widget_action( self.menu, text=translate('OpenLP.ProjectorManager', 'Power O&ff Projector'), icon=':/projector/projector_power_off.png', triggers=self.on_poweroff_projector) self.menu.addSeparator() self.select_input_action = create_widget_action( self.menu, text=translate('OpenLP.ProjectorManager', 'Select &Input'), icon=':/projector/projector_hdmi.png', triggers=self.on_select_input) self.edit_input_action = create_widget_action( self.menu, text=translate('OpenLP.ProjectorManager', 'Edit Input Source'), icon=':/general/general_edit.png', triggers=self.on_edit_input) self.blank_action = create_widget_action( self.menu, text=translate('OpenLP.ProjectorManager', '&Blank Projector Screen'), icon=':/projector/projector_blank.png', triggers=self.on_blank_projector) self.show_action = create_widget_action( self.menu, text=translate('OpenLP.ProjectorManager', '&Show Projector Screen'), icon=':/projector/projector_show.png', triggers=self.on_show_projector) self.menu.addSeparator() self.delete_action = create_widget_action( self.menu, text=translate('OpenLP.ProjectorManager', '&Delete Projector'), icon=':/general/general_delete.png', triggers=self.on_delete_projector) self.update_icons()
class Ui_ProjectorManager(object): """ UI part of the Projector Manager """ def setup_ui(self, widget): """ Define the UI :param widget: The screen object the dialog is to be attached to. """ log.debug('setup_ui()') # Create ProjectorManager box self.layout = QtGui.QVBoxLayout(widget) self.layout.setSpacing(0) self.layout.setMargin(0) self.layout.setObjectName('layout') # Add one selection toolbar self.one_toolbar = OpenLPToolbar(widget) self.one_toolbar.add_toolbar_action('new_projector', text=translate('OpenLP.ProjectorManager', 'Add Projector'), icon=':/projector/projector_new.png', tooltip=translate('OpenLP.ProjectorManager', 'Add a new projector'), triggers=self.on_add_projector) # Show edit/delete when projector not connected self.one_toolbar.add_toolbar_action('edit_projector', text=translate('OpenLP.ProjectorManager', 'Edit Projector'), icon=':/general/general_edit.png', tooltip=translate('OpenLP.ProjectorManager', 'Edit selected projector'), triggers=self.on_edit_projector) self.one_toolbar.add_toolbar_action('delete_projector', text=translate('OpenLP.ProjectorManager', 'Delete Projector'), icon=':/general/general_delete.png', tooltip=translate('OpenLP.ProjectorManager', 'Delete selected projector'), triggers=self.on_delete_projector) # Show source/view when projector connected self.one_toolbar.add_toolbar_action('source_view_projector', text=translate('OpenLP.ProjectorManager', 'Select Input Source'), icon=':/projector/projector_hdmi.png', tooltip=translate('OpenLP.ProjectorManager', 'Choose input source on selected projector'), triggers=self.on_select_input) self.one_toolbar.add_toolbar_action('view_projector', text=translate('OpenLP.ProjectorManager', 'View Projector'), icon=':/system/system_about.png', tooltip=translate('OpenLP.ProjectorManager', 'View selected projector information'), triggers=self.on_status_projector) self.one_toolbar.addSeparator() self.one_toolbar.add_toolbar_action('connect_projector', text=translate('OpenLP.ProjectorManager', 'Connect to selected projector'), icon=':/projector/projector_connect.png', tooltip=translate('OpenLP.ProjectorManager', 'Connect to selected projector'), triggers=self.on_connect_projector) self.one_toolbar.add_toolbar_action('connect_projector_multiple', text=translate('OpenLP.ProjectorManager', 'Connect to selected projectors'), icon=':/projector/projector_connect_tiled.png', tooltip=translate('OpenLP.ProjectorManager', 'Connect to selected projector'), triggers=self.on_connect_projector) self.one_toolbar.add_toolbar_action('disconnect_projector', text=translate('OpenLP.ProjectorManager', 'Disconnect from selected projectors'), icon=':/projector/projector_disconnect.png', tooltip=translate('OpenLP.ProjectorManager', 'Disconnect from selected projector'), triggers=self.on_disconnect_projector) self.one_toolbar.add_toolbar_action('disconnect_projector_multiple', text=translate('OpenLP.ProjectorManager', 'Disconnect from selected projector'), icon=':/projector/projector_disconnect_tiled.png', tooltip=translate('OpenLP.ProjectorManager', 'Disconnect from selected projector'), triggers=self.on_disconnect_projector) self.one_toolbar.addSeparator() self.one_toolbar.add_toolbar_action('poweron_projector', text=translate('OpenLP.ProjectorManager', 'Power on selected projector'), icon=':/projector/projector_power_on.png', tooltip=translate('OpenLP.ProjectorManager', 'Power on selected projector'), triggers=self.on_poweron_projector) self.one_toolbar.add_toolbar_action('poweron_projector_multiple', text=translate('OpenLP.ProjectorManager', 'Power on selected projector'), icon=':/projector/projector_power_on_tiled.png', tooltip=translate('OpenLP.ProjectorManager', 'Power on selected projector'), triggers=self.on_poweron_projector) self.one_toolbar.add_toolbar_action('poweroff_projector', text=translate('OpenLP.ProjectorManager', 'Standby selected projector'), icon=':/projector/projector_power_off.png', tooltip=translate('OpenLP.ProjectorManager', 'Put selected projector in standby'), triggers=self.on_poweroff_projector) self.one_toolbar.add_toolbar_action('poweroff_projector_multiple', text=translate('OpenLP.ProjectorManager', 'Standby selected projector'), icon=':/projector/projector_power_off_tiled.png', tooltip=translate('OpenLP.ProjectorManager', 'Put selected projector in standby'), triggers=self.on_poweroff_projector) self.one_toolbar.addSeparator() self.one_toolbar.add_toolbar_action('blank_projector', text=translate('OpenLP.ProjectorManager', 'Blank selected projector screen'), icon=':/projector/projector_blank.png', tooltip=translate('OpenLP.ProjectorManager', 'Blank selected projector screen'), triggers=self.on_blank_projector) self.one_toolbar.add_toolbar_action('blank_projector_multiple', text=translate('OpenLP.ProjectorManager', 'Blank selected projector screen'), icon=':/projector/projector_blank_tiled.png', tooltip=translate('OpenLP.ProjectorManager', 'Blank selected projector screen'), triggers=self.on_blank_projector) self.one_toolbar.add_toolbar_action('show_projector', text=translate('OpenLP.ProjectorManager', 'Show selected projector screen'), icon=':/projector/projector_show.png', tooltip=translate('OpenLP.ProjectorManager', 'Show selected projector screen'), triggers=self.on_show_projector) self.one_toolbar.add_toolbar_action('show_projector_multiple', text=translate('OpenLP.ProjectorManager', 'Show selected projector screen'), icon=':/projector/projector_show_tiled.png', tooltip=translate('OpenLP.ProjectorManager', 'Show selected projector screen'), triggers=self.on_show_projector) self.layout.addWidget(self.one_toolbar) self.projector_one_widget = QtGui.QWidgetAction(self.one_toolbar) self.projector_one_widget.setObjectName('projector_one_toolbar_widget') # Create projector manager list self.projector_list_widget = QtGui.QListWidget(widget) self.projector_list_widget.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) self.projector_list_widget.setAlternatingRowColors(True) self.projector_list_widget.setIconSize(QtCore.QSize(90, 50)) self.projector_list_widget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.projector_list_widget.setObjectName('projector_list_widget') self.layout.addWidget(self.projector_list_widget) self.projector_list_widget.customContextMenuRequested.connect(self.context_menu) self.projector_list_widget.itemDoubleClicked.connect(self.on_doubleclick_item) # Build the context menu self.menu = QtGui.QMenu() self.status_action = create_widget_action(self.menu, text=translate('OpenLP.ProjectorManager', '&View Projector Information'), icon=':/system/system_about.png', triggers=self.on_status_projector) self.edit_action = create_widget_action(self.menu, text=translate('OpenLP.ProjectorManager', '&Edit Projector'), icon=':/projector/projector_edit.png', triggers=self.on_edit_projector) self.menu.addSeparator() self.connect_action = create_widget_action(self.menu, text=translate('OpenLP.ProjectorManager', '&Connect Projector'), icon=':/projector/projector_connect.png', triggers=self.on_connect_projector) self.disconnect_action = create_widget_action(self.menu, text=translate('OpenLP.ProjectorManager', 'D&isconnect Projector'), icon=':/projector/projector_disconnect.png', triggers=self.on_disconnect_projector) self.menu.addSeparator() self.poweron_action = create_widget_action(self.menu, text=translate('OpenLP.ProjectorManager', 'Power &On Projector'), icon=':/projector/projector_power_on.png', triggers=self.on_poweron_projector) self.poweroff_action = create_widget_action(self.menu, text=translate('OpenLP.ProjectorManager', 'Power O&ff Projector'), icon=':/projector/projector_power_off.png', triggers=self.on_poweroff_projector) self.menu.addSeparator() self.select_input_action = create_widget_action(self.menu, text=translate('OpenLP.ProjectorManager', 'Select &Input'), icon=':/projector/projector_hdmi.png', triggers=self.on_select_input) self.edit_input_action = create_widget_action(self.menu, text=translate('OpenLP.ProjectorManager', 'Edit Input Source'), icon=':/general/general_edit.png', triggers=self.on_edit_input) self.blank_action = create_widget_action(self.menu, text=translate('OpenLP.ProjectorManager', '&Blank Projector Screen'), icon=':/projector/projector_blank.png', triggers=self.on_blank_projector) self.show_action = create_widget_action(self.menu, text=translate('OpenLP.ProjectorManager', '&Show Projector Screen'), icon=':/projector/projector_show.png', triggers=self.on_show_projector) self.menu.addSeparator() self.delete_action = create_widget_action(self.menu, text=translate('OpenLP.ProjectorManager', '&Delete Projector'), icon=':/general/general_delete.png', triggers=self.on_delete_projector) self.update_icons()
class MediaManagerItem(QtGui.QWidget, RegistryProperties): """ MediaManagerItem is a helper widget for plugins. None of the following *need* to be used, feel free to override them completely in your plugin's implementation. Alternatively, call them from your plugin before or after you've done extra things that you need to. **Constructor Parameters** ``parent`` The parent widget. Usually this will be the *Media Manager* itself. This needs to be a class descended from ``QWidget``. ``plugin`` The plugin widget. Usually this will be the *Plugin* itself. This needs to be a class descended from ``Plugin``. **Member Variables** When creating a descendant class from this class for your plugin, the following member variables should be set. ``self.on_new_prompt`` Defaults to *'Select Image(s)'*. ``self.on_new_file_masks`` Defaults to *'Images (*.jpg *jpeg *.gif *.png *.bmp)'*. This assumes that the new action is to load a file. If not, you need to override the ``OnNew`` method. ``self.PreviewFunction`` This must be a method which returns a QImage to represent the item (usually a preview). No scaling is required, that is performed automatically by OpenLP when necessary. If this method is not defined, a default will be used (treat the filename as an image). """ log.info('Media Item loaded') def __init__(self, parent=None, plugin=None): """ Constructor to create the media manager item. """ super(MediaManagerItem, self).__init__(parent) self.plugin = plugin self._setup() self.setup_item() def _setup(self): """ Run some initial setup. This method is separate from __init__ in order to mock it out in tests. """ self.hide() self.whitespace = re.compile(r'[\W_]+', re.UNICODE) visible_title = self.plugin.get_string(StringContent.VisibleName) self.title = str(visible_title['title']) Registry().register(self.plugin.name, self) self.settings_section = self.plugin.name self.toolbar = None self.remote_triggered = None self.single_service_item = True self.quick_preview_allowed = False self.has_search = False self.page_layout = QtGui.QVBoxLayout(self) self.page_layout.setSpacing(0) self.page_layout.setMargin(0) self.required_icons() self.setupUi() self.retranslateUi() self.auto_select_id = -1 # Need to use event as called across threads and UI is updated QtCore.QObject.connect(self, QtCore.SIGNAL('%s_go_live' % self.plugin.name), self.go_live_remote) QtCore.QObject.connect(self, QtCore.SIGNAL('%s_add_to_service' % self.plugin.name), self.add_to_service_remote) def setup_item(self): """ Override this for additional Plugin setup """ pass def required_icons(self): """ This method is called to define the icons for the plugin. It provides a default set and the plugin is able to override the if required. """ self.has_import_icon = False self.has_new_icon = True self.has_edit_icon = True self.has_file_icon = False self.has_delete_icon = True self.add_to_service_item = False def retranslateUi(self): """ This method is called automatically to provide OpenLP with the opportunity to translate the ``MediaManagerItem`` to another language. """ pass def add_toolbar(self): """ A method to help developers easily add a toolbar to the media manager item. """ if self.toolbar is None: self.toolbar = OpenLPToolbar(self) self.page_layout.addWidget(self.toolbar) def setupUi(self): """ This method sets up the interface on the button. Plugin developers use this to add and create toolbars, and the rest of the interface of the media manager item. """ # Add a toolbar self.add_toolbar() # Allow the plugin to define buttons at start of bar self.add_start_header_bar() # Add the middle of the tool bar (pre defined) self.add_middle_header_bar() # Allow the plugin to define buttons at end of bar self.add_end_header_bar() # Add the list view self.add_list_view_to_toolbar() def add_middle_header_bar(self): """ Create buttons for the media item toolbar """ toolbar_actions = [] # Import Button if self.has_import_icon: toolbar_actions.append(['Import', StringContent.Import, ':/general/general_import.png', self.on_import_click]) # Load Button if self.has_file_icon: toolbar_actions.append(['Load', StringContent.Load, ':/general/general_open.png', self.on_file_click]) # New Button if self.has_new_icon: toolbar_actions.append(['New', StringContent.New, ':/general/general_new.png', self.on_new_click]) # Edit Button if self.has_edit_icon: toolbar_actions.append(['Edit', StringContent.Edit, ':/general/general_edit.png', self.on_edit_click]) # Delete Button if self.has_delete_icon: toolbar_actions.append(['Delete', StringContent.Delete, ':/general/general_delete.png', self.on_delete_click]) # Preview toolbar_actions.append(['Preview', StringContent.Preview, ':/general/general_preview.png', self.on_preview_click]) # Live Button toolbar_actions.append(['Live', StringContent.Live, ':/general/general_live.png', self.on_live_click]) # Add to service Button toolbar_actions.append(['Service', StringContent.Service, ':/general/general_add.png', self.on_add_click]) for action in toolbar_actions: if action[0] == StringContent.Preview: self.toolbar.addSeparator() self.toolbar.add_toolbar_action('%s%sAction' % (self.plugin.name, action[0]), text=self.plugin.get_string(action[1])['title'], icon=action[2], tooltip=self.plugin.get_string(action[1])['tooltip'], triggers=action[3]) def add_list_view_to_toolbar(self): """ Creates the main widget for listing items the media item is tracking """ # Add the List widget self.list_view = ListWidgetWithDnD(self, self.plugin.name) self.list_view.setSpacing(1) self.list_view.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) self.list_view.setAlternatingRowColors(True) self.list_view.setObjectName('%sListView' % self.plugin.name) # Add to page_layout self.page_layout.addWidget(self.list_view) # define and add the context menu self.list_view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) if self.has_edit_icon: create_widget_action(self.list_view, text=self.plugin.get_string(StringContent.Edit)['title'], icon=':/general/general_edit.png', triggers=self.on_edit_click) create_widget_action(self.list_view, separator=True) create_widget_action(self.list_view, 'listView%s%sItem' % (self.plugin.name.title(), StringContent.Preview.title()), text=self.plugin.get_string(StringContent.Preview)['title'], icon=':/general/general_preview.png', can_shortcuts=True, triggers=self.on_preview_click) create_widget_action(self.list_view, 'listView%s%sItem' % (self.plugin.name.title(), StringContent.Live.title()), text=self.plugin.get_string(StringContent.Live)['title'], icon=':/general/general_live.png', can_shortcuts=True, triggers=self.on_live_click) create_widget_action(self.list_view, 'listView%s%sItem' % (self.plugin.name.title(), StringContent.Service.title()), can_shortcuts=True, text=self.plugin.get_string(StringContent.Service)['title'], icon=':/general/general_add.png', triggers=self.on_add_click) if self.has_delete_icon: create_widget_action(self.list_view, separator=True) create_widget_action(self.list_view, 'listView%s%sItem' % (self.plugin.name.title(), StringContent.Delete.title()), text=self.plugin.get_string(StringContent.Delete)['title'], icon=':/general/general_delete.png', can_shortcuts=True, triggers=self.on_delete_click) if self.add_to_service_item: create_widget_action(self.list_view, separator=True) create_widget_action(self.list_view, text=translate('OpenLP.MediaManagerItem', '&Add to selected Service Item'), icon=':/general/general_add.png', triggers=self.on_add_edit_click) self.add_custom_context_actions() # Create the context menu and add all actions from the list_view. self.menu = QtGui.QMenu() self.menu.addActions(self.list_view.actions()) self.list_view.doubleClicked.connect(self.on_double_clicked) self.list_view.itemSelectionChanged.connect(self.on_selection_change) self.list_view.customContextMenuRequested.connect(self.context_menu) def add_search_to_toolbar(self): """ Creates a search field with button and related signal handling. """ self.search_widget = QtGui.QWidget(self) self.search_widget.setObjectName('search_widget') self.search_layout = QtGui.QVBoxLayout(self.search_widget) self.search_layout.setObjectName('search_layout') self.search_text_layout = QtGui.QFormLayout() self.search_text_layout.setObjectName('search_text_layout') self.search_text_label = QtGui.QLabel(self.search_widget) self.search_text_label.setObjectName('search_text_label') self.search_text_edit = SearchEdit(self.search_widget) self.search_text_edit.setObjectName('search_text_edit') self.search_text_label.setBuddy(self.search_text_edit) self.search_text_layout.addRow(self.search_text_label, self.search_text_edit) self.search_layout.addLayout(self.search_text_layout) self.search_button_layout = QtGui.QHBoxLayout() self.search_button_layout.setObjectName('search_button_layout') self.search_button_layout.addStretch() self.search_text_button = QtGui.QPushButton(self.search_widget) self.search_text_button.setObjectName('search_text_button') self.search_button_layout.addWidget(self.search_text_button) self.search_layout.addLayout(self.search_button_layout) self.page_layout.addWidget(self.search_widget) # Signals and slots self.search_text_edit.returnPressed.connect(self.on_search_text_button_clicked) self.search_text_button.clicked.connect(self.on_search_text_button_clicked) self.search_text_edit.textChanged.connect(self.on_search_text_edit_changed) def add_custom_context_actions(self): """ Implement this method in your descendant media manager item to add any context menu items. This method is called automatically. """ pass def initialise(self): """ Implement this method in your descendant media manager item to do any UI or other initialisation. This method is called automatically. """ pass def add_start_header_bar(self): """ Slot at start of toolbar for plugin to add widgets """ pass def add_end_header_bar(self): """ Slot at end of toolbar for plugin to add widgets """ pass def on_file_click(self): """ Add a file to the list widget to make it available for showing """ files = FileDialog.getOpenFileNames(self, self.on_new_prompt, Settings().value(self.settings_section + '/last directory'), self.on_new_file_masks) log.info('New files(s) %s' % files) if files: self.application.set_busy_cursor() self.validate_and_load(files) self.application.set_normal_cursor() def load_file(self, data): """ Turn file from Drag and Drop into an array so the Validate code can run it. :param data: A dictionary containing the list of files to be loaded and the target """ new_files = [] error_shown = False for file_name in data['files']: file_type = file_name.split('.')[-1] if file_type.lower() not in self.on_new_file_masks: if not error_shown: critical_error_message_box(translate('OpenLP.MediaManagerItem', 'Invalid File Type'), translate('OpenLP.MediaManagerItem', 'Invalid File %s.\nSuffix not supported') % file_name) error_shown = True else: new_files.append(file_name) if new_files: self.validate_and_load(new_files, data['target']) def dnd_move_internal(self, target): """ Handle internal moving of media manager items :param target: The target of the DnD action """ pass def validate_and_load(self, files, target_group=None): """ Process a list for files either from the File Dialog or from Drag and Drop :param files: The files to be loaded. :param target_group: The QTreeWidgetItem of the group that will be the parent of the added files """ names = [] full_list = [] for count in range(self.list_view.count()): names.append(self.list_view.item(count).text()) full_list.append(self.list_view.item(count).data(QtCore.Qt.UserRole)) duplicates_found = False files_added = False for file_path in files: if file_path in full_list: duplicates_found = True else: files_added = True full_list.append(file_path) if full_list and files_added: if target_group is None: self.list_view.clear() self.load_list(full_list, target_group) last_dir = os.path.split(files[0])[0] Settings().setValue(self.settings_section + '/last directory', last_dir) Settings().setValue('%s/%s files' % (self.settings_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 context_menu(self, point): """ Display a context menu :param point: The point the cursor was at """ item = self.list_view.itemAt(point) # Decide if we have to show the context menu or not. if item is None: return if not item.flags() & QtCore.Qt.ItemIsSelectable: return self.menu.exec_(self.list_view.mapToGlobal(point)) def get_file_list(self): """ Return the current list of files """ file_list = [] for index in range(self.list_view.count()): list_item = self.list_view.item(index) filename = list_item.data(QtCore.Qt.UserRole) file_list.append(filename) return file_list def load_list(self, load_list, target_group): """ Load a list. Needs to be implemented by the plugin. :param load_list: List object to load :param target_group: Group to load """ raise NotImplementedError('MediaManagerItem.loadList needs to be defined by the plugin') def on_new_click(self): """ Hook for plugins to define behaviour for adding new items. """ pass def on_edit_click(self): """ Hook for plugins to define behaviour for editing items. """ pass def on_delete_click(self): """ Delete an item. Needs to be implemented by the plugin. """ raise NotImplementedError('MediaManagerItem.on_delete_click needs to be defined by the plugin') def on_focus(self): """ Run when a tab in the media manager gains focus. This gives the media item a chance to focus any elements it wants to. """ pass def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False, context=ServiceItemContext.Live): """ Generate the slide data. Needs to be implemented by the plugin. :param service_item: The service Item to be processed :param item: The database item to be used to build the service item :param xml_version: :param remote: Was this remote triggered (False) :param context: The service context """ raise NotImplementedError('MediaManagerItem.generate_slide_data needs to be defined by the plugin') def on_double_clicked(self): """ Allows the list click action to be determined dynamically """ if Settings().value('advanced/double click live'): self.on_live_click() elif not Settings().value('advanced/single click preview'): # NOTE: The above check is necessary to prevent bug #1419300 self.on_preview_click() def on_selection_change(self): """ Allows the change of current item in the list to be actioned """ if Settings().value('advanced/single click preview') and self.quick_preview_allowed \ and self.list_view.selectedIndexes() and self.auto_select_id == -1: self.on_preview_click(True) def on_preview_click(self, keep_focus=False): """ Preview an item by building a service item then adding that service item to the preview slide controller. :param keep_focus: Do we keep focus (False) """ if not self.list_view.selectedIndexes() and not self.remote_triggered: QtGui.QMessageBox.information(self, UiStrings().NISp, translate('OpenLP.MediaManagerItem', 'You must select one or more items to preview.')) else: log.debug('%s Preview requested' % self.plugin.name) service_item = self.build_service_item() if service_item: service_item.from_plugin = True self.preview_controller.add_service_item(service_item) if not keep_focus: self.preview_controller.preview_widget.setFocus() def on_live_click(self): """ Send an item live by building a service item then adding that service item to the live slide controller. """ if not self.list_view.selectedIndexes(): QtGui.QMessageBox.information(self, UiStrings().NISp, translate('OpenLP.MediaManagerItem', 'You must select one or more items to send live.')) else: self.go_live() def go_live_remote(self, message): """ Remote Call wrapper :param message: The passed data item_id:Remote. """ self.go_live(message[0], remote=message[1]) def go_live(self, item_id=None, remote=False): """ Make the currently selected item go live. :param item_id: item to make live :param remote: From Remote """ log.debug('%s Live requested', self.plugin.name) item = None if item_id: item = self.create_item_from_id(item_id) service_item = self.build_service_item(item, remote=remote) if service_item: if not item_id: service_item.from_plugin = True if remote: service_item.will_auto_start = True self.live_controller.add_service_item(service_item) self.live_controller.preview_widget.setFocus() def create_item_from_id(self, item_id): """ Create a media item from an item id. :param item_id: Id to make live """ item = QtGui.QListWidgetItem() item.setData(QtCore.Qt.UserRole, item_id) return item def on_add_click(self): """ Add a selected item to the current service """ if not self.list_view.selectedIndexes(): QtGui.QMessageBox.information(self, UiStrings().NISp, translate('OpenLP.MediaManagerItem', 'You must select one or more items to add.')) else: # Is it possible to process multiple list items to generate # multiple service items? if self.single_service_item: log.debug('%s Add requested', self.plugin.name) self.add_to_service(replace=self.remote_triggered) else: items = self.list_view.selectedIndexes() drop_position = self.service_manager.get_drop_position() for item in items: self.add_to_service(item, position=drop_position) if drop_position != -1: drop_position += 1 def add_to_service_remote(self, message): """ Remote Call wrapper :param message: The passed data item:Remote. """ self.add_to_service(message[0], remote=message[1]) def add_to_service(self, item=None, replace=None, remote=False, position=-1): """ Add this item to the current service. :param item: Item to be processed :param replace: Replace the existing item :param remote: Triggered from remote :param position: Position to place item """ service_item = self.build_service_item(item, True, remote=remote, context=ServiceItemContext.Service) if service_item: service_item.from_plugin = False self.service_manager.add_service_item(service_item, replace=replace, position=position) def on_add_edit_click(self): """ Add a selected item to an existing item in the current service. """ if not self.list_view.selectedIndexes() and not self.remote_triggered: QtGui.QMessageBox.information(self, UiStrings().NISp, translate('OpenLP.MediaManagerItem', 'You must select one or more items.')) else: log.debug('%s Add requested', self.plugin.name) service_item = self.service_manager.get_service_item() if not service_item: QtGui.QMessageBox.information(self, UiStrings().NISs, translate('OpenLP.MediaManagerItem', 'You must select an existing service item to add to.')) elif self.plugin.name == service_item.name: self.generate_slide_data(service_item) self.service_manager.add_service_item(service_item, replace=True) else: # Turn off the remote edit update message indicator QtGui.QMessageBox.information(self, translate('OpenLP.MediaManagerItem', 'Invalid Service Item'), translate('OpenLP.MediaManagerItem', 'You must select a %s service item.') % self.title) def build_service_item(self, item=None, xml_version=False, remote=False, context=ServiceItemContext.Live): """ Common method for generating a service item :param item: Service Item to be built. :param xml_version: version of XML (False) :param remote: Remote triggered (False) :param context: The context on which this is called """ service_item = ServiceItem(self.plugin) service_item.add_icon(self.plugin.icon_path) if self.generate_slide_data(service_item, item, xml_version, remote, context): return service_item else: return None def service_load(self, item): """ Method to add processing when a service has been loaded and individual service items need to be processed by the plugins. :param item: The item to be processed and returned. """ return item def check_search_result(self): """ Checks if the list_view is empty and adds a "No Search Results" item. """ if self.list_view.count(): return message = translate('OpenLP.MediaManagerItem', 'No Search Results') item = QtGui.QListWidgetItem(message) item.setFlags(QtCore.Qt.NoItemFlags) font = QtGui.QFont() font.setItalic(True) item.setFont(font) self.list_view.addItem(item) def _get_id_of_item_to_generate(self, item, remote_item): """ Utility method to check items being submitted for slide generation. :param item: The item to check. :param remote_item: The id to assign if the slide generation was remotely triggered. """ if item is None: if self.remote_triggered is None: item = self.list_view.currentItem() if item is None: return False item_id = item.data(QtCore.Qt.UserRole) else: item_id = remote_item else: item_id = item.data(QtCore.Qt.UserRole) return item_id def save_auto_select_id(self): """ Sorts out, what item to select after loading a list. """ # The item to select has not been set. if self.auto_select_id == -1: item = self.list_view.currentItem() if item: self.auto_select_id = item.data(QtCore.Qt.UserRole) def search(self, string, show_error=True): """ Performs a plugin specific search for items containing ``string`` :param string: String to be displayed :param show_error: Should the error be shown (True) """ raise NotImplementedError('Plugin.search needs to be defined by the plugin')
class Ui_ThemeManager(object): """ UI part of the Theme Manager """ def setup_ui(self, widget): """ Define the UI :param widget: The screen object the the dialog is to be attached to. """ # start with the layout self.layout = QtGui.QVBoxLayout(widget) self.layout.setSpacing(0) self.layout.setMargin(0) self.layout.setObjectName('layout') self.toolbar = OpenLPToolbar(widget) self.toolbar.setObjectName('toolbar') self.toolbar.add_toolbar_action('newTheme', text=UiStrings().NewTheme, icon=':/themes/theme_new.png', tooltip=translate('OpenLP.ThemeManager', 'Create a new theme.'), triggers=self.on_add_theme) self.toolbar.add_toolbar_action('editTheme', text=translate('OpenLP.ThemeManager', 'Edit Theme'), icon=':/themes/theme_edit.png', tooltip=translate('OpenLP.ThemeManager', 'Edit a theme.'), triggers=self.on_edit_theme) self.delete_toolbar_action = self.toolbar.add_toolbar_action('delete_theme', text=translate('OpenLP.ThemeManager', 'Delete Theme'), icon=':/general/general_delete.png', tooltip=translate('OpenLP.ThemeManager', 'Delete a theme.'), triggers=self.on_delete_theme) self.toolbar.addSeparator() self.toolbar.add_toolbar_action('importTheme', text=translate('OpenLP.ThemeManager', 'Import Theme'), icon=':/general/general_import.png', tooltip=translate('OpenLP.ThemeManager', 'Import a theme.'), triggers=self.on_import_theme) self.toolbar.add_toolbar_action('exportTheme', text=translate('OpenLP.ThemeManager', 'Export Theme'), icon=':/general/general_export.png', tooltip=translate('OpenLP.ThemeManager', 'Export a theme.'), triggers=self.on_export_theme) self.layout.addWidget(self.toolbar) self.theme_widget = QtGui.QWidgetAction(self.toolbar) self.theme_widget.setObjectName('theme_widget') # create theme manager list self.theme_list_widget = QtGui.QListWidget(widget) self.theme_list_widget.setAlternatingRowColors(True) self.theme_list_widget.setIconSize(QtCore.QSize(88, 50)) self.theme_list_widget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.theme_list_widget.setObjectName('theme_list_widget') self.layout.addWidget(self.theme_list_widget) self.theme_list_widget.customContextMenuRequested.connect(self.context_menu) # build the context menu self.menu = QtGui.QMenu() self.edit_action = create_widget_action(self.menu, text=translate('OpenLP.ThemeManager', '&Edit Theme'), icon=':/themes/theme_edit.png', triggers=self.on_edit_theme) self.copy_action = create_widget_action(self.menu, text=translate('OpenLP.ThemeManager', '&Copy Theme'), icon=':/themes/theme_edit.png', triggers=self.on_copy_theme) self.rename_action = create_widget_action(self.menu, text=translate('OpenLP.ThemeManager', '&Rename Theme'), icon=':/themes/theme_edit.png', triggers=self.on_rename_theme) self.delete_action = create_widget_action(self.menu, text=translate('OpenLP.ThemeManager', '&Delete Theme'), icon=':/general/general_delete.png', triggers=self.on_delete_theme) self.menu.addSeparator() self.global_action = create_widget_action(self.menu, text=translate('OpenLP.ThemeManager', 'Set As &Global Default'), icon=':/general/general_export.png', triggers=self.change_global_from_screen) self.export_action = create_widget_action(self.menu, text=translate('OpenLP.ThemeManager', '&Export Theme'), icon=':/general/general_export.png', triggers=self.on_export_theme) # Signals self.theme_list_widget.doubleClicked.connect(self.change_global_from_screen) self.theme_list_widget.currentItemChanged.connect(self.check_list_state)