diff --git a/openlp.pyw b/openlp.pyw index cc58c6a21..8d5c90957 100755 --- a/openlp.pyw +++ b/openlp.pyw @@ -26,12 +26,6 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### -# Import uuid now, to avoid the rare bug described in the support system: -# http://support.openlp.org/issues/102 -# If https://bugs.gentoo.org/show_bug.cgi?id=317557 is fixed, the import can be -# removed. -import uuid - from openlp.core import main diff --git a/openlp/core/__init__.py b/openlp/core/__init__.py index 71c27a1d0..96520195d 100644 --- a/openlp/core/__init__.py +++ b/openlp/core/__init__.py @@ -91,6 +91,7 @@ class OpenLP(QtGui.QApplication): """ Override exec method to allow the shared memory to be released on exit """ + self.eventLoopIsActive = True QtGui.QApplication.exec_() self.sharedMemory.detach() @@ -98,6 +99,7 @@ class OpenLP(QtGui.QApplication): """ Run the OpenLP application. """ + self.eventLoopIsActive = False # On Windows, the args passed into the constructor are # ignored. Not very handy, so set the ones we want to use. self.args.extend(args) @@ -109,7 +111,7 @@ class OpenLP(QtGui.QApplication): QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'cursor_normal'), self.setNormalCursor) # Decide how many screens we have and their size - screens = ScreenList(self.desktop()) + screens = ScreenList.create(self.desktop()) # First time checks in settings has_run_wizard = QtCore.QSettings().value( u'general/has run wizard', QtCore.QVariant(False)).toBool() @@ -127,7 +129,7 @@ class OpenLP(QtGui.QApplication): # make sure Qt really display the splash screen self.processEvents() # start the main app window - self.mainWindow = MainWindow(self.clipboard(), self.args) + self.mainWindow = MainWindow(self) self.mainWindow.show() if show_splash: # now kill the splashscreen diff --git a/openlp/core/lib/dockwidget.py b/openlp/core/lib/dockwidget.py index e08b5eee5..23ce9efcb 100644 --- a/openlp/core/lib/dockwidget.py +++ b/openlp/core/lib/dockwidget.py @@ -52,7 +52,7 @@ class OpenLPDockWidget(QtGui.QDockWidget): if icon: self.setWindowIcon(build_icon(icon)) # Sort out the minimum width. - screens = ScreenList.get_instance() + screens = ScreenList() mainwindow_docbars = screens.current[u'size'].width() / 5 if mainwindow_docbars > 300: self.setMinimumWidth(300) diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index b32e36194..47a7ed3f6 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -163,7 +163,7 @@ class ImageManager(QtCore.QObject): def __init__(self): QtCore.QObject.__init__(self) - current_screen = ScreenList.get_instance().current + current_screen = ScreenList().current self.width = current_screen[u'size'].width() self.height = current_screen[u'size'].height() self._cache = {} @@ -177,7 +177,7 @@ class ImageManager(QtCore.QObject): Screen has changed size so rebuild the cache to new size. """ log.debug(u'update_display') - current_screen = ScreenList.get_instance().current + current_screen = ScreenList().current self.width = current_screen[u'size'].width() self.height = current_screen[u'size'].height() # Mark the images as dirty for a rebuild by setting the image and byte diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 8694ca6b6..aa39e779b 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -69,7 +69,7 @@ class Renderer(object): log.debug(u'Initialisation started') self.themeManager = themeManager self.imageManager = imageManager - self.screens = ScreenList.get_instance() + self.screens = ScreenList() self.service_theme = u'' self.theme_level = u'' self.override_background = None diff --git a/openlp/core/lib/ui.py b/openlp/core/lib/ui.py index c4b1181b1..c0472cce8 100644 --- a/openlp/core/lib/ui.py +++ b/openlp/core/lib/ui.py @@ -94,6 +94,7 @@ class UiStrings(object): self.NewService = translate('OpenLP.Ui', 'New Service') self.NewTheme = translate('OpenLP.Ui', 'New Theme') self.NextTrack = translate('OpenLP.Ui', 'Next Track') + self.NFdSs = translate('OpenLP.Ui', 'No Folder Selected', 'Singular') self.NFSs = translate('OpenLP.Ui', 'No File Selected', 'Singular') self.NFSp = translate('OpenLP.Ui', 'No Files Selected', 'Plural') self.NISs = translate('OpenLP.Ui', 'No Item Selected', 'Singular') diff --git a/openlp/core/ui/generaltab.py b/openlp/core/ui/generaltab.py index baf28f40f..d0647d829 100644 --- a/openlp/core/ui/generaltab.py +++ b/openlp/core/ui/generaltab.py @@ -42,7 +42,7 @@ class GeneralTab(SettingsTab): """ Initialise the general settings tab """ - self.screens = ScreenList.get_instance() + self.screens = ScreenList() self.iconPath = u':/icon/openlp-logo-16x16.png' generalTranslated = translate('OpenLP.GeneralTab', 'General') SettingsTab.__init__(self, parent, u'General', generalTranslated) diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index 15fb9eefe..a04203387 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -119,7 +119,7 @@ class MainDisplay(Display): def __init__(self, parent, imageManager, live, controller): Display.__init__(self, parent, live, controller) self.imageManager = imageManager - self.screens = ScreenList.get_instance() + self.screens = ScreenList() self.plugins = PluginManager.get_instance().plugins self.rebuildCSS = False self.hideMode = None diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index e4a4e1616..fe0d69c32 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -542,14 +542,15 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): """ log.info(u'MainWindow loaded') - def __init__(self, clipboard, arguments): + def __init__(self, application): """ This constructor sets up the interface, the various managers, and the plugins. """ QtGui.QMainWindow.__init__(self) - self.clipboard = clipboard - self.arguments = arguments + self.application = application + self.clipboard = self.application.clipboard() + self.arguments = self.application.args # Set up settings sections for the main application # (not for use by plugins) self.uiSettingsSection = u'user interface' @@ -795,7 +796,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): if answer == QtGui.QMessageBox.No: return Receiver.send_message(u'cursor_busy') - screens = ScreenList.get_instance() + screens = ScreenList() FirstTimeForm(screens, self).exec_() self.firstTime() for plugin in self.pluginManager.plugins: @@ -830,7 +831,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): translate('OpenLP.MainWindow', 'OpenLP Main Display Blanked'), translate('OpenLP.MainWindow', - 'The Main Display has been blanked out')) + 'The Main Display has been blanked out')) def onErrorMessage(self, data): Receiver.send_message(u'close_splash') @@ -1132,6 +1133,11 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): """ Hook to close the main window and display windows on exit """ + # The MainApplication did not even enter the event loop (this happens + # when OpenLP is not fully loaded). Just ignore the event. + if not self.application.eventLoopIsActive: + event.ignore() + return # If we just did a settings import, close without saving changes. if self.settingsImported: event.accept() @@ -1184,7 +1190,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): # Save settings self.saveSettings() # Close down the display - self.liveController.display.close() + if self.liveController.display: + self.liveController.display.close() + self.liveController.display = None def serviceChanged(self, reset=False, serviceName=None): """ diff --git a/openlp/core/ui/screen.py b/openlp/core/ui/screen.py index 21fbd6144..72c88908e 100644 --- a/openlp/core/ui/screen.py +++ b/openlp/core/ui/screen.py @@ -41,36 +41,40 @@ class ScreenList(object): """ Wrapper to handle the parameters of the display screen. - To get access to the screen list call ``ScreenList.get_instance()``. + To get access to the screen list call ``ScreenList()``. """ log.info(u'Screen loaded') - instance = None + __instance__ = None - @staticmethod - def get_instance(): - return ScreenList.instance + def __new__(cls): + if not cls.__instance__: + cls.__instance__ = object.__new__(cls) + return cls.__instance__ - def __init__(self, desktop): + @classmethod + def create(cls, desktop): """ Initialise the screen list. ``desktop`` A ``QDesktopWidget`` object. """ - ScreenList.instance = self - self.desktop = desktop - self.preview = None - self.current = None - self.override = None - self.screen_list = [] - self.display_count = 0 - self.screen_count_changed() - self._load_screen_settings() + screen_list = cls() + screen_list.desktop = desktop + screen_list.preview = None + screen_list.current = None + screen_list.override = None + screen_list.screen_list = [] + screen_list.display_count = 0 + screen_list.screen_count_changed() + screen_list._load_screen_settings() QtCore.QObject.connect(desktop, - QtCore.SIGNAL(u'resized(int)'), self.screen_resolution_changed) + QtCore.SIGNAL(u'resized(int)'), + screen_list.screen_resolution_changed) QtCore.QObject.connect(desktop, QtCore.SIGNAL(u'screenCountChanged(int)'), - self.screen_count_changed) + screen_list.screen_count_changed) + return screen_list def screen_resolution_changed(self, number): """ @@ -233,8 +237,8 @@ class ScreenList(object): y = window.y() + (window.height() / 2) for screen in self.screen_list: size = screen[u'size'] - if x >= size.x() and x <= (size.x() + size.width()) \ - and y >= size.y() and y <= (size.y() + size.height()): + if x >= size.x() and x <= (size.x() + size.width()) and \ + y >= size.y() and y <= (size.y() + size.height()): return screen[u'number'] def _load_screen_settings(self): diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 7d3e8289c..30567f2d2 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -302,17 +302,14 @@ class ServiceManager(QtGui.QWidget): self.timeAction = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', '&Start Time'), icon=u':/media/media_time.png', triggers=self.onStartTimeForm) - self.deleteAction = create_widget_action(self.menu, - text=translate('OpenLP.ServiceManager', '&Delete From Service'), - icon=u':/general/general_delete.png', - triggers=self.onDeleteFromService) + # Add already existing delete action to the menu. + self.menu.addAction(self.serviceManagerList.delete) self.menu.addSeparator() self.previewAction = create_widget_action(self.menu, text=translate('OpenLP.ServiceManager', 'Show &Preview'), icon=u':/general/general_preview.png', triggers=self.makePreview) - self.liveAction = create_widget_action(self.menu, - text=translate('OpenLP.ServiceManager', 'Show &Live'), - icon=u':/general/general_live.png', triggers=self.makeLive) + # Add already existing make live action to the menu. + self.menu.addAction(self.serviceManagerList.makeLive) self.menu.addSeparator() self.themeMenu = QtGui.QMenu( translate('OpenLP.ServiceManager', '&Change Item Theme')) @@ -564,14 +561,12 @@ class ServiceManager(QtGui.QWidget): zip.write(audio_from, audio_to.encode(u'utf-8')) except IOError: log.exception(u'Failed to save service to disk: %s', temp_file_name) - # Add this line in after the release to notify the user that saving - # their file failed. Commented out due to string freeze. - #Receiver.send_message(u'openlp_error_message', { - # u'title': translate(u'OpenLP.ServiceManager', - # u'Error Saving File'), - # u'message': translate(u'OpenLP.ServiceManager', - # u'There was an error saving your file.') - #}) + Receiver.send_message(u'openlp_error_message', { + u'title': translate(u'OpenLP.ServiceManager', + u'Error Saving File'), + u'message': translate(u'OpenLP.ServiceManager', + u'There was an error saving your file.') + }) success = False finally: if zip: diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 1dc005aa6..4224222ca 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -73,6 +73,7 @@ class Controller(QtGui.QWidget): controller = self Receiver.send_message('%s' % sender, [controller, args]) + class SlideController(Controller): """ SlideController is the slide controller widget. This widget is what the @@ -83,7 +84,7 @@ class SlideController(Controller): Set up the Slide Controller. """ Controller.__init__(self, parent, isLive) - self.screens = ScreenList.get_instance() + self.screens = ScreenList() try: self.ratio = float(self.screens.current[u'size'].width()) / \ float(self.screens.current[u'size'].height()) @@ -577,8 +578,7 @@ class SlideController(Controller): # rebuild display as screen size changed if self.display: self.display.close() - self.display = MainDisplay(self, self.imageManager, self.isLive, - self) + self.display = MainDisplay(self, self.imageManager, self.isLive, self) self.display.setup() if self.isLive: self.__addActionsToWidget(self.display) diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index f8c061851..60e073b13 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -136,16 +136,14 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): """ self.backgroundPage.registerField( u'background_type', self.backgroundComboBox) - self.backgroundPage.registerField( - u'color', self.colorButton) + self.backgroundPage.registerField(u'color', self.colorButton) self.backgroundPage.registerField( u'grandient_start', self.gradientStartButton) self.backgroundPage.registerField( u'grandient_end', self.gradientEndButton) self.backgroundPage.registerField( u'background_image', self.imageFileEdit) - self.backgroundPage.registerField( - u'gradient', self.gradientComboBox) + self.backgroundPage.registerField(u'gradient', self.gradientComboBox) self.mainAreaPage.registerField( u'mainColorButton', self.mainColorButton) self.mainAreaPage.registerField( @@ -158,8 +156,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): u'outlineColorButton', self.outlineColorButton) self.mainAreaPage.registerField( u'outlineSizeSpinBox', self.outlineSizeSpinBox) - self.mainAreaPage.registerField( - u'shadowCheckBox', self.shadowCheckBox) + self.mainAreaPage.registerField(u'shadowCheckBox', self.shadowCheckBox) self.mainAreaPage.registerField( u'mainBoldCheckBox', self.mainBoldCheckBox) self.mainAreaPage.registerField( @@ -170,10 +167,8 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): u'shadowSizeSpinBox', self.shadowSizeSpinBox) self.mainAreaPage.registerField( u'footerSizeSpinBox', self.footerSizeSpinBox) - self.areaPositionPage.registerField( - u'mainPositionX', self.mainXSpinBox) - self.areaPositionPage.registerField( - u'mainPositionY', self.mainYSpinBox) + self.areaPositionPage.registerField(u'mainPositionX', self.mainXSpinBox) + self.areaPositionPage.registerField(u'mainPositionY', self.mainYSpinBox) self.areaPositionPage.registerField( u'mainPositionWidth', self.mainWidthSpinBox) self.areaPositionPage.registerField( @@ -188,12 +183,10 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): u'footerPositionHeight', self.footerHeightSpinBox) self.backgroundPage.registerField( u'horizontal', self.horizontalComboBox) - self.backgroundPage.registerField( - u'vertical', self.verticalComboBox) + self.backgroundPage.registerField(u'vertical', self.verticalComboBox) self.backgroundPage.registerField( u'slideTransition', self.transitionsCheckBox) - self.backgroundPage.registerField( - u'name', self.themeNameEdit) + self.backgroundPage.registerField(u'name', self.themeNameEdit) def calculateLines(self): """ @@ -269,10 +262,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): Change state as Outline check box changed """ if self.updateThemeAllowed: - if state == QtCore.Qt.Checked: - self.theme.font_main_outline = True - else: - self.theme.font_main_outline = False + self.theme.font_main_outline = state == QtCore.Qt.Checked self.outlineColorButton.setEnabled(self.theme.font_main_outline) self.outlineSizeSpinBox.setEnabled(self.theme.font_main_outline) self.calculateLines() @@ -350,19 +340,19 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): if self.theme.background_type == \ BackgroundType.to_string(BackgroundType.Solid): self.colorButton.setStyleSheet(u'background-color: %s' % - self.theme.background_color) + self.theme.background_color) self.setField(u'background_type', QtCore.QVariant(0)) elif self.theme.background_type == \ BackgroundType.to_string(BackgroundType.Gradient): self.gradientStartButton.setStyleSheet(u'background-color: %s' % - self.theme.background_start_color) + self.theme.background_start_color) self.gradientEndButton.setStyleSheet(u'background-color: %s' % - self.theme.background_end_color) + self.theme.background_end_color) self.setField(u'background_type', QtCore.QVariant(1)) elif self.theme.background_type == \ BackgroundType.to_string(BackgroundType.Image): self.imageColorButton.setStyleSheet(u'background-color: %s' % - self.theme.background_border_color) + self.theme.background_border_color) self.imageFileEdit.setText(self.theme.background_filename) self.setField(u'background_type', QtCore.QVariant(2)) elif self.theme.background_type == \ @@ -642,8 +632,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): """ Handle Color buttons """ - new_color = QtGui.QColorDialog.getColor( - QtGui.QColor(field), self) + new_color = QtGui.QColorDialog.getColor(QtGui.QColor(field), self) if new_color.isValid(): field = new_color.name() return field diff --git a/openlp/core/ui/wizard.py b/openlp/core/ui/wizard.py index 500d958fd..0b4e8ec37 100644 --- a/openlp/core/ui/wizard.py +++ b/openlp/core/ui/wizard.py @@ -72,11 +72,14 @@ class WizardStrings(object): 'importer, you will need to install the "python-sqlite" ' 'module.') OpenTypeFile = unicode(translate('OpenLP.Ui', 'Open %s File')) + OpenTypeFolder = unicode(translate('OpenLP.Ui', 'Open %s Folder')) PercentSymbolFormat = unicode(translate('OpenLP.Ui', '%p%')) Ready = translate('OpenLP.Ui', 'Ready.') StartingImport = translate('OpenLP.Ui', 'Starting import...') YouSpecifyFile = unicode(translate('OpenLP.Ui', 'You need to specify at ' 'least one %s file to import from.', 'A file type e.g. OpenSong')) + YouSpecifyFolder = unicode(translate('OpenLP.Ui', 'You need to specify a ' + '%s folder to import from.', 'A file type e.g. OpenSong')) class OpenLPWizard(QtGui.QWizard): @@ -254,7 +257,7 @@ class OpenLPWizard(QtGui.QWizard): The title of the dialog (unicode). ``editbox`` - A editbox (QLineEdit). + An editbox (QLineEdit). ``filters`` The file extension filters. It should contain the file description @@ -265,11 +268,28 @@ class OpenLPWizard(QtGui.QWizard): if filters: filters += u';;' filters += u'%s (*)' % UiStrings().AllFiles - filename = QtGui.QFileDialog.getOpenFileName(self, title, + filename = unicode(QtGui.QFileDialog.getOpenFileName(self, title, os.path.dirname(SettingsManager.get_last_dir( - self.plugin.settingsSection, 1)), filters) + self.plugin.settingsSection, 1)), filters)) if filename: editbox.setText(filename) SettingsManager.set_last_dir(self.plugin.settingsSection, filename, 1) + def getFolder(self, title, editbox): + """ + Opens a QFileDialog and saves the selected folder to the given editbox. + + ``title`` + The title of the dialog (unicode). + + ``editbox`` + An editbox (QLineEdit). + """ + folder = unicode(QtGui.QFileDialog.getExistingDirectory(self, title, + os.path.dirname(SettingsManager.get_last_dir( + self.plugin.settingsSection, 1)), QtGui.QFileDialog.ShowDirsOnly)) + if folder: + editbox.setText(folder) + SettingsManager.set_last_dir(self.plugin.settingsSection, + folder, 1) diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index 9d00e22b7..f73237c06 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -34,7 +34,6 @@ import os import re from subprocess import Popen, PIPE import sys -import time import urllib2 from PyQt4 import QtGui, QtCore @@ -69,7 +68,7 @@ class VersionThread(QtCore.QThread): """ Run the thread. """ - time.sleep(1) + self.sleep(1) app_version = get_application_version() version = check_latest_version(app_version) if LooseVersion(str(version)) > LooseVersion(str(app_version[u'full'])): diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py index 9a82cc388..bfba082af 100644 --- a/openlp/plugins/bibles/lib/manager.py +++ b/openlp/plugins/bibles/lib/manager.py @@ -330,13 +330,7 @@ class BibleManager(object): 'Import Wizard to install one or more Bibles.') }) return None - language_selection = self.get_meta_data(bible, u'book_name_language') - if language_selection: - language_selection = int(language_selection.value) - if language_selection is None or language_selection == -1: - language_selection = QtCore.QSettings().value( - self.settingsSection + u'/bookname language', - QtCore.QVariant(0)).toInt()[0] + language_selection = self.get_language_selection(bible) reflist = parse_reference(versetext, self.db_cache[bible], language_selection, book_ref_id) if reflist: @@ -378,12 +372,16 @@ class BibleManager(object): """ log.debug(u'BibleManager.get_language_selection("%s")', bible) language_selection = self.get_meta_data(bible, u'book_name_language') - if language_selection and language_selection.value != u'None': - return int(language_selection.value) - if language_selection is None or language_selection.value == u'None': - return QtCore.QSettings().value( + if language_selection: + try: + language_selection = int(language_selection.value) + except (ValueError, TypeError): + language_selection = LanguageSelection.Application + if language_selection is None or language_selection == -1: + language_selection = QtCore.QSettings().value( self.settingsSection + u'/bookname language', QtCore.QVariant(0)).toInt()[0] + return language_selection def verse_search(self, bible, second_bible, text): """ diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index 3c723d760..288e0e2de 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -843,10 +843,11 @@ class BibleMediaItem(MediaManagerItem): items = [] language_selection = self.plugin.manager.get_language_selection(bible) for count, verse in enumerate(search_results): + book = None if language_selection == LanguageSelection.Bible: book = verse.book.name elif language_selection == LanguageSelection.Application: - book_names = BibleStrings().Booknames + book_names = BibleStrings().BookNames data = BiblesResourcesDB.get_book_by_id( verse.book.book_reference_id) book = unicode(book_names[data[u'abbreviation']]) diff --git a/openlp/plugins/songs/forms/songexportform.py b/openlp/plugins/songs/forms/songexportform.py index 397b52cfc..dcca098dc 100644 --- a/openlp/plugins/songs/forms/songexportform.py +++ b/openlp/plugins/songs/forms/songexportform.py @@ -363,11 +363,5 @@ class SongExportForm(OpenLPWizard): Called when the *directoryButton* was clicked. Opens a dialog and writes the path to *directoryLineEdit*. """ - path = unicode(QtGui.QFileDialog.getExistingDirectory(self, - translate('SongsPlugin.ExportWizardForm', - 'Select Destination Folder'), - SettingsManager.get_last_dir(self.plugin.settingsSection, 1), - options=QtGui.QFileDialog.ShowDirsOnly)) - SettingsManager.set_last_dir(self.plugin.settingsSection, path, 1) - self.directoryLineEdit.setText(path) - + self.getFolder(translate('SongsPlugin.ExportWizardForm', + 'Select Destination Folder'), self.directoryLineEdit) diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py index d5f7715ea..4bdabd1a2 100644 --- a/openlp/plugins/songs/forms/songimportform.py +++ b/openlp/plugins/songs/forms/songimportform.py @@ -105,6 +105,9 @@ class SongImportForm(OpenLPWizard): QtCore.QObject.connect(self.openLP1BrowseButton, QtCore.SIGNAL(u'clicked()'), self.onOpenLP1BrowseButtonClicked) + QtCore.QObject.connect(self.powerSongBrowseButton, + QtCore.SIGNAL(u'clicked()'), + self.onPowerSongBrowseButtonClicked) QtCore.QObject.connect(self.openLyricsAddButton, QtCore.SIGNAL(u'clicked()'), self.onOpenLyricsAddButtonClicked) @@ -171,12 +174,6 @@ class SongImportForm(OpenLPWizard): QtCore.QObject.connect(self.foilPresenterRemoveButton, QtCore.SIGNAL(u'clicked()'), self.onFoilPresenterRemoveButtonClicked) - QtCore.QObject.connect(self.powerSongAddButton, - QtCore.SIGNAL(u'clicked()'), - self.onPowerSongAddButtonClicked) - QtCore.QObject.connect(self.powerSongRemoveButton, - QtCore.SIGNAL(u'clicked()'), - self.onPowerSongRemoveButtonClicked) def addCustomPages(self): """ @@ -224,7 +221,7 @@ class SongImportForm(OpenLPWizard): # Open Song self.addFileSelectItem(u'openSong', u'OpenSong') # PowerSong - self.addFileSelectItem(u'powerSong') + self.addFileSelectItem(u'powerSong', single_select=True) # SongBeamer self.addFileSelectItem(u'songBeamer') # Song Show Plus @@ -290,6 +287,9 @@ class SongImportForm(OpenLPWizard): translate('SongsPlugin.ImportWizardForm', 'Filename:')) self.openLP1BrowseButton.setText(UiStrings().Browse) self.openLP1DisabledLabel.setText(WizardStrings.NoSqlite) + self.powerSongFilenameLabel.setText( + translate('SongsPlugin.ImportWizardForm', 'Folder:')) + self.powerSongBrowseButton.setText(UiStrings().Browse) self.openLyricsAddButton.setText( translate('SongsPlugin.ImportWizardForm', 'Add Files...')) self.openLyricsRemoveButton.setText( @@ -315,10 +315,6 @@ class SongImportForm(OpenLPWizard): translate('SongsPlugin.ImportWizardForm', 'Add Files...')) self.dreamBeamRemoveButton.setText( translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) - self.powerSongAddButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Add Files...')) - self.powerSongRemoveButton.setText( - translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) self.songsOfFellowshipAddButton.setText( translate('SongsPlugin.ImportWizardForm', 'Add Files...')) self.songsOfFellowshipRemoveButton.setText( @@ -389,6 +385,7 @@ class SongImportForm(OpenLPWizard): source_format = self.formatComboBox.currentIndex() QtCore.QSettings().setValue(u'songs/last import type', source_format) + import_class = SongFormat.get_class(source_format) if source_format == SongFormat.OpenLP2: if self.openLP2FilenameEdit.text().isEmpty(): critical_error_message_box(UiStrings().NFSs, @@ -401,6 +398,14 @@ class SongImportForm(OpenLPWizard): WizardStrings.YouSpecifyFile % UiStrings().OLPV1) self.openLP1BrowseButton.setFocus() return False + elif source_format == SongFormat.PowerSong: + if self.powerSongFilenameEdit.text().isEmpty() or \ + not import_class.isValidSource( + folder=self.powerSongFilenameEdit.text()): + critical_error_message_box(UiStrings().NFdSs, + WizardStrings.YouSpecifyFolder % WizardStrings.PS) + self.powerSongBrowseButton.setFocus() + return False elif source_format == SongFormat.OpenLyrics: if self.openLyricsFileListWidget.count() == 0: critical_error_message_box(UiStrings().NFSp, @@ -431,12 +436,6 @@ class SongImportForm(OpenLPWizard): WizardStrings.YouSpecifyFile % WizardStrings.DB) self.dreamBeamAddButton.setFocus() return False - elif source_format == SongFormat.PowerSong: - if self.powerSongFileListWidget.count() == 0: - critical_error_message_box(UiStrings().NFSp, - WizardStrings.YouSpecifyFile % WizardStrings.PS) - self.powerSongAddButton.setFocus() - return False elif source_format == SongFormat.SongsOfFellowship: if self.songsOfFellowshipFileListWidget.count() == 0: critical_error_message_box(UiStrings().NFSp, @@ -546,6 +545,13 @@ class SongImportForm(OpenLPWizard): 'openlp.org v1.x Databases') ) + def onPowerSongBrowseButtonClicked(self): + """ + Get PowerSong song database folder + """ + self.getFolder(WizardStrings.OpenTypeFolder % WizardStrings.PS, + self.powerSongFilenameEdit) + def onOpenLyricsAddButtonClicked(self): """ Get OpenLyrics song database files @@ -620,22 +626,6 @@ class SongImportForm(OpenLPWizard): """ self.removeSelectedItems(self.dreamBeamFileListWidget) - def onPowerSongAddButtonClicked(self): - """ - Get PowerSong song database files - """ - self.getFiles(WizardStrings.OpenTypeFile % WizardStrings.PS, - self.powerSongFileListWidget, u'%s (*.song)' - % translate('SongsPlugin.ImportWizardForm', - 'PowerSong 1.0 Song Files') - ) - - def onPowerSongRemoveButtonClicked(self): - """ - Remove selected PowerSong files from the import list - """ - self.removeSelectedItems(self.powerSongFileListWidget) - def onSongsOfFellowshipAddButtonClicked(self): """ Get Songs of Fellowship song database files @@ -748,12 +738,12 @@ class SongImportForm(OpenLPWizard): self.formatComboBox.setCurrentIndex(last_import_type) self.openLP2FilenameEdit.setText(u'') self.openLP1FilenameEdit.setText(u'') + self.powerSongFilenameEdit.setText(u'') self.openLyricsFileListWidget.clear() self.openSongFileListWidget.clear() self.wordsOfWorshipFileListWidget.clear() self.ccliFileListWidget.clear() self.dreamBeamFileListWidget.clear() - self.powerSongFileListWidget.clear() self.songsOfFellowshipFileListWidget.clear() self.genericFileListWidget.clear() self.easySlidesFilenameEdit.setText(u'') @@ -794,6 +784,11 @@ class SongImportForm(OpenLPWizard): filename=unicode(self.openLP1FilenameEdit.text()), plugin=self.plugin ) + elif source_format == SongFormat.PowerSong: + # Import PowerSong folder + importer = self.plugin.importSongs(SongFormat.PowerSong, + folder=unicode(self.powerSongFilenameEdit.text()) + ) elif source_format == SongFormat.OpenLyrics: # Import OpenLyrics songs importer = self.plugin.importSongs(SongFormat.OpenLyrics, @@ -821,12 +816,6 @@ class SongImportForm(OpenLPWizard): filenames=self.getListOfFiles( self.dreamBeamFileListWidget) ) - elif source_format == SongFormat.PowerSong: - # Import PowerSong songs - importer = self.plugin.importSongs(SongFormat.PowerSong, - filenames=self.getListOfFiles( - self.powerSongFileListWidget) - ) elif source_format == SongFormat.SongsOfFellowship: # Import a Songs of Fellowship RTF file importer = self.plugin.importSongs(SongFormat.SongsOfFellowship, @@ -864,11 +853,7 @@ class SongImportForm(OpenLPWizard): filenames=self.getListOfFiles(self.foilPresenterFileListWidget) ) importer.doImport() - if importer.errorLog: - self.progressLabel.setText(translate( - 'SongsPlugin.SongImportForm', 'Your song import failed.')) - else: - self.progressLabel.setText(WizardStrings.FinishedImport) + self.progressLabel.setText(WizardStrings.FinishedImport) def onErrorCopyToButtonClicked(self): """ diff --git a/openlp/plugins/songs/lib/powersongimport.py b/openlp/plugins/songs/lib/powersongimport.py index 31491398c..9946d273d 100644 --- a/openlp/plugins/songs/lib/powersongimport.py +++ b/openlp/plugins/songs/lib/powersongimport.py @@ -29,8 +29,11 @@ The :mod:`powersongimport` module provides the functionality for importing PowerSong songs into the OpenLP database. """ import logging +import fnmatch +import os from openlp.core.lib import translate +from openlp.core.ui.wizard import WizardStrings from openlp.plugins.songs.lib.songimport import SongImport log = logging.getLogger(__name__) @@ -69,13 +72,39 @@ class PowerSongImport(SongImport): * .song """ + @staticmethod + def isValidSource(**kwargs): + """ + Checks if source is a PowerSong 1.0 folder: + * is a directory + * contains at least one *.song file + """ + if u'folder' in kwargs: + dir = kwargs[u'folder'] + if os.path.isdir(dir): + for file in os.listdir(dir): + if fnmatch.fnmatch(file, u'*.song'): + return True + return False + def doImport(self): """ - Receive a list of files to import. + Receive either a list of files or a folder (unicode) to import. """ - if not isinstance(self.importSource, list): + if isinstance(self.importSource, unicode): + if os.path.isdir(self.importSource): + dir = self.importSource + self.importSource = [] + for file in os.listdir(dir): + if fnmatch.fnmatch(file, u'*.song'): + self.importSource.append(os.path.join(dir, file)) + else: + self.importSource = u'' + if not self.importSource or not isinstance(self.importSource, list): self.logError(unicode(translate('SongsPlugin.PowerSongImport', - 'No files to import.'))) + 'No songs to import.')), + unicode(translate('SongsPlugin.PowerSongImport', + 'No %s files found.' % WizardStrings.PS))) return self.importWizard.progressBar.setMaximum(len(self.importSource)) for file in self.importSource: @@ -92,9 +121,10 @@ class PowerSongImport(SongImport): field = self._readString(song_data) except ValueError: parse_error = True - self.logError(file, unicode( + self.logError(os.path.basename(file), unicode( translate('SongsPlugin.PowerSongImport', - 'Invalid PowerSong file. Unexpected byte value.'))) + 'Invalid %s file. Unexpected byte value.' + % WizardStrings.PS))) break else: if label == u'TITLE': @@ -110,26 +140,26 @@ class PowerSongImport(SongImport): continue # Check that file had TITLE field if not self.title: - self.logError(file, unicode( + self.logError(os.path.basename(file), unicode( translate('SongsPlugin.PowerSongImport', - 'Invalid PowerSong file. Missing "TITLE" header.'))) + 'Invalid %s file. Missing "TITLE" header.' + % WizardStrings.PS))) continue # Check that file had COPYRIGHTLINE label if not found_copyright: - self.logError(file, unicode( + self.logError(self.title, unicode( translate('SongsPlugin.PowerSongImport', - '"%s" Invalid PowerSong file. Missing "COPYRIGHTLINE" ' - 'header.' % self.title))) + 'Invalid %s file. Missing "COPYRIGHTLINE" ' + 'header.' % WizardStrings.PS))) continue # Check that file had at least one verse if not self.verses: - self.logError(file, unicode( + self.logError(self.title, unicode( translate('SongsPlugin.PowerSongImport', - '"%s" Verses not found. Missing "PART" header.' - % self.title))) + 'Verses not found. Missing "PART" header.'))) continue if not self.finish(): - self.logError(file) + self.logError(self.title) def _readString(self, file_object): """ diff --git a/openlp/plugins/songs/lib/songimport.py b/openlp/plugins/songs/lib/songimport.py index 9bfdce124..ac6818184 100644 --- a/openlp/plugins/songs/lib/songimport.py +++ b/openlp/plugins/songs/lib/songimport.py @@ -50,6 +50,13 @@ class SongImport(QtCore.QObject): whether the authors etc already exist and add them or refer to them as necessary """ + @staticmethod + def isValidSource(**kwargs): + """ + Override this method to validate the source prior to import. + """ + pass + def __init__(self, manager, **kwargs): """ Initialise and create defaults for properties @@ -65,14 +72,16 @@ class SongImport(QtCore.QObject): self.importSource = kwargs[u'filename'] elif u'filenames' in kwargs: self.importSource = kwargs[u'filenames'] + elif u'folder' in kwargs: + self.importSource = kwargs[u'folder'] else: - raise KeyError(u'Keyword arguments "filename[s]" not supplied.') + raise KeyError( + u'Keyword arguments "filename[s]" or "folder" not supplied.') log.debug(self.importSource) self.importWizard = None self.song = None self.stopImportFlag = False self.setDefaults() - self.errorLog = [] QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'openlp_stop_wizard'), self.stopImport)