def on_edit_book_button_clicked(self): """ Edit a book. """ book_id = self._get_current_item_id(self.song_books_list_widget) if book_id == -1: return book = self.manager.get_object(Book, book_id) if book.publisher is None: book.publisher = '' self.song_book_form.name_edit.setText(book.name) self.song_book_form.publisher_edit.setText(book.publisher) # Save the book's name and publisher for the case that they have to # be restored. temp_name = book.name temp_publisher = book.publisher if self.song_book_form.exec_(False): book.name = self.song_book_form.name_edit.text() book.publisher = self.song_book_form.publisher_edit.text() if self.check_song_book_exists(book, True): if self.manager.save_object(book): self.reset_song_books() else: critical_error_message_box( message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your changes.')) elif critical_error_message_box( message=translate('SongsPlugin.SongMaintenanceForm', 'The book %s already exists. Would you like to make ' 'songs with book %s use the existing book %s?') % (book.name, temp_name, book.name), parent=self, question=True) == QtGui.QMessageBox.Yes: self._merge_objects(book, self.merge_song_books, self.reset_song_books) else: # We restore the book's old name and publisher. book.name = temp_name book.publisher = temp_publisher
def trigger_alert(self, text): """ Prepares the alert text for displaying. :param text: The alert text. """ if not text: return False # We found '<>' in the alert text, but the ParameterEdit field is empty. if text.find('<>') != -1 and not self.parameter_edit.text() and \ QtGui.QMessageBox.question(self, translate('AlertsPlugin.AlertForm', 'No Parameter Found'), translate('AlertsPlugin.AlertForm', 'You have not entered a parameter to be replaced.\n' 'Do you want to continue anyway?'), QtGui.QMessageBox.StandardButtons( QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No: self.parameter_edit.setFocus() return False # The ParameterEdit field is not empty, but we have not found '<>' # in the alert text. elif text.find('<>') == -1 and self.parameter_edit.text() and \ QtGui.QMessageBox.question(self, translate('AlertsPlugin.AlertForm', 'No Placeholder Found'), translate('AlertsPlugin.AlertForm', 'The alert text does not contain \'<>\'.\n' 'Do you want to continue anyway?'), QtGui.QMessageBox.StandardButtons( QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No: self.parameter_edit.setFocus() return False text = text.replace('<>', self.parameter_edit.text()) self.plugin.alerts_manager.display_alert(text) return True
def validate_xml_file(self, filename, tag): """ Validate the supplied file :param filename: The supplied file :param tag: The expected root tag type :return: True if valid. ValidationError is raised otherwise. """ if BibleImport.is_compressed(filename): raise ValidationError(msg='Compressed file') bible = self.parse_xml(filename, use_objectify=True) if bible is None: raise ValidationError(msg='Error when opening file') root_tag = bible.tag.lower() bible_type = translate('BiblesPlugin.BibleImport', 'unknown type of', 'This looks like an unknown type of XML bible.') if root_tag == tag: return True elif root_tag == 'bible': bible_type = "OpenSong" elif root_tag == '{http://www.bibletechnologies.net/2003/osis/namespace}osis': bible_type = 'OSIS' elif root_tag == 'xmlbible': bible_type = 'Zefania' critical_error_message_box( message=translate('BiblesPlugin.BibleImport', 'Incorrect Bible file type supplied. This looks like an {bible_type} XML bible.' .format(bible_type=bible_type))) raise ValidationError(msg='Invalid xml.')
def on_rename_theme(self, field=None): """ Renames an existing theme to a new name :param field: """ # TODO: Check for delayed format() conversions if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to rename.'), translate('OpenLP.ThemeManager', 'Rename Confirmation'), translate('OpenLP.ThemeManager', 'Rename %s theme?'), False, False): item = self.theme_list_widget.currentItem() old_theme_name = item.data(QtCore.Qt.UserRole) self.file_rename_form.file_name_edit.setText(old_theme_name) if self.file_rename_form.exec(): new_theme_name = self.file_rename_form.file_name_edit.text() if old_theme_name == new_theme_name: return if self.check_if_theme_exists(new_theme_name): old_theme_data = self.get_theme_data(old_theme_name) self.clone_theme_data(old_theme_data, new_theme_name) self.delete_theme(old_theme_name) for plugin in self.plugin_manager.plugins: if plugin.uses_theme(old_theme_name): plugin.rename_theme(old_theme_name, new_theme_name) self.renderer.update_theme(new_theme_name, old_theme_name) self.load_themes()
def post_wizard(self): """ Clean up the UI after the import has finished. """ successful_import = 0 failed_import = 0 for number, filename in enumerate(self.files): if self.success.get(number): successful_import += 1 elif self.checkBox[number].checkState() == QtCore.Qt.Checked: failed_import += 1 # Delete upgraded (but not complete, corrupted, ...) bible. delete_file(os.path.join(self.path, filename[0])) # Copy not upgraded bible back. shutil.move(os.path.join(self.temp_dir, filename[0]), self.path) if failed_import > 0: failed_import_text = translate('BiblesPlugin.UpgradeWizardForm', ', %s failed') % failed_import else: failed_import_text = '' if successful_import > 0: if self.includeWebBible: self.progress_label.setText( translate('BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible(s): %s successful%s\nPlease note that verses from Web Bibles will be ' 'downloaded on demand and so an Internet connection is required.') % (successful_import, failed_import_text)) else: self.progress_label.setText( translate('BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible(s): %s successful%s') % ( successful_import, failed_import_text)) else: self.progress_label.setText(translate('BiblesPlugin.UpgradeWizardForm', 'Upgrade failed.')) # Remove temp directory. shutil.rmtree(self.temp_dir, True) super(BibleUpgradeForm, self).post_wizard()
def media_length(self, service_item): """ Loads and starts a media item to obtain the media length :param service_item: The ServiceItem containing the details to be played. """ controller = self.display_controllers[DisplayControllerType.Plugin] log.debug('media_length') # stop running videos self.media_reset(controller) controller.media_info = MediaInfo() controller.media_info.volume = 0 controller.media_info.file_info = QtCore.QFileInfo(service_item.get_frame_path()) display = controller.preview_display if not self._check_file_type(controller, display, service_item): # Media could not be loaded correctly critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'), translate('MediaPlugin.MediaItem', 'Unsupported File')) return False if not self.media_play(controller): critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'), translate('MediaPlugin.MediaItem', 'Unsupported File')) return False service_item.set_media_length(controller.media_info.length) self.media_stop(controller) log.debug('use %s controller' % self.current_media_players[controller.controller_type]) return True
def create_separated_list(string_list): """ Returns a string that represents a join of a list of strings with a localized separator. This function corresponds to QLocale::createSeparatedList which was introduced in Qt 4.8 and implements the algorithm from http://www.unicode.org/reports/tr35/#ListPatterns :param string_list: List of unicode strings """ if LooseVersion(Qt.PYQT_VERSION_STR) >= LooseVersion('4.9') and LooseVersion(Qt.qVersion()) >= LooseVersion('4.8'): return QtCore.QLocale().createSeparatedList(string_list) if not string_list: return '' elif len(string_list) == 1: return string_list[0] elif len(string_list) == 2: return translate('OpenLP.core.lib', '%s and %s', 'Locale list separator: 2 items') % (string_list[0], string_list[1]) else: merged = translate('OpenLP.core.lib', '%s, and %s', 'Locale list separator: end') % (string_list[-2], string_list[-1]) for index in reversed(list(range(1, len(string_list) - 2))): merged = translate('OpenLP.core.lib', '%s, %s', 'Locale list separator: middle') % (string_list[index], merged) return translate('OpenLP.core.lib', '%s, %s', 'Locale list separator: start') % (string_list[0], merged)
def on_text_search(self, text, search_while_type=False): """ We are doing a 'Text Search'. This search is called on def text_search by 'Search' Text and Combined Searches. """ self.search_results = self.plugin.manager.verse_search(self.bible.name, text) if self.second_bible and self.search_results: filtered_search_results = [] not_found_count = 0 for verse in self.search_results: second_verse = self.second_bible.get_verses( [(verse.book.book_reference_id, verse.chapter, verse.verse, verse.verse)], False) if second_verse: filtered_search_results.append(verse) self.second_search_results += second_verse else: log.debug('Verse "{name} {chapter:d}:{verse:d}" not found in Second Bible "{bible_name}"'.format( name=verse.book.name, chapter=verse.chapter, verse=verse.verse, bible_name=self.second_bible.name)) not_found_count += 1 self.search_results = filtered_search_results if not_found_count != 0 and not search_while_type: self.main_window.information_message( translate('BiblesPlugin.MediaItem', 'Verses not found'), translate('BiblesPlugin.MediaItem', 'The second Bible "{second_name}" does not contain all the verses that are in the main ' 'Bible "{name}".\nOnly verses found in both Bibles will be shown.\n\n' '{count:d} verses have not been included in the results.' ).format(second_name=self.second_bible.name, name=self.bible.name, count=not_found_count)) self.display_results()
def set_language(action, message=True): """ Set the language to translate OpenLP into :param action: The language menu option :param message: Display the message option """ language = "en" if action: action_name = str(action.objectName()) if action_name == "autoLanguageItem": LanguageManager.auto_language = True else: LanguageManager.auto_language = False qm_list = LanguageManager.get_qm_list() language = str(qm_list[action_name]) if LanguageManager.auto_language: language = "[%s]" % language Settings().setValue("core/language", language) log.info("Language file: '%s' written to conf file" % language) if message: QtGui.QMessageBox.information( None, translate("OpenLP.LanguageManager", "Language"), translate("OpenLP.LanguageManager", "Please restart OpenLP to use your new " "language setting."), )
def __init__(self, parent, projectordb, edit=False): """ Build the source select dialog using tabbed interface. :param projectordb: ProjectorDB session to use """ log.debug('Initializing SourceSelectTabs()') super(SourceSelectTabs, self).__init__(parent, QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint) self.setMinimumWidth(350) self.projectordb = projectordb self.edit = edit if self.edit: title = translate('OpenLP.SourceSelectForm', 'Edit Projector Source Text') else: title = translate('OpenLP.SourceSelectForm', 'Select Projector Source') self.setWindowTitle(title) self.setObjectName('source_select_tabs') self.setWindowIcon(build_icon(':/icon/openlp-log.svg')) self.setModal(True) self.layout = QtWidgets.QVBoxLayout() self.layout.setObjectName('source_select_tabs_layout') if is_macosx(): self.tabwidget = QtWidgets.QTabWidget(self) else: self.tabwidget = FingerTabWidget(self) self.tabwidget.setObjectName('source_select_tabs_tabwidget') self.tabwidget.setUsesScrollButtons(False) if is_macosx(): self.tabwidget.setTabPosition(QtWidgets.QTabWidget.North) else: self.tabwidget.setTabPosition(QtWidgets.QTabWidget.West) self.layout.addWidget(self.tabwidget) self.setLayout(self.layout)
def text_search(self, search_while_type=False): """ This triggers the proper 'Search' search based on which search type is used. "Eg. "Reference Search", "Text Search" or "Combined search". """ log.debug('text_search called') text = self.search_edit.text() if text == '': self.list_view.clear() return self.list_view.clear(search_while_typing=search_while_type) if self.search_edit.current_search_type() == BibleSearch.Reference: if get_reference_match('full').match(text): # Valid reference found. Do reference search. self.text_reference_search(text) elif not search_while_type: self.main_window.information_message( translate('BiblesPlugin.BibleManager', 'Scripture Reference Error'), translate('BiblesPlugin.BibleManager', '<strong>The reference you typed is invalid!<br><br>' 'Please make sure that your reference follows one of these patterns:</strong><br><br>%s') % UiStrings().BibleScriptureError % get_reference_separators()) elif self.search_edit.current_search_type() == BibleSearch.Combined and get_reference_match('full').match(text): # Valid reference found. Do reference search. self.text_reference_search(text) else: # It can only be a 'Combined' search without a valid reference, or a 'Text' search if search_while_type: if len(text) > 8 and VALID_TEXT_SEARCH.search(text): self.on_text_search(text, True) elif VALID_TEXT_SEARCH.search(text): self.on_text_search(text)
def set_plugin_text_strings(self): """ Called to define all translatable texts of the plugin """ # Name PluginList self.text_strings[StringContent.Name] = { 'singular': translate('MediaPlugin', 'Media', 'name singular'), 'plural': translate('MediaPlugin', 'Media', 'name plural') } # Name for MediaDockManager, SettingsManager self.text_strings[StringContent.VisibleName] = { 'title': translate('MediaPlugin', 'Media', 'container title') } # Middle Header Bar tooltips = { 'load': translate('MediaPlugin', 'Load new media.'), 'import': '', 'new': translate('MediaPlugin', 'Add new media.'), 'edit': translate('MediaPlugin', 'Edit the selected media.'), 'delete': translate('MediaPlugin', 'Delete the selected media.'), 'preview': translate('MediaPlugin', 'Preview the selected media.'), 'live': translate('MediaPlugin', 'Send the selected media live.'), 'service': translate('MediaPlugin', 'Add the selected media to the service.') } self.set_plugin_ui_text_strings(tooltips)
def on_replace_click(self): """ Called to replace Live background with the media selected. """ if check_item_selected(self.list_view, translate('MediaPlugin.MediaItem', 'You must select a media file to replace the background with.')): item = self.list_view.currentItem() filename = item.data(QtCore.Qt.UserRole) if os.path.exists(filename): service_item = ServiceItem() service_item.title = 'webkit' service_item.processor = 'webkit' (path, name) = os.path.split(filename) service_item.add_from_command(path, name, CLAPPERBOARD) if self.media_controller.video(DisplayControllerType.Live, service_item, video_behind_text=True): self.reset_action.setVisible(True) else: critical_error_message_box(UiStrings().LiveBGError, translate('MediaPlugin.MediaItem', 'There was no display item to amend.')) else: critical_error_message_box(UiStrings().LiveBGError, translate('MediaPlugin.MediaItem', 'There was a problem replacing your background, ' 'the media file "%s" no longer exists.') % filename)
def accept(self): """ Lets save the theme as Finish has been triggered """ # Save the theme name self.theme.theme_name = self.field('name') if not self.theme.theme_name: critical_error_message_box( translate('OpenLP.ThemeWizard', 'Theme Name Missing'), translate('OpenLP.ThemeWizard', 'There is no name for this theme. Please enter one.')) return if self.theme.theme_name == '-1' or self.theme.theme_name == 'None': critical_error_message_box( translate('OpenLP.ThemeWizard', 'Theme Name Invalid'), translate('OpenLP.ThemeWizard', 'Invalid theme name. Please enter one.')) return save_from = None save_to = None if self.theme.background_type == BackgroundType.to_string(BackgroundType.Image) or \ self.theme.background_type == BackgroundType.to_string(BackgroundType.Video): filename = os.path.split(str(self.theme.background_filename))[1] save_to = os.path.join(self.path, self.theme.theme_name, filename) save_from = self.theme.background_filename if not self.edit_mode and not self.theme_manager.check_if_theme_exists(self.theme.theme_name): return self.theme_manager.save_theme(self.theme, save_from, save_to) return QtWidgets.QDialog.accept(self)
def validate_book(self, new_book_name, abbreviation): """ Validate a book. """ book_regex = re.compile('[\d]*[^\d]+$') if not new_book_name: self.book_name_edit[abbreviation].setFocus() critical_error_message_box( UiStrings().EmptyField, translate('BiblesPlugin.BibleEditForm', 'You need to specify a book name for "%s".') % self.book_names[abbreviation]) return False elif not book_regex.match(new_book_name): self.book_name_edit[abbreviation].setFocus() critical_error_message_box( UiStrings().EmptyField, translate('BiblesPlugin.BibleEditForm', 'The book name "%s" is not correct.\nNumbers can only be used at the beginning and must\nbe ' 'followed by one or more non-numeric characters.') % new_book_name) return False for abbr, book in self.books.items(): if book: if abbr == abbreviation: continue if self.book_name_edit[abbr].text() == new_book_name: self.book_name_edit[abbreviation].setFocus() critical_error_message_box( translate('BiblesPlugin.BibleEditForm', 'Duplicate Book Name'), translate('BiblesPlugin.BibleEditForm', 'The Book Name "%s" has been entered more than once.') % new_book_name) return False return True
def validate_meta(self, name, copyright): """ Validate the Meta before saving. """ if not name: self.version_name_edit.setFocus() critical_error_message_box( UiStrings().EmptyField, translate('BiblesPlugin.BibleEditForm', 'You need to specify a version name for your Bible.')) return False elif not copyright: self.copyright_edit.setFocus() critical_error_message_box( UiStrings().EmptyField, translate('BiblesPlugin.BibleEditForm', 'You need to set a copyright for your Bible. Bibles in the Public Domain need to be marked ' 'as such.')) return False elif self.manager.exists(name) and self.manager.get_meta_data(self.bible, 'name').value != name: self.version_name_edit.setFocus() critical_error_message_box( translate('BiblesPlugin.BibleEditForm', 'Bible Exists'), translate('BiblesPlugin.BibleEditForm', 'This Bible already exists. Please import ' 'a different Bible or first delete the existing one.')) return False return True
def retranslateUi(self): """ The name of the plugin media displayed in UI """ self.on_new_prompt = translate('PresentationPlugin.MediaItem', 'Select Presentation(s)') self.automatic = translate('PresentationPlugin.MediaItem', 'Automatic') self.display_type_label.setText(translate('PresentationPlugin.MediaItem', 'Present using:'))
def on_delete_loop(self, field=None): """ Delete a loop triggered by the UI. :param field: """ if check_item_selected(self.loop_list_widget, translate('OpenLP.LoopManager', 'You must select a loop to delete.')): item = self.loop_list_widget.currentItem() cur_loop = item.text() check_answer = QtGui.QMessageBox.question(self, translate('OpenLP.LoopManager', 'Delete Confirmation'), translate('OpenLP.LoopManager', 'Remove %s loop and delete files?' % cur_loop), QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No), QtGui.QMessageBox.No) if check_answer == QtGui.QMessageBox.No: return # Remove loop from UI row = self.loop_list_widget.row(item) self.loop_list_widget.takeItem(row) # Remove loop and thumbnail from disk self.application.set_busy_cursor() os.remove(os.path.join(self.path, item.data(QtCore.Qt.UserRole))) os.remove(os.path.join(self.thumb_path, cur_loop + '.jpg')) self.application.set_normal_cursor()
def retranslateUi(self, custom_slide_edit_dialog): custom_slide_edit_dialog.setWindowTitle(translate('CustomPlugin.EditVerseForm', 'Edit Slide')) self.split_button.setText(UiStrings().Split) self.split_button.setToolTip(UiStrings().SplitToolTip) self.insert_button.setText(translate('CustomPlugin.EditCustomForm', 'Insert Slide')) self.insert_button.setToolTip(translate('CustomPlugin.EditCustomForm', 'Split a slide into two by inserting a slide splitter.'))
def on_add_group_click(self): """ Called to add a new group """ # Find out if a group must be pre-selected preselect_group = 0 selected_items = self.list_view.selectedItems() if selected_items: selected_item = selected_items[0] if isinstance(selected_item.data(0, QtCore.Qt.UserRole), ImageFilenames): selected_item = selected_item.parent() if isinstance(selected_item, QtGui.QTreeWidgetItem): if isinstance(selected_item.data(0, QtCore.Qt.UserRole), ImageGroups): preselect_group = selected_item.data(0, QtCore.Qt.UserRole).id # Show 'add group' dialog if self.add_group_form.exec_(show_top_level_group=True, selected_group=preselect_group): new_group = ImageGroups.populate(parent_id=self.add_group_form.parent_group_combobox.itemData( self.add_group_form.parent_group_combobox.currentIndex(), QtCore.Qt.UserRole), group_name=self.add_group_form.name_edit.text()) if not self.check_group_exists(new_group): if self.manager.save_object(new_group): self.load_full_list(self.manager.get_all_objects( ImageFilenames, order_by_ref=ImageFilenames.filename)) self.expand_group(new_group.id) self.fill_groups_combobox(self.choose_group_form.group_combobox) self.fill_groups_combobox(self.add_group_form.parent_group_combobox) else: critical_error_message_box( message=translate('ImagePlugin.AddGroupForm', 'Could not add the new group.')) else: critical_error_message_box(message=translate('ImagePlugin.AddGroupForm', 'This group already exists.'))
def load(self): """ Load the plugin details into the screen """ self.plugin_list_widget.clear() self.programatic_change = True self._clear_details() self.programatic_change = True plugin_list_width = 0 for plugin in self.plugin_manager.plugins: item = QtGui.QListWidgetItem(self.plugin_list_widget) # We do this just to make 100% sure the status is an integer as # sometimes when it's loaded from the config, it isn't cast to int. plugin.status = int(plugin.status) # Set the little status text in brackets next to the plugin name. if plugin.status == PluginStatus.Disabled: status_text = translate('OpenLP.PluginForm', '%s (Disabled)') elif plugin.status == PluginStatus.Active: status_text = translate('OpenLP.PluginForm', '%s (Active)') else: # PluginStatus.Inactive status_text = translate('OpenLP.PluginForm', '%s (Inactive)') item.setText(status_text % plugin.name_strings['singular']) # If the plugin has an icon, set it! if plugin.icon: item.setIcon(plugin.icon) self.plugin_list_widget.addItem(item) plugin_list_width = max(plugin_list_width, self.fontMetrics().width( translate('OpenLP.PluginForm', '%s (Inactive)') % plugin.name_strings['singular'])) self.plugin_list_widget.setFixedWidth(plugin_list_width + self.plugin_list_widget.iconSize().width() + 48)
def _export_theme(self, path, theme): """ Create the zipfile with the theme contents. :param path: Location where the zip file will be placed :param theme: The name of the theme to be exported """ theme_path = os.path.join(path, theme + '.otz') theme_zip = None try: theme_zip = zipfile.ZipFile(theme_path, 'w') source = os.path.join(self.path, theme) for files in os.walk(source): for name in files[2]: theme_zip.write(os.path.join(source, name), os.path.join(theme, name)) theme_zip.close() return True except OSError as ose: self.log_exception('Export Theme Failed') critical_error_message_box(translate('OpenLP.ThemeManager', 'Theme Export Failed'), translate('OpenLP.ThemeManager', 'The theme export failed because this error ' 'occurred: {err}').format(err=ose.strerror)) if theme_zip: theme_zip.close() shutil.rmtree(theme_path, True) return False
def on_data_directory_browse_button_clicked(self): """ Browse for a new data directory location. """ old_root_path = str(self.data_directory_label.text()) # Get the new directory location. new_data_path = QtWidgets.QFileDialog.getExistingDirectory(self, translate('OpenLP.AdvancedTab', 'Select Data Directory Location'), old_root_path, options=QtWidgets.QFileDialog.ShowDirsOnly) # Set the new data path. if new_data_path: new_data_path = os.path.normpath(new_data_path) if self.current_data_path.lower() == new_data_path.lower(): self.on_data_directory_cancel_button_clicked() return else: return # Make sure they want to change the data. answer = QtWidgets.QMessageBox.question(self, translate('OpenLP.AdvancedTab', 'Confirm Data Directory Change'), translate('OpenLP.AdvancedTab', 'Are you sure you want to change the ' 'location of the OpenLP data directory to:\n\n{path}' '\n\nThe data directory will be changed when OpenLP is ' 'closed.').format(path=new_data_path), QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No), QtWidgets.QMessageBox.No) if answer != QtWidgets.QMessageBox.Yes: return # Check if data already exists here. self.check_data_overwrite(new_data_path) # Save the new location. self.main_window.set_new_data_path(new_data_path) self.new_data_directory_edit.setText(new_data_path) self.data_directory_cancel_button.show()
def first_time(self): """ If the first time wizard has run, this function is run to import all the new songs into the database. """ self.application.process_events() self.on_tools_reindex_item_triggered() self.application.process_events() db_dir = os.path.join(gettempdir(), 'openlp') if not os.path.exists(db_dir): return song_dbs = [] song_count = 0 for sfile in os.listdir(db_dir): if sfile.startswith('songs_') and sfile.endswith('.sqlite'): self.application.process_events() song_dbs.append(os.path.join(db_dir, sfile)) song_count += SongsPlugin._count_songs(os.path.join(db_dir, sfile)) if not song_dbs: return self.application.process_events() progress = QtWidgets.QProgressDialog(self.main_window) progress.setWindowModality(QtCore.Qt.WindowModal) progress.setWindowTitle(translate('OpenLP.Ui', 'Importing Songs')) progress.setLabelText(translate('OpenLP.Ui', 'Starting import...')) progress.setCancelButton(None) progress.setRange(0, song_count) progress.setMinimumDuration(0) progress.forceShow() self.application.process_events() for db in song_dbs: importer = OpenLPSongImport(self.manager, filename=db) importer.do_import(progress) self.application.process_events() progress.setValue(song_count) self.media_item.on_search_text_button_clicked()
def validateCurrentPage(self): """ Validate the current page before moving on to the next page. """ if self.currentPage() == self.welcome_page: return True elif self.currentPage() == self.available_songs_page: items = [ item for item in self._find_list_widget_items(self.available_list_widget) if item.checkState() ] if not items: critical_error_message_box( UiStrings().NISp, translate('SongsPlugin.ExportWizardForm', 'You need to add at least one Song to export.')) return False self.selected_list_widget.clear() # Add the songs to the list of selected songs. for item in items: song = QtGui.QListWidgetItem(item.text()) song.setData(QtCore.Qt.UserRole, item.data(QtCore.Qt.UserRole)) song.setFlags(QtCore.Qt.ItemIsEnabled) self.selected_list_widget.addItem(song) return True elif self.currentPage() == self.export_song_page: if not self.directory_line_edit.text(): critical_error_message_box( translate('SongsPlugin.ExportWizardForm', 'No Save Location specified'), translate('SongsPlugin.ExportWizardForm', 'You need to specify a directory.')) return False return True elif self.currentPage() == self.progress_page: self.available_list_widget.clear() self.selected_list_widget.clear() return True
def on_data_directory_default_button_clicked(self): """ Re-set the data directory location to the 'default' location. """ new_data_path = AppLocation.get_directory(AppLocation.DataDir) if self.current_data_path.lower() != new_data_path.lower(): # Make sure they want to change the data location back to the # default. answer = QtWidgets.QMessageBox.question(self, translate('OpenLP.AdvancedTab', 'Reset Data Directory'), translate('OpenLP.AdvancedTab', 'Are you sure you want to change ' 'the location of the OpenLP data ' 'directory to the default location?' '\n\nThis location will be used ' 'after OpenLP is closed.'), QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No), QtWidgets.QMessageBox.No) if answer != QtWidgets.QMessageBox.Yes: return self.check_data_overwrite(new_data_path) # Save the new location. self.main_window.set_new_data_path(new_data_path) self.new_data_directory_edit.setText(os.path.abspath(new_data_path)) self.data_directory_cancel_button.show() else: # We cancel the change in case user changed their mind. self.on_data_directory_cancel_button_clicked()
def on_replace_click(self): """ Called to replace Live background with the image selected. """ if check_item_selected( self.list_view, translate('ImagePlugin.MediaItem', 'You must select an image to replace the background with.')): background = QtGui.QColor(Settings().value(self.settings_section + '/background color')) bitem = self.list_view.selectedItems()[0] if not isinstance(bitem.data(0, QtCore.Qt.UserRole), ImageFilenames): # Only continue when an image is selected. return filename = bitem.data(0, QtCore.Qt.UserRole).filename if os.path.exists(filename): if self.live_controller.display.direct_image(filename, background): self.reset_action.setVisible(True) else: critical_error_message_box( UiStrings().LiveBGError, translate('ImagePlugin.MediaItem', 'There was no display item to amend.')) else: critical_error_message_box( UiStrings().LiveBGError, translate('ImagePlugin.MediaItem', 'There was a problem replacing your background, ' 'the image file "%s" no longer exists.') % filename)
def on_edit_topic_button_clicked(self): """ Edit a topic. """ topic_id = self._get_current_item_id(self.topics_list_widget) if topic_id == -1: return topic = self.manager.get_object(Topic, topic_id) self.topic_form.name = topic.name # Save the topic's name for the case that he has to be restored. temp_name = topic.name if self.topic_form.exec_(False): topic.name = self.topic_form.name_edit.text() if self.check_topic_exists(topic, True): if self.manager.save_object(topic): self.reset_topics() else: critical_error_message_box( message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your changes.')) elif critical_error_message_box( message=translate('SongsPlugin.SongMaintenanceForm', 'The topic %s already exists. Would you like to make songs with topic %s use the ' 'existing topic %s?') % (topic.name, temp_name, topic.name), parent=self, question=True) == QtGui.QMessageBox.Yes: self._merge_objects(topic, self.merge_topics, self.reset_topics) else: # We restore the topics's old name. topic.name = temp_name critical_error_message_box( message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your modified topic, because it already exists.'))
def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False, context=ServiceItemContext.Service): """ Generate the slide data. Needs to be implemented by the plugin. :param service_item: The service item to be built on :param item: The Song item to be used :param xml_version: The xml version (not used) :param remote: Triggered from remote :param context: Why is it being generated """ if item is None: item = self.list_view.currentItem() if item is None: return False filename = item.data(QtCore.Qt.UserRole) # Special handling if the filename is a optical clip if filename.startswith('optical:'): (name, title, audio_track, subtitle_track, start, end, clip_name) = parse_optical_path(filename) if not os.path.exists(name): if not remote: # Optical disc is no longer present critical_error_message_box( translate('MediaPlugin.MediaItem', 'Missing Media File'), translate('MediaPlugin.MediaItem', 'The optical disc %s is no longer available.') % name) return False service_item.processor = self.display_type_combo_box.currentText() service_item.add_from_command(filename, name, CLAPPERBOARD) service_item.title = clip_name # Set the length self.media_controller.media_setup_optical(name, title, audio_track, subtitle_track, start, end, None, None) service_item.set_media_length((end - start) / 1000) service_item.start_time = start / 1000 service_item.end_time = end / 1000 service_item.add_capability(ItemCapabilities.IsOptical) else: if not os.path.exists(filename): if not remote: # File is no longer present critical_error_message_box( translate('MediaPlugin.MediaItem', 'Missing Media File'), translate('MediaPlugin.MediaItem', 'The file %s no longer exists.') % filename) return False (path, name) = os.path.split(filename) service_item.title = name service_item.processor = self.display_type_combo_box.currentText() service_item.add_from_command(path, name, CLAPPERBOARD) # Only get start and end times if going to a service if context == ServiceItemContext.Service: # Start media and obtain the length if not self.media_controller.media_length(service_item): return False service_item.add_capability(ItemCapabilities.CanAutoStartForLive) service_item.add_capability(ItemCapabilities.CanEditTitle) service_item.add_capability(ItemCapabilities.RequiresMedia) if Settings().value(self.settings_section + '/media auto start') == QtCore.Qt.Checked: service_item.will_auto_start = True # force a non-existent theme service_item.theme = -1 return True
def check_data_overwrite(self, data_path): """ Check if there's already data in the target directory. """ test_path = os.path.join(data_path, 'songs') self.data_directory_copy_check_box.show() if os.path.exists(test_path): self.data_exists = True # Check is they want to replace existing data. answer = QtWidgets.QMessageBox.warning(self, translate('OpenLP.AdvancedTab', 'Overwrite Existing Data'), translate('OpenLP.AdvancedTab', 'WARNING: \n\nThe location you have selected \n\n{path}' '\n\nappears to contain OpenLP data files. Do you wish to ' 'replace these files with the current data ' 'files?').format(path=os.path.abspath(data_path,)), QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No), QtWidgets.QMessageBox.No) if answer == QtWidgets.QMessageBox.Yes: self.data_directory_copy_check_box.setChecked(True) self.new_data_directory_has_files_label.show() else: self.data_directory_copy_check_box.setChecked(False) self.new_data_directory_has_files_label.hide() else: self.data_exists = False self.data_directory_copy_check_box.setChecked(True) self.new_data_directory_has_files_label.hide()
def delete_sources(self): """ Delete the sources for this projector """ msg = QtWidgets.QMessageBox() msg.setText( translate('OpenLP.SourceSelectForm', 'Delete entries for this projector')) msg.setInformativeText( translate( 'OpenLP.SourceSelectForm', 'Are you sure you want to delete ALL user-defined ' 'source input text for this projector?')) msg.setStandardButtons(msg.Cancel | msg.Ok) msg.setDefaultButton(msg.Cancel) ans = msg.exec() if ans == msg.Cancel: return self.projectordb.delete_all_objects( ProjectorSource, ProjectorSource.projector_id == self.projector.db_item.id) self.done(100)
def build_file_mask_string(self): """ Build the list of file extensions to be used in the Open file dialog. """ file_type_string = '' for controller in self.controllers: if self.controllers[controller].enabled(): file_types = self.controllers[controller].supports + self.controllers[controller].also_supports for file_type in file_types: if file_type not in file_type_string: file_type_string += '*.%s ' % file_type self.service_manager.supported_suffixes(file_type) self.on_new_file_masks = translate('PresentationPlugin.MediaItem', 'Presentations (%s)') % file_type_string
def about(): about_text = translate('ImagePlugin', '<strong>Image Plugin</strong>' '<br />The image plugin provides displaying of images.<br />One ' 'of the distinguishing features of this plugin is the ability to ' 'group a number of images together in the service manager, making ' 'the displaying of multiple images easier. This plugin can also ' 'make use of OpenLP\'s "timed looping" feature to create a slide ' 'show that runs automatically. In addition to this, images from ' 'the plugin can be used to override the current theme\'s ' 'background, which renders text-based items like songs with the ' 'selected image as a background instead of the background ' 'provided by the theme.') return about_text
def pre_wizard(self): """ Prepare the UI for the import. """ super(BibleImportForm, self).pre_wizard() bible_type = self.field('source_format') if bible_type == BibleFormat.WebDownload: self.progress_label.setText( translate('BiblesPlugin.ImportWizardForm', 'Registering Bible...')) else: self.progress_label.setText(WizardStrings.StartingImport) self.application.process_events()
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 on_display_loop(self, field=None): if check_item_selected(self.loop_list_widget, translate('OpenLP.LoopManager', 'You must select a loop to play.')): item = self.loop_list_widget.currentItem() loop_file = os.path.join(self.path, item.data(QtCore.Qt.UserRole)) vlc_cmd = ['vlc', loop_file, '--one-instance', '--repeat', '-f'] subprocess.Popen(vlc_cmd) # Update GUI to show currently playing loop_thumb #f = item.font #QtGui.QFont.setBold(True) #item.setFont(f) #item.setBackgroundColor(QtGui.QColor(0,255,0,255)) return True
def on_current_cell_changed(self, cur_row, cur_col, pre_row, pre_col): """ This function processes all user edits in the table. It is called on each cell change. """ if self.is_deleting: self.is_deleting = False return if self.reloading: return # only process for editable rows if self.tag_table_widget.item(pre_row, 0): item = self.tag_table_widget.item(pre_row, pre_col) text = item.text() errors = None if pre_col is EditColumn.Description: if not text: errors = translate('OpenLP.FormattingTagForm', 'Description is missing') elif pre_col is EditColumn.Tag: if not text: errors = translate('OpenLP.FormattingTagForm', 'Tag is missing') elif pre_col is EditColumn.StartHtml: # HTML edited item = self.tag_table_widget.item(pre_row, 3) end_html = item.text() errors, tag = self.services.start_tag_changed(text, end_html) if tag: self.tag_table_widget.setItem(pre_row, 3, QtWidgets.QTableWidgetItem(tag)) self.tag_table_widget.resizeRowsToContents() elif pre_col is EditColumn.EndHtml: # HTML edited item = self.tag_table_widget.item(pre_row, 2) start_html = item.text() errors, tag = self.services.end_tag_changed(start_html, text) if tag: self.tag_table_widget.setItem(pre_row, 3, QtWidgets.QTableWidgetItem(tag)) if errors: QtWidgets.QMessageBox.warning(self, translate('OpenLP.FormattingTagForm', 'Validation Error'), errors, QtWidgets.QMessageBox.Ok) self.tag_table_widget.resizeRowsToContents()
def validateCurrentPage(self): """ Validate the current page before moving on to the next page. """ if self.currentPage() == self.welcome_page: return True elif self.currentPage() == self.available_songs_page: items = [ item for item in find_list_widget_items(self.available_list_widget) if item.checkState() ] if not items: critical_error_message_box( UiStrings().NISp, translate('SongsPlugin.ExportWizardForm', 'You need to add at least one Song to export.')) return False self.selected_list_widget.clear() # Add the songs to the list of selected songs. for item in items: song = QtWidgets.QListWidgetItem(item.text()) song.setData(QtCore.Qt.UserRole, item.data(QtCore.Qt.UserRole)) song.setFlags(QtCore.Qt.ItemIsEnabled) self.selected_list_widget.addItem(song) return True elif self.currentPage() == self.export_song_page: if not self.directory_line_edit.text(): critical_error_message_box( translate('SongsPlugin.ExportWizardForm', 'No Save Location specified'), translate('SongsPlugin.ExportWizardForm', 'You need to specify a directory.')) return False return True elif self.currentPage() == self.progress_page: self.available_list_widget.clear() self.selected_list_widget.clear() return True
def on_data_directory_browse_button_clicked(self): """ Browse for a new data directory location. """ old_root_path = str(self.data_directory_label.text()) # Get the new directory location. new_data_path = QtGui.QFileDialog.getExistingDirectory( self, translate('OpenLP.AdvancedTab', 'Select Data Directory Location'), old_root_path, options=QtGui.QFileDialog.ShowDirsOnly) # Set the new data path. if new_data_path: new_data_path = os.path.normpath(new_data_path) if self.current_data_path.lower() == new_data_path.lower(): self.on_data_directory_cancel_button_clicked() return else: return # Make sure they want to change the data. answer = QtGui.QMessageBox.question( self, translate('OpenLP.AdvancedTab', 'Confirm Data Directory Change'), translate( 'OpenLP.AdvancedTab', 'Are you sure you want to change the ' 'location of the OpenLP data directory to:\n\n%s\n\nThe data ' 'directory will be changed when OpenLP is closed.').replace( '%s', new_data_path), QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No), QtGui.QMessageBox.No) if answer != QtGui.QMessageBox.Yes: return # Check if data already exists here. self.check_data_overwrite(new_data_path) # Save the new location. self.main_window.set_new_data_path(new_data_path) self.new_data_directory_edit.setText(new_data_path) self.data_directory_cancel_button.show()
def _get_status(self, status): """ Helper to retrieve status/error codes and convert to strings. :param status: Status/Error code :returns: (Status/Error code, String) """ if status in ERROR_STRING: return ERROR_STRING[status], ERROR_MSG[status] elif status in STATUS_STRING: return STATUS_STRING[status], ERROR_MSG[status] else: return status, translate('OpenLP.PJLink1', 'Unknown status')
def on_description_updated(self): """ Update the minimum number of characters needed in the description. """ count = int(20 - len(self.description_text_edit.toPlainText())) if count < 0: count = 0 self.__button_state(True) else: self.__button_state(False) self.description_word_count.setText( translate('OpenLP.ExceptionDialog', 'Description characters to enter : %s') % count)
def retranslateUi(self): """ This method is called automatically to provide OpenLP with the opportunity to translate the ``MediaManagerItem`` to another language. """ self.on_new_prompt = translate('MediaPlugin.MediaItem', 'Select Media') self.replace_action.setText(UiStrings().ReplaceBG) self.replace_action_context.setText(UiStrings().ReplaceBG) if 'webkit' in get_media_players()[0]: self.replace_action.setToolTip(UiStrings().ReplaceLiveBG) self.replace_action_context.setToolTip(UiStrings().ReplaceLiveBG) else: self.replace_action.setToolTip(UiStrings().ReplaceLiveBGDisabled) self.replace_action_context.setToolTip( UiStrings().ReplaceLiveBGDisabled) self.reset_action.setText(UiStrings().ResetBG) self.reset_action.setToolTip(UiStrings().ResetLiveBG) self.reset_action_context.setText(UiStrings().ResetBG) self.reset_action_context.setToolTip(UiStrings().ResetLiveBG) self.automatic = UiStrings().Automatic self.display_type_label.setText( translate('MediaPlugin.MediaItem', 'Use Player:'))
def validate_book(self, new_book_name, abbreviation): """ Validate a book. """ book_regex = re.compile('[\d]*[^\d]+$') if not new_book_name: self.book_name_edit[abbreviation].setFocus() critical_error_message_box( UiStrings().EmptyField, translate('BiblesPlugin.BibleEditForm', 'You need to specify a book name for "%s".') % self.book_names[abbreviation]) return False elif not book_regex.match(new_book_name): self.book_name_edit[abbreviation].setFocus() critical_error_message_box( UiStrings().EmptyField, translate( 'BiblesPlugin.BibleEditForm', 'The book name "%s" is not correct.\nNumbers can only be used at the beginning and must\nbe ' 'followed by one or more non-numeric characters.') % new_book_name) return False for abbr, book in self.books.items(): if book: if abbr == abbreviation: continue if self.book_name_edit[abbr].text() == new_book_name: self.book_name_edit[abbreviation].setFocus() critical_error_message_box( translate('BiblesPlugin.BibleEditForm', 'Duplicate Book Name'), translate( 'BiblesPlugin.BibleEditForm', 'The Book Name "%s" has been entered more than once.' ) % new_book_name) return False return True
def _post_wizard(self): """ Clean up the UI after the process has finished. """ if self.max_progress: self.progress_bar.setValue(self.progress_bar.maximum()) if self.has_run_wizard: self.progress_label.setText( translate( 'OpenLP.FirstTimeWizard', 'Download complete. Click the %s button to return to OpenLP.' ) % clean_button_text( self.buttonText(QtGui.QWizard.FinishButton))) else: self.progress_label.setText( translate( 'OpenLP.FirstTimeWizard', 'Download complete. Click the %s button to start OpenLP.' ) % clean_button_text( self.buttonText(QtGui.QWizard.FinishButton))) else: if self.has_run_wizard: self.progress_label.setText( translate('OpenLP.FirstTimeWizard', 'Click the %s button to return to OpenLP.') % clean_button_text( self.buttonText(QtGui.QWizard.FinishButton))) else: self.progress_label.setText( translate('OpenLP.FirstTimeWizard', 'Click the %s button to start OpenLP.') % clean_button_text( self.buttonText(QtGui.QWizard.FinishButton))) self.finish_button.setVisible(True) self.finish_button.setEnabled(True) self.cancel_button.setVisible(False) self.next_button.setVisible(False) self.application.process_events()
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 on_status_checkbox_changed(self, status): """ If the status of a plugin is altered, apply the change """ if self.programatic_change or self.active_plugin is None: return if status: self.application.set_busy_cursor() self.active_plugin.toggle_status(PluginStatus.Active) self.application.set_normal_cursor() self.active_plugin.app_startup() else: self.active_plugin.toggle_status(PluginStatus.Inactive) # TODO: Tested at home status_text = translate('OpenLP.PluginForm', '{name} (Inactive)') if self.active_plugin.status == PluginStatus.Active: status_text = translate('OpenLP.PluginForm', '{name} (Active)') elif self.active_plugin.status == PluginStatus.Inactive: status_text = translate('OpenLP.PluginForm', '{name} (Inactive)') elif self.active_plugin.status == PluginStatus.Disabled: status_text = translate('OpenLP.PluginForm', '{name} (Disabled)') self.plugin_list_widget.currentItem().setText( status_text.format(name=self.active_plugin.name_strings['singular']))
def no_authentication_error(self, name): """ Display warning dialog when pin saved for item but projector does not require pin. :param name: Name from QListWidgetItem """ QtGui.QMessageBox.warning( self, translate('OpenLP.ProjectorManager', '"%s" No Authentication Error' % name), '<br />PIN is set and projector does not require authentication.' '<br /><br />Please verify your PIN setting ' 'for projector item "%s"' % name)
def set_plugin_text_strings(self): """ Called to define all translatable texts of the plugin. """ # Name PluginList self.text_strings[StringContent.Name] = { 'singular': translate('ImagePlugin', 'Image', 'name singular'), 'plural': translate('ImagePlugin', 'Images', 'name plural') } # Name for MediaDockManager, SettingsManager self.text_strings[StringContent.VisibleName] = {'title': translate('ImagePlugin', 'Images', 'container title')} # Middle Header Bar tooltips = { 'load': translate('ImagePlugin', 'Add new image(s).'), 'import': '', 'new': translate('ImagePlugin', 'Add a new image.'), 'edit': translate('ImagePlugin', 'Edit the selected image.'), 'delete': translate('ImagePlugin', 'Delete the selected image.'), 'preview': translate('ImagePlugin', 'Preview the selected image.'), 'live': translate('ImagePlugin', 'Send the selected image live.'), 'service': translate('ImagePlugin', 'Add the selected image to the service.') } self.set_plugin_ui_text_strings(tooltips)
def define_output_location(self): """ Triggered when the Directory selection button is clicked """ path = QtGui.QFileDialog.getExistingDirectory( self, translate('SongUsagePlugin.SongUsageDetailForm', 'Output File Location'), Settings().value(self.plugin.settings_section + '/last directory export')) if path: Settings().setValue( self.plugin.settings_section + '/last directory export', path) self.file_line_edit.setText(path)
def _validiate_shortcut(self, changing_action, key_sequence): """ Checks if the given ``changing_action `` can use the given ``key_sequence``. Returns ``True`` if the ``key_sequence`` can be used by the action, otherwise displays a dialog and returns ``False``. :param changing_action: The action which wants to use the ``key_sequence``. :param key_sequence: The key sequence which the action want so use. """ is_valid = True for category in self.action_list.categories: for action in category.actions: shortcuts = self._action_shortcuts(action) if key_sequence not in shortcuts: continue if action is changing_action: if self.primary_push_button.isChecked() and shortcuts.index(key_sequence) == 0: continue if self.alternate_push_button.isChecked() and shortcuts.index(key_sequence) == 1: continue # Have the same parent, thus they cannot have the same shortcut. if action.parent() is changing_action.parent(): is_valid = False # The new shortcut is already assigned, but if both shortcuts are only valid in a different widget the # new shortcut is valid, because they will not interfere. if action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]: is_valid = False if changing_action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]: is_valid = False if not is_valid: text = translate('OpenLP.ShortcutListDialog', 'The shortcut "{key}" is already assigned to another action, please' ' use a different shortcut.' ).format(key=self.get_shortcut_string(key_sequence)) self.main_window.warning_message(translate('OpenLP.ShortcutListDialog', 'Duplicate Shortcut'), text, for_display=True) self.dialog_was_shown = True return is_valid
def retranslateUi(self): """ Translate the UI on the fly """ self.tab_title_visible = UiStrings().Themes self.global_group_box.setTitle( translate('OpenLP.ThemesTab', 'Global Theme')) self.universal_group_box.setTitle( translate('OpenLP.ThemesTab', 'Universal Settings')) self.wrap_footer_check_box.setText( translate('OpenLP.ThemesTab', '&Wrap footer text')) self.level_group_box.setTitle( translate('OpenLP.ThemesTab', 'Theme Level')) self.song_level_radio_button.setText( translate('OpenLP.ThemesTab', 'S&ong Level')) self.song_level_label.setText( translate( 'OpenLP.ThemesTab', 'Use the theme from each song in the database. If a song doesn\'t have a ' 'theme associated with it, then use the service\'s theme. If the service ' 'doesn\'t have a theme, then use the global theme.')) self.service_level_radio_button.setText( translate('OpenLP.ThemesTab', '&Service Level')) self.service_level_label.setText( translate( 'OpenLP.ThemesTab', 'Use the theme from the service, overriding any of the individual ' 'songs\' themes. If the service doesn\'t have a theme, then use the global ' 'theme.')) self.global_level_radio_button.setText( translate('OpenLP.ThemesTab', '&Global Level')) self.global_level_label.setText( translate( 'OpenLP.ThemesTab', 'Use the global theme, overriding any themes ' 'associated with either the service or the ' 'songs.'))
def do_import(self): """ Receive a single file to import. """ password = self.extract_mdb_password() try: conn = pyodbc.connect('DRIVER={{Microsoft Access Driver (*.mdb)}};DBQ={source};' 'PWD={password}'.format(source=self.import_source, password=password)) except (pyodbc.DatabaseError, pyodbc.IntegrityError, pyodbc.InternalError, pyodbc.OperationalError) as e: log.warning('Unable to connect the OPS Pro database {source}. {error}'.format(source=self.import_source, error=str(e))) # Unfortunately no specific exception type self.log_error(self.import_source, translate('SongsPlugin.OPSProImport', 'Unable to connect the OPS Pro database.')) return cursor = conn.cursor() cursor.execute('SELECT Song.ID, SongNumber, SongBookName, Title, CopyrightText, Version, Origin FROM Song ' 'LEFT JOIN SongBook ON Song.SongBookID = SongBook.ID ORDER BY Title') songs = cursor.fetchall() self.import_wizard.progress_bar.setMaximum(len(songs)) for song in songs: if self.stop_import_flag: break # Type means: 0=Original, 1=Projection, 2=Own cursor.execute('SELECT Lyrics, Type, IsDualLanguage FROM Lyrics WHERE SongID = ? AND Type < 2 ' 'ORDER BY Type DESC', float(song.ID)) lyrics = cursor.fetchone() cursor.execute('SELECT CategoryName FROM Category INNER JOIN SongCategory ' 'ON Category.ID = SongCategory.CategoryID WHERE SongCategory.SongID = ? ' 'ORDER BY CategoryName', float(song.ID)) topics = cursor.fetchall() try: self.process_song(song, lyrics, topics) except Exception as e: self.log_error(self.import_source, translate('SongsPlugin.OPSProImport', '"{title}" could not be imported. {error}').format(title=song.Title, error=e))
def on_edit_topic_button_clicked(self): """ Edit a topic. """ topic_id = self._get_current_item_id(self.topics_list_widget) if topic_id == -1: return topic = self.manager.get_object(Topic, topic_id) self.topic_form.name = topic.name # Save the topic's name for the case that he has to be restored. temp_name = topic.name if self.topic_form.exec(False): topic.name = self.topic_form.name_edit.text() if self.check_topic_exists(topic, True): if self.manager.save_object(topic): self.reset_topics() else: critical_error_message_box( message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your changes.')) elif critical_error_message_box(message=translate( 'SongsPlugin.SongMaintenanceForm', 'The topic {original} already exists. Would you like to make songs with ' 'topic {new} use the existing topic {original}?').format( original=topic.name, new=temp_name), parent=self, question=True ) == QtWidgets.QMessageBox.Yes: self._merge_objects(topic, self.merge_topics, self.reset_topics) else: # We restore the topics's old name. topic.name = temp_name critical_error_message_box(message=translate( 'SongsPlugin.SongMaintenanceForm', 'Could not save your modified topic, because it already exists.' ))
def _perform_wizard(self): """ Run the tasks in the wizard. """ # Set plugin states self._increment_progress_bar( translate('OpenLP.FirstTimeWizard', 'Enabling selected plugins...')) self._set_plugin_status(self.songs_check_box, 'songs/status') self._set_plugin_status(self.bible_check_box, 'bibles/status') self._set_plugin_status(self.presentation_check_box, 'presentations/status') self._set_plugin_status(self.image_check_box, 'images/status') self._set_plugin_status(self.media_check_box, 'media/status') self._set_plugin_status(self.remote_check_box, 'remotes/status') self._set_plugin_status(self.custom_check_box, 'custom/status') self._set_plugin_status(self.song_usage_check_box, 'songusage/status') self._set_plugin_status(self.alert_check_box, 'alerts/status') if self.web_access: if not self._download_selected(): critical_error_message_box( translate('OpenLP.FirstTimeWizard', 'Download Error'), translate( 'OpenLP.FirstTimeWizard', 'There was a connection problem while ' 'downloading, so further downloads will be skipped. Try to re-run ' 'the First Time Wizard later.')) # Set Default Display if self.display_combo_box.currentIndex() != -1: Settings().setValue('core/monitor', self.display_combo_box.currentIndex()) self.screens.set_current_display( self.display_combo_box.currentIndex()) # Set Global Theme if self.theme_combo_box.currentIndex() != -1: Settings().setValue('themes/global theme', self.theme_combo_box.currentText())
def retranslateUi(self, alert_dialog): """ Retranslate the UI strings :param alert_dialog: The dialog """ alert_dialog.setWindowTitle(translate('AlertsPlugin.AlertForm', 'Alert Message')) self.alert_entry_label.setText(translate('AlertsPlugin.AlertForm', 'Alert &text:')) self.alert_parameter.setText(translate('AlertsPlugin.AlertForm', '&Parameter:')) self.new_button.setText(translate('AlertsPlugin.AlertForm', '&New')) self.save_button.setText(translate('AlertsPlugin.AlertForm', '&Save')) self.display_button.setText(translate('AlertsPlugin.AlertForm', 'Displ&ay')) self.display_close_button.setText(translate('AlertsPlugin.AlertForm', 'Display && Cl&ose'))
def get_images_filter(): """ Returns a filter string for a file dialog containing all the supported image formats. """ global IMAGES_FILTER if not IMAGES_FILTER: log.debug('Generating images filter.') formats = list( map(bytes.decode, list(map(bytes, QtGui.QImageReader.supportedImageFormats())))) visible_formats = '(*.%s)' % '; *.'.join(formats) actual_formats = '(*.%s)' % ' *.'.join(formats) IMAGES_FILTER = '%s %s %s' % (translate( 'OpenLP', 'Image Files'), visible_formats, actual_formats) return IMAGES_FILTER
def __init__(self, parent, projectordb, edit=False): """ Build the source select dialog using tabbed interface. :param projectordb: ProjectorDB session to use """ log.debug('Initializing SourceSelectTabs()') super(SourceSelectTabs, self).__init__( parent, QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint) self.setMinimumWidth(350) self.projectordb = projectordb self.edit = edit if self.edit: title = translate('OpenLP.SourceSelectForm', 'Edit Projector Source Text') else: title = translate('OpenLP.SourceSelectForm', 'Select Projector Source') self.setWindowTitle(title) self.setObjectName('source_select_tabs') self.setWindowIcon(build_icon(':/icon/openlp-log-32x32.png')) self.setModal(True) self.layout = QtWidgets.QVBoxLayout() self.layout.setObjectName('source_select_tabs_layout') if is_macosx(): self.tabwidget = QtWidgets.QTabWidget(self) else: self.tabwidget = FingerTabWidget(self) self.tabwidget.setObjectName('source_select_tabs_tabwidget') self.tabwidget.setUsesScrollButtons(False) if is_macosx(): self.tabwidget.setTabPosition(QtWidgets.QTabWidget.North) else: self.tabwidget.setTabPosition(QtWidgets.QTabWidget.West) self.layout.addWidget(self.tabwidget) self.setLayout(self.layout)
def create_valign_selection_widgets(parent): """ Creates a standard label and combo box for asking users to select a vertical alignment. :param parent: The parent object. This should be a ``QWidget`` descendant. """ label = QtWidgets.QLabel(parent) label.setText(translate('OpenLP.Ui', '&Vertical Align:')) combo_box = QtWidgets.QComboBox(parent) combo_box.addItems( [UiStrings().Top, UiStrings().Middle, UiStrings().Bottom]) label.setBuddy(combo_box) return label, combo_box
def on_copy_theme(self, field=None): """ Copies an existing theme to a new name :param field: """ item = self.theme_list_widget.currentItem() old_theme_name = item.data(QtCore.Qt.UserRole) self.file_rename_form.file_name_edit.setText( translate('OpenLP.ThemeManager', 'Copy of %s', 'Copy of <theme name>') % old_theme_name) if self.file_rename_form.exec(True): new_theme_name = self.file_rename_form.file_name_edit.text() if self.check_if_theme_exists(new_theme_name): theme_data = self.get_theme_data(old_theme_name) self.clone_theme_data(theme_data, new_theme_name)
def add_import_menu_item(self, import_menu): """ Give the Songs plugin the opportunity to add items to the **Import** menu. :param import_menu: The actual **Import** menu item, so that your actions can use it as their parent. """ # Main song import menu item - will eventually be the only one self.song_import_item = create_action( import_menu, 'songImportItem', text=translate('SongsPlugin', '&Song'), tooltip=translate('SongsPlugin', 'Import songs using the import wizard.'), triggers=self.on_song_import_item_clicked) import_menu.addAction(self.song_import_item) self.import_songselect_item = create_action( import_menu, 'import_songselect_item', text=translate('SongsPlugin', 'CCLI SongSelect'), statustip=translate( 'SongsPlugin', 'Import songs from CCLI\'s SongSelect service.'), triggers=self.on_import_songselect_item_triggered) import_menu.addAction(self.import_songselect_item)