diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index 86e0a0a30..b6f12d180 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -358,10 +358,17 @@ class Manager(object): def delete_all_objects(self, object_class, filter_clause=None): """ - Delete all object records + Delete all object records. + This method should only be used for simple tables and not ones with + relationships. The relationships are not deleted from the database and + this will lead to database corruptions. ``object_class`` The type of object to delete + + ``filter_clause`` + The filter governing selection of objects to return. Defaults to + None. """ try: query = self.session.query(object_class) diff --git a/openlp/core/lib/eventreceiver.py b/openlp/core/lib/eventreceiver.py index 14b6126bc..40cac8e35 100644 --- a/openlp/core/lib/eventreceiver.py +++ b/openlp/core/lib/eventreceiver.py @@ -115,8 +115,12 @@ class EventReceiver(QtCore.QObject): ``slidecontroller_live_stop_loop`` Stop the loop on the main display. + **Servicemanager related signals** + ``servicemanager_new_service`` + A new service is being loaded or created. + ``servicemanager_previous_item`` Display the previous item in the service. diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index b12a27f1d..62418f49e 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -119,6 +119,7 @@ class ServiceItem(object): self.image_border = u'#000000' self.background_audio = [] self.theme_overwritten = False + self.temporary_edit = False self._new_item() def _new_item(self): @@ -365,6 +366,7 @@ class ServiceItem(object): """ self._uuid = other._uuid self.notes = other.notes + self.temporary_edit = other.temporary_edit # Copy theme over if present. if other.theme is not None: self.theme = other.theme diff --git a/openlp/core/lib/settingstab.py b/openlp/core/lib/settingstab.py index 46263efca..f36f9f561 100644 --- a/openlp/core/lib/settingstab.py +++ b/openlp/core/lib/settingstab.py @@ -125,3 +125,9 @@ class SettingsTab(QtGui.QWidget): """ pass + + def tabVisible(self): + """ + Tab has just been made visible to the user + """ + pass diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index e439b1db1..328970d45 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -45,7 +45,7 @@ log = logging.getLogger(__name__) class Display(QtGui.QGraphicsView): """ - This is a general display screen class. Here the general display settings + This is a general display screen class. Here the general display settings will done. It will be used as specialized classes by Main Display and Preview display. """ @@ -66,7 +66,7 @@ class Display(QtGui.QGraphicsView): """ Set up and build the screen base """ - log.debug(u'Start Display base setup (live = %s)' % self.isLive) + log.debug(u'Start Display base setup (live = %s)' % self.isLive) self.setGeometry(self.screen[u'size']) log.debug(u'Setup webView') self.webView = QtWebKit.QWebView(self) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 0480cb70b..0eb1e77c5 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -37,7 +37,7 @@ log = logging.getLogger(__name__) from PyQt4 import QtCore, QtGui from openlp.core.lib import OpenLPToolbar, ServiceItem, Receiver, build_icon, \ - ItemCapabilities, SettingsManager, translate + ItemCapabilities, SettingsManager, translate, str_to_bool from openlp.core.lib.theme import ThemeLevel from openlp.core.lib.ui import UiStrings, critical_error_message_box, \ context_menu_action, context_menu_separator, find_and_set_in_combo_box @@ -465,6 +465,7 @@ class ServiceManager(QtGui.QWidget): self.setModified(False) QtCore.QSettings(). \ setValue(u'servicemanager/last file',QtCore.QVariant(u'')) + Receiver.send_message(u'servicemanager_new_service') def saveFile(self): """ @@ -663,13 +664,14 @@ class ServiceManager(QtGui.QWidget): serviceItem.renderer = self.mainwindow.renderer serviceItem.set_from_service(item, self.servicePath) self.validateItem(serviceItem) - self.loadItem_uuid = 0 + self.load_item_uuid = 0 if serviceItem.is_capable(ItemCapabilities.OnLoadUpdate): Receiver.send_message(u'%s_service_load' % serviceItem.name.lower(), serviceItem) # if the item has been processed - if serviceItem._uuid == self.loadItem_uuid: - serviceItem.edit_id = int(self.loadItem_editId) + if serviceItem._uuid == self.load_item_uuid: + serviceItem.edit_id = int(self.load_item_edit_id) + serviceItem.temporary_edit = self.load_item_temporary self.addServiceItem(serviceItem, repaint=False) delete_file(p_file) self.setFileName(fileName) @@ -999,6 +1001,17 @@ class ServiceManager(QtGui.QWidget): painter.drawImage(0, 0, overlay) painter.end() treewidgetitem.setIcon(0, build_icon(icon)) + elif serviceitem.temporary_edit: + icon = QtGui.QImage(serviceitem.icon) + icon = icon.scaled(80, 80, QtCore.Qt.KeepAspectRatio, + QtCore.Qt.SmoothTransformation) + overlay = QtGui.QImage(':/general/general_export.png') + overlay = overlay.scaled(40, 40, QtCore.Qt.KeepAspectRatio, + QtCore.Qt.SmoothTransformation) + painter = QtGui.QPainter(icon) + painter.drawImage(40, 0, overlay) + painter.end() + treewidgetitem.setIcon(0, build_icon(icon)) else: treewidgetitem.setIcon(0, serviceitem.iconic_representation) else: @@ -1006,6 +1019,11 @@ class ServiceManager(QtGui.QWidget): build_icon(u':/general/general_delete.png')) treewidgetitem.setText(0, serviceitem.get_display_title()) tips = [] + if serviceitem.temporary_edit: + tips.append(u'%s: %s' % + (unicode(translate('OpenLP.ServiceManager', 'Edit')), + (unicode(translate('OpenLP.ServiceManager', + 'Service copy only'))))) if serviceitem.theme and serviceitem.theme != -1: tips.append(u'%s: %s' % (unicode(translate('OpenLP.ServiceManager', 'Slide theme')), @@ -1127,8 +1145,9 @@ class ServiceManager(QtGui.QWidget): Triggered from plugins to update service items. Save the values as they will be used as part of the service load """ - editId, self.loadItem_uuid = message.split(u':') - self.loadItem_editId = int(editId) + edit_id, self.load_item_uuid, temporary = message.split(u':') + self.load_item_edit_id = int(edit_id) + self.load_item_temporary = str_to_bool(temporary) def replaceServiceItem(self, newItem): """ diff --git a/openlp/core/ui/settingsdialog.py b/openlp/core/ui/settingsdialog.py index 296337f0f..643ab0a6e 100644 --- a/openlp/core/ui/settingsdialog.py +++ b/openlp/core/ui/settingsdialog.py @@ -55,7 +55,7 @@ class Ui_SettingsDialog(object): QtCore.QMetaObject.connectSlotsByName(settingsDialog) QtCore.QObject.connect(self.settingListWidget, QtCore.SIGNAL(u'currentRowChanged(int)'), - self.stackedLayout.setCurrentIndex) + self.tabChanged) def retranslateUi(self, settingsDialog): settingsDialog.setWindowTitle(translate('OpenLP.SettingsForm', diff --git a/openlp/core/ui/settingsform.py b/openlp/core/ui/settingsform.py index 37da93b5b..b25a3a856 100644 --- a/openlp/core/ui/settingsform.py +++ b/openlp/core/ui/settingsform.py @@ -116,3 +116,10 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog): for plugin in self.plugins: if plugin.settings_tab: plugin.settings_tab.postSetUp() + + def tabChanged(self, tabIndex): + """ + A different settings tab is selected + """ + self.stackedLayout.setCurrentIndex(tabIndex) + self.stackedLayout.currentWidget().tabVisible() diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index 36f684ad4..8355da5a8 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -184,7 +184,15 @@ class ImpressController(PresentationController): if not desktop: return docs = desktop.getComponents() + cnt = 0 if docs.hasElements(): + list = docs.createEnumeration() + while list.hasMoreElements(): + doc = list.nextElement() + if doc.getImplementationName() != \ + u'com.sun.star.comp.framework.BackingComp': + cnt = cnt + 1 + if cnt > 0: log.debug(u'OpenOffice not terminated as docs are still open') else: try: diff --git a/openlp/plugins/presentations/lib/presentationcontroller.py b/openlp/plugins/presentations/lib/presentationcontroller.py index a9d384c81..7ff04179f 100644 --- a/openlp/plugins/presentations/lib/presentationcontroller.py +++ b/openlp/plugins/presentations/lib/presentationcontroller.py @@ -378,7 +378,7 @@ class PresentationController(object): self.name = name self.document_class = document_class self.settings_section = self.plugin.settingsSection - self.available = self.check_available() + self.available = None self.temp_folder = os.path.join( AppLocation.get_section_data_path(self.settings_section), name) self.thumbnail_folder = os.path.join( @@ -392,14 +392,19 @@ class PresentationController(object): """ Return whether the controller is currently enabled """ - if self.available: - return QtCore.QSettings().value( - self.settings_section + u'/' + self.name, - QtCore.QVariant(QtCore.Qt.Checked)).toInt()[0] == \ - QtCore.Qt.Checked + if QtCore.QSettings().value( + self.settings_section + u'/' + self.name, + QtCore.QVariant(QtCore.Qt.Checked)).toInt()[0] == \ + QtCore.Qt.Checked: + return self.is_available() else: return False + def is_available(self): + if self.available is None: + self.available = self.check_available() + return self.available + def check_available(self): """ Presentation app is able to run on this machine diff --git a/openlp/plugins/presentations/lib/presentationtab.py b/openlp/plugins/presentations/lib/presentationtab.py index b0c3de7a8..c11f36c20 100644 --- a/openlp/plugins/presentations/lib/presentationtab.py +++ b/openlp/plugins/presentations/lib/presentationtab.py @@ -55,7 +55,6 @@ class PresentationTab(SettingsTab): for key in self.controllers: controller = self.controllers[key] checkbox = QtGui.QCheckBox(self.ControllersGroupBox) - checkbox.setEnabled(controller.available) checkbox.setObjectName(controller.name + u'CheckBox') self.PresenterCheckboxes[controller.name] = checkbox self.ControllersLayout.addWidget(checkbox) @@ -81,17 +80,20 @@ class PresentationTab(SettingsTab): for key in self.controllers: controller = self.controllers[key] checkbox = self.PresenterCheckboxes[controller.name] - if controller.available: - checkbox.setText(controller.name) - else: - checkbox.setText( - unicode(translate('PresentationPlugin.PresentationTab', - '%s (unavailable)')) % controller.name) + self.setControllerText(checkbox, controller) self.AdvancedGroupBox.setTitle(UiStrings().Advanced) self.OverrideAppCheckBox.setText( translate('PresentationPlugin.PresentationTab', 'Allow presentation application to be overriden')) + def setControllerText(self, checkbox, controller): + if checkbox.isEnabled(): + checkbox.setText(controller.name) + else: + checkbox.setText( + unicode(translate('PresentationPlugin.PresentationTab', + '%s (unavailable)')) % controller.name) + def load(self): """ Load the settings. @@ -113,7 +115,7 @@ class PresentationTab(SettingsTab): changed = False for key in self.controllers: controller = self.controllers[key] - if controller.available: + if controller.is_available(): checkbox = self.PresenterCheckboxes[controller.name] setting_key = self.settingsSection + u'/' + controller.name if QtCore.QSettings().value(setting_key) != \ @@ -133,3 +135,13 @@ class PresentationTab(SettingsTab): changed = True if changed: Receiver.send_message(u'mediaitem_presentation_rebuild') + + def tabVisible(self): + """ + Tab has just been made visible to the user + """ + for key in self.controllers: + controller = self.controllers[key] + checkbox = self.PresenterCheckboxes[controller.name] + checkbox.setEnabled(controller.is_available()) + self.setControllerText(checkbox, controller) diff --git a/openlp/plugins/songs/forms/songexportform.py b/openlp/plugins/songs/forms/songexportform.py index 22020a401..20a52c82d 100644 --- a/openlp/plugins/songs/forms/songexportform.py +++ b/openlp/plugins/songs/forms/songexportform.py @@ -252,6 +252,9 @@ class SongExportForm(OpenLPWizard): songs = self.plugin.manager.get_all_objects(Song) songs.sort(cmp=locale.strcoll, key=lambda song: song.title.lower()) for song in songs: + # No need to export temporary songs. + if song.temporary: + continue authors = u', '.join([author.display_name for author in song.authors]) title = u'%s (%s)' % (unicode(song.title), authors) diff --git a/openlp/plugins/songs/lib/db.py b/openlp/plugins/songs/lib/db.py index 37ee42451..ce228e5f8 100644 --- a/openlp/plugins/songs/lib/db.py +++ b/openlp/plugins/songs/lib/db.py @@ -199,7 +199,8 @@ def init_schema(url): Column(u'search_lyrics', types.UnicodeText, nullable=False), Column(u'create_date', types.DateTime(), default=func.now()), Column(u'last_modified', types.DateTime(), default=func.now(), - onupdate=func.now()) + onupdate=func.now()), + Column(u'temporary', types.Boolean(), default=False) ) # Definition of the "topics" table diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index dad95c61b..052fb5b7b 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -270,6 +270,9 @@ class SongMediaItem(MediaManagerItem): searchresults.sort( cmp=locale.strcoll, key=lambda song: song.title.lower()) for song in searchresults: + # Do not display temporary songs + if song.temporary: + continue author_list = [author.display_name for author in song.authors] song_title = unicode(song.title) song_detail = u'%s (%s)' % (song_title, u', '.join(author_list)) @@ -286,6 +289,9 @@ class SongMediaItem(MediaManagerItem): self.listView.clear() for author in searchresults: for song in author.songs: + # Do not display temporary songs + if song.temporary: + continue song_detail = u'%s (%s)' % (author.display_name, song.title) song_name = QtGui.QListWidgetItem(song_detail) song_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(song.id)) @@ -534,6 +540,7 @@ class SongMediaItem(MediaManagerItem): Song.search_title.asc()) editId = 0 add_song = True + temporary = False if search_results: for song in search_results: author_list = item.data_string[u'authors'] @@ -559,13 +566,18 @@ class SongMediaItem(MediaManagerItem): self._updateBackgroundAudio(song, item) editId = song.id self.onSearchTextButtonClick() - else: + elif add_song and not self.addSongFromService: # Make sure we temporary import formatting tags. - self.openLyrics.xml_to_song(item.xml_version, True) + song = self.openLyrics.xml_to_song(item.xml_version, True) + # If there's any backing tracks, copy them over. + if len(item.background_audio) > 0: + self._updateBackgroundAudio(song, item) + editId = song.id + temporary = True # Update service with correct song id. if editId: Receiver.send_message(u'service_item_update', - u'%s:%s' % (editId, item._uuid)) + u'%s:%s:%s' % (editId, item._uuid, temporary)) def search(self, string): """ diff --git a/openlp/plugins/songs/lib/sofimport.py b/openlp/plugins/songs/lib/sofimport.py index 4bb91f58a..7bd0a50d6 100644 --- a/openlp/plugins/songs/lib/sofimport.py +++ b/openlp/plugins/songs/lib/sofimport.py @@ -345,7 +345,8 @@ class SofImport(OooImport): u'I\'M', u'I\'LL', u'SAVIOUR', u'O', u'YOU\'RE', u'HE', u'HIS', u'HIM', u'ZION', u'EMMANUEL', u'MAJESTY', u'JESUS\'', u'JIREH', u'JUDAH', u'LION', u'LORD\'S', u'ABRAHAM', u'GOD\'S', - u'FATHER\'S', u'ELIJAH'): + u'FATHER\'S', u'ELIJAH' u'MARTHA', u'CHRISTMAS', u'ALPHA', + u'OMEGA'): textarr[i] = textarr[i].capitalize() else: textarr[i] = textarr[i].lower() diff --git a/openlp/plugins/songs/lib/upgrade.py b/openlp/plugins/songs/lib/upgrade.py index f97fdff42..25f90e860 100644 --- a/openlp/plugins/songs/lib/upgrade.py +++ b/openlp/plugins/songs/lib/upgrade.py @@ -33,7 +33,9 @@ from sqlalchemy import Column, Table, types from sqlalchemy.sql.expression import func from migrate.changeset.constraint import ForeignKeyConstraint -__version__ = 2 +from openlp.plugins.songs.lib.db import Song + +__version__ = 3 def upgrade_setup(metadata): """ @@ -86,3 +88,12 @@ def upgrade_2(session, metadata, tables): Column(u'last_modified', types.DateTime(), default=func.now())\ .create(table=tables[u'songs']) +def upgrade_3(session, metadata, tables): + """ + Version 3 upgrade. + + This upgrade adds a temporary song flag to the songs table + """ + Column(u'temporary', types.Boolean(), default=False)\ + .create(table=tables[u'songs']) + diff --git a/openlp/plugins/songs/lib/xml.py b/openlp/plugins/songs/lib/xml.py index aaf82b395..b16db7e94 100644 --- a/openlp/plugins/songs/lib/xml.py +++ b/openlp/plugins/songs/lib/xml.py @@ -346,7 +346,7 @@ class OpenLyrics(object): lines_element.set(u'break', u'optional') return self._extract_xml(song_xml) - def xml_to_song(self, xml, parse_and_not_save=False): + def xml_to_song(self, xml, parse_and_temporary_save=False): """ Create and save a song from OpenLyrics format xml to the database. Since we also export XML from external sources (e. g. OpenLyrics import), we @@ -355,9 +355,9 @@ class OpenLyrics(object): ``xml`` The XML to parse (unicode). - ``parse_and_not_save`` - Switch to skip processing the whole song and to prevent storing the - songs to the database. Defaults to ``False``. + ``parse_and_temporary_save`` + Switch to skip processing the whole song and storing the songs in + the database with a temporary flag. Defaults to ``False``. """ # No xml get out of here. if not xml: @@ -371,14 +371,13 @@ class OpenLyrics(object): return None # Formatting tags are new in OpenLyrics 0.8 if float(song_xml.get(u'version')) > 0.7: - self._process_formatting_tags(song_xml, parse_and_not_save) - if parse_and_not_save: - return + self._process_formatting_tags(song_xml, parse_and_temporary_save) song = Song() # Values will be set when cleaning the song. song.search_lyrics = u'' song.verse_order = u'' song.search_title = u'' + song.temporary = parse_and_temporary_save self._process_copyright(properties, song) self._process_cclinumber(properties, song) self._process_titles(properties, song) diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index 307769df0..5402ec1fa 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -78,6 +78,10 @@ class SongsPlugin(Plugin): action_list.add_action(self.songExportItem, unicode(UiStrings().Export)) action_list.add_action(self.toolsReindexItem, unicode(UiStrings().Tools)) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'servicemanager_new_service'), + self.clearTemporarySongs) + def addImportMenuItem(self, import_menu): """ @@ -265,6 +269,8 @@ class SongsPlugin(Plugin): Time to tidy up on exit """ log.info(u'Songs Finalising') + self.clearTemporarySongs() + # Clean up files and connections self.manager.finalise() self.songImportItem.setVisible(False) self.songExportItem.setVisible(False) @@ -277,3 +283,9 @@ class SongsPlugin(Plugin): action_list.remove_action(self.toolsReindexItem, unicode(UiStrings().Tools)) Plugin.finalise(self) + + def clearTemporarySongs(self): + # Remove temporary songs + songs = self.manager.get_all_objects(Song, Song.temporary == True) + for song in songs: + self.manager.delete_object(Song, song.id)