This commit is contained in:
Jonathan Corwin 2010-09-08 21:37:12 +01:00
commit 327370ef39
27 changed files with 690 additions and 266 deletions

View File

@ -29,12 +29,14 @@ import os
import sys import sys
import logging import logging
from optparse import OptionParser from optparse import OptionParser
from traceback import format_exception
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver from openlp.core.lib import Receiver
from openlp.core.resources import qInitResources from openlp.core.resources import qInitResources
from openlp.core.ui.mainwindow import MainWindow from openlp.core.ui.mainwindow import MainWindow
from openlp.core.ui.exceptionform import ExceptionForm
from openlp.core.ui import SplashScreen, ScreenList from openlp.core.ui import SplashScreen, ScreenList
from openlp.core.utils import AppLocation, LanguageManager, VersionThread from openlp.core.utils import AppLocation, LanguageManager, VersionThread
@ -144,6 +146,13 @@ class OpenLP(QtGui.QApplication):
VersionThread(self.mainWindow, app_version).start() VersionThread(self.mainWindow, app_version).start()
return self.exec_() return self.exec_()
def hookException(self, exctype, value, traceback):
if not hasattr(self, u'exceptionForm'):
self.exceptionForm = ExceptionForm(self.mainWindow)
self.exceptionForm.exceptionTextEdit.setPlainText(
''.join(format_exception(exctype, value, traceback)))
self.exceptionForm.exec_()
def main(): def main():
""" """
The main function which parses command line options and then runs The main function which parses command line options and then runs
@ -194,7 +203,7 @@ def main():
language = LanguageManager.get_language() language = LanguageManager.get_language()
appTranslator = LanguageManager.get_translator(language) appTranslator = LanguageManager.get_translator(language)
app.installTranslator(appTranslator) app.installTranslator(appTranslator)
sys.excepthook = app.hookException
sys.exit(app.run()) sys.exit(app.run())
if __name__ == u'__main__': if __name__ == u'__main__':

View File

@ -145,6 +145,7 @@ body {
} }
document.getElementById('black').style.display = black; document.getElementById('black').style.display = black;
document.getElementById('lyricsmain').style.visibility = lyrics; document.getElementById('lyricsmain').style.visibility = lyrics;
document.getElementById('image').style.visibility = lyrics;
outline = document.getElementById('lyricsoutline') outline = document.getElementById('lyricsoutline')
if(outline!=null) if(outline!=null)
outline.style.visibility = lyrics; outline.style.visibility = lyrics;
@ -370,7 +371,7 @@ def build_lyrics_css(item, webkitvers):
lyricsmain = u'' lyricsmain = u''
outline = u'' outline = u''
shadow = u'' shadow = u''
if theme: if theme and item.main:
lyricstable = u'left: %spx; top: %spx;' % \ lyricstable = u'left: %spx; top: %spx;' % \
(item.main.x(), item.main.y()) (item.main.x(), item.main.y())
lyrics = build_lyrics_format_css(theme, item.main.width(), lyrics = build_lyrics_format_css(theme, item.main.width(),
@ -520,7 +521,7 @@ def build_footer_css(item):
text-align: %s; text-align: %s;
""" """
theme = item.themedata theme = item.themedata
if not theme: if not theme or not item.footer:
return u'' return u''
if theme.display_horizontalAlign == 2: if theme.display_horizontalAlign == 2:
align = u'center' align = u'center'

View File

@ -70,21 +70,11 @@ class Renderer(object):
self.theme_name = theme.theme_name self.theme_name = theme.theme_name
if theme.background_type == u'image': if theme.background_type == u'image':
if theme.background_filename: if theme.background_filename:
self.set_bg_image(theme.background_filename) self._bg_image_filename = unicode(theme.background_filename)
if self.frame:
def set_bg_image(self, filename): self.bg_image = resize_image(self._bg_image_filename,
""" self.frame.width(),
Set a background image. self.frame.height())
``filename``
The name of the image file.
"""
log.debug(u'set bg image %s', filename)
self._bg_image_filename = unicode(filename)
if self.frame:
self.bg_image = resize_image(self._bg_image_filename,
self.frame.width(),
self.frame.height())
def set_text_rectangle(self, rect_main, rect_footer): def set_text_rectangle(self, rect_main, rect_footer):
""" """
@ -100,7 +90,7 @@ class Renderer(object):
self._rect = rect_main self._rect = rect_main
self._rect_footer = rect_footer self._rect_footer = rect_footer
def set_frame_dest(self, frame_width, frame_height, preview=False): def set_frame_dest(self, frame_width, frame_height):
""" """
Set the size of the slide. Set the size of the slide.
@ -110,11 +100,7 @@ class Renderer(object):
``frame_height`` ``frame_height``
The height of the slide. The height of the slide.
``preview``
Defaults to *False*. Whether or not to generate a preview.
""" """
if preview:
self.bg_frame = None
log.debug(u'set frame dest (frame) w %d h %d', frame_width, log.debug(u'set frame dest (frame) w %d h %d', frame_width,
frame_height) frame_height)
self.frame = QtGui.QImage(frame_width, frame_height, self.frame = QtGui.QImage(frame_width, frame_height,
@ -122,8 +108,17 @@ class Renderer(object):
if self._bg_image_filename and not self.bg_image: if self._bg_image_filename and not self.bg_image:
self.bg_image = resize_image(self._bg_image_filename, self.bg_image = resize_image(self._bg_image_filename,
self.frame.width(), self.frame.height()) self.frame.width(), self.frame.height())
if self.bg_frame is None: if self._theme.background_type == u'image':
self._generate_background_frame() self.bg_frame = QtGui.QImage(self.frame.width(),
self.frame.height(), QtGui.QImage.Format_ARGB32_Premultiplied)
painter = QtGui.QPainter()
painter.begin(self.bg_frame)
painter.fillRect(self.frame.rect(), QtCore.Qt.black)
if self.bg_image:
painter.drawImage(0, 0, self.bg_image)
painter.end()
else:
self.bg_frame = None
def format_slide(self, words, line_break): def format_slide(self, words, line_break):
""" """
@ -174,57 +169,3 @@ class Renderer(object):
formatted.append(html_text) formatted.append(html_text)
log.debug(u'format_slide - End') log.debug(u'format_slide - End')
return formatted return formatted
def _generate_background_frame(self):
"""
Generate a background frame to the same size as the frame to be used.
Results are cached for performance reasons.
"""
assert(self._theme)
self.bg_frame = QtGui.QImage(self.frame.width(),
self.frame.height(), QtGui.QImage.Format_ARGB32_Premultiplied)
log.debug(u'render background %s start', self._theme.background_type)
if self._theme.background_type == u'solid':
self.bg_frame = None
# painter.fillRect(self.frame.rect(),
# QtGui.QColor(self._theme.background_color))
elif self._theme.background_type == u'gradient':
self.bg_frame = None
# gradient
# gradient = None
# if self._theme.background_direction == u'horizontal':
# w = int(self.frame.width()) / 2
# # vertical
# gradient = QtGui.QLinearGradient(w, 0, w, self.frame.height())
# elif self._theme.background_direction == u'vertical':
# h = int(self.frame.height()) / 2
# # Horizontal
# gradient = QtGui.QLinearGradient(0, h, self.frame.width(), h)
# else:
# w = int(self.frame.width()) / 2
# h = int(self.frame.height()) / 2
# # Circular
# gradient = QtGui.QRadialGradient(w, h, w)
# gradient.setColorAt(0,
# QtGui.QColor(self._theme.background_startColor))
# gradient.setColorAt(1,
# QtGui.QColor(self._theme.background_endColor))
# painter.setBrush(QtGui.QBrush(gradient))
# rect_path = QtGui.QPainterPath()
# max_x = self.frame.width()
# max_y = self.frame.height()
# rect_path.moveTo(0, 0)
# rect_path.lineTo(0, max_y)
# rect_path.lineTo(max_x, max_y)
# rect_path.lineTo(max_x, 0)
# rect_path.closeSubpath()
# painter.drawPath(rect_path)
# painter.end()
elif self._theme.background_type == u'image':
# image
painter = QtGui.QPainter()
painter.begin(self.bg_frame)
painter.fillRect(self.frame.rect(), QtCore.Qt.black)
if self.bg_image:
painter.drawImage(0, 0, self.bg_image)
painter.end()

View File

@ -93,6 +93,8 @@ class RenderManager(object):
""" """
self.global_theme = global_theme self.global_theme = global_theme
self.theme_level = theme_level self.theme_level = theme_level
self.global_theme_data = \
self.theme_manager.getThemeData(self.global_theme)
self.themedata = None self.themedata = None
def set_service_theme(self, service_theme): def set_service_theme(self, service_theme):

View File

@ -170,6 +170,7 @@ class ServiceItem(object):
u'verseTag': slide[u'verseTag'] }) u'verseTag': slide[u'verseTag'] })
log.log(15, u'Formatting took %4s' % (time.time() - before)) log.log(15, u'Formatting took %4s' % (time.time() - before))
elif self.service_item_type == ServiceItemType.Image: elif self.service_item_type == ServiceItemType.Image:
self.themedata = self.render_manager.global_theme_data
for slide in self._raw_frames: for slide in self._raw_frames:
slide[u'image'] = resize_image(slide[u'image'], slide[u'image'] = resize_image(slide[u'image'],
self.render_manager.width, self.render_manager.height) self.render_manager.width, self.render_manager.height)

View File

@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2010 Raoul Snyman #
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
# Carsten Tinggaard, 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 translate
class Ui_ExceptionDialog(object):
def setupUi(self, exceptionDialog):
exceptionDialog.setObjectName(u'exceptionDialog')
exceptionDialog.resize(580, 407)
self.exceptionLayout = QtGui.QVBoxLayout(exceptionDialog)
self.exceptionLayout.setSpacing(8)
self.exceptionLayout.setMargin(8)
self.exceptionLayout.setObjectName(u'exceptionLayout')
self.messageLayout = QtGui.QHBoxLayout()
self.messageLayout.setSpacing(0)
self.messageLayout.setContentsMargins(0, -1, 0, -1)
self.messageLayout.setObjectName(u'messageLayout')
self.bugLabel = QtGui.QLabel(exceptionDialog)
self.bugLabel.setMinimumSize(QtCore.QSize(64, 64))
self.bugLabel.setMaximumSize(QtCore.QSize(64, 64))
self.bugLabel.setText(u'')
self.bugLabel.setPixmap(QtGui.QPixmap(u':/graphics/exception.png'))
self.bugLabel.setAlignment(QtCore.Qt.AlignCenter)
self.bugLabel.setObjectName(u'bugLabel')
self.messageLayout.addWidget(self.bugLabel)
self.messageLabel = QtGui.QLabel(exceptionDialog)
self.messageLabel.setWordWrap(True)
self.messageLabel.setObjectName(u'messageLabel')
self.messageLayout.addWidget(self.messageLabel)
self.exceptionLayout.addLayout(self.messageLayout)
self.exceptionTextEdit = QtGui.QPlainTextEdit(exceptionDialog)
self.exceptionTextEdit.setReadOnly(True)
self.exceptionTextEdit.setBackgroundVisible(False)
self.exceptionTextEdit.setObjectName(u'exceptionTextEdit')
self.exceptionLayout.addWidget(self.exceptionTextEdit)
self.exceptionButtonBox = QtGui.QDialogButtonBox(exceptionDialog)
self.exceptionButtonBox.setOrientation(QtCore.Qt.Horizontal)
self.exceptionButtonBox.setStandardButtons(QtGui.QDialogButtonBox.Close)
self.exceptionButtonBox.setObjectName(u'exceptionButtonBox')
self.exceptionLayout.addWidget(self.exceptionButtonBox)
self.retranslateUi(exceptionDialog)
QtCore.QObject.connect(self.exceptionButtonBox,
QtCore.SIGNAL(u'accepted()'), exceptionDialog.accept)
QtCore.QObject.connect(self.exceptionButtonBox,
QtCore.SIGNAL(u'rejected()'), exceptionDialog.reject)
QtCore.QMetaObject.connectSlotsByName(exceptionDialog)
def retranslateUi(self, exceptionDialog):
exceptionDialog.setWindowTitle(
translate('OpenLP.ExceptionDialog', 'Error Occured'))
self.messageLabel.setText(translate('OpenLP.ExceptionDialog', 'Oops! '
'OpenLP hit a problem, and couldn\'t recover. The text in the box '
'below contains information that might be helpful to the OpenLP '
'developers, so please e-mail it to bugs@openlp.org, along with a '
'detailed description of what you were doing when the problem '
'occurred.'))

View File

@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2010 Raoul Snyman #
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
# Carsten Tinggaard, 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 exceptiondialog import Ui_ExceptionDialog
from openlp.core.lib import translate
class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
"""
The exception dialog
"""
def __init__(self, parent):
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)

