diff --git a/documentation/api/source/plugins/songs.rst b/documentation/api/source/plugins/songs.rst index fed9907a2..1e86ce020 100644 --- a/documentation/api/source/plugins/songs.rst +++ b/documentation/api/source/plugins/songs.rst @@ -72,9 +72,6 @@ Song Importers .. automodule:: openlp.plugins.songs.lib.cclifileimport :members: -.. autoclass:: openlp.plugins.songs.lib.cclifileimport.CCLIFileImportError - :members: - .. automodule:: openlp.plugins.songs.lib.ewimport :members: diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index c2e1243ce..3171730ea 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -34,7 +34,7 @@ from sqlalchemy import create_engine, MetaData from sqlalchemy.exceptions import InvalidRequestError from sqlalchemy.orm import scoped_session, sessionmaker -from openlp.core.utils import AppLocation +from openlp.core.utils import AppLocation, delete_file log = logging.getLogger(__name__) @@ -75,11 +75,7 @@ def delete_database(plugin_name, db_file_name=None): else: db_file_path = os.path.join( AppLocation.get_section_data_path(plugin_name), plugin_name) - try: - os.remove(db_file_path) - return True - except OSError: - return False + return delete_file(db_file_path) class BaseModel(object): """ @@ -295,4 +291,4 @@ class Manager(object): if self.is_dirty: engine = create_engine(self.db_url) if self.db_url.startswith(u'sqlite'): - engine.execute("vacuum") \ No newline at end of file + engine.execute("vacuum") diff --git a/openlp/core/lib/spelltextedit.py b/openlp/core/lib/spelltextedit.py index 30811e08b..82391a0b3 100644 --- a/openlp/core/lib/spelltextedit.py +++ b/openlp/core/lib/spelltextedit.py @@ -28,9 +28,9 @@ import re try: import enchant from enchant import DictNotFoundError - enchant_available = True + ENCHANT_AVAILABLE = True except ImportError: - enchant_available = False + ENCHANT_AVAILABLE = False # based on code from # http://john.nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check @@ -45,7 +45,7 @@ class SpellTextEdit(QtGui.QPlainTextEdit): def __init__(self, *args): QtGui.QPlainTextEdit.__init__(self, *args) # Default dictionary based on the current locale. - if enchant_available: + if ENCHANT_AVAILABLE: try: self.dict = enchant.Dict() except DictNotFoundError: @@ -72,7 +72,7 @@ class SpellTextEdit(QtGui.QPlainTextEdit): self.setTextCursor(cursor) # Check if the selected word is misspelled and offer spelling # suggestions if it is. - if enchant_available and self.textCursor().hasSelection(): + if ENCHANT_AVAILABLE and self.textCursor().hasSelection(): text = unicode(self.textCursor().selectedText()) if not self.dict.check(text): spell_menu = QtGui.QMenu(translate('OpenLP.SpellTextEdit', diff --git a/openlp/core/ui/__init__.py b/openlp/core/ui/__init__.py index 698216365..80124c2be 100644 --- a/openlp/core/ui/__init__.py +++ b/openlp/core/ui/__init__.py @@ -26,6 +26,9 @@ """ The :mod:`ui` module provides the core user interface for OpenLP """ +from PyQt4 import QtGui + +from openlp.core.lib import translate, Receiver class HideMode(object): """ @@ -48,6 +51,34 @@ class HideMode(object): Theme = 2 Screen = 3 + +def criticalErrorMessageBox(title=None, message=None, parent=None, + question=False): + """ + Provides a standard critical message box for errors that OpenLP displays + to users. + + ``title`` + The title for the message box. + + ``message`` + The message to display to the user. + + ``parent`` + The parent UI element to attach the dialog to. + + ``question`` + Should this message box question the user. + """ + error = translate('OpenLP.Ui', 'Error') + if question: + return QtGui.QMessageBox.critical(parent, error, message, + QtGui.QMessageBox.StandardButtons( + QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)) + data = {u'message': message} + data[u'title'] = title if title else error + return Receiver.send_message(u'openlp_error_message', data) + from themeform import ThemeForm from filerenameform import FileRenameForm from maindisplay import MainDisplay @@ -68,6 +99,6 @@ from mediadockmanager import MediaDockManager from servicemanager import ServiceManager from thememanager import ThemeManager -__all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', - 'MainDisplay', 'SlideController', 'ServiceManager', 'ThemeManager', - 'MediaDockManager', 'ServiceItemEditForm'] +__all__ = ['criticalErrorMessageBox', 'SplashScreen', 'AboutForm', + 'SettingsForm', 'MainDisplay', 'SlideController', 'ServiceManager', + 'ThemeManager', 'MediaDockManager', 'ServiceItemEditForm'] diff --git a/openlp/core/ui/advancedtab.py b/openlp/core/ui/advancedtab.py index 7cebe9930..58b637bc2 100644 --- a/openlp/core/ui/advancedtab.py +++ b/openlp/core/ui/advancedtab.py @@ -72,6 +72,14 @@ class AdvancedTab(SettingsTab): u'enableAutoCloseCheckBox') self.uiLayout.addRow(self.enableAutoCloseCheckBox) self.leftLayout.addWidget(self.uiGroupBox) + self.hideMouseGroupBox = QtGui.QGroupBox(self.leftColumn) + self.hideMouseGroupBox.setObjectName(u'hideMouseGroupBox') + self.hideMouseLayout = QtGui.QVBoxLayout(self.hideMouseGroupBox) + self.hideMouseLayout.setObjectName(u'hideMouseLayout') + self.hideMouseCheckBox = QtGui.QCheckBox(self.hideMouseGroupBox) + self.hideMouseCheckBox.setObjectName(u'hideMouseCheckBox') + self.hideMouseLayout.addWidget(self.hideMouseCheckBox) + self.leftLayout.addWidget(self.hideMouseGroupBox) # self.sharedDirGroupBox = QtGui.QGroupBox(self.leftColumn) # self.sharedDirGroupBox.setObjectName(u'sharedDirGroupBox') # self.sharedDirLayout = QtGui.QFormLayout(self.sharedDirGroupBox) @@ -117,6 +125,10 @@ class AdvancedTab(SettingsTab): 'Expand new service items on creation')) self.enableAutoCloseCheckBox.setText(translate('OpenLP.AdvancedTab', 'Enable application exit confirmation')) + self.hideMouseGroupBox.setTitle(translate('OpenLP.AdvancedTab', + 'Mouse Cursor')) + self.hideMouseCheckBox.setText(translate('OpenLP.AdvancedTab', + 'Hide the mouse cursor when moved over the display window')) # self.sharedDirGroupBox.setTitle( # translate('AdvancedTab', 'Central Data Store')) # self.sharedCheckBox.setText( @@ -150,6 +162,8 @@ class AdvancedTab(SettingsTab): self.enableAutoCloseCheckBox.setChecked( settings.value(u'enable exit confirmation', QtCore.QVariant(True)).toBool()) + self.hideMouseCheckBox.setChecked( + settings.value(u'hide mouse', QtCore.QVariant(False)).toBool()) settings.endGroup() def save(self): @@ -168,6 +182,8 @@ class AdvancedTab(SettingsTab): QtCore.QVariant(self.expandServiceItemCheckBox.isChecked())) settings.setValue(u'enable exit confirmation', QtCore.QVariant(self.enableAutoCloseCheckBox.isChecked())) + settings.setValue(u'hide mouse', + QtCore.QVariant(self.hideMouseCheckBox.isChecked())) settings.endGroup() # def onSharedCheckBoxChanged(self, checked): diff --git a/openlp/core/ui/displaytagtab.py b/openlp/core/ui/displaytagtab.py index 154d397b9..1c77084b9 100644 --- a/openlp/core/ui/displaytagtab.py +++ b/openlp/core/ui/displaytagtab.py @@ -34,6 +34,7 @@ import cPickle from PyQt4 import QtCore, QtGui from openlp.core.lib import SettingsTab, translate, DisplayTags +from openlp.core.ui import criticalErrorMessageBox class DisplayTagTab(SettingsTab): ''' @@ -275,12 +276,10 @@ class DisplayTagTab(SettingsTab): """ for html in DisplayTags.get_html_tags(): if self._strip(html[u'start tag']) == u'n': - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('OpenLP.DisplayTagTab', 'Update Error'), translate('OpenLP.DisplayTagTab', - 'Tag "n" already defined.'), - QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok), - QtGui.QMessageBox.Ok) + 'Tag "n" already defined.')) return # Add new tag to list tag = {u'desc': u'New Item', u'start tag': u'{n}', @@ -318,12 +317,10 @@ class DisplayTagTab(SettingsTab): for linenumber, html1 in enumerate(html_expands): if self._strip(html1[u'start tag']) == tag and \ linenumber != self.selected: - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('OpenLP.DisplayTagTab', 'Update Error'), unicode(translate('OpenLP.DisplayTagTab', - 'Tag %s already defined.')) % tag, - QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok), - QtGui.QMessageBox.Ok) + 'Tag %s already defined.')) % tag) return html[u'desc'] = unicode(self.descriptionLineEdit.text()) html[u'start html'] = unicode(self.startTagLineEdit.text()) diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index ab69cd1e9..6ddd2544f 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -24,6 +24,8 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ +The :mod:`maindisplay` module provides the functionality to display screens +and play multimedia within OpenLP. """ import logging import os @@ -92,6 +94,7 @@ class DisplayWidget(QtGui.QGraphicsView): else: event.ignore() + class MainDisplay(DisplayWidget): """ This is the display screen. @@ -268,6 +271,8 @@ class MainDisplay(DisplayWidget): else: js = u'show_image("");' self.frame.evaluateJavaScript(js) + # Update the preview frame. + Receiver.send_message(u'maindisplay_active') def resetImage(self): """ @@ -276,6 +281,8 @@ class MainDisplay(DisplayWidget): """ log.debug(u'resetImage') self.displayImage(self.serviceItem.bg_image_bytes) + # Update the preview frame. + Receiver.send_message(u'maindisplay_active') def resetVideo(self): """ @@ -290,6 +297,8 @@ class MainDisplay(DisplayWidget): self.phononActive = False else: self.frame.evaluateJavaScript(u'show_video("close");') + # Update the preview frame. + Receiver.send_message(u'maindisplay_active') def videoPlay(self): """ @@ -357,6 +366,8 @@ class MainDisplay(DisplayWidget): self.webView.setVisible(False) self.videoWidget.setVisible(True) self.audio.setVolume(vol) + # Update the preview frame. + Receiver.send_message(u'maindisplay_active') return self.preview() def isLoaded(self): @@ -424,6 +435,14 @@ class MainDisplay(DisplayWidget): # if was hidden keep it hidden if self.hideMode and self.isLive: self.hideDisplay(self.hideMode) + # Hide mouse cursor when moved over display if enabled in settings + settings = QtCore.QSettings() + if settings.value(u'advanced/hide mouse', QtCore.QVariant(False)).toBool(): + self.setCursor(QtCore.Qt.BlankCursor) + self.frame.evaluateJavaScript('document.body.style.cursor = "none"') + else: + self.setCursor(QtCore.Qt.ArrowCursor) + self.frame.evaluateJavaScript('document.body.style.cursor = "auto"') def footer(self, text): """ @@ -473,6 +492,7 @@ class MainDisplay(DisplayWidget): # Trigger actions when display is active again Receiver.send_message(u'maindisplay_active') + class AudioPlayer(QtCore.QObject): """ This Class will play audio only allowing components to work with a diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index ffc2bee25..81f514959 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -36,8 +36,10 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import OpenLPToolbar, ServiceItem, context_menu_action, \ Receiver, build_icon, ItemCapabilities, SettingsManager, translate, \ ThemeLevel -from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm -from openlp.core.utils import AppLocation, file_is_unicode, split_filename +from openlp.core.ui import criticalErrorMessageBox, ServiceNoteForm, \ + ServiceItemEditForm +from openlp.core.utils import AppLocation, delete_file, file_is_unicode, \ + split_filename class ServiceManagerList(QtGui.QTreeWidget): """ @@ -445,11 +447,7 @@ class ServiceManager(QtGui.QWidget): file.close() if zip: zip.close() - try: - os.remove(serviceFileName) - except (IOError, OSError): - # if not present do not worry - pass + delete_file(serviceFileName) self.mainwindow.addRecentFile(fileName) self.setModified(False) return True @@ -486,11 +484,10 @@ class ServiceManager(QtGui.QWidget): for file in zip.namelist(): ucsfile = file_is_unicode(file) if not ucsfile: - QtGui.QMessageBox.critical( - self, translate('OpenLP.ServiceManager', 'Error'), - translate('OpenLP.ServiceManager', - 'File is not a valid service.\n' - 'The content encoding is not UTF-8.')) + criticalErrorMessageBox( + message=translate('OpenLP.ServiceManager', + 'File is not a valid service.\n' + 'The content encoding is not UTF-8.')) continue osfile = unicode(QtCore.QDir.toNativeSeparators(ucsfile)) filePath = os.path.join(self.servicePath, @@ -515,16 +512,11 @@ class ServiceManager(QtGui.QWidget): if serviceItem.is_capable(ItemCapabilities.OnLoadUpdate): Receiver.send_message(u'%s_service_load' % serviceItem.name.lower(), serviceItem) - try: - if os.path.isfile(p_file): - os.remove(p_file) - except (IOError, OSError): - log.exception(u'Failed to remove osd file') + delete_file(p_file) else: - QtGui.QMessageBox.critical( - self, translate('OpenLP.ServiceManager', 'Error'), - translate('OpenLP.ServiceManager', - 'File is not a valid service.')) + criticalErrorMessageBox( + message=translate('OpenLP.ServiceManager', + 'File is not a valid service.')) log.exception(u'File contains no service data') except (IOError, NameError): log.exception(u'Problem loading a service file') @@ -873,11 +865,7 @@ class ServiceManager(QtGui.QWidget): """ for file in os.listdir(self.servicePath): file_path = os.path.join(self.servicePath, file) - try: - if os.path.isfile(file_path): - os.remove(file_path) - except OSError: - log.exception(u'Failed to clean up servicePath') + delete_file(file_path) def onThemeComboBoxSelected(self, currentIndex): """ @@ -1004,7 +992,7 @@ class ServiceManager(QtGui.QWidget): self.mainwindow.previewController.addServiceManagerItem( self.serviceItems[item][u'service_item'], count) else: - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('OpenLP.ServiceManager', 'Missing Display Handler'), translate('OpenLP.ServiceManager', 'Your item cannot be ' 'displayed as there is no handler to display it')) @@ -1038,11 +1026,11 @@ class ServiceManager(QtGui.QWidget): self.serviceItems[item][u'service_item'], 0) self.mainwindow.liveController.PreviewListWidget.setFocus() else: - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('OpenLP.ServiceManager', 'Missing Display Handler'), translate('OpenLP.ServiceManager', 'Your item cannot be ' - 'displayed as the plugin required to display it is missing ' - 'or inactive')) + 'displayed as the plugin required to display it is missing ' + 'or inactive')) def remoteEdit(self): """ diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index f8236a1eb..2db76063c 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -31,6 +31,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import translate, BackgroundType, BackgroundGradientType, \ Receiver +from openlp.core.ui import criticalErrorMessageBox from openlp.core.utils import get_images_filter from themewizard import Ui_ThemeWizard @@ -567,20 +568,16 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): self.theme.theme_name = \ unicode(self.field(u'name').toString()) if not self.theme.theme_name: - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('OpenLP.ThemeForm', 'Theme Name Missing'), translate('OpenLP.ThemeForm', - 'There is no name for this theme. Please enter one.'), - (QtGui.QMessageBox.Ok), - QtGui.QMessageBox.Ok) + 'There is no name for this theme. Please enter one.')) return if self.theme.theme_name == u'-1' or self.theme.theme_name == u'None': - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('OpenLP.ThemeForm', 'Theme Name Invalid'), translate('OpenLP.ThemeForm', - 'Invalid theme name. Please enter one.'), - (QtGui.QMessageBox.Ok), - QtGui.QMessageBox.Ok) + 'Invalid theme name. Please enter one.')) return saveFrom = None saveTo = None diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index b0f3d6147..df1f1f775 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -32,12 +32,12 @@ import logging from xml.etree.ElementTree import ElementTree, XML from PyQt4 import QtCore, QtGui -from openlp.core.ui import FileRenameForm, ThemeForm +from openlp.core.ui import criticalErrorMessageBox, FileRenameForm, ThemeForm from openlp.core.theme import Theme from openlp.core.lib import OpenLPToolbar, ThemeXML, get_text_file_string, \ build_icon, Receiver, SettingsManager, translate, check_item_selected, \ BackgroundType, BackgroundGradientType, check_directory_exists -from openlp.core.utils import AppLocation, file_is_unicode, \ +from openlp.core.utils import AppLocation, delete_file, file_is_unicode, \ get_filesystem_encoding log = logging.getLogger(__name__) @@ -341,9 +341,9 @@ class ThemeManager(QtGui.QWidget): """ self.themelist.remove(theme) thumb = theme + u'.png' + delete_file(os.path.join(self.path, thumb)) + delete_file(os.path.join(self.thumbPath, thumb)) try: - os.remove(os.path.join(self.path, thumb)) - os.remove(os.path.join(self.thumbPath, thumb)) encoding = get_filesystem_encoding() shutil.rmtree(os.path.join(self.path, theme).encode(encoding)) except OSError: @@ -359,9 +359,7 @@ class ThemeManager(QtGui.QWidget): """ item = self.themeListWidget.currentItem() if item is None: - QtGui.QMessageBox.critical(self, - translate('OpenLP.ThemeManager', 'Error'), - translate('OpenLP.ThemeManager', + criticalErrorMessageBox(message=translate('OpenLP.ThemeManager', 'You have not selected a theme.')) return theme = unicode(item.data(QtCore.Qt.UserRole).toString()) @@ -388,10 +386,10 @@ class ThemeManager(QtGui.QWidget): 'Your theme has been successfully exported.')) except (IOError, OSError): log.exception(u'Export Theme Failed') - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('OpenLP.ThemeManager', 'Theme Export Failed'), translate('OpenLP.ThemeManager', - 'Your theme could not be exported due to an error.')) + 'Your theme could not be exported due to an error.')) finally: if zip: zip.close() @@ -498,11 +496,10 @@ class ThemeManager(QtGui.QWidget): for file in zip.namelist(): ucsfile = file_is_unicode(file) if not ucsfile: - QtGui.QMessageBox.critical( - self, translate('OpenLP.ThemeManager', 'Error'), - translate('OpenLP.ThemeManager', - 'File is not a valid theme.\n' - 'The content encoding is not UTF-8.')) + criticalErrorMessageBox( + message=translate('OpenLP.ThemeManager', + 'File is not a valid theme.\n' + 'The content encoding is not UTF-8.')) continue osfile = unicode(QtCore.QDir.toNativeSeparators(ucsfile)) theme_dir = None @@ -521,11 +518,8 @@ class ThemeManager(QtGui.QWidget): check_directory_exists(theme_dir) if os.path.splitext(ucsfile)[1].lower() in [u'.xml']: xml_data = zip.read(file) - try: - xml_data = xml_data.decode(u'utf-8') - except UnicodeDecodeError: - log.exception(u'Theme XML is not UTF-8 ' - u'encoded.') + xml_data = file_is_unicode(xml_data) + if not xml_data: break filexml = self._checkVersionAndConvert(xml_data) outfile = open(fullpath, u'w') @@ -537,19 +531,17 @@ class ThemeManager(QtGui.QWidget): theme = self._createThemeFromXml(filexml, self.path) self.generateAndSaveImage(dir, themename, theme) else: - Receiver.send_message(u'openlp_error_message', { - u'title': translate('OpenLP.ThemeManager', - 'Validation Error'), - u'message':translate('OpenLP.ThemeManager', - 'File is not a valid theme.')}) + criticalErrorMessageBox( + translate('OpenLP.ThemeManager', 'Validation Error'), + translate('OpenLP.ThemeManager', + 'File is not a valid theme.')) log.exception(u'Theme file does not contain XML data %s' % filename) except (IOError, NameError): - Receiver.send_message(u'openlp_error_message', { - u'title': translate('OpenLP.ThemeManager', - 'Validation Error'), - u'message':translate('OpenLP.ThemeManager', - 'File is not a valid theme.')}) + criticalErrorMessageBox( + translate('OpenLP.ThemeManager', 'Validation Error'), + translate('OpenLP.ThemeManager', + 'File is not a valid theme.')) log.exception(u'Importing theme from zip failed %s' % filename) finally: if zip: @@ -566,11 +558,10 @@ class ThemeManager(QtGui.QWidget): """ theme_dir = os.path.join(self.path, themeName) if os.path.exists(theme_dir): - Receiver.send_message(u'openlp_error_message', { - u'title': translate('OpenLP.ThemeManager', - 'Validation Error'), - u'message':translate('OpenLP.ThemeManager', - 'A theme with this name already exists.')}) + criticalErrorMessageBox( + translate('OpenLP.ThemeManager', 'Validation Error'), + translate('OpenLP.ThemeManager', + 'A theme with this name already exists.')) return False return True @@ -587,10 +578,7 @@ class ThemeManager(QtGui.QWidget): theme_file = os.path.join(theme_dir, name + u'.xml') if imageTo and self.oldBackgroundImage and \ imageTo != self.oldBackgroundImage: - try: - os.remove(self.oldBackgroundImage) - except OSError: - log.exception(u'Unable to remove old theme background') + delete_file(self.oldBackgroundImage) outfile = None try: outfile = open(theme_file, u'w') @@ -700,21 +688,19 @@ class ThemeManager(QtGui.QWidget): return False # should be the same unless default if theme != unicode(item.data(QtCore.Qt.UserRole).toString()): - QtGui.QMessageBox.critical(self, - translate('OpenLP.ThemeManager', 'Error'), - translate('OpenLP.ThemeManager', - 'You are unable to delete the default theme.')) + criticalErrorMessageBox( + message=translate('OpenLP.ThemeManager', + 'You are unable to delete the default theme.')) return False # check for use in the system else where. if testPlugin: for plugin in self.mainwindow.pluginManager.plugins: if plugin.usesTheme(theme): - Receiver.send_message(u'openlp_error_message', { - u'title': translate('OpenLP.ThemeManager', + criticalErrorMessageBox(translate('OpenLP.ThemeManager', 'Validation Error'), - u'message': unicode(translate('OpenLP.ThemeManager', + unicode(translate('OpenLP.ThemeManager', 'Theme %s is used in the %s plugin.')) % \ - (theme, plugin.name)}) + (theme, plugin.name)) return False return True diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index d8012f433..9117a8e19 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -26,7 +26,6 @@ """ The :mod:`utils` module provides the utility libraries for OpenLP """ - import logging import os import re @@ -36,12 +35,18 @@ import urllib2 from datetime import datetime from PyQt4 import QtGui, QtCore +if sys.platform != u'win32' and sys.platform != u'darwin': + try: + from xdg import BaseDirectory + XDG_BASE_AVAILABLE = True + except ImportError: + XDG_BASE_AVAILABLE = False import openlp from openlp.core.lib import Receiver, translate log = logging.getLogger(__name__) -images_filter = None +IMAGES_FILTER = None class VersionThread(QtCore.QThread): """ @@ -113,77 +118,46 @@ class AppLocation(object): The directory type you want, for instance the data directory. """ if dir_type == AppLocation.AppDir: - if hasattr(sys, u'frozen') and sys.frozen == 1: - app_path = os.path.abspath(os.path.split(sys.argv[0])[0]) - else: - app_path = os.path.split(openlp.__file__)[0] - return app_path + return _get_frozen_path( + os.path.abspath(os.path.split(sys.argv[0])[0]), + os.path.split(openlp.__file__)[0]) elif dir_type == AppLocation.ConfigDir: - if sys.platform == u'win32': - path = os.path.join(os.getenv(u'APPDATA'), u'openlp') - elif sys.platform == u'darwin': - path = os.path.join(os.getenv(u'HOME'), u'Library', - u'Application Support', u'openlp') - else: - try: - from xdg import BaseDirectory - path = os.path.join( - BaseDirectory.xdg_config_home, u'openlp') - except ImportError: - path = os.path.join(os.getenv(u'HOME'), u'.openlp') - return path + return _get_os_dir_path(u'openlp', + os.path.join(os.getenv(u'HOME'), u'Library', + u'Application Support', u'openlp'), + os.path.join(BaseDirectory.xdg_config_home, u'openlp'), + os.path.join(os.getenv(u'HOME'), u'.openlp')) elif dir_type == AppLocation.DataDir: - if sys.platform == u'win32': - path = os.path.join(os.getenv(u'APPDATA'), u'openlp', u'data') - elif sys.platform == u'darwin': - path = os.path.join(os.getenv(u'HOME'), u'Library', - u'Application Support', u'openlp', u'Data') - else: - try: - from xdg import BaseDirectory - path = os.path.join(BaseDirectory.xdg_data_home, u'openlp') - except ImportError: - path = os.path.join(os.getenv(u'HOME'), u'.openlp', u'data') - return path + return _get_os_dir_path(os.path.join(u'openlp', u'data'), + os.path.join(os.getenv(u'HOME'), u'Library', + u'Application Support', u'openlp', u'Data'), + os.path.join(BaseDirectory.xdg_data_home, u'openlp'), + os.path.join(os.getenv(u'HOME'), u'.openlp', u'data')) elif dir_type == AppLocation.PluginsDir: - plugin_path = None app_path = os.path.abspath(os.path.split(sys.argv[0])[0]) - if hasattr(sys, u'frozen') and sys.frozen == 1: - plugin_path = os.path.join(app_path, u'plugins') - else: - plugin_path = os.path.join( - os.path.split(openlp.__file__)[0], u'plugins') - return plugin_path + return _get_frozen_path(os.path.join(app_path, u'plugins'), + os.path.join(os.path.split(openlp.__file__)[0], u'plugins')) elif dir_type == AppLocation.VersionDir: - if hasattr(sys, u'frozen') and sys.frozen == 1: - version_path = os.path.abspath(os.path.split(sys.argv[0])[0]) - else: - version_path = os.path.split(openlp.__file__)[0] - return version_path + return _get_frozen_path( + os.path.abspath(os.path.split(sys.argv[0])[0]), + os.path.split(openlp.__file__)[0]) elif dir_type == AppLocation.CacheDir: - if sys.platform == u'win32': - path = os.path.join(os.getenv(u'APPDATA'), u'openlp') - elif sys.platform == u'darwin': - path = os.path.join(os.getenv(u'HOME'), u'Library', - u'Application Support', u'openlp') - else: - try: - from xdg import BaseDirectory - path = os.path.join( - BaseDirectory.xdg_cache_home, u'openlp') - except ImportError: - path = os.path.join(os.getenv(u'HOME'), u'.openlp') - return path + return _get_os_dir_path(u'openlp', + os.path.join(os.getenv(u'HOME'), u'Library', + u'Application Support', u'openlp'), + os.path.join(BaseDirectory.xdg_cache_home, u'openlp'), + os.path.join(os.getenv(u'HOME'), u'.openlp')) if dir_type == AppLocation.LanguageDir: - if hasattr(sys, u'frozen') and sys.frozen == 1: - app_path = os.path.abspath(os.path.split(sys.argv[0])[0]) - else: - app_path = os.path.split(openlp.__file__)[0] + app_path = _get_frozen_path( + os.path.abspath(os.path.split(sys.argv[0])[0]), + os.path.split(openlp.__file__)[0]) return os.path.join(app_path, u'i18n') - @staticmethod def get_data_path(): + """ + Return the path OpenLP stores all its data under. + """ path = AppLocation.get_directory(AppLocation.DataDir) if not os.path.exists(path): os.makedirs(path) @@ -191,12 +165,38 @@ class AppLocation(object): @staticmethod def get_section_data_path(section): + """ + Return the path a particular module stores its data under. + """ data_path = AppLocation.get_data_path() path = os.path.join(data_path, section) if not os.path.exists(path): os.makedirs(path) return path +def _get_os_dir_path(win_option, darwin_option, base_dir_option, + non_base_dir_option): + """ + Return a path based on which OS and environment we are running in. + """ + if sys.platform == u'win32': + return os.path.join(os.getenv(u'APPDATA'), win_option) + elif sys.platform == u'darwin': + return darwin_option + else: + if XDG_BASE_AVAILABLE: + return base_dir_option + else: + return non_base_dir_option + +def _get_frozen_path(frozen_option, non_frozen_option): + """ + Return a path based on the system status. + """ + if hasattr(sys, u'frozen') and sys.frozen == 1: + return frozen_option + else: + return non_frozen_option def check_latest_version(current_version): """ @@ -225,9 +225,8 @@ def check_latest_version(current_version): remote_version = None try: remote_version = unicode(urllib2.urlopen(req, None).read()).strip() - except IOError, e: - if hasattr(e, u'reason'): - log.exception(u'Reason for failure: %s', e.reason) + except IOError: + log.exception(u'Failed to download the latest OpenLP version file') if remote_version: version_string = remote_version return version_string @@ -264,24 +263,44 @@ def get_images_filter(): Returns a filter string for a file dialog containing all the supported image formats. """ - global images_filter - if not images_filter: + global IMAGES_FILTER + if not IMAGES_FILTER: log.debug(u'Generating images filter.') formats = [unicode(fmt) for fmt in QtGui.QImageReader.supportedImageFormats()] visible_formats = u'(*.%s)' % u'; *.'.join(formats) actual_formats = u'(*.%s)' % u' *.'.join(formats) - images_filter = u'%s %s %s' % (translate('OpenLP', 'Image Files'), + IMAGES_FILTER = u'%s %s %s' % (translate('OpenLP', 'Image Files'), visible_formats, actual_formats) - return images_filter + return IMAGES_FILTER def split_filename(path): + """ + Return a list of the parts in a given path. + """ path = os.path.abspath(path) if not os.path.isfile(path): return path, u'' else: return os.path.split(path) +def delete_file(file_path_name): + """ + Deletes a file from the system. + + ``file_path_name`` + The file, including path, to delete. + """ + if not file_path_name: + return False + try: + if os.path.exists(file_path_name): + os.remove(file_path_name) + return True + except (IOError, OSError): + log.exception("Unable to delete file %s" % file_path_name) + return False + def get_web_page(url, header=None, update_openlp=False): """ Attempts to download the webpage at url and returns that page or None. diff --git a/openlp/plugins/bibles/forms/bibleimportform.py b/openlp/plugins/bibles/forms/bibleimportform.py index d79051126..d3f41804b 100644 --- a/openlp/plugins/bibles/forms/bibleimportform.py +++ b/openlp/plugins/bibles/forms/bibleimportform.py @@ -35,6 +35,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import Receiver, SettingsManager, translate from openlp.core.lib.db import delete_database +from openlp.core.ui import criticalErrorMessageBox from openlp.core.ui.wizard import OpenLPWizard from openlp.core.utils import AppLocation, string_is_unicode from openlp.plugins.bibles.lib.manager import BibleFormat @@ -468,7 +469,7 @@ class BibleImportForm(OpenLPWizard): elif self.currentPage() == self.selectPage: if self.field(u'source_format').toInt()[0] == BibleFormat.OSIS: if not self.field(u'osis_location').toString(): - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('BiblesPlugin.ImportWizardForm', 'Invalid Bible Location'), translate('BiblesPlugin.ImportWizardForm', @@ -478,7 +479,7 @@ class BibleImportForm(OpenLPWizard): return False elif self.field(u'source_format').toInt()[0] == BibleFormat.CSV: if not self.field(u'csv_booksfile').toString(): - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('BiblesPlugin.ImportWizardForm', 'Invalid Books File'), translate('BiblesPlugin.ImportWizardForm', @@ -487,7 +488,7 @@ class BibleImportForm(OpenLPWizard): self.csvBooksEdit.setFocus() return False elif not self.field(u'csv_versefile').toString(): - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('BiblesPlugin.ImportWizardForm', 'Invalid Verse File'), translate('BiblesPlugin.ImportWizardForm', @@ -498,7 +499,7 @@ class BibleImportForm(OpenLPWizard): elif self.field(u'source_format').toInt()[0] == \ BibleFormat.OpenSong: if not self.field(u'opensong_file').toString(): - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('BiblesPlugin.ImportWizardForm', 'Invalid OpenSong Bible'), translate('BiblesPlugin.ImportWizardForm', @@ -508,7 +509,7 @@ class BibleImportForm(OpenLPWizard): return False elif self.field(u'source_format').toInt()[0] == BibleFormat.OpenLP1: if not self.field(u'openlp1_location').toString(): - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('BiblesPlugin.ImportWizardForm', 'Invalid Bible Location'), translate('BiblesPlugin.ImportWizardForm', @@ -522,7 +523,7 @@ class BibleImportForm(OpenLPWizard): license_copyright = \ unicode(self.field(u'license_copyright').toString()) if not license_version: - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('BiblesPlugin.ImportWizardForm', 'Empty Version Name'), translate('BiblesPlugin.ImportWizardForm', @@ -530,7 +531,7 @@ class BibleImportForm(OpenLPWizard): self.versionNameEdit.setFocus() return False elif not license_copyright: - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('BiblesPlugin.ImportWizardForm', 'Empty Copyright'), translate('BiblesPlugin.ImportWizardForm', @@ -539,7 +540,7 @@ class BibleImportForm(OpenLPWizard): self.copyrightEdit.setFocus() return False elif self.manager.exists(license_version): - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('BiblesPlugin.ImportWizardForm', 'Bible Exists'), translate('BiblesPlugin.ImportWizardForm', 'This Bible already exists. Please import ' diff --git a/openlp/plugins/bibles/lib/db.py b/openlp/plugins/bibles/lib/db.py index 9f4376da1..f442a9cd6 100644 --- a/openlp/plugins/bibles/lib/db.py +++ b/openlp/plugins/bibles/lib/db.py @@ -33,8 +33,9 @@ from sqlalchemy import Column, ForeignKey, or_, Table, types from sqlalchemy.orm import class_mapper, mapper, relation from sqlalchemy.orm.exc import UnmappedClassError -from openlp.core.lib import Receiver, translate +from openlp.core.lib import translate from openlp.core.lib.db import BaseModel, init_db, Manager +from openlp.core.ui import criticalErrorMessageBox log = logging.getLogger(__name__) @@ -339,11 +340,11 @@ class BibleDB(QtCore.QObject, Manager): verse_list = [] for book, chapter, start_verse, end_verse in reference_list: db_book = self.get_book(book) - if end_verse == -1: - end_verse = self.get_verse_count(book, chapter) if db_book: book = db_book.name log.debug(u'Book name corrected to "%s"', book) + if end_verse == -1: + end_verse = self.get_verse_count(book, chapter) verses = self.session.query(Verse)\ .filter_by(book_id=db_book.id)\ .filter_by(chapter=chapter)\ @@ -354,12 +355,11 @@ class BibleDB(QtCore.QObject, Manager): verse_list.extend(verses) else: log.debug(u'OpenLP failed to find book %s', book) - Receiver.send_message(u'openlp_error_message', { - u'title': translate('BiblesPlugin', 'No Book Found'), - u'message': translate('BiblesPlugin', 'No matching book ' + criticalErrorMessageBox( + translate('BiblesPlugin', 'No Book Found'), + translate('BiblesPlugin', 'No matching book ' 'could be found in this Bible. Check that you have ' - 'spelled the name of the book correctly.') - }) + 'spelled the name of the book correctly.')) return verse_list def verse_search(self, text): diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py index 6f6b861e9..b844bbe61 100644 --- a/openlp/plugins/bibles/lib/http.py +++ b/openlp/plugins/bibles/lib/http.py @@ -38,6 +38,7 @@ from HTMLParser import HTMLParseError from BeautifulSoup import BeautifulSoup, NavigableString from openlp.core.lib import Receiver, translate +from openlp.core.ui import criticalErrorMessageBox from openlp.core.utils import AppLocation, get_web_page from openlp.plugins.bibles.lib import SearchResults from openlp.plugins.bibles.lib.db import BibleDB, Book @@ -429,12 +430,11 @@ class HTTPBible(BibleDB): if not db_book: book_details = HTTPBooks.get_book(book) if not book_details: - Receiver.send_message(u'openlp_error_message', { - u'title': translate('BiblesPlugin', 'No Book Found'), - u'message': translate('BiblesPlugin', 'No matching ' + criticalErrorMessageBox( + translate('BiblesPlugin', 'No Book Found'), + translate('BiblesPlugin', 'No matching ' 'book could be found in this Bible. Check that you ' - 'have spelled the name of the book correctly.') - }) + 'have spelled the name of the book correctly.')) return [] db_book = self.create_book(book_details[u'name'], book_details[u'abbreviation'], @@ -540,17 +540,15 @@ def send_error_message(error_type): The type of error that occured for the issue. """ if error_type == u'download': - Receiver.send_message(u'openlp_error_message', { - u'title': translate('BiblePlugin.HTTPBible', 'Download Error'), - u'message': translate('BiblePlugin.HTTPBible', 'There was a ' + criticalErrorMessageBox( + translate('BiblePlugin.HTTPBible', 'Download Error'), + translate('BiblePlugin.HTTPBible', 'There was a ' 'problem downloading your verse selection. Please check your ' 'Internet connection, and if this error continues to occur ' - 'please consider reporting a bug.') - }) + 'please consider reporting a bug.')) elif error_type == u'parse': - Receiver.send_message(u'openlp_error_message', { - u'title': translate('BiblePlugin.HTTPBible', 'Parse Error'), - u'message': translate('BiblePlugin.HTTPBible', 'There was a ' + criticalErrorMessageBox( + translate('BiblePlugin.HTTPBible', 'Parse Error'), + translate('BiblePlugin.HTTPBible', 'There was a ' 'problem extracting your verse selection. If this error continues ' - 'to occur please consider reporting a bug.') - }) + 'to occur please consider reporting a bug.')) diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index 7ee450c8a..4ecd4b49e 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -30,6 +30,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import MediaManagerItem, Receiver, BaseListWithDnD, \ ItemCapabilities, translate +from openlp.core.ui import criticalErrorMessageBox from openlp.plugins.bibles.forms import BibleImportForm from openlp.plugins.bibles.lib import get_reference_match @@ -389,11 +390,8 @@ class BibleMediaItem(MediaManagerItem): verse_count = self.parent.manager.get_verse_count(bible, book, 1) if verse_count == 0: self.advancedSearchButton.setEnabled(False) - Receiver.send_message(u'openlp_error_message', { - u'title': translate('BiblePlugin.MediaItem', 'Error'), - u'message': translate('BiblePlugin.MediaItem', - 'Bible not fully loaded') - }) + criticalErrorMessageBox(message=translate('BiblePlugin.MediaItem', + 'Bible not fully loaded')) else: self.advancedSearchButton.setEnabled(True) self.adjustComboBox(1, self.chapter_count, self.advancedFromChapter) @@ -534,13 +532,11 @@ class BibleMediaItem(MediaManagerItem): 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 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: + elif criticalErrorMessageBox( + message=translate('BiblePlugin.MediaItem', + 'You cannot combine single and second bible verses. Do you ' + 'want to delete your search results and start a new search?'), + parent=self, question=True) == QtGui.QMessageBox.Yes: self.listView.clear() self.displayResults(bible, second_bible) else: @@ -584,13 +580,11 @@ class BibleMediaItem(MediaManagerItem): 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 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: + elif criticalErrorMessageBox( + message=translate('BiblePlugin.MediaItem', + 'You cannot combine single and second bible verses. Do you ' + 'want to delete your search results and start a new search?'), + parent=self, question=True) == QtGui.QMessageBox.Yes: self.listView.clear() self.displayResults(bible, second_bible) elif self.search_results: diff --git a/openlp/plugins/bibles/lib/opensong.py b/openlp/plugins/bibles/lib/opensong.py index 2b3b6dfb7..12a6562bc 100644 --- a/openlp/plugins/bibles/lib/opensong.py +++ b/openlp/plugins/bibles/lib/opensong.py @@ -79,7 +79,7 @@ class OpenSongBible(BibleDB): break self.create_verse( db_book.id, - int(chapter.attrib[u'n']), + int(chapter.attrib[u'n'].split()[-1]), int(verse.attrib[u'n']), unicode(verse.text) ) @@ -87,7 +87,7 @@ class OpenSongBible(BibleDB): self.wizard.incrementProgressBar(unicode(translate( 'BiblesPlugin.Opensong', 'Importing %s %s...', 'Importing ...')) % - (db_book.name, int(chapter.attrib[u'n']))) + (db_book.name, int(chapter.attrib[u'n'].split()[-1]))) self.session.commit() except (IOError, AttributeError): log.exception(u'Loading bible from OpenSong file failed') diff --git a/openlp/plugins/custom/forms/editcustomform.py b/openlp/plugins/custom/forms/editcustomform.py index 2f005828a..ebc917e99 100644 --- a/openlp/plugins/custom/forms/editcustomform.py +++ b/openlp/plugins/custom/forms/editcustomform.py @@ -29,6 +29,7 @@ import logging from PyQt4 import QtCore, QtGui from openlp.core.lib import Receiver, translate +from openlp.core.ui import criticalErrorMessageBox from openlp.plugins.custom.lib import CustomXMLBuilder, CustomXMLParser from openlp.plugins.custom.lib.db import CustomSlide from editcustomdialog import Ui_CustomEditDialog @@ -151,8 +152,7 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog): """ valid, message = self._validate() if not valid: - QtGui.QMessageBox.critical(self, - translate('CustomPlugin.EditCustomForm', 'Error'), message) + criticalErrorMessageBox(message=message) return False sxml = CustomXMLBuilder() sxml.new_document() @@ -265,4 +265,4 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog): if self.slideListView.count() == 0: return False, translate('CustomPlugin.EditCustomForm', 'You need to add at least one slide') - return True, u'' \ No newline at end of file + return True, u'' diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index 063a80d02..bd84219fb 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -31,8 +31,9 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import MediaManagerItem, BaseListWithDnD, build_icon, \ ItemCapabilities, SettingsManager, translate, check_item_selected, \ - Receiver, check_directory_exists -from openlp.core.utils import AppLocation, get_images_filter + check_directory_exists +from openlp.core.ui import criticalErrorMessageBox +from openlp.core.utils import AppLocation, delete_file, get_images_filter log = logging.getLogger(__name__) @@ -115,12 +116,8 @@ class ImageMediaItem(MediaManagerItem): for row in row_list: text = self.listView.item(row) if text: - try: - os.remove(os.path.join(self.servicePath, - unicode(text.text()))) - except OSError: - # if not present do not worry - pass + delete_file(os.path.join(self.servicePath, + unicode(text.text()))) self.listView.takeItem(row) SettingsManager.set_list(self.settingsSection, self.settingsSection, self.getFileList()) @@ -164,7 +161,7 @@ class ImageMediaItem(MediaManagerItem): items.remove(item) # We cannot continue, as all images do not exist. if not items: - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('ImagePlugin.MediaItem', 'Missing Image(s)'), unicode(translate('ImagePlugin.MediaItem', 'The following image(s) no longer exist: %s')) % @@ -190,12 +187,15 @@ class ImageMediaItem(MediaManagerItem): return False def onResetClick(self): + """ + Called to reset the Live backgound with the image selected, + """ self.resetAction.setVisible(False) self.parent.liveController.display.resetImage() def onReplaceClick(self): """ - Called to replace Live backgound with the video selected + Called to replace Live backgound with the image selected. """ if check_item_selected(self.listView, translate('ImagePlugin.MediaItem', @@ -208,12 +208,11 @@ class ImageMediaItem(MediaManagerItem): self.parent.liveController.display.directImage(name, filename) self.resetAction.setVisible(True) else: - Receiver.send_message(u'openlp_error_message', { - u'title': translate('ImagePlugin.MediaItem', - 'Live Background Error'), - u'message': unicode(translate('ImagePlugin.MediaItem', + criticalErrorMessageBox( + translate('ImagePlugin.MediaItem', 'Live Background Error'), + unicode(translate('ImagePlugin.MediaItem', 'There was a problem replacing your background, ' - 'the image file "%s" no longer exists.')) % filename}) + 'the image file "%s" no longer exists.')) % filename) def onPreviewClick(self): - MediaManagerItem.onPreviewClick(self) \ No newline at end of file + MediaManagerItem.onPreviewClick(self) diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index cc75dfc2b..121fa80a0 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -30,8 +30,8 @@ import os from PyQt4 import QtCore, QtGui from openlp.core.lib import MediaManagerItem, BaseListWithDnD, build_icon, \ - ItemCapabilities, SettingsManager, translate, check_item_selected, \ - Receiver + ItemCapabilities, SettingsManager, translate, check_item_selected +from openlp.core.ui import criticalErrorMessageBox log = logging.getLogger(__name__) @@ -40,6 +40,7 @@ class MediaListView(BaseListWithDnD): self.PluginName = u'Media' BaseListWithDnD.__init__(self, parent) + class MediaMediaItem(MediaManagerItem): """ This is the custom media manager item for Media Slides. @@ -92,10 +93,16 @@ class MediaMediaItem(MediaManagerItem): self.resetAction.setVisible(False) def onResetClick(self): + """ + Called to reset the Live backgound with the media selected, + """ self.resetAction.setVisible(False) self.parent.liveController.display.resetVideo() def onReplaceClick(self): + """ + Called to replace Live backgound with the media selected. + """ if check_item_selected(self.listView, translate('MediaPlugin.MediaItem', 'You must select a media file to replace the background with.')): @@ -106,12 +113,11 @@ class MediaMediaItem(MediaManagerItem): self.parent.liveController.display.video(filename, 0, True) self.resetAction.setVisible(True) else: - Receiver.send_message(u'openlp_error_message', { - u'title': translate('MediaPlugin.MediaItem', + criticalErrorMessageBox(translate('MediaPlugin.MediaItem', 'Live Background Error'), - u'message': unicode(translate('MediaPlugin.MediaItem', + unicode(translate('MediaPlugin.MediaItem', 'There was a problem replacing your background, ' - 'the media file "%s" no longer exists.')) % filename}) + 'the media file "%s" no longer exists.')) % filename) def generateSlideData(self, service_item, item=None, xmlVersion=False): if item is None: @@ -131,9 +137,8 @@ class MediaMediaItem(MediaManagerItem): return True else: # File is no longer present - QtGui.QMessageBox.critical( - self, translate('MediaPlugin.MediaItem', - 'Missing Media File'), + criticalErrorMessageBox( + translate('MediaPlugin.MediaItem', 'Missing Media File'), unicode(translate('MediaPlugin.MediaItem', 'The file %s no longer exists.')) % filename) return False diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index 7c8cf593d..516c595c7 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -51,6 +51,7 @@ else: from PyQt4 import QtCore +from openlp.core.utils import delete_file from presentationcontroller import PresentationController, PresentationDocument log = logging.getLogger(__name__) @@ -292,8 +293,7 @@ class ImpressDocument(PresentationDocument): try: doc.storeToURL(urlpath, props) self.convert_thumbnail(path, idx + 1) - if os.path.exists(path): - os.remove(path) + delete_file(path) except: log.exception(u'%s - Unable to store openoffice preview' % path) diff --git a/openlp/plugins/presentations/lib/mediaitem.py b/openlp/plugins/presentations/lib/mediaitem.py index 1e65a3358..2c9381a70 100644 --- a/openlp/plugins/presentations/lib/mediaitem.py +++ b/openlp/plugins/presentations/lib/mediaitem.py @@ -31,6 +31,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import MediaManagerItem, BaseListWithDnD, build_icon, \ SettingsManager, translate, check_item_selected, Receiver, ItemCapabilities +from openlp.core.ui import criticalErrorMessageBox from openlp.plugins.presentations.lib import MessageListener log = logging.getLogger(__name__) @@ -180,7 +181,7 @@ class PresentationMediaItem(MediaManagerItem): filename = os.path.split(unicode(file))[1] if titles.count(filename) > 0: if not initialLoad: - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('PresentationPlugin.MediaItem', 'File Exists'), translate('PresentationPlugin.MediaItem', @@ -204,7 +205,7 @@ class PresentationMediaItem(MediaManagerItem): if initialLoad: icon = build_icon(u':/general/general_delete.png') else: - QtGui.QMessageBox.critical( + criticalErrorMessageBox( self, translate('PresentationPlugin.MediaItem', 'Unsupported File'), translate('PresentationPlugin.MediaItem', @@ -275,8 +276,8 @@ class PresentationMediaItem(MediaManagerItem): return True else: # File is no longer present - QtGui.QMessageBox.critical( - self, translate('PresentationPlugin.MediaItem', + criticalErrorMessageBox( + translate('PresentationPlugin.MediaItem', 'Missing Presentation'), unicode(translate('PresentationPlugin.MediaItem', 'The Presentation %s no longer exists.')) % filename) diff --git a/openlp/plugins/songs/forms/authorsform.py b/openlp/plugins/songs/forms/authorsform.py index 320d3c1d3..091618bde 100644 --- a/openlp/plugins/songs/forms/authorsform.py +++ b/openlp/plugins/songs/forms/authorsform.py @@ -27,6 +27,7 @@ from PyQt4 import QtGui, QtCore from openlp.core.lib import translate +from openlp.core.ui import criticalErrorMessageBox from openlp.plugins.songs.forms.authorsdialog import Ui_AuthorsDialog class AuthorsForm(QtGui.QDialog, Ui_AuthorsDialog): @@ -79,28 +80,21 @@ class AuthorsForm(QtGui.QDialog, Ui_AuthorsDialog): def accept(self): if not self.firstNameEdit.text(): - QtGui.QMessageBox.critical( - self, translate('SongsPlugin.AuthorsForm', 'Error'), - translate('SongsPlugin.AuthorsForm', - 'You need to type in the first name of the author.')) + criticalErrorMessageBox(message=translate('SongsPlugin.AuthorsForm', + 'You need to type in the first name of the author.')) self.firstNameEdit.setFocus() return False elif not self.lastNameEdit.text(): - QtGui.QMessageBox.critical( - self, translate('SongsPlugin.AuthorsForm', 'Error'), - translate('SongsPlugin.AuthorsForm', - 'You need to type in the last name of the author.')) + criticalErrorMessageBox(message=translate('SongsPlugin.AuthorsForm', + 'You need to type in the last name of the author.')) self.lastNameEdit.setFocus() return False elif not self.displayEdit.text(): - if QtGui.QMessageBox.critical( - self, translate('SongsPlugin.AuthorsForm', 'Error'), - translate('SongsPlugin.AuthorsForm', - 'You have not set a display name for the ' - 'author, combine the first and last names?'), - QtGui.QMessageBox.StandardButtons( - QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) - ) == QtGui.QMessageBox.Yes: + if criticalErrorMessageBox( + message=translate('SongsPlugin.AuthorsForm', + 'You have not set a display name for the ' + 'author, combine the first and last names?'), + parent=self, question=True) == QtGui.QMessageBox.Yes: self.displayEdit.setText(self.firstNameEdit.text() + \ u' ' + self.lastNameEdit.text()) return QtGui.QDialog.accept(self) diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index 86249f024..8a7157e29 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -30,6 +30,7 @@ import re from PyQt4 import QtCore, QtGui from openlp.core.lib import Receiver, translate +from openlp.core.ui import criticalErrorMessageBox from openlp.plugins.songs.forms import EditVerseForm from openlp.plugins.songs.lib import SongXML, VerseType from openlp.plugins.songs.lib.db import Book, Song, Author, Topic @@ -346,10 +347,9 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): author = self.manager.get_object(Author, item_id) if self.authorsListView.findItems(unicode(author.display_name), QtCore.Qt.MatchExactly): - QtGui.QMessageBox.warning(self, - translate('SongsPlugin.EditSongForm', 'Error'), - translate('SongsPlugin.EditSongForm', 'This author is ' - 'already in the list.')) + criticalErrorMessageBox( + message=translate('SongsPlugin.EditSongForm', + 'This author is already in the list.')) else: author_item = QtGui.QListWidgetItem(unicode( author.display_name)) @@ -400,10 +400,9 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): topic = self.manager.get_object(Topic, item_id) if self.topicsListView.findItems(unicode(topic.name), QtCore.Qt.MatchExactly): - QtGui.QMessageBox.warning(self, - translate('SongsPlugin.EditSongForm', 'Error'), - translate('SongsPlugin.EditSongForm', 'This topic is ' - 'already in the list.')) + criticalErrorMessageBox( + message=translate('SongsPlugin.EditSongForm', + 'This topic is already in the list.')) else: topic_item = QtGui.QListWidgetItem(unicode(topic.name)) topic_item.setData(QtCore.Qt.UserRole, @@ -525,38 +524,36 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): def _validate_song(self): """ - Check the validity of the form. Only display the 'save' if the data - can be saved. + Check the validity of the song. """ + # This checks data in the form *not* self.song. self.song is still + # None at this point. log.debug(u'Validate Song') # Lets be nice and assume the data is correct. - if len(self.titleEdit.displayText()) == 0: + if not self.titleEdit.text(): self.songTabWidget.setCurrentIndex(0) self.titleEdit.setFocus() - QtGui.QMessageBox.critical(self, - translate('SongsPlugin.EditSongForm', 'Error'), - translate('SongsPlugin.EditSongForm', + criticalErrorMessageBox( + message=translate('SongsPlugin.EditSongForm', 'You need to type in a song title.')) return False if self.verseListWidget.rowCount() == 0: self.songTabWidget.setCurrentIndex(0) self.verseListWidget.setFocus() - QtGui.QMessageBox.critical(self, - translate('SongsPlugin.EditSongForm', 'Error'), - translate('SongsPlugin.EditSongForm', + criticalErrorMessageBox( + message=translate('SongsPlugin.EditSongForm', 'You need to type in at least one verse.')) return False if self.authorsListView.count() == 0: self.songTabWidget.setCurrentIndex(1) self.authorsListView.setFocus() - QtGui.QMessageBox.critical(self, - translate('SongsPlugin.EditSongForm', 'Warning'), - translate('SongsPlugin.EditSongForm', + criticalErrorMessageBox( + message=translate('SongsPlugin.EditSongForm', 'You need to have an author for this song.')) return False - if self.song.verse_order: + if self.verseOrderEdit.text(): order = [] - order_names = self.song.verse_order.split() + order_names = self.verseOrderEdit.text().split() for item in order_names: if len(item) == 1: order.append(item.lower() + u'1') @@ -578,9 +575,8 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): valid = verses.pop(0) for verse in verses: valid = valid + u', ' + verse - QtGui.QMessageBox.critical(self, - translate('SongsPlugin.EditSongForm', 'Error'), - unicode(translate('SongsPlugin.EditSongForm', + criticalErrorMessageBox( + message=unicode(translate('SongsPlugin.EditSongForm', 'The verse order is invalid. There is no verse ' 'corresponding to %s. Valid entries are %s.')) % \ (order_names[count], valid)) @@ -598,6 +594,19 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) if answer == QtGui.QMessageBox.No: return False + item = int(self.songBookComboBox.currentIndex()) + text = unicode(self.songBookComboBox.currentText()) + if self.songBookComboBox.findText(text, QtCore.Qt.MatchExactly) < 0: + if QtGui.QMessageBox.question(self, + translate('SongsPlugin.EditSongForm', 'Add Book'), + translate('SongsPlugin.EditSongForm', 'This song book does ' + 'not exist, do you want to add it?'), + QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, + QtGui.QMessageBox.Yes) == QtGui.QMessageBox.Yes: + book = Book.populate(name=text, publisher=u'') + self.manager.save_object(book) + else: + return False return True def onCopyrightInsertButtonTriggered(self): @@ -654,37 +663,29 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): def accept(self): """ - Exit Dialog and save soong if valid + Exit Dialog and save song if valid """ log.debug(u'accept') self.clearCaches() - if not self.song: - self.song = Song() - item = int(self.songBookComboBox.currentIndex()) - text = unicode(self.songBookComboBox.currentText()) - if self.songBookComboBox.findText(text, QtCore.Qt.MatchExactly) < 0: - if QtGui.QMessageBox.question(self, - translate('SongsPlugin.EditSongForm', 'Add Book'), - translate('SongsPlugin.EditSongForm', 'This song book does ' - 'not exist, do you want to add it?'), - QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, - QtGui.QMessageBox.Yes) == QtGui.QMessageBox.Yes: - book = Book.populate(name=text, publisher=u'') - self.manager.save_object(book) - else: - return - if self.saveSong(): + if self._validate_song(): + self.saveSong() Receiver.send_message(u'songs_load_list') self.close() def saveSong(self, preview=False): """ Get all the data from the widgets on the form, and then save it to the - database. + database. The form has been validated and all reference items + (Authors, Books and Topics) have been saved before this function is + called. ``preview`` Should be ``True`` if the song is also previewed (boolean). """ + # The Song() assignment. No database calls should be made while a + # Song() is in a partially complete state. + if not self.song: + self.song = Song() self.song.title = unicode(self.titleEdit.text()) self.song.alternate_title = unicode(self.alternativeEdit.text()) self.song.copyright = unicode(self.copyrightEdit.text()) @@ -708,27 +709,27 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): self.song.theme_name = theme_name else: self.song.theme_name = None - if self._validate_song(): - self.processLyrics() - self.processTitle() - self.song.authors = [] - for row in range(self.authorsListView.count()): - item = self.authorsListView.item(row) - authorId = (item.data(QtCore.Qt.UserRole)).toInt()[0] - self.song.authors.append(self.manager.get_object(Author, - authorId)) - self.song.topics = [] - for row in range(self.topicsListView.count()): - item = self.topicsListView.item(row) - topicId = (item.data(QtCore.Qt.UserRole)).toInt()[0] - self.song.topics.append(self.manager.get_object(Topic, topicId)) - self.manager.save_object(self.song) - if not preview: - self.song = None - return True - return False + self.processLyrics() + self.processTitle() + self.song.authors = [] + for row in range(self.authorsListView.count()): + item = self.authorsListView.item(row) + authorId = (item.data(QtCore.Qt.UserRole)).toInt()[0] + self.song.authors.append(self.manager.get_object(Author, authorId)) + self.song.topics = [] + for row in range(self.topicsListView.count()): + item = self.topicsListView.item(row) + topicId = (item.data(QtCore.Qt.UserRole)).toInt()[0] + self.song.topics.append(self.manager.get_object(Topic, topicId)) + self.manager.save_object(self.song) + if not preview: + self.song = None def processLyrics(self): + """ + Process the lyric data entered by the user into the OpenLP XML format. + """ + # This method must only be run after the self.song = Song() assignment. log.debug(u'processLyrics') try: sxml = SongXML() @@ -754,6 +755,11 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): sxml.dump_xml()) def processTitle(self): + """ + Process the song title entered by the user to remove stray punctuation + characters. + """ + # This method must only be run after the self.song = Song() assignment. log.debug(u'processTitle') self.song.search_title = re.sub(r'[\'"`,;:(){}?]+', u'', unicode(self.song.search_title)).lower() diff --git a/openlp/plugins/songs/forms/editverseform.py b/openlp/plugins/songs/forms/editverseform.py index c01ad9726..c10e48cb7 100644 --- a/openlp/plugins/songs/forms/editverseform.py +++ b/openlp/plugins/songs/forms/editverseform.py @@ -29,6 +29,7 @@ import logging from PyQt4 import QtCore, QtGui +from openlp.core.ui import criticalErrorMessageBox from openlp.plugins.songs.lib import VerseType, translate from editversedialog import Ui_EditVerseDialog @@ -167,9 +168,8 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog): else: value = self.getVerse()[0].split(u'\n')[1] if len(value) == 0: - QtGui.QMessageBox.critical(self, - translate('SongsPlugin.EditSongForm', 'Error'), - translate('SongsPlugin.EditSongForm', + criticalErrorMessageBox( + message=translate('SongsPlugin.EditSongForm', 'You need to type some text in to the verse.')) return False QtGui.QDialog.accept(self) diff --git a/openlp/plugins/songs/forms/songbookform.py b/openlp/plugins/songs/forms/songbookform.py index 4a4a08ff6..8341a7c4c 100644 --- a/openlp/plugins/songs/forms/songbookform.py +++ b/openlp/plugins/songs/forms/songbookform.py @@ -27,6 +27,7 @@ from PyQt4 import QtGui from openlp.core.lib import translate +from openlp.core.ui import criticalErrorMessageBox from openlp.plugins.songs.forms.songbookdialog import Ui_SongBookDialog class SongBookForm(QtGui.QDialog, Ui_SongBookDialog): @@ -49,10 +50,9 @@ class SongBookForm(QtGui.QDialog, Ui_SongBookDialog): def accept(self): if not self.nameEdit.text(): - QtGui.QMessageBox.critical( - self, translate('SongsPlugin.SongBookForm', 'Error'), - translate('SongsPlugin.SongBookForm', - 'You need to type in a name for the book.')) + criticalErrorMessageBox( + message=translate('SongsPlugin.SongBookForm', + 'You need to type in a name for the book.')) self.nameEdit.setFocus() return False else: diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py index 22a7ab61f..4cd4c6713 100644 --- a/openlp/plugins/songs/forms/songimportform.py +++ b/openlp/plugins/songs/forms/songimportform.py @@ -32,6 +32,7 @@ import os from PyQt4 import QtCore, QtGui from openlp.core.lib import Receiver, SettingsManager, translate +from openlp.core.ui import criticalErrorMessageBox from openlp.core.ui.wizard import OpenLPWizard from openlp.plugins.songs.lib.importer import SongFormat @@ -325,7 +326,7 @@ class SongImportForm(OpenLPWizard): source_format = self.formatComboBox.currentIndex() if source_format == SongFormat.OpenLP2: if self.openLP2FilenameEdit.text().isEmpty(): - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('SongsPlugin.ImportWizardForm', 'No OpenLP 2.0 Song Database Selected'), translate('SongsPlugin.ImportWizardForm', @@ -335,7 +336,7 @@ class SongImportForm(OpenLPWizard): return False elif source_format == SongFormat.OpenLP1: if self.openLP1FilenameEdit.text().isEmpty(): - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('SongsPlugin.ImportWizardForm', 'No openlp.org 1.x Song Database Selected'), translate('SongsPlugin.ImportWizardForm', @@ -345,7 +346,7 @@ class SongImportForm(OpenLPWizard): return False elif source_format == SongFormat.OpenLyrics: if self.openLyricsFileListWidget.count() == 0: - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('SongsPlugin.ImportWizardForm', 'No OpenLyrics Files Selected'), translate('SongsPlugin.ImportWizardForm', @@ -355,7 +356,7 @@ class SongImportForm(OpenLPWizard): return False elif source_format == SongFormat.OpenSong: if self.openSongFileListWidget.count() == 0: - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('SongsPlugin.ImportWizardForm', 'No OpenSong Files Selected'), translate('SongsPlugin.ImportWizardForm', @@ -365,7 +366,7 @@ class SongImportForm(OpenLPWizard): return False elif source_format == SongFormat.WordsOfWorship: if self.wordsOfWorshipFileListWidget.count() == 0: - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('SongsPlugin.ImportWizardForm', 'No Words of Worship Files Selected'), translate('SongsPlugin.ImportWizardForm', @@ -375,7 +376,7 @@ class SongImportForm(OpenLPWizard): return False elif source_format == SongFormat.CCLI: if self.ccliFileListWidget.count() == 0: - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('SongsPlugin.ImportWizardForm', 'No CCLI Files Selected'), translate('SongsPlugin.ImportWizardForm', @@ -385,7 +386,7 @@ class SongImportForm(OpenLPWizard): return False elif source_format == SongFormat.SongsOfFellowship: if self.songsOfFellowshipFileListWidget.count() == 0: - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('SongsPlugin.ImportWizardForm', 'No Songs of Fellowship File Selected'), translate('SongsPlugin.ImportWizardForm', @@ -395,7 +396,7 @@ class SongImportForm(OpenLPWizard): return False elif source_format == SongFormat.Generic: if self.genericFileListWidget.count() == 0: - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('SongsPlugin.ImportWizardForm', 'No Document/Presentation Selected'), translate('SongsPlugin.ImportWizardForm', @@ -405,7 +406,7 @@ class SongImportForm(OpenLPWizard): return False elif source_format == SongFormat.EasyWorship: if self.ewFilenameEdit.text().isEmpty(): - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('SongsPlugin.ImportWizardForm', 'No EasyWorship Song Database Selected'), translate('SongsPlugin.ImportWizardForm', @@ -415,7 +416,7 @@ class SongImportForm(OpenLPWizard): return False elif source_format == SongFormat.SongBeamer: if self.songBeamerFileListWidget.count() == 0: - QtGui.QMessageBox.critical(self, + criticalErrorMessageBox( translate('SongsPlugin.ImportWizardForm', 'No SongBeamer File Selected'), translate('SongsPlugin.ImportWizardForm', diff --git a/openlp/plugins/songs/forms/songmaintenanceform.py b/openlp/plugins/songs/forms/songmaintenanceform.py index c964c5192..cd10dca9b 100644 --- a/openlp/plugins/songs/forms/songmaintenanceform.py +++ b/openlp/plugins/songs/forms/songmaintenanceform.py @@ -23,15 +23,19 @@ # with this program; if not, write to the Free Software Foundation, Inc., 59 # # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### +import logging from PyQt4 import QtGui, QtCore from sqlalchemy.sql import and_ from openlp.core.lib import Receiver, translate +from openlp.core.ui import criticalErrorMessageBox from openlp.plugins.songs.forms import AuthorsForm, TopicsForm, SongBookForm from openlp.plugins.songs.lib.db import Author, Book, Topic, Song from songmaintenancedialog import Ui_SongMaintenanceDialog +log = logging.getLogger(__name__) + class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog): """ Class documentation goes here. @@ -87,15 +91,14 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog): if item_id != -1: item = self.manager.get_object(item_class, item_id) if item and len(item.songs) == 0: - if QtGui.QMessageBox.warning(self, dlg_title, del_text, - QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | - QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.Yes: + if criticalErrorMessageBox(title=dlg_title, message=del_text, + parent=self, question=True) == QtGui.QMessageBox.Yes: self.manager.delete_object(item_class, item.id) reset_func() else: - QtGui.QMessageBox.critical(self, dlg_title, err_text) + criticalErrorMessageBox(dlg_title, err_text) else: - QtGui.QMessageBox.critical(self, dlg_title, sel_text) + criticalErrorMessageBox(dlg_title, sel_text) def resetAuthors(self): """ @@ -229,14 +232,12 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog): if self.manager.save_object(author): self.resetAuthors() else: - QtGui.QMessageBox.critical(self, - translate('SongsPlugin.SongMaintenanceForm', 'Error'), - translate('SongsPlugin.SongMaintenanceForm', + criticalErrorMessageBox( + message=translate('SongsPlugin.SongMaintenanceForm', 'Could not add your author.')) else: - QtGui.QMessageBox.critical(self, - translate('SongsPlugin.SongMaintenanceForm', 'Error'), - translate('SongsPlugin.SongMaintenanceForm', + criticalErrorMessageBox( + message=translate('SongsPlugin.SongMaintenanceForm', 'This author already exists.')) def onTopicAddButtonClick(self): @@ -246,14 +247,12 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog): if self.manager.save_object(topic): self.resetTopics() else: - QtGui.QMessageBox.critical(self, - translate('SongsPlugin.SongMaintenanceForm', 'Error'), - translate('SongsPlugin.SongMaintenanceForm', + criticalErrorMessageBox( + message=translate('SongsPlugin.SongMaintenanceForm', 'Could not add your topic.')) else: - QtGui.QMessageBox.critical(self, - translate('SongsPlugin.SongMaintenanceForm', 'Error'), - translate('SongsPlugin.SongMaintenanceForm', + criticalErrorMessageBox( + message=translate('SongsPlugin.SongMaintenanceForm', 'This topic already exists.')) def onBookAddButtonClick(self): @@ -264,14 +263,12 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog): if self.manager.save_object(book): self.resetBooks() else: - QtGui.QMessageBox.critical(self, - translate('SongsPlugin.SongMaintenanceForm', 'Error'), - translate('SongsPlugin.SongMaintenanceForm', + criticalErrorMessageBox( + message=translate('SongsPlugin.SongMaintenanceForm', 'Could not add your book.')) else: - QtGui.QMessageBox.critical(self, - translate('SongsPlugin.SongMaintenanceForm', 'Error'), - translate('SongsPlugin.SongMaintenanceForm', + criticalErrorMessageBox( + message=translate('SongsPlugin.SongMaintenanceForm', 'This book already exists.')) def onAuthorEditButtonClick(self): @@ -298,20 +295,15 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog): self.resetAuthors() Receiver.send_message(u'songs_load_list') else: - QtGui.QMessageBox.critical(self, - translate('SongsPlugin.SongMaintenanceForm', - 'Error'), - translate('SongsPlugin.SongMaintenanceForm', + criticalErrorMessageBox( + message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your changes.')) - elif QtGui.QMessageBox.critical(self, - translate('SongsPlugin.SongMaintenanceForm', 'Error'), - unicode(translate('SongsPlugin.SongMaintenanceForm', - 'The author %s already exists. Would you like to make songs' - ' with author %s use the existing author %s?')) % - (author.display_name, temp_display_name, - author.display_name), QtGui.QMessageBox.StandardButtons( - QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == \ - QtGui.QMessageBox.Yes: + elif criticalErrorMessageBox(message=unicode(translate( + 'SongsPlugin.SongMaintenanceForm', 'The author %s already ' + 'exists. Would you like to make songs with author %s use ' + 'the existing author %s?')) % (author.display_name, + temp_display_name, author.display_name), + parent=self, question=True) == QtGui.QMessageBox.Yes: self.mergeAuthors(author) self.resetAuthors() Receiver.send_message(u'songs_load_list') @@ -321,9 +313,8 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog): author.first_name = temp_first_name author.last_name = temp_last_name author.display_name = temp_display_name - QtGui.QMessageBox.critical(self, - translate('SongsPlugin.SongMaintenanceForm', 'Error'), - translate('SongsPlugin.SongMaintenanceForm', + criticalErrorMessageBox( + message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your modified author, because the ' 'author already exists.')) @@ -340,27 +331,22 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog): if self.manager.save_object(topic): self.resetTopics() else: - QtGui.QMessageBox.critical(self, - translate('SongsPlugin.SongMaintenanceForm', - 'Error'), - translate('SongsPlugin.SongMaintenanceForm', + criticalErrorMessageBox( + message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your changes.')) - elif QtGui.QMessageBox.critical(self, - translate('SongsPlugin.SongMaintenanceForm', 'Error'), - unicode(translate('SongsPlugin.SongMaintenanceForm', + elif criticalErrorMessageBox( + message=unicode(translate('SongsPlugin.SongMaintenanceForm', 'The topic %s already exists. Would you like to make songs ' 'with topic %s use the existing topic %s?')) % (topic.name, - temp_name, topic.name), QtGui.QMessageBox.StandardButtons( - QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == \ - QtGui.QMessageBox.Yes: + temp_name, topic.name), + parent=self, question=True) == QtGui.QMessageBox.Yes: self.mergeTopics(topic) self.resetTopics() else: # We restore the topics's old name. topic.name = temp_name - QtGui.QMessageBox.critical(self, - translate('SongsPlugin.SongMaintenanceForm', 'Error'), - translate('SongsPlugin.SongMaintenanceForm', + criticalErrorMessageBox( + message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your modified topic, because it ' 'already exists.')) @@ -383,19 +369,15 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog): if self.manager.save_object(book): self.resetBooks() else: - QtGui.QMessageBox.critical(self, - translate('SongsPlugin.SongMaintenanceForm', - 'Error'), - translate('SongsPlugin.SongMaintenanceForm', + criticalErrorMessageBox( + message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your changes.')) - elif QtGui.QMessageBox.critical(self, - translate('SongsPlugin.SongMaintenanceForm', 'Error'), - unicode(translate('SongsPlugin.SongMaintenanceForm', + elif criticalErrorMessageBox( + message=unicode(translate('SongsPlugin.SongMaintenanceForm', 'The book %s already exists. Would you like to make songs ' 'with book %s use the existing book %s?')) % (book.name, - temp_name, book.name), QtGui.QMessageBox.StandardButtons( - QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == \ - QtGui.QMessageBox.Yes: + temp_name, book.name), + parent=self, question=True) == QtGui.QMessageBox.Yes: self.mergeBooks(book) self.resetBooks() else: diff --git a/openlp/plugins/songs/forms/topicsform.py b/openlp/plugins/songs/forms/topicsform.py index 1ff827423..4ab2b63fa 100644 --- a/openlp/plugins/songs/forms/topicsform.py +++ b/openlp/plugins/songs/forms/topicsform.py @@ -27,6 +27,7 @@ from PyQt4 import QtGui from openlp.core.lib import translate +from openlp.core.ui import criticalErrorMessageBox from openlp.plugins.songs.forms.topicsdialog import Ui_TopicsDialog class TopicsForm(QtGui.QDialog, Ui_TopicsDialog): @@ -48,10 +49,8 @@ class TopicsForm(QtGui.QDialog, Ui_TopicsDialog): def accept(self): if not self.nameEdit.text(): - QtGui.QMessageBox.critical( - self, translate('SongsPlugin.TopicsForm', 'Error'), - translate('SongsPlugin.TopicsForm', - 'You need to type in a topic name.')) + criticalErrorMessageBox(message=translate('SongsPlugin.TopicsForm', + 'You need to type in a topic name.')) self.nameEdit.setFocus() return False else: diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 462dac89a..af8b71795 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -48,49 +48,27 @@ class VerseType(object): ``verse_type`` The type to return a string for """ - if verse_type == VerseType.Verse: - return translate('SongsPlugin.VerseType', 'Verse') - elif verse_type == VerseType.Chorus: - return translate('SongsPlugin.VerseType', 'Chorus') - elif verse_type == VerseType.Bridge: - return translate('SongsPlugin.VerseType', 'Bridge') - elif verse_type == VerseType.PreChorus: - return translate('SongsPlugin.VerseType', 'Pre-Chorus') - elif verse_type == VerseType.Intro: - return translate('SongsPlugin.VerseType', 'Intro') - elif verse_type == VerseType.Ending: - return translate('SongsPlugin.VerseType', 'Ending') - 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 == \ + if not isinstance(verse_type, int): + verse_type = verse_type.lower() + if verse_type == VerseType.Verse or verse_type == \ unicode(VerseType.to_string(VerseType.Verse)).lower()[0]: return translate('SongsPlugin.VerseType', 'Verse') - elif verse_type == \ + elif verse_type == VerseType.Chorus or verse_type == \ unicode(VerseType.to_string(VerseType.Chorus)).lower()[0]: return translate('SongsPlugin.VerseType', 'Chorus') - elif verse_type == \ + elif verse_type == VerseType.Bridge or verse_type == \ unicode(VerseType.to_string(VerseType.Bridge)).lower()[0]: return translate('SongsPlugin.VerseType', 'Bridge') - elif verse_type == \ + elif verse_type == VerseType.PreChorus or verse_type == \ unicode(VerseType.to_string(VerseType.PreChorus)).lower()[0]: - return translate('SongsPlugin.VerseType', 'PreChorus') - elif verse_type == \ + return translate('SongsPlugin.VerseType', 'Pre-Chorus') + elif verse_type == VerseType.Intro or verse_type == \ unicode(VerseType.to_string(VerseType.Intro)).lower()[0]: return translate('SongsPlugin.VerseType', 'Intro') - elif verse_type == \ + elif verse_type == VerseType.Ending or verse_type == \ unicode(VerseType.to_string(VerseType.Ending)).lower()[0]: return translate('SongsPlugin.VerseType', 'Ending') - elif verse_type == \ + elif verse_type == VerseType.Other or verse_type == \ unicode(VerseType.to_string(VerseType.Other)).lower()[0]: return translate('SongsPlugin.VerseType', 'Other') @@ -163,7 +141,7 @@ def retrieve_windows_encoding(recommendation=None): translate('SongsPlugin', 'Character Encoding'), translate('SongsPlugin', 'The codepage setting is responsible\n' 'for the correct character representation.\n' - 'Usually you are fine with the preselected choise.'), + 'Usually you are fine with the preselected choice.'), [pair[1] for pair in encodings], recommended_index, False) else: choice = QtGui.QInputDialog.getItem(None, diff --git a/openlp/plugins/songs/lib/cclifileimport.py b/openlp/plugins/songs/lib/cclifileimport.py index 2234a81b7..441391d02 100644 --- a/openlp/plugins/songs/lib/cclifileimport.py +++ b/openlp/plugins/songs/lib/cclifileimport.py @@ -34,9 +34,6 @@ from songimport import SongImport log = logging.getLogger(__name__) -class CCLIFileImportError(Exception): - pass - class CCLIFileImport(SongImport): """ The :class:`CCLIFileImport` class provides OpenLP with the ability to @@ -152,7 +149,6 @@ class CCLIFileImport(SongImport): """ log.debug(u'USR file text: %s', textList) - lyrics = [] self.set_defaults() for line in textList: if line.startswith(u'Title='): diff --git a/openlp/plugins/songs/lib/db.py b/openlp/plugins/songs/lib/db.py index fc3aa06d1..838172893 100644 --- a/openlp/plugins/songs/lib/db.py +++ b/openlp/plugins/songs/lib/db.py @@ -181,4 +181,4 @@ def init_schema(url): mapper(Topic, topics_table) metadata.create_all(checkfirst=True) - return session \ No newline at end of file + return session diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index 128d80138..120f47738 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -23,7 +23,9 @@ # with this program; if not, write to the Free Software Foundation, Inc., 59 # # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### - +""" +The :mod:`importer` modules provides the general song import functionality. +""" from opensongimport import OpenSongImport from olpimport import OpenLPSongImport from openlyricsimport import OpenLyricsImport @@ -34,19 +36,19 @@ from songbeamerimport import SongBeamerImport # Imports that might fail try: from olp1import import OpenLP1SongImport - has_openlp1 = True + HAS_OPENLP1 = True except ImportError: - has_openlp1 = False + HAS_OPENLP1 = False try: from sofimport import SofImport - has_sof = True + HAS_SOF = True except ImportError: - has_sof = False + HAS_SOF = False try: from oooimport import OooImport - has_ooo = True + HAS_OOO = True except ImportError: - has_ooo = False + HAS_OOO = False class SongFormat(object): """ @@ -118,14 +120,20 @@ class SongFormat(object): @staticmethod def set_availability(format, available): + """ + Set the availability for a given song format. + """ SongFormat._format_availability[format] = available @staticmethod def get_availability(format): + """ + Return the availability of a given song format. + """ return SongFormat._format_availability.get(format, True) -SongFormat.set_availability(SongFormat.OpenLP1, has_openlp1) -SongFormat.set_availability(SongFormat.SongsOfFellowship, has_sof) -SongFormat.set_availability(SongFormat.Generic, has_ooo) +SongFormat.set_availability(SongFormat.OpenLP1, HAS_OPENLP1) +SongFormat.set_availability(SongFormat.SongsOfFellowship, HAS_SOF) +SongFormat.set_availability(SongFormat.Generic, HAS_OOO) -__all__ = [u'SongFormat'] \ No newline at end of file +__all__ = [u'SongFormat'] diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 93e40f58a..67021616b 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -194,8 +194,7 @@ class SongMediaItem(MediaManagerItem): elif search_type == 5: log.debug(u'Theme Search') search_results = self.parent.manager.get_all_objects(Song, - Song.theme_name == search_keywords, - Song.search_lyrics.asc()) + Song.theme_name == search_keywords, Song.search_lyrics.asc()) self.displayResultsSong(search_results) def onSongListLoad(self): diff --git a/openlp/plugins/songs/lib/songbeamerimport.py b/openlp/plugins/songs/lib/songbeamerimport.py index c783793db..47290bfbd 100644 --- a/openlp/plugins/songs/lib/songbeamerimport.py +++ b/openlp/plugins/songs/lib/songbeamerimport.py @@ -83,7 +83,7 @@ class SongBeamerImport(SongImport): def do_import(self): """ - Recieve a single file, or a list of files to import. + Receive a single file or a list of files to import. """ if isinstance(self.import_source, list): self.import_wizard.progressBar.setMaximum( @@ -94,21 +94,21 @@ class SongBeamerImport(SongImport): self.current_verse = u'' self.current_verse_type = u'V' read_verses = False - self.file_name = os.path.split(file)[1] + file_name = os.path.split(file)[1] self.import_wizard.incrementProgressBar( - u'Importing %s' % (self.file_name), 0) + u'Importing %s' % (file_name), 0) if os.path.isfile(file): detect_file = open(file, u'r') details = chardet.detect(detect_file.read(2048)) detect_file.close() infile = codecs.open(file, u'r', details['encoding']) - self.songData = infile.readlines() + songData = infile.readlines() infile.close() else: return False - self.title = self.file_name.split('.sng')[0] + self.title = file_name.split('.sng')[0] read_verses = False - for line in self.songData: + for line in songData: # Just make sure that the line is of the type 'Unicode'. line = unicode(line).strip() if line.startswith(u'#') and not read_verses: @@ -136,7 +136,7 @@ class SongBeamerImport(SongImport): self.finish() self.import_wizard.incrementProgressBar(unicode(translate( 'SongsPlugin.SongBeamerImport', 'Importing %s...')) % - self.file_name) + file_name) return True def replace_html_tags(self): diff --git a/openlp/plugins/songs/lib/songimport.py b/openlp/plugins/songs/lib/songimport.py index c1105a578..b4f64f9b4 100644 --- a/openlp/plugins/songs/lib/songimport.py +++ b/openlp/plugins/songs/lib/songimport.py @@ -62,7 +62,6 @@ class SongImport(QtCore.QObject): Create defaults for properties - call this before each song if importing many songs at once to ensure a clean beginning """ - self.authors = [] self.title = u'' self.song_number = u'' self.alternate_title = u'' @@ -251,17 +250,11 @@ class SongImport(QtCore.QObject): def finish(self): """ - All fields have been set to this song. Write it away + All fields have been set to this song. Write the song to disk. """ if not self.authors: self.authors.append(unicode(translate('SongsPlugin.SongImport', 'Author unknown'))) - self.commit_song() - - def commit_song(self): - """ - Write the song and its fields to disk - """ log.info(u'commiting song %s to database', self.title) song = Song() song.title = self.title diff --git a/openlp/plugins/songs/lib/wowimport.py b/openlp/plugins/songs/lib/wowimport.py index d0c308413..b90a47de6 100644 --- a/openlp/plugins/songs/lib/wowimport.py +++ b/openlp/plugins/songs/lib/wowimport.py @@ -107,63 +107,60 @@ class WowImport(SongImport): def do_import(self): """ - Recieve a single file, or a list of files to import. + Receive a single file or a list of files to import. """ - if isinstance(self.import_source, list): self.import_wizard.progressBar.setMaximum(len(self.import_source)) for file in self.import_source: - self.author = u'' - self.copyright = u'' - self.file_name = os.path.split(file)[1] + author = u'' + copyright = u'' + file_name = os.path.split(file)[1] self.import_wizard.incrementProgressBar( - u'Importing %s' % (self.file_name), 0) + u'Importing %s' % (file_name), 0) # Get the song title - self.title = self.file_name.rpartition(u'.')[0] - self.songData = open(file, 'rb') - if self.songData.read(19) != u'WoW File\nSong Words': + self.title = file_name.rpartition(u'.')[0] + songData = open(file, 'rb') + if songData.read(19) != u'WoW File\nSong Words': continue # Seek to byte which stores number of blocks in the song - self.songData.seek(56) - self.no_of_blocks = ord(self.songData.read(1)) + songData.seek(56) + no_of_blocks = ord(songData.read(1)) # Seek to the beging of the first block - self.songData.seek(82) - for block in range(self.no_of_blocks): - self.lines_to_read = ord(self.songData.read(1)) + songData.seek(82) + for block in range(no_of_blocks): + self.lines_to_read = ord(songData.read(1)) # Skip 3 nulls to the beginnig of the 1st line - self.songData.seek(3, os.SEEK_CUR) - self.block_text = u'' + songData.seek(3, os.SEEK_CUR) + block_text = u'' while self.lines_to_read: - self.length_of_line = ord(self.songData.read(1)) self.line_text = unicode( - self.songData.read(self.length_of_line), u'cp1252') - self.songData.seek(1, os.SEEK_CUR) - if self.block_text != u'': - self.block_text += u'\n' - self.block_text += self.line_text + songData.read(ord(songData.read(1))), u'cp1252') + songData.seek(1, os.SEEK_CUR) + if block_text != u'': + block_text += u'\n' + block_text += self.line_text self.lines_to_read -= 1 - self.block_type = BLOCK_TYPES[ord(self.songData.read(1))] + block_type = BLOCK_TYPES[ord(songData.read(1))] # Skip 3 nulls at the end of the block - self.songData.seek(3, os.SEEK_CUR) + songData.seek(3, os.SEEK_CUR) # Blocks are seperated by 2 bytes, skip them, but not if # this is the last block! - if (block + 1) < self.no_of_blocks: - self.songData.seek(2, os.SEEK_CUR) - self.add_verse(self.block_text, self.block_type) - # Now to extact the author - self.author_length = ord(self.songData.read(1)) - if self.author_length != 0: - self.author = unicode( - self.songData.read(self.author_length), u'cp1252') + if (block + 1) < no_of_blocks: + songData.seek(2, os.SEEK_CUR) + self.add_verse(block_text, block_type) + # Now to extract the author + author_length = ord(songData.read(1)) + if author_length != 0: + author = unicode(songData.read(author_length), u'cp1252') # Finally the copyright - self.copyright_length = ord(self.songData.read(1)) - if self.copyright_length != 0: - self.copyright = unicode( - self.songData.read(self.copyright_length), u'cp1252') - self.parse_author(self.author) - self.add_copyright(self.copyright) - self.songData.close() + copyright_length = ord(songData.read(1)) + if copyright_length != 0: + copyright = unicode( + songData.read(copyright_length), u'cp1252') + self.parse_author(author) + self.add_copyright(copyright) + songData.close() self.finish() self.import_wizard.incrementProgressBar( - u'Importing %s' % (self.file_name)) + u'Importing %s' % (file_name)) return True diff --git a/openlp/plugins/songs/lib/xml.py b/openlp/plugins/songs/lib/xml.py index cbe313212..88459b797 100644 --- a/openlp/plugins/songs/lib/xml.py +++ b/openlp/plugins/songs/lib/xml.py @@ -435,7 +435,7 @@ class OpenLyrics(object): text += u'\n' text += u'\n'.join([unicode(line) for line in lines.line]) verse_name = self._get(verse, u'name') - verse_type = unicode(VerseType.expand_string(verse_name[0]))[0] + verse_type = unicode(VerseType.to_string(verse_name[0]))[0] verse_number = re.compile(u'[a-zA-Z]*').sub(u'', verse_name) verse_part = re.compile(u'[0-9]*').sub(u'', verse_name[1:]) # OpenLyrics allows e. g. "c", but we need "c1".