From b95924ae74630adab2cc071d6391db9d982c7ba3 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Tue, 16 Aug 2011 22:58:07 -0400 Subject: [PATCH 01/53] Added code to export/import settings via an ini file --- openlp/core/ui/aboutdialog.py | 4 +- openlp/core/ui/mainwindow.py | 183 ++++++++++++++++++++++++++++++- openlp/core/ui/servicemanager.py | 23 ++-- 3 files changed, 192 insertions(+), 18 deletions(-) diff --git a/openlp/core/ui/aboutdialog.py b/openlp/core/ui/aboutdialog.py index 3e941c051..f4a732fb6 100644 --- a/openlp/core/ui/aboutdialog.py +++ b/openlp/core/ui/aboutdialog.py @@ -116,7 +116,7 @@ class Ui_AboutDialog(object): u'Scott "sguerrieri" Guerrieri', u'Matthias "matthub" Hub', u'Meinert "m2j" Jordan', u'Armin "orangeshirt" K\xf6hler', u'Joshua "milleja46" Miller', - u'Stevan "StevanP" Pettit', u'Mattias "mahfiaz" P\xf5ldaru', + u'Stevan "ElderP" Pettit', u'Mattias "mahfiaz" P\xf5ldaru', u'Christian "crichter" Richter', u'Philip "Phill" Ridout', u'Simon "samscudder" Scudder', u'Jeffrey "whydoubt" Smith', u'Maikel Stuivenberg', u'Frode "frodus" Woldsund'] @@ -125,7 +125,7 @@ class Ui_AboutDialog(object): packagers = ['Thomas "tabthorpe" Abthorpe (FreeBSD)', u'Tim "TRB143" Bentley (Fedora)', u'Matthias "matthub" Hub (Mac OS X)', - u'Stevan "StevanP" Pettit (Windows)', + u'Stevan "ElderP" Pettit (Windows)', u'Raoul "superfly" Snyman (Ubuntu)'] translators = { u'af': [u'Johan "nuvolari" Mynhardt'], diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 510a94dfd..609c02efa 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -27,13 +27,15 @@ import logging import os -import sys +import sys, string from tempfile import gettempdir +from datetime import datetime from PyQt4 import QtCore, QtGui from openlp.core.lib import Renderer, build_icon, OpenLPDockWidget, \ - PluginManager, Receiver, translate, ImageManager, PluginStatus + PluginManager, Receiver, translate, ImageManager, PluginStatus, \ + SettingsManager from openlp.core.lib.ui import UiStrings, base_action, checkable_action, \ icon_action, shortcut_action from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \ @@ -213,7 +215,7 @@ class Ui_MainWindow(object): self.mediaManagerDock.isVisible(), UiStrings().View) self.viewThemeManagerItem = shortcut_action(mainWindow, u'viewThemeManagerItem', [QtGui.QKeySequence(u'F10')], - self.toggleThemeManager, u':/system/system_thememanager.png', + self.toggleThemeManager, u':/system/system_thememanager.png', self.themeManagerDock.isVisible(), UiStrings().View) self.viewServiceManagerItem = shortcut_action(mainWindow, u'viewServiceManagerItem', [QtGui.QKeySequence(u'F9')], @@ -283,6 +285,12 @@ class Ui_MainWindow(object): self.settingsConfigureItem = icon_action(mainWindow, u'settingsConfigureItem', u':/system/system_settings.png', category=UiStrings().Settings) + self.settingsImportItem = icon_action(mainWindow, + u'settingsImportItem', u':/general/general_import.png', + category=UiStrings().Settings) + self.settingsExportItem = icon_action(mainWindow, + u'settingsExportItem', u':/general/general_export.png', + category=UiStrings().Settings) action_list.add_category(UiStrings().Help, CategoryOrder.standardMenu) self.aboutItem = shortcut_action(mainWindow, u'aboutItem', [QtGui.QKeySequence(u'Ctrl+F1')], self.onAboutItemClicked, @@ -324,12 +332,14 @@ class Ui_MainWindow(object): add_actions(self.settingsMenu, (self.settingsPluginListItem, self.settingsLanguageMenu.menuAction(), None, self.settingsConfigureItem, self.settingsShortcutsItem, - self.formattingTagItem)) + self.formattingTagItem, None, + self.settingsImportItem, self.settingsExportItem)) else: add_actions(self.settingsMenu, (self.settingsPluginListItem, self.settingsLanguageMenu.menuAction(), None, self.formattingTagItem, self.settingsShortcutsItem, - self.settingsConfigureItem)) + self.settingsConfigureItem, None, + self.settingsImportItem, self.settingsExportItem)) add_actions(self.toolsMenu, (self.toolsAddToolItem, None)) add_actions(self.toolsMenu, (self.toolsOpenDataFolder, None)) add_actions(self.toolsMenu, (self.toolsFirstTimeWizard, None)) @@ -356,6 +366,7 @@ class Ui_MainWindow(object): self.importLanguageItem.setVisible(False) self.exportLanguageItem.setVisible(False) self.setLockPanel(panelLocked) + self.settingsImported = False def retranslateUi(self, mainWindow): """ @@ -419,6 +430,10 @@ class Ui_MainWindow(object): translate('OpenLP.MainWindow', '&Configure Formatting Tags...')) self.settingsConfigureItem.setText( translate('OpenLP.MainWindow', '&Configure OpenLP...')) + self.settingsExportItem.setText( + translate('OpenLP.MainWindow', 'Export Settings')) + self.settingsImportItem.setText( + translate('OpenLP.MainWindow', 'Import Settings')) self.viewMediaManagerItem.setText( translate('OpenLP.MainWindow', '&Media Manager')) self.viewMediaManagerItem.setToolTip( @@ -522,8 +537,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): # (not for use by plugins) self.uiSettingsSection = u'user interface' self.generalSettingsSection = u'general' - self.serviceSettingsSection = u'servicemanager' + self.advancedlSettingsSection = u'advanced' + self.servicemanagerSettingsSection = u'servicemanager' self.songsSettingsSection = u'songs' + self.themesSettingsSection = u'themes' self.serviceNotSaved = False self.aboutForm = AboutForm(self) self.settingsForm = SettingsForm(self, self) @@ -572,6 +589,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtCore.SIGNAL(u'triggered()'), self.onSettingsConfigureItemClicked) QtCore.QObject.connect(self.settingsShortcutsItem, QtCore.SIGNAL(u'triggered()'), self.onSettingsShortcutsItemClicked) + QtCore.QObject.connect(self.settingsImportItem, + QtCore.SIGNAL(u'triggered()'), self.onSettingsImportItemClicked) + QtCore.QObject.connect(self.settingsExportItem, + QtCore.SIGNAL(u'triggered()'), self.onSettingsExportItemClicked) # i18n set signals for languages self.languageGroup.triggered.connect(LanguageManager.set_language) QtCore.QObject.connect(self.modeDefaultItem, @@ -871,6 +892,150 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): if self.shortcutForm.exec_(): self.shortcutForm.save() + def onSettingsImportItemClicked(self): + """ + Import settings from an export INI file + """ + answer = QtGui.QMessageBox.critical(self, + translate('OpenLP.MainWindow', 'Import settings?'), + translate('OpenLP.MainWindow', + 'Are you sure you want to import settings?\n\n' + 'Importing settings will make permanent changes to your current ' + 'OpenLP configuration.\n\n' + 'Importing incorrect settings may cause erratic behaviour or ' + 'OpenLP to terminate abnormally.'), + QtGui.QMessageBox.StandardButtons( + QtGui.QMessageBox.Yes | + QtGui.QMessageBox.No), + QtGui.QMessageBox.No) + if answer == QtGui.QMessageBox.No: + return + importFileName = unicode(QtGui.QFileDialog.getOpenFileName(self, + translate('OpenLP.MainWindow', 'Open File'), + '', + translate('OpenLP.MainWindow', + 'OpenLP Export Settings Files (*.ini)'))) + if not importFileName: + return + settingSections = [] + # Add main sections. + settingSections.extend([self.generalSettingsSection]) + settingSections.extend([self.advancedlSettingsSection]) + settingSections.extend([self.uiSettingsSection]) + settingSections.extend([self.servicemanagerSettingsSection]) + settingSections.extend([self.themesSettingsSection]) + settingSections.extend([u'SettingsExport']) + # Add plugin sections. + for plugin in self.pluginManager.plugins: + settingSections.extend([plugin.name]) + settings = QtCore.QSettings() + importSettings = QtCore.QSettings(importFileName, + QtCore.QSettings.IniFormat) + importKeys = importSettings.allKeys() + for sectionKey in importKeys: + # We need to handle the really bad files. + try: + section, key = string.split(sectionKey, u'/') + except: + section = u'unknown' + key = u'' + # Switch General back to lowercase. + if section == u'General': + section = u'general' + sectionKey = section + "/" + key + section = section.replace(u'_', u' ') + # Make sure it's a valid section for us. + if not section in settingSections: + QtGui.QMessageBox.critical(self, + translate('OpenLP.MainWindow', 'Import settings'), + translate('OpenLP.MainWindow', + 'The file you selected does appear to be a valid OpenLP ' + 'settings file.\n\n' + 'Section [%s] is not valid \n\n' + 'Processing has terminated and no changed have been made.' + % section), + QtGui.QMessageBox.StandardButtons( + QtGui.QMessageBox.Ok)) + return + # We have a good file, import it. + for sectionKey in importKeys: + value = importSettings.value(sectionKey) + # Get rid of the "_" we replaced the " " with. + sectionKey = sectionKey.replace(u'_', u' ') + settings.setValue(u'%s' % (sectionKey) , + QtCore.QVariant(value)) + # We must do an immediate restart or current configuration will + # overwrite what was just imported when application terminates + # normally. We need to exit without saving configuration. + QtGui.QMessageBox.information(self, + translate('OpenLP.MainWindow', 'Import settings'), + translate('OpenLP.MainWindow', + 'OpenLP will now close. Imported settings will ' + 'take place the next time you start OpenLP'), + QtGui.QMessageBox.StandardButtons( + QtGui.QMessageBox.Ok)) + self.settingsImported = True + self.cleanUp() + sys.exit() + + def onSettingsExportItemClicked(self, exportFileName=None): + """ + Export settings to an INI file + """ + if not exportFileName: + exportFileName = unicode(QtGui.QFileDialog.getSaveFileName(self, + translate('OpenLP.MainWindow', 'Export Settings File'), '', + translate('OpenLP.MainWindow', + 'OpenLP Export Settings File (*.ini)'))) + if not exportFileName: + return + self.saveSettings() + headerSection = u'SettingsExport' + settingSections = [] + # Add main sections. + settingSections.extend([self.generalSettingsSection]) + settingSections.extend([self.advancedlSettingsSection]) + settingSections.extend([self.uiSettingsSection]) + settingSections.extend([self.servicemanagerSettingsSection]) + settingSections.extend([self.themesSettingsSection]) + # Add plugin sections. + for plugin in self.pluginManager.plugins: + settingSections.extend([plugin.name]) + # Delete old file if found. + if os.path.exists(exportFileName): + os.remove(exportFileName) + settings = QtCore.QSettings() + settings.remove(headerSection) + # Get the settings. + keys = settings.allKeys() + exportSettings = QtCore.QSettings(exportFileName, + QtCore.QSettings.IniFormat) + # Add a header section. + # This is to insure it's our ini file for import. + now = datetime.now() + applicationVersion = get_application_version() + # Write INI format using Qsettings. + # Write our header. + exportSettings.beginGroup(headerSection) + exportSettings.setValue(u'Make_Changes', u'At Own RISK') + exportSettings.setValue(u'type', u'OpenLP_settings_export') + exportSettings.setValue(u'date_created', + now.strftime("%Y-%m-%d %H:%M")) + exportSettings.setValue(u'version', applicationVersion[u'full']) + exportSettings.endGroup() + # Write all the sections and keys. + for sectionKey in keys: + section, key = string.split(sectionKey, u'/') + keyValue = settings.value(sectionKey) + section = section.replace(u' ', u'_') + key = key.replace(u' ', u'_') + sectionKey = section + u"/" + key + # Change the service section to servicemanager. + if section == u'service': + sectionKey = u'servicemanager/' + key + exportSettings.setValue(sectionKey, keyValue) + return + def onModeDefaultItemClicked(self): """ Put OpenLP into "Default" view mode. @@ -923,6 +1088,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): """ Hook to close the main window and display windows on exit """ + # If we just did a settings import, close without saving changes. + if self.settingsImported: + event.accept() if self.serviceManagerContents.isModified(): ret = self.serviceManagerContents.saveModifiedService() if ret == QtGui.QMessageBox.Save: @@ -1120,6 +1288,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): """ Save the main window settings. """ + # Exit if we just did a settings import. + if self.settingsImported: + return log.debug(u'Saving QSettings') settings = QtCore.QSettings() settings.beginGroup(self.generalSettingsSection) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 0ef45af12..c1a6ddb9d 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -289,7 +289,7 @@ class ServiceManager(QtGui.QWidget): QtCore.SIGNAL(u'service_item_update'), self.serviceItemUpdate) # Last little bits of setting up self.service_theme = unicode(QtCore.QSettings().value( - self.mainwindow.serviceSettingsSection + u'/service theme', + self.mainwindow.servicemanagerSettingsSection + u'/service theme', QtCore.QVariant(u'')).toString()) self.servicePath = AppLocation.get_section_data_path(u'servicemanager') # build the drag and drop context menu @@ -370,7 +370,7 @@ class ServiceManager(QtGui.QWidget): self.mainwindow.setServiceModified(self.isModified(), self.shortFileName()) QtCore.QSettings(). \ - setValue(u'service/last file',QtCore.QVariant(fileName)) + setValue(u'servicemanager/last file',QtCore.QVariant(fileName)) def fileName(self): """ @@ -428,14 +428,15 @@ class ServiceManager(QtGui.QWidget): self.mainwindow, translate('OpenLP.ServiceManager', 'Open File'), SettingsManager.get_last_dir( - self.mainwindow.serviceSettingsSection), + self.mainwindow.servicemanagerSettingsSection), translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz)'))) if not fileName: return False else: fileName = loadFile - SettingsManager.set_last_dir(self.mainwindow.serviceSettingsSection, + SettingsManager.set_last_dir( + self.mainwindow.servicemanagerSettingsSection, split_filename(fileName)[0]) self.loadFile(fileName) @@ -460,7 +461,7 @@ class ServiceManager(QtGui.QWidget): self.setFileName(u'') self.setModified(False) QtCore.QSettings(). \ - setValue(u'service/last file',QtCore.QVariant(u'')) + setValue(u'servicemanager/last file',QtCore.QVariant(u'')) def saveFile(self): """ @@ -473,7 +474,8 @@ class ServiceManager(QtGui.QWidget): (basename, extension) = os.path.splitext(file_name) service_file_name = basename + '.osd' log.debug(u'ServiceManager.saveFile - %s' % path_file_name) - SettingsManager.set_last_dir(self.mainwindow.serviceSettingsSection, + SettingsManager.set_last_dir( + self.mainwindow.servicemanagerSettingsSection, path) service = [] write_list = [] @@ -561,7 +563,7 @@ class ServiceManager(QtGui.QWidget): fileName = unicode(QtGui.QFileDialog.getSaveFileName(self.mainwindow, UiStrings().SaveService, SettingsManager.get_last_dir( - self.mainwindow.serviceSettingsSection), + self.mainwindow.servicemanagerSettingsSection), translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz)'))) if not fileName: return False @@ -623,7 +625,7 @@ class ServiceManager(QtGui.QWidget): self.mainwindow.addRecentFile(fileName) self.setModified(False) QtCore.QSettings().setValue( - 'service/last file', QtCore.QVariant(fileName)) + 'servicemanager/last file', QtCore.QVariant(fileName)) else: critical_error_message_box( message=translate('OpenLP.ServiceManager', @@ -665,7 +667,7 @@ class ServiceManager(QtGui.QWidget): present. """ fileName = QtCore.QSettings(). \ - value(u'service/last file',QtCore.QVariant(u'')).toString() + value(u'servicemanager/last file',QtCore.QVariant(u'')).toString() if fileName: self.loadFile(fileName) @@ -1004,7 +1006,8 @@ class ServiceManager(QtGui.QWidget): self.service_theme = unicode(self.themeComboBox.currentText()) self.mainwindow.renderer.set_service_theme(self.service_theme) QtCore.QSettings().setValue( - self.mainwindow.serviceSettingsSection + u'/service theme', + self.mainwindow.servicemanagerSettingsSection + + u'/service theme', QtCore.QVariant(self.service_theme)) self.regenerateServiceItems() From 9f284d9ab20fc38f7a0121b7982e059677a5b003 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Thu, 18 Aug 2011 22:43:08 -0400 Subject: [PATCH 02/53] Moved export/import settings menu items from tools to file menu. Added status-tips --- openlp/core/ui/mainwindow.py | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 609c02efa..0a51c2bf3 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -285,12 +285,10 @@ class Ui_MainWindow(object): self.settingsConfigureItem = icon_action(mainWindow, u'settingsConfigureItem', u':/system/system_settings.png', category=UiStrings().Settings) - self.settingsImportItem = icon_action(mainWindow, - u'settingsImportItem', u':/general/general_import.png', - category=UiStrings().Settings) - self.settingsExportItem = icon_action(mainWindow, - u'settingsExportItem', u':/general/general_export.png', - category=UiStrings().Settings) + self.settingsImportItem = base_action(mainWindow, + u'settingsImportItem', category=UiStrings().Settings) + self.settingsExportItem = base_action(mainWindow, + u'settingsExportItem', category=UiStrings().Settings) action_list.add_category(UiStrings().Help, CategoryOrder.standardMenu) self.aboutItem = shortcut_action(mainWindow, u'aboutItem', [QtGui.QKeySequence(u'Ctrl+F1')], self.onAboutItemClicked, @@ -308,10 +306,10 @@ class Ui_MainWindow(object): u':/system/system_online_help.png', category=UiStrings().Help) self.webSiteItem = base_action( mainWindow, u'webSiteItem', category=UiStrings().Help) - add_actions(self.fileImportMenu, - (self.importThemeItem, self.importLanguageItem)) - add_actions(self.fileExportMenu, - (self.exportThemeItem, self.exportLanguageItem)) + add_actions(self.fileImportMenu, (self.settingsImportItem, None, + self.importThemeItem, self.importLanguageItem)) + add_actions(self.fileExportMenu, (self.settingsExportItem, None, + self.exportThemeItem, self.exportLanguageItem)) add_actions(self.fileMenu, (self.fileNewItem, self.fileOpenItem, self.fileSaveItem, self.fileSaveAsItem, None, self.recentFilesMenu.menuAction(), None, self.printServiceOrderItem, @@ -332,14 +330,12 @@ class Ui_MainWindow(object): add_actions(self.settingsMenu, (self.settingsPluginListItem, self.settingsLanguageMenu.menuAction(), None, self.settingsConfigureItem, self.settingsShortcutsItem, - self.formattingTagItem, None, - self.settingsImportItem, self.settingsExportItem)) + self.formattingTagItem)) else: add_actions(self.settingsMenu, (self.settingsPluginListItem, self.settingsLanguageMenu.menuAction(), None, self.formattingTagItem, self.settingsShortcutsItem, - self.settingsConfigureItem, None, - self.settingsImportItem, self.settingsExportItem)) + self.settingsConfigureItem)) add_actions(self.toolsMenu, (self.toolsAddToolItem, None)) add_actions(self.toolsMenu, (self.toolsOpenDataFolder, None)) add_actions(self.toolsMenu, (self.toolsFirstTimeWizard, None)) @@ -430,10 +426,15 @@ class Ui_MainWindow(object): translate('OpenLP.MainWindow', '&Configure Formatting Tags...')) self.settingsConfigureItem.setText( translate('OpenLP.MainWindow', '&Configure OpenLP...')) + self.settingsExportItem.setStatusTip(translate('OpenLP.MainWindow', + 'Export OpenLP settings to a specified Ini file')) self.settingsExportItem.setText( - translate('OpenLP.MainWindow', 'Export Settings')) + translate('OpenLP.MainWindow', 'Settings')) + self.settingsImportItem.setStatusTip(translate('OpenLP.MainWindow', + 'Import OpenLP settings from a specified Ini file previously ' + 'exported on this or another machine')) self.settingsImportItem.setText( - translate('OpenLP.MainWindow', 'Import Settings')) + translate('OpenLP.MainWindow', 'Settings')) self.viewMediaManagerItem.setText( translate('OpenLP.MainWindow', '&Media Manager')) self.viewMediaManagerItem.setToolTip( From ad61defdae087489603f70412df5491adc447270 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 20 Aug 2011 12:45:06 +0100 Subject: [PATCH 03/53] Add border colors and fix song usage --- openlp/core/lib/__init__.py | 2 +- openlp/core/lib/imagemanager.py | 20 +++++++++++++++----- openlp/core/lib/renderer.py | 5 +++-- openlp/core/lib/serviceitem.py | 8 ++++++-- openlp/core/lib/theme.py | 7 +++++-- openlp/core/ui/printserviceform.py | 5 ++++- openlp/core/ui/themeform.py | 12 ++++++++++++ openlp/core/ui/themewizard.py | 12 +++++++++++- openlp/plugins/images/imageplugin.py | 5 +++-- openlp/plugins/images/lib/__init__.py | 1 + openlp/plugins/images/lib/mediaitem.py | 4 +++- openlp/plugins/songusage/songusageplugin.py | 3 +++ 12 files changed, 67 insertions(+), 17 deletions(-) diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index f83e92de7..d9d29efab 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -137,7 +137,7 @@ def image_to_byte(image): # convert to base64 encoding so does not get missed! return byte_array.toBase64() -def resize_image(image_path, width, height, background=QtCore.Qt.black): +def resize_image(image_path, width, height, background): """ Resize an image to fit on the current screen. diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index 37d1de79c..a4a60b2f4 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -36,7 +36,7 @@ import Queue from PyQt4 import QtCore -from openlp.core.lib import resize_image, image_to_byte +from openlp.core.lib import resize_image, image_to_byte, Receiver from openlp.core.ui import ScreenList log = logging.getLogger(__name__) @@ -100,12 +100,14 @@ class Image(object): variables ``image`` and ``image_bytes`` to ``None`` and add the image object to the queue of images to process. """ - def __init__(self, name='', path=''): + def __init__(self, name, path, source, background): self.name = name self.path = path self.image = None self.image_bytes = None self.priority = Priority.Normal + self.source = source + self.background = background class PriorityQueue(Queue.PriorityQueue): @@ -151,6 +153,8 @@ class ImageManager(QtCore.QObject): self._cache = {} self._imageThread = ImageThread(self) self._conversion_queue = PriorityQueue() + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'config_updated'), self.config_updated) def update_display(self): """ @@ -168,6 +172,11 @@ class ImageManager(QtCore.QObject): image.image = None image.image_bytes = None self._conversion_queue.put((image.priority, image)) + + def config_updated(self): + """ + Flush the queue to updated any data to update + """ # We want only one thread. if not self._imageThread.isRunning(): self._imageThread.start() @@ -215,13 +224,13 @@ class ImageManager(QtCore.QObject): self._conversion_queue.remove(self._cache[name]) del self._cache[name] - def add_image(self, name, path): + def add_image(self, name, path, source, background): """ Add image to cache if it is not already there. """ log.debug(u'add_image %s:%s' % (name, path)) if not name in self._cache: - image = Image(name, path) + image = Image(name, path, source, background) self._cache[name] = image self._conversion_queue.put((image.priority, image)) else: @@ -247,7 +256,8 @@ class ImageManager(QtCore.QObject): image = self._conversion_queue.get()[1] # Generate the QImage for the image. if image.image is None: - image.image = resize_image(image.path, self.width, self.height) + image.image = resize_image(image.path, self.width, self.height, + image.background) # Set the priority to Lowest and stop here as we need to process # more important images first. if image.priority == Priority.Normal: diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index ac7e95c4c..9ea9c8094 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -27,7 +27,7 @@ import logging -from PyQt4 import QtCore, QtWebKit +from PyQt4 import QtGui, QtCore, QtWebKit from openlp.core.lib import ServiceItem, expand_tags, \ build_lyrics_format_css, build_lyrics_outline_css, Receiver, \ @@ -166,7 +166,8 @@ class Renderer(object): # if No file do not update cache if self.theme_data.background_filename: self.imageManager.add_image(self.theme_data.theme_name, - self.theme_data.background_filename) + self.theme_data.background_filename, u'theme', + QtGui.QColor(self.theme_data.background_border_color)) return self._rect, self._rect_footer def generate_preview(self, theme_data, force_page=False): diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index 15c16c551..7be28520c 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -115,6 +115,7 @@ class ServiceItem(object): self.end_time = 0 self.media_length = 0 self.from_service = False + self.image_border = u'#000000' self._new_item() def _new_item(self): @@ -195,7 +196,7 @@ class ServiceItem(object): self.foot_text = \ u'
'.join([footer for footer in self.raw_footer if footer]) - def add_from_image(self, path, title): + def add_from_image(self, path, title, background=None): """ Add an image slide to the service item. @@ -205,9 +206,12 @@ class ServiceItem(object): ``title`` A title for the slide in the service item. """ + if background: + self.image_border = background self.service_item_type = ServiceItemType.Image self._raw_frames.append({u'title': title, u'path': path}) - self.renderer.imageManager.add_image(title, path) + self.renderer.imageManager.add_image(title, path, u'image', + self.image_border) self._new_item() def add_from_text(self, title, raw_slide, verse_tag=None): diff --git a/openlp/core/lib/theme.py b/openlp/core/lib/theme.py index c87f9aa2e..3b0a62f5b 100644 --- a/openlp/core/lib/theme.py +++ b/openlp/core/lib/theme.py @@ -44,6 +44,7 @@ BLANK_THEME_XML = \ + #000000 #000000 @@ -282,7 +283,7 @@ class ThemeXML(object): # Create direction element self.child_element(background, u'direction', unicode(direction)) - def add_background_image(self, filename): + def add_background_image(self, filename, borderColor): """ Add a image background. @@ -294,6 +295,8 @@ class ThemeXML(object): self.theme.appendChild(background) # Create Filename element self.child_element(background, u'filename', filename) + # Create endColor element + self.child_element(background, u'borderColor', unicode(borderColor)) def add_font(self, name, color, size, override, fonttype=u'main', bold=u'False', italics=u'False', line_adjustment=0, @@ -597,7 +600,7 @@ class ThemeXML(object): self.background_direction) else: filename = os.path.split(self.background_filename)[1] - self.add_background_image(filename) + self.add_background_image(filename, self.background_border_color) self.add_font(self.font_main_name, self.font_main_color, self.font_main_size, diff --git a/openlp/core/ui/printserviceform.py b/openlp/core/ui/printserviceform.py index 55fc6eb3c..f33092061 100644 --- a/openlp/core/ui/printserviceform.py +++ b/openlp/core/ui/printserviceform.py @@ -31,7 +31,7 @@ import os from PyQt4 import QtCore, QtGui from lxml import html -from openlp.core.lib import translate, get_text_file_string +from openlp.core.lib import translate, get_text_file_string, Receiver from openlp.core.lib.ui import UiStrings from openlp.core.ui.printservicedialog import Ui_PrintServiceDialog, ZoomSize from openlp.core.utils import AppLocation @@ -188,6 +188,9 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): html_data.body, classId=u'serviceTitle') for index, item in enumerate(self.serviceManager.serviceItems): self._addPreviewItem(html_data.body, item[u'service_item'], index) + # Trigger Audit requests + Receiver.send_message(u'print_service_started', + [item[u'service_item']]) # Add the custom service notes: if self.footerTextEdit.toPlainText(): div = self._addElement(u'div', parent=html_data.body, diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index d5d955926..b56b68b5b 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -66,6 +66,8 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): self.onGradientComboBoxCurrentIndexChanged) QtCore.QObject.connect(self.colorButton, QtCore.SIGNAL(u'clicked()'), self.onColorButtonClicked) + QtCore.QObject.connect(self.imageColorButton, + QtCore.SIGNAL(u'clicked()'), self.onImageColorButtonClicked) QtCore.QObject.connect(self.gradientStartButton, QtCore.SIGNAL(u'clicked()'), self.onGradientStartButtonClicked) QtCore.QObject.connect(self.gradientEndButton, @@ -330,6 +332,8 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): self.theme.background_end_color) self.setField(u'background_type', QtCore.QVariant(1)) else: + self.imageColorButton.setStyleSheet(u'background-color: %s' % + self.theme.background_border_color) self.imageFileEdit.setText(self.theme.background_filename) self.setField(u'background_type', QtCore.QVariant(2)) if self.theme.background_direction == \ @@ -464,6 +468,14 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): self._colorButton(self.theme.background_color) self.setBackgroundPageValues() + def onImageColorButtonClicked(self): + """ + Background / Gradient 1 Color button pushed. + """ + self.theme.background_border_color = \ + self._colorButton(self.theme.background_border_color) + self.setBackgroundPageValues() + def onGradientStartButtonClicked(self): """ Gradient 2 Color button pushed. diff --git a/openlp/core/ui/themewizard.py b/openlp/core/ui/themewizard.py index 27ac3a182..805ce876b 100644 --- a/openlp/core/ui/themewizard.py +++ b/openlp/core/ui/themewizard.py @@ -64,6 +64,7 @@ class Ui_ThemeWizard(object): self.backgroundStack.setObjectName(u'BackgroundStack') self.colorWidget = QtGui.QWidget(self.backgroundPage) self.colorWidget.setObjectName(u'ColorWidget') + self.colorLayout = QtGui.QFormLayout(self.colorWidget) self.colorLayout.setMargin(0) self.colorLayout.setObjectName(u'ColorLayout') @@ -73,6 +74,7 @@ class Ui_ThemeWizard(object): self.colorButton.setObjectName(u'ColorButton') self.colorLayout.addRow(self.colorLabel, self.colorButton) self.colorLayout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer) + self.backgroundStack.addWidget(self.colorWidget) self.gradientWidget = QtGui.QWidget(self.backgroundPage) self.gradientWidget.setObjectName(u'GradientWidget') @@ -100,11 +102,17 @@ class Ui_ThemeWizard(object): self.gradientComboBox) self.gradientLayout.setItem(3, QtGui.QFormLayout.LabelRole, self.spacer) self.backgroundStack.addWidget(self.gradientWidget) + self.imageWidget = QtGui.QWidget(self.backgroundPage) self.imageWidget.setObjectName(u'ImageWidget') self.imageLayout = QtGui.QFormLayout(self.imageWidget) self.imageLayout.setMargin(0) self.imageLayout.setObjectName(u'ImageLayout') + self.imageColorLabel = QtGui.QLabel(self.colorWidget) + self.imageColorLabel.setObjectName(u'ImageColorLabel') + self.imageColorButton = QtGui.QPushButton(self.colorWidget) + self.imageColorButton.setObjectName(u'ImageColorButton') + self.imageLayout.addRow(self.imageColorLabel, self.imageColorButton) self.imageLabel = QtGui.QLabel(self.imageWidget) self.imageLabel.setObjectName(u'ImageLabel') self.imageFileLayout = QtGui.QHBoxLayout() @@ -118,7 +126,7 @@ class Ui_ThemeWizard(object): build_icon(u':/general/general_open.png')) self.imageFileLayout.addWidget(self.imageBrowseButton) self.imageLayout.addRow(self.imageLabel, self.imageFileLayout) - self.imageLayout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer) + self.imageLayout.setItem(2, QtGui.QFormLayout.LabelRole, self.spacer) self.backgroundStack.addWidget(self.imageWidget) self.backgroundLayout.addLayout(self.backgroundStack) themeWizard.addPage(self.backgroundPage) @@ -443,6 +451,8 @@ class Ui_ThemeWizard(object): translate('OpenLP.ThemeWizard', 'Top Left - Bottom Right')) self.gradientComboBox.setItemText(BackgroundGradientType.LeftBottom, translate('OpenLP.ThemeWizard', 'Bottom Left - Top Right')) + self.imageColorLabel.setText( + translate(u'OpenLP.ThemeWizard', 'Border color:')) self.imageLabel.setText(u'%s:' % UiStrings().Image) self.mainAreaPage.setTitle( translate('OpenLP.ThemeWizard', 'Main Area Font Details')) diff --git a/openlp/plugins/images/imageplugin.py b/openlp/plugins/images/imageplugin.py index 1ddbe8357..aeeee5c5d 100644 --- a/openlp/plugins/images/imageplugin.py +++ b/openlp/plugins/images/imageplugin.py @@ -28,7 +28,7 @@ import logging from openlp.core.lib import Plugin, StringContent, build_icon, translate -from openlp.plugins.images.lib import ImageMediaItem +from openlp.plugins.images.lib import ImageMediaItem, ImageTab log = logging.getLogger(__name__) @@ -36,7 +36,8 @@ class ImagePlugin(Plugin): log.info(u'Image Plugin loaded') def __init__(self, plugin_helpers): - Plugin.__init__(self, u'images', plugin_helpers, ImageMediaItem) + Plugin.__init__(self, u'images', plugin_helpers, ImageMediaItem, + ImageTab) self.weight = -7 self.icon_path = u':/plugins/plugin_images.png' self.icon = build_icon(self.icon_path) diff --git a/openlp/plugins/images/lib/__init__.py b/openlp/plugins/images/lib/__init__.py index b26d00184..e216623cd 100644 --- a/openlp/plugins/images/lib/__init__.py +++ b/openlp/plugins/images/lib/__init__.py @@ -26,3 +26,4 @@ ############################################################################### from mediaitem import ImageMediaItem +from imagetab import ImageTab diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index acd420880..d88cf47e7 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -140,6 +140,8 @@ class ImageMediaItem(MediaManagerItem): self.plugin.formparent.finishedProgressBar() def generateSlideData(self, service_item, item=None, xmlVersion=False): + background = QtGui.QColor(QtCore.QSettings().value(self.settingsSection + + u'/background color', QtCore.QVariant(u'#000000'))) if item: items = [item] else: @@ -183,7 +185,7 @@ class ImageMediaItem(MediaManagerItem): for bitem in items: filename = unicode(bitem.data(QtCore.Qt.UserRole).toString()) (path, name) = os.path.split(filename) - service_item.add_from_image(filename, name) + service_item.add_from_image(filename, name, background) return True def onResetClick(self): diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index 4ca23aeb0..55e968360 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -121,6 +121,9 @@ class SongUsagePlugin(Plugin): QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'slidecontroller_live_started'), self.onReceiveSongUsage) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'print_service_started'), + self.onReceiveSongUsage) self.songUsageActive = QtCore.QSettings().value( self.settingsSection + u'/active', QtCore.QVariant(False)).toBool() From cc1e174d6246a56eed19944bbe0c1ede43fca4ae Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 20 Aug 2011 14:21:25 +0100 Subject: [PATCH 04/53] Updates --- openlp/core/lib/imagemanager.py | 16 ++++++++++++++++ openlp/core/ui/themewizard.py | 3 --- openlp/plugins/images/imageplugin.py | 12 +++++++++++- openlp/plugins/images/lib/mediaitem.py | 4 ++-- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index a4a60b2f4..3de1ff532 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -173,6 +173,22 @@ class ImageManager(QtCore.QObject): image.image_bytes = None self._conversion_queue.put((image.priority, image)) + def update_images(self, background): + """ + Screen has changed size so rebuild the cache to new size. + """ + log.debug(u'update_images') + # Mark the images as dirty for a rebuild by setting the image and byte + # stream to None. + self._conversion_queue = PriorityQueue() + for key, image in self._cache.iteritems(): + if image.source == u'images': + image.background = background + image.priority = Priority.Normal + image.image = None + image.image_bytes = None + self._conversion_queue.put((image.priority, image)) + def config_updated(self): """ Flush the queue to updated any data to update diff --git a/openlp/core/ui/themewizard.py b/openlp/core/ui/themewizard.py index 805ce876b..12fc70760 100644 --- a/openlp/core/ui/themewizard.py +++ b/openlp/core/ui/themewizard.py @@ -64,7 +64,6 @@ class Ui_ThemeWizard(object): self.backgroundStack.setObjectName(u'BackgroundStack') self.colorWidget = QtGui.QWidget(self.backgroundPage) self.colorWidget.setObjectName(u'ColorWidget') - self.colorLayout = QtGui.QFormLayout(self.colorWidget) self.colorLayout.setMargin(0) self.colorLayout.setObjectName(u'ColorLayout') @@ -74,7 +73,6 @@ class Ui_ThemeWizard(object): self.colorButton.setObjectName(u'ColorButton') self.colorLayout.addRow(self.colorLabel, self.colorButton) self.colorLayout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer) - self.backgroundStack.addWidget(self.colorWidget) self.gradientWidget = QtGui.QWidget(self.backgroundPage) self.gradientWidget.setObjectName(u'GradientWidget') @@ -102,7 +100,6 @@ class Ui_ThemeWizard(object): self.gradientComboBox) self.gradientLayout.setItem(3, QtGui.QFormLayout.LabelRole, self.spacer) self.backgroundStack.addWidget(self.gradientWidget) - self.imageWidget = QtGui.QWidget(self.backgroundPage) self.imageWidget.setObjectName(u'ImageWidget') self.imageLayout = QtGui.QFormLayout(self.imageWidget) diff --git a/openlp/plugins/images/imageplugin.py b/openlp/plugins/images/imageplugin.py index aeeee5c5d..1d1ef46ee 100644 --- a/openlp/plugins/images/imageplugin.py +++ b/openlp/plugins/images/imageplugin.py @@ -25,9 +25,12 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### +from PyQt4 import QtCore, QtGui + import logging -from openlp.core.lib import Plugin, StringContent, build_icon, translate +from openlp.core.lib import Plugin, StringContent, build_icon, translate, \ + Receiver from openlp.plugins.images.lib import ImageMediaItem, ImageTab log = logging.getLogger(__name__) @@ -41,6 +44,8 @@ class ImagePlugin(Plugin): self.weight = -7 self.icon_path = u':/plugins/plugin_images.png' self.icon = build_icon(self.icon_path) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'image_updated'), self.image_updated) def about(self): about_text = translate('ImagePlugin', 'Image Plugin' @@ -82,3 +87,8 @@ class ImagePlugin(Plugin): 'Add the selected image to the service.') } self.setPluginUiTextStrings(tooltips) + + def image_updated(self): + background = QtGui.QColor(QtCore.QSettings().value(self.settingsSection + + u'/background color', QtCore.QVariant(u'#000000'))) + self.liveController.imageManager.update_images(background) diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index d88cf47e7..d00b8c9f0 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -140,8 +140,8 @@ class ImageMediaItem(MediaManagerItem): self.plugin.formparent.finishedProgressBar() def generateSlideData(self, service_item, item=None, xmlVersion=False): - background = QtGui.QColor(QtCore.QSettings().value(self.settingsSection + - u'/background color', QtCore.QVariant(u'#000000'))) + background = QtGui.QColor(QtCore.QSettings().value(self.settingsSection + + u'/background color', QtCore.QVariant(u'#000000'))) if item: items = [item] else: From 3c17af592dc75940b367e93d693087ef1c453a71 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 20 Aug 2011 16:02:57 +0100 Subject: [PATCH 05/53] Fix autoupdates --- openlp/core/lib/imagemanager.py | 8 ++++---- openlp/core/ui/themeform.py | 2 +- openlp/core/ui/thememanager.py | 5 +++++ openlp/plugins/images/imageplugin.py | 7 ++++++- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index 3de1ff532..87501602e 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -154,7 +154,7 @@ class ImageManager(QtCore.QObject): self._imageThread = ImageThread(self) self._conversion_queue = PriorityQueue() QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'config_updated'), self.config_updated) + QtCore.SIGNAL(u'config_updated'), self.process_updates) def update_display(self): """ @@ -173,7 +173,7 @@ class ImageManager(QtCore.QObject): image.image_bytes = None self._conversion_queue.put((image.priority, image)) - def update_images(self, background): + def update_images(self, image_type, background): """ Screen has changed size so rebuild the cache to new size. """ @@ -182,14 +182,14 @@ class ImageManager(QtCore.QObject): # stream to None. self._conversion_queue = PriorityQueue() for key, image in self._cache.iteritems(): - if image.source == u'images': + if image.source == image_type: image.background = background image.priority = Priority.Normal image.image = None image.image_bytes = None self._conversion_queue.put((image.priority, image)) - def config_updated(self): + def process_updates(self): """ Flush the queue to updated any data to update """ diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index b56b68b5b..dc3c23d0d 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -576,7 +576,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): def accept(self): """ - Lets save the them as Finish has been pressed + Lets save the theme as Finish has been pressed """ # Save the theme name self.theme.theme_name = unicode(self.field(u'name').toString()) diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index 69c229532..40b39b7fd 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -610,6 +610,11 @@ class ThemeManager(QtGui.QWidget): and to trigger the reload of the theme list """ self._writeTheme(theme, imageFrom, imageTo) + if theme.background_type == \ + BackgroundType.to_string(BackgroundType.Image): + self.mainwindow.imageManager.update_images(u'theme', + QtGui.QColor(theme.background_border_color)) + self.mainwindow.imageManager.process_updates() self.loadThemes() def _writeTheme(self, theme, imageFrom, imageTo): diff --git a/openlp/plugins/images/imageplugin.py b/openlp/plugins/images/imageplugin.py index 1d1ef46ee..4b5a6f3c0 100644 --- a/openlp/plugins/images/imageplugin.py +++ b/openlp/plugins/images/imageplugin.py @@ -89,6 +89,11 @@ class ImagePlugin(Plugin): self.setPluginUiTextStrings(tooltips) def image_updated(self): + """ + Triggered by saving and changing the image border. Sets the images in + image manager to require updates. Actual update is triggered by the + last part of saving the config. + """ background = QtGui.QColor(QtCore.QSettings().value(self.settingsSection + u'/background color', QtCore.QVariant(u'#000000'))) - self.liveController.imageManager.update_images(background) + self.liveController.imageManager.update_images(u'image', background) From d660d1d5aea1036a1d638420e194aba12a63c714 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 21 Aug 2011 05:51:03 +0100 Subject: [PATCH 06/53] Add missing file --- openlp/plugins/images/lib/imagetab.py | 99 +++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 openlp/plugins/images/lib/imagetab.py diff --git a/openlp/plugins/images/lib/imagetab.py b/openlp/plugins/images/lib/imagetab.py new file mode 100644 index 000000000..640cd4495 --- /dev/null +++ b/openlp/plugins/images/lib/imagetab.py @@ -0,0 +1,99 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2011 Raoul Snyman # +# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, # +# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias # +# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### + +from PyQt4 import QtCore, QtGui + +from openlp.core.lib import SettingsTab, translate, Receiver +from openlp.core.lib.ui import UiStrings, create_valign_combo + +class ImageTab(SettingsTab): + """ + ImageTab is the images settings tab in the settings dialog. + """ + def __init__(self, parent, name, visible_title, icon_path): + SettingsTab.__init__(self, parent, name, visible_title, icon_path) + + def setupUi(self): + self.setObjectName(u'ImagesTab') + SettingsTab.setupUi(self) + self.fontGroupBox = QtGui.QGroupBox(self.leftColumn) + self.fontGroupBox.setObjectName(u'FontGroupBox') + self.formLayout = QtGui.QFormLayout(self.fontGroupBox) + self.formLayout.setObjectName(u'FormLayout') + self.colorLayout = QtGui.QHBoxLayout() + self.backgroundColorLabel = QtGui.QLabel(self.fontGroupBox) + self.backgroundColorLabel.setObjectName(u'BackgroundColorLabel') + self.colorLayout.addWidget(self.backgroundColorLabel) + self.backgroundColorButton = QtGui.QPushButton(self.fontGroupBox) + self.backgroundColorButton.setObjectName(u'BackgroundColorButton') + self.colorLayout.addWidget(self.backgroundColorButton) + self.formLayout.addRow(self.colorLayout) + self.informationLabel = QtGui.QLabel(self.fontGroupBox) + self.informationLabel.setObjectName(u'InformationLabel') + self.formLayout.addRow(self.informationLabel) + self.leftLayout.addWidget(self.fontGroupBox) + self.leftLayout.addStretch() + self.rightLayout.addStretch() + # Signals and slots + QtCore.QObject.connect(self.backgroundColorButton, + QtCore.SIGNAL(u'pressed()'), self.onbackgroundColorButtonClicked) + + def retranslateUi(self): + self.fontGroupBox.setTitle( + translate('ImagesPlugin.ImageTab', 'Background Font')) + self.backgroundColorLabel.setText( + translate('ImagesPlugin.ImageTab', 'Background color:')) + self.informationLabel.setText( + translate('ImagesPlugin.ImageTab', 'Provides border where image ' + 'is not the correct dimensions for the screen when resized.')) + + def onbackgroundColorButtonClicked(self): + new_color = QtGui.QColorDialog.getColor( + QtGui.QColor(self.bg_color), self) + if new_color.isValid(): + self.bg_color = new_color.name() + self.backgroundColorButton.setStyleSheet( + u'background-color: %s' % self.bg_color) + + def load(self): + settings = QtCore.QSettings() + settings.beginGroup(self.settingsSection) + self.bg_color = unicode(settings.value( + u'background color', QtCore.QVariant(u'#000000')).toString()) + self.initial_color = self.bg_color + settings.endGroup() + self.backgroundColorButton.setStyleSheet( + u'background-color: %s' % self.bg_color) + + def save(self): + settings = QtCore.QSettings() + settings.beginGroup(self.settingsSection) + settings.setValue(u'background color', QtCore.QVariant(self.bg_color)) + settings.endGroup() + if self.initial_color != self.bg_color: + Receiver.send_message(u'image_updated') + From 21bf34c436c70389a14ad8f2bc14cf148032d557 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 21 Aug 2011 06:33:07 +0100 Subject: [PATCH 07/53] Theme fix --- openlp/core/lib/imagemanager.py | 18 +++++++++++++++++- openlp/core/ui/thememanager.py | 4 ++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index 87501602e..70d4b46ec 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -175,7 +175,7 @@ class ImageManager(QtCore.QObject): def update_images(self, image_type, background): """ - Screen has changed size so rebuild the cache to new size. + Border has changed so update all the images affected. """ log.debug(u'update_images') # Mark the images as dirty for a rebuild by setting the image and byte @@ -189,6 +189,22 @@ class ImageManager(QtCore.QObject): image.image_bytes = None self._conversion_queue.put((image.priority, image)) + def update_image(self, name, image_type, background): + """ + Border has changed so update the image affected. + """ + log.debug(u'update_images') + # Mark the images as dirty for a rebuild by setting the image and byte + # stream to None. + self._conversion_queue = PriorityQueue() + for key, image in self._cache.iteritems(): + if image.source == image_type and image.name == name: + image.background = background + image.priority = Priority.Normal + image.image = None + image.image_bytes = None + self._conversion_queue.put((image.priority, image)) + def process_updates(self): """ Flush the queue to updated any data to update diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index 40b39b7fd..fdd0d74f3 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -612,8 +612,8 @@ class ThemeManager(QtGui.QWidget): self._writeTheme(theme, imageFrom, imageTo) if theme.background_type == \ BackgroundType.to_string(BackgroundType.Image): - self.mainwindow.imageManager.update_images(u'theme', - QtGui.QColor(theme.background_border_color)) + self.mainwindow.imageManager.update_image(theme.theme_name, + u'theme', QtGui.QColor(theme.background_border_color)) self.mainwindow.imageManager.process_updates() self.loadThemes() From 79ab8cc1c0db012396da7053a513de5d22948906 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Sun, 21 Aug 2011 10:05:24 -0400 Subject: [PATCH 08/53] Added code to always create a filename.INI file. --- openlp/core/ui/mainwindow.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 0a51c2bf3..0811c34bd 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -977,7 +977,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtGui.QMessageBox.Ok)) self.settingsImported = True self.cleanUp() - sys.exit() + sys.exit(0) def onSettingsExportItemClicked(self, exportFileName=None): """ @@ -990,6 +990,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): 'OpenLP Export Settings File (*.ini)'))) if not exportFileName: return + # Make sure it's an .ini file. + if not exportFileName.endswith(u'ini'): + exportFileName =+ u'.ini' self.saveSettings() headerSection = u'SettingsExport' settingSections = [] From 62cffbb3b6e1bcf98cb5b4f5ac287670814f2bd5 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 21 Aug 2011 17:13:45 +0100 Subject: [PATCH 09/53] Review fixes and improvements --- openlp/core/lib/imagemanager.py | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index 70d4b46ec..1201d9431 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -166,12 +166,8 @@ class ImageManager(QtCore.QObject): self.height = current_screen[u'size'].height() # Mark the images as dirty for a rebuild by setting the image and byte # stream to None. - self._conversion_queue = PriorityQueue() for key, image in self._cache.iteritems(): - image.priority = Priority.Normal - image.image = None - image.image_bytes = None - self._conversion_queue.put((image.priority, image)) + self.add_to_queue(image) def update_images(self, image_type, background): """ @@ -180,14 +176,10 @@ class ImageManager(QtCore.QObject): log.debug(u'update_images') # Mark the images as dirty for a rebuild by setting the image and byte # stream to None. - self._conversion_queue = PriorityQueue() for key, image in self._cache.iteritems(): if image.source == image_type: image.background = background - image.priority = Priority.Normal - image.image = None - image.image_bytes = None - self._conversion_queue.put((image.priority, image)) + self.add_to_queue(image) def update_image(self, name, image_type, background): """ @@ -196,14 +188,16 @@ class ImageManager(QtCore.QObject): log.debug(u'update_images') # Mark the images as dirty for a rebuild by setting the image and byte # stream to None. - self._conversion_queue = PriorityQueue() for key, image in self._cache.iteritems(): if image.source == image_type and image.name == name: image.background = background - image.priority = Priority.Normal - image.image = None - image.image_bytes = None - self._conversion_queue.put((image.priority, image)) + self.add_to_queue(image) + + def add_to_queue(self, image): + image.priority = Priority.Normal + image.image = None + image.image_bytes = None + self._conversion_queue.put((image.priority, image)) def process_updates(self): """ From 6c55362eee1f5d0455343c6bbb0663068c559878 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 21 Aug 2011 17:59:03 +0100 Subject: [PATCH 10/53] More fixes --- openlp/core/lib/imagemanager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index 1201d9431..2280cc2a6 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -197,7 +197,7 @@ class ImageManager(QtCore.QObject): image.priority = Priority.Normal image.image = None image.image_bytes = None - self._conversion_queue.put((image.priority, image)) + self._conversion_queue.modify_priority(image, image.priority) def process_updates(self): """ From d1f823d86435a842d8e574cbdab7e41f69647d78 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 21 Aug 2011 19:02:58 +0100 Subject: [PATCH 11/53] More fixes 2 --- openlp/core/lib/imagemanager.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index 2280cc2a6..4d6c90078 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -167,7 +167,7 @@ class ImageManager(QtCore.QObject): # Mark the images as dirty for a rebuild by setting the image and byte # stream to None. for key, image in self._cache.iteritems(): - self.add_to_queue(image) + self._reset_image(image) def update_images(self, image_type, background): """ @@ -179,7 +179,7 @@ class ImageManager(QtCore.QObject): for key, image in self._cache.iteritems(): if image.source == image_type: image.background = background - self.add_to_queue(image) + self._reset_image(image) def update_image(self, name, image_type, background): """ @@ -191,13 +191,12 @@ class ImageManager(QtCore.QObject): for key, image in self._cache.iteritems(): if image.source == image_type and image.name == name: image.background = background - self.add_to_queue(image) + self._reset_image(image) - def add_to_queue(self, image): - image.priority = Priority.Normal + def _reset_image(self, image): image.image = None image.image_bytes = None - self._conversion_queue.modify_priority(image, image.priority) + self._conversion_queue.modify_priority(image, Priority.Normal) def process_updates(self): """ From b36a4f74d35b9804b39b6e77db43f3c87a8d142f Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Sun, 21 Aug 2011 19:15:16 -0400 Subject: [PATCH 12/53] Fixed traceback error when adding ini to filename --- openlp/core/ui/mainwindow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 0811c34bd..ab7fe2fe4 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -992,7 +992,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): return # Make sure it's an .ini file. if not exportFileName.endswith(u'ini'): - exportFileName =+ u'.ini' + exportFileName = exportFileName + u'.ini' self.saveSettings() headerSection = u'SettingsExport' settingSections = [] From 652b1b86ea6b4e45356755479b3124fa161d4acf Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Mon, 22 Aug 2011 10:45:03 +0200 Subject: [PATCH 13/53] use urllib to download file --- scripts/translation_utils.py | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/scripts/translation_utils.py b/scripts/translation_utils.py index db1788aba..935ef97e8 100755 --- a/scripts/translation_utils.py +++ b/scripts/translation_utils.py @@ -186,25 +186,6 @@ def update_export_at_pootle(source_filename): page = urllib.urlopen(REVIEW_URL) page.close() - -def download_file(source_filename, dest_filename): - """ - Download a file and save it to disk. - - ``source_filename`` - The file to download. - - ``dest_filename`` - The new local file name. - """ - print_verbose(u'Downloading from: %s' % (SERVER_URL + source_filename)) - page = urllib.urlopen(SERVER_URL + source_filename) - content = page.read().decode('utf8') - page.close() - file = open(dest_filename, u'w') - file.write(content.encode('utf8')) - file.close() - def download_translations(): """ This method downloads the translation files from the Pootle server. @@ -219,7 +200,7 @@ def download_translations(): filename = os.path.join(os.path.abspath(u'..'), u'resources', u'i18n', language_file) print_verbose(u'Get Translation File: %s' % filename) - download_file(language_file, filename) + urllib.urlretrieve(SERVER_URL + language_file, filename) print_quiet(u' Done.') def prepare_project(): @@ -304,7 +285,7 @@ def create_translation(language): if not language.endswith(u'.ts'): language += u'.ts' filename = os.path.join(os.path.abspath(u'..'), u'resources', u'i18n', language) - download_file(u'en.ts', filename) + urllib.urlretrieve(SERVER_URL + u'en.ts', filename) print_quiet(u' ** Please Note **') print_quiet(u' In order to get this file into OpenLP and onto the ' u'Pootle translation server you will need to subscribe to the ' From 957a86b11e76a3532921d1d288dc6e9f7dadf9b9 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Mon, 22 Aug 2011 18:32:18 +0100 Subject: [PATCH 14/53] fexes --- openlp/core/ui/maindisplay.py | 4 ++-- openlp/core/ui/printserviceform.py | 12 +++++++++--- openlp/plugins/images/lib/mediaitem.py | 5 ++++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index 9904868ce..77f2e2f7c 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -228,11 +228,11 @@ class MainDisplay(QtGui.QGraphicsView): shrinkItem.setVisible(False) self.setGeometry(self.screen[u'size']) - def directImage(self, name, path): + def directImage(self, name, path, background): """ API for replacement backgrounds so Images are added directly to cache """ - self.imageManager.add_image(name, path) + self.imageManager.add_image(name, path, u'image', background) if hasattr(self, u'serviceItem'): self.override[u'image'] = name self.override[u'theme'] = self.serviceItem.themedata.theme_name diff --git a/openlp/core/ui/printserviceform.py b/openlp/core/ui/printserviceform.py index f33092061..b9c1cc4a0 100644 --- a/openlp/core/ui/printserviceform.py +++ b/openlp/core/ui/printserviceform.py @@ -188,9 +188,6 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): html_data.body, classId=u'serviceTitle') for index, item in enumerate(self.serviceManager.serviceItems): self._addPreviewItem(html_data.body, item[u'service_item'], index) - # Trigger Audit requests - Receiver.send_message(u'print_service_started', - [item[u'service_item']]) # Add the custom service notes: if self.footerTextEdit.toPlainText(): div = self._addElement(u'div', parent=html_data.body, @@ -299,6 +296,7 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): ``printer`` A *QPrinter* object. """ + self.update_song_usage() self.document.print_(printer) def displaySizeChanged(self, display): @@ -330,12 +328,14 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): """ Copies the display text to the clipboard as plain text """ + self.update_song_usage() self.mainWindow.clipboard.setText(self.document.toPlainText()) def copyHtmlText(self): """ Copies the display text to the clipboard as Html """ + self.update_song_usage() self.mainWindow.clipboard.setText(self.document.toHtml()) def printServiceOrder(self): @@ -400,3 +400,9 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): settings.setValue(u'print notes', QtCore.QVariant(self.notesCheckBox.isChecked())) settings.endGroup() + + def update_song_usage(self): + for index, item in enumerate(self.serviceManager.serviceItems): + # Trigger Audit requests + Receiver.send_message(u'print_service_started', + [item[u'service_item']]) diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index d00b8c9f0..18d5d2a1c 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -208,13 +208,16 @@ class ImageMediaItem(MediaManagerItem): if check_item_selected(self.listView, translate('ImagePlugin.MediaItem', 'You must select an image to replace the background with.')): + background = QtGui.QColor(QtCore.QSettings().value( + self.settingsSection + u'/background color', + QtCore.QVariant(u'#000000'))) item = self.listView.selectedIndexes()[0] bitem = self.listView.item(item.row()) filename = unicode(bitem.data(QtCore.Qt.UserRole).toString()) if os.path.exists(filename): (path, name) = os.path.split(filename) if self.plugin.liveController.display.directImage(name, - filename): + filename, background): self.resetAction.setVisible(True) else: critical_error_message_box(UiStrings().LiveBGError, From 131c9f90b56f0d393f95ed24d3eb31ecba117fc1 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Tue, 23 Aug 2011 08:11:41 -0400 Subject: [PATCH 15/53] Modified shutdown from sys.exit to os._exit --- openlp/core/ui/mainwindow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index ab7fe2fe4..b11769bd9 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -977,7 +977,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtGui.QMessageBox.Ok)) self.settingsImported = True self.cleanUp() - sys.exit(0) + os._exit(0) def onSettingsExportItemClicked(self, exportFileName=None): """ From 0d99f5be96048c5a40862c39970392234593b692 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Tue, 23 Aug 2011 21:57:29 +0200 Subject: [PATCH 16/53] hopefully fixed bug #796528 (to be cleaned up Fixes: https://launchpad.net/bugs/796528 --- openlp/core/lib/renderer.py | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index ac7e95c4c..711be4227 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -229,13 +229,33 @@ class Renderer(object): pages = self._paginate_slide(lines, line_end) if len(pages) > 1: # Songs and Custom - if item.is_capable(ItemCapabilities.AllowsVirtualSplit): - # Do not forget the line breaks! - slides = text.split(u'[---]') + if item.is_capable(ItemCapabilities.AllowsVirtualSplit) and \ + u'[---]' in text: pages = [] - for slide in slides: - lines = slide.strip(u'\n').split(u'\n') - pages.extend(self._paginate_slide(lines, line_end)) + while True: + html_text = expand_tags(text.split(u'[---]', 1)[0]) + html_text = html_text.strip() + html_text = html_text.replace(u'\n', u'
') + if not self._text_fits_on_slide(html_text): + text = text.replace(u'\n[---]', u'', 1) + else: + if u'[---]' in text: + slides = text.split(u'[---]', 1) + text_to_render = slides[0] + text_to_render = text_to_render.strip() + text_to_render = text_to_render.replace(u'\n', u'
') + text = slides[1] + else: + text_to_render = text + text = u'' + lines = text_to_render.strip(u'\n').split(u'\n') + lines = map(expand_tags, lines) + pages.extend(self._paginate_slide(lines, line_end)) + if not text or u'[---]' not in text: + lines = text.strip(u'\n').split(u'\n') + lines = map(expand_tags, lines) + pages.extend(self._paginate_slide(lines, line_end)) + break new_pages = [] for page in pages: while page.endswith(u'
'): @@ -488,7 +508,7 @@ class Renderer(object): returned, otherwise ``False``. ``text`` - The text to check. It can contain HTML tags. + The text to check. It may contain HTML tags. """ self.web_frame.evaluateJavaScript(u'show_text("%s")' % text.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"')) From 9b4df37a779f4221815966d0580bea935ceb1ee8 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Wed, 24 Aug 2011 12:17:24 -0400 Subject: [PATCH 17/53] Modified code to handle keys with _ --- openlp/core/ui/mainwindow.py | 47 ++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index b11769bd9..b9bf7ae34 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -542,6 +542,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): self.servicemanagerSettingsSection = u'servicemanager' self.songsSettingsSection = u'songs' self.themesSettingsSection = u'themes' + self.displayTagsSection = u'displayTags' + self.headerSection = u'SettingsImport' self.serviceNotSaved = False self.aboutForm = AboutForm(self) self.settingsForm = SettingsForm(self, self) @@ -925,7 +927,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): settingSections.extend([self.uiSettingsSection]) settingSections.extend([self.servicemanagerSettingsSection]) settingSections.extend([self.themesSettingsSection]) - settingSections.extend([u'SettingsExport']) + settingSections.extend([self.displayTagsSection]) + settingSections.extend([self.headerSection]) # Add plugin sections. for plugin in self.pluginManager.plugins: settingSections.extend([plugin.name]) @@ -944,7 +947,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): if section == u'General': section = u'general' sectionKey = section + "/" + key - section = section.replace(u'_', u' ') # Make sure it's a valid section for us. if not section in settingSections: QtGui.QMessageBox.critical(self, @@ -961,10 +963,15 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): # We have a good file, import it. for sectionKey in importKeys: value = importSettings.value(sectionKey) - # Get rid of the "_" we replaced the " " with. - sectionKey = sectionKey.replace(u'_', u' ') settings.setValue(u'%s' % (sectionKey) , QtCore.QVariant(value)) + now = datetime.now() + settings.beginGroup(self.headerSection) + settings.setValue( u'file_imported' , QtCore.QVariant(importFileName)) + settings.setValue(u'file_date_imported', + now.strftime("%Y-%m-%d %H:%M")) + settings.endGroup() + settings.sync() # We must do an immediate restart or current configuration will # overwrite what was just imported when application terminates # normally. We need to exit without saving configuration. @@ -993,8 +1000,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): # Make sure it's an .ini file. if not exportFileName.endswith(u'ini'): exportFileName = exportFileName + u'.ini' + temp_file = os.path.join(unicode(gettempdir()), + u'openlp', u'exportIni.tmp') self.saveSettings() - headerSection = u'SettingsExport' settingSections = [] # Add main sections. settingSections.extend([self.generalSettingsSection]) @@ -1002,17 +1010,20 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): settingSections.extend([self.uiSettingsSection]) settingSections.extend([self.servicemanagerSettingsSection]) settingSections.extend([self.themesSettingsSection]) + settingSections.extend([self.displayTagsSection]) # Add plugin sections. for plugin in self.pluginManager.plugins: settingSections.extend([plugin.name]) - # Delete old file if found. + # Delete old files if found. + if os.path.exists(temp_file): + os.remove(temp_file) if os.path.exists(exportFileName): os.remove(exportFileName) settings = QtCore.QSettings() - settings.remove(headerSection) + settings.remove(self.headerSection) # Get the settings. keys = settings.allKeys() - exportSettings = QtCore.QSettings(exportFileName, + exportSettings = QtCore.QSettings(temp_file, QtCore.QSettings.IniFormat) # Add a header section. # This is to insure it's our ini file for import. @@ -1020,10 +1031,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): applicationVersion = get_application_version() # Write INI format using Qsettings. # Write our header. - exportSettings.beginGroup(headerSection) - exportSettings.setValue(u'Make_Changes', u'At Own RISK') + exportSettings.beginGroup(self.headerSection) + exportSettings.setValue(u'Make_Changes', u'At_Own_RISK') exportSettings.setValue(u'type', u'OpenLP_settings_export') - exportSettings.setValue(u'date_created', + exportSettings.setValue(u'file_date_created', now.strftime("%Y-%m-%d %H:%M")) exportSettings.setValue(u'version', applicationVersion[u'full']) exportSettings.endGroup() @@ -1031,13 +1042,23 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): for sectionKey in keys: section, key = string.split(sectionKey, u'/') keyValue = settings.value(sectionKey) - section = section.replace(u' ', u'_') - key = key.replace(u' ', u'_') sectionKey = section + u"/" + key # Change the service section to servicemanager. if section == u'service': sectionKey = u'servicemanager/' + key exportSettings.setValue(sectionKey, keyValue) + exportSettings.sync() + # Temp INI file has been written. Blanks in keys are now '%20'. + # Read the temp file and output the user's INI file with blanks to + # make it more readable. + tempIni = open(temp_file, u'r') + exportIni = open(exportFileName, u'w') + for fileRecord in tempIni: + fileRecord = fileRecord.replace(u'%20', u' ') + exportIni.write(fileRecord) + tempIni.close() + exportIni.close() + os.remove(temp_file) return def onModeDefaultItemClicked(self): From 7e572cd0c2dc8fee5b9c457e799ee22c777284cb Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 25 Aug 2011 11:02:59 +0200 Subject: [PATCH 18/53] Database upgrading, revision 1. --- openlp/core/lib/db.py | 55 +++++++++++++++++++++++-- openlp/plugins/songs/lib/db.py | 51 ++++++++++++----------- openlp/plugins/songs/lib/upgrade.py | 63 +++++++++++++++++++++++++++++ openlp/plugins/songs/songsplugin.py | 4 +- 4 files changed, 142 insertions(+), 31 deletions(-) create mode 100644 openlp/plugins/songs/lib/upgrade.py diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index 41b445cd5..93cd293a5 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -31,9 +31,9 @@ import logging import os from PyQt4 import QtCore -from sqlalchemy import create_engine, MetaData +from sqlalchemy import Table, MetaData, Column, types, create_engine from sqlalchemy.exc import InvalidRequestError -from sqlalchemy.orm import scoped_session, sessionmaker +from sqlalchemy.orm import scoped_session, sessionmaker, mapper from sqlalchemy.pool import NullPool from openlp.core.utils import AppLocation, delete_file @@ -59,6 +59,42 @@ def init_db(url, auto_flush=True, auto_commit=False): autocommit=auto_commit, bind=engine)) return session, metadata + +def upgrade_db(url, upgrade): + """ + Upgrade a database. + + ``url`` + The url of the database to upgrade. + + ``upgrade`` + The python module that contains the upgrade instructions. + """ + session, metadata = init_db(url) + tables = upgrade.upgrade_setup(metadata) + metadata_table = Table(u'metadata', metadata, + Column(u'key', types.Unicode(64), primary_key=True), + Column(u'value', types.UnicodeText(), default=None) + ) + metadata_table.create(checkfirst=True) + mapper(Metadata, metadata_table) + version_meta = session.query(Metadata).get(u'version') + if version_meta is None: + version_meta = Metadata.populate(key=u'version', value=u'0') + version = 0 + else: + version = int(version_meta.value) + version += 1 + while hasattr(upgrade, u'upgrade_%d' % version): + log.debug(u'Running upgrade_%d', version) + do_upgrade = getattr(upgrade, u'upgrade_%d' % version) + if not do_upgrade(session, metadata, tables): + break + version += 1 + version_meta.value = unicode(version) + session.add(version_meta) + session.commit() + def delete_database(plugin_name, db_file_name=None): """ Remove a database file from the system. @@ -79,6 +115,7 @@ def delete_database(plugin_name, db_file_name=None): AppLocation.get_section_data_path(plugin_name), plugin_name) return delete_file(db_file_path) + class BaseModel(object): """ BaseModel provides a base object with a set of generic functions @@ -94,11 +131,18 @@ class BaseModel(object): return instance +class Metadata(BaseModel): + """ + Provides a class for the metadata table. + """ + pass + + class Manager(object): """ Provide generic object persistence management """ - def __init__(self, plugin_name, init_schema, db_file_name=None): + def __init__(self, plugin_name, init_schema, db_file_name=None, upgrade_schema=None): """ Runs the initialisation process that includes creating the connection to the database and the tables if they don't exist. @@ -109,6 +153,9 @@ class Manager(object): ``init_schema`` The init_schema function for this database + ``upgrade_schema`` + The upgrade_schema function for this database + ``db_file_name`` The file name to use for this database. Defaults to None resulting in the plugin_name being used. @@ -134,6 +181,8 @@ class Manager(object): unicode(settings.value(u'db hostname').toString()), unicode(settings.value(u'db database').toString())) settings.endGroup() + if upgrade_schema: + upgrade_schema(self.db_url) self.session = init_schema(self.db_url) def save_object(self, object_instance, commit=True): diff --git a/openlp/plugins/songs/lib/db.py b/openlp/plugins/songs/lib/db.py index c5c019c3c..f37aed29f 100644 --- a/openlp/plugins/songs/lib/db.py +++ b/openlp/plugins/songs/lib/db.py @@ -32,7 +32,8 @@ the Songs plugin from sqlalchemy import Column, ForeignKey, Table, types from sqlalchemy.orm import mapper, relation -from openlp.core.lib.db import BaseModel, init_db +from openlp.core.lib.db import BaseModel, init_db, upgrade_db +from openlp.plugins.songs.lib import upgrade class Author(BaseModel): """ @@ -70,6 +71,14 @@ class Topic(BaseModel): """ pass +def upgrade_schema(url): + """ + Upgrades the songs database. + + ``url`` + The database to upgrade + """ + upgrade_db(url, upgrade) def init_schema(url): """ @@ -111,10 +120,6 @@ def init_schema(url): * file_name * type - **media_files_songs Table** - * media_file_id - * song_id - **song_books Table** The *song_books* table holds a list of books that a congregation gets their songs from, or old hymnals now no longer used. This table has the @@ -162,7 +167,7 @@ def init_schema(url): # Definition of the "authors" table authors_table = Table(u'authors', metadata, - Column(u'id', types.Integer, primary_key=True), + Column(u'id', types.Integer(), primary_key=True), Column(u'first_name', types.Unicode(128)), Column(u'last_name', types.Unicode(128)), Column(u'display_name', types.Unicode(255), index=True, nullable=False) @@ -170,22 +175,25 @@ def init_schema(url): # Definition of the "media_files" table media_files_table = Table(u'media_files', metadata, - Column(u'id', types.Integer, primary_key=True), + Column(u'id', types.Integer(), primary_key=True), + Column(u'song_id', types.Integer(), ForeignKey(u'songs.id'), + default=None), Column(u'file_name', types.Unicode(255), nullable=False), - Column(u'type', types.Unicode(64), nullable=False, default=u'audio') + Column(u'type', types.Unicode(64), nullable=False, default=u'audio'), + Column(u'weight', types.Integer(), default=0) ) # Definition of the "song_books" table song_books_table = Table(u'song_books', metadata, - Column(u'id', types.Integer, primary_key=True), + Column(u'id', types.Integer(), primary_key=True), Column(u'name', types.Unicode(128), nullable=False), Column(u'publisher', types.Unicode(128)) ) # Definition of the "songs" table songs_table = Table(u'songs', metadata, - Column(u'id', types.Integer, primary_key=True), - Column(u'song_book_id', types.Integer, + Column(u'id', types.Integer(), primary_key=True), + Column(u'song_book_id', types.Integer(), ForeignKey(u'song_books.id'), default=None), Column(u'title', types.Unicode(255), nullable=False), Column(u'alternate_title', types.Unicode(255)), @@ -202,31 +210,23 @@ def init_schema(url): # Definition of the "topics" table topics_table = Table(u'topics', metadata, - Column(u'id', types.Integer, primary_key=True), + Column(u'id', types.Integer(), primary_key=True), Column(u'name', types.Unicode(128), index=True, nullable=False) ) # Definition of the "authors_songs" table authors_songs_table = Table(u'authors_songs', metadata, - Column(u'author_id', types.Integer, + Column(u'author_id', types.Integer(), ForeignKey(u'authors.id'), primary_key=True), - Column(u'song_id', types.Integer, - ForeignKey(u'songs.id'), primary_key=True) - ) - - # Definition of the "media_files_songs" table - media_files_songs_table = Table(u'media_files_songs', metadata, - Column(u'media_file_id', types.Integer, - ForeignKey(u'media_files.id'), primary_key=True), - Column(u'song_id', types.Integer, + Column(u'song_id', types.Integer(), ForeignKey(u'songs.id'), primary_key=True) ) # Definition of the "songs_topics" table songs_topics_table = Table(u'songs_topics', metadata, - Column(u'song_id', types.Integer, + Column(u'song_id', types.Integer(), ForeignKey(u'songs.id'), primary_key=True), - Column(u'topic_id', types.Integer, + Column(u'topic_id', types.Integer(), ForeignKey(u'topics.id'), primary_key=True) ) @@ -238,8 +238,7 @@ def init_schema(url): 'authors': relation(Author, backref='songs', secondary=authors_songs_table, lazy=False), 'book': relation(Book, backref='songs'), - 'media_files': relation(MediaFile, backref='songs', - secondary=media_files_songs_table), + 'media_files': relation(MediaFile, backref='songs'), 'topics': relation(Topic, backref='songs', secondary=songs_topics_table) }) diff --git a/openlp/plugins/songs/lib/upgrade.py b/openlp/plugins/songs/lib/upgrade.py new file mode 100644 index 000000000..09b7cc2e0 --- /dev/null +++ b/openlp/plugins/songs/lib/upgrade.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2011 Raoul Snyman # +# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, # +# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias # +# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### +""" +The :mod:`upgrade` module provides a way for the database and schema that is the backend for +the Songs plugin +""" + +from sqlalchemy import Column, ForeignKey, Table, types +from migrate import changeset +from migrate.changeset.constraint import ForeignKeyConstraint + +def upgrade_setup(metadata): + """ + Set up the latest revision all tables, with reflection, needed for the + upgrade process. If you want to drop a table, you need to remove it from + here, and add it to your upgrade function. + """ + tables = { + u'authors': Table(u'authors', metadata, autoload=True), + u'media_files': Table(u'media_files', metadata, autoload=True), + u'song_books': Table(u'song_books', metadata, autoload=True), + u'songs': Table(u'songs', metadata, autoload=True), + u'topics': Table(u'topics', metadata, autoload=True), + u'authors_songs': Table(u'authors_songs', metadata, autoload=True), + u'songs_topics': Table(u'songs_topics', metadata, autoload=True) + } + return tables + + +def upgrade_1(session, metadata, tables): + Table(u'media_files_songs', metadata, autoload=True).drop(checkfirst=True) + Column(u'song_id', types.Integer(), default=None)\ + .create(table=tables[u'media_files'], populate_default=True) + Column(u'weight', types.Integer(), default=0)\ + .create(table=tables[u'media_files'], populate_default=True) + if metadata.bind.url.get_dialect().name != 'sqlite': + ForeignKeyConstraint([u'song_id'], [u'songs.id'], + table=tables[u'media_files']).create() + return True \ No newline at end of file diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index 8a773be90..9fd113186 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -37,7 +37,7 @@ from openlp.core.lib.db import Manager from openlp.core.lib.ui import UiStrings, base_action, icon_action from openlp.core.utils.actions import ActionList from openlp.plugins.songs.lib import clean_song, SongMediaItem, SongsTab -from openlp.plugins.songs.lib.db import init_schema, Song +from openlp.plugins.songs.lib.db import init_schema, upgrade_schema, Song from openlp.plugins.songs.lib.importer import SongFormat from openlp.plugins.songs.lib.olpimport import OpenLPSongImport @@ -58,8 +58,8 @@ class SongsPlugin(Plugin): Create and set up the Songs plugin. """ Plugin.__init__(self, u'songs', plugin_helpers, SongMediaItem, SongsTab) + self.manager = Manager(u'songs', init_schema, upgrade_schema=upgrade_schema) self.weight = -10 - self.manager = Manager(u'songs', init_schema) self.icon_path = u':/plugins/plugin_songs.png' self.icon = build_icon(self.icon_path) From 923261c59c90bd54d1da72f6656612a31147ae87 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 25 Aug 2011 11:22:48 +0200 Subject: [PATCH 19/53] Even better, got rid of 'upgrade_schema' function which is not really needed. --- openlp/core/lib/db.py | 7 ++++--- openlp/plugins/songs/lib/db.py | 12 +----------- openlp/plugins/songs/songsplugin.py | 7 ++++--- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index 93cd293a5..fab20d36f 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -142,7 +142,8 @@ class Manager(object): """ Provide generic object persistence management """ - def __init__(self, plugin_name, init_schema, db_file_name=None, upgrade_schema=None): + def __init__(self, plugin_name, init_schema, db_file_name=None, + upgrade_mod=None): """ Runs the initialisation process that includes creating the connection to the database and the tables if they don't exist. @@ -181,8 +182,8 @@ class Manager(object): unicode(settings.value(u'db hostname').toString()), unicode(settings.value(u'db database').toString())) settings.endGroup() - if upgrade_schema: - upgrade_schema(self.db_url) + if upgrade_mod: + upgrade_db(self.db_url, upgrade_mod) self.session = init_schema(self.db_url) def save_object(self, object_instance, commit=True): diff --git a/openlp/plugins/songs/lib/db.py b/openlp/plugins/songs/lib/db.py index f37aed29f..bee64b3ba 100644 --- a/openlp/plugins/songs/lib/db.py +++ b/openlp/plugins/songs/lib/db.py @@ -32,8 +32,7 @@ the Songs plugin from sqlalchemy import Column, ForeignKey, Table, types from sqlalchemy.orm import mapper, relation -from openlp.core.lib.db import BaseModel, init_db, upgrade_db -from openlp.plugins.songs.lib import upgrade +from openlp.core.lib.db import BaseModel, init_db class Author(BaseModel): """ @@ -71,15 +70,6 @@ class Topic(BaseModel): """ pass -def upgrade_schema(url): - """ - Upgrades the songs database. - - ``url`` - The database to upgrade - """ - upgrade_db(url, upgrade) - def init_schema(url): """ Setup the songs database connection and initialise the database schema. diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index 9fd113186..f2bf36790 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -36,8 +36,9 @@ from openlp.core.lib import Plugin, StringContent, build_icon, translate, \ from openlp.core.lib.db import Manager from openlp.core.lib.ui import UiStrings, base_action, icon_action from openlp.core.utils.actions import ActionList -from openlp.plugins.songs.lib import clean_song, SongMediaItem, SongsTab -from openlp.plugins.songs.lib.db import init_schema, upgrade_schema, Song +from openlp.plugins.songs.lib import clean_song, upgrade, SongMediaItem, \ + SongsTab +from openlp.plugins.songs.lib.db import init_schema, Song from openlp.plugins.songs.lib.importer import SongFormat from openlp.plugins.songs.lib.olpimport import OpenLPSongImport @@ -58,7 +59,7 @@ class SongsPlugin(Plugin): Create and set up the Songs plugin. """ Plugin.__init__(self, u'songs', plugin_helpers, SongMediaItem, SongsTab) - self.manager = Manager(u'songs', init_schema, upgrade_schema=upgrade_schema) + self.manager = Manager(u'songs', init_schema, upgrade_mod=upgrade) self.weight = -10 self.icon_path = u':/plugins/plugin_songs.png' self.icon = build_icon(self.icon_path) From ddf148449d253e7fdf541e7fedb69b657d793349 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 25 Aug 2011 13:47:07 +0200 Subject: [PATCH 20/53] Now with exception handling. --- openlp/core/lib/db.py | 13 ++++++++----- openlp/plugins/songs/lib/upgrade.py | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index fab20d36f..12f35ad1f 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -32,7 +32,7 @@ import os from PyQt4 import QtCore from sqlalchemy import Table, MetaData, Column, types, create_engine -from sqlalchemy.exc import InvalidRequestError +from sqlalchemy.exc import SQLAlchemyError, InvalidRequestError, DBAPIError from sqlalchemy.orm import scoped_session, sessionmaker, mapper from sqlalchemy.pool import NullPool @@ -87,11 +87,14 @@ def upgrade_db(url, upgrade): version += 1 while hasattr(upgrade, u'upgrade_%d' % version): log.debug(u'Running upgrade_%d', version) - do_upgrade = getattr(upgrade, u'upgrade_%d' % version) - if not do_upgrade(session, metadata, tables): + try: + getattr(upgrade, u'upgrade_%d' % version)(session, metadata, tables) + version += 1 + version_meta.value = unicode(version) + except SQLAlchemyError, DBAPIError: + log.exception(u'Could not run database upgrade script "upgrade_%s"'\ + ', upgrade process has been halted.', version) break - version += 1 - version_meta.value = unicode(version) session.add(version_meta) session.commit() diff --git a/openlp/plugins/songs/lib/upgrade.py b/openlp/plugins/songs/lib/upgrade.py index 09b7cc2e0..278b6fe86 100644 --- a/openlp/plugins/songs/lib/upgrade.py +++ b/openlp/plugins/songs/lib/upgrade.py @@ -60,4 +60,4 @@ def upgrade_1(session, metadata, tables): if metadata.bind.url.get_dialect().name != 'sqlite': ForeignKeyConstraint([u'song_id'], [u'songs.id'], table=tables[u'media_files']).create() - return True \ No newline at end of file + From ff7a7d734a76152ca6751ce7979e17254762cd32 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 25 Aug 2011 17:24:47 +0200 Subject: [PATCH 21/53] Added migrate dependency to deb package. --- resources/debian/debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/debian/debian/control b/resources/debian/debian/control index 220b500d2..423d81df0 100644 --- a/resources/debian/debian/control +++ b/resources/debian/debian/control @@ -11,7 +11,7 @@ Package: openlp Architecture: all Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}, python-qt4, python-qt4-phonon, python-sqlalchemy, python-chardet, python-beautifulsoup, - python-lxml, python-sqlite, python-enchant + python-lxml, python-sqlite, python-enchant, python-migrate Conflicts: python-openlp Description: Church lyrics projection application OpenLP is free church presentation software, or lyrics projection software, From 803adc92c0b45d474975a73d5f3f5da26a4ee463 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Thu, 25 Aug 2011 19:33:25 +0100 Subject: [PATCH 22/53] Fixes --- openlp/core/ui/themewizard.py | 2 +- openlp/plugins/images/lib/imagetab.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/openlp/core/ui/themewizard.py b/openlp/core/ui/themewizard.py index 12fc70760..6001c83d6 100644 --- a/openlp/core/ui/themewizard.py +++ b/openlp/core/ui/themewizard.py @@ -449,7 +449,7 @@ class Ui_ThemeWizard(object): self.gradientComboBox.setItemText(BackgroundGradientType.LeftBottom, translate('OpenLP.ThemeWizard', 'Bottom Left - Top Right')) self.imageColorLabel.setText( - translate(u'OpenLP.ThemeWizard', 'Border color:')) + translate(u'OpenLP.ThemeWizard', 'Background color:')) self.imageLabel.setText(u'%s:' % UiStrings().Image) self.mainAreaPage.setTitle( translate('OpenLP.ThemeWizard', 'Main Area Font Details')) diff --git a/openlp/plugins/images/lib/imagetab.py b/openlp/plugins/images/lib/imagetab.py index 640cd4495..05e998d81 100644 --- a/openlp/plugins/images/lib/imagetab.py +++ b/openlp/plugins/images/lib/imagetab.py @@ -57,6 +57,8 @@ class ImageTab(SettingsTab): self.formLayout.addRow(self.informationLabel) self.leftLayout.addWidget(self.fontGroupBox) self.leftLayout.addStretch() + self.rightColumn.setSizePolicy( + QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred) self.rightLayout.addStretch() # Signals and slots QtCore.QObject.connect(self.backgroundColorButton, @@ -64,9 +66,9 @@ class ImageTab(SettingsTab): def retranslateUi(self): self.fontGroupBox.setTitle( - translate('ImagesPlugin.ImageTab', 'Background Font')) + translate('ImagesPlugin.ImageTab', 'Background Color')) self.backgroundColorLabel.setText( - translate('ImagesPlugin.ImageTab', 'Background color:')) + translate('ImagesPlugin.ImageTab', 'Default Color:')) self.informationLabel.setText( translate('ImagesPlugin.ImageTab', 'Provides border where image ' 'is not the correct dimensions for the screen when resized.')) From d927adbe5a7f54a701d84cd15c11f5596af32449 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Thu, 25 Aug 2011 14:40:44 -0400 Subject: [PATCH 23/53] Changed import re-start message. Removed need for "import string" --- openlp/core/ui/mainwindow.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 00b8d6dae..1404e4206 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -27,7 +27,7 @@ import logging import os -import sys, string +import sys import shutil from tempfile import gettempdir from datetime import datetime @@ -936,8 +936,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): for sectionKey in importKeys: # We need to handle the really bad files. try: - section, key = string.split(sectionKey, u'/') - except: + section, key = sectionKey.split(u'/') + except ValueError: section = u'unknown' key = u'' # Switch General back to lowercase. @@ -976,7 +976,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): translate('OpenLP.MainWindow', 'Import settings'), translate('OpenLP.MainWindow', 'OpenLP will now close. Imported settings will ' - 'take place the next time you start OpenLP'), + 'be applied the next time you start OpenLP.'), QtGui.QMessageBox.StandardButtons( QtGui.QMessageBox.Ok)) self.settingsImported = True @@ -1037,7 +1037,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): exportSettings.endGroup() # Write all the sections and keys. for sectionKey in keys: - section, key = string.split(sectionKey, u'/') + section, key = sectionKey.split(u'/') keyValue = settings.value(sectionKey) sectionKey = section + u"/" + key # Change the service section to servicemanager. From 5f6b315c4af9c9d0ceb492b4237d86df8c7654ff Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Thu, 25 Aug 2011 20:52:07 +0100 Subject: [PATCH 24/53] fix trace --- openlp/plugins/custom/lib/mediaitem.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index 667434a8b..693e1ef8d 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -217,8 +217,7 @@ class CustomMediaItem(MediaManagerItem): for item in self.listView.selectedIndexes()] for id in id_list: self.plugin.manager.delete_object(CustomSlide, id) - for row in row_list: - self.listView.takeItem(row) + self.onSearchTextButtonClick() def onFocus(self): self.searchTextEdit.setFocus() From bcf9b174ff12cf9c4223c1964bb19ad7033066ee Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 25 Aug 2011 22:02:55 +0200 Subject: [PATCH 25/53] Fixed a bug where the version number saved to the database was incorrect. Added the ability to throw an error message and not load the database if the db is too new or incorrect. --- openlp/core/lib/db.py | 29 ++++++++++++++++++++++++++--- openlp/plugins/songs/lib/upgrade.py | 2 ++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index 12f35ad1f..fb8a38b1f 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -36,6 +36,8 @@ from sqlalchemy.exc import SQLAlchemyError, InvalidRequestError, DBAPIError from sqlalchemy.orm import scoped_session, sessionmaker, mapper from sqlalchemy.pool import NullPool +from openlp.core.lib import translate +from openlp.core.lib.ui import critical_error_message_box from openlp.core.utils import AppLocation, delete_file log = logging.getLogger(__name__) @@ -84,19 +86,22 @@ def upgrade_db(url, upgrade): version = 0 else: version = int(version_meta.value) + if version > upgrade.__version__: + return version, upgrade.__version__ version += 1 while hasattr(upgrade, u'upgrade_%d' % version): log.debug(u'Running upgrade_%d', version) try: getattr(upgrade, u'upgrade_%d' % version)(session, metadata, tables) - version += 1 version_meta.value = unicode(version) except SQLAlchemyError, DBAPIError: log.exception(u'Could not run database upgrade script "upgrade_%s"'\ ', upgrade process has been halted.', version) break + version += 1 session.add(version_meta) session.commit() + return int(version_meta.value), upgrade.__version__ def delete_database(plugin_name, db_file_name=None): """ @@ -186,8 +191,26 @@ class Manager(object): unicode(settings.value(u'db database').toString())) settings.endGroup() if upgrade_mod: - upgrade_db(self.db_url, upgrade_mod) - self.session = init_schema(self.db_url) + db_ver, up_ver = upgrade_db(self.db_url, upgrade_mod) + if db_ver > up_ver: + critical_error_message_box( + translate('OpenLP.Manager', 'Database Error'), + unicode(translate('OpenLP.Manager', 'The database being ' + 'loaded was created in a more recent version of ' + 'OpenLP. The database is version %d, while OpenLP ' + 'expects version %d. The database will not be loaded.' + '\n\nDatabase: %s')) % \ + (db_ver, up_ver, self.db_url) + ) + return + try: + self.session = init_schema(self.db_url) + except: + critical_error_message_box( + translate('OpenLP.Manager', 'Database Error'), + unicode(translate('OpenLP.Manager', 'OpenLP cannot load your ' + 'database.\n\nDatabase: %s')) % self.db_url + ) def save_object(self, object_instance, commit=True): """ diff --git a/openlp/plugins/songs/lib/upgrade.py b/openlp/plugins/songs/lib/upgrade.py index 278b6fe86..56b04bb01 100644 --- a/openlp/plugins/songs/lib/upgrade.py +++ b/openlp/plugins/songs/lib/upgrade.py @@ -33,6 +33,8 @@ from sqlalchemy import Column, ForeignKey, Table, types from migrate import changeset from migrate.changeset.constraint import ForeignKeyConstraint +__version__ = 1 + def upgrade_setup(metadata): """ Set up the latest revision all tables, with reflection, needed for the From 4b1ce7102e48e2d71bc63a49f7f928903517cbb9 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 25 Aug 2011 22:14:02 +0200 Subject: [PATCH 26/53] A few more tweaks as requested by Andreas. --- openlp/plugins/songs/lib/upgrade.py | 12 ++++++++++++ scripts/check_dependencies.py | 7 ++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/openlp/plugins/songs/lib/upgrade.py b/openlp/plugins/songs/lib/upgrade.py index 56b04bb01..e0f2668d9 100644 --- a/openlp/plugins/songs/lib/upgrade.py +++ b/openlp/plugins/songs/lib/upgrade.py @@ -54,12 +54,24 @@ def upgrade_setup(metadata): def upgrade_1(session, metadata, tables): + """ + Version 1 upgrade. + + This upgrade removes the many-to-many relationship between songs and + media_files and replaces it with a one-to-many, which is far more + representative of the real relationship between the two entities. + + In order to facilitate this one-to-many relationship, a song_id column is + added to the media_files table, and a weight column so that the media + files can be ordered. + """ Table(u'media_files_songs', metadata, autoload=True).drop(checkfirst=True) Column(u'song_id', types.Integer(), default=None)\ .create(table=tables[u'media_files'], populate_default=True) Column(u'weight', types.Integer(), default=0)\ .create(table=tables[u'media_files'], populate_default=True) if metadata.bind.url.get_dialect().name != 'sqlite': + # SQLite doesn't support ALTER TABLE ADD CONSTRAINT ForeignKeyConstraint([u'song_id'], [u'songs.id'], table=tables[u'media_files']).create() diff --git a/scripts/check_dependencies.py b/scripts/check_dependencies.py index 7048ceeab..5f2e4c148 100755 --- a/scripts/check_dependencies.py +++ b/scripts/check_dependencies.py @@ -46,14 +46,14 @@ VERS = { 'sqlalchemy': '0.5', # pyenchant 1.6 required on Windows 'enchant': '1.6' if is_win else '1.3' - } +} # pywin32 WIN32_MODULES = [ 'win32com', 'win32ui', 'pywintypes', - ] +] MODULES = [ 'PyQt4', @@ -72,7 +72,8 @@ MODULES = [ 'enchant', 'BeautifulSoup', 'mako', - ] + 'migrate', +] OPTIONAL_MODULES = [ From 869bc9bb209190d3920e112e89e284c63a93964c Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 26 Aug 2011 09:21:27 +0100 Subject: [PATCH 27/53] Fix field name --- openlp/plugins/images/lib/imagetab.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/openlp/plugins/images/lib/imagetab.py b/openlp/plugins/images/lib/imagetab.py index 05e998d81..98fbd203f 100644 --- a/openlp/plugins/images/lib/imagetab.py +++ b/openlp/plugins/images/lib/imagetab.py @@ -40,22 +40,22 @@ class ImageTab(SettingsTab): def setupUi(self): self.setObjectName(u'ImagesTab') SettingsTab.setupUi(self) - self.fontGroupBox = QtGui.QGroupBox(self.leftColumn) - self.fontGroupBox.setObjectName(u'FontGroupBox') - self.formLayout = QtGui.QFormLayout(self.fontGroupBox) + self.bgColorGroupBox = QtGui.QGroupBox(self.leftColumn) + self.bgColorGroupBox.setObjectName(u'FontGroupBox') + self.formLayout = QtGui.QFormLayout(self.bgColorGroupBox) self.formLayout.setObjectName(u'FormLayout') self.colorLayout = QtGui.QHBoxLayout() - self.backgroundColorLabel = QtGui.QLabel(self.fontGroupBox) + self.backgroundColorLabel = QtGui.QLabel(self.bgColorGroupBox) self.backgroundColorLabel.setObjectName(u'BackgroundColorLabel') self.colorLayout.addWidget(self.backgroundColorLabel) - self.backgroundColorButton = QtGui.QPushButton(self.fontGroupBox) + self.backgroundColorButton = QtGui.QPushButton(self.bgColorGroupBox) self.backgroundColorButton.setObjectName(u'BackgroundColorButton') self.colorLayout.addWidget(self.backgroundColorButton) self.formLayout.addRow(self.colorLayout) - self.informationLabel = QtGui.QLabel(self.fontGroupBox) + self.informationLabel = QtGui.QLabel(self.bgColorGroupBox) self.informationLabel.setObjectName(u'InformationLabel') self.formLayout.addRow(self.informationLabel) - self.leftLayout.addWidget(self.fontGroupBox) + self.leftLayout.addWidget(self.bgColorGroupBox) self.leftLayout.addStretch() self.rightColumn.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred) @@ -65,7 +65,7 @@ class ImageTab(SettingsTab): QtCore.SIGNAL(u'pressed()'), self.onbackgroundColorButtonClicked) def retranslateUi(self): - self.fontGroupBox.setTitle( + self.bgColorGroupBox.setTitle( translate('ImagesPlugin.ImageTab', 'Background Color')) self.backgroundColorLabel.setText( translate('ImagesPlugin.ImageTab', 'Default Color:')) From 61feddd34e81947424a3576dd1cc90351bc2c5cc Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 26 Aug 2011 11:21:47 +0100 Subject: [PATCH 28/53] Fix method call --- openlp/core/ui/printserviceform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/ui/printserviceform.py b/openlp/core/ui/printserviceform.py index b9c1cc4a0..c08b6293e 100644 --- a/openlp/core/ui/printserviceform.py +++ b/openlp/core/ui/printserviceform.py @@ -296,7 +296,6 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): ``printer`` A *QPrinter* object. """ - self.update_song_usage() self.document.print_(printer) def displaySizeChanged(self, display): @@ -344,6 +343,7 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): """ if not self.printDialog.exec_(): return + self.update_song_usage() # Print the document. self.document.print_(self.printer) From 1adac78588f63aea8cf110c54ce6fed8415c92a5 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 26 Aug 2011 13:02:06 +0100 Subject: [PATCH 29/53] Add date fields to songs --- openlp/plugins/songs/lib/db.py | 5 ++++- openlp/plugins/songs/lib/upgrade.py | 19 +++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/openlp/plugins/songs/lib/db.py b/openlp/plugins/songs/lib/db.py index bee64b3ba..13ce24266 100644 --- a/openlp/plugins/songs/lib/db.py +++ b/openlp/plugins/songs/lib/db.py @@ -31,6 +31,7 @@ the Songs plugin from sqlalchemy import Column, ForeignKey, Table, types from sqlalchemy.orm import mapper, relation +from sqlalchemy.sql.expression import func from openlp.core.lib.db import BaseModel, init_db @@ -195,7 +196,9 @@ def init_schema(url): Column(u'song_number', types.Unicode(64)), Column(u'theme_name', types.Unicode(128)), Column(u'search_title', types.Unicode(255), index=True, nullable=False), - Column(u'search_lyrics', types.UnicodeText, nullable=False) + Column(u'search_lyrics', types.UnicodeText, nullable=False), + Column(u'create_date', types.DateTime(), default=func.now()), + Column(u'last_modified', types.DateTime(), onupdate=func.now()) ) # Definition of the "topics" table diff --git a/openlp/plugins/songs/lib/upgrade.py b/openlp/plugins/songs/lib/upgrade.py index e0f2668d9..fae3400c2 100644 --- a/openlp/plugins/songs/lib/upgrade.py +++ b/openlp/plugins/songs/lib/upgrade.py @@ -25,15 +25,16 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`upgrade` module provides a way for the database and schema that is the backend for -the Songs plugin +The :mod:`upgrade` module provides a way for the database and schema that is the +backend for the Songs plugin """ from sqlalchemy import Column, ForeignKey, Table, types +from sqlalchemy.sql.expression import func from migrate import changeset from migrate.changeset.constraint import ForeignKeyConstraint -__version__ = 1 +__version__ = 2 def upgrade_setup(metadata): """ @@ -57,7 +58,7 @@ def upgrade_1(session, metadata, tables): """ Version 1 upgrade. - This upgrade removes the many-to-many relationship between songs and + This upgrade removes the many-to-many relationship between songs and media_files and replaces it with a one-to-many, which is far more representative of the real relationship between the two entities. @@ -75,3 +76,13 @@ def upgrade_1(session, metadata, tables): ForeignKeyConstraint([u'song_id'], [u'songs.id'], table=tables[u'media_files']).create() +def upgrade_2(session, metadata, tables): + """ + Version 2 upgrade. + + This upgrade adds a create_date and last_modified date to the songs table + """ + Column(u'create_date', types.DateTime(), default=func.now())\ + .create(table=tables[u'songs'], populate_default=True) + Column(u'last_modified', types.DateTime(), default=func.now())\ + .create(table=tables[u'songs'], populate_default=True) From 8f2b2381eea910d3c58f0a1ed8aa367e89bd65df Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Fri, 26 Aug 2011 14:14:21 +0200 Subject: [PATCH 30/53] Fixed a missing dependency (which already exists on the build server). --- resources/debian/debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/debian/debian/control b/resources/debian/debian/control index 423d81df0..a1c2298e9 100644 --- a/resources/debian/debian/control +++ b/resources/debian/debian/control @@ -11,7 +11,7 @@ Package: openlp Architecture: all Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}, python-qt4, python-qt4-phonon, python-sqlalchemy, python-chardet, python-beautifulsoup, - python-lxml, python-sqlite, python-enchant, python-migrate + python-lxml, python-sqlite, python-enchant, python-mako, python-migrate Conflicts: python-openlp Description: Church lyrics projection application OpenLP is free church presentation software, or lyrics projection software, From 4f0c7716bc2c53067de6722716a05f17bbc0981d Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 26 Aug 2011 14:13:32 +0100 Subject: [PATCH 31/53] Fix default value --- openlp/plugins/songs/lib/db.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openlp/plugins/songs/lib/db.py b/openlp/plugins/songs/lib/db.py index 13ce24266..5bfa0c830 100644 --- a/openlp/plugins/songs/lib/db.py +++ b/openlp/plugins/songs/lib/db.py @@ -198,7 +198,8 @@ def init_schema(url): Column(u'search_title', types.Unicode(255), index=True, nullable=False), Column(u'search_lyrics', types.UnicodeText, nullable=False), Column(u'create_date', types.DateTime(), default=func.now()), - Column(u'last_modified', types.DateTime(), onupdate=func.now()) + Column(u'last_modified', types.DateTime(), default=func.now(), + onupdate=func.now()) ) # Definition of the "topics" table From 24126e74c881522271234bae7469a1104b55ba3b Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Fri, 26 Aug 2011 09:14:12 -0400 Subject: [PATCH 32/53] Changed filetype of settings file from .ini to .conf --- openlp/core/ui/mainwindow.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 1404e4206..6dbd57511 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -914,7 +914,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): translate('OpenLP.MainWindow', 'Open File'), '', translate('OpenLP.MainWindow', - 'OpenLP Export Settings Files (*.ini)'))) + 'OpenLP Export Settings Files (*.conf)'))) if not importFileName: return settingSections = [] @@ -991,12 +991,12 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): exportFileName = unicode(QtGui.QFileDialog.getSaveFileName(self, translate('OpenLP.MainWindow', 'Export Settings File'), '', translate('OpenLP.MainWindow', - 'OpenLP Export Settings File (*.ini)'))) + 'OpenLP Export Settings File (*.conf)'))) if not exportFileName: return # Make sure it's an .ini file. - if not exportFileName.endswith(u'ini'): - exportFileName = exportFileName + u'.ini' + if not exportFileName.endswith(u'conf'): + exportFileName = exportFileName + u'.conf' temp_file = os.path.join(unicode(gettempdir()), u'openlp', u'exportIni.tmp') self.saveSettings() From 6c3d15636301db0249aafa1eee81b2d152824f4d Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Fri, 26 Aug 2011 17:22:57 +0200 Subject: [PATCH 33/53] fixed inversion :-D --- openlp/core/lib/renderer.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 711be4227..df8235b33 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -236,7 +236,7 @@ class Renderer(object): html_text = expand_tags(text.split(u'[---]', 1)[0]) html_text = html_text.strip() html_text = html_text.replace(u'\n', u'
') - if not self._text_fits_on_slide(html_text): + if self._text_fits_on_slide(html_text): text = text.replace(u'\n[---]', u'', 1) else: if u'[---]' in text: @@ -361,7 +361,7 @@ class Renderer(object): separator = u'
' html_lines = map(expand_tags, lines) # Text too long so go to next page. - if self._text_fits_on_slide(separator.join(html_lines)): + if not self._text_fits_on_slide(separator.join(html_lines)): html_text, previous_raw = self._binary_chop(formatted, previous_html, previous_raw, html_lines, lines, separator, u'') else: @@ -394,18 +394,18 @@ class Renderer(object): line = line.strip() html_line = expand_tags(line) # Text too long so go to next page. - if self._text_fits_on_slide(previous_html + html_line): + if not self._text_fits_on_slide(previous_html + html_line): # Check if there was a verse before the current one and append # it, when it fits on the page. if previous_html: - if not self._text_fits_on_slide(previous_html): + if self._text_fits_on_slide(previous_html): formatted.append(previous_raw) previous_html = u'' previous_raw = u'' # Now check if the current verse will fit, if it does # not we have to start to process the verse word by # word. - if not self._text_fits_on_slide(html_line): + if self._text_fits_on_slide(html_line): previous_html = html_line + line_end previous_raw = line + line_end continue @@ -462,7 +462,7 @@ class Renderer(object): highest_index = len(html_list) - 1 index = int(highest_index / 2) while True: - if self._text_fits_on_slide( + if not self._text_fits_on_slide( previous_html + separator.join(html_list[:index + 1]).strip()): # We know that it does not fit, so change/calculate the # new index and highest_index accordingly. @@ -485,8 +485,8 @@ class Renderer(object): else: continue # Check if the remaining elements fit on the slide. - if not self._text_fits_on_slide( - separator.join(html_list[index + 1:]).strip()): + if self._text_fits_on_slide( + separator.join(html_list[index + 1:]).strip()): previous_html = separator.join( html_list[index + 1:]).strip() + line_end previous_raw = separator.join( @@ -512,7 +512,7 @@ class Renderer(object): """ self.web_frame.evaluateJavaScript(u'show_text("%s")' % text.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"')) - return self.web_frame.contentsSize().height() > self.page_height + return self.web_frame.contentsSize().height() <= self.page_height def _words_split(self, line): """ From fbb32a027880259eec86bf5219bfdd86ef7e3ebd Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Fri, 26 Aug 2011 17:30:51 +0200 Subject: [PATCH 34/53] added hints that exported files are OpenLyrics files --- openlp/plugins/songs/forms/songexportform.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/openlp/plugins/songs/forms/songexportform.py b/openlp/plugins/songs/forms/songexportform.py index 90c3b0275..3d3c4d559 100644 --- a/openlp/plugins/songs/forms/songexportform.py +++ b/openlp/plugins/songs/forms/songexportform.py @@ -170,8 +170,8 @@ class SongExportForm(OpenLPWizard): translate('OpenLP.Ui', 'Welcome to the Song Export Wizard')) self.informationLabel.setText( translate('SongsPlugin.ExportWizardForm', 'This wizard will help to' - ' export your songs to the open and free OpenLyrics worship song ' - 'format.')) + ' export your songs to the open and free OpenLyrics' + ' worship song format.')) self.availableSongsPage.setTitle( translate('SongsPlugin.ExportWizardForm', 'Select Songs')) self.availableSongsPage.setSubTitle( @@ -285,7 +285,9 @@ class SongExportForm(OpenLPWizard): self, songs, unicode(self.directoryLineEdit.text())) if exporter.do_export(): self.progressLabel.setText( - translate('SongsPlugin.SongExportForm', 'Finished export.')) + translate('SongsPlugin.SongExportForm', 'Finished export. To ' + 'import these files again use the OpenLyrics ' + 'importer.')) else: self.progressLabel.setText( translate('SongsPlugin.SongExportForm', From d88a268c5cfcc9b4bc589ed5a21f7ac81e50aa80 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Fri, 26 Aug 2011 17:48:58 +0200 Subject: [PATCH 35/53] removed 'again' --- openlp/plugins/songs/forms/songexportform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/songs/forms/songexportform.py b/openlp/plugins/songs/forms/songexportform.py index 3d3c4d559..22020a401 100644 --- a/openlp/plugins/songs/forms/songexportform.py +++ b/openlp/plugins/songs/forms/songexportform.py @@ -286,7 +286,7 @@ class SongExportForm(OpenLPWizard): if exporter.do_export(): self.progressLabel.setText( translate('SongsPlugin.SongExportForm', 'Finished export. To ' - 'import these files again use the OpenLyrics ' + 'import these files use the OpenLyrics ' 'importer.')) else: self.progressLabel.setText( From f266485001f809f5ee46457dcb90a61f93cce7b8 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 26 Aug 2011 18:56:36 +0100 Subject: [PATCH 36/53] Add fields to database --- openlp/core/lib/db.py | 1 + openlp/plugins/songs/lib/upgrade.py | 6 +- openlp/plugins/songusage/lib/db.py | 4 +- openlp/plugins/songusage/lib/upgrade.py | 61 +++++++++++++++++++++ openlp/plugins/songusage/songusageplugin.py | 5 +- 5 files changed, 70 insertions(+), 7 deletions(-) create mode 100644 openlp/plugins/songusage/lib/upgrade.py diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index fb8a38b1f..2c504c3ae 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -72,6 +72,7 @@ def upgrade_db(url, upgrade): ``upgrade`` The python module that contains the upgrade instructions. """ + print url, upgrade session, metadata = init_db(url) tables = upgrade.upgrade_setup(metadata) metadata_table = Table(u'metadata', metadata, diff --git a/openlp/plugins/songs/lib/upgrade.py b/openlp/plugins/songs/lib/upgrade.py index e0f2668d9..a7aa1bd6c 100644 --- a/openlp/plugins/songs/lib/upgrade.py +++ b/openlp/plugins/songs/lib/upgrade.py @@ -25,8 +25,8 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`upgrade` module provides a way for the database and schema that is the backend for -the Songs plugin +The :mod:`upgrade` module provides a way for the database and schema that is the +backend for the Songs plugin """ from sqlalchemy import Column, ForeignKey, Table, types @@ -57,7 +57,7 @@ def upgrade_1(session, metadata, tables): """ Version 1 upgrade. - This upgrade removes the many-to-many relationship between songs and + This upgrade removes the many-to-many relationship between songs and media_files and replaces it with a one-to-many, which is far more representative of the real relationship between the two entities. diff --git a/openlp/plugins/songusage/lib/db.py b/openlp/plugins/songusage/lib/db.py index 9a11ef16b..bbd645634 100644 --- a/openlp/plugins/songusage/lib/db.py +++ b/openlp/plugins/songusage/lib/db.py @@ -56,7 +56,9 @@ def init_schema(url): Column(u'title', types.Unicode(255), nullable=False), Column(u'authors', types.Unicode(255), nullable=False), Column(u'copyright', types.Unicode(255)), - Column(u'ccl_number', types.Unicode(65)) + Column(u'ccl_number', types.Unicode(65)), + Column(u'plugin_name', types.Unicode(20)), + Column(u'source', types.Unicode(10)) ) mapper(SongUsageItem, songusage_table) diff --git a/openlp/plugins/songusage/lib/upgrade.py b/openlp/plugins/songusage/lib/upgrade.py new file mode 100644 index 000000000..cdae3b694 --- /dev/null +++ b/openlp/plugins/songusage/lib/upgrade.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2011 Raoul Snyman # +# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, # +# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias # +# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### +""" +The :mod:`upgrade` module provides a way for the database and schema that is the +backend for the SongsUsage plugin +""" + +from sqlalchemy import Column, ForeignKey, Table, types +from migrate import changeset +from migrate.changeset.constraint import ForeignKeyConstraint + +__version__ = 1 + +def upgrade_setup(metadata): + """ + Set up the latest revision all tables, with reflection, needed for the + upgrade process. If you want to drop a table, you need to remove it from + here, and add it to your upgrade function. + """ + tables = { + u'songusage_data': Table(u'songusage_data', metadata, autoload=True) + } + print tables + return tables + + +def upgrade_1(session, metadata, tables): + """ + Version 1 upgrade. + + This upgrade adds two new fields to the songusage database + """ + print "hi" + Column(u'plugin_name', types.Unicode(20), default=u'') \ + .create(table=tables[u'songusage_data'], populate_default=True) + Column(u'source', types.Unicode(10), default=u'') \ + .create(table=tables[u'songusage_data'], populate_default=True) diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index b39fe1a33..1a0335d67 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -37,6 +37,7 @@ from openlp.core.lib.ui import base_action, shortcut_action from openlp.core.utils.actions import ActionList from openlp.plugins.songusage.forms import SongUsageDetailForm, \ SongUsageDeleteForm +from openlp.plugins.songusage.lib import upgrade from openlp.plugins.songusage.lib.db import init_schema, SongUsageItem log = logging.getLogger(__name__) @@ -46,11 +47,11 @@ class SongUsagePlugin(Plugin): def __init__(self, plugin_helpers): Plugin.__init__(self, u'songusage', plugin_helpers) + self.manager = Manager(u'songusage', init_schema, upgrade_mod=upgrade) self.weight = -4 self.icon = build_icon(u':/plugins/plugin_songusage.png') self.activeIcon = build_icon(u':/songusage/song_usage_active.png') self.inactiveIcon = build_icon(u':/songusage/song_usage_inactive.png') - self.manager = None self.songUsageActive = False def addToolsMenuItem(self, tools_menu): @@ -137,8 +138,6 @@ class SongUsagePlugin(Plugin): translate('SongUsagePlugin', 'Song Usage')) action_list.add_action(self.songUsageReport, translate('SongUsagePlugin', 'Song Usage')) - if self.manager is None: - self.manager = Manager(u'songusage', init_schema) self.songUsageDeleteForm = SongUsageDeleteForm(self.manager, self.formparent) self.songUsageDetailForm = SongUsageDetailForm(self, self.formparent) From 2dd0aa234e1b3e364105b9bd1098f158a262fcf5 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 26 Aug 2011 19:07:44 +0100 Subject: [PATCH 37/53] remove prints --- openlp/core/lib/db.py | 1 - openlp/plugins/songusage/lib/upgrade.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index 2c504c3ae..fb8a38b1f 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -72,7 +72,6 @@ def upgrade_db(url, upgrade): ``upgrade`` The python module that contains the upgrade instructions. """ - print url, upgrade session, metadata = init_db(url) tables = upgrade.upgrade_setup(metadata) metadata_table = Table(u'metadata', metadata, diff --git a/openlp/plugins/songusage/lib/upgrade.py b/openlp/plugins/songusage/lib/upgrade.py index cdae3b694..31b552fc6 100644 --- a/openlp/plugins/songusage/lib/upgrade.py +++ b/openlp/plugins/songusage/lib/upgrade.py @@ -44,7 +44,6 @@ def upgrade_setup(metadata): tables = { u'songusage_data': Table(u'songusage_data', metadata, autoload=True) } - print tables return tables @@ -54,7 +53,6 @@ def upgrade_1(session, metadata, tables): This upgrade adds two new fields to the songusage database """ - print "hi" Column(u'plugin_name', types.Unicode(20), default=u'') \ .create(table=tables[u'songusage_data'], populate_default=True) Column(u'source', types.Unicode(10), default=u'') \ From 1e4b922bface5007549f69faeb26892299f3f6e7 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 26 Aug 2011 20:09:25 +0100 Subject: [PATCH 38/53] DB Fixed --- openlp/core/lib/db.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index fb8a38b1f..7ad743235 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -73,6 +73,13 @@ def upgrade_db(url, upgrade): The python module that contains the upgrade instructions. """ session, metadata = init_db(url) + + class Metadata(BaseModel): + """ + Provides a class for the metadata table. + """ + pass + tables = upgrade.upgrade_setup(metadata) metadata_table = Table(u'metadata', metadata, Column(u'key', types.Unicode(64), primary_key=True), @@ -103,6 +110,7 @@ def upgrade_db(url, upgrade): session.commit() return int(version_meta.value), upgrade.__version__ + def delete_database(plugin_name, db_file_name=None): """ Remove a database file from the system. @@ -138,14 +146,6 @@ class BaseModel(object): instance.__setattr__(key, value) return instance - -class Metadata(BaseModel): - """ - Provides a class for the metadata table. - """ - pass - - class Manager(object): """ Provide generic object persistence management From 01128d4dc784a464a3404fa2012665b3fc7bec53 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 26 Aug 2011 20:31:02 +0100 Subject: [PATCH 39/53] Fix report and triggers --- .../songusage/forms/songusagedetailform.py | 8 ++++--- openlp/plugins/songusage/songusageplugin.py | 21 +++++++++++++++---- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/openlp/plugins/songusage/forms/songusagedetailform.py b/openlp/plugins/songusage/forms/songusagedetailform.py index 303789d20..f7b04a656 100644 --- a/openlp/plugins/songusage/forms/songusagedetailform.py +++ b/openlp/plugins/songusage/forms/songusagedetailform.py @@ -117,9 +117,11 @@ class SongUsageDetailForm(QtGui.QDialog, Ui_SongUsageDetailDialog): try: fileHandle = open(outname, u'w') for instance in usage: - record = u'\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"\n' % ( - instance.usagedate, instance.usagetime, instance.title, - instance.copyright, instance.ccl_number, instance.authors) + record = u'\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",' \ + u'\"%s\",\"%s\"\n' % ( instance.usagedate, + instance.usagetime, instance.title, instance.copyright, + instance.ccl_number, instance.authors, + instance.plugin_name, instance.source) fileHandle.write(record.encode(u'utf-8')) Receiver.send_message(u'openlp_information_message', { u'title': translate('SongUsagePlugin.SongUsageDetailForm', diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index 1a0335d67..495d3103d 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -122,10 +122,10 @@ class SongUsagePlugin(Plugin): Plugin.initialise(self) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'slidecontroller_live_started'), - self.onReceiveSongUsage) + self.displaySongUsage) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'print_service_started'), - self.onReceiveSongUsage) + self.printSongUsage) self.songUsageActive = QtCore.QSettings().value( self.settingsSection + u'/active', QtCore.QVariant(False)).toBool() @@ -196,10 +196,21 @@ class SongUsagePlugin(Plugin): self.songUsageStatus.blockSignals(False) - def onReceiveSongUsage(self, item): + def displaySongUsage(self, item): """ - Song Usage for live song from SlideController + Song Usage for which has been displayed """ + self._add_song_usage(unicode(translate('SongUsagePlugin', + 'display')), item) + + def printSongUsage(self, item): + """ + Song Usage for which has been printed + """ + self._add_song_usage(unicode(translate('SongUsagePlugin', + 'printed')), item) + + def _add_song_usage(self, source, item): audit = item[0].audit if self.songUsageActive and audit: song_usage_item = SongUsageItem() @@ -209,6 +220,8 @@ class SongUsagePlugin(Plugin): song_usage_item.copyright = audit[2] song_usage_item.ccl_number = audit[3] song_usage_item.authors = u' '.join(audit[1]) + song_usage_item.plugin_name = item[0].name + song_usage_item.source = source self.manager.save_object(song_usage_item) def onSongUsageDelete(self): From 3722253bcfe4597807331fb3cf9d270155cd3c79 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Fri, 26 Aug 2011 23:14:30 -0400 Subject: [PATCH 40/53] Added code to process any Bibles downloaded during the re-run of the First Time wizard --- openlp/core/ui/mainwindow.py | 3 +++ openlp/plugins/bibles/bibleplugin.py | 5 ++++- openlp/plugins/bibles/lib/mediaitem.py | 5 ++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 4ecf792bc..5bd8e9fb7 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -767,6 +767,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): self.themeManagerContents.loadThemes(True) Receiver.send_message(u'theme_update_global', self.themeManagerContents.global_theme) + # Check if any Bibles downloaded. If there are, they will be + # processed. + Receiver.send_message(u'bibles_load_list', True) def blankCheck(self): """ diff --git a/openlp/plugins/bibles/bibleplugin.py b/openlp/plugins/bibles/bibleplugin.py index 619581b17..900f04b50 100644 --- a/openlp/plugins/bibles/bibleplugin.py +++ b/openlp/plugins/bibles/bibleplugin.py @@ -29,7 +29,8 @@ import logging from PyQt4 import QtCore, QtGui -from openlp.core.lib import Plugin, StringContent, build_icon, translate +from openlp.core.lib import Plugin, StringContent, build_icon, translate, \ + Receiver from openlp.core.lib.ui import base_action, UiStrings from openlp.core.utils.actions import ActionList from openlp.plugins.bibles.lib import BibleManager, BiblesTab, BibleMediaItem @@ -62,6 +63,8 @@ class BiblePlugin(Plugin): self.exportBibleItem.setVisible(False) if len(self.manager.old_bible_databases): self.toolsUpgradeItem.setVisible(True) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'bibles_appStartup'), self.appStartup) def finalise(self): """ diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index 91009424c..710803bd2 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -391,10 +391,13 @@ class BibleMediaItem(MediaManagerItem): elif len(bibles): self.initialiseAdvancedBible(bibles[0]) - def reloadBibles(self): + def reloadBibles(self, process=False): log.debug(u'Reloading Bibles') self.plugin.manager.reload_bibles() self.loadBibles() + # If called from first time wizard re-run, process any new bibles. + if process: + Receiver.send_message(u'bibles_appStartup') self.updateAutoCompleter() def initialiseAdvancedBible(self, bible): From 9de4c0c1189cb3c8de2eab5942f7f37f20de5ce0 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 27 Aug 2011 07:07:30 +0100 Subject: [PATCH 41/53] Remove extra imports --- openlp/plugins/songusage/lib/upgrade.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/songusage/lib/upgrade.py b/openlp/plugins/songusage/lib/upgrade.py index 31b552fc6..1824fd594 100644 --- a/openlp/plugins/songusage/lib/upgrade.py +++ b/openlp/plugins/songusage/lib/upgrade.py @@ -29,7 +29,7 @@ The :mod:`upgrade` module provides a way for the database and schema that is the backend for the SongsUsage plugin """ -from sqlalchemy import Column, ForeignKey, Table, types +from sqlalchemy import Column, Table, types from migrate import changeset from migrate.changeset.constraint import ForeignKeyConstraint From 611577577fd27409b8a061ff9b2375047208792a Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 27 Aug 2011 07:12:03 +0100 Subject: [PATCH 42/53] Remove extra imports 2 --- openlp/plugins/songusage/lib/upgrade.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openlp/plugins/songusage/lib/upgrade.py b/openlp/plugins/songusage/lib/upgrade.py index 1824fd594..50ca32fcd 100644 --- a/openlp/plugins/songusage/lib/upgrade.py +++ b/openlp/plugins/songusage/lib/upgrade.py @@ -31,7 +31,6 @@ backend for the SongsUsage plugin from sqlalchemy import Column, Table, types from migrate import changeset -from migrate.changeset.constraint import ForeignKeyConstraint __version__ = 1 From c1a648900f2ac60e3ddf33826191160f009864bc Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 27 Aug 2011 16:02:45 +0100 Subject: [PATCH 43/53] Fix initial setup bug --- openlp/core/lib/db.py | 2 +- openlp/plugins/songs/lib/upgrade.py | 21 ++++++++++++--------- openlp/plugins/songusage/lib/upgrade.py | 9 ++++++--- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index 7ad743235..176262b22 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -90,7 +90,7 @@ def upgrade_db(url, upgrade): version_meta = session.query(Metadata).get(u'version') if version_meta is None: version_meta = Metadata.populate(key=u'version', value=u'0') - version = 0 + version = 0 if tables else upgrade.__version__; else: version = int(version_meta.value) if version > upgrade.__version__: diff --git a/openlp/plugins/songs/lib/upgrade.py b/openlp/plugins/songs/lib/upgrade.py index a7aa1bd6c..4f3c3d0dc 100644 --- a/openlp/plugins/songs/lib/upgrade.py +++ b/openlp/plugins/songs/lib/upgrade.py @@ -41,15 +41,18 @@ def upgrade_setup(metadata): upgrade process. If you want to drop a table, you need to remove it from here, and add it to your upgrade function. """ - tables = { - u'authors': Table(u'authors', metadata, autoload=True), - u'media_files': Table(u'media_files', metadata, autoload=True), - u'song_books': Table(u'song_books', metadata, autoload=True), - u'songs': Table(u'songs', metadata, autoload=True), - u'topics': Table(u'topics', metadata, autoload=True), - u'authors_songs': Table(u'authors_songs', metadata, autoload=True), - u'songs_topics': Table(u'songs_topics', metadata, autoload=True) - } + try: + tables = { + u'authors': Table(u'authors', metadata, autoload=True), + u'media_files': Table(u'media_files', metadata, autoload=True), + u'song_books': Table(u'song_books', metadata, autoload=True), + u'songs': Table(u'songs', metadata, autoload=True), + u'topics': Table(u'topics', metadata, autoload=True), + u'authors_songs': Table(u'authors_songs', metadata, autoload=True), + u'songs_topics': Table(u'songs_topics', metadata, autoload=True) + } + except: + tables = None return tables diff --git a/openlp/plugins/songusage/lib/upgrade.py b/openlp/plugins/songusage/lib/upgrade.py index 50ca32fcd..d4211a038 100644 --- a/openlp/plugins/songusage/lib/upgrade.py +++ b/openlp/plugins/songusage/lib/upgrade.py @@ -40,9 +40,12 @@ def upgrade_setup(metadata): upgrade process. If you want to drop a table, you need to remove it from here, and add it to your upgrade function. """ - tables = { - u'songusage_data': Table(u'songusage_data', metadata, autoload=True) - } + try: + tables = { + u'songusage_data': Table(u'songusage_data', metadata, autoload=True) + } + except: + tables = None return tables From 67894aa8d91210a8f85d08d02e7e656497795c24 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 27 Aug 2011 19:43:05 +0100 Subject: [PATCH 44/53] Error Handling improvements --- openlp/core/lib/db.py | 34 +++++++++++++++---------- openlp/plugins/songs/lib/upgrade.py | 21 +++++++-------- openlp/plugins/songusage/lib/upgrade.py | 9 +++---- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index 176262b22..2e5d011cf 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -79,8 +79,11 @@ def upgrade_db(url, upgrade): Provides a class for the metadata table. """ pass - - tables = upgrade.upgrade_setup(metadata) + load_changes = True + try: + tables = upgrade.upgrade_setup(metadata) + except SQLAlchemyError, DBAPIError: + load_changes = False metadata_table = Table(u'metadata', metadata, Column(u'key', types.Unicode(64), primary_key=True), Column(u'value', types.UnicodeText(), default=None) @@ -90,22 +93,27 @@ def upgrade_db(url, upgrade): version_meta = session.query(Metadata).get(u'version') if version_meta is None: version_meta = Metadata.populate(key=u'version', value=u'0') - version = 0 if tables else upgrade.__version__; + version = 0 else: version = int(version_meta.value) if version > upgrade.__version__: return version, upgrade.__version__ version += 1 - while hasattr(upgrade, u'upgrade_%d' % version): - log.debug(u'Running upgrade_%d', version) - try: - getattr(upgrade, u'upgrade_%d' % version)(session, metadata, tables) - version_meta.value = unicode(version) - except SQLAlchemyError, DBAPIError: - log.exception(u'Could not run database upgrade script "upgrade_%s"'\ - ', upgrade process has been halted.', version) - break - version += 1 + if load_changes: + while hasattr(upgrade, u'upgrade_%d' % version): + log.debug(u'Running upgrade_%d', version) + try: + getattr(upgrade, u'upgrade_%d' % version) \ + (session, metadata, tables) + version_meta.value = unicode(version) + except SQLAlchemyError, DBAPIError: + log.exception(u'Could not run database upgrade script ' + '"upgrade_%s", upgrade process has been halted.', version) + break + version += 1 + else: + version_meta = Metadata.populate(key=u'version', + value=int(upgrade.__version__)) session.add(version_meta) session.commit() return int(version_meta.value), upgrade.__version__ diff --git a/openlp/plugins/songs/lib/upgrade.py b/openlp/plugins/songs/lib/upgrade.py index b28d1764d..fae3400c2 100644 --- a/openlp/plugins/songs/lib/upgrade.py +++ b/openlp/plugins/songs/lib/upgrade.py @@ -42,18 +42,15 @@ def upgrade_setup(metadata): upgrade process. If you want to drop a table, you need to remove it from here, and add it to your upgrade function. """ - try: - tables = { - u'authors': Table(u'authors', metadata, autoload=True), - u'media_files': Table(u'media_files', metadata, autoload=True), - u'song_books': Table(u'song_books', metadata, autoload=True), - u'songs': Table(u'songs', metadata, autoload=True), - u'topics': Table(u'topics', metadata, autoload=True), - u'authors_songs': Table(u'authors_songs', metadata, autoload=True), - u'songs_topics': Table(u'songs_topics', metadata, autoload=True) - } - except: - tables = None + tables = { + u'authors': Table(u'authors', metadata, autoload=True), + u'media_files': Table(u'media_files', metadata, autoload=True), + u'song_books': Table(u'song_books', metadata, autoload=True), + u'songs': Table(u'songs', metadata, autoload=True), + u'topics': Table(u'topics', metadata, autoload=True), + u'authors_songs': Table(u'authors_songs', metadata, autoload=True), + u'songs_topics': Table(u'songs_topics', metadata, autoload=True) + } return tables diff --git a/openlp/plugins/songusage/lib/upgrade.py b/openlp/plugins/songusage/lib/upgrade.py index d4211a038..50ca32fcd 100644 --- a/openlp/plugins/songusage/lib/upgrade.py +++ b/openlp/plugins/songusage/lib/upgrade.py @@ -40,12 +40,9 @@ def upgrade_setup(metadata): upgrade process. If you want to drop a table, you need to remove it from here, and add it to your upgrade function. """ - try: - tables = { - u'songusage_data': Table(u'songusage_data', metadata, autoload=True) - } - except: - tables = None + tables = { + u'songusage_data': Table(u'songusage_data', metadata, autoload=True) + } return tables From d4e6c44d217d982c2e9e3a6755b05a9e39f14441 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Sat, 27 Aug 2011 16:42:22 -0400 Subject: [PATCH 45/53] Fixed signal name --- openlp/plugins/bibles/bibleplugin.py | 2 +- openlp/plugins/bibles/lib/mediaitem.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/plugins/bibles/bibleplugin.py b/openlp/plugins/bibles/bibleplugin.py index 900f04b50..17bad2b64 100644 --- a/openlp/plugins/bibles/bibleplugin.py +++ b/openlp/plugins/bibles/bibleplugin.py @@ -64,7 +64,7 @@ class BiblePlugin(Plugin): if len(self.manager.old_bible_databases): self.toolsUpgradeItem.setVisible(True) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'bibles_appStartup'), self.appStartup) + QtCore.SIGNAL(u'bibles_app_startup'), self.appStartup) def finalise(self): """ diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index 710803bd2..fe0fc58c3 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -397,7 +397,7 @@ class BibleMediaItem(MediaManagerItem): self.loadBibles() # If called from first time wizard re-run, process any new bibles. if process: - Receiver.send_message(u'bibles_appStartup') + Receiver.send_message(u'bibles_app_startup') self.updateAutoCompleter() def initialiseAdvancedBible(self, bible): From 9957419f2b72d824cb165bbbce6927008b4ec81c Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Sun, 28 Aug 2011 09:39:34 -0400 Subject: [PATCH 46/53] Changed system exit call --- openlp/core/ui/mainwindow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 6dbd57511..3fe4a777d 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -981,7 +981,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtGui.QMessageBox.Ok)) self.settingsImported = True self.cleanUp() - os._exit(0) + QtCore.QCoreApplication.exit() def onSettingsExportItemClicked(self, exportFileName=None): """ From 2364ea72c2b4b8fc2da0c7badd317639959b432e Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sun, 28 Aug 2011 17:53:27 +0200 Subject: [PATCH 47/53] hopefully completed the fix --- openlp/core/lib/renderer.py | 43 +++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index df8235b33..b5d507e29 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -227,35 +227,36 @@ class Renderer(object): # Clean up line endings. lines = self._lines_split(text) pages = self._paginate_slide(lines, line_end) - if len(pages) > 1: - # Songs and Custom - if item.is_capable(ItemCapabilities.AllowsVirtualSplit) and \ - u'[---]' in text: - pages = [] - while True: - html_text = expand_tags(text.split(u'[---]', 1)[0]) - html_text = html_text.strip() + # Songs and Custom + if item.is_capable(ItemCapabilities.AllowsVirtualSplit) and \ + len(pages) > 1 and u'[---]' in text: + pages = [] + while True: + html_text = expand_tags( + u'\n'.join(text.split(u'\n[---]\n', 2)[:-1])) + html_text = html_text.replace(u'\n', u'
') + if self._text_fits_on_slide(html_text): + text = text.replace(u'\n[---]', u'', 2) + else: + html_text = expand_tags(text.split(u'\n[---]\n', 1)[1]) html_text = html_text.replace(u'\n', u'
') if self._text_fits_on_slide(html_text): text = text.replace(u'\n[---]', u'', 1) else: if u'[---]' in text: - slides = text.split(u'[---]', 1) - text_to_render = slides[0] - text_to_render = text_to_render.strip() - text_to_render = text_to_render.replace(u'\n', u'
') - text = slides[1] + html_text, text = text.split(u'\n[---]\n', 1) + html_text = html_text.replace(u'\n', u'
') else: - text_to_render = text + html_text = text text = u'' - lines = text_to_render.strip(u'\n').split(u'\n') - lines = map(expand_tags, lines) + lines = expand_tags(html_text) + lines = lines.strip(u'\n').split(u'\n') pages.extend(self._paginate_slide(lines, line_end)) - if not text or u'[---]' not in text: - lines = text.strip(u'\n').split(u'\n') - lines = map(expand_tags, lines) - pages.extend(self._paginate_slide(lines, line_end)) - break + if u'[---]' not in text: + lines = expand_tags(text) + lines = lines.strip(u'\n').split(u'\n') + pages.extend(self._paginate_slide(lines, line_end)) + break new_pages = [] for page in pages: while page.endswith(u'
'): From 2acd1ae2adfdc7f93240d1668a82b8a60677a021 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sun, 28 Aug 2011 18:04:18 +0200 Subject: [PATCH 48/53] added comments --- openlp/core/lib/renderer.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index b5d507e29..c4cbe8568 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -232,17 +232,26 @@ class Renderer(object): len(pages) > 1 and u'[---]' in text: pages = [] while True: + # Check if the first two potential virtual slides will fit + # (as a whole) on one slide. html_text = expand_tags( u'\n'.join(text.split(u'\n[---]\n', 2)[:-1])) html_text = html_text.replace(u'\n', u'
') if self._text_fits_on_slide(html_text): + # The first two virtual slides fit (as a whole) on one + # slide. Replace the occurrences of [---]. text = text.replace(u'\n[---]', u'', 2) else: + # The first two virtual slides did not fit as a whole. + # Check if the first virtual slide will fit. html_text = expand_tags(text.split(u'\n[---]\n', 1)[1]) html_text = html_text.replace(u'\n', u'
') if self._text_fits_on_slide(html_text): + # The first virtual slide fits, so remove it. text = text.replace(u'\n[---]', u'', 1) else: + # The first virtual slide does not fit, which means + # we have to render the first virtual slide. if u'[---]' in text: html_text, text = text.split(u'\n[---]\n', 1) html_text = html_text.replace(u'\n', u'
') From bc1f2d2977f050ddcd392adb9c730f6d11e2e50b Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sun, 28 Aug 2011 18:59:09 +0200 Subject: [PATCH 49/53] removed wrong line --- openlp/core/lib/renderer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index c4cbe8568..94cff011d 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -254,7 +254,6 @@ class Renderer(object): # we have to render the first virtual slide. if u'[---]' in text: html_text, text = text.split(u'\n[---]\n', 1) - html_text = html_text.replace(u'\n', u'
') else: html_text = text text = u'' From fc71905735e4d6fa9712e4bdc762c3a132314eb7 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sun, 28 Aug 2011 19:46:52 +0200 Subject: [PATCH 50/53] append text to the last slide (if more than one) --- openlp/core/lib/renderer.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 94cff011d..eed31a689 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -252,14 +252,26 @@ class Renderer(object): else: # The first virtual slide does not fit, which means # we have to render the first virtual slide. - if u'[---]' in text: + text_contains_break = u'[---]' in text + if text_contains_break: html_text, text = text.split(u'\n[---]\n', 1) else: html_text = text text = u'' lines = expand_tags(html_text) lines = lines.strip(u'\n').split(u'\n') - pages.extend(self._paginate_slide(lines, line_end)) + slides = self._paginate_slide(lines, line_end) + if len(slides) > 1 and text: + # Add all slides apart from the last one the + # list. + pages.extend(slides[:-1]) + if text_contains_break: + text = slides[-1] + u'\n[---]\n' + text + else: + text = slides[-1] + u'\n'+ text + text = text.replace(u'
', u'\n') + else: + pages.extend(slides) if u'[---]' not in text: lines = expand_tags(text) lines = lines.strip(u'\n').split(u'\n') From d061436a35d147ac0578524f262ec65a27a49db4 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Mon, 29 Aug 2011 08:30:31 +0200 Subject: [PATCH 51/53] replaced Ini by config --- openlp/core/ui/mainwindow.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 3fe4a777d..1b69e481f 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -289,7 +289,7 @@ class Ui_MainWindow(object): self.settingsImportItem = base_action(mainWindow, u'settingsImportItem', category=UiStrings().Settings) self.settingsExportItem = base_action(mainWindow, - u'settingsExportItem', category=UiStrings().Settings) + u'settingsExportItem', category=UiStrings().Settings) action_list.add_category(UiStrings().Help, CategoryOrder.standardMenu) self.aboutItem = shortcut_action(mainWindow, u'aboutItem', [QtGui.QKeySequence(u'Ctrl+F1')], self.onAboutItemClicked, @@ -428,11 +428,11 @@ class Ui_MainWindow(object): self.settingsConfigureItem.setText( translate('OpenLP.MainWindow', '&Configure OpenLP...')) self.settingsExportItem.setStatusTip(translate('OpenLP.MainWindow', - 'Export OpenLP settings to a specified Ini file')) + 'Export OpenLP settings to a specified *.config file')) self.settingsExportItem.setText( translate('OpenLP.MainWindow', 'Settings')) self.settingsImportItem.setStatusTip(translate('OpenLP.MainWindow', - 'Import OpenLP settings from a specified Ini file previously ' + 'Import OpenLP settings from a specified *.config file previously ' 'exported on this or another machine')) self.settingsImportItem.setText( translate('OpenLP.MainWindow', 'Settings')) @@ -997,7 +997,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): # Make sure it's an .ini file. if not exportFileName.endswith(u'conf'): exportFileName = exportFileName + u'.conf' - temp_file = os.path.join(unicode(gettempdir()), + temp_file = os.path.join(unicode(gettempdir()), u'openlp', u'exportIni.tmp') self.saveSettings() settingSections = [] From 7e4825653430ec51fed47f48c117676a6dc64a16 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Mon, 29 Aug 2011 08:47:32 -0400 Subject: [PATCH 52/53] Removed need for signal to run appStartup --- openlp/plugins/bibles/bibleplugin.py | 2 -- openlp/plugins/bibles/lib/mediaitem.py | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/openlp/plugins/bibles/bibleplugin.py b/openlp/plugins/bibles/bibleplugin.py index 17bad2b64..b9f4769cf 100644 --- a/openlp/plugins/bibles/bibleplugin.py +++ b/openlp/plugins/bibles/bibleplugin.py @@ -63,8 +63,6 @@ class BiblePlugin(Plugin): self.exportBibleItem.setVisible(False) if len(self.manager.old_bible_databases): self.toolsUpgradeItem.setVisible(True) - QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'bibles_app_startup'), self.appStartup) def finalise(self): """ diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index fe0fc58c3..9083b18a2 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -397,7 +397,7 @@ class BibleMediaItem(MediaManagerItem): self.loadBibles() # If called from first time wizard re-run, process any new bibles. if process: - Receiver.send_message(u'bibles_app_startup') + self.plugin.appStartup() self.updateAutoCompleter() def initialiseAdvancedBible(self, bible): From 96076a4bac95e99872d5e33b4146aa645ffe1d41 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Mon, 29 Aug 2011 08:59:19 -0400 Subject: [PATCH 53/53] Removed import receiver --- openlp/plugins/bibles/bibleplugin.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openlp/plugins/bibles/bibleplugin.py b/openlp/plugins/bibles/bibleplugin.py index b9f4769cf..619581b17 100644 --- a/openlp/plugins/bibles/bibleplugin.py +++ b/openlp/plugins/bibles/bibleplugin.py @@ -29,8 +29,7 @@ import logging from PyQt4 import QtCore, QtGui -from openlp.core.lib import Plugin, StringContent, build_icon, translate, \ - Receiver +from openlp.core.lib import Plugin, StringContent, build_icon, translate from openlp.core.lib.ui import base_action, UiStrings from openlp.core.utils.actions import ActionList from openlp.plugins.bibles.lib import BibleManager, BiblesTab, BibleMediaItem