diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index 1b8d086df..cafc867b3 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -29,6 +29,7 @@ The :mod:`db` module provides the core database functionality for OpenLP """ import logging import os +from urllib import quote_plus as urlquote from PyQt4 import QtCore from sqlalchemy import Table, MetaData, Column, types, create_engine @@ -193,10 +194,10 @@ class Manager(object): AppLocation.get_section_data_path(plugin_name), plugin_name) else: self.db_url = u'%s://%s:%s@%s/%s' % (db_type, - unicode(settings.value(u'db username').toString()), - unicode(settings.value(u'db password').toString()), - unicode(settings.value(u'db hostname').toString()), - unicode(settings.value(u'db database').toString())) + urlquote(unicode(settings.value(u'db username').toString())), + urlquote(unicode(settings.value(u'db password').toString())), + urlquote(unicode(settings.value(u'db hostname').toString())), + urlquote(unicode(settings.value(u'db database').toString()))) settings.endGroup() if upgrade_mod: db_ver, up_ver = upgrade_db(self.db_url, upgrade_mod) diff --git a/openlp/core/lib/htmlbuilder.py b/openlp/core/lib/htmlbuilder.py index 863943e40..5dfe00d36 100644 --- a/openlp/core/lib/htmlbuilder.py +++ b/openlp/core/lib/htmlbuilder.py @@ -610,24 +610,3 @@ def build_footer_css(item, height): theme.font_footer_size, theme.font_footer_color) return lyrics_html -def build_alert_css(alertTab, width): - """ - Build the display of the footer - - ``alertTab`` - Details from the Alert tab for fonts etc - """ - style = u""" - width: %spx; - vertical-align: %s; - font-family: %s; - font-size: %spt; - color: %s; - background-color: %s; - """ - if not alertTab: - return u'' - align = VerticalType.Names[alertTab.location] - alert = style % (width, align, alertTab.font_face, alertTab.font_size, - alertTab.font_color, alertTab.bg_color) - return alert diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 02f6970ac..226e8b472 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -250,7 +250,12 @@ class Renderer(object): # render the first virtual slide. text_contains_break = u'[---]' in text if text_contains_break: - text_to_render, text = text.split(u'\n[---]\n', 1) + try: + text_to_render, text = \ + text.split(u'\n[---]\n', 1) + except: + text_to_render = text.split(u'\n[---]\n')[0] + text = u'' else: text_to_render = text text = u'' diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index 0eb0c866f..b12a27f1d 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -118,6 +118,7 @@ class ServiceItem(object): self.from_service = False self.image_border = u'#000000' self.background_audio = [] + self.theme_overwritten = False self._new_item() def _new_item(self): @@ -273,7 +274,8 @@ class ServiceItem(object): u'start_time': self.start_time, u'end_time': self.end_time, u'media_length': self.media_length, - u'background_audio': self.background_audio + u'background_audio': self.background_audio, + u'theme_overwritten': self.theme_overwritten } service_data = [] if self.service_item_type == ServiceItemType.Text: @@ -323,6 +325,7 @@ class ServiceItem(object): self.media_length = header[u'media_length'] if u'background_audio' in header: self.background_audio = header[u'background_audio'] + self.theme_overwritten = header.get(u'theme_overwritten', False) if self.service_item_type == ServiceItemType.Text: for slide in serviceitem[u'serviceitem'][u'data']: self._raw_frames.append(slide) @@ -484,6 +487,7 @@ class ServiceItem(object): ``theme`` The new theme to be replaced in the service item """ + self.theme_overwritten = (theme == None) self.theme = theme self._new_item() self.render() diff --git a/openlp/core/ui/__init__.py b/openlp/core/ui/__init__.py index 7d2dfa0ba..6a04a080b 100644 --- a/openlp/core/ui/__init__.py +++ b/openlp/core/ui/__init__.py @@ -52,6 +52,24 @@ class HideMode(object): Theme = 2 Screen = 3 +class AlertLocation(object): + """ + This is an enumeration class which controls where Alerts are placed on the + screen. + + ``Top`` + Place the text at the top of the screen. + + ``Middle`` + Place the text in the middle of the screen. + + ``Bottom`` + Place the text at the bottom of the screen. + """ + Top = 0 + Middle = 1 + Bottom = 2 + from firsttimeform import FirstTimeForm from firsttimelanguageform import FirstTimeLanguageForm from themelayoutform import ThemeLayoutForm diff --git a/openlp/core/ui/aboutdialog.py b/openlp/core/ui/aboutdialog.py index f4a732fb6..8216d3e7a 100644 --- a/openlp/core/ui/aboutdialog.py +++ b/openlp/core/ui/aboutdialog.py @@ -123,7 +123,7 @@ class Ui_AboutDialog(object): testers = [u'Philip "Phill" Ridout', u'Wesley "wrst" Stout', u'John "jseagull1" Cegalis (lead)'] packagers = ['Thomas "tabthorpe" Abthorpe (FreeBSD)', - u'Tim "TRB143" Bentley (Fedora)', + u'Tim "TRB143" Bentley (Fedora and Android)', u'Matthias "matthub" Hub (Mac OS X)', u'Stevan "ElderP" Pettit (Windows)', u'Raoul "superfly" Snyman (Ubuntu)'] diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py index c5fc678e2..0cda4bd60 100644 --- a/openlp/core/ui/exceptionform.py +++ b/openlp/core/ui/exceptionform.py @@ -39,6 +39,11 @@ try: PHONON_VERSION = Phonon.phononVersion() except ImportError: PHONON_VERSION = u'-' +try: + import migrate + MIGRATE_VERSION = getattr(migrate, u'__version__', u'< 0.7') +except ImportError: + MIGRATE_VERSION = u'-' try: import chardet CHARDET_VERSION = chardet.__version__ @@ -54,6 +59,24 @@ try: SQLITE_VERSION = sqlite.version except ImportError: SQLITE_VERSION = u'-' +try: + import mako + MAKO_VERSION = mako.__version__ +except ImportError: + MAKO_VERSION = u'-' +try: + import uno + arg = uno.createUnoStruct(u'com.sun.star.beans.PropertyValue') + arg.Name = u'nodepath' + arg.Value = u'/org.openoffice.Setup/Product' + context = uno.getComponentContext() + provider = context.ServiceManager.createInstance( + u'com.sun.star.configuration.ConfigurationProvider') + node = provider.createInstanceWithArguments( + u'com.sun.star.configuration.ConfigurationAccess', (arg,)) + UNO_VERSION = node.getByName(u'ooSetupVersion') +except ImportError: + UNO_VERSION = u'-' from openlp.core.lib import translate, SettingsManager from openlp.core.lib.ui import UiStrings @@ -89,11 +112,14 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog): u'Phonon: %s\n' % PHONON_VERSION + \ u'PyQt4: %s\n' % Qt.PYQT_VERSION_STR + \ u'SQLAlchemy: %s\n' % sqlalchemy.__version__ + \ + u'SQLAlchemy Migrate: %s\n' % MIGRATE_VERSION + \ u'BeautifulSoup: %s\n' % BeautifulSoup.__version__ + \ u'lxml: %s\n' % etree.__version__ + \ u'Chardet: %s\n' % CHARDET_VERSION + \ u'PyEnchant: %s\n' % ENCHANT_VERSION + \ - u'PySQLite: %s\n' % SQLITE_VERSION + u'PySQLite: %s\n' % SQLITE_VERSION + \ + u'Mako: %s\n' % MAKO_VERSION + \ + u'pyUNO bridge: %s\n' % UNO_VERSION if platform.system() == u'Linux': if os.environ.get(u'KDE_FULL_SESSION') == u'true': system = system + u'Desktop: KDE SC\n' @@ -152,6 +178,8 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog): 'Please add the information that bug reports are favoured written ' 'in English.')) content = self._createReport() + source = u'' + exception = u'' for line in content[2].split(u'\n'): if re.search(r'[/\\]openlp[/\\]', line): source = re.sub(r'.*[/\\]openlp[/\\](.*)".*', r'\1', line) diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index aa94454b7..2a16867e5 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -37,7 +37,7 @@ from PyQt4.phonon import Phonon from openlp.core.lib import Receiver, build_html, ServiceItem, image_to_byte, \ translate, PluginManager -from openlp.core.ui import HideMode, ScreenList +from openlp.core.ui import HideMode, ScreenList, AlertLocation log = logging.getLogger(__name__) @@ -51,7 +51,7 @@ class MainDisplay(QtGui.QGraphicsView): def __init__(self, parent, imageManager, live): if live: QtGui.QGraphicsView.__init__(self) - # Do not overwrite the parent() method. + # Overwrite the parent() method. self.parent = lambda: parent else: QtGui.QGraphicsView.__init__(self, parent) @@ -171,7 +171,7 @@ class MainDisplay(QtGui.QGraphicsView): serviceItem = ServiceItem() serviceItem.bg_image_bytes = image_to_byte(self.initialFrame) self.webView.setHtml(build_html(serviceItem, self.screen, - self.isLive, None)) + self.isLive, None, plugins=self.plugins)) self.__hideMouse() # To display or not to display? if not self.screen[u'primary']: @@ -213,7 +213,7 @@ class MainDisplay(QtGui.QGraphicsView): self.frame.evaluateJavaScript(u'show_text("%s")' % slide.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"')) - def alert(self, text): + def alert(self, text, location): """ Display an alert. @@ -241,10 +241,10 @@ class MainDisplay(QtGui.QGraphicsView): alert_height = int(height.toString()) shrinkItem.resize(self.width(), alert_height) shrinkItem.setVisible(True) - if self.alertTab.location == 1: + if location == AlertLocation.Middle: shrinkItem.move(self.screen[u'size'].left(), (self.screen[u'size'].height() - alert_height) / 2) - elif self.alertTab.location == 2: + elif location == AlertLocation.Bottom: shrinkItem.move(self.screen[u'size'].left(), self.screen[u'size'].height() - alert_height) else: diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 97c30436e..d871dc474 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -321,6 +321,94 @@ class SlideController(QtGui.QWidget): self.slidePreview.setObjectName(u'slidePreview') self.slideLayout.insertWidget(0, self.slidePreview) self.grid.addLayout(self.slideLayout, 0, 0, 1, 1) + if self.isLive: + self.current_shortcut = u'' + self.shortcutTimer = QtCore.QTimer() + self.shortcutTimer.setObjectName(u'shortcutTimer') + self.shortcutTimer.setSingleShot(True) + self.verseShortcut = shortcut_action(self, u'verseShortcut', + [QtGui.QKeySequence(u'V')], self.slideShortcutActivated, + category=UiStrings().LiveToolbar, + context=QtCore.Qt.WidgetWithChildrenShortcut) + self.verseShortcut.setText(translate( + 'OpenLP.SlideController', 'Go to "Verse"')) + self.shortcut0 = shortcut_action(self, u'0', + [QtGui.QKeySequence(u'0')], self.slideShortcutActivated, + context=QtCore.Qt.WidgetWithChildrenShortcut) + self.shortcut1 = shortcut_action(self, u'1', + [QtGui.QKeySequence(u'1')], self.slideShortcutActivated, + context=QtCore.Qt.WidgetWithChildrenShortcut) + self.shortcut2 = shortcut_action(self, u'2', + [QtGui.QKeySequence(u'2')], self.slideShortcutActivated, + context=QtCore.Qt.WidgetWithChildrenShortcut) + self.shortcut3 = shortcut_action(self, u'3', + [QtGui.QKeySequence(u'3')], self.slideShortcutActivated, + context=QtCore.Qt.WidgetWithChildrenShortcut) + self.shortcut4 = shortcut_action(self, u'4', + [QtGui.QKeySequence(u'4')], self.slideShortcutActivated, + context=QtCore.Qt.WidgetWithChildrenShortcut) + self.shortcut5 = shortcut_action(self, u'5', + [QtGui.QKeySequence(u'5')], self.slideShortcutActivated, + context=QtCore.Qt.WidgetWithChildrenShortcut) + self.shortcut6 = shortcut_action(self, u'6', + [QtGui.QKeySequence(u'6')], self.slideShortcutActivated, + context=QtCore.Qt.WidgetWithChildrenShortcut) + self.shortcut7 = shortcut_action(self, u'7', + [QtGui.QKeySequence(u'7')], self.slideShortcutActivated, + context=QtCore.Qt.WidgetWithChildrenShortcut) + self.shortcut8 = shortcut_action(self, u'8', + [QtGui.QKeySequence(u'8')], self.slideShortcutActivated, + context=QtCore.Qt.WidgetWithChildrenShortcut) + self.shortcut9 = shortcut_action(self, u'9', + [QtGui.QKeySequence(u'9')], self.slideShortcutActivated, + context=QtCore.Qt.WidgetWithChildrenShortcut) + self.chorusShortcut = shortcut_action(self, u'chorusShortcut', + [QtGui.QKeySequence(u'C')], self.slideShortcutActivated, + category=UiStrings().LiveToolbar, + context=QtCore.Qt.WidgetWithChildrenShortcut) + self.chorusShortcut.setText(translate( + 'OpenLP.SlideController', 'Go to "Chorus"')) + self.bridgeShortcut = shortcut_action(self, u'bridgeShortcut', + [QtGui.QKeySequence(u'B')], self.slideShortcutActivated, + category=UiStrings().LiveToolbar, + context=QtCore.Qt.WidgetWithChildrenShortcut) + self.bridgeShortcut.setText(translate( + 'OpenLP.SlideController', 'Go to "Bridge"')) + self.preChorusShortcut = shortcut_action(self, u'preChorusShortcut', + [QtGui.QKeySequence(u'P')], self.slideShortcutActivated, + category=UiStrings().LiveToolbar, + context=QtCore.Qt.WidgetWithChildrenShortcut) + self.preChorusShortcut.setText(translate( + 'OpenLP.SlideController', 'Go to "Pre-Chorus"')) + self.introShortcut = shortcut_action(self, u'introShortcut', + [QtGui.QKeySequence(u'I')], self.slideShortcutActivated, + category=UiStrings().LiveToolbar, + context=QtCore.Qt.WidgetWithChildrenShortcut) + self.introShortcut.setText(translate( + 'OpenLP.SlideController', 'Go to "Intro"')) + self.endingShortcut = shortcut_action(self, u'endingShortcut', + [QtGui.QKeySequence(u'E')], self.slideShortcutActivated, + category=UiStrings().LiveToolbar, + context=QtCore.Qt.WidgetWithChildrenShortcut) + self.endingShortcut.setText(translate( + 'OpenLP.SlideController', 'Go to "Ending"')) + self.otherShortcut = shortcut_action(self, u'otherShortcut', + [QtGui.QKeySequence(u'O')], self.slideShortcutActivated, + category=UiStrings().LiveToolbar, + context=QtCore.Qt.WidgetWithChildrenShortcut) + self.otherShortcut.setText(translate( + 'OpenLP.SlideController', 'Go to "Other"')) + self.previewListWidget.addActions([ + self.shortcut0, self.shortcut1, self.shortcut2, self.shortcut3, + self.shortcut4, self.shortcut5, self.shortcut6, self.shortcut7, + self.shortcut8, self.shortcut9, self.verseShortcut, + self.chorusShortcut, self.bridgeShortcut, + self.preChorusShortcut, self.introShortcut, self.endingShortcut, + self.otherShortcut + ]) + QtCore.QObject.connect( + self.shortcutTimer, QtCore.SIGNAL(u'timeout()'), + self.slideShortcutActivated) # Signals QtCore.QObject.connect(self.previewListWidget, QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSlideSelected) @@ -367,6 +455,90 @@ class SlideController(QtGui.QWidget): QtCore.SIGNAL(u'slidecontroller_%s_unblank' % self.typePrefix), self.onSlideUnblank) + def slideShortcutActivated(self): + """ + Called, when a shortcut has been activated to jump to a chorus, verse, + etc. + + **Note**: This implementation is based on shortcuts. But it rather works + like "key sequenes". You have to press one key after the other and + **not** at the same time. + For example to jump to "V3" you have to press "V" and afterwards but + within a time frame of 350ms you have to press "3". + """ + try: + from openlp.plugins.songs.lib import VerseType + SONGS_PLUGIN_AVAILABLE = True + except ImportError: + SONGS_PLUGIN_AVAILABLE = False + verse_type = unicode(self.sender().objectName()) + if verse_type.startswith(u'verseShortcut'): + if SONGS_PLUGIN_AVAILABLE: + self.current_shortcut = \ + VerseType.TranslatedTags[VerseType.Verse] + else: + self.current_shortcut = u'V' + elif verse_type.startswith(u'chorusShortcut'): + if SONGS_PLUGIN_AVAILABLE: + self.current_shortcut = \ + VerseType.TranslatedTags[VerseType.Chorus] + else: + self.current_shortcut = u'C' + elif verse_type.startswith(u'bridgeShortcut'): + if SONGS_PLUGIN_AVAILABLE: + self.current_shortcut = \ + VerseType.TranslatedTags[VerseType.Bridge] + else: + self.current_shortcut = u'B' + elif verse_type.startswith(u'preChorusShortcut'): + if SONGS_PLUGIN_AVAILABLE: + self.current_shortcut = \ + VerseType.TranslatedTags[VerseType.PreChorus] + else: + self.current_shortcut = u'P' + elif verse_type.startswith(u'introShortcut'): + if SONGS_PLUGIN_AVAILABLE: + self.current_shortcut = \ + VerseType.TranslatedTags[VerseType.Intro] + else: + self.current_shortcut = u'I' + elif verse_type.startswith(u'endingShortcut'): + if SONGS_PLUGIN_AVAILABLE: + self.current_shortcut = \ + VerseType.TranslatedTags[VerseType.Ending] + else: + self.current_shortcut = u'E' + elif verse_type.startswith(u'otherShortcut'): + if SONGS_PLUGIN_AVAILABLE: + self.current_shortcut = \ + VerseType.TranslatedTags[VerseType.Other] + else: + self.current_shortcut = u'O' + elif verse_type.isnumeric(): + self.current_shortcut += verse_type + self.current_shortcut = self.current_shortcut.upper() + keys = self.slideList.keys() + matches = [match for match in keys + if match.startswith(self.current_shortcut)] + if len(matches) == 1: + self.shortcutTimer.stop() + self.current_shortcut = u'' + self.__checkUpdateSelectedSlide(self.slideList[matches[0]]) + self.slideSelected() + elif verse_type != u'shortcutTimer': + # Start the time as we did not have any match. + self.shortcutTimer.start(350) + else: + # The timer timed out. + if self.current_shortcut in keys: + # We had more than one match for example "V1" and "V10", but + # "V1" was the slide we wanted to go. + self.__checkUpdateSelectedSlide( + self.slideList[self.current_shortcut]) + self.slideSelected() + # Reset the shortcut. + self.current_shortcut = u'' + def setPreviewHotkeys(self, parent=None): self.previousItem.setObjectName(u'previousItemPreview') self.nextItem.setObjectName(u'nextItemPreview') @@ -643,13 +815,14 @@ class SlideController(QtGui.QWidget): verse_def = u'%s%s' % (verse_def[0], verse_def[1:]) two_line_def = u'%s\n%s' % (verse_def[0], verse_def[1:]) row = two_line_def - if self.isLive: - if verse_def not in self.slideList: - self.slideList[verse_def] = framenumber + if verse_def not in self.slideList: + self.slideList[verse_def] = framenumber + if self.isLive: self.songMenu.menu().addAction(verse_def, self.onSongBarHandler) else: row += 1 + self.slideList[unicode(row)] = row - 1 item.setText(frame[u'text']) else: label = QtGui.QLabel() @@ -667,6 +840,7 @@ class SlideController(QtGui.QWidget): self.previewListWidget.setCellWidget(framenumber, 0, label) slideHeight = width * self.parent().renderer.screen_ratio row += 1 + self.slideList[unicode(row)] = row - 1 text.append(unicode(row)) self.previewListWidget.setItem(framenumber, 0, item) if slideHeight != 0: diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index b472ccef0..6fc2a7ea5 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -370,7 +370,7 @@ class ThemeManager(QtGui.QWidget): def onExportTheme(self): """ - Save the theme in a zip file + Export the theme in a zip file """ item = self.themeListWidget.currentItem() if item is None: @@ -625,7 +625,7 @@ class ThemeManager(QtGui.QWidget): theme_dir = os.path.join(self.path, name) check_directory_exists(theme_dir) theme_file = os.path.join(theme_dir, name + u'.xml') - if imageTo and self.oldBackgroundImage and \ + if self.oldBackgroundImage and \ imageTo != self.oldBackgroundImage: delete_file(self.oldBackgroundImage) outfile = None diff --git a/openlp/plugins/alerts/alertsplugin.py b/openlp/plugins/alerts/alertsplugin.py index 213c6814f..493f08ba0 100644 --- a/openlp/plugins/alerts/alertsplugin.py +++ b/openlp/plugins/alerts/alertsplugin.py @@ -71,11 +71,24 @@ JAVASCRIPT = """ function update_css(align, font, size, color, bgcolor){ var text = document.getElementById('alert'); - text.style.verticalAlign = align; text.style.fontSize = size + "pt"; text.style.fontFamily = font; text.style.color = color; text.style.backgroundColor = bgcolor; + switch(align) + { + case 'top': + text.style.top = '0px'; + break; + case 'middle': + text.style.top = ((window.innerHeight - text.clientHeight) / 2) + + 'px'; + break; + case 'bottom': + text.style.top = (window.innerHeight - text.clientHeight) + + 'px'; + break; + } } """ CSS = """ diff --git a/openlp/plugins/alerts/lib/alertsmanager.py b/openlp/plugins/alerts/lib/alertsmanager.py index 8e91aecf5..e73273fe7 100644 --- a/openlp/plugins/alerts/lib/alertsmanager.py +++ b/openlp/plugins/alerts/lib/alertsmanager.py @@ -85,7 +85,7 @@ class AlertsManager(QtCore.QObject): return text = self.alertList.pop(0) alertTab = self.parent().settings_tab - self.parent().liveController.display.alert(text) + self.parent().liveController.display.alert(text, alertTab.location) # Check to see if we have a timer running. if self.timer_id == 0: self.timer_id = self.startTimer(int(alertTab.timeout) * 1000) @@ -100,7 +100,8 @@ class AlertsManager(QtCore.QObject): """ log.debug(u'timer event') if event.timerId() == self.timer_id: - self.parent().liveController.display.alert(u'') + alertTab = self.parent().settings_tab + self.parent().liveController.display.alert(u'', alertTab.location) self.killTimer(self.timer_id) self.timer_id = 0 self.generateAlert() diff --git a/openlp/plugins/alerts/lib/alertstab.py b/openlp/plugins/alerts/lib/alertstab.py index 8720c5111..bd879fef3 100644 --- a/openlp/plugins/alerts/lib/alertstab.py +++ b/openlp/plugins/alerts/lib/alertstab.py @@ -28,6 +28,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import SettingsTab, translate, Receiver +from openlp.core.ui import AlertLocation from openlp.core.lib.ui import UiStrings, create_valign_combo class AlertsTab(SettingsTab): @@ -159,7 +160,7 @@ class AlertsTab(SettingsTab): self.font_face = unicode(settings.value( u'font face', QtCore.QVariant(QtGui.QFont().family())).toString()) self.location = settings.value( - u'location', QtCore.QVariant(1)).toInt()[0] + u'location', QtCore.QVariant(AlertLocation.Bottom)).toInt()[0] settings.endGroup() self.fontSizeSpinBox.setValue(self.font_size) self.timeoutSpinBox.setValue(self.timeout) diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py index 522c354b8..acbe103a7 100644 --- a/openlp/plugins/remotes/lib/httpserver.py +++ b/openlp/plugins/remotes/lib/httpserver.py @@ -411,7 +411,7 @@ class HttpConnection(object): ``action`` This is the action, either ``hide`` or ``show``. """ - event = u'maindisplay_%s' % action + event = u'live_display_%s' % action Receiver.send_message(event, HideMode.Blank) return HttpResponse(json.dumps({u'results': {u'success': True}}), {u'Content-Type': u'application/json'}) diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index d98a55c00..29f5d6a18 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -419,8 +419,7 @@ class SongMediaItem(MediaManagerItem): item_id = (self.editItem.data(QtCore.Qt.UserRole)).toInt()[0] old_song = self.plugin.manager.get_object(Song, item_id) song_xml = self.openLyrics.song_to_xml(old_song) - new_song_id = self.openLyrics.xml_to_song(song_xml) - new_song = self.plugin.manager.get_object(Song, new_song_id) + new_song = self.openLyrics.xml_to_song(song_xml) new_song.title = u'%s <%s>' % (new_song.title, translate('SongsPlugin.MediaItem', 'copy', 'For song cloning')) diff --git a/openlp/plugins/songs/lib/olp1import.py b/openlp/plugins/songs/lib/olp1import.py index 72bd5f952..fa43d94cf 100644 --- a/openlp/plugins/songs/lib/olp1import.py +++ b/openlp/plugins/songs/lib/olp1import.py @@ -78,30 +78,35 @@ class OpenLP1SongImport(SongImport): connection = sqlite.connect(self.importSource, mode=0444, encoding=(encoding, 'replace')) cursor = connection.cursor() - # Determine if we're using a new or an old DB. + # Determine if the db supports linking audio to songs. cursor.execute(u'SELECT name FROM sqlite_master ' u'WHERE type = \'table\' AND name = \'tracks\'') - new_db = len(cursor.fetchall()) > 0 + db_has_tracks = len(cursor.fetchall()) > 0 + # Determine if the db contains theme information. + cursor.execute(u'SELECT name FROM sqlite_master ' + u'WHERE type = \'table\' AND name = \'settings\'') + db_has_themes = len(cursor.fetchall()) > 0 # "cache" our list of authors. cursor.execute(u'-- types int, unicode') cursor.execute(u'SELECT authorid, authorname FROM authors') authors = cursor.fetchall() - if new_db: + if db_has_tracks: # "cache" our list of tracks. cursor.execute(u'-- types int, unicode') cursor.execute(u'SELECT trackid, fulltrackname FROM tracks') tracks = cursor.fetchall() - # "cache" our list of themes. - cursor.execute(u'-- types int, unicode') - cursor.execute(u'SELECT settingsid, settingsname FROM settings') - themes = {} - for theme_id, theme_name in cursor.fetchall(): - if theme_name in self.availableThemes: - themes[theme_id] = theme_name + if db_has_themes: + # "cache" our list of themes. + themes = {} + cursor.execute(u'-- types int, unicode') + cursor.execute(u'SELECT settingsid, settingsname FROM settings') + for theme_id, theme_name in cursor.fetchall(): + if theme_name in self.availableThemes: + themes[theme_id] = theme_name # Import the songs. - cursor.execute(u'-- types int, unicode, unicode, unicode, int') - cursor.execute(u'SELECT songid, songtitle, lyrics || \'\' AS lyrics, ' - u'copyrightinfo, settingsid FROM songs') + cursor.execute(u'-- types int, unicode, unicode, unicode') + cursor.execute(u'SELECT songid, songtitle, lyrics || \'\' AS ' \ + u'lyrics, copyrightinfo FROM songs') songs = cursor.fetchall() self.importWizard.progressBar.setMaximum(len(songs)) for song in songs: @@ -112,8 +117,13 @@ class OpenLP1SongImport(SongImport): self.title = song[1] lyrics = song[2].replace(u'\r\n', u'\n') self.addCopyright(song[3]) - if themes.has_key(song[4]): - self.themeName = themes[song[4]] + if db_has_themes: + cursor.execute(u'-- types int') + cursor.execute( + u'SELECT settingsid FROM songs WHERE songid = %s' % song_id) + theme_id = cursor.fetchone()[0] + if themes.has_key(theme_id): + self.themeName = themes[theme_id] verses = lyrics.split(u'\n\n') for verse in verses: if verse.strip(): @@ -131,7 +141,7 @@ class OpenLP1SongImport(SongImport): break if self.stopImportFlag: break - if new_db: + if db_has_tracks: cursor.execute(u'-- types int, int') cursor.execute(u'SELECT trackid, listindex ' u'FROM songtracks ' diff --git a/openlp/plugins/songs/lib/oooimport.py b/openlp/plugins/songs/lib/oooimport.py index 4a97e43b0..f817bfb45 100644 --- a/openlp/plugins/songs/lib/oooimport.py +++ b/openlp/plugins/songs/lib/oooimport.py @@ -65,7 +65,7 @@ class OooImport(SongImport): if not isinstance(self.importSource, list): return try: - self.start_ooo() + self.startOoo() except NoConnectException as exc: self.logError( self.importSource[0], @@ -145,7 +145,7 @@ class OooImport(SongImport): process.waitForStarted() self.processStarted = True except: - log.exception("start_ooo_process failed") + log.exception("startOooProcess failed") def openOooFile(self, filepath): """ @@ -171,7 +171,7 @@ class OooImport(SongImport): self.importWizard.incrementProgressBar( u'Processing file ' + filepath, 0) except AttributeError: - log.exception("open_ooo_file failed: %s", url) + log.exception("openOooFile failed: %s", url) return def closeOooFile(self): diff --git a/resources/windows/OpenLP-2.0.iss b/resources/windows/OpenLP-2.0.iss index 119b73900..9805787e5 100644 --- a/resources/windows/OpenLP-2.0.iss +++ b/resources/windows/OpenLP-2.0.iss @@ -67,7 +67,7 @@ Name: quicklaunchicon; Description: {cm:CreateQuickLaunchIcon}; GroupDescription Source: ..\..\dist\OpenLP\*; DestDir: {app}; Flags: ignoreversion recursesubdirs createallsubdirs ; DLL used to check if the target program is running at install time Source: psvince.dll; flags: dontcopy -; psvince is installed in {app} folder, so it will be loaded at +; psvince is installed in {app} folder, so it will be loaded at ; uninstall time to check if the target program is running Source: psvince.dll; DestDir: {app} @@ -84,10 +84,16 @@ Name: {userappdata}\Microsoft\Internet Explorer\Quick Launch\{#AppName}; Filenam Filename: {app}\{#AppExeName}; Description: {cm:LaunchProgram,{#AppName}}; Flags: nowait postinstall skipifsilent [Registry] -Root: HKCR; Subkey: ".osz"; ValueType: string; ValueName: ""; ValueData: "OpenLP"; Flags: uninsdeletevalue -Root: HKCR; Subkey: "OpenLP"; ValueType: string; ValueName: ""; ValueData: "OpenLP Service"; Flags: uninsdeletekey -Root: HKCR; Subkey: "OpenLP\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\OpenLP.exe,0" -Root: HKCR; Subkey: "OpenLP\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\OpenLP.exe"" ""%1""" +Root: HKCR; Subkey: .osz; ValueType: string; ValueName: ; ValueData: OpenLP; Flags: uninsdeletevalue +Root: HKCR; Subkey: OpenLP; ValueType: string; ValueName: ; ValueData: OpenLP Service; Flags: uninsdeletekey +Root: HKCR; Subkey: OpenLP\DefaultIcon; ValueType: string; ValueName: ; ValueData: {app}\OpenLP.exe,0 +Root: HKCR; Subkey: OpenLP\shell\open\command; ValueType: string; ValueName: ; ValueData: """{app}\OpenLP.exe"" ""%1""" + +[UninstallDelete] +; Remove support directory created when program is run: +Type: filesandordirs; Name: {app}\support +; Remove program directory if empty: +Name: {app}; Type: dirifempty [Code] // Function to call psvince.dll at install time @@ -173,4 +179,6 @@ begin Result := false; end; end; -end; \ No newline at end of file +// Unload psvince.dll, otherwise it is not deleted + UnloadDLL(ExpandConstant('{app}\psvince.dll')); +end; diff --git a/scripts/check_dependencies.py b/scripts/check_dependencies.py index dd2907ba9..d1ec2228b 100755 --- a/scripts/check_dependencies.py +++ b/scripts/check_dependencies.py @@ -73,6 +73,7 @@ MODULES = [ 'BeautifulSoup', 'mako', 'migrate', + 'uno', ] diff --git a/scripts/windows-builder.py b/scripts/windows-builder.py index b7bf70472..9076971cb 100644 --- a/scripts/windows-builder.py +++ b/scripts/windows-builder.py @@ -48,10 +48,10 @@ Inno Setup 5 Sphinx This is used to build the documentation. The documentation trunk must be at - the same directory level as Openlp trunk and named "documentation" + the same directory level as Openlp trunk and named "documentation". HTML Help Workshop - This is used to create the help file + This is used to create the help file. PyInstaller PyInstaller should be a checkout of revision 1470 of trunk, and in a @@ -65,10 +65,6 @@ PyInstaller http://svn.pyinstaller.org/trunk - Then you need to copy the two hook-*.py files from the "pyinstaller" - subdirectory in OpenLP's "resources" directory into PyInstaller's - "PyInstaller/hooks" directory. - Bazaar You need the command line "bzr" client installed. @@ -79,7 +75,7 @@ OpenLP Visual C++ 2008 Express Edition This is to build pptviewlib.dll, the library for controlling the - PowerPointViewer + PowerPointViewer. windows-builder.py This script, of course. It should be in the "scripts" directory of OpenLP. @@ -88,15 +84,25 @@ psvince.dll This dll is used during the actual install of OpenLP to check if OpenLP is running on the users machine prior to the setup. If OpenLP is running, the install will fail. The dll can be obtained from here: - http://www.vincenzo.net/isxkb/index.php?title=PSVince) + + http://www.vincenzo.net/isxkb/index.php?title=PSVince) + + The dll is presently included in .\\resources\\windows Mako Mako Templates for Python. This package is required for building the remote plugin. It can be installed by going to your python_directory\scripts\.. and running "easy_install Mako". If you do not have easy_install, the Mako package can be obtained here: - http://www.makotemplates.org/download.html - + + http://www.makotemplates.org/download.html + +Sqlalchemy Migrate + Required for the data-bases used in OpenLP. The package can be + obtained here: + + http://code.google.com/p/sqlalchemy-migrate/ + """ import os @@ -149,6 +155,7 @@ build_path = os.path.join(branch_path, u'build') dist_path = os.path.join(branch_path, u'dist', u'OpenLP') pptviewlib_path = os.path.join(source_path, u'plugins', u'presentations', u'lib', u'pptviewlib') +hooks_path = os.path.join(branch_path , u'resources', u'pyinstaller') def update_code(): os.chdir(branch_path) @@ -173,7 +180,8 @@ def run_pyinstaller(): pyinstaller = Popen((python_exe, pyi_build, u'--noconfirm', u'--windowed', - u'--noupx', + u'--noupx', + u'--additional-hooks-dir', hooks_path, u'-o', branch_path, u'-i', win32_icon, u'-p', branch_path,