diff --git a/documentation/manual/source/pics/songusage.png b/documentation/manual/source/pics/songusage.png new file mode 100644 index 000000000..10f29f2a9 Binary files /dev/null and b/documentation/manual/source/pics/songusage.png differ diff --git a/documentation/manual/source/pics/songusagedelete.png b/documentation/manual/source/pics/songusagedelete.png new file mode 100644 index 000000000..fec1b5e5d Binary files /dev/null and b/documentation/manual/source/pics/songusagedelete.png differ diff --git a/documentation/manual/source/pics/songusagereport.png b/documentation/manual/source/pics/songusagereport.png new file mode 100644 index 000000000..c0d9df3dd Binary files /dev/null and b/documentation/manual/source/pics/songusagereport.png differ diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index b6946a628..a90a4c194 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -38,48 +38,51 @@ log = logging.getLogger(__name__) # TODO make external and configurable in alpha 4 via a settings dialog html_expands = [] -html_expands.append({u'desc':u'Red', u'start tag':u'{r}', - u'start html':u'', - u'end tag':u'{/r}', u'end html':u'', u'protected':False}) -html_expands.append({u'desc':u'Black', u'start tag':u'{b}', - u'start html':u'', - u'end tag':u'{/b}', u'end html':u'', u'protected':False}) -html_expands.append({u'desc':u'Blue', u'start tag':u'{bl}', - u'start html':u'', - u'end tag':u'{/bl}', u'end html':u'', u'protected':False}) -html_expands.append({u'desc':u'Yellow', u'start tag':u'{y}', - u'start html':u'', - u'end tag':u'{/y}', u'end html':u'', u'protected':False}) -html_expands.append({u'desc':u'Green', u'start tag':u'{g}', - u'start html':u'', - u'end tag':u'{/g}', u'end html':u'', u'protected':False}) -html_expands.append({u'desc':u'Pink', u'start tag':u'{pk}', - u'start html':u'', - u'end tag':u'{/pk}', u'end html':u'', u'protected':False}) -html_expands.append({u'desc':u'Orange', u'start tag':u'{o}', - u'start html':u'', - u'end tag':u'{/o}', u'end html':u'', u'protected':False}) -html_expands.append({u'desc':u'Purple', u'start tag':u'{pp}', - u'start html':u'', - u'end tag':u'{/pp}', u'end html':u'', u'protected':False}) -html_expands.append({u'desc':u'White', u'start tag':u'{w}', - u'start html':u'', - u'end tag':u'{/w}', u'end html':u'', u'protected':False}) -html_expands.append({u'desc':u'Superscript', u'start tag':u'{su}', - u'start html':u'', u'end tag':u'{/su}', u'end html':u'', - u'protected':True}) -html_expands.append({u'desc':u'Subscript', u'start tag':u'{sb}', - u'start html':u'', u'end tag':u'{/sb}', u'end html':u'', - u'protected':True}) -html_expands.append({u'desc':u'Paragraph', u'start tag':u'{p}', - u'start html':u'

', u'end tag':u'{/p}', u'end html':u'

', - u'protected':True}) -html_expands.append({u'desc':u'Bold', u'start tag':u'{st}', - u'start html':u'', u'end tag':u'{/st}', u'end html':u'', - u'protected':True}) -html_expands.append({u'desc':u'Italics', u'start tag':u'{it}', - u'start html':u'', u'end tag':u'{/it}', u'end html':u'', - u'protected':True}) +html_expands.append({u'desc': u'Red', u'start tag': u'{r}', + u'start html': u'', + u'end tag': u'{/r}', u'end html': u'', u'protected': False}) +html_expands.append({u'desc': u'Black', u'start tag': u'{b}', + u'start html': u'', + u'end tag': u'{/b}', u'end html': u'', u'protected': False}) +html_expands.append({u'desc': u'Blue', u'start tag': u'{bl}', + u'start html': u'', + u'end tag': u'{/bl}', u'end html': u'', u'protected': False}) +html_expands.append({u'desc': u'Yellow', u'start tag': u'{y}', + u'start html': u'', + u'end tag': u'{/y}', u'end html': u'', u'protected': False}) +html_expands.append({u'desc': u'Green', u'start tag': u'{g}', + u'start html': u'', + u'end tag': u'{/g}', u'end html': u'', u'protected': False}) +html_expands.append({u'desc': u'Pink', u'start tag': u'{pk}', + u'start html': u'', + u'end tag': u'{/pk}', u'end html': u'', u'protected': False}) +html_expands.append({u'desc': u'Orange', u'start tag': u'{o}', + u'start html': u'', + u'end tag': u'{/o}', u'end html': u'', u'protected': False}) +html_expands.append({u'desc': u'Purple', u'start tag': u'{pp}', + u'start html': u'', + u'end tag': u'{/pp}', u'end html': u'', u'protected': False}) +html_expands.append({u'desc': u'White', u'start tag': u'{w}', + u'start html': u'', + u'end tag': u'{/w}', u'end html': u'', u'protected': False}) +html_expands.append({u'desc': u'Superscript', u'start tag': u'{su}', + u'start html': u'', u'end tag': u'{/su}', u'end html': u'', + u'protected': True}) +html_expands.append({u'desc': u'Subscript', u'start tag': u'{sb}', + u'start html': u'', u'end tag': u'{/sb}', u'end html': u'', + u'protected': True}) +html_expands.append({u'desc': u'Paragraph', u'start tag': u'{p}', + u'start html': u'

', u'end tag': u'{/p}', u'end html': u'