View File

@ -195,6 +195,19 @@ class GeneralTab(SettingsTab):
self.currentYValueLabel.setObjectName(u'currentYValueLabel') self.currentYValueLabel.setObjectName(u'currentYValueLabel')
self.currentYLayout.addWidget(self.currentYValueLabel) self.currentYLayout.addWidget(self.currentYValueLabel)
self.currentLayout.addLayout(self.currentYLayout) self.currentLayout.addLayout(self.currentYLayout)
self.currentWidthLayout = QtGui.QVBoxLayout()
self.currentWidthLayout.setSpacing(0)
self.currentWidthLayout.setMargin(0)
self.currentWidthLayout.setObjectName(u'currentWidthLayout')
self.currentWidthLabel = QtGui.QLabel(self.displayGroupBox)
self.currentWidthLabel.setAlignment(QtCore.Qt.AlignCenter)
self.currentWidthLabel.setObjectName(u'currentWidthLabel')
self.currentWidthLayout.addWidget(self.currentWidthLabel)
self.currentWidthValueLabel = QtGui.QLabel(self.displayGroupBox)
self.currentWidthValueLabel.setAlignment(QtCore.Qt.AlignCenter)
self.currentWidthValueLabel.setObjectName(u'currentWidthValueLabel')
self.currentWidthLayout.addWidget(self.currentWidthValueLabel)
self.currentLayout.addLayout(self.currentWidthLayout)
self.currentHeightLayout = QtGui.QVBoxLayout() self.currentHeightLayout = QtGui.QVBoxLayout()
self.currentHeightLayout.setSpacing(0) self.currentHeightLayout.setSpacing(0)
self.currentHeightLayout.setMargin(0) self.currentHeightLayout.setMargin(0)
@ -209,19 +222,6 @@ class GeneralTab(SettingsTab):
self.currentHeightValueLabel.setObjectName(u'Height') self.currentHeightValueLabel.setObjectName(u'Height')
self.currentHeightLayout.addWidget(self.currentHeightValueLabel) self.currentHeightLayout.addWidget(self.currentHeightValueLabel)
self.currentLayout.addLayout(self.currentHeightLayout) self.currentLayout.addLayout(self.currentHeightLayout)
self.currentWidthLayout = QtGui.QVBoxLayout()
self.currentWidthLayout.setSpacing(0)
self.currentWidthLayout.setMargin(0)
self.currentWidthLayout.setObjectName(u'currentWidthLayout')
self.currentWidthLabel = QtGui.QLabel(self.displayGroupBox)
self.currentWidthLabel.setAlignment(QtCore.Qt.AlignCenter)
self.currentWidthLabel.setObjectName(u'currentWidthLabel')
self.currentWidthLayout.addWidget(self.currentWidthLabel)
self.currentWidthValueLabel = QtGui.QLabel(self.displayGroupBox)
self.currentWidthValueLabel.setAlignment(QtCore.Qt.AlignCenter)
self.currentWidthValueLabel.setObjectName(u'currentWidthValueLabel')
self.currentWidthLayout.addWidget(self.currentWidthValueLabel)
self.currentLayout.addLayout(self.currentWidthLayout)
self.displayLayout.addLayout(self.currentLayout) self.displayLayout.addLayout(self.currentLayout)
self.overrideCheckBox = QtGui.QCheckBox(self.displayGroupBox) self.overrideCheckBox = QtGui.QCheckBox(self.displayGroupBox)
self.overrideCheckBox.setObjectName(u'overrideCheckBox') self.overrideCheckBox.setObjectName(u'overrideCheckBox')
@ -256,18 +256,6 @@ class GeneralTab(SettingsTab):
self.customYValueEdit.setObjectName(u'customYValueEdit') self.customYValueEdit.setObjectName(u'customYValueEdit')
self.customYLayout.addWidget(self.customYValueEdit) self.customYLayout.addWidget(self.customYValueEdit)
self.customLayout.addLayout(self.customYLayout) self.customLayout.addLayout(self.customYLayout)
self.customHeightLayout = QtGui.QVBoxLayout()
self.customHeightLayout.setSpacing(0)
self.customHeightLayout.setMargin(0)
self.customHeightLayout.setObjectName(u'customHeightLayout')
self.customHeightLabel = QtGui.QLabel(self.displayGroupBox)
self.customHeightLabel.setAlignment(QtCore.Qt.AlignCenter)
self.customHeightLabel.setObjectName(u'customHeightLabel')
self.customHeightLayout.addWidget(self.customHeightLabel)
self.customHeightValueEdit = QtGui.QLineEdit(self.displayGroupBox)
self.customHeightValueEdit.setObjectName(u'customHeightValueEdit')
self.customHeightLayout.addWidget(self.customHeightValueEdit)
self.customLayout.addLayout(self.customHeightLayout)
self.customWidthLayout = QtGui.QVBoxLayout() self.customWidthLayout = QtGui.QVBoxLayout()
self.customWidthLayout.setSpacing(0) self.customWidthLayout.setSpacing(0)
self.customWidthLayout.setMargin(0) self.customWidthLayout.setMargin(0)
@ -281,6 +269,18 @@ class GeneralTab(SettingsTab):
self.customWidthValueEdit.setObjectName(u'customWidthValueEdit') self.customWidthValueEdit.setObjectName(u'customWidthValueEdit')
self.customWidthLayout.addWidget(self.customWidthValueEdit) self.customWidthLayout.addWidget(self.customWidthValueEdit)
self.customLayout.addLayout(self.customWidthLayout) self.customLayout.addLayout(self.customWidthLayout)
self.customHeightLayout = QtGui.QVBoxLayout()
self.customHeightLayout.setSpacing(0)
self.customHeightLayout.setMargin(0)
self.customHeightLayout.setObjectName(u'customHeightLayout')
self.customHeightLabel = QtGui.QLabel(self.displayGroupBox)
self.customHeightLabel.setAlignment(QtCore.Qt.AlignCenter)
self.customHeightLabel.setObjectName(u'customHeightLabel')
self.customHeightLayout.addWidget(self.customHeightLabel)
self.customHeightValueEdit = QtGui.QLineEdit(self.displayGroupBox)
self.customHeightValueEdit.setObjectName(u'customHeightValueEdit')
self.customHeightLayout.addWidget(self.customHeightValueEdit)
self.customLayout.addLayout(self.customHeightLayout)
self.displayLayout.addLayout(self.customLayout) self.displayLayout.addLayout(self.customLayout)
# Bottom spacer # Bottom spacer
self.generalRightSpacer = QtGui.QSpacerItem(20, 40, self.generalRightSpacer = QtGui.QSpacerItem(20, 40,
@ -476,7 +476,6 @@ class GeneralTab(SettingsTab):
# Order is important so be careful if you change # Order is important so be careful if you change
if self.overrideChanged or postUpdate: if self.overrideChanged or postUpdate:
Receiver.send_message(u'config_screen_changed') Receiver.send_message(u'config_screen_changed')
Receiver.send_message(u'config_updated')
self.overrideChanged = False self.overrideChanged = False
def onOverrideCheckBoxToggled(self, checked): def onOverrideCheckBoxToggled(self, checked):

View File

@ -97,6 +97,7 @@ class MainDisplay(DisplayWidget):
self.screens = screens self.screens = screens
self.isLive = live self.isLive = live
self.alertTab = None self.alertTab = None
self.hide_mode = None
self.setWindowTitle(u'OpenLP Display') self.setWindowTitle(u'OpenLP Display')
self.setWindowFlags(QtCore.Qt.FramelessWindowHint | self.setWindowFlags(QtCore.Qt.FramelessWindowHint |
QtCore.Qt.WindowStaysOnTopHint) QtCore.Qt.WindowStaysOnTopHint)
@ -340,6 +341,9 @@ class MainDisplay(DisplayWidget):
self.webView.setHtml(html) self.webView.setHtml(html)
if serviceItem.foot_text and serviceItem.foot_text: if serviceItem.foot_text and serviceItem.foot_text:
self.footer(serviceItem.foot_text) self.footer(serviceItem.foot_text)
# if was hidden keep it hidden
if self.hide_mode and self.isLive:
self.hideDisplay(self.hide_mode)
def footer(self, text): def footer(self, text):
""" """
@ -365,6 +369,7 @@ class MainDisplay(DisplayWidget):
self.frame.evaluateJavaScript(u'show_blank("theme");') self.frame.evaluateJavaScript(u'show_blank("theme");')
if mode != HideMode.Screen and self.isHidden(): if mode != HideMode.Screen and self.isHidden():
self.setVisible(True) self.setVisible(True)
self.hide_mode = mode
def showDisplay(self): def showDisplay(self):
""" """
@ -378,6 +383,7 @@ class MainDisplay(DisplayWidget):
self.setVisible(True) self.setVisible(True)
# Trigger actions when display is active again # Trigger actions when display is active again
Receiver.send_message(u'maindisplay_active') Receiver.send_message(u'maindisplay_active')
self.hide_mode = None
class AudioPlayer(QtCore.QObject): class AudioPlayer(QtCore.QObject):
""" """

View File

@ -93,7 +93,6 @@ class Ui_PluginViewDialog(object):
self.pluginListButtonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok) self.pluginListButtonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok)
self.pluginListButtonBox.setObjectName(u'pluginListButtonBox') self.pluginListButtonBox.setObjectName(u'pluginListButtonBox')
self.pluginLayout.addWidget(self.pluginListButtonBox) self.pluginLayout.addWidget(self.pluginListButtonBox)
self.retranslateUi(pluginViewDialog) self.retranslateUi(pluginViewDialog)
QtCore.QObject.connect(self.pluginListButtonBox, QtCore.QObject.connect(self.pluginListButtonBox,
QtCore.SIGNAL(u'accepted()'), pluginViewDialog.close) QtCore.SIGNAL(u'accepted()'), pluginViewDialog.close)

