diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index e104f4022..a687ded64 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -80,6 +80,9 @@ def get_text_file_string(text_file): content_string = None try: file_handle = open(text_file, u'r') + if not file_handle.read(3) == '\xEF\xBB\xBF': + # no BOM was found + file_handle.seek(0) content = file_handle.read() content_string = content.decode(u'utf-8') except (IOError, UnicodeError): @@ -191,10 +194,10 @@ def validate_thumb(file_path, thumb_path): ``thumb_path`` The path to the thumb. """ - if not os.path.exists(unicode(thumb_path)): + if not os.path.exists(thumb_path): return False - image_date = os.stat(unicode(file_path)).st_mtime - thumb_date = os.stat(unicode(thumb_path)).st_mtime + image_date = os.stat(file_path).st_mtime + thumb_date = os.stat(thumb_path).st_mtime return image_date <= thumb_date def resize_image(image_path, width, height, background=u'#000000'): diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index 86e0a0a30..b6f12d180 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -358,10 +358,17 @@ class Manager(object): def delete_all_objects(self, object_class, filter_clause=None): """ - Delete all object records + Delete all object records. + This method should only be used for simple tables and not ones with + relationships. The relationships are not deleted from the database and + this will lead to database corruptions. ``object_class`` The type of object to delete + + ``filter_clause`` + The filter governing selection of objects to return. Defaults to + None. """ try: query = self.session.query(object_class) diff --git a/openlp/core/lib/eventreceiver.py b/openlp/core/lib/eventreceiver.py index 14b6126bc..40cac8e35 100644 --- a/openlp/core/lib/eventreceiver.py +++ b/openlp/core/lib/eventreceiver.py @@ -115,8 +115,12 @@ class EventReceiver(QtCore.QObject): ``slidecontroller_live_stop_loop`` Stop the loop on the main display. + **Servicemanager related signals** + ``servicemanager_new_service`` + A new service is being loaded or created. + ``servicemanager_previous_item`` Display the previous item in the service. diff --git a/openlp/core/lib/formattingtags.py b/openlp/core/lib/formattingtags.py index ea5547f27..bc0055325 100644 --- a/openlp/core/lib/formattingtags.py +++ b/openlp/core/lib/formattingtags.py @@ -149,11 +149,17 @@ class FormattingTags(object): tags = [] for tag in FormattingTags.html_expands: if not tag[u'protected'] and not tag.get(u'temporary'): - tags.append(tag) - # Remove key 'temporary' from tags. It is not needed to be saved. - for tag in tags: - if u'temporary' in tag: - del tag[u'temporary'] + # Using dict ensures that copy is made and encoding of values + # a little later does not affect tags in the original list + tags.append(dict(tag)) + tag = tags[-1] + # Remove key 'temporary' from tags. + # It is not needed to be saved. + if u'temporary' in tag: + del tag[u'temporary'] + for element in tag: + if isinstance(tag[element], unicode): + tag[element] = tag[element].encode('utf8') # Formatting Tags were also known as display tags. QtCore.QSettings().setValue(u'displayTags/html_tags', QtCore.QVariant(cPickle.dumps(tags) if tags else u'')) @@ -171,9 +177,13 @@ class FormattingTags(object): user_expands = QtCore.QSettings().value(u'displayTags/html_tags', QtCore.QVariant(u'')).toString() # cPickle only accepts str not unicode strings - user_expands_string = str(unicode(user_expands).encode(u'utf8')) + user_expands_string = str(user_expands) if user_expands_string: user_tags = cPickle.loads(user_expands_string) + for tag in user_tags: + for element in tag: + if isinstance(tag[element], str): + tag[element] = tag[element].decode('utf8') # If we have some user ones added them as well FormattingTags.add_html_tags(user_tags) diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index b12a27f1d..62418f49e 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -119,6 +119,7 @@ class ServiceItem(object): self.image_border = u'#000000' self.background_audio = [] self.theme_overwritten = False + self.temporary_edit = False self._new_item() def _new_item(self): @@ -365,6 +366,7 @@ class ServiceItem(object): """ self._uuid = other._uuid self.notes = other.notes + self.temporary_edit = other.temporary_edit # Copy theme over if present. if other.theme is not None: self.theme = other.theme diff --git a/openlp/core/lib/settingstab.py b/openlp/core/lib/settingstab.py index 46263efca..f36f9f561 100644 --- a/openlp/core/lib/settingstab.py +++ b/openlp/core/lib/settingstab.py @@ -125,3 +125,9 @@ class SettingsTab(QtGui.QWidget): """ pass + + def tabVisible(self): + """ + Tab has just been made visible to the user + """ + pass diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index e439b1db1..328970d45 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -45,7 +45,7 @@ log = logging.getLogger(__name__) class Display(QtGui.QGraphicsView): """ - This is a general display screen class. Here the general display settings + This is a general display screen class. Here the general display settings will done. It will be used as specialized classes by Main Display and Preview display. """ @@ -66,7 +66,7 @@ class Display(QtGui.QGraphicsView): """ Set up and build the screen base """ - log.debug(u'Start Display base setup (live = %s)' % self.isLive) + log.debug(u'Start Display base setup (live = %s)' % self.isLive) self.setGeometry(self.screen[u'size']) log.debug(u'Setup webView') self.webView = QtWebKit.QWebView(self) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index ab21a9c19..07c90e62f 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -176,92 +176,100 @@ class Ui_MainWindow(object): self.themeManagerDock) # Create the menu items action_list = ActionList.get_instance() - action_list.add_category(UiStrings().File, CategoryOrder.standardMenu) + action_list.add_category(unicode(UiStrings().File), + CategoryOrder.standardMenu) self.fileNewItem = shortcut_action(mainWindow, u'fileNewItem', [QtGui.QKeySequence(u'Ctrl+N')], self.serviceManagerContents.onNewServiceClicked, - u':/general/general_new.png', category=UiStrings().File) + u':/general/general_new.png', category=unicode(UiStrings().File)) self.fileOpenItem = shortcut_action(mainWindow, u'fileOpenItem', [QtGui.QKeySequence(u'Ctrl+O')], self.serviceManagerContents.onLoadServiceClicked, - u':/general/general_open.png', category=UiStrings().File) + u':/general/general_open.png', category=unicode(UiStrings().File)) self.fileSaveItem = shortcut_action(mainWindow, u'fileSaveItem', [QtGui.QKeySequence(u'Ctrl+S')], self.serviceManagerContents.saveFile, - u':/general/general_save.png', category=UiStrings().File) + u':/general/general_save.png', category=unicode(UiStrings().File)) self.fileSaveAsItem = shortcut_action(mainWindow, u'fileSaveAsItem', [QtGui.QKeySequence(u'Ctrl+Shift+S')], - self.serviceManagerContents.saveFileAs, category=UiStrings().File) + self.serviceManagerContents.saveFileAs, + category=unicode(UiStrings().File)) self.printServiceOrderItem = shortcut_action(mainWindow, u'printServiceItem', [QtGui.QKeySequence(u'Ctrl+P')], self.serviceManagerContents.printServiceOrder, - category=UiStrings().File) + category=unicode(UiStrings().File)) self.fileExitItem = shortcut_action(mainWindow, u'fileExitItem', [QtGui.QKeySequence(u'Alt+F4')], mainWindow.close, - u':/system/system_exit.png', category=UiStrings().File) - action_list.add_category(UiStrings().Import, CategoryOrder.standardMenu) + u':/system/system_exit.png', category=unicode(UiStrings().File)) + action_list.add_category(unicode(UiStrings().Import), + CategoryOrder.standardMenu) self.importThemeItem = base_action( - mainWindow, u'importThemeItem', UiStrings().Import) + mainWindow, u'importThemeItem', unicode(UiStrings().Import)) self.importLanguageItem = base_action( - mainWindow, u'importLanguageItem')#, UiStrings().Import) - action_list.add_category(UiStrings().Export, CategoryOrder.standardMenu) + mainWindow, u'importLanguageItem')#, unicode(UiStrings().Import)) + action_list.add_category(unicode(UiStrings().Export), + CategoryOrder.standardMenu) self.exportThemeItem = base_action( - mainWindow, u'exportThemeItem', UiStrings().Export) + mainWindow, u'exportThemeItem', unicode(UiStrings().Export)) self.exportLanguageItem = base_action( - mainWindow, u'exportLanguageItem')#, UiStrings().Export) - action_list.add_category(UiStrings().View, CategoryOrder.standardMenu) + mainWindow, u'exportLanguageItem')#, unicode(UiStrings().Export)) + action_list.add_category(unicode(UiStrings().View), + CategoryOrder.standardMenu) self.viewMediaManagerItem = shortcut_action(mainWindow, u'viewMediaManagerItem', [QtGui.QKeySequence(u'F8')], self.toggleMediaManager, u':/system/system_mediamanager.png', - self.mediaManagerDock.isVisible(), UiStrings().View) + self.mediaManagerDock.isVisible(), unicode(UiStrings().View)) self.viewThemeManagerItem = shortcut_action(mainWindow, u'viewThemeManagerItem', [QtGui.QKeySequence(u'F10')], self.toggleThemeManager, u':/system/system_thememanager.png', - self.themeManagerDock.isVisible(), UiStrings().View) + self.themeManagerDock.isVisible(), unicode(UiStrings().View)) self.viewServiceManagerItem = shortcut_action(mainWindow, u'viewServiceManagerItem', [QtGui.QKeySequence(u'F9')], self.toggleServiceManager, u':/system/system_servicemanager.png', - self.serviceManagerDock.isVisible(), UiStrings().View) + self.serviceManagerDock.isVisible(), unicode(UiStrings().View)) self.viewPreviewPanel = shortcut_action(mainWindow, u'viewPreviewPanel', [QtGui.QKeySequence(u'F11')], self.setPreviewPanelVisibility, checked=previewVisible, - category=UiStrings().View) + category=unicode(UiStrings().View)) self.viewLivePanel = shortcut_action(mainWindow, u'viewLivePanel', [QtGui.QKeySequence(u'F12')], self.setLivePanelVisibility, - checked=liveVisible, category=UiStrings().View) + checked=liveVisible, category=unicode(UiStrings().View)) self.lockPanel = shortcut_action(mainWindow, u'lockPanel', None, self.setLockPanel, checked=panelLocked, category=None) - action_list.add_category(UiStrings().ViewMode, + action_list.add_category(unicode(UiStrings().ViewMode), CategoryOrder.standardMenu) self.modeDefaultItem = checkable_action( - mainWindow, u'modeDefaultItem', category=UiStrings().ViewMode) + mainWindow, u'modeDefaultItem', + category=unicode(UiStrings().ViewMode)) self.modeSetupItem = checkable_action( - mainWindow, u'modeSetupItem', category=UiStrings().ViewMode) + mainWindow, u'modeSetupItem', + category=unicode(UiStrings().ViewMode)) self.modeLiveItem = checkable_action( - mainWindow, u'modeLiveItem', True, UiStrings().ViewMode) + mainWindow, u'modeLiveItem', True, unicode(UiStrings().ViewMode)) self.modeGroup = QtGui.QActionGroup(mainWindow) self.modeGroup.addAction(self.modeDefaultItem) self.modeGroup.addAction(self.modeSetupItem) self.modeGroup.addAction(self.modeLiveItem) self.modeDefaultItem.setChecked(True) - action_list.add_category(UiStrings().Tools, CategoryOrder.standardMenu) + action_list.add_category(unicode(UiStrings().Tools), + CategoryOrder.standardMenu) self.toolsAddToolItem = icon_action(mainWindow, u'toolsAddToolItem', - u':/tools/tools_add.png', category=UiStrings().Tools) + u':/tools/tools_add.png', category=unicode(UiStrings().Tools)) self.toolsOpenDataFolder = icon_action(mainWindow, u'toolsOpenDataFolder', u':/general/general_open.png', - category=UiStrings().Tools) + category=unicode(UiStrings().Tools)) self.toolsFirstTimeWizard = icon_action(mainWindow, u'toolsFirstTimeWizard', u':/general/general_revert.png', - category=UiStrings().Tools) + category=unicode(UiStrings().Tools)) self.updateThemeImages = base_action(mainWindow, - u'updateThemeImages', category=UiStrings().Tools) - action_list.add_category(UiStrings().Settings, + u'updateThemeImages', category=unicode(UiStrings().Tools)) + action_list.add_category(unicode(UiStrings().Settings), CategoryOrder.standardMenu) self.settingsPluginListItem = shortcut_action(mainWindow, u'settingsPluginListItem', [QtGui.QKeySequence(u'Alt+F7')], self.onPluginItemClicked, u':/system/settings_plugin_list.png', - category=UiStrings().Settings) + category=unicode(UiStrings().Settings)) # i18n Language Items self.autoLanguageItem = checkable_action(mainWindow, u'autoLanguageItem', LanguageManager.auto_language) @@ -278,35 +286,38 @@ class Ui_MainWindow(object): self.settingsShortcutsItem = icon_action(mainWindow, u'settingsShortcutsItem', u':/system/system_configure_shortcuts.png', - category=UiStrings().Settings) + category=unicode(UiStrings().Settings)) # Formatting Tags were also known as display tags. self.formattingTagItem = icon_action(mainWindow, u'displayTagItem', u':/system/tag_editor.png', - category=UiStrings().Settings) + category=unicode(UiStrings().Settings)) self.settingsConfigureItem = icon_action(mainWindow, u'settingsConfigureItem', u':/system/system_settings.png', - category=UiStrings().Settings) + category=unicode(UiStrings().Settings)) self.settingsImportItem = base_action(mainWindow, - u'settingsImportItem', category=UiStrings().Settings) + u'settingsImportItem', category=unicode(UiStrings().Settings)) self.settingsExportItem = base_action(mainWindow, - u'settingsExportItem', category=UiStrings().Settings) - action_list.add_category(UiStrings().Help, CategoryOrder.standardMenu) + u'settingsExportItem', category=unicode(UiStrings().Settings)) + action_list.add_category(unicode(UiStrings().Help), + CategoryOrder.standardMenu) self.aboutItem = shortcut_action(mainWindow, u'aboutItem', [QtGui.QKeySequence(u'Ctrl+F1')], self.onAboutItemClicked, - u':/system/system_about.png', category=UiStrings().Help) + u':/system/system_about.png', category=unicode(UiStrings().Help)) if os.name == u'nt': self.localHelpFile = os.path.join( AppLocation.get_directory(AppLocation.AppDir), 'OpenLP.chm') self.offlineHelpItem = shortcut_action( mainWindow, u'offlineHelpItem', [QtGui.QKeySequence(u'F1')], self.onOfflineHelpClicked, - u':/system/system_help_contents.png', category=UiStrings().Help) + u':/system/system_help_contents.png', + category=unicode(UiStrings().Help)) self.onlineHelpItem = shortcut_action( mainWindow, u'onlineHelpItem', [QtGui.QKeySequence(u'Alt+F1')], self.onOnlineHelpClicked, - u':/system/system_online_help.png', category=UiStrings().Help) + u':/system/system_online_help.png', + category=unicode(UiStrings().Help)) self.webSiteItem = base_action( - mainWindow, u'webSiteItem', category=UiStrings().Help) + mainWindow, u'webSiteItem', category=unicode(UiStrings().Help)) add_actions(self.fileImportMenu, (self.settingsImportItem, None, self.importThemeItem, self.importLanguageItem)) add_actions(self.fileExportMenu, (self.settingsExportItem, None, diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 8ad2db9c2..0eb1e77c5 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -37,7 +37,7 @@ log = logging.getLogger(__name__) from PyQt4 import QtCore, QtGui from openlp.core.lib import OpenLPToolbar, ServiceItem, Receiver, build_icon, \ - ItemCapabilities, SettingsManager, translate + ItemCapabilities, SettingsManager, translate, str_to_bool from openlp.core.lib.theme import ThemeLevel from openlp.core.lib.ui import UiStrings, critical_error_message_box, \ context_menu_action, context_menu_separator, find_and_set_in_combo_box @@ -177,9 +177,9 @@ class ServiceManager(QtGui.QWidget): self.serviceManagerList.moveTop.setObjectName(u'moveTop') action_list = ActionList.get_instance() action_list.add_category( - UiStrings().Service, CategoryOrder.standardToolbar) + unicode(UiStrings().Service), CategoryOrder.standardToolbar) action_list.add_action( - self.serviceManagerList.moveTop, UiStrings().Service) + self.serviceManagerList.moveTop, unicode(UiStrings().Service)) self.serviceManagerList.moveUp = self.orderToolbar.addToolbarButton( translate('OpenLP.ServiceManager', 'Move &up'), u':/services/service_up.png', @@ -188,7 +188,7 @@ class ServiceManager(QtGui.QWidget): self.onServiceUp, shortcuts=[QtCore.Qt.Key_PageUp]) self.serviceManagerList.moveUp.setObjectName(u'moveUp') action_list.add_action( - self.serviceManagerList.moveUp, UiStrings().Service) + self.serviceManagerList.moveUp, unicode(UiStrings().Service)) self.serviceManagerList.moveDown = self.orderToolbar.addToolbarButton( translate('OpenLP.ServiceManager', 'Move &down'), u':/services/service_down.png', @@ -197,7 +197,7 @@ class ServiceManager(QtGui.QWidget): self.onServiceDown, shortcuts=[QtCore.Qt.Key_PageDown]) self.serviceManagerList.moveDown.setObjectName(u'moveDown') action_list.add_action( - self.serviceManagerList.moveDown, UiStrings().Service) + self.serviceManagerList.moveDown, unicode(UiStrings().Service)) self.serviceManagerList.moveBottom = self.orderToolbar.addToolbarButton( translate('OpenLP.ServiceManager', 'Move to &bottom'), u':/services/service_bottom.png', @@ -206,7 +206,7 @@ class ServiceManager(QtGui.QWidget): self.onServiceEnd, shortcuts=[QtCore.Qt.Key_End]) self.serviceManagerList.moveBottom.setObjectName(u'moveBottom') action_list.add_action( - self.serviceManagerList.moveBottom, UiStrings().Service) + self.serviceManagerList.moveBottom, unicode(UiStrings().Service)) self.serviceManagerList.down = self.orderToolbar.addToolbarButton( translate('OpenLP.ServiceManager', 'Move &down'), None, @@ -241,7 +241,7 @@ class ServiceManager(QtGui.QWidget): self.onExpandAll, shortcuts=[QtCore.Qt.Key_Plus]) self.serviceManagerList.expand.setObjectName(u'expand') action_list.add_action( - self.serviceManagerList.expand, UiStrings().Service) + self.serviceManagerList.expand, unicode(UiStrings().Service)) self.serviceManagerList.collapse = self.orderToolbar.addToolbarButton( translate('OpenLP.ServiceManager', '&Collapse all'), u':/services/service_collapse_all.png', @@ -250,7 +250,7 @@ class ServiceManager(QtGui.QWidget): self.onCollapseAll, shortcuts=[QtCore.Qt.Key_Minus]) self.serviceManagerList.collapse.setObjectName(u'collapse') action_list.add_action( - self.serviceManagerList.collapse, UiStrings().Service) + self.serviceManagerList.collapse, unicode(UiStrings().Service)) self.orderToolbar.addSeparator() self.serviceManagerList.makeLive = self.orderToolbar.addToolbarButton( translate('OpenLP.ServiceManager', 'Go Live'), @@ -260,7 +260,7 @@ class ServiceManager(QtGui.QWidget): shortcuts=[QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return]) self.serviceManagerList.makeLive.setObjectName(u'orderToolbar') action_list.add_action( - self.serviceManagerList.makeLive, UiStrings().Service) + self.serviceManagerList.makeLive, unicode(UiStrings().Service)) self.layout.addWidget(self.orderToolbar) # Connect up our signals and slots QtCore.QObject.connect(self.themeComboBox, @@ -465,6 +465,7 @@ class ServiceManager(QtGui.QWidget): self.setModified(False) QtCore.QSettings(). \ setValue(u'servicemanager/last file',QtCore.QVariant(u'')) + Receiver.send_message(u'servicemanager_new_service') def saveFile(self): """ @@ -663,13 +664,14 @@ class ServiceManager(QtGui.QWidget): serviceItem.renderer = self.mainwindow.renderer serviceItem.set_from_service(item, self.servicePath) self.validateItem(serviceItem) - self.loadItem_uuid = 0 + self.load_item_uuid = 0 if serviceItem.is_capable(ItemCapabilities.OnLoadUpdate): Receiver.send_message(u'%s_service_load' % serviceItem.name.lower(), serviceItem) # if the item has been processed - if serviceItem._uuid == self.loadItem_uuid: - serviceItem.edit_id = int(self.loadItem_editId) + if serviceItem._uuid == self.load_item_uuid: + serviceItem.edit_id = int(self.load_item_edit_id) + serviceItem.temporary_edit = self.load_item_temporary self.addServiceItem(serviceItem, repaint=False) delete_file(p_file) self.setFileName(fileName) @@ -999,6 +1001,17 @@ class ServiceManager(QtGui.QWidget): painter.drawImage(0, 0, overlay) painter.end() treewidgetitem.setIcon(0, build_icon(icon)) + elif serviceitem.temporary_edit: + icon = QtGui.QImage(serviceitem.icon) + icon = icon.scaled(80, 80, QtCore.Qt.KeepAspectRatio, + QtCore.Qt.SmoothTransformation) + overlay = QtGui.QImage(':/general/general_export.png') + overlay = overlay.scaled(40, 40, QtCore.Qt.KeepAspectRatio, + QtCore.Qt.SmoothTransformation) + painter = QtGui.QPainter(icon) + painter.drawImage(40, 0, overlay) + painter.end() + treewidgetitem.setIcon(0, build_icon(icon)) else: treewidgetitem.setIcon(0, serviceitem.iconic_representation) else: @@ -1006,6 +1019,11 @@ class ServiceManager(QtGui.QWidget): build_icon(u':/general/general_delete.png')) treewidgetitem.setText(0, serviceitem.get_display_title()) tips = [] + if serviceitem.temporary_edit: + tips.append(u'%s: %s' % + (unicode(translate('OpenLP.ServiceManager', 'Edit')), + (unicode(translate('OpenLP.ServiceManager', + 'Service copy only'))))) if serviceitem.theme and serviceitem.theme != -1: tips.append(u'%s: %s' % (unicode(translate('OpenLP.ServiceManager', 'Slide theme')), @@ -1127,8 +1145,9 @@ class ServiceManager(QtGui.QWidget): Triggered from plugins to update service items. Save the values as they will be used as part of the service load """ - editId, self.loadItem_uuid = message.split(u':') - self.loadItem_editId = int(editId) + edit_id, self.load_item_uuid, temporary = message.split(u':') + self.load_item_edit_id = int(edit_id) + self.load_item_temporary = str_to_bool(temporary) def replaceServiceItem(self, newItem): """ diff --git a/openlp/core/ui/settingsdialog.py b/openlp/core/ui/settingsdialog.py index 296337f0f..643ab0a6e 100644 --- a/openlp/core/ui/settingsdialog.py +++ b/openlp/core/ui/settingsdialog.py @@ -55,7 +55,7 @@ class Ui_SettingsDialog(object): QtCore.QMetaObject.connectSlotsByName(settingsDialog) QtCore.QObject.connect(self.settingListWidget, QtCore.SIGNAL(u'currentRowChanged(int)'), - self.stackedLayout.setCurrentIndex) + self.tabChanged) def retranslateUi(self, settingsDialog): settingsDialog.setWindowTitle(translate('OpenLP.SettingsForm', diff --git a/openlp/core/ui/settingsform.py b/openlp/core/ui/settingsform.py index 37da93b5b..b25a3a856 100644 --- a/openlp/core/ui/settingsform.py +++ b/openlp/core/ui/settingsform.py @@ -116,3 +116,10 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog): for plugin in self.plugins: if plugin.settings_tab: plugin.settings_tab.postSetUp() + + def tabChanged(self, tabIndex): + """ + A different settings tab is selected + """ + self.stackedLayout.setCurrentIndex(tabIndex) + self.stackedLayout.currentWidget().tabVisible() diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 92eb7971e..cd4663297 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -187,18 +187,20 @@ class SlideController(Controller): translate('OpenLP.SlideController', 'Hide'), self.toolbar)) self.blankScreen = shortcut_action(self.hideMenu, u'blankScreen', [QtCore.Qt.Key_Period], self.onBlankDisplay, - u':/slides/slide_blank.png', False, UiStrings().LiveToolbar) + u':/slides/slide_blank.png', False, + unicode(UiStrings().LiveToolbar)) self.blankScreen.setText( translate('OpenLP.SlideController', 'Blank Screen')) self.themeScreen = shortcut_action(self.hideMenu, u'themeScreen', [QtGui.QKeySequence(u'T')], self.onThemeDisplay, - u':/slides/slide_theme.png', False, UiStrings().LiveToolbar) + u':/slides/slide_theme.png', False, + unicode(UiStrings().LiveToolbar)) self.themeScreen.setText( translate('OpenLP.SlideController', 'Blank to Theme')) self.desktopScreen = shortcut_action(self.hideMenu, u'desktopScreen', [QtGui.QKeySequence(u'D')], self.onHideDisplay, u':/slides/slide_desktop.png', False, - UiStrings().LiveToolbar) + unicode(UiStrings().LiveToolbar)) self.desktopScreen.setText( translate('OpenLP.SlideController', 'Show Desktop')) self.hideMenu.setDefaultAction(self.blankScreen) @@ -218,11 +220,13 @@ class SlideController(Controller): self.toolbar)) self.playSlidesLoop = shortcut_action(self.playSlidesMenu, u'playSlidesLoop', [], self.onPlaySlidesLoop, - u':/media/media_time.png', False, UiStrings().LiveToolbar) + u':/media/media_time.png', False, + unicode(UiStrings().LiveToolbar)) self.playSlidesLoop.setText(UiStrings().PlaySlidesInLoop) self.playSlidesOnce = shortcut_action(self.playSlidesMenu, u'playSlidesOnce', [], self.onPlaySlidesOnce, - u':/media/media_time.png', False, UiStrings().LiveToolbar) + u':/media/media_time.png', False, + unicode(UiStrings().LiveToolbar)) self.playSlidesOnce.setText(UiStrings().PlaySlidesToEnd) if QtCore.QSettings().value(self.parent().generalSettingsSection + u'/enable slide loop', QtCore.QVariant(True)).toBool(): @@ -320,7 +324,7 @@ class SlideController(Controller): self.shortcutTimer.setSingleShot(True) self.verseShortcut = shortcut_action(self, u'verseShortcut', [QtGui.QKeySequence(u'V')], self.slideShortcutActivated, - category=UiStrings().LiveToolbar, + category=unicode(UiStrings().LiveToolbar), context=QtCore.Qt.WidgetWithChildrenShortcut) self.verseShortcut.setText(translate( 'OpenLP.SlideController', 'Go to "Verse"')) @@ -356,37 +360,37 @@ class SlideController(Controller): context=QtCore.Qt.WidgetWithChildrenShortcut) self.chorusShortcut = shortcut_action(self, u'chorusShortcut', [QtGui.QKeySequence(u'C')], self.slideShortcutActivated, - category=UiStrings().LiveToolbar, + category=unicode(UiStrings().LiveToolbar), context=QtCore.Qt.WidgetWithChildrenShortcut) self.chorusShortcut.setText(translate( 'OpenLP.SlideController', 'Go to "Chorus"')) self.bridgeShortcut = shortcut_action(self, u'bridgeShortcut', [QtGui.QKeySequence(u'B')], self.slideShortcutActivated, - category=UiStrings().LiveToolbar, + category=unicode(UiStrings().LiveToolbar), context=QtCore.Qt.WidgetWithChildrenShortcut) self.bridgeShortcut.setText(translate( 'OpenLP.SlideController', 'Go to "Bridge"')) self.preChorusShortcut = shortcut_action(self, u'preChorusShortcut', [QtGui.QKeySequence(u'P')], self.slideShortcutActivated, - category=UiStrings().LiveToolbar, + category=unicode(UiStrings().LiveToolbar), context=QtCore.Qt.WidgetWithChildrenShortcut) self.preChorusShortcut.setText(translate( 'OpenLP.SlideController', 'Go to "Pre-Chorus"')) self.introShortcut = shortcut_action(self, u'introShortcut', [QtGui.QKeySequence(u'I')], self.slideShortcutActivated, - category=UiStrings().LiveToolbar, + category=unicode(UiStrings().LiveToolbar), context=QtCore.Qt.WidgetWithChildrenShortcut) self.introShortcut.setText(translate( 'OpenLP.SlideController', 'Go to "Intro"')) self.endingShortcut = shortcut_action(self, u'endingShortcut', [QtGui.QKeySequence(u'E')], self.slideShortcutActivated, - category=UiStrings().LiveToolbar, + category=unicode(UiStrings().LiveToolbar), context=QtCore.Qt.WidgetWithChildrenShortcut) self.endingShortcut.setText(translate( 'OpenLP.SlideController', 'Go to "Ending"')) self.otherShortcut = shortcut_action(self, u'otherShortcut', [QtGui.QKeySequence(u'O')], self.slideShortcutActivated, - category=UiStrings().LiveToolbar, + category=unicode(UiStrings().LiveToolbar), context=QtCore.Qt.WidgetWithChildrenShortcut) self.otherShortcut.setText(translate( 'OpenLP.SlideController', 'Go to "Other"')) @@ -540,24 +544,24 @@ class SlideController(Controller): self.nextItem.setObjectName(u'nextItemLive') action_list = ActionList.get_instance() action_list.add_category( - UiStrings().LiveToolbar, CategoryOrder.standardToolbar) + unicode(UiStrings().LiveToolbar), CategoryOrder.standardToolbar) action_list.add_action(self.previousItem) action_list.add_action(self.nextItem) self.previousService = shortcut_action(parent, u'previousService', [QtCore.Qt.Key_Left], self.servicePrevious, - category=UiStrings().LiveToolbar, + category=unicode(UiStrings().LiveToolbar), context=QtCore.Qt.WidgetWithChildrenShortcut) self.previousService.setText( translate('OpenLP.SlideController', 'Previous Service')) self.nextService = shortcut_action(parent, 'nextService', [QtCore.Qt.Key_Right], self.serviceNext, - category=UiStrings().LiveToolbar, + category=unicode(UiStrings().LiveToolbar), context=QtCore.Qt.WidgetWithChildrenShortcut) self.nextService.setText( translate('OpenLP.SlideController', 'Next Service')) self.escapeItem = shortcut_action(parent, 'escapeItem', [QtCore.Qt.Key_Escape], self.liveEscape, - category=UiStrings().LiveToolbar, + category=unicode(UiStrings().LiveToolbar), context=QtCore.Qt.WidgetWithChildrenShortcut) self.escapeItem.setText( translate('OpenLP.SlideController', 'Escape Item')) diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index 596bce5d9..b8767d736 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -526,13 +526,11 @@ class ThemeManager(QtGui.QWidget): zip = zipfile.ZipFile(filename) themename = None for file in zip.namelist(): + # Handle UTF-8 files ucsfile = file_is_unicode(file) if not ucsfile: - critical_error_message_box( - message=translate('OpenLP.ThemeManager', - 'File is not a valid theme.\n' - 'The content encoding is not UTF-8.')) - continue + # Handle native Unicode files from Windows + ucsfile = file osfile = unicode(QtCore.QDir.toNativeSeparators(ucsfile)) theme_dir = None if osfile.endswith(os.path.sep): @@ -620,7 +618,7 @@ class ThemeManager(QtGui.QWidget): """ name = theme.theme_name theme_pretty_xml = theme.extract_formatted_xml() - log.debug(u'saveTheme %s %s', name, theme_pretty_xml) + log.debug(u'saveTheme %s %s', name, theme_pretty_xml.decode(u'utf-8')) theme_dir = os.path.join(self.path, name) check_directory_exists(theme_dir) theme_file = os.path.join(theme_dir, name + u'.xml') diff --git a/openlp/core/utils/actions.py b/openlp/core/utils/actions.py index 86ee69a48..8b807bf9e 100644 --- a/openlp/core/utils/actions.py +++ b/openlp/core/utils/actions.py @@ -217,8 +217,6 @@ class ActionList(object): The weight specifies how important a category is. However, this only has an impact on the order the categories are displayed. """ - if category is not None: - category = unicode(category) if category not in self.categories: self.categories.append(category) action.defaultShortcuts = action.shortcuts() @@ -226,7 +224,7 @@ class ActionList(object): self.categories[category].actions.append(action) else: self.categories[category].actions.add(action, weight) - if category is None: + if not category: # Stop here, as this action is not configurable. return # Load the shortcut from the config. @@ -250,8 +248,6 @@ class ActionList(object): The name (unicode string) of the category, which contains the action. Defaults to None. """ - if category is not None: - category = unicode(category) if category not in self.categories: return self.categories[category].actions.remove(action) diff --git a/openlp/plugins/alerts/alertsplugin.py b/openlp/plugins/alerts/alertsplugin.py index 493f08ba0..ba2af74e8 100644 --- a/openlp/plugins/alerts/alertsplugin.py +++ b/openlp/plugins/alerts/alertsplugin.py @@ -149,7 +149,7 @@ class AlertsPlugin(Plugin): Plugin.initialise(self) self.toolsAlertItem.setVisible(True) action_list = ActionList.get_instance() - action_list.add_action(self.toolsAlertItem, UiStrings().Tools) + action_list.add_action(self.toolsAlertItem, unicode(UiStrings().Tools)) def finalise(self): """ diff --git a/openlp/plugins/bibles/bibleplugin.py b/openlp/plugins/bibles/bibleplugin.py index 619581b17..68b4d1ce8 100644 --- a/openlp/plugins/bibles/bibleplugin.py +++ b/openlp/plugins/bibles/bibleplugin.py @@ -55,9 +55,11 @@ class BiblePlugin(Plugin): Plugin.initialise(self) self.importBibleItem.setVisible(True) action_list = ActionList.get_instance() - action_list.add_action(self.importBibleItem, UiStrings().Import) + action_list.add_action(self.importBibleItem, + unicode(UiStrings().Import)) # Do not add the action to the list yet. - #action_list.add_action(self.exportBibleItem, UiStrings().Export) + #action_list.add_action(self.exportBibleItem, + # unicode(UiStrings().Export)) # Set to invisible until we can export bibles self.exportBibleItem.setVisible(False) if len(self.manager.old_bible_databases): @@ -71,7 +73,8 @@ class BiblePlugin(Plugin): self.manager.finalise() Plugin.finalise(self) action_list = ActionList.get_instance() - action_list.remove_action(self.importBibleItem, UiStrings().Import) + action_list.remove_action(self.importBibleItem, + unicode(UiStrings().Import)) self.importBibleItem.setVisible(False) #action_list.remove_action(self.exportBibleItem, UiStrings().Export) self.exportBibleItem.setVisible(False) diff --git a/openlp/plugins/bibles/lib/csvbible.py b/openlp/plugins/bibles/lib/csvbible.py index 6735a7344..55feae7d4 100644 --- a/openlp/plugins/bibles/lib/csvbible.py +++ b/openlp/plugins/bibles/lib/csvbible.py @@ -28,17 +28,7 @@ The :mod:`cvsbible` modules provides a facility to import bibles from a set of CSV files. -The module expects two mandatory files containing the books and the verses and -will accept an optional third file containing the testaments. - -The format of the testament file is: - - , - - For example: - - 1,Old Testament - 2,New Testament +The module expects two mandatory files containing the books and the verses. The format of the books file is: @@ -110,6 +100,9 @@ class CSVBible(BibleDB): try: details = get_file_encoding(self.booksfile) books_file = open(self.booksfile, 'r') + if not books_file.read(3) == '\xEF\xBB\xBF': + # no BOM was found + books_file.seek(0) books_reader = csv.reader(books_file, delimiter=',', quotechar='"') for line in books_reader: if self.stop_import_flag: @@ -144,6 +137,9 @@ class CSVBible(BibleDB): book_ptr = None details = get_file_encoding(self.versesfile) verse_file = open(self.versesfile, 'rb') + if not verse_file.read(3) == '\xEF\xBB\xBF': + # no BOM was found + verse_file.seek(0) verse_reader = csv.reader(verse_file, delimiter=',', quotechar='"') for line in verse_reader: if self.stop_import_flag: diff --git a/openlp/plugins/bibles/lib/osis.py b/openlp/plugins/bibles/lib/osis.py index b802cda85..d4d797513 100644 --- a/openlp/plugins/bibles/lib/osis.py +++ b/openlp/plugins/bibles/lib/osis.py @@ -78,8 +78,7 @@ class OSISBible(BibleDB): fbibles = open(filepath, u'r') for line in fbibles: book = line.split(u',') - self.books[book[0]] = (book[1].lstrip().rstrip(), - book[2].lstrip().rstrip()) + self.books[book[0]] = (book[1].strip(), book[2].strip()) except IOError: log.exception(u'OSIS bible import failed') finally: diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index 049e2da18..b1e815a3a 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -127,13 +127,13 @@ class ImageMediaItem(MediaManagerItem): self.plugin.formparent.incrementProgressBar() filename = os.path.split(unicode(imageFile))[1] thumb = os.path.join(self.servicePath, filename) - if not os.path.exists(imageFile): + if not os.path.exists(unicode(imageFile)): icon = build_icon(u':/general/general_delete.png') else: - if validate_thumb(imageFile, thumb): + if validate_thumb(unicode(imageFile), thumb): icon = build_icon(thumb) else: - icon = create_thumb(imageFile, thumb) + icon = create_thumb(unicode(imageFile), thumb) item_name = QtGui.QListWidgetItem(filename) item_name.setIcon(icon) item_name.setToolTip(imageFile) diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index 36f684ad4..8355da5a8 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -184,7 +184,15 @@ class ImpressController(PresentationController): if not desktop: return docs = desktop.getComponents() + cnt = 0 if docs.hasElements(): + list = docs.createEnumeration() + while list.hasMoreElements(): + doc = list.nextElement() + if doc.getImplementationName() != \ + u'com.sun.star.comp.framework.BackingComp': + cnt = cnt + 1 + if cnt > 0: log.debug(u'OpenOffice not terminated as docs are still open') else: try: diff --git a/openlp/plugins/presentations/lib/presentationcontroller.py b/openlp/plugins/presentations/lib/presentationcontroller.py index a9d384c81..7ff04179f 100644 --- a/openlp/plugins/presentations/lib/presentationcontroller.py +++ b/openlp/plugins/presentations/lib/presentationcontroller.py @@ -378,7 +378,7 @@ class PresentationController(object): self.name = name self.document_class = document_class self.settings_section = self.plugin.settingsSection - self.available = self.check_available() + self.available = None self.temp_folder = os.path.join( AppLocation.get_section_data_path(self.settings_section), name) self.thumbnail_folder = os.path.join( @@ -392,14 +392,19 @@ class PresentationController(object): """ Return whether the controller is currently enabled """ - if self.available: - return QtCore.QSettings().value( - self.settings_section + u'/' + self.name, - QtCore.QVariant(QtCore.Qt.Checked)).toInt()[0] == \ - QtCore.Qt.Checked + if QtCore.QSettings().value( + self.settings_section + u'/' + self.name, + QtCore.QVariant(QtCore.Qt.Checked)).toInt()[0] == \ + QtCore.Qt.Checked: + return self.is_available() else: return False + def is_available(self): + if self.available is None: + self.available = self.check_available() + return self.available + def check_available(self): """ Presentation app is able to run on this machine diff --git a/openlp/plugins/presentations/lib/presentationtab.py b/openlp/plugins/presentations/lib/presentationtab.py index b0c3de7a8..c11f36c20 100644 --- a/openlp/plugins/presentations/lib/presentationtab.py +++ b/openlp/plugins/presentations/lib/presentationtab.py @@ -55,7 +55,6 @@ class PresentationTab(SettingsTab): for key in self.controllers: controller = self.controllers[key] checkbox = QtGui.QCheckBox(self.ControllersGroupBox) - checkbox.setEnabled(controller.available) checkbox.setObjectName(controller.name + u'CheckBox') self.PresenterCheckboxes[controller.name] = checkbox self.ControllersLayout.addWidget(checkbox) @@ -81,17 +80,20 @@ class PresentationTab(SettingsTab): for key in self.controllers: controller = self.controllers[key] checkbox = self.PresenterCheckboxes[controller.name] - if controller.available: - checkbox.setText(controller.name) - else: - checkbox.setText( - unicode(translate('PresentationPlugin.PresentationTab', - '%s (unavailable)')) % controller.name) + self.setControllerText(checkbox, controller) self.AdvancedGroupBox.setTitle(UiStrings().Advanced) self.OverrideAppCheckBox.setText( translate('PresentationPlugin.PresentationTab', 'Allow presentation application to be overriden')) + def setControllerText(self, checkbox, controller): + if checkbox.isEnabled(): + checkbox.setText(controller.name) + else: + checkbox.setText( + unicode(translate('PresentationPlugin.PresentationTab', + '%s (unavailable)')) % controller.name) + def load(self): """ Load the settings. @@ -113,7 +115,7 @@ class PresentationTab(SettingsTab): changed = False for key in self.controllers: controller = self.controllers[key] - if controller.available: + if controller.is_available(): checkbox = self.PresenterCheckboxes[controller.name] setting_key = self.settingsSection + u'/' + controller.name if QtCore.QSettings().value(setting_key) != \ @@ -133,3 +135,13 @@ class PresentationTab(SettingsTab): changed = True if changed: Receiver.send_message(u'mediaitem_presentation_rebuild') + + def tabVisible(self): + """ + Tab has just been made visible to the user + """ + for key in self.controllers: + controller = self.controllers[key] + checkbox = self.PresenterCheckboxes[controller.name] + checkbox.setEnabled(controller.is_available()) + self.setControllerText(checkbox, controller) diff --git a/openlp/plugins/songs/forms/songexportform.py b/openlp/plugins/songs/forms/songexportform.py index 22020a401..20a52c82d 100644 --- a/openlp/plugins/songs/forms/songexportform.py +++ b/openlp/plugins/songs/forms/songexportform.py @@ -252,6 +252,9 @@ class SongExportForm(OpenLPWizard): songs = self.plugin.manager.get_all_objects(Song) songs.sort(cmp=locale.strcoll, key=lambda song: song.title.lower()) for song in songs: + # No need to export temporary songs. + if song.temporary: + continue authors = u', '.join([author.display_name for author in song.authors]) title = u'%s (%s)' % (unicode(song.title), authors) diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py index b79e56f7b..53e70cde6 100644 --- a/openlp/plugins/songs/forms/songimportform.py +++ b/openlp/plugins/songs/forms/songimportform.py @@ -191,32 +191,32 @@ class SongImportForm(OpenLPWizard): QtGui.QSizePolicy.Expanding) self.formatStack = QtGui.QStackedLayout() self.formatStack.setObjectName(u'FormatStack') + # OpenLyrics + self.addFileSelectItem(u'openLyrics', u'OpenLyrics', True) # OpenLP 2.0 self.addFileSelectItem(u'openLP2', single_select=True) # openlp.org 1.x self.addFileSelectItem(u'openLP1', None, True, True) - # OpenLyrics - self.addFileSelectItem(u'openLyrics', u'OpenLyrics', True) - # Open Song - self.addFileSelectItem(u'openSong', u'OpenSong') - # Words of Worship - self.addFileSelectItem(u'wordsOfWorship') - # CCLI File import - self.addFileSelectItem(u'ccli') - # Songs of Fellowship - self.addFileSelectItem(u'songsOfFellowship', None, True) # Generic Document/Presentation import self.addFileSelectItem(u'generic', None, True) - # EasySlides + # CCLI File import + self.addFileSelectItem(u'ccli') + # EasiSlides self.addFileSelectItem(u'easiSlides', single_select=True) # EasyWorship self.addFileSelectItem(u'ew', single_select=True) - # Words of Worship + # Foilpresenter + self.addFileSelectItem(u'foilPresenter') + # Open Song + self.addFileSelectItem(u'openSong', u'OpenSong') + # SongBeamer self.addFileSelectItem(u'songBeamer') # Song Show Plus self.addFileSelectItem(u'songShowPlus') - # Foilpresenter - self.addFileSelectItem(u'foilPresenter') + # Songs of Fellowship + self.addFileSelectItem(u'songsOfFellowship', None, True) + # Words of Worship + self.addFileSelectItem(u'wordsOfWorship') # Commented out for future use. # self.addFileSelectItem(u'csv', u'CSV', single_select=True) self.sourceLayout.addLayout(self.formatStack) @@ -238,30 +238,30 @@ class SongImportForm(OpenLPWizard): self.sourcePage.setTitle(WizardStrings.ImportSelect) self.sourcePage.setSubTitle(WizardStrings.ImportSelectLong) self.formatLabel.setText(WizardStrings.FormatLabel) - self.formatComboBox.setItemText(SongFormat.OpenLP2, UiStrings().OLPV2) - self.formatComboBox.setItemText(SongFormat.OpenLP1, UiStrings().OLPV1) self.formatComboBox.setItemText(SongFormat.OpenLyrics, translate('SongsPlugin.ImportWizardForm', 'OpenLyrics or OpenLP 2.0 Exported Song')) - self.formatComboBox.setItemText(SongFormat.OpenSong, WizardStrings.OS) - self.formatComboBox.setItemText( - SongFormat.WordsOfWorship, WizardStrings.WoW) - self.formatComboBox.setItemText(SongFormat.CCLI, WizardStrings.CCLI) - self.formatComboBox.setItemText( - SongFormat.SongsOfFellowship, WizardStrings.SoF) + self.formatComboBox.setItemText(SongFormat.OpenLP2, UiStrings().OLPV2) + self.formatComboBox.setItemText(SongFormat.OpenLP1, UiStrings().OLPV1) self.formatComboBox.setItemText(SongFormat.Generic, translate('SongsPlugin.ImportWizardForm', 'Generic Document/Presentation')) + self.formatComboBox.setItemText(SongFormat.CCLI, WizardStrings.CCLI) self.formatComboBox.setItemText( SongFormat.EasiSlides, WizardStrings.ES) self.formatComboBox.setItemText( SongFormat.EasyWorship, WizardStrings.EW) + self.formatComboBox.setItemText( + SongFormat.FoilPresenter, WizardStrings.FP) + self.formatComboBox.setItemText(SongFormat.OpenSong, WizardStrings.OS) self.formatComboBox.setItemText( SongFormat.SongBeamer, WizardStrings.SB) self.formatComboBox.setItemText( SongFormat.SongShowPlus, WizardStrings.SSP) self.formatComboBox.setItemText( - SongFormat.FoilPresenter, WizardStrings.FP) + SongFormat.SongsOfFellowship, WizardStrings.SoF) + self.formatComboBox.setItemText( + SongFormat.WordsOfWorship, WizardStrings.WoW) # self.formatComboBox.setItemText(SongFormat.CSV, WizardStrings.CSV) self.openLP2FilenameLabel.setText( translate('SongsPlugin.ImportWizardForm', 'Filename:')) @@ -359,6 +359,8 @@ class SongImportForm(OpenLPWizard): return True elif self.currentPage() == self.sourcePage: source_format = self.formatComboBox.currentIndex() + QtCore.QSettings().setValue(u'songs/last import type', + source_format) if source_format == SongFormat.OpenLP2: if self.openLP2FilenameEdit.text().isEmpty(): critical_error_message_box(UiStrings().NFSs, @@ -657,7 +659,12 @@ class SongImportForm(OpenLPWizard): self.restart() self.finishButton.setVisible(False) self.cancelButton.setVisible(True) - self.formatComboBox.setCurrentIndex(0) + last_import_type = QtCore.QSettings().value( + u'songs/last import type').toInt()[0] + if last_import_type < 0 or \ + last_import_type >= self.formatComboBox.count(): + last_import_type = 0 + self.formatComboBox.setCurrentIndex(last_import_type) self.openLP2FilenameEdit.setText(u'') self.openLP1FilenameEdit.setText(u'') self.openLyricsFileListWidget.clear() diff --git a/openlp/plugins/songs/lib/cclifileimport.py b/openlp/plugins/songs/lib/cclifileimport.py index 624256290..e9b1aa925 100644 --- a/openlp/plugins/songs/lib/cclifileimport.py +++ b/openlp/plugins/songs/lib/cclifileimport.py @@ -75,6 +75,9 @@ class CCLIFileImport(SongImport): details = chardet.detect(detect_content) detect_file.close() infile = codecs.open(filename, u'r', details['encoding']) + if not infile.read(3) == '\xEF\xBB\xBF': + # not UTF or no BOM was found + infile.seek(0) lines = infile.readlines() infile.close() ext = os.path.splitext(filename)[1] diff --git a/openlp/plugins/songs/lib/db.py b/openlp/plugins/songs/lib/db.py index 37ee42451..ce228e5f8 100644 --- a/openlp/plugins/songs/lib/db.py +++ b/openlp/plugins/songs/lib/db.py @@ -199,7 +199,8 @@ def init_schema(url): Column(u'search_lyrics', types.UnicodeText, nullable=False), Column(u'create_date', types.DateTime(), default=func.now()), Column(u'last_modified', types.DateTime(), default=func.now(), - onupdate=func.now()) + onupdate=func.now()), + Column(u'temporary', types.Boolean(), default=False) ) # Definition of the "topics" table diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index d8432f668..c24313be1 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -68,19 +68,19 @@ class SongFormat(object): """ _format_availability = {} Unknown = -1 - OpenLP2 = 0 - OpenLP1 = 1 - OpenLyrics = 2 - OpenSong = 3 - WordsOfWorship = 4 - CCLI = 5 - SongsOfFellowship = 6 - Generic = 7 - EasiSlides = 8 - EasyWorship = 9 - SongBeamer = 10 - SongShowPlus = 11 - FoilPresenter = 12 + OpenLyrics = 0 + OpenLP2 = 1 + OpenLP1 = 2 + Generic = 3 + CCLI = 4 + EasiSlides = 5 + EasyWorship = 6 + FoilPresenter = 7 + OpenSong = 8 + SongBeamer = 9 + SongShowPlus = 10 + SongsOfFellowship = 11 + WordsOfWorship = 12 #CSV = 13 @staticmethod @@ -125,19 +125,19 @@ class SongFormat(object): Return a list of the supported song formats. """ return [ + SongFormat.OpenLyrics, SongFormat.OpenLP2, SongFormat.OpenLP1, - SongFormat.OpenLyrics, - SongFormat.OpenSong, - SongFormat.WordsOfWorship, - SongFormat.CCLI, - SongFormat.SongsOfFellowship, SongFormat.Generic, + SongFormat.CCLI, SongFormat.EasiSlides, - SongFormat.EasyWorship, + SongFormat.EasyWorship, + SongFormat.FoilPresenter, + SongFormat.OpenSong, SongFormat.SongBeamer, SongFormat.SongShowPlus, - SongFormat.FoilPresenter + SongFormat.SongsOfFellowship, + SongFormat.WordsOfWorship ] @staticmethod diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index dad95c61b..052fb5b7b 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -270,6 +270,9 @@ class SongMediaItem(MediaManagerItem): searchresults.sort( cmp=locale.strcoll, key=lambda song: song.title.lower()) for song in searchresults: + # Do not display temporary songs + if song.temporary: + continue author_list = [author.display_name for author in song.authors] song_title = unicode(song.title) song_detail = u'%s (%s)' % (song_title, u', '.join(author_list)) @@ -286,6 +289,9 @@ class SongMediaItem(MediaManagerItem): self.listView.clear() for author in searchresults: for song in author.songs: + # Do not display temporary songs + if song.temporary: + continue song_detail = u'%s (%s)' % (author.display_name, song.title) song_name = QtGui.QListWidgetItem(song_detail) song_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(song.id)) @@ -534,6 +540,7 @@ class SongMediaItem(MediaManagerItem): Song.search_title.asc()) editId = 0 add_song = True + temporary = False if search_results: for song in search_results: author_list = item.data_string[u'authors'] @@ -559,13 +566,18 @@ class SongMediaItem(MediaManagerItem): self._updateBackgroundAudio(song, item) editId = song.id self.onSearchTextButtonClick() - else: + elif add_song and not self.addSongFromService: # Make sure we temporary import formatting tags. - self.openLyrics.xml_to_song(item.xml_version, True) + song = self.openLyrics.xml_to_song(item.xml_version, True) + # If there's any backing tracks, copy them over. + if len(item.background_audio) > 0: + self._updateBackgroundAudio(song, item) + editId = song.id + temporary = True # Update service with correct song id. if editId: Receiver.send_message(u'service_item_update', - u'%s:%s' % (editId, item._uuid)) + u'%s:%s:%s' % (editId, item._uuid, temporary)) def search(self, string): """ diff --git a/openlp/plugins/songs/lib/sofimport.py b/openlp/plugins/songs/lib/sofimport.py index 4bb91f58a..7bd0a50d6 100644 --- a/openlp/plugins/songs/lib/sofimport.py +++ b/openlp/plugins/songs/lib/sofimport.py @@ -345,7 +345,8 @@ class SofImport(OooImport): u'I\'M', u'I\'LL', u'SAVIOUR', u'O', u'YOU\'RE', u'HE', u'HIS', u'HIM', u'ZION', u'EMMANUEL', u'MAJESTY', u'JESUS\'', u'JIREH', u'JUDAH', u'LION', u'LORD\'S', u'ABRAHAM', u'GOD\'S', - u'FATHER\'S', u'ELIJAH'): + u'FATHER\'S', u'ELIJAH' u'MARTHA', u'CHRISTMAS', u'ALPHA', + u'OMEGA'): textarr[i] = textarr[i].capitalize() else: textarr[i] = textarr[i].lower() diff --git a/openlp/plugins/songs/lib/upgrade.py b/openlp/plugins/songs/lib/upgrade.py index f97fdff42..25f90e860 100644 --- a/openlp/plugins/songs/lib/upgrade.py +++ b/openlp/plugins/songs/lib/upgrade.py @@ -33,7 +33,9 @@ from sqlalchemy import Column, Table, types from sqlalchemy.sql.expression import func from migrate.changeset.constraint import ForeignKeyConstraint -__version__ = 2 +from openlp.plugins.songs.lib.db import Song + +__version__ = 3 def upgrade_setup(metadata): """ @@ -86,3 +88,12 @@ def upgrade_2(session, metadata, tables): Column(u'last_modified', types.DateTime(), default=func.now())\ .create(table=tables[u'songs']) +def upgrade_3(session, metadata, tables): + """ + Version 3 upgrade. + + This upgrade adds a temporary song flag to the songs table + """ + Column(u'temporary', types.Boolean(), default=False)\ + .create(table=tables[u'songs']) + diff --git a/openlp/plugins/songs/lib/xml.py b/openlp/plugins/songs/lib/xml.py index aaf82b395..b16db7e94 100644 --- a/openlp/plugins/songs/lib/xml.py +++ b/openlp/plugins/songs/lib/xml.py @@ -346,7 +346,7 @@ class OpenLyrics(object): lines_element.set(u'break', u'optional') return self._extract_xml(song_xml) - def xml_to_song(self, xml, parse_and_not_save=False): + def xml_to_song(self, xml, parse_and_temporary_save=False): """ Create and save a song from OpenLyrics format xml to the database. Since we also export XML from external sources (e. g. OpenLyrics import), we @@ -355,9 +355,9 @@ class OpenLyrics(object): ``xml`` The XML to parse (unicode). - ``parse_and_not_save`` - Switch to skip processing the whole song and to prevent storing the - songs to the database. Defaults to ``False``. + ``parse_and_temporary_save`` + Switch to skip processing the whole song and storing the songs in + the database with a temporary flag. Defaults to ``False``. """ # No xml get out of here. if not xml: @@ -371,14 +371,13 @@ class OpenLyrics(object): return None # Formatting tags are new in OpenLyrics 0.8 if float(song_xml.get(u'version')) > 0.7: - self._process_formatting_tags(song_xml, parse_and_not_save) - if parse_and_not_save: - return + self._process_formatting_tags(song_xml, parse_and_temporary_save) song = Song() # Values will be set when cleaning the song. song.search_lyrics = u'' song.verse_order = u'' song.search_title = u'' + song.temporary = parse_and_temporary_save self._process_copyright(properties, song) self._process_cclinumber(properties, song) self._process_titles(properties, song) diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index a5f194f7b..5402ec1fa 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -74,9 +74,14 @@ class SongsPlugin(Plugin): self.songExportItem.setVisible(True) self.toolsReindexItem.setVisible(True) action_list = ActionList.get_instance() - action_list.add_action(self.songImportItem, UiStrings().Import) - action_list.add_action(self.songExportItem, UiStrings().Export) - action_list.add_action(self.toolsReindexItem, UiStrings().Tools) + action_list.add_action(self.songImportItem, unicode(UiStrings().Import)) + action_list.add_action(self.songExportItem, unicode(UiStrings().Export)) + action_list.add_action(self.toolsReindexItem, + unicode(UiStrings().Tools)) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'servicemanager_new_service'), + self.clearTemporarySongs) + def addImportMenuItem(self, import_menu): """ @@ -264,12 +269,23 @@ class SongsPlugin(Plugin): Time to tidy up on exit """ log.info(u'Songs Finalising') + self.clearTemporarySongs() + # Clean up files and connections self.manager.finalise() self.songImportItem.setVisible(False) self.songExportItem.setVisible(False) self.toolsReindexItem.setVisible(False) action_list = ActionList.get_instance() - action_list.remove_action(self.songImportItem, UiStrings().Import) - action_list.remove_action(self.songExportItem, UiStrings().Export) - action_list.remove_action(self.toolsReindexItem, UiStrings().Tools) + action_list.remove_action(self.songImportItem, + unicode(UiStrings().Import)) + action_list.remove_action(self.songExportItem, + unicode(UiStrings().Export)) + action_list.remove_action(self.toolsReindexItem, + unicode(UiStrings().Tools)) Plugin.finalise(self) + + def clearTemporarySongs(self): + # Remove temporary songs + songs = self.manager.get_all_objects(Song, Song.temporary == True) + for song in songs: + self.manager.delete_object(Song, song.id) diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index d09831052..29c5c4927 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -136,11 +136,11 @@ class SongUsagePlugin(Plugin): self.setButtonState() action_list = ActionList.get_instance() action_list.add_action(self.songUsageStatus, - translate('SongUsagePlugin', 'Song Usage')) + unicode(translate('SongUsagePlugin', 'Song Usage'))) action_list.add_action(self.songUsageDelete, - translate('SongUsagePlugin', 'Song Usage')) + unicode(translate('SongUsagePlugin', 'Song Usage'))) action_list.add_action(self.songUsageReport, - translate('SongUsagePlugin', 'Song Usage')) + unicode(translate('SongUsagePlugin', 'Song Usage'))) self.songUsageDeleteForm = SongUsageDeleteForm(self.manager, self.formparent) self.songUsageDetailForm = SongUsageDetailForm(self, self.formparent) @@ -157,11 +157,11 @@ class SongUsagePlugin(Plugin): self.songUsageMenu.menuAction().setVisible(False) action_list = ActionList.get_instance() action_list.remove_action(self.songUsageStatus, - translate('SongUsagePlugin', 'Song Usage')) + unicode(translate('SongUsagePlugin', 'Song Usage'))) action_list.remove_action(self.songUsageDelete, - translate('SongUsagePlugin', 'Song Usage')) + unicode(translate('SongUsagePlugin', 'Song Usage'))) action_list.remove_action(self.songUsageReport, - translate('SongUsagePlugin', 'Song Usage')) + unicode(translate('SongUsagePlugin', 'Song Usage'))) self.songUsageActiveButton.hide() # stop any events being processed self.songUsageActive = False