', + u'protected': True}) +html_expands.append({u'desc': u'Bold', u'start tag': u'{st}', + u'start html': u'', u'end tag': u'{/st}', u'end html': u'', + u'protected': True}) +html_expands.append({u'desc': u'Italics', u'start tag': u'{it}', + u'start html': u'', u'end tag': u'{/it}', u'end html': u'', + u'protected': True}) +html_expands.append({u'desc': u'Underline', u'start tag': u'{u}', + u'start html': u'', + u'end tag': u'{/u}', u'end html': u'', u'protected': True}) def translate(context, text, comment=None): """ diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index 0dc138abc..8afa02111 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -294,4 +294,5 @@ class Manager(object): """ if self.is_dirty: engine = create_engine(self.db_url) - engine.execute("vacuum") + if self.db_url.startswith(u'sqlite'): + engine.execute("vacuum") diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index 3eae97238..130da0c0e 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -320,15 +320,9 @@ class MediaManagerItem(QtGui.QWidget): translate('OpenLP.MediaManagerItem', '&Add to selected Service Item'), self.onAddEditClick)) - if QtCore.QSettings().value(u'advanced/double click live', - QtCore.QVariant(False)).toBool(): - QtCore.QObject.connect(self.listView, - QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), - self.onLiveClick) - else: - QtCore.QObject.connect(self.listView, - QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), - self.onPreviewClick) + QtCore.QObject.connect(self.listView, + QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), + self.onClickPressed) def initialise(self): """ @@ -426,10 +420,20 @@ class MediaManagerItem(QtGui.QWidget): raise NotImplementedError(u'MediaManagerItem.onDeleteClick needs to ' u'be defined by the plugin') - def generateSlideData(self, service_item, item=None): + def generateSlideData(self, serviceItem, item=None, xmlVersion=False): raise NotImplementedError(u'MediaManagerItem.generateSlideData needs ' u'to be defined by the plugin') + def onClickPressed(self): + """ + Allows the list click action to be determined dynamically + """ + if QtCore.QSettings().value(u'advanced/double click live', + QtCore.QVariant(False)).toBool(): + self.onLiveClick() + else: + self.onPreviewClick() + def onPreviewClick(self): """ Preview an item by building a service item then adding that service @@ -442,10 +446,10 @@ class MediaManagerItem(QtGui.QWidget): 'You must select one or more items to preview.')) else: log.debug(self.plugin.name + u' Preview requested') - service_item = self.buildServiceItem() - if service_item: - service_item.from_plugin = True - self.parent.previewController.addServiceItem(service_item) + serviceItem = self.buildServiceItem() + if serviceItem: + serviceItem.from_plugin = True + self.parent.previewController.addServiceItem(serviceItem) def onLiveClick(self): """ @@ -459,10 +463,10 @@ class MediaManagerItem(QtGui.QWidget): 'You must select one or more items to send live.')) else: log.debug(self.plugin.name + u' Live requested') - service_item = self.buildServiceItem() - if service_item: - service_item.from_plugin = True - self.parent.liveController.addServiceItem(service_item) + serviceItem = self.buildServiceItem() + if serviceItem: + serviceItem.from_plugin = True + self.parent.liveController.addServiceItem(serviceItem) def onAddClick(self): """ @@ -474,22 +478,22 @@ class MediaManagerItem(QtGui.QWidget): translate('OpenLP.MediaManagerItem', 'You must select one or more items.')) else: - # Is it posssible to process multiple list items to generate multiple - # service items? + # Is it posssible to process multiple list items to generate + # multiple service items? if self.singleServiceItem or self.remoteTriggered: log.debug(self.plugin.name + u' Add requested') - service_item = self.buildServiceItem() - if service_item: - service_item.from_plugin = False - self.parent.serviceManager.addServiceItem(service_item, + serviceItem = self.buildServiceItem(None, True) + if serviceItem: + serviceItem.from_plugin = False + self.parent.serviceManager.addServiceItem(serviceItem, replace=self.remoteTriggered) else: items = self.listView.selectedIndexes() for item in items: - service_item = self.buildServiceItem(item) - if service_item: - service_item.from_plugin = False - self.parent.serviceManager.addServiceItem(service_item) + serviceItem = self.buildServiceItem(item, True) + if serviceItem: + serviceItem.from_plugin = False + self.parent.serviceManager.addServiceItem(serviceItem) def onAddEditClick(self): """ @@ -502,16 +506,16 @@ class MediaManagerItem(QtGui.QWidget): 'You must select one or more items')) else: log.debug(self.plugin.name + u' Add requested') - service_item = self.parent.serviceManager.getServiceItem() - if not service_item: + serviceItem = self.parent.serviceManager.getServiceItem() + if not serviceItem: QtGui.QMessageBox.information(self, translate('OpenLP.MediaManagerItem', 'No Service Item Selected'), translate('OpenLP.MediaManagerItem', 'You must select an existing service item to add to.')) - elif self.title.lower() == service_item.name.lower(): - self.generateSlideData(service_item) - self.parent.serviceManager.addServiceItem(service_item, + elif self.title.lower() == serviceItem.name.lower(): + self.generateSlideData(serviceItem) + self.parent.serviceManager.addServiceItem(serviceItem, replace=True) else: # Turn off the remote edit update message indicator @@ -521,17 +525,17 @@ class MediaManagerItem(QtGui.QWidget): unicode(translate('OpenLP.MediaManagerItem', 'You must select a %s service item.')) % self.title) - def buildServiceItem(self, item=None): + def buildServiceItem(self, item=None, xmlVersion=False): """ Common method for generating a service item """ - service_item = ServiceItem(self.parent) + serviceItem = ServiceItem(self.parent) if self.serviceItemIconName: - service_item.add_icon(self.serviceItemIconName) + serviceItem.add_icon(self.serviceItemIconName) else: - service_item.add_icon(self.parent.icon_path) - if self.generateSlideData(service_item, item): - return service_item + serviceItem.add_icon(self.parent.icon_path) + if self.generateSlideData(serviceItem, item, xmlVersion): + return serviceItem else: return None diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index 0cbc34de5..b9394030a 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -101,6 +101,7 @@ class ServiceItem(object): self.search_string = u'' self.data_string = u'' self.edit_id = None + self.xml_version = None self._new_item() def _new_item(self): @@ -252,7 +253,8 @@ class ServiceItem(object): u'from_plugin': self.from_plugin, u'capabilities': self.capabilities, u'search': self.search_string, - u'data': self.data_string + u'data': self.data_string, + u'xml_version': self.xml_version } service_data = [] if self.service_item_type == ServiceItemType.Text: @@ -294,6 +296,8 @@ class ServiceItem(object): if u'search' in header: self.search_string = header[u'search'] self.data_string = header[u'data'] + if u'xml_version' in header: + self.xml_version = header[u'xml_version'] if self.service_item_type == ServiceItemType.Text: for slide in serviceitem[u'serviceitem'][u'data']: self._raw_frames.append(slide) diff --git a/openlp/core/ui/advancedtab.py b/openlp/core/ui/advancedtab.py index dc126d863..a390780ca 100644 --- a/openlp/core/ui/advancedtab.py +++ b/openlp/core/ui/advancedtab.py @@ -146,7 +146,7 @@ class AdvancedTab(SettingsTab): self.mediaPluginCheckBox.setText(translate('OpenLP.AdvancedTab', 'Remember active media manager tab on startup')) self.doubleClickLiveCheckBox.setText(translate('OpenLP.AdvancedTab', - 'Double-click to send items straight to live (requires restart)')) + 'Double-click to send items straight to live')) self.expandServiceItemCheckBox.setText(translate('OpenLP.AdvancedTab', 'Expand new service items on creation')) # self.sharedDirGroupBox.setTitle( diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index 5a53a84fe..90f920a50 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -100,7 +100,7 @@ class MainDisplay(DisplayWidget): self.screens = screens self.isLive = live self.alertTab = None - self.hide_mode = None + self.hideMode = None self.setWindowTitle(u'OpenLP Display') self.setStyleSheet(u'border: 0px; margin: 0px; padding: 0px;') self.setWindowFlags(QtCore.Qt.FramelessWindowHint | @@ -381,8 +381,8 @@ class MainDisplay(DisplayWidget): if self.isLive: self.setVisible(True) # if was hidden keep it hidden - if self.hide_mode and self.isLive: - self.hideDisplay(self.hide_mode) + if self.hideMode and self.isLive: + self.hideDisplay(self.hideMode) preview = QtGui.QImage(self.screen[u'size'].width(), self.screen[u'size'].height(), QtGui.QImage.Format_ARGB32_Premultiplied) @@ -412,8 +412,8 @@ class MainDisplay(DisplayWidget): if serviceItem.foot_text and serviceItem.foot_text: self.footer(serviceItem.foot_text) # if was hidden keep it hidden - if self.hide_mode and self.isLive: - self.hideDisplay(self.hide_mode) + if self.hideMode and self.isLive: + self.hideDisplay(self.hideMode) def footer(self, text): """ @@ -444,7 +444,7 @@ class MainDisplay(DisplayWidget): self.setVisible(True) if self.phononActive: self.webView.setVisible(True) - self.hide_mode = mode + self.hideMode = mode def showDisplay(self): """ @@ -459,9 +459,9 @@ class MainDisplay(DisplayWidget): if self.phononActive: self.webView.setVisible(False) self.videoPlay() + self.hideMode = None # Trigger actions when display is active again Receiver.send_message(u'maindisplay_active') - self.hide_mode = None class AudioPlayer(QtCore.QObject): """ diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index f294cedd4..6d721823a 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -789,6 +789,8 @@ class ServiceManager(QtGui.QWidget): self.serviceName = name[len(name) - 1] self.parent.addRecentFile(filename) self.parent.serviceChanged(True, self.serviceName) + # Refresh Plugin lists + Receiver.send_message(u'plugin_list_refresh') def validateItem(self, serviceItem): """ @@ -1028,6 +1030,9 @@ class ServiceManager(QtGui.QWidget): # ServiceManager started the drag and drop if plugin == u'ServiceManager': startpos, startCount = self.findServiceItem() + # If no items selected + if startpos == -1: + return if item is None: endpos = len(self.serviceItems) else: diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 0afb0efaa..48810990a 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -331,10 +331,8 @@ class SlideController(QtGui.QWidget): QtCore.QObject.connect(self.PreviewListWidget, QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSlideSelected) if not self.isLive: - if QtCore.QSettings().value(u'advanced/double click live', - QtCore.QVariant(False)).toBool(): - QtCore.QObject.connect(self.PreviewListWidget, - QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onGoLive) + QtCore.QObject.connect(self.PreviewListWidget, + QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onGoLiveClick) if isLive: QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'slidecontroller_live_spin_delay'), @@ -391,6 +389,8 @@ class SlideController(QtGui.QWidget): if self.isLive: QtCore.QObject.connect(self.volumeSlider, QtCore.SIGNAL(u'sliderReleased()'), self.mediaVolume) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'maindisplay_active'), self.updatePreview) def screenSizeChanged(self): """ @@ -823,16 +823,15 @@ class SlideController(QtGui.QWidget): row) def updatePreview(self): + log.debug(u'updatePreview %s ' %self.screens.current[u'primary']) if not self.screens.current[u'primary']: # Grab now, but try again in a couple of seconds if slide change # is slow QtCore.QTimer.singleShot(0.5, self.grabMainDisplay) QtCore.QTimer.singleShot(2.5, self.grabMainDisplay) else: - label = self.PreviewListWidget.cellWidget( - self.PreviewListWidget.currentRow(), 1) - if label: - self.SlidePreview.setPixmap(label.pixmap()) + self.SlidePreview.setPixmap( + QtGui.QPixmap.fromImage(self.display.preview())) def grabMainDisplay(self): winid = QtGui.QApplication.desktop().winId() @@ -944,6 +943,14 @@ class SlideController(QtGui.QWidget): Receiver.send_message(u'%s_edit' % self.serviceItem.name.lower(), u'P:%s' % self.serviceItem.edit_id) + def onGoLiveClick(self): + """ + triggered by clicking the Preview slide items + """ + if QtCore.QSettings().value(u'advanced/double click live', + QtCore.QVariant(False)).toBool(): + self.onGoLive() + def onGoLive(self): """ If preview copy slide item to live diff --git a/openlp/core/ui/themestab.py b/openlp/core/ui/themestab.py index 853865bb5..fe1f95aee 100644 --- a/openlp/core/ui/themestab.py +++ b/openlp/core/ui/themestab.py @@ -183,9 +183,14 @@ class ThemesTab(SettingsTab): def updateThemeList(self, theme_list): """ - Called from ThemeManager when the Themes have changed + Called from ThemeManager when the Themes have changed. + + ``theme_list`` + The list of available themes:: + + [u'Bible Theme', u'Song Theme'] """ - #reload as may have been triggered by the ThemeManager + # Reload as may have been triggered by the ThemeManager. self.global_theme = unicode(QtCore.QSettings().value( self.settingsSection + u'/global theme', QtCore.QVariant(u'')).toString()) diff --git a/openlp/plugins/bibles/forms/bibleimportform.py b/openlp/plugins/bibles/forms/bibleimportform.py index 2e11c30ad..749f1f938 100644 --- a/openlp/plugins/bibles/forms/bibleimportform.py +++ b/openlp/plugins/bibles/forms/bibleimportform.py @@ -133,7 +133,7 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard): self.OSISLocationEdit.setFocus() return False elif self.field(u'source_format').toInt()[0] == BibleFormat.CSV: - if self.field(u'csv_booksfile').toString() == u'': + if not self.field(u'csv_booksfile').toString(): QtGui.QMessageBox.critical(self, translate('BiblesPlugin.ImportWizardForm', 'Invalid Books File'), @@ -142,7 +142,7 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard): 'the Bible to use in the import.')) self.BooksLocationEdit.setFocus() return False - elif self.field(u'csv_versefile').toString() == u'': + elif not self.field(u'csv_versefile').toString(): QtGui.QMessageBox.critical(self, translate('BiblesPlugin.ImportWizardForm', 'Invalid Verse File'), @@ -153,7 +153,7 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard): return False elif self.field(u'source_format').toInt()[0] == \ BibleFormat.OpenSong: - if self.field(u'opensong_file').toString() == u'': + if not self.field(u'opensong_file').toString(): QtGui.QMessageBox.critical(self, translate('BiblesPlugin.ImportWizardForm', 'Invalid OpenSong Bible'), @@ -168,7 +168,7 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard): license_version = unicode(self.field(u'license_version').toString()) license_copyright = \ unicode(self.field(u'license_copyright').toString()) - if license_version == u'': + if not license_version: QtGui.QMessageBox.critical(self, translate('BiblesPlugin.ImportWizardForm', 'Empty Version Name'), @@ -176,7 +176,7 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard): 'You need to specify a version name for your Bible.')) self.VersionNameEdit.setFocus() return False - elif license_copyright == u'': + elif not license_copyright: QtGui.QMessageBox.critical(self, translate('BiblesPlugin.ImportWizardForm', 'Empty Copyright'), @@ -207,9 +207,11 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard): The index of the combo box. """ self.BibleComboBox.clear() - for bible in self.web_bible_list[index].keys(): - self.BibleComboBox.addItem(unicode( - translate('BiblesPlugin.ImportWizardForm', bible))) + bibles = [unicode(translate('BiblesPlugin.ImportWizardForm', bible)) for + bible in self.web_bible_list[index].keys()] + bibles.sort() + for bible in bibles: + self.BibleComboBox.addItem(bible) def onOsisFileButtonClicked(self): """ @@ -317,7 +319,7 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard): """ Load the list of Crosswalk and BibleGateway bibles. """ - #Load and store Crosswalk Bibles + # Load and store Crosswalk Bibles. filepath = AppLocation.get_directory(AppLocation.PluginsDir) filepath = os.path.join(filepath, u'bibles', u'resources') books_file = None @@ -341,7 +343,7 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard): finally: if books_file: books_file.close() - #Load and store BibleGateway Bibles + # Load and store BibleGateway Bibles. books_file = None try: self.web_bible_list[WebDownload.BibleGateway] = {} @@ -379,12 +381,18 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard): Receiver.send_message(u'openlp_process_events') def preImport(self): + bible_type = self.field(u'source_format').toInt()[0] self.finishButton.setVisible(False) self.ImportProgressBar.setMinimum(0) self.ImportProgressBar.setMaximum(1188) self.ImportProgressBar.setValue(0) - self.ImportProgressLabel.setText( - translate('BiblesPlugin.ImportWizardForm', 'Starting import...')) + if bible_type == BibleFormat.WebDownload: + self.ImportProgressLabel.setText(translate( + 'BiblesPlugin.ImportWizardForm', + 'Starting Registering bible...')) + else: + self.ImportProgressLabel.setText(translate( + 'BiblesPlugin.ImportWizardForm', 'Starting import...')) Receiver.send_message(u'openlp_process_events') def performImport(self): @@ -395,26 +403,26 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard): unicode(self.field(u'license_permissions').toString()) importer = None if bible_type == BibleFormat.OSIS: - # Import an OSIS bible + # Import an OSIS bible. importer = self.manager.import_bible(BibleFormat.OSIS, name=license_version, filename=unicode(self.field(u'osis_location').toString()) ) elif bible_type == BibleFormat.CSV: - # Import a CSV bible + # Import a CSV bible. importer = self.manager.import_bible(BibleFormat.CSV, name=license_version, booksfile=unicode(self.field(u'csv_booksfile').toString()), versefile=unicode(self.field(u'csv_versefile').toString()) ) elif bible_type == BibleFormat.OpenSong: - # Import an OpenSong bible + # Import an OpenSong bible. importer = self.manager.import_bible(BibleFormat.OpenSong, name=license_version, filename=unicode(self.field(u'opensong_file').toString()) ) elif bible_type == BibleFormat.WebDownload: - # Import a bible from the web + # Import a bible from the web. self.ImportProgressBar.setMaximum(1) download_location = self.field(u'web_location').toInt()[0] bible_version = unicode(self.BibleComboBox.currentText()) @@ -438,8 +446,14 @@ class BibleImportForm(QtGui.QWizard, Ui_BibleImportWizard): self.manager.save_meta_data(license_version, license_version, license_copyright, license_permissions) self.manager.reload_bibles() - self.ImportProgressLabel.setText( - translate('BiblesPlugin.ImportWizardForm', 'Finished import.')) + if bible_type == BibleFormat.WebDownload: + self.ImportProgressLabel.setText( + translate('BiblesPlugin.ImportWizardForm', 'Registered ' + 'bible. Please note, that verses will be downloaded on\n' + 'demand and thus an internet connection is required.')) + else: + self.ImportProgressLabel.setText(translate( + 'BiblesPlugin.ImportWizardForm', 'Finished import.')) else: self.ImportProgressLabel.setText( translate('BiblesPlugin.ImportWizardForm', diff --git a/openlp/plugins/bibles/lib/biblestab.py b/openlp/plugins/bibles/lib/biblestab.py index b7d1b9bde..a52c31fb7 100644 --- a/openlp/plugins/bibles/lib/biblestab.py +++ b/openlp/plugins/bibles/lib/biblestab.py @@ -110,9 +110,9 @@ class BiblesTab(SettingsTab): self.BibleThemeComboBox.setObjectName(u'BibleThemeComboBox') self.BibleThemeComboBox.addItem(QtCore.QString()) self.BibleThemeLayout.addWidget(self.BibleThemeComboBox) - self.BibleDualCheckBox = QtGui.QCheckBox(self.VerseDisplayGroupBox) - self.BibleDualCheckBox.setObjectName(u'BibleDualCheckBox') - self.VerseDisplayLayout.addWidget(self.BibleDualCheckBox, 3, 0, 1, 1) + self.BibleSecondCheckBox = QtGui.QCheckBox(self.VerseDisplayGroupBox) + self.BibleSecondCheckBox.setObjectName(u'BibleSecondCheckBox') + self.VerseDisplayLayout.addWidget(self.BibleSecondCheckBox, 3, 0, 1, 1) self.VerseDisplayLayout.addWidget(self.BibleThemeWidget, 4, 0, 1, 1) self.ChangeNoteLabel = QtGui.QLabel(self.VerseDisplayGroupBox) self.ChangeNoteLabel.setObjectName(u'ChangeNoteLabel') @@ -143,8 +143,8 @@ class BiblesTab(SettingsTab): self.LayoutStyleComboBox, QtCore.SIGNAL(u'activated(int)'), self.onLayoutStyleComboBoxChanged) QtCore.QObject.connect( - self.BibleDualCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), - self.onBibleDualCheckBox) + self.BibleSecondCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), + self.onBibleSecondCheckBox) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'theme_update_list'), self.updateThemeList) @@ -176,8 +176,8 @@ class BiblesTab(SettingsTab): translate('BiblesPlugin.BiblesTab', '[ And ]')) self.ChangeNoteLabel.setText(translate('BiblesPlugin.BiblesTab', 'Note:\nChanges do not affect verses already in the service.')) - self.BibleDualCheckBox.setText( - translate('BiblesPlugin.BiblesTab', 'Display dual Bible verses')) + self.BibleSecondCheckBox.setText( + translate('BiblesPlugin.BiblesTab', 'Display second Bible verses')) def onBibleThemeComboBoxChanged(self): self.bible_theme = self.BibleThemeComboBox.currentText() @@ -190,15 +190,15 @@ class BiblesTab(SettingsTab): def onNewChaptersCheckBoxChanged(self, check_state): self.show_new_chapters = False - # we have a set value convert to True/False + # We have a set value convert to True/False. if check_state == QtCore.Qt.Checked: self.show_new_chapters = True - def onBibleDualCheckBox(self, check_state): - self.dual_bibles = False - # we have a set value convert to True/False + def onBibleSecondCheckBox(self, check_state): + self.second_bibles = False + # We have a set value convert to True/False. if check_state == QtCore.Qt.Checked: - self.dual_bibles = True + self.second_bibles = True def load(self): settings = QtCore.QSettings() @@ -211,12 +211,12 @@ class BiblesTab(SettingsTab): u'verse layout style', QtCore.QVariant(0)).toInt()[0] self.bible_theme = unicode( settings.value(u'bible theme', QtCore.QVariant(u'')).toString()) - self.dual_bibles = settings.value( - u'dual bibles', QtCore.QVariant(True)).toBool() + self.second_bibles = settings.value( + u'second bibles', QtCore.QVariant(True)).toBool() self.NewChaptersCheckBox.setChecked(self.show_new_chapters) self.DisplayStyleComboBox.setCurrentIndex(self.display_style) self.LayoutStyleComboBox.setCurrentIndex(self.layout_style) - self.BibleDualCheckBox.setChecked(self.dual_bibles) + self.BibleSecondCheckBox.setChecked(self.second_bibles) settings.endGroup() def save(self): @@ -228,13 +228,18 @@ class BiblesTab(SettingsTab): QtCore.QVariant(self.display_style)) settings.setValue(u'verse layout style', QtCore.QVariant(self.layout_style)) - settings.setValue(u'dual bibles', QtCore.QVariant(self.dual_bibles)) + settings.setValue(u'second bibles', QtCore.QVariant(self.second_bibles)) settings.setValue(u'bible theme', QtCore.QVariant(self.bible_theme)) settings.endGroup() def updateThemeList(self, theme_list): """ - Called from ThemeManager when the Themes have changed + Called from ThemeManager when the Themes have changed. + + ``theme_list`` + The list of available themes:: + + [u'Bible Theme', u'Song Theme'] """ self.BibleThemeComboBox.clear() self.BibleThemeComboBox.addItem(u'') @@ -243,7 +248,7 @@ class BiblesTab(SettingsTab): index = self.BibleThemeComboBox.findText( unicode(self.bible_theme), QtCore.Qt.MatchExactly) if index == -1: - # Not Found + # Not Found. index = 0 self.bible_theme = u'' self.BibleThemeComboBox.setCurrentIndex(index) diff --git a/openlp/plugins/bibles/lib/db.py b/openlp/plugins/bibles/lib/db.py index 8f5c7dc79..9852ed16b 100644 --- a/openlp/plugins/bibles/lib/db.py +++ b/openlp/plugins/bibles/lib/db.py @@ -44,24 +44,28 @@ class BibleMeta(BaseModel): """ pass + class Testament(BaseModel): """ Bible Testaments """ pass + class Book(BaseModel): """ Song model """ pass + class Verse(BaseModel): """ Topic model """ pass + def init_schema(url): """ Setup a bible database connection and initialise the database schema. @@ -240,7 +244,7 @@ class BibleDB(QtCore.QObject, Manager): and the value is the verse text. """ log.debug(u'create_chapter %s,%s', book_id, chapter) - # text list has book and chapter as first two elements of the array + # Text list has book and chapter as first two elements of the array. for verse_number, verse_text in textlist.iteritems(): verse = Verse.populate( book_id = book_id, diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py index 235862ae8..fa47dd7f5 100644 --- a/openlp/plugins/bibles/lib/http.py +++ b/openlp/plugins/bibles/lib/http.py @@ -364,12 +364,11 @@ class HTTPBible(BibleDB): if self.proxy_server: self.create_meta(u'proxy server', self.proxy_server) if self.proxy_username: - # store the proxy userid + # Store the proxy userid. self.create_meta(u'proxy username', self.proxy_username) if self.proxy_password: - # store the proxy password + # Store the proxy password. self.create_meta(u'proxy password', self.proxy_password) - self.wizard.incrementProgressBar('Registered.') return True def get_verses(self, reference_list): @@ -417,7 +416,7 @@ class HTTPBible(BibleDB): ## to request ac and get Acts back. bookname = search_results.book Receiver.send_message(u'openlp_process_events') - # check to see if book/chapter exists + # Check to see if book/chapter exists. db_book = self.get_book(bookname) self.create_chapter(db_book.id, search_results.chapter, search_results.verselist) diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py index 9afc4a4b2..6b4d7c800 100644 --- a/openlp/plugins/bibles/lib/manager.py +++ b/openlp/plugins/bibles/lib/manager.py @@ -257,17 +257,34 @@ class BibleManager(object): 'Book Chapter:Verse-Chapter:Verse')) return None - def verse_search(self, bible, text): + def verse_search(self, bible, second_bible, text): """ Does a verse search for the given bible and text. ``bible`` The bible to seach in (unicode). + ``second_bible`` + The second bible (unicode). We do not search in this bible. + ``text`` The text to search for (unicode). """ - log.debug(u'BibleManager.verse_search("%s", "%s")', bible, text) + log.debug(u'BibleManager.verse_search("%s", "%s")', bible, text) + # Check if the bible or second_bible is a web bible. + webbible = self.db_cache[bible].get_object(BibleMeta, + u'download source') + second_webbible = u'' + if second_bible: + second_webbible = self.db_cache[second_bible].get_object(BibleMeta, + u'download source') + if webbible or second_webbible: + QtGui.QMessageBox.information(self.parent.mediaItem, + translate('BiblesPlugin.BibleManager', + 'Web Bible cannot be used'), + translate('BiblesPlugin.BibleManager', 'Text Search is not ' + 'available with Web Bibles.')) + return None if text: return self.db_cache[bible].verse_search(text) else: @@ -317,4 +334,3 @@ class BibleManager(object): """ for bible in self.db_cache: self.db_cache[bible].finalise() - diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index bb3c1b26d..949035c0b 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -47,21 +47,22 @@ class BibleListView(BaseListWithDnD): self.parent().onListViewResize(event.size().width(), event.size().width()) + class BibleMediaItem(MediaManagerItem): """ This is the custom media manager item for Bibles. """ log.info(u'Bible Media Item loaded') - def __init__(self, parent, icon, title): + def __init__(self, parent, plugin, icon): self.PluginNameShort = u'Bible' self.pluginNameVisible = translate('BiblesPlugin.MediaItem', 'Bible') self.IconPath = u'songs/song' self.ListViewWithDnD_class = BibleListView - MediaManagerItem.__init__(self, parent, icon, title) - # place to store the search results for both bibles + MediaManagerItem.__init__(self, parent, plugin, icon) + # Place to store the search results for both bibles. self.search_results = {} - self.dual_search_results = {} + self.second_search_results = {} QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'bibles_load_list'), self.reloadBibles) @@ -83,7 +84,7 @@ class BibleMediaItem(MediaManagerItem): self.SearchTabWidget.sizePolicy().hasHeightForWidth()) self.SearchTabWidget.setSizePolicy(sizePolicy) self.SearchTabWidget.setObjectName(u'SearchTabWidget') - # Add the Quick Search tab + # Add the Quick Search tab. self.QuickTab = QtGui.QWidget() self.QuickTab.setObjectName(u'QuickTab') self.QuickLayout = QtGui.QGridLayout(self.QuickTab) @@ -144,7 +145,7 @@ class BibleMediaItem(MediaManagerItem): QuickSpacerItem = QtGui.QSpacerItem(20, 35, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) self.QuickLayout.addItem(QuickSpacerItem, 6, 2, 1, 1) - # Add the Advanced Search tab + # Add the Advanced Search tab. self.AdvancedTab = QtGui.QWidget() self.AdvancedTab.setObjectName(u'AdvancedTab') self.AdvancedLayout = QtGui.QGridLayout(self.AdvancedTab) @@ -226,7 +227,7 @@ class BibleMediaItem(MediaManagerItem): self.AdvancedLayout.addWidget(self.AdvancedMessage, 8, 0, 1, 3) self.SearchTabWidget.addTab(self.AdvancedTab, translate('BiblesPlugin.MediaItem', 'Advanced')) - # Add the search tab widget to the page layout + # Add the search tab widget to the page layout. self.pageLayout.addWidget(self.SearchTabWidget) # Combo Boxes QtCore.QObject.connect(self.AdvancedVersionComboBox, @@ -239,6 +240,10 @@ class BibleMediaItem(MediaManagerItem): QtCore.SIGNAL(u'activated(int)'), self.onAdvancedFromVerse) QtCore.QObject.connect(self.AdvancedToChapter, QtCore.SIGNAL(u'activated(int)'), self.onAdvancedToChapter) + QtCore.QObject.connect(self.QuickSearchComboBox, + QtCore.SIGNAL(u'activated(int)'), self.updateAutoCompleter) + QtCore.QObject.connect(self.QuickVersionComboBox, + QtCore.SIGNAL(u'activated(int)'), self.updateAutoCompleter) # Buttons QtCore.QObject.connect(self.AdvancedSearchButton, QtCore.SIGNAL(u'pressed()'), self.onAdvancedSearchButton) @@ -270,7 +275,7 @@ class BibleMediaItem(MediaManagerItem): def configUpdated(self): log.debug(u'configUpdated') - if QtCore.QSettings().value(self.settingsSection + u'/dual bibles', + if QtCore.QSettings().value(self.settingsSection + u'/second bibles', QtCore.QVariant(True)).toBool(): self.AdvancedSecondBibleLabel.setVisible(True) self.AdvancedSecondBibleComboBox.setVisible(True) @@ -287,7 +292,7 @@ class BibleMediaItem(MediaManagerItem): self.QuickVersionLabel.setText( translate('BiblesPlugin.MediaItem', 'Version:')) self.QuickSecondVersionLabel.setText( - translate('BiblesPlugin.MediaItem', 'Dual:')) + translate('BiblesPlugin.MediaItem', 'Second:')) self.QuickSearchLabel.setText( translate('BiblesPlugin.MediaItem', 'Search type:')) self.QuickSearchLabel.setText( @@ -299,7 +304,7 @@ class BibleMediaItem(MediaManagerItem): self.AdvancedVersionLabel.setText( translate('BiblesPlugin.MediaItem', 'Version:')) self.AdvancedSecondBibleLabel.setText( - translate('BiblesPlugin.MediaItem', 'Dual:')) + translate('BiblesPlugin.MediaItem', 'Second:')) self.AdvancedBookLabel.setText( translate('BiblesPlugin.MediaItem', 'Book:')) self.AdvancedChapterLabel.setText( @@ -331,6 +336,7 @@ class BibleMediaItem(MediaManagerItem): log.debug(u'bible manager initialise') self.parent.manager.media = self self.loadBibles() + self.updateAutoCompleter() self.configUpdated() log.debug(u'bible manager initialise complete') @@ -338,7 +344,7 @@ class BibleMediaItem(MediaManagerItem): self.QuickMessage.setText(text) self.AdvancedMessage.setText(text) Receiver.send_message(u'openlp_process_events') - # minor delay to get the events processed + # Minor delay to get the events processed. time.sleep(0.1) def onListViewResize(self, width, height): @@ -358,13 +364,15 @@ class BibleMediaItem(MediaManagerItem): translate('BiblesPlugin.MediaItem', 'No Book Found'), translate('BiblesPlugin.MediaItem', 'No matching book could be found in this Bible.')) + self.AdvancedSearchButton.setEnabled(True) def onImportClick(self): if not hasattr(self, u'import_wizard'): self.import_wizard = BibleImportForm(self, self.parent.manager, self.parent) - self.import_wizard.exec_() - self.reloadBibles() + # If the import was not canceled then reload. + if self.import_wizard.exec_(): + self.reloadBibles() def loadBibles(self): log.debug(u'Loading Bibles') @@ -374,8 +382,10 @@ class BibleMediaItem(MediaManagerItem): self.AdvancedSecondBibleComboBox.clear() self.QuickSecondBibleComboBox.addItem(u'') self.AdvancedSecondBibleComboBox.addItem(u'') + # Get all bibles and sort the list. bibles = self.parent.manager.get_bibles().keys() - # load bibles into the combo boxes + bibles.sort() + # Load the bibles into the combo boxes. first = True for bible in bibles: if bible: @@ -393,6 +403,15 @@ class BibleMediaItem(MediaManagerItem): self.loadBibles() def initialiseBible(self, bible): + """ + This initialises the given bible, which means that its book names and + their chapter numbers is added to the combo boxes on the + 'Advanced Search' Tab. This is not of any importance of the + 'Quick Search' Tab. + + ``bible`` + The bible to initialise (unicode). + """ log.debug(u'initialiseBible %s', bible) book_data = self.parent.manager.get_books(bible) self.AdvancedBookComboBox.clear() @@ -423,6 +442,25 @@ class BibleMediaItem(MediaManagerItem): self.adjustComboBox(1, verse_count, self.AdvancedFromVerse) self.adjustComboBox(1, verse_count, self.AdvancedToVerse) + def updateAutoCompleter(self): + """ + This updates the bible book completion list for the search field. The + completion depends on the bible. It is only updated when we are doing a + verse search, otherwise the auto completion list is removed. + """ + books = [] + # We have to do a 'Verse Search'. + if self.QuickSearchComboBox.currentIndex() == 0: + bibles = self.parent.manager.get_bibles() + bible = unicode(self.QuickVersionComboBox.currentText()) + if bible: + book_data = bibles[bible].get_books() + books = [book.name for book in book_data] + books.sort() + completer = QtGui.QCompleter(books) + completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive) + self.QuickSearchEdit.setCompleter(completer) + def onAdvancedVersionComboBox(self): self.initialiseBible( unicode(self.AdvancedVersionComboBox.currentText())) @@ -482,6 +520,17 @@ class BibleMediaItem(MediaManagerItem): def adjustComboBox(self, range_from, range_to, combo, restore=False): """ + Adjusts the given como box to the given values. + + ``range_from`` + The first number of the range (int). + + ``range_to`` + The last number of the range (int). + + ``combo`` + The combo box itself (QComboBox). + ``restore`` If True, then the combo's currentText will be restored after adjusting (if possible). @@ -490,16 +539,19 @@ class BibleMediaItem(MediaManagerItem): if restore: old_text = unicode(combo.currentText()) combo.clear() - for i in range(int(range_from), int(range_to) + 1): + for i in range(range_from, range_to + 1): combo.addItem(unicode(i)) if restore and combo.findText(old_text) != -1: combo.setCurrentIndex(combo.findText(old_text)) def onAdvancedSearchButton(self): + """ + Does an advanced search and saves the search results. + """ log.debug(u'Advanced Search Button pressed') self.AdvancedSearchButton.setEnabled(False) bible = unicode(self.AdvancedVersionComboBox.currentText()) - dual_bible = unicode(self.AdvancedSecondBibleComboBox.currentText()) + second_bible = unicode(self.AdvancedSecondBibleComboBox.currentText()) book = unicode(self.AdvancedBookComboBox.currentText()) chapter_from = int(self.AdvancedFromChapter.currentText()) chapter_to = int(self.AdvancedToChapter.currentText()) @@ -508,74 +560,81 @@ class BibleMediaItem(MediaManagerItem): versetext = u'%s %s:%s-%s:%s' % (book, chapter_from, verse_from, chapter_to, verse_to) self.search_results = self.parent.manager.get_verses(bible, versetext) - if dual_bible: - self.dual_search_results = self.parent.manager.get_verses( - dual_bible, versetext) + if second_bible: + self.second_search_results = self.parent.manager.get_verses( + second_bible, versetext) if self.ClearAdvancedSearchComboBox.currentIndex() == 0: self.listView.clear() if self.listView.count() != 0: + # Check if the first item is a second bible item or not. bitem = self.listView.item(0) - item_dual_bible = self._decodeQtObject(bitem, 'dual_bible') - if item_dual_bible and dual_bible or not item_dual_bible and \ - not dual_bible: - self.displayResults(bible, dual_bible) + item_second_bible = self._decodeQtObject(bitem, 'second_bible') + if item_second_bible and second_bible or not item_second_bible and \ + not second_bible: + self.displayResults(bible, second_bible) elif QtGui.QMessageBox.critical(self, translate('BiblePlugin.MediaItem', 'Error'), translate('BiblePlugin.MediaItem', 'You cannot combine single ' - 'and dual bible verses. Do you want to delete your search ' + 'and second bible verses. Do you want to delete your search ' 'results and start a new search?'), QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.Yes: self.listView.clear() - self.displayResults(bible, dual_bible) + self.displayResults(bible, second_bible) else: - self.displayResults(bible, dual_bible) + self.displayResults(bible, second_bible) self.AdvancedSearchButton.setEnabled(True) def onQuickSearchButton(self): + """ + Does a quick search and saves the search results. Quick search can + either be "Verse Search" or "Text Search". + """ log.debug(u'Quick Search Button pressed') self.QuickSearchButton.setEnabled(False) bible = unicode(self.QuickVersionComboBox.currentText()) - dual_bible = unicode(self.QuickSecondBibleComboBox.currentText()) + second_bible = unicode(self.QuickSecondBibleComboBox.currentText()) text = unicode(self.QuickSearchEdit.text()) if self.QuickSearchComboBox.currentIndex() == 0: # We are doing a 'Verse Search'. self.search_results = self.parent.manager.get_verses(bible, text) - if dual_bible and self.search_results: - self.dual_search_results = self.parent.manager.get_verses( - dual_bible, text) + if second_bible and self.search_results: + self.second_search_results = self.parent.manager.get_verses( + second_bible, text) else: - # We are doing a ' Text Search'. + # We are doing a 'Text Search'. bibles = self.parent.manager.get_bibles() - self.search_results = self.parent.manager.verse_search(bible, text) - if dual_bible and self.search_results: + self.search_results = self.parent.manager.verse_search(bible, + second_bible, text) + if second_bible and self.search_results: text = [] for verse in self.search_results: text.append((verse.book.name, verse.chapter, verse.verse, verse.verse)) - self.dual_search_results = bibles[dual_bible].get_verses(text) + self.second_search_results = \ + bibles[second_bible].get_verses(text) if self.ClearQuickSearchComboBox.currentIndex() == 0: self.listView.clear() if self.listView.count() != 0 and self.search_results: bitem = self.listView.item(0) - item_dual_bible = self._decodeQtObject(bitem, 'dual_bible') - if item_dual_bible and dual_bible or not item_dual_bible and \ - not dual_bible: - self.displayResults(bible, dual_bible) + item_second_bible = self._decodeQtObject(bitem, 'second_bible') + if item_second_bible and second_bible or not item_second_bible and \ + not second_bible: + self.displayResults(bible, second_bible) elif QtGui.QMessageBox.critical(self, translate('BiblePlugin.MediaItem', 'Error'), translate('BiblePlugin.MediaItem', 'You cannot combine single ' - 'and dual bible verses. Do you want to delete your search ' + 'and second bible verses. Do you want to delete your search ' 'results and start a new search?'), QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.Yes: self.listView.clear() - self.displayResults(bible, dual_bible) + self.displayResults(bible, second_bible) elif self.search_results: - self.displayResults(bible, dual_bible) + self.displayResults(bible, second_bible) self.QuickSearchButton.setEnabled(True) - def displayResults(self, bible, dual_bible=u''): + def displayResults(self, bible, second_bible=u''): """ Displays the search results in the media manager. All data needed for further action is saved for/in each row. @@ -583,38 +642,41 @@ class BibleMediaItem(MediaManagerItem): version = self.parent.manager.get_meta_data(bible, u'Version') copyright = self.parent.manager.get_meta_data(bible, u'Copyright') permissions = self.parent.manager.get_meta_data(bible, u'Permissions') - if dual_bible: - dual_version = self.parent.manager.get_meta_data(dual_bible, + if second_bible: + second_version = self.parent.manager.get_meta_data(second_bible, u'Version') - dual_copyright = self.parent.manager.get_meta_data(dual_bible, + second_copyright = self.parent.manager.get_meta_data(second_bible, u'Copyright') - dual_permissions = self.parent.manager.get_meta_data(dual_bible, + second_permissions = self.parent.manager.get_meta_data(second_bible, u'Permissions') - if not dual_permissions: - dual_permissions = u'' - # We count the number of rows which are maybe already present. - start_count = self.listView.count() + if not second_permissions: + second_permissions = u'' for count, verse in enumerate(self.search_results): - if dual_bible: - vdict = { - 'book': QtCore.QVariant(verse.book.name), - 'chapter': QtCore.QVariant(verse.chapter), - 'verse': QtCore.QVariant(verse.verse), - 'bible': QtCore.QVariant(bible), - 'version': QtCore.QVariant(version.value), - 'copyright': QtCore.QVariant(copyright.value), - 'permissions': QtCore.QVariant(permissions.value), - 'text': QtCore.QVariant(verse.text), - 'dual_bible': QtCore.QVariant(dual_bible), - 'dual_version': QtCore.QVariant(dual_version.value), - 'dual_copyright': QtCore.QVariant(dual_copyright.value), - 'dual_permissions': QtCore.QVariant(dual_permissions.value), - 'dual_text': QtCore.QVariant( - self.dual_search_results[count].text) - } + if second_bible: + try: + vdict = { + 'book': QtCore.QVariant(verse.book.name), + 'chapter': QtCore.QVariant(verse.chapter), + 'verse': QtCore.QVariant(verse.verse), + 'bible': QtCore.QVariant(bible), + 'version': QtCore.QVariant(version.value), + 'copyright': QtCore.QVariant(copyright.value), + 'permissions': QtCore.QVariant(permissions.value), + 'text': QtCore.QVariant(verse.text), + 'second_bible': QtCore.QVariant(second_bible), + 'second_version': QtCore.QVariant(second_version.value), + 'second_copyright': QtCore.QVariant( + second_copyright.value), + 'second_permissions': QtCore.QVariant( + second_permissions.value), + 'second_text': QtCore.QVariant( + self.second_search_results[count].text) + } + except IndexError: + break bible_text = u' %s %d:%d (%s, %s)' % (verse.book.name, verse.chapter, verse.verse, version.value, - dual_version.value) + second_version.value) else: vdict = { 'book': QtCore.QVariant(verse.book.name), @@ -625,22 +687,20 @@ class BibleMediaItem(MediaManagerItem): 'copyright': QtCore.QVariant(copyright.value), 'permissions': QtCore.QVariant(permissions.value), 'text': QtCore.QVariant(verse.text), - 'dual_bible': QtCore.QVariant(u''), - 'dual_version': QtCore.QVariant(u''), - 'dual_copyright': QtCore.QVariant(u''), - 'dual_permissions': QtCore.QVariant(u''), - 'dual_text': QtCore.QVariant(u'') + 'second_bible': QtCore.QVariant(u''), + 'second_version': QtCore.QVariant(u''), + 'second_copyright': QtCore.QVariant(u''), + 'second_permissions': QtCore.QVariant(u''), + 'second_text': QtCore.QVariant(u'') } - bible_text = u' %s %d:%d (%s)' % (verse.book.name, + bible_text = u'%s %d:%d (%s)' % (verse.book.name, verse.chapter, verse.verse, version.value) bible_verse = QtGui.QListWidgetItem(bible_text) bible_verse.setData(QtCore.Qt.UserRole, QtCore.QVariant(vdict)) self.listView.addItem(bible_verse) - row = self.listView.setCurrentRow(count + start_count) - if row: - row.setSelected(True) + self.listView.selectAll() self.search_results = {} - self.dual_search_results = {} + self.second_search_results = {} def _decodeQtObject(self, bitem, key): reference = bitem.data(QtCore.Qt.UserRole) @@ -651,7 +711,7 @@ class BibleMediaItem(MediaManagerItem): obj = obj.toPyObject() return unicode(obj) - def generateSlideData(self, service_item, item=None): + def generateSlideData(self, service_item, item=None, xmlVersion=False): """ Generates and formats the slides for the service item as well as the service item's title. @@ -661,7 +721,7 @@ class BibleMediaItem(MediaManagerItem): if len(items) == 0: return False bible_text = u'' - old_chapter = u'' + old_chapter = -1 raw_footer = [] raw_slides = [] raw_title = [] @@ -676,22 +736,22 @@ class BibleMediaItem(MediaManagerItem): copyright = self._decodeQtObject(bitem, 'copyright') permissions = self._decodeQtObject(bitem, 'permissions') text = self._decodeQtObject(bitem, 'text') - dual_bible = self._decodeQtObject(bitem, 'dual_bible') - dual_version = self._decodeQtObject(bitem, 'dual_version') - dual_copyright = self._decodeQtObject(bitem, 'dual_copyright') - dual_permissions = self._decodeQtObject(bitem, 'dual_permissions') - dual_text = self._decodeQtObject(bitem, 'dual_text') + second_bible = self._decodeQtObject(bitem, 'second_bible') + second_version = self._decodeQtObject(bitem, 'second_version') + second_copyright = self._decodeQtObject(bitem, 'second_copyright') + second_permissions = self._decodeQtObject(bitem, 'second_permissions') + second_text = self._decodeQtObject(bitem, 'second_text') verse_text = self.formatVerse(old_chapter, chapter, verse) footer = u'%s (%s %s %s)' % (book, version, copyright, permissions) if footer not in raw_footer: raw_footer.append(footer) - if dual_bible: - footer = u'%s (%s %s %s)' % (book, dual_version, dual_copyright, - dual_permissions) + if second_bible: + footer = u'%s (%s %s %s)' % (book, second_version, + second_copyright, second_permissions) if footer not in raw_footer: raw_footer.append(footer) bible_text = u'%s %s\n\n%s %s' % (verse_text, text, verse_text, - dual_text) + second_text) raw_slides.append(bible_text) bible_text = u'' # If we are 'Verse Per Slide' then create a new slide. @@ -719,7 +779,7 @@ class BibleMediaItem(MediaManagerItem): raw_slides.append(bible_text) bible_text = u'' # Service Item: Capabilities - if self.parent.settings_tab.layout_style == 2 and not dual_bible: + if self.parent.settings_tab.layout_style == 2 and not second_bible: # Split the line but do not replace line breaks in renderer. service_item.add_capability(ItemCapabilities.NoLineBreaks) service_item.add_capability(ItemCapabilities.AllowsPreview) @@ -749,6 +809,12 @@ class BibleMediaItem(MediaManagerItem): This methode is called, when we have to change the title, because we are at the end of a verse range. E. g. if we want to add Genesis 1:1-6 as well as Daniel 2:14. + + ``start_item`` + The first item of a range. + + ``old_item`` + The last item of a range. """ old_bitem = self.listView.item(old_item.row()) old_chapter = int(self._decodeQtObject(old_bitem, 'chapter')) @@ -758,18 +824,18 @@ class BibleMediaItem(MediaManagerItem): start_chapter = int(self._decodeQtObject(start_bitem, 'chapter')) start_verse = int(self._decodeQtObject(start_bitem, 'verse')) start_bible = self._decodeQtObject(start_bitem, 'bible') - start_dual_bible = self._decodeQtObject(start_bitem, 'dual_bible') - if start_dual_bible: + start_second_bible = self._decodeQtObject(start_bitem, 'second_bible') + if start_second_bible: if start_verse == old_verse and start_chapter == old_chapter: title = u'%s %s:%s (%s, %s)' % (start_book, start_chapter, - start_verse, start_bible, start_dual_bible) + start_verse, start_bible, start_second_bible) elif start_chapter == old_chapter: title = u'%s %s:%s-%s (%s, %s)' % (start_book, start_chapter, - start_verse, old_verse, start_bible, start_dual_bible) + start_verse, old_verse, start_bible, start_second_bible) else: title = u'%s %s:%s-%s:%s (%s, %s)' % (start_book, start_chapter, start_verse, old_chapter, old_verse, start_bible, - start_dual_bible) + start_second_bible) else: if start_verse == old_verse and start_chapter == old_chapter: title = u'%s %s:%s (%s)' % (start_book, start_chapter, @@ -785,34 +851,62 @@ class BibleMediaItem(MediaManagerItem): def checkTitle(self, item, old_item): """ This methode checks if we are at the end of an verse range. If that is - the case, we return True, else False. E. g. if we added Genesis 1:1-6, - but the next verse is Daniel 2:14. + the case, we return True, otherwise False. E. g. if we added + Genesis 1:1-6, but the next verse is Daniel 2:14, we return True. + + ``item`` + The item we are dealing with at the moment. + + ``old_item`` + The item we were previously dealing with. """ + # Get all the necessary meta data. bitem = self.listView.item(item.row()) book = self._decodeQtObject(bitem, 'book') chapter = int(self._decodeQtObject(bitem, 'chapter')) verse = int(self._decodeQtObject(bitem, 'verse')) bible = self._decodeQtObject(bitem, 'bible') - dual_bible = self._decodeQtObject(bitem, 'dual_bible') + second_bible = self._decodeQtObject(bitem, 'second_bible') old_bitem = self.listView.item(old_item.row()) old_book = self._decodeQtObject(old_bitem, 'book') old_chapter = int(self._decodeQtObject(old_bitem, 'chapter')) old_verse = int(self._decodeQtObject(old_bitem, 'verse')) old_bible = self._decodeQtObject(old_bitem, 'bible') - old_dual_bible = self._decodeQtObject(old_bitem, 'dual_bible') - if old_bible != bible or old_dual_bible != dual_bible or \ + old_second_bible = self._decodeQtObject(old_bitem, 'second_bible') + if old_bible != bible or old_second_bible != second_bible or \ old_book != book: + # The bible, second bible or book has changed. return True elif old_verse + 1 != verse and old_chapter == chapter: + # We are still in the same chapter, but a verse has been skipped. return True elif old_chapter + 1 == chapter and (verse != 1 or old_verse != self.parent.manager.get_verse_count( old_bible, old_book, old_chapter)): + # We are in the following chapter, but the last verse was not the + # last verse of the chapter or the current verse is not the + # first one of the chapter. return True else: return False def formatVerse(self, old_chapter, chapter, verse): + """ + Formats and returns the text, each verse starts with, for the given + chapter and verse. The text is either surrounded by round, square, + curly brackets or no brackets at all. For example:: + + u'{su}1:1{/su}' + + ``old_chapter`` + The previous verse's chapter number (int). + + ``chapter`` + The chapter number (int). + + ``verse`` + The verse number (int). + """ if not self.parent.settings_tab.show_new_chapters or \ old_chapter != chapter: verse_text = u'%s:%s' % (chapter, verse) diff --git a/openlp/plugins/custom/forms/editcustomform.py b/openlp/plugins/custom/forms/editcustomform.py index 65a73337a..c5281574b 100644 --- a/openlp/plugins/custom/forms/editcustomform.py +++ b/openlp/plugins/custom/forms/editcustomform.py @@ -46,7 +46,6 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog): Constructor """ QtGui.QDialog.__init__(self, parent) - #self.parent = parent self.setupUi(self) # Connecting signals and slots self.previewButton = QtGui.QPushButton() @@ -124,8 +123,9 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog): self.slideListView.addItem(slide[1]) theme = self.customSlide.theme_name id = self.themeComboBox.findText(theme, QtCore.Qt.MatchExactly) + # No theme match if id == -1: - id = 0 # Not Found + id = 0 self.themeComboBox.setCurrentIndex(id) else: self.themeComboBox.setCurrentIndex(0) @@ -264,7 +264,7 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog): self.titleEdit.setFocus() return False, translate('CustomPlugin.EditCustomForm', 'You need to type in a title.') - # We must have one slide. + # We must have at least one slide. if self.slideListView.count() == 0: return False, translate('CustomPlugin.EditCustomForm', 'You need to add at least one slide') diff --git a/openlp/plugins/custom/forms/editcustomslideform.py b/openlp/plugins/custom/forms/editcustomslideform.py index 5f535c8bc..72c7dbb4a 100644 --- a/openlp/plugins/custom/forms/editcustomslideform.py +++ b/openlp/plugins/custom/forms/editcustomslideform.py @@ -50,7 +50,7 @@ class EditCustomSlideForm(QtGui.QDialog, Ui_CustomSlideEditDialog): def setText(self, text): """ Set the text for slideTextEdit. - + ``text`` The text (unicode). """ @@ -67,7 +67,7 @@ class EditCustomSlideForm(QtGui.QDialog, Ui_CustomSlideEditDialog): def onSplitButtonPressed(self): """ - Splits a slide in two slides. + Adds a slide split at the cursor. """ if self.slideTextEdit.textCursor().columnNumber() != 0: self.slideTextEdit.insertPlainText(u'\n') diff --git a/openlp/plugins/custom/lib/customxmlhandler.py b/openlp/plugins/custom/lib/customxmlhandler.py index b554f9657..907c3470d 100644 --- a/openlp/plugins/custom/lib/customxmlhandler.py +++ b/openlp/plugins/custom/lib/customxmlhandler.py @@ -43,6 +43,7 @@ import logging from xml.dom.minidom import Document from xml.etree.ElementTree import ElementTree, XML, dump +from lxml import etree, objectify from xml.parsers.expat import ExpatError log = logging.getLogger(__name__) @@ -55,14 +56,14 @@ class CustomXMLBuilder(object): def __init__(self): """ - Set up the song builder. + Set up the custom builder. """ # Create the minidom document self.custom_xml = Document() def new_document(self): """ - Create a new song XML document. + Create a new custom XML document. """ # Create the base element self.song = self.custom_xml.createElement(u'song') @@ -72,7 +73,7 @@ class CustomXMLBuilder(object): def add_lyrics_to_song(self): """ Set up and add a ```` tag which contains the lyrics of the - song. + custom item. """ # Create the main element self.lyrics = self.custom_xml.createElement(u'lyrics') @@ -93,7 +94,6 @@ class CustomXMLBuilder(object): ``content`` The actual text of the verse to be stored. """ - #log.debug(u'add_verse_to_lyrics %s, %s\n%s' % (type, number, content)) verse = self.custom_xml.createElement(u'verse') verse.setAttribute(u'type', type) verse.setAttribute(u'label', number) @@ -102,7 +102,7 @@ class CustomXMLBuilder(object): cds = self.custom_xml.createCDATASection(content) verse.appendChild(cds) - def dump_xml(self): + def _dump_xml(self): """ Debugging aid to dump XML so that we can see what we have. """ @@ -110,29 +110,30 @@ class CustomXMLBuilder(object): def extract_xml(self): """ - Extract our newly created XML song. + Extract our newly created XML custom. """ return self.custom_xml.toxml(u'utf-8') class CustomXMLParser(object): """ - A class to read in and parse a song's XML. + A class to read in and parse a custom's XML. """ log.info(u'CustomXMLParser Loaded') def __init__(self, xml): """ - Set up our song XML parser. + Set up our custom XML parser. ``xml`` - The XML of the song to be parsed. + The XML of the custom to be parsed. """ self.custom_xml = None + if xml[:5] == u' 1: self.DisplayTypeComboBox.insertItem(0, self.Automatic) self.DisplayTypeComboBox.setCurrentIndex(0) - if QtCore.QSettings().value(self.settingsSection + u'/override app', + if QtCore.QSettings().value(self.settingsSection + u'/override app', QtCore.QVariant(QtCore.Qt.Unchecked)) == QtCore.Qt.Checked: self.PresentationWidget.show() else: @@ -238,7 +238,7 @@ class PresentationMediaItem(MediaManagerItem): SettingsManager.set_list(self.settingsSection, self.settingsSection, self.getFileList()) - def generateSlideData(self, service_item, item=None): + def generateSlideData(self, service_item, item=None, xmlVersion=False): """ Load the relevant information for displaying the presentation in the slidecontroller. In the case of powerpoints, an image @@ -277,7 +277,7 @@ class PresentationMediaItem(MediaManagerItem): def findControllerByType(self, filename): """ Determine the default application controller to use for the selected - file type. This is used if "Automatic" is set as the preferred + file type. This is used if "Automatic" is set as the preferred controller. Find the first (alphabetic) enabled controller which "supports" the extension. If none found, then look for a controller which "alsosupports" it instead. diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index d81f1a27a..e421e63a0 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -650,8 +650,11 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): self.song.title = unicode(self.TitleEditItem.text()) self.song.alternate_title = unicode(self.AlternativeEdit.text()) self.song.copyright = unicode(self.CopyrightEditItem.text()) - self.song.search_title = self.song.title + u'@' + \ - self.song.alternate_title + if self.song.alternate_title: + self.song.search_title = self.song.title + u'@' + \ + self.song.alternate_title + else: + self.song.search_title = self.song.title self.song.comments = unicode(self.CommentsEdit.toPlainText()) self.song.verse_order = unicode(self.VerseOrderEdit.text()) self.song.ccli_number = unicode(self.CCLNumberEdit.text()) @@ -662,6 +665,11 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): Book.name == book_name) else: self.song.book = None + theme_name = unicode(self.ThemeSelectionComboItem.currentText()) + if theme_name: + self.song.theme_name = theme_name + else: + self.song.theme_name = None if self._validate_song(): self.processLyrics() self.processTitle() diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py index 014c66a51..67ef4d8c1 100644 --- a/openlp/plugins/songs/forms/songimportform.py +++ b/openlp/plugins/songs/forms/songimportform.py @@ -507,8 +507,7 @@ class SongImportForm(QtGui.QWizard, Ui_SongImportWizard): filenames=self.getListOfFiles( self.songBeamerFileListWidget) ) - success = importer.do_import() - if success: + if importer.do_import(): # reload songs self.importProgressLabel.setText( translate('SongsPlugin.SongImportForm', 'Finished import.')) diff --git a/openlp/plugins/songs/forms/songmaintenanceform.py b/openlp/plugins/songs/forms/songmaintenanceform.py index 7c13e0989..e057bb516 100644 --- a/openlp/plugins/songs/forms/songmaintenanceform.py +++ b/openlp/plugins/songs/forms/songmaintenanceform.py @@ -405,7 +405,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog): def mergeAuthors(self, old_author): """ Merges two authors into one author. - + ``old_author`` The author which will be deleted afterwards. """ @@ -427,7 +427,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog): def mergeTopics(self, old_topic): """ Merges two topics into one topic. - + ``old_topic`` The topic which will be deleted afterwards. """ @@ -447,7 +447,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog): def mergeBooks(self, old_book): """ Merges two books into one book. - + ``old_book`` The book which will be deleted afterwards. """ diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 351d50071..795116b4e 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -62,6 +62,36 @@ class VerseType(object): elif verse_type == VerseType.Other: return translate('SongsPlugin.VerseType', 'Other') + @staticmethod + def expand_string(verse_type): + """ + Return the VerseType for a given string + + ``verse_type`` + The string to return a VerseType for + """ + verse_type = verse_type.lower() + if verse_type == unicode(VerseType.to_string(VerseType.Verse)).lower()[0]: + return translate('SongsPlugin.VerseType', 'Verse') + elif verse_type == \ + unicode(VerseType.to_string(VerseType.Chorus)).lower()[0]: + return translate('SongsPlugin.VerseType', 'Chorus') + elif verse_type == \ + unicode(VerseType.to_string(VerseType.Bridge)).lower()[0]: + return translate('SongsPlugin.VerseType', 'Bridge') + elif verse_type == \ + unicode(VerseType.to_string(VerseType.PreChorus)).lower()[0]: + return translate('SongsPlugin.VerseType', 'PreChorus') + elif verse_type == \ + unicode(VerseType.to_string(VerseType.Intro)).lower()[0]: + return translate('SongsPlugin.VerseType', 'Intro') + elif verse_type == \ + unicode(VerseType.to_string(VerseType.Ending)).lower()[0]: + return translate('SongsPlugin.VerseType', 'Ending') + elif verse_type == \ + unicode(VerseType.to_string(VerseType.Other)).lower()[0]: + return translate('SongsPlugin.VerseType', 'Other') + @staticmethod def from_string(verse_type): """ @@ -92,7 +122,6 @@ class VerseType(object): unicode(VerseType.to_string(VerseType.Other)).lower(): return VerseType.Other - -from xml import LyricsXML, SongXMLBuilder, SongXMLParser +from xml import LyricsXML, SongXMLBuilder, SongXMLParser, OpenLyricsParser from songstab import SongsTab from mediaitem import SongMediaItem diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index cb2d6a6e0..432eee744 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -32,7 +32,7 @@ from openlp.core.lib import MediaManagerItem, BaseListWithDnD, Receiver, \ ItemCapabilities, translate, check_item_selected from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \ SongImportForm -from openlp.plugins.songs.lib import SongXMLParser +from openlp.plugins.songs.lib import SongXMLParser, OpenLyricsParser from openlp.plugins.songs.lib.db import Author, Song log = logging.getLogger(__name__) @@ -53,8 +53,8 @@ class SongMediaItem(MediaManagerItem): self.ListViewWithDnD_class = SongListView MediaManagerItem.__init__(self, parent, self, icon) self.edit_song_form = EditSongForm(self, self.parent.manager) + self.openLyrics = OpenLyricsParser(self.parent.manager) self.singleServiceItem = False - #self.edit_song_form = EditSongForm(self.parent.manager, self) self.song_maintenance_form = SongMaintenanceForm( self.parent.manager, self) # Holds information about whether the edit is remotly triggered and @@ -114,6 +114,8 @@ class SongMediaItem(MediaManagerItem): self.SearchButtonLayout.addWidget(self.ClearTextButton) self.pageLayout.addLayout(self.SearchButtonLayout) # Signals and slots + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'plugin_list_refresh'), self.onSearchTextButtonClick) QtCore.QObject.connect(self.SearchTextEdit, QtCore.SIGNAL(u'returnPressed()'), self.onSearchTextButtonClick) QtCore.QObject.connect(self.SearchTextButton, @@ -141,7 +143,7 @@ class SongMediaItem(MediaManagerItem): self.updateServiceOnEdit = QtCore.QSettings().value( self.settingsSection + u'/update service on edit', QtCore.QVariant(u'False')).toBool() - self.AddSongFromServide = QtCore.QSettings().value( + self.addSongFromService = QtCore.QSettings().value( self.settingsSection + u'/add song from service', QtCore.QVariant(u'True')).toBool() @@ -328,7 +330,7 @@ class SongMediaItem(MediaManagerItem): self.parent.manager.delete_object(Song, item_id) self.onSearchTextButtonClick() - def generateSlideData(self, service_item, item=None): + def generateSlideData(self, service_item, item=None, xmlVersion=False): log.debug(u'generateSlideData (%s:%s)' % (service_item, item)) raw_footer = [] author_list = u'' @@ -355,7 +357,7 @@ class SongMediaItem(MediaManagerItem): if song.lyrics.startswith(u' 0: - self.add_verse(self.current_verse, + # Just make sure that the line is of the type 'Unicode'. + line = unicode(line).strip() + if line.startswith(u'#') and not read_verses: + self.parse_tags(line) + elif line.startswith(u'---'): + if self.current_verse: + self.replace_html_tags() + self.add_verse(self.current_verse, self.current_verse_type) self.current_verse = u'' self.current_verse_type = u'V' - self.read_verse = True - self.verse_start = True - elif self.read_verse: - if self.verse_start: - self.check_verse_marks(line) - self.verse_start = False + read_verses = True + verse_start = True + elif read_verses: + if verse_start: + verse_start = False + if not self.check_verse_marks(line): + self.current_verse = u'%s\n' % line else: self.current_verse += u'%s\n' % line - if len(self.current_verse) > 0: + if self.current_verse: + self.replace_html_tags() self.add_verse(self.current_verse, self.current_verse_type) self.finish() self.import_wizard.incrementProgressBar( "Importing %s" % (self.file_name)) return True + def replace_html_tags(self): + """ + This can be called to replace SongBeamer's specific (html) tags with + OpenLP's specific (html) tags. + """ + tag_pairs = [ + (u'', u'{st}'), + (u'', u'{/st}'), + (u'', u'{it}'), + (u'', u'{/it}'), + (u'', u'{u}'), + (u'', u'{/u}'), + (u'
', u'{st}'), + (u'
', u'{st}'), + (u'', u'{st}'), + (u'