View File

@ -134,5 +134,6 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
elif self.activePlugin.status == PluginStatus.Disabled: elif self.activePlugin.status == PluginStatus.Disabled:
status_text = unicode( status_text = unicode(
translate('OpenLP.PluginForm', '%s (Disabled)')) translate('OpenLP.PluginForm', '%s (Disabled)'))
self.pluginListWidget.currentItem().setText( if self.pluginListWidget.currentItem():
status_text % self.activePlugin.name) self.pluginListWidget.currentItem().setText(
status_text % self.activePlugin.name)

View File

@ -30,6 +30,7 @@ import logging
from PyQt4 import QtGui from PyQt4 import QtGui
from openlp.core.lib import Receiver
from openlp.core.ui import AdvancedTab, GeneralTab, ThemesTab from openlp.core.ui import AdvancedTab, GeneralTab, ThemesTab
from settingsdialog import Ui_SettingsDialog from settingsdialog import Ui_SettingsDialog
@ -87,6 +88,8 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
""" """
for tabIndex in range(0, self.settingsTabWidget.count()): for tabIndex in range(0, self.settingsTabWidget.count()):
self.settingsTabWidget.widget(tabIndex).save() self.settingsTabWidget.widget(tabIndex).save()
# Must go after all settings are save
Receiver.send_message(u'config_updated')
return QtGui.QDialog.accept(self) return QtGui.QDialog.accept(self)
def postSetUp(self): def postSetUp(self):