', u'{p}'), + (u'

', u'{/p}'), + (u'', u'{su}'), + (u'', u'{/su}'), + (u'', u'{sb}'), + (u'', u'{/sb}'), + (u'', u''), + (u'', u''), + (u'', u''), + (u'', u'') + ] + for pair in tag_pairs: + self.current_verse = self.current_verse.replace(pair[0], pair[1]) + # TODO: check for unsupported tags (see wiki) and remove them as well. + def parse_tags(self, line): - tag_val = line.split('=') - if len(tag_val[0]) == 0 or len(tag_val[1]) == 0: - return True - if tag_val[0] == '#(c)': + """ + Parses a meta data line. + + ``line`` + The line in the file. It should consist of a tag and a value + for this tag (unicode):: + + u'#Title=Nearer my God to Thee' + """ + tag_val = line.split(u'=', 1) + if len(tag_val) == 1: + return + if not tag_val[0] or not tag_val[1]: + return + if tag_val[0] == u'#(c)': self.add_copyright(tag_val[1]) - elif tag_val[0] == '#AddCopyrightInfo': + elif tag_val[0] == u'#AddCopyrightInfo': pass - elif tag_val[0] == '#Author': - #TODO split Authors - self.add_author(tag_val[1]) - elif tag_val[0] == '#BackgroundImage': + elif tag_val[0] == u'#Author': + self.parse_author(tag_val[1]) + elif tag_val[0] == u'#BackgroundImage': pass - elif tag_val[0] == '#Bible': + elif tag_val[0] == u'#Bible': pass - elif tag_val[0] == '#Categories': + elif tag_val[0] == u'#Categories': self.topics = line.split(',') - elif tag_val[0] == '#CCLI': + elif tag_val[0] == u'#CCLI': self.ccli_number = tag_val[1] - elif tag_val[0] == '#Chords': + elif tag_val[0] == u'#Chords': pass - elif tag_val[0] == '#ChurchSongID': + elif tag_val[0] == u'#ChurchSongID': pass - elif tag_val[0] == '#ColorChords': + elif tag_val[0] == u'#ColorChords': pass - elif tag_val[0] == '#Comments': + elif tag_val[0] == u'#Comments': self.comments = tag_val[1] - elif tag_val[0] == '#Editor': + elif tag_val[0] == u'#Editor': pass - elif tag_val[0] == '#Font': + elif tag_val[0] == u'#Font': pass - elif tag_val[0] == '#FontLang2': + elif tag_val[0] == u'#FontLang2': pass - elif tag_val[0] == '#FontSize': + elif tag_val[0] == u'#FontSize': pass - elif tag_val[0] == '#Format': + elif tag_val[0] == u'#Format': pass - elif tag_val[0] == '#Format_PreLine': + elif tag_val[0] == u'#Format_PreLine': pass - elif tag_val[0] == '#Format_PrePage': + elif tag_val[0] == u'#Format_PrePage': pass - elif tag_val[0] == '#ID': + elif tag_val[0] == u'#ID': pass - elif tag_val[0] == '#Key': + elif tag_val[0] == u'#Key': pass - elif tag_val[0] == '#Keywords': + elif tag_val[0] == u'#Keywords': pass - elif tag_val[0] == '#LangCount': + elif tag_val[0] == u'#LangCount': pass - elif tag_val[0] == '#Melody': - #TODO split Authors - self.add_author(tag_val[1]) - elif tag_val[0] == '#NatCopyright': + elif tag_val[0] == u'#Melody': + self.parse_author(tag_val[1]) + elif tag_val[0] == u'#NatCopyright': pass - elif tag_val[0] == '#OTitle': + elif tag_val[0] == u'#OTitle': pass - elif tag_val[0] == '#OutlineColor': + elif tag_val[0] == u'#OutlineColor': pass - elif tag_val[0] == '#OutlinedFont': + elif tag_val[0] == u'#OutlinedFont': pass - elif tag_val[0] == '#QuickFind': + elif tag_val[0] == u'#QuickFind': pass - elif tag_val[0] == '#Rights': + elif tag_val[0] == u'#Rights': song_book_pub = tag_val[1] - elif tag_val[0] == '#Songbook': + elif tag_val[0] == u'#Songbook': book_num = tag_val[1].split(' / ') self.song_book_name = book_num[0] if len(book_num) == book_num[1]: self.song_number = u'' - elif tag_val[0] == '#Speed': + elif tag_val[0] == u'#Speed': pass - elif tag_val[0] == '#TextAlign': + elif tag_val[0] == u'#TextAlign': pass - elif tag_val[0] == '#Title': + elif tag_val[0] == u'#Title': self.title = u'%s' % tag_val[1] - elif tag_val[0] == '#TitleAlign': + elif tag_val[0] == u'#TitleAlign': pass - elif tag_val[0] == '#TitleFontSize': + elif tag_val[0] == u'#TitleFontSize': pass - elif tag_val[0] == '#TitleLang2': + elif tag_val[0] == u'#TitleLang2': pass - elif tag_val[0] == '#TitleLang3': + elif tag_val[0] == u'#TitleLang3': pass - elif tag_val[0] == '#TitleLang4': + elif tag_val[0] == u'#TitleLang4': pass - elif tag_val[0] == '#Translation': + elif tag_val[0] == u'#Translation': pass - elif tag_val[0] == '#Transpose': + elif tag_val[0] == u'#Transpose': pass - elif tag_val[0] == '#TransposeAccidental': + elif tag_val[0] == u'#TransposeAccidental': pass - elif tag_val[0] == '#Version': + elif tag_val[0] == u'#Version': pass - else: - pass - return True def check_verse_marks(self, line): - marks = line.split(' ') + """ + Check and add the verse's MarkType. Returns ``True`` if the given line + contains a correct verse mark otherwise ``False``. + + ``line`` + The line to check for marks (unicode). + """ + marks = line.split(u' ') if len(marks) <= 2 and marks[0] in SongBeamerTypes.MarkTypes: self.current_verse_type = SongBeamerTypes.MarkTypes[marks[0]] if len(marks) == 2: - #TODO: may check, because of only digits are allowed - self.current_verse_type += marks[1] + # If we have a digit, we append it to current_verse_type. + if marks[1].isdigit(): + self.current_verse_type += marks[1] + return True + else: + return False diff --git a/openlp/plugins/songs/lib/songimport.py b/openlp/plugins/songs/lib/songimport.py index 2c1de83a2..ea36d55b5 100644 --- a/openlp/plugins/songs/lib/songimport.py +++ b/openlp/plugins/songs/lib/songimport.py @@ -254,7 +254,8 @@ class SongImport(QtCore.QObject): All fields have been set to this song. Write it away """ if not self.authors: - self.authors.append(u'Author unknown') + self.authors.append(unicode(translate('SongsPlugin.SongImport', + 'Author unknown'))) self.commit_song() def commit_song(self): diff --git a/openlp/plugins/songs/lib/xml.py b/openlp/plugins/songs/lib/xml.py index ff39a0efa..655ea1e3c 100644 --- a/openlp/plugins/songs/lib/xml.py +++ b/openlp/plugins/songs/lib/xml.py @@ -39,8 +39,11 @@ The basic XML is of the format:: """ import logging +import re from lxml import etree, objectify +from openlp.plugins.songs.lib import VerseType +from openlp.plugins.songs.lib.db import Author, Song log = logging.getLogger(__name__) @@ -77,7 +80,6 @@ class SongXMLBuilder(object): ``content`` The actual text of the verse to be stored. """ - # log.debug(u'add_verse_to_lyrics %s, %s\n%s' % (type, number, content)) verse = etree.Element(u'verse', type = unicode(type), label = unicode(number)) verse.text = etree.CDATA(content) @@ -239,3 +241,153 @@ class LyricsXML(object): song_output = u'' + \ u'%s' % lyrics_output return song_output + + +class OpenLyricsParser(object): + """ + This class represents the converter for Song to/from OpenLyrics XML. + """ + def __init__(self, manager): + self.manager = manager + + def song_to_xml(self, song): + """ + Convert the song to OpenLyrics Format + """ + song_xml_parser = SongXMLParser(song.lyrics) + verse_list = song_xml_parser.get_verses() + song_xml = objectify.fromstring( + u'') + properties = etree.SubElement(song_xml, u'properties') + titles = etree.SubElement(properties, u'titles') + self._add_text_to_element(u'title', titles, song.title) + if song.alternate_title: + self._add_text_to_element(u'title', titles, song.alternate_title) + if song.theme_name: + themes = etree.SubElement(properties, u'themes') + self._add_text_to_element(u'theme', themes, song.theme_name) + self._add_text_to_element(u'copyright', properties, song.copyright) + self._add_text_to_element(u'verseOrder', properties, song.verse_order) + if song.ccli_number: + self._add_text_to_element(u'ccliNo', properties, song.ccli_number) + authors = etree.SubElement(properties, u'authors') + for author in song.authors: + self._add_text_to_element(u'author', authors, author.display_name) + lyrics = etree.SubElement(song_xml, u'lyrics') + for verse in verse_list: + verse_tag = u'%s%s' % ( + verse[0][u'type'][0].lower(), verse[0][u'label']) + element = \ + self._add_text_to_element(u'verse', lyrics, None, verse_tag) + element = self._add_text_to_element(u'lines', element) + for line in unicode(verse[1]).split(u'\n'): + self._add_text_to_element(u'line', element, line) + return self._extract_xml(song_xml) + + def xml_to_song(self, xml): + """ + Create a Song from OpenLyrics format xml + """ + # No xml get out of here + if not xml: + return 0 + song = Song() + if xml[:5] == u'