View File

@ -162,11 +162,6 @@ class SlideController(QtGui.QWidget):
sizeToolbarPolicy.setHeightForWidth( sizeToolbarPolicy.setHeightForWidth(
self.Toolbar.sizePolicy().hasHeightForWidth()) self.Toolbar.sizePolicy().hasHeightForWidth())
self.Toolbar.setSizePolicy(sizeToolbarPolicy) self.Toolbar.setSizePolicy(sizeToolbarPolicy)
# if self.isLive:
# self.Toolbar.addToolbarButton(
# u'First Slide', u':/slides/slide_first.png',
# translate('OpenLP.SlideController', 'Move to first'),
# self.onSlideSelectedFirst)
self.Toolbar.addToolbarButton( self.Toolbar.addToolbarButton(
u'Previous Slide', u':/slides/slide_previous.png', u'Previous Slide', u':/slides/slide_previous.png',
translate('OpenLP.SlideController', 'Move to previous'), translate('OpenLP.SlideController', 'Move to previous'),
@ -175,11 +170,6 @@ class SlideController(QtGui.QWidget):
u'Next Slide', u':/slides/slide_next.png', u'Next Slide', u':/slides/slide_next.png',
translate('OpenLP.SlideController', 'Move to next'), translate('OpenLP.SlideController', 'Move to next'),
self.onSlideSelectedNext) self.onSlideSelectedNext)
# if self.isLive:
# self.Toolbar.addToolbarButton(
# u'Last Slide', u':/slides/slide_last.png',
# translate('OpenLP.SlideController', 'Move to last'),
# self.onSlideSelectedLast)
if self.isLive: if self.isLive:
self.Toolbar.addToolbarSeparator(u'Close Separator') self.Toolbar.addToolbarSeparator(u'Close Separator')
self.HideMenu = QtGui.QToolButton(self.Toolbar) self.HideMenu = QtGui.QToolButton(self.Toolbar)
@ -279,11 +269,11 @@ class SlideController(QtGui.QWidget):
if isLive: if isLive:
self.SongMenu = QtGui.QToolButton(self.Toolbar) self.SongMenu = QtGui.QToolButton(self.Toolbar)
self.SongMenu.setText(translate('OpenLP.SlideController', self.SongMenu.setText(translate('OpenLP.SlideController',
'Go to Verse')) 'Go to'))
self.SongMenu.setPopupMode(QtGui.QToolButton.InstantPopup) self.SongMenu.setPopupMode(QtGui.QToolButton.InstantPopup)
self.Toolbar.addToolbarWidget(u'Song Menu', self.SongMenu) self.Toolbar.addToolbarWidget(u'Song Menu', self.SongMenu)
self.SongMenu.setMenu(QtGui.QMenu( self.SongMenu.setMenu(QtGui.QMenu(
translate('OpenLP.SlideController', 'Go to Verse'), translate('OpenLP.SlideController', 'Go to'),
self.Toolbar)) self.Toolbar))
self.Toolbar.makeWidgetsInvisible([u'Song Menu']) self.Toolbar.makeWidgetsInvisible([u'Song Menu'])
# Screen preview area # Screen preview area

View File

@ -196,10 +196,10 @@ class BiblesTab(SettingsTab):
self.show_new_chapters = True self.show_new_chapters = True
def onBibleDualCheckBox(self, check_state): def onBibleDualCheckBox(self, check_state):
self.duel_bibles = False self.dual_bibles = False
# we have a set value convert to True/False # we have a set value convert to True/False
if check_state == QtCore.Qt.Checked: if check_state == QtCore.Qt.Checked:
self.duel_bibles = True self.dual_bibles = True
def load(self): def load(self):
settings = QtCore.QSettings() settings = QtCore.QSettings()
@ -212,12 +212,12 @@ class BiblesTab(SettingsTab):
u'verse layout style', QtCore.QVariant(0)).toInt()[0] u'verse layout style', QtCore.QVariant(0)).toInt()[0]
self.bible_theme = unicode( self.bible_theme = unicode(
settings.value(u'bible theme', QtCore.QVariant(u'')).toString()) settings.value(u'bible theme', QtCore.QVariant(u'')).toString())
self.duel_bibles = settings.value( self.dual_bibles = settings.value(
u'dual bibles', QtCore.QVariant(True)).toBool() u'dual bibles', QtCore.QVariant(True)).toBool()
self.NewChaptersCheckBox.setChecked(self.show_new_chapters) self.NewChaptersCheckBox.setChecked(self.show_new_chapters)
self.DisplayStyleComboBox.setCurrentIndex(self.display_style) self.DisplayStyleComboBox.setCurrentIndex(self.display_style)
self.LayoutStyleComboBox.setCurrentIndex(self.layout_style) self.LayoutStyleComboBox.setCurrentIndex(self.layout_style)
self.BibleDualCheckBox.setChecked(self.duel_bibles) self.BibleDualCheckBox.setChecked(self.dual_bibles)
settings.endGroup() settings.endGroup()
def save(self): def save(self):
@ -229,7 +229,7 @@ class BiblesTab(SettingsTab):
QtCore.QVariant(self.display_style)) QtCore.QVariant(self.display_style))
settings.setValue(u'verse layout style', settings.setValue(u'verse layout style',
QtCore.QVariant(self.layout_style)) QtCore.QVariant(self.layout_style))
settings.setValue(u'dual bibles', QtCore.QVariant(self.duel_bibles)) settings.setValue(u'dual bibles', QtCore.QVariant(self.dual_bibles))
settings.setValue(u'bible theme', QtCore.QVariant(self.bible_theme)) settings.setValue(u'bible theme', QtCore.QVariant(self.bible_theme))
settings.endGroup() settings.endGroup()

View File

@ -275,8 +275,9 @@ class BibleMediaItem(MediaManagerItem):
self.SearchProgress.setObjectName(u'SearchProgress') self.SearchProgress.setObjectName(u'SearchProgress')
def configUpdated(self): def configUpdated(self):
log.debug(u'configUpdated')
if QtCore.QSettings().value(self.settingsSection + u'/dual bibles', if QtCore.QSettings().value(self.settingsSection + u'/dual bibles',
QtCore.QVariant(False)).toBool(): QtCore.QVariant(True)).toBool():
self.AdvancedSecondBibleLabel.setVisible(True) self.AdvancedSecondBibleLabel.setVisible(True)
self.AdvancedSecondBibleComboBox.setVisible(True) self.AdvancedSecondBibleComboBox.setVisible(True)
self.QuickSecondVersionLabel.setVisible(True) self.QuickSecondVersionLabel.setVisible(True)

View File

@ -274,7 +274,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
item = self.VerseListWidget.item(row, 0) item = self.VerseListWidget.item(row, 0)
data = unicode(item.data(QtCore.Qt.UserRole).toString()) data = unicode(item.data(QtCore.Qt.UserRole).toString())
bit = data.split(u':') bit = data.split(u':')
rowTag = u'%s\n%s' % (bit[0][0:1], bit[1]) rowTag = u'%s%s' % (bit[0][0:1], bit[1])
rowLabel.append(rowTag) rowLabel.append(rowTag)
self.VerseListWidget.setVerticalHeaderLabels(rowLabel) self.VerseListWidget.setVerticalHeaderLabels(rowLabel)
@ -395,9 +395,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.VerseDeleteButton.setEnabled(True) self.VerseDeleteButton.setEnabled(True)
def onVerseAddButtonClicked(self): def onVerseAddButtonClicked(self):
# Allow insert button as you do not know if multiple verses will self.verse_form.setVerse(u'', True)
# be entered.
self.verse_form.setVerse(u'')
if self.verse_form.exec_(): if self.verse_form.exec_():
afterText, verse, subVerse = self.verse_form.getVerse() afterText, verse, subVerse = self.verse_form.getVerse()
data = u'%s:%s' % (verse, subVerse) data = u'%s:%s' % (verse, subVerse)

View File

@ -31,7 +31,6 @@ from PyQt4 import QtCore, QtGui
from songimportwizard import Ui_SongImportWizard from songimportwizard import Ui_SongImportWizard
from openlp.core.lib import Receiver, SettingsManager, translate from openlp.core.lib import Receiver, SettingsManager, translate
#from openlp.core.utils import AppLocation
from openlp.plugins.songs.lib.importer import SongFormat from openlp.plugins.songs.lib.importer import SongFormat
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -136,7 +135,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
self.openLP2BrowseButton.setFocus() self.openLP2BrowseButton.setFocus()
return False return False
elif source_format == SongFormat.OpenLP1: elif source_format == SongFormat.OpenLP1:
if self.openSongFilenameEdit.text().isEmpty(): if self.openLP1FilenameEdit.text().isEmpty():
QtGui.QMessageBox.critical(self, QtGui.QMessageBox.critical(self,
translate('SongsPlugin.ImportWizardForm', translate('SongsPlugin.ImportWizardForm',
'No openlp.org 1.x Song Database Selected'), 'No openlp.org 1.x Song Database Selected'),
@ -374,11 +373,11 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard):
importer = self.plugin.importSongs(SongFormat.OpenLP2, importer = self.plugin.importSongs(SongFormat.OpenLP2,
filename=unicode(self.openLP2FilenameEdit.text()) filename=unicode(self.openLP2FilenameEdit.text())
) )
#elif source_format == SongFormat.OpenLP1: elif source_format == SongFormat.OpenLP1:
# # Import an openlp.org database # Import an openlp.org database
# importer = self.plugin.importSongs(SongFormat.OpenLP1, importer = self.plugin.importSongs(SongFormat.OpenLP1,
# filename=unicode(self.field(u'openlp1_filename').toString()) filename=unicode(self.openLP1FilenameEdit.text())
# ) )
elif source_format == SongFormat.OpenLyrics: elif source_format == SongFormat.OpenLyrics:
# Import OpenLyrics songs # Import OpenLyrics songs
importer = self.plugin.importSongs(SongFormat.OpenLyrics, importer = self.plugin.importSongs(SongFormat.OpenLyrics,

View File

@ -26,6 +26,7 @@
from opensongimport import OpenSongImport from opensongimport import OpenSongImport
from olpimport import OpenLPSongImport from olpimport import OpenLPSongImport
from olp1import import OpenLP1SongImport
try: try:
from sofimport import SofImport from sofimport import SofImport
from oooimport import OooImport from oooimport import OooImport
@ -61,6 +62,8 @@ class SongFormat(object):
""" """
if format == SongFormat.OpenLP2: if format == SongFormat.OpenLP2:
return OpenLPSongImport return OpenLPSongImport
if format == SongFormat.OpenLP1:
return OpenLP1SongImport
elif format == SongFormat.OpenSong: elif format == SongFormat.OpenSong:
return OpenSongImport return OpenSongImport
elif format == SongFormat.SongsOfFellowship: elif format == SongFormat.SongsOfFellowship:

View File

@ -359,16 +359,13 @@ class SongMediaItem(MediaManagerItem):
author_list = author_list + u', ' author_list = author_list + u', '
author_list = author_list + unicode(author.display_name) author_list = author_list + unicode(author.display_name)
author_audit.append(unicode(author.display_name)) author_audit.append(unicode(author.display_name))
if song.ccli_number is None or len(song.ccli_number) == 0:
ccli = QtCore.QSettings().value(u'general/ccli number',
QtCore.QVariant(u'')).toString()
else:
ccli = unicode(song.ccli_number)
raw_footer.append(song.title) raw_footer.append(song.title)
raw_footer.append(author_list) raw_footer.append(author_list)
raw_footer.append(song.copyright ) raw_footer.append(song.copyright )
raw_footer.append(unicode( raw_footer.append(unicode(
translate('SongsPlugin.MediaItem', 'CCLI Licence: ') + ccli)) translate('SongsPlugin.MediaItem', 'CCLI Licence: ') +
QtCore.QSettings().value(u'general/ccli number',
QtCore.QVariant(u'')).toString()))
service_item.raw_footer = raw_footer service_item.raw_footer = raw_footer
service_item.audit = [ service_item.audit = [
song.title, author_audit, song.copyright, unicode(song.ccli_number) song.title, author_audit, song.copyright, unicode(song.ccli_number)

View File

@ -0,0 +1,129 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2010 Raoul Snyman #
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
# Carsten Tinggaard, 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:`olp1import` module provides the functionality for importing
openlp.org 1.x song databases into the current installation database.
"""
import logging
try:
import sqlite
except:
pass
from openlp.core.lib import translate
from songimport import SongImport
log = logging.getLogger(__name__)
class OpenLP1SongImport(SongImport):
"""
The :class:`OpenLP1SongImport` class provides OpenLP with the ability to
import song databases from installations of openlp.org 1.x.
"""
def __init__(self, manager, **kwargs):
"""
Initialise the import.
``manager``
The song manager for the running OpenLP installation.
``filename``
The database providing the data to import.
"""
SongImport.__init__(self, manager)
self.import_source = kwargs[u'filename']
def do_import(self):
"""
Run the import for an openlp.org 1.x song database.
"""
# Connect to the database
connection = sqlite.connect(self.import_source)
cursor = connection.cursor()
# Count the number of records we need to import, for the progress bar
cursor.execute(u'SELECT COUNT(songid) FROM songs')
count = int(cursor.fetchone()[0])
success = True
self.import_wizard.importProgressBar.setMaximum(count)
# "cache" our list of authors
cursor.execute(u'SELECT authorid, authorname FROM authors')
authors = cursor.fetchall()
# "cache" our list of tracks
cursor.execute(u'SELECT trackid, fulltrackname FROM tracks')
tracks = cursor.fetchall()
# Import the songs
cursor.execute(u'SELECT songid, songtitle, lyrics || \'\' AS lyrics, '
u'copyrightinfo FROM songs')
songs = cursor.fetchall()
for song in songs:
self.set_defaults()
if self.stop_import_flag:
success = False
break
song_id = song[0]
title = unicode(song[1], u'cp1252')
lyrics = unicode(song[2], u'cp1252').replace(u'\r', u'')
copyright = unicode(song[3], u'cp1252')
self.import_wizard.incrementProgressBar(
unicode(translate('SongsPlugin.ImportWizardForm',
'Importing "%s"...')) % title)
self.title = title
self.process_song_text(lyrics)
self.add_copyright(copyright)
cursor.execute(u'SELECT authorid FROM songauthors '
u'WHERE songid = %s' % song_id)
author_ids = cursor.fetchall()
for author_id in author_ids:
if self.stop_import_flag:
success = False
break
for author in authors:
if author[0] == author_id[0]:
self.parse_author(unicode(author[1], u'cp1252'))
break
if self.stop_import_flag:
success = False
break
cursor.execute(u'SELECT name FROM sqlite_master '
u'WHERE type = \'table\' AND name = \'tracks\'')
table_list = cursor.fetchall()
if len(table_list) > 0:
cursor.execute(u'SELECT trackid FROM songtracks '
u'WHERE songid = %s ORDER BY listindex' % song_id)
track_ids = cursor.fetchall()
for track_id in track_ids:
if self.stop_import_flag:
success = False
break
for track in tracks:
if track[0] == track_id[0]:
self.add_media_file(unicode(track[1], u'cp1252'))
break
if self.stop_import_flag:
success = False
break
self.finish()
return success

View File

@ -28,6 +28,7 @@ import os
from PyQt4 import QtCore from PyQt4 import QtCore
from openlp.core.lib import Receiver
from songimport import SongImport from songimport import SongImport
if os.name == u'nt': if os.name == u'nt':
@ -43,23 +44,32 @@ else:
except ImportError: except ImportError:
pass pass
class OooImport(object): class OooImport(SongImport):
""" """
Import songs from Impress/Powerpoint docs using Impress Import songs from Impress/Powerpoint docs using Impress
""" """
def __init__(self, songmanager): def __init__(self, master_manager, **kwargs):
""" """
Initialise the class. Requires a songmanager class which is passed Initialise the class. Requires a songmanager class which is passed
to SongImport for writing song to disk to SongImport for writing song to disk
""" """
SongImport.__init__(self, master_manager)
self.song = None self.song = None
self.manager = songmanager self.master_manager = master_manager
self.document = None self.document = None
self.process_started = False self.process_started = False
self.filenames = kwargs[u'filenames']
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'song_stop_import'), self.stop_import)
def import_docs(self, filenames): def do_import(self):
self.abort = False
self.import_wizard.importProgressBar.setMaximum(0)
self.start_ooo() self.start_ooo()
for filename in filenames: for filename in self.filenames:
if self.abort:
self.import_wizard.incrementProgressBar(u'Import cancelled', 0)
return
filename = unicode(filename) filename = unicode(filename)
if os.path.isfile(filename): if os.path.isfile(filename):
self.open_ooo_file(filename) self.open_ooo_file(filename)
@ -72,6 +82,12 @@ class OooImport(object):
self.process_doc() self.process_doc()
self.close_ooo_file() self.close_ooo_file()
self.close_ooo() self.close_ooo()
self.import_wizard.importProgressBar.setMaximum(1)
self.import_wizard.incrementProgressBar(u'', 1)
return True
def stop_import(self):
self.abort = True
def start_ooo(self): def start_ooo(self):
""" """
@ -135,6 +151,9 @@ class OooImport(object):
"com.sun.star.presentation.PresentationDocument") and not \ "com.sun.star.presentation.PresentationDocument") and not \
self.document.supportsService("com.sun.star.text.TextDocument"): self.document.supportsService("com.sun.star.text.TextDocument"):
self.close_ooo_file() self.close_ooo_file()
else:
self.import_wizard.incrementProgressBar(
u'Processing file ' + filepath, 0)
except: except:
pass pass
return return
@ -161,6 +180,9 @@ class OooImport(object):
slides = doc.getDrawPages() slides = doc.getDrawPages()
text = u'' text = u''
for slide_no in range(slides.getCount()): for slide_no in range(slides.getCount()):
if self.abort:
self.import_wizard.incrementProgressBar(u'Import cancelled', 0)
return
slide = slides.getByIndex(slide_no) slide = slides.getByIndex(slide_no)
slidetext = u'' slidetext = u''
for idx in range(slide.getCount()): for idx in range(slide.getCount()):

View File

@ -28,6 +28,7 @@ import logging
import os import os
from zipfile import ZipFile from zipfile import ZipFile
from lxml import objectify from lxml import objectify
from lxml.etree import Error, LxmlError
from openlp.plugins.songs.lib.songimport import SongImport from openlp.plugins.songs.lib.songimport import SongImport
@ -36,119 +37,163 @@ log = logging.getLogger(__name__)
class OpenSongImportError(Exception): class OpenSongImportError(Exception):
pass pass
class OpenSongImport(object): class OpenSongImport(SongImport):
""" """
Import songs exported from OpenSong - the format is described loosly here: Import songs exported from OpenSong
http://www.opensong.org/d/manual/song_file_format_specification
However, it doesn't describe the <lyrics> section, so here's an attempt: The format is described loosly on the `OpenSong File Format Specification
<http://www.opensong.org/d/manual/song_file_format_specification>`_ page on
the OpenSong web site. However, it doesn't describe the <lyrics> section,
so here's an attempt:
Verses can be expressed in one of 2 ways: Verses can be expressed in one of 2 ways, either in complete verses, or by
<lyrics> line grouping, i.e. grouping all line 1's of a verse together, all line 2's
[v1]List of words of a verse together, and so on.
Another Line
[v2]Some words for the 2nd verse An example of complete verses::
etc...
</lyrics>
The 'v' can be left out - it is implied <lyrics>
or: [v1]
<lyrics> List of words
[V] Another Line
1List of words
2Some words for the 2nd Verse
1Another Line [v2]
2etc... Some words for the 2nd verse
</lyrics> etc...
</lyrics>
Either or both forms can be used in one song. The Number does not The 'v' in the verse specifiers above can be left out, it is implied.
necessarily appear at the start of the line
An example of line grouping::
<lyrics>
[V]
1List of words
2Some words for the 2nd Verse
1Another Line
2etc...
</lyrics>
Either or both forms can be used in one song. The number does not
necessarily appear at the start of the line. Additionally, the [v1] labels
can have either upper or lower case Vs.
The [v1] labels can have either upper or lower case Vs
Other labels can be used also: Other labels can be used also:
C - Chorus
B - Bridge
Guitar chords can be provided 'above' the lyrics (the line is C
preceeded by a'.') and _s can be used to signify long-drawn-out Chorus
words:
. A7 Bm B
1 Some____ Words Bridge
Chords and _s are removed by this importer. All verses are imported and tagged appropriately.
The verses etc. are imported and tagged appropriately. Guitar chords can be provided "above" the lyrics (the line is preceeded by
a period "."), and one or more "_" can be used to signify long-drawn-out
words. Chords and "_" are removed by this importer. For example::
The <presentation> tag is used to populate the OpenLP verse . A7 Bm
display order field. The Author and Copyright tags are also 1 Some____ Words
imported to the appropriate places.
The <presentation> tag is used to populate the OpenLP verse display order
field. The Author and Copyright tags are also imported to the appropriate
places.
""" """
def __init__(self, songmanager): def __init__(self, manager, **kwargs):
""" """
Initialise the class. Requires a songmanager class which Initialise the class.
is passed to SongImport for writing song to disk
""" """
self.songmanager = songmanager SongImport.__init__(self, manager)
self.filenames = kwargs[u'filenames']
self.song = None self.song = None
self.commit = True
def do_import(self, filename, commit=True): def do_import(self):
""" """
Import either a single opensong file, or a zipfile Import either a single opensong file, or a zipfile containing multiple
containing multiple opensong files If the commit parameter is opensong files. If `self.commit` is set False, the import will not be
set False, the import will not be committed to the database committed to the database (useful for test scripts).
(useful for test scripts)
""" """
ext = os.path.splitext(filename)[1] success = True
if ext.lower() == ".zip": self.import_wizard.importProgressBar.setMaximum(len(self.filenames))
log.info('Zipfile found %s', filename) for filename in self.filenames:
z = ZipFile(filename, u'r') if self.stop_import_flag:
for song in z.infolist(): success = False
parts = os.path.split(song.filename) break
if parts[-1] == u'': ext = os.path.splitext(filename)[1]
#No final part => directory if ext.lower() == u'.zip':
continue log.debug(u'Zipfile found %s', filename)
songfile = z.open(song) z = ZipFile(filename, u'r')
self.do_import_file(songfile) self.import_wizard.importProgressBar.setMaximum(
if commit: self.import_wizard.importProgressBar.maximum() +
len(z.infolist()))
for song in z.infolist():
if self.stop_import_flag:
success = False
break
parts = os.path.split(song.filename)
if parts[-1] == u'':
#No final part => directory
continue
self.import_wizard.incrementProgressBar(
unicode(translate('SongsPlugin.ImportWizardForm',
'Importing %s...')) % parts[-1])
songfile = z.open(song)
self.do_import_file(songfile)
if self.commit:
self.finish()
self.set_defaults()
if self.stop_import_flag:
success = False
break
else:
log.info('Direct import %s', filename)
self.import_wizard.incrementProgressBar(
unicode(translate('SongsPlugin.ImportWizardForm',
'Importing %s...')) % os.path.split(filename)[-1])
file = open(filename)
self.do_import_file(file)
if self.commit:
self.finish() self.finish()
else: self.set_defaults()
log.info('Direct import %s', filename) if not self.commit:
file = open(filename) self.finish()
self.do_import_file(file) return success
if commit:
self.finish()
def do_import_file(self, file): def do_import_file(self, file):
""" """
Process the OpenSong file - pass in a file-like object, Process the OpenSong file - pass in a file-like object,
not a filename not a filename
""" """
self.song_import = SongImport(self.songmanager) self.authors = []
tree = objectify.parse(file) try:
tree = objectify.parse(file)
except Error, LxmlError:
log.exception(u'Error parsing XML')
return
root = tree.getroot() root = tree.getroot()
fields = dir(root) fields = dir(root)
decode = {u'copyright':self.song_import.add_copyright, decode = {
u'ccli':u'ccli_number', u'copyright': self.add_copyright,
u'author':self.song_import.parse_author, u'ccli': u'ccli_number',
u'title':u'title', u'author': self.parse_author,
u'aka':u'alternate_title', u'title': u'title',
u'hymn_number':u'song_number'} u'aka': u'alternate_title',
for (attr, fn_or_string) in decode.items(): u'hymn_number': u'song_number'
}
for attr, fn_or_string in decode.items():
if attr in fields: if attr in fields:
ustring = unicode(root.__getattr__(attr)) ustring = unicode(root.__getattr__(attr))
if type(fn_or_string) == type(u''): if isinstance(fn_or_string, basestring):
self.song_import.__setattr__(fn_or_string, ustring) setattr(self, fn_or_string, ustring)
else: else:
fn_or_string(ustring) fn_or_string(ustring)
if u'theme' in fields: if u'theme' in fields and unicode(root.theme) not in self.topics:
self.song_import.topics.append(unicode(root.theme)) self.topics.append(unicode(root.theme))
if u'alttheme' in fields: if u'alttheme' in fields and unicode(root.alttheme) not in self.topics:
self.song_import.topics.append(unicode(root.alttheme)) self.topics.append(unicode(root.alttheme))
# data storage while importing # data storage while importing
verses = {} verses = {}
lyrics = unicode(root.lyrics) lyrics = unicode(root.lyrics)
@ -158,6 +203,7 @@ class OpenSongImport(object):
# in the absence of any other indication, verses are the default, # in the absence of any other indication, verses are the default,
# erm, versetype! # erm, versetype!
versetype = u'V' versetype = u'V'
versenum = None
for thisline in lyrics.split(u'\n'): for thisline in lyrics.split(u'\n'):
# remove comments # remove comments
semicolon = thisline.find(u';') semicolon = thisline.find(u';')
@ -170,7 +216,6 @@ class OpenSongImport(object):
if thisline[0] == u'.' or thisline.startswith(u'---') \ if thisline[0] == u'.' or thisline.startswith(u'---') \
or thisline.startswith(u'-!!'): or thisline.startswith(u'-!!'):
continue continue
# verse/chorus/etc. marker # verse/chorus/etc. marker
if thisline[0] == u'[': if thisline[0] == u'[':
versetype = thisline[1].upper() versetype = thisline[1].upper()
@ -186,7 +231,6 @@ class OpenSongImport(object):
versenum = u'1' versenum = u'1'
continue continue
words = None words = None
# number at start of line.. it's verse number # number at start of line.. it's verse number
if thisline[0].isdigit(): if thisline[0].isdigit():
versenum = thisline[0] versenum = thisline[0]
@ -207,7 +251,7 @@ class OpenSongImport(object):
our_verse_order.append(versetag) our_verse_order.append(versetag)
if words: if words:
# Tidy text and remove the ____s from extended words # Tidy text and remove the ____s from extended words
words = self.song_import.tidy_text(words) words = self.tidy_text(words)
words = words.replace('_', '') words = words.replace('_', '')
verses[versetype][versenum].append(words) verses[versetype][versenum].append(words)
# done parsing # done parsing
@ -220,24 +264,23 @@ class OpenSongImport(object):
for num in versenums: for num in versenums:
versetag = u'%s%s' % (versetype, num) versetag = u'%s%s' % (versetype, num)
lines = u'\n'.join(verses[versetype][num]) lines = u'\n'.join(verses[versetype][num])
self.song_import.verses.append([versetag, lines]) self.verses.append([versetag, lines])
# Keep track of what we have for error checking later # Keep track of what we have for error checking later
versetags[versetag] = 1 versetags[versetag] = 1
# now figure out the presentation order # now figure out the presentation order
order = []
if u'presentation' in fields and root.presentation != u'': if u'presentation' in fields and root.presentation != u'':
order = unicode(root.presentation) order = unicode(root.presentation)
order = order.split() order = order.split()
else: else:
assert len(our_verse_order)>0 if len(our_verse_order) > 0:
order = our_verse_order order = our_verse_order
else:
log.warn(u'No verse order available for %s, skipping.', self.title)
for tag in order: for tag in order:
if len(tag) == 1: if len(tag) == 1:
tag = tag + u'1' # Assume it's no.1 if it's not there tag = tag + u'1' # Assume it's no.1 if it's not there
if not versetags.has_key(tag): if not versetags.has_key(tag):
log.warn(u'Got order %s but not in versetags, skipping', tag) log.warn(u'Got order %s but not in versetags, skipping', tag)
else: else:
self.song_import.verse_order_list.append(tag) self.verse_order_list.append(tag)
def finish(self):
""" Separate function, allows test suite to not pollute database"""
self.song_import.finish()

View File

@ -68,19 +68,30 @@ class SofImport(OooImport):
It attempts to detect italiced verses, and treats these as choruses in It attempts to detect italiced verses, and treats these as choruses in
the verse ordering. Again not perfect, but a start. the verse ordering. Again not perfect, but a start.
""" """
def __init__(self, songmanager): def __init__(self, master_manager, **kwargs):
""" """
Initialise the class. Requires a songmanager class which is passed Initialise the class. Requires a songmanager class which is passed
to SongImport for writing song to disk to SongImport for writing song to disk
""" """
OooImport.__init__(self, songmanager) OooImport.__init__(self, master_manager, **kwargs)
def import_sof(self, filename): def do_import(self):
self.abort = False
self.start_ooo() self.start_ooo()
self.open_ooo_file(filename) for filename in self.filenames:
self.process_sof_file() if self.abort:
self.close_ooo_file() self.import_wizard.incrementProgressBar(u'Import cancelled', 0)
return
filename = unicode(filename)
if os.path.isfile(filename):
self.open_ooo_file(filename)
if self.document:
self.process_sof_file()
self.close_ooo_file()
self.close_ooo() self.close_ooo()
self.import_wizard.importProgressBar.setMaximum(1)
self.import_wizard.incrementProgressBar(u'', 1)
return True
def process_sof_file(self): def process_sof_file(self):
""" """
@ -90,6 +101,9 @@ class SofImport(OooImport):
self.new_song() self.new_song()
paragraphs = self.document.getText().createEnumeration() paragraphs = self.document.getText().createEnumeration()
while paragraphs.hasMoreElements(): while paragraphs.hasMoreElements():
if self.abort:
self.import_wizard.incrementProgressBar(u'Import cancelled', 0)
return
paragraph = paragraphs.nextElement() paragraph = paragraphs.nextElement()
if paragraph.supportsService("com.sun.star.text.Paragraph"): if paragraph.supportsService("com.sun.star.text.Paragraph"):
self.process_paragraph(paragraph) self.process_paragraph(paragraph)
@ -244,6 +258,7 @@ class SofImport(OooImport):
if title.endswith(u','): if title.endswith(u','):
title = title[:-1] title = title[:-1]
self.song.title = title self.song.title = title
self.import_wizard.incrementProgressBar(u'Processing song ' + title, 0)
def add_author(self, text): def add_author(self, text):
""" """

View File

@ -30,7 +30,7 @@ from PyQt4 import QtCore
from openlp.core.lib import Receiver, translate from openlp.core.lib import Receiver, translate
from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib.db import Song, Author, Topic, Book from openlp.plugins.songs.lib.db import Song, Author, Topic, Book, MediaFile
from openlp.plugins.songs.lib.xml import SongXMLBuilder from openlp.plugins.songs.lib.xml import SongXMLBuilder
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -66,6 +66,7 @@ class SongImport(QtCore.QObject):
self.ccli_number = u'' self.ccli_number = u''
self.authors = [] self.authors = []
self.topics = [] self.topics = []
self.media_files = []
self.song_book_name = u'' self.song_book_name = u''
self.song_book_pub = u'' self.song_book_pub = u''
self.verse_order_list = [] self.verse_order_list = []
@ -129,13 +130,13 @@ class SongImport(QtCore.QObject):
def process_verse_text(self, text): def process_verse_text(self, text):
lines = text.split(u'\n') lines = text.split(u'\n')
if text.lower().find(COPYRIGHT_STRING) >= 0 \ if text.lower().find(self.copyright_string) >= 0 \
or text.lower().find(COPYRIGHT_SYMBOL) >= 0: or text.lower().find(self.copyright_symbol) >= 0:
copyright_found = False copyright_found = False
for line in lines: for line in lines:
if (copyright_found or if (copyright_found or
line.lower().find(COPYRIGHT_STRING) >= 0 or line.lower().find(self.copyright_string) >= 0 or
line.lower().find(COPYRIGHT_SYMBOL) >= 0): line.lower().find(self.copyright_symbol) >= 0):
copyright_found = True copyright_found = True
self.add_copyright(line) self.add_copyright(line)
else: else:
@ -184,6 +185,14 @@ class SongImport(QtCore.QObject):
return return
self.authors.append(author) self.authors.append(author)
def add_media_file(self, filename):
"""
Add a media file to the list
"""
if filename in self.media_files:
return
self.media_files.append(filename)
def add_verse(self, verse, versetag=None): def add_verse(self, verse, versetag=None):
""" """
Add a verse. This is the whole verse, lines split by \n Add a verse. This is the whole verse, lines split by \n
@ -279,11 +288,16 @@ class SongImport(QtCore.QObject):
for authortext in self.authors: for authortext in self.authors:
author = self.manager.get_object_filtered(Author, author = self.manager.get_object_filtered(Author,
Author.display_name == authortext) Author.display_name == authortext)
if author is None: if not author:
author = Author.populate(display_name = authortext, author = Author.populate(display_name = authortext,
last_name=authortext.split(u' ')[-1], last_name=authortext.split(u' ')[-1],
first_name=u' '.join(authortext.split(u' ')[:-1])) first_name=u' '.join(authortext.split(u' ')[:-1]))
song.authors.append(author) song.authors.append(author)
for filename in self.media_files:
media_file = self.manager.get_object_filtered(MediaFile,
MediaFile.file_name == filename)
if not media_file:
song.media_files.append(MediaFile.populate(file_name=filename))
if self.song_book_name: if self.song_book_name:
song_book = self.manager.get_object_filtered(Book, song_book = self.manager.get_object_filtered(Book,
Book.name == self.song_book_name) Book.name == self.song_book_name)
@ -300,7 +314,7 @@ class SongImport(QtCore.QObject):
topic = Topic.populate(name=topictext) topic = Topic.populate(name=topictext)
song.topics.append(topic) song.topics.append(topic)
self.manager.save_object(song) self.manager.save_object(song)
self.setDefaults() self.set_defaults()
def print_song(self): def print_song(self):
""" """

View File

@ -0,0 +1,130 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ExceptionDialog</class>
<widget class="QDialog" name="ExceptionDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>580</width>
<height>407</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="exceptionLayout">
<property name="spacing">
<number>8</number>
</property>
<property name="margin">
<number>8</number>
</property>
<item>
<layout class="QHBoxLayout" name="messageLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="bugLabel">
<property name="minimumSize">
<size>
<width>64</width>
<height>64</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>64</width>
<height>64</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../images/openlp-2.qrc">:/graphics/exception.png</pixmap>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="messageLabel">
<property name="text">
<string>Oops! OpenLP hit a problem, and couldn't recover. The text in the box below contains information that might be helpful to the OpenLP developers, so please e-mail it to bugs@openlp.org, along with a detailed description of what you were doing when the problem occurred.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPlainTextEdit" name="exceptionTextEdit">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="backgroundVisible">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="exceptionButtonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../images/openlp-2.qrc"/>
</resources>
<connections>
<connection>
<sender>exceptionButtonBox</sender>
<signal>accepted()</signal>
<receiver>ExceptionDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>exceptionButtonBox</sender>
<signal>rejected()</signal>
<receiver>ExceptionDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -62,6 +62,7 @@
<file>openlp-logo-256x256.png</file> <file>openlp-logo-256x256.png</file>
</qresource> </qresource>
<qresource prefix="graphics"> <qresource prefix="graphics">
<file>exception.png</file>
<file>openlp-about-logo.png</file> <file>openlp-about-logo.png</file>
<file>openlp-splash-screen.png</file> <file>openlp-splash-screen.png</file>
</qresource> </qresource>