This commit is contained in:
Andreas Preikschat 2011-02-18 15:50:06 +01:00
commit e0b1b003df
39 changed files with 702 additions and 186 deletions

View File

@ -239,7 +239,8 @@ def resize_image(image, width, height, background=QtCore.Qt.black):
Resize an image to fit on the current screen. Resize an image to fit on the current screen.
``image`` ``image``
The image to resize. The image to resize. It has to be either a ``QImage`` instance or the
path to the image.
``width`` ``width``
The new image width. The new image width.

View File

@ -85,8 +85,7 @@ class ImageManager(QtCore.QObject):
for key in self._cache.keys(): for key in self._cache.keys():
image = self._cache[key] image = self._cache[key]
image.dirty = True image.dirty = True
image.image = resize_image(image.path, image.image = resize_image(image.path, self.width, self.height)
self.width, self.height)
self._cache_dirty = True self._cache_dirty = True
# only one thread please # only one thread please
if not self._thread_running: if not self._thread_running:
@ -128,8 +127,7 @@ class ImageManager(QtCore.QObject):
image = Image() image = Image()
image.name = name image.name = name
image.path = path image.path = path
image.image = resize_image(path, image.image = resize_image(path, self.width, self.height)
self.width, self.height)
self._cache[name] = image self._cache[name] = image
else: else:
log.debug(u'Image in cache %s:%s' % (name, path)) log.debug(u'Image in cache %s:%s' % (name, path))

View File

@ -252,7 +252,6 @@ class MediaManagerItem(QtGui.QWidget):
self.pageLayout.addWidget(self.listView) self.pageLayout.addWidget(self.listView)
# define and add the context menu # define and add the context menu
self.listView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) self.listView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
name_string = self.plugin.getString(StringContent.Name)
if self.hasEditIcon: if self.hasEditIcon:
self.listView.addAction( self.listView.addAction(
context_menu_action( context_menu_action(

View File

@ -335,37 +335,39 @@ class Plugin(QtCore.QObject):
""" """
return self.textStrings[name] return self.textStrings[name]
def setPluginTextStrings(self): def setPluginUiTextStrings(self, tooltips):
""" """
Called to define all translatable texts of the plugin Called to define all translatable texts of the plugin
""" """
## Load Action ## ## Load Action ##
self._setSingularTextString(StringContent.Load, self.__setNameTextString(StringContent.Load,
UiStrings.Load, UiStrings.LoadANew) UiStrings.Load, tooltips[u'load'])
## Import Action ##
self.__setNameTextString(StringContent.Import,
UiStrings.Import, tooltips[u'import'])
## New Action ## ## New Action ##
self._setSingularTextString(StringContent.New, self.__setNameTextString(StringContent.New,
UiStrings.Add, UiStrings.AddANew) UiStrings.Add, tooltips[u'new'])
## Edit Action ## ## Edit Action ##
self._setSingularTextString(StringContent.Edit, self.__setNameTextString(StringContent.Edit,
UiStrings.Edit, UiStrings.EditSelect) UiStrings.Edit, tooltips[u'edit'])
## Delete Action ## ## Delete Action ##
self._setSingularTextString(StringContent.Delete, self.__setNameTextString(StringContent.Delete,
UiStrings.Delete, UiStrings.DeleteSelect) UiStrings.Delete, tooltips[u'delete'])
## Preview Action ## ## Preview Action ##
self._setSingularTextString(StringContent.Preview, self.__setNameTextString(StringContent.Preview,
UiStrings.Preview, UiStrings.PreviewSelect) UiStrings.Preview, tooltips[u'preview'])
## Send Live Action ## ## Send Live Action ##
self._setSingularTextString(StringContent.Live, self.__setNameTextString(StringContent.Live,
UiStrings.Live, UiStrings.SendSelectLive) UiStrings.Live, tooltips[u'live'])
## Add to Service Action ## ## Add to Service Action ##
self._setSingularTextString(StringContent.Service, self.__setNameTextString(StringContent.Service,
UiStrings.Service, UiStrings.AddSelectService) UiStrings.Service, tooltips[u'service'])
def _setSingularTextString(self, name, title, tooltip): def __setNameTextString(self, name, title, tooltip):
""" """
Utility method for creating a plugin's textStrings. This method makes Utility method for creating a plugin's textStrings. This method makes
use of the singular name of the plugin object so must only be called use of the singular name of the plugin object so must only be called
after this has been set. after this has been set.
""" """
self.textStrings[name] = { u'title': title, u'tooltip': tooltip % self.textStrings[name] = {u'title': title, u'tooltip': tooltip}
self.getString(StringContent.Name)[u'singular']}

View File

@ -203,12 +203,12 @@ class RenderManager(object):
# set the default image size for previews # set the default image size for previews
self.calculate_default(self.screens.preview[u'size']) self.calculate_default(self.screens.preview[u'size'])
verse = u'The Lord said to {r}Noah{/r}: \n' \ verse = u'The Lord said to {r}Noah{/r}: \n' \
'There\'s gonna be a {su}floody{/su}, {sb}floody{/sb}\n' \ 'There\'s gonna be a {su}floody{/su}, {sb}floody{/sb}\n' \
'The Lord said to {g}Noah{/g}:\n' \ 'The Lord said to {g}Noah{/g}:\n' \
'There\'s gonna be a {st}floody{/st}, {it}floody{/it}\n' \ 'There\'s gonna be a {st}floody{/st}, {it}floody{/it}\n' \
'Get those children out of the muddy, muddy \n' \ 'Get those children out of the muddy, muddy \n' \
'{r}C{/r}{b}h{/b}{bl}i{/bl}{y}l{/y}{g}d{/g}{pk}' \ '{r}C{/r}{b}h{/b}{bl}i{/bl}{y}l{/y}{g}d{/g}{pk}' \
'r{/pk}{o}e{/o}{pp}n{/pp} of the Lord\n' 'r{/pk}{o}e{/o}{pp}n{/pp} of the Lord\n'
# make big page for theme edit dialog to get line count # make big page for theme edit dialog to get line count
if self.force_page: if self.force_page:
verse = verse + verse + verse verse = verse + verse + verse

View File

@ -28,11 +28,13 @@ The :mod:`serviceitem` provides the service item functionality including the
type and capability of an item. type and capability of an item.
""" """
import datetime
import logging import logging
import os import os
import uuid import uuid
from openlp.core.lib import build_icon, clean_tags, expand_tags from openlp.core.lib import build_icon, clean_tags, expand_tags
from openlp.core.lib.ui import UiStrings
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -60,6 +62,7 @@ class ItemCapabilities(object):
AddIfNewItem = 9 AddIfNewItem = 9
ProvidesOwnDisplay = 10 ProvidesOwnDisplay = 10
AllowsDetailedTitleDisplay = 11 AllowsDetailedTitleDisplay = 11
AllowsVarableStartTime = 12
class ServiceItem(object): class ServiceItem(object):
@ -105,6 +108,8 @@ class ServiceItem(object):
self.data_string = u'' self.data_string = u''
self.edit_id = None self.edit_id = None
self.xml_version = None self.xml_version = None
self.start_time = 0
self.media_length = 0
self._new_item() self._new_item()
def _new_item(self): def _new_item(self):
@ -257,7 +262,9 @@ class ServiceItem(object):
u'capabilities': self.capabilities, u'capabilities': self.capabilities,
u'search': self.search_string, u'search': self.search_string,
u'data': self.data_string, u'data': self.data_string,
u'xml_version': self.xml_version u'xml_version': self.xml_version,
u'start_time': self.start_time,
u'media_length': self.media_length
} }
service_data = [] service_data = []
if self.service_item_type == ServiceItemType.Text: if self.service_item_type == ServiceItemType.Text:
@ -301,6 +308,10 @@ class ServiceItem(object):
self.data_string = header[u'data'] self.data_string = header[u'data']
if u'xml_version' in header: if u'xml_version' in header:
self.xml_version = header[u'xml_version'] self.xml_version = header[u'xml_version']
if u'start_time' in header:
self.start_time = header[u'start_time']
if u'media_length' in header:
self.media_length = header[u'media_length']
if self.service_item_type == ServiceItemType.Text: if self.service_item_type == ServiceItemType.Text:
for slide in serviceitem[u'serviceitem'][u'data']: for slide in serviceitem[u'serviceitem'][u'data']:
self._raw_frames.append(slide) self._raw_frames.append(slide)
@ -420,3 +431,24 @@ class ServiceItem(object):
return self._raw_frames[row][u'path'] return self._raw_frames[row][u'path']
except IndexError: except IndexError:
return u'' return u''
def get_media_time(self):
"""
Returns the start and finish time for a media item
"""
start = None
end = None
if self.start_time != 0:
start = UiStrings.StartTimeCode % \
unicode(datetime.timedelta(seconds=self.start_time))
if self.media_length != 0:
end = UiStrings.LengthTime % \
unicode(datetime.timedelta(seconds=self.media_length))
if not start and not end:
return None
elif start and not end:
return start
elif not start and end:
return end
else:
return u'%s : %s' % (start, end)

View File

@ -170,17 +170,17 @@ class HorizontalType(object):
Type enumeration for horizontal alignment. Type enumeration for horizontal alignment.
""" """
Left = 0 Left = 0
Center = 1 Center = 2
Right = 2 Right = 1
@staticmethod @staticmethod
def to_string(horizontal_type): def to_string(horizontal_type):
""" """
Return a string representation of a horizontal type. Return a string representation of a horizontal type.
""" """
if horizontal_type == Horizontal.Right: if horizontal_type == HorizontalType.Right:
return u'right' return u'right'
elif horizontal_type == Horizontal.Center: elif horizontal_type == HorizontalType.Center:
return u'center' return u'center'
else: else:
return u'left' return u'left'

View File

@ -41,44 +41,32 @@ class UiStrings(object):
# These strings should need a good reason to be retranslated elsewhere. # These strings should need a good reason to be retranslated elsewhere.
# Should some/more/less of these have an & attached? # Should some/more/less of these have an & attached?
Add = translate('OpenLP.Ui', '&Add') Add = translate('OpenLP.Ui', '&Add')
AddANew = unicode(translate('OpenLP.Ui', 'Add a new %s.'))
AddSelectService = unicode(translate('OpenLP.Ui',
'Add the selected %s to the service.'))
Advanced = translate('OpenLP.Ui', 'Advanced') Advanced = translate('OpenLP.Ui', 'Advanced')
AllFiles = translate('OpenLP.Ui', 'All Files') AllFiles = translate('OpenLP.Ui', 'All Files')
Authors = translate('OpenLP.Ui', 'Authors') Authors = translate('OpenLP.Ui', 'Authors')
CreateANew = unicode(translate('OpenLP.Ui', 'Create a new %s.')) CreateService = translate('OpenLP.Ui', 'Create a new service.')
Delete = translate('OpenLP.Ui', '&Delete') Delete = translate('OpenLP.Ui', '&Delete')
DeleteSelect = unicode(translate('OpenLP.Ui', 'Delete the selected %s.'))
DeleteType = unicode(translate('OpenLP.Ui', 'Delete %s'))
Edit = translate('OpenLP.Ui', '&Edit') Edit = translate('OpenLP.Ui', '&Edit')
EditSelect = unicode(translate('OpenLP.Ui', 'Edit the selected %s.'))
EditType = unicode(translate('OpenLP.Ui', 'Edit %s'))
Error = translate('OpenLP.Ui', 'Error') Error = translate('OpenLP.Ui', 'Error')
ExportType = unicode(translate('OpenLP.Ui', 'Export %s'))
Import = translate('OpenLP.Ui', 'Import') Import = translate('OpenLP.Ui', 'Import')
ImportType = unicode(translate('OpenLP.Ui', 'Import %s')) LengthTime = unicode(translate('OpenLP.Ui', 'Length %s'))
Live = translate('OpenLP.Ui', 'Live') Live = translate('OpenLP.Ui', 'Live')
Load = translate('OpenLP.Ui', 'Load') Load = translate('OpenLP.Ui', 'Load')
LoadANew = unicode(translate('OpenLP.Ui', 'Load a new %s.'))
New = translate('OpenLP.Ui', 'New') New = translate('OpenLP.Ui', 'New')
NewType = unicode(translate('OpenLP.Ui', 'New %s')) NewService = translate('OpenLP.Ui', 'New Service')
OLPV2 = translate('OpenLP.Ui', 'OpenLP 2.0') OLPV2 = translate('OpenLP.Ui', 'OpenLP 2.0')
OpenType = unicode(translate('OpenLP.Ui', 'Open %s')) OpenService = translate('OpenLP.Ui', 'Open Service')
Preview = translate('OpenLP.Ui', 'Preview') Preview = translate('OpenLP.Ui', 'Preview')
PreviewSelect = unicode(translate('OpenLP.Ui', 'Preview the selected %s.'))
ReplaceBG = translate('OpenLP.Ui', 'Replace Background') ReplaceBG = translate('OpenLP.Ui', 'Replace Background')
ReplaceLiveBG = translate('OpenLP.Ui', 'Replace Live Background') ReplaceLiveBG = translate('OpenLP.Ui', 'Replace Live Background')
ResetBG = translate('OpenLP.Ui', 'Reset Background') ResetBG = translate('OpenLP.Ui', 'Reset Background')
ResetLiveBG = translate('OpenLP.Ui', 'Reset Live Background') ResetLiveBG = translate('OpenLP.Ui', 'Reset Live Background')
SaveType = unicode(translate('OpenLP.Ui', 'Save %s')) SaveService = translate('OpenLP.Ui', 'Save Service')
SendSelectLive = unicode(translate('OpenLP.Ui',
'Send the selected %s live.'))
Service = translate('OpenLP.Ui', 'Service') Service = translate('OpenLP.Ui', 'Service')
StartTimeCode = unicode(translate('OpenLP.Ui', 'Start %s'))
Theme = translate('OpenLP.Ui', 'Theme') Theme = translate('OpenLP.Ui', 'Theme')
Themes = translate('OpenLP.Ui', 'Themes') Themes = translate('OpenLP.Ui', 'Themes')
def add_welcome_page(parent, image): def add_welcome_page(parent, image):
""" """
Generate an opening welcome page for a wizard using a provided image. Generate an opening welcome page for a wizard using a provided image.

View File

@ -53,6 +53,7 @@ class HideMode(object):
from themeform import ThemeForm from themeform import ThemeForm
from filerenameform import FileRenameForm from filerenameform import FileRenameForm
from starttimeform import StartTimeForm
from maindisplay import MainDisplay from maindisplay import MainDisplay
from servicenoteform import ServiceNoteForm from servicenoteform import ServiceNoteForm
from serviceitemeditform import ServiceItemEditForm from serviceitemeditform import ServiceItemEditForm

View File

@ -106,6 +106,9 @@ class MainDisplay(DisplayWidget):
self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self.mediaObject) self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self.mediaObject)
Phonon.createPath(self.mediaObject, self.videoWidget) Phonon.createPath(self.mediaObject, self.videoWidget)
Phonon.createPath(self.mediaObject, self.audio) Phonon.createPath(self.mediaObject, self.audio)
QtCore.QObject.connect(self.mediaObject,
QtCore.SIGNAL(u'stateChanged(Phonon::State, Phonon::State)'),
self.videoStart)
self.webView = QtWebKit.QWebView(self) self.webView = QtWebKit.QWebView(self)
self.webView.setGeometry(0, 0, self.webView.setGeometry(0, 0,
self.screen[u'size'].width(), self.screen[u'size'].height()) self.screen[u'size'].width(), self.screen[u'size'].height())
@ -341,6 +344,13 @@ class MainDisplay(DisplayWidget):
Receiver.send_message(u'maindisplay_active') Receiver.send_message(u'maindisplay_active')
return self.preview() return self.preview()
def videoStart(self, newState, oldState):
"""
Start the video at a predetermined point.
"""
if newState == Phonon.PlayingState:
self.mediaObject.seek(self.serviceItem.start_time * 1000)
def isWebLoaded(self): def isWebLoaded(self):
""" """
Called by webView event to show display is fully loaded Called by webView event to show display is fully loaded

View File

@ -319,17 +319,16 @@ class Ui_MainWindow(object):
self.themeManagerDock.setWindowTitle( self.themeManagerDock.setWindowTitle(
translate('OpenLP.MainWindow', 'Theme Manager')) translate('OpenLP.MainWindow', 'Theme Manager'))
self.FileNewItem.setText(translate('OpenLP.MainWindow', '&New')) self.FileNewItem.setText(translate('OpenLP.MainWindow', '&New'))
self.FileNewItem.setToolTip(UiStrings.NewType % UiStrings.Service) self.FileNewItem.setToolTip(UiStrings.NewService)
self.FileNewItem.setStatusTip( self.FileNewItem.setStatusTip(UiStrings.CreateService)
UiStrings.CreateANew % UiStrings.Service.toLower())
self.FileNewItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+N')) self.FileNewItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+N'))
self.FileOpenItem.setText(translate('OpenLP.MainWindow', '&Open')) self.FileOpenItem.setText(translate('OpenLP.MainWindow', '&Open'))
self.FileOpenItem.setToolTip(UiStrings.OpenType % UiStrings.Service) self.FileOpenItem.setToolTip(UiStrings.OpenService)
self.FileOpenItem.setStatusTip( self.FileOpenItem.setStatusTip(
translate('OpenLP.MainWindow', 'Open an existing service.')) translate('OpenLP.MainWindow', 'Open an existing service.'))
self.FileOpenItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+O')) self.FileOpenItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+O'))
self.FileSaveItem.setText(translate('OpenLP.MainWindow', '&Save')) self.FileSaveItem.setText(translate('OpenLP.MainWindow', '&Save'))
self.FileSaveItem.setToolTip(UiStrings.SaveType % UiStrings.Service) self.FileSaveItem.setToolTip(UiStrings.SaveService)
self.FileSaveItem.setStatusTip( self.FileSaveItem.setStatusTip(
translate('OpenLP.MainWindow', 'Save the current service to disk.')) translate('OpenLP.MainWindow', 'Save the current service to disk.'))
self.FileSaveItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+S')) self.FileSaveItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+S'))

View File

@ -24,8 +24,6 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
import datetime import datetime
import mutagen
import os
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
@ -113,16 +111,9 @@ class PrintServiceOrderForm(QtGui.QDialog, Ui_PrintServiceOrderDialog):
item.notes.replace(u'\n', u'<br />')) item.notes.replace(u'\n', u'<br />'))
# Add play length of media files. # Add play length of media files.
if item.is_media() and self.printMetaDataCheckBox.isChecked(): if item.is_media() and self.printMetaDataCheckBox.isChecked():
path = os.path.join(item.get_frames()[0][u'path'], text += u'<p><b>%s</b> %s</p>' % (translate(
item.get_frames()[0][u'title']) 'OpenLP.ServiceManager', u'Playing time:'),
if not os.path.isfile(path): unicode(datetime.timedelta(seconds=item.media_length)))
continue
file = mutagen.File(path)
if file is not None:
length = int(file.info.length)
text += u'<p><b>%s</b> %s</p>' % (translate(
'OpenLP.ServiceManager', u'Playing time:'),
unicode(datetime.timedelta(seconds=length)))
if self.customNoteEdit.toPlainText(): if self.customNoteEdit.toPlainText():
text += u'<h4>%s</h4>%s' % (translate('OpenLP.ServiceManager', text += u'<h4>%s</h4>%s' % (translate('OpenLP.ServiceManager',
u'Custom Service Notes:'), self.customNoteEdit.toPlainText()) u'Custom Service Notes:'), self.customNoteEdit.toPlainText())

View File

@ -36,7 +36,7 @@ from openlp.core.lib import OpenLPToolbar, ServiceItem, context_menu_action, \
Receiver, build_icon, ItemCapabilities, SettingsManager, translate, \ Receiver, build_icon, ItemCapabilities, SettingsManager, translate, \
ThemeLevel ThemeLevel
from openlp.core.lib.ui import UiStrings, critical_error_message_box from openlp.core.lib.ui import UiStrings, critical_error_message_box
from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm, StartTimeForm
from openlp.core.ui.printserviceorderform import PrintServiceOrderForm from openlp.core.ui.printserviceorderform import PrintServiceOrderForm
from openlp.core.utils import AppLocation, delete_file, file_is_unicode, \ from openlp.core.utils import AppLocation, delete_file, file_is_unicode, \
split_filename split_filename
@ -88,6 +88,7 @@ class ServiceManager(QtGui.QWidget):
self._fileName = u'' self._fileName = u''
self.serviceNoteForm = ServiceNoteForm(self.mainwindow) self.serviceNoteForm = ServiceNoteForm(self.mainwindow)
self.serviceItemEditForm = ServiceItemEditForm(self.mainwindow) self.serviceItemEditForm = ServiceItemEditForm(self.mainwindow)
self.startTimeForm = StartTimeForm(self.mainwindow)
# start with the layout # start with the layout
self.layout = QtGui.QVBoxLayout(self) self.layout = QtGui.QVBoxLayout(self)
self.layout.setSpacing(0) self.layout.setSpacing(0)
@ -95,18 +96,14 @@ class ServiceManager(QtGui.QWidget):
# Create the top toolbar # Create the top toolbar
self.toolbar = OpenLPToolbar(self) self.toolbar = OpenLPToolbar(self)
self.toolbar.addToolbarButton( self.toolbar.addToolbarButton(
UiStrings.NewType % UiStrings.Service, UiStrings.NewService, u':/general/general_new.png',
u':/general/general_new.png', UiStrings.CreateService, self.onNewServiceClicked)
UiStrings.CreateANew % UiStrings.Service.toLower(),
self.onNewServiceClicked)
self.toolbar.addToolbarButton( self.toolbar.addToolbarButton(
UiStrings.OpenType % UiStrings.Service, UiStrings.OpenService, u':/general/general_open.png',
u':/general/general_open.png',
translate('OpenLP.ServiceManager', 'Load an existing service'), translate('OpenLP.ServiceManager', 'Load an existing service'),
self.onLoadServiceClicked) self.onLoadServiceClicked)
self.toolbar.addToolbarButton( self.toolbar.addToolbarButton(
UiStrings.SaveType % UiStrings.Service, UiStrings.SaveService, u':/general/general_save.png',
u':/general/general_save.png',
translate('OpenLP.ServiceManager', 'Save this service'), translate('OpenLP.ServiceManager', 'Save this service'),
self.saveFile) self.saveFile)
self.toolbar.addSeparator() self.toolbar.addSeparator()
@ -270,16 +267,19 @@ class ServiceManager(QtGui.QWidget):
self.notesAction = self.menu.addAction( self.notesAction = self.menu.addAction(
translate('OpenLP.ServiceManager', '&Notes')) translate('OpenLP.ServiceManager', '&Notes'))
self.notesAction.setIcon(build_icon(u':/services/service_notes.png')) self.notesAction.setIcon(build_icon(u':/services/service_notes.png'))
self.timeAction = self.menu.addAction(
translate('OpenLP.ServiceManager', '&Start Time'))
self.timeAction.setIcon(build_icon(u':/media/media_time.png'))
self.deleteAction = self.menu.addAction( self.deleteAction = self.menu.addAction(
translate('OpenLP.ServiceManager', '&Delete From Service')) translate('OpenLP.ServiceManager', '&Delete From Service'))
self.deleteAction.setIcon(build_icon(u':/general/general_delete.png')) self.deleteAction.setIcon(build_icon(u':/general/general_delete.png'))
self.sep1 = self.menu.addAction(u'') self.sep1 = self.menu.addAction(u'')
self.sep1.setSeparator(True) self.sep1.setSeparator(True)
self.previewAction = self.menu.addAction( self.previewAction = self.menu.addAction(
translate('OpenLP.ServiceManager', '&Preview Verse')) translate('OpenLP.ServiceManager', 'Show &Preview'))
self.previewAction.setIcon(build_icon(u':/general/general_preview.png')) self.previewAction.setIcon(build_icon(u':/general/general_preview.png'))
self.liveAction = self.menu.addAction( self.liveAction = self.menu.addAction(
translate('OpenLP.ServiceManager', '&Live Verse')) translate('OpenLP.ServiceManager', 'Show &Live'))
self.liveAction.setIcon(build_icon(u':/general/general_live.png')) self.liveAction.setIcon(build_icon(u':/general/general_live.png'))
self.sep2 = self.menu.addAction(u'') self.sep2 = self.menu.addAction(u'')
self.sep2.setSeparator(True) self.sep2.setSeparator(True)
@ -465,7 +465,7 @@ class ServiceManager(QtGui.QWidget):
save the file. save the file.
""" """
fileName = unicode(QtGui.QFileDialog.getSaveFileName(self.mainwindow, fileName = unicode(QtGui.QFileDialog.getSaveFileName(self.mainwindow,
UiStrings.SaveType % UiStrings.Service, UiStrings.SaveService,
SettingsManager.get_last_dir( SettingsManager.get_last_dir(
self.mainwindow.serviceSettingsSection), self.mainwindow.serviceSettingsSection),
translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz)'))) translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz)')))
@ -563,6 +563,7 @@ class ServiceManager(QtGui.QWidget):
self.editAction.setVisible(False) self.editAction.setVisible(False)
self.maintainAction.setVisible(False) self.maintainAction.setVisible(False)
self.notesAction.setVisible(False) self.notesAction.setVisible(False)
self.timeAction.setVisible(False)
if serviceItem[u'service_item'].is_capable(ItemCapabilities.AllowsEdit)\ if serviceItem[u'service_item'].is_capable(ItemCapabilities.AllowsEdit)\
and serviceItem[u'service_item'].edit_id: and serviceItem[u'service_item'].edit_id:
self.editAction.setVisible(True) self.editAction.setVisible(True)
@ -571,6 +572,9 @@ class ServiceManager(QtGui.QWidget):
self.maintainAction.setVisible(True) self.maintainAction.setVisible(True)
if item.parent() is None: if item.parent() is None:
self.notesAction.setVisible(True) self.notesAction.setVisible(True)
if serviceItem[u'service_item']\
.is_capable(ItemCapabilities.AllowsVarableStartTime):
self.timeAction.setVisible(True)
self.themeMenu.menuAction().setVisible(False) self.themeMenu.menuAction().setVisible(False)
if serviceItem[u'service_item'].is_text(): if serviceItem[u'service_item'].is_text():
self.themeMenu.menuAction().setVisible(True) self.themeMenu.menuAction().setVisible(True)
@ -583,6 +587,8 @@ class ServiceManager(QtGui.QWidget):
self.onDeleteFromService() self.onDeleteFromService()
if action == self.notesAction: if action == self.notesAction:
self.onServiceItemNoteForm() self.onServiceItemNoteForm()
if action == self.timeAction:
self.onStartTimeForm()
if action == self.previewAction: if action == self.previewAction:
self.makePreview() self.makePreview()
if action == self.liveAction: if action == self.liveAction:
@ -597,6 +603,16 @@ class ServiceManager(QtGui.QWidget):
self.serviceNoteForm.textEdit.toPlainText() self.serviceNoteForm.textEdit.toPlainText()
self.repaintServiceList(item, -1) self.repaintServiceList(item, -1)
def onStartTimeForm(self):
item = self.findServiceItem()[0]
self.startTimeForm.item = self.serviceItems[item]
if self.startTimeForm.exec_():
self.serviceItems[item][u'service_item'].start_time = \
self.startTimeForm.hourSpinBox.value() * 3600 + \
self.startTimeForm.minuteSpinBox.value() * 60 + \
self.startTimeForm.secondSpinBox.value()
self.repaintServiceList(item, -1)
def onServiceItemEditForm(self): def onServiceItemEditForm(self):
item = self.findServiceItem()[0] item = self.findServiceItem()[0]
self.serviceItemEditForm.setServiceItem( self.serviceItemEditForm.setServiceItem(
@ -843,6 +859,11 @@ class ServiceManager(QtGui.QWidget):
text = frame[u'title'].replace(u'\n', u' ') text = frame[u'title'].replace(u'\n', u' ')
child.setText(0, text[:40]) child.setText(0, text[:40])
child.setData(0, QtCore.Qt.UserRole, QtCore.QVariant(count)) child.setData(0, QtCore.Qt.UserRole, QtCore.QVariant(count))
if item[u'service_item'] \
.is_capable(ItemCapabilities.AllowsVarableStartTime):
tip = item[u'service_item'].get_media_time()
if tip:
child.setToolTip(0, tip)
if serviceItem == itemcount: if serviceItem == itemcount:
if item[u'expanded'] and serviceItemChild == count: if item[u'expanded'] and serviceItemChild == count:
self.serviceManagerList.setCurrentItem(child) self.serviceManagerList.setCurrentItem(child)

View File

@ -36,7 +36,6 @@ class Ui_SettingsDialog(object):
settingsDialog.setWindowIcon( settingsDialog.setWindowIcon(
build_icon(u':/system/system_settings.png')) build_icon(u':/system/system_settings.png'))
self.settingsLayout = QtGui.QVBoxLayout(settingsDialog) self.settingsLayout = QtGui.QVBoxLayout(settingsDialog)
margins = self.settingsLayout.contentsMargins()
self.settingsLayout.setObjectName(u'settingsLayout') self.settingsLayout.setObjectName(u'settingsLayout')
self.settingsTabWidget = QtGui.QTabWidget(settingsDialog) self.settingsTabWidget = QtGui.QTabWidget(settingsDialog)
self.settingsTabWidget.setObjectName(u'settingsTabWidget') self.settingsTabWidget.setObjectName(u'settingsTabWidget')

View File

@ -36,7 +36,7 @@ class Ui_ShortcutListDialog(object):
self.treeWidget = QtGui.QTreeWidget(shortcutListDialog) self.treeWidget = QtGui.QTreeWidget(shortcutListDialog)
self.treeWidget.setAlternatingRowColors(True) self.treeWidget.setAlternatingRowColors(True)
self.treeWidget.setObjectName(u'treeWidget') self.treeWidget.setObjectName(u'treeWidget')
self.treeWidget.setColumnCount(2) self.treeWidget.setColumnCount(3)
self.dialogLayout.addWidget(self.treeWidget) self.dialogLayout.addWidget(self.treeWidget)
self.defaultButton = QtGui.QRadioButton(shortcutListDialog) self.defaultButton = QtGui.QRadioButton(shortcutListDialog)
self.defaultButton.setChecked(True) self.defaultButton.setChecked(True)
@ -78,7 +78,8 @@ class Ui_ShortcutListDialog(object):
translate('OpenLP.ShortcutListDialog', 'Customize Shortcuts')) translate('OpenLP.ShortcutListDialog', 'Customize Shortcuts'))
self.treeWidget.setHeaderLabels([ self.treeWidget.setHeaderLabels([
translate('OpenLP.ShortcutListDialog', 'Action'), translate('OpenLP.ShortcutListDialog', 'Action'),
translate('OpenLP.ShortcutListDialog', 'Shortcut')]) translate('OpenLP.ShortcutListDialog', 'Shortcut'),
translate('OpenLP.ShortcutListDialog', 'Alternate')])
self.defaultButton.setText( self.defaultButton.setText(
translate('OpenLP.ShortcutListDialog', 'Default: %s')) translate('OpenLP.ShortcutListDialog', 'Default: %s'))
self.customButton.setText( self.customButton.setText(

View File

@ -95,8 +95,13 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
item = QtGui.QTreeWidgetItem([category.name]) item = QtGui.QTreeWidgetItem([category.name])
for action in category.actions: for action in category.actions:
actionText = REMOVE_AMPERSAND.sub('', unicode(action.text())) actionText = REMOVE_AMPERSAND.sub('', unicode(action.text()))
shortcutText = action.shortcut().toString() if (len(action.shortcuts()) == 2):
actionItem = QtGui.QTreeWidgetItem([actionText, shortcutText]) shortcutText = action.shortcuts()[0].toString()
alternateText = action.shortcuts()[1].toString()
else:
shortcutText = action.shortcut().toString()
alternateText = u''
actionItem = QtGui.QTreeWidgetItem([actionText, shortcutText, alternateText])
actionItem.setIcon(0, action.icon()) actionItem.setIcon(0, action.icon())
item.addChild(actionItem) item.addChild(actionItem)
item.setExpanded(True) item.setExpanded(True)

View File

@ -380,7 +380,7 @@ class SlideController(QtGui.QWidget):
self.previousItem.setShortcuts([QtCore.Qt.Key_Up, QtCore.Qt.Key_PageUp]) self.previousItem.setShortcuts([QtCore.Qt.Key_Up, QtCore.Qt.Key_PageUp])
self.previousItem.setShortcutContext( self.previousItem.setShortcutContext(
QtCore.Qt.WidgetWithChildrenShortcut) QtCore.Qt.WidgetWithChildrenShortcut)
actionList.add_action(self.nextItem, u'Live') actionList.add_action(self.previousItem, u'Live')
self.nextItem.setShortcuts([QtCore.Qt.Key_Down, QtCore.Qt.Key_PageDown]) self.nextItem.setShortcuts([QtCore.Qt.Key_Down, QtCore.Qt.Key_PageDown])
self.nextItem.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut) self.nextItem.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
actionList.add_action(self.nextItem, u'Live') actionList.add_action(self.nextItem, u'Live')

View File

@ -0,0 +1,70 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 Tim Bentley, 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
from openlp.core.lib.ui import create_accept_reject_button_box
class Ui_StartTimeDialog(object):
def setupUi(self, StartTimeDialog):
StartTimeDialog.setObjectName(u'StartTimeDialog')
StartTimeDialog.resize(300, 10)
self.dialogLayout = QtGui.QGridLayout(StartTimeDialog)
self.dialogLayout.setObjectName(u'dialogLayout')
self.hourLabel = QtGui.QLabel(StartTimeDialog)
self.hourLabel.setObjectName("hourLabel")
self.dialogLayout.addWidget(self.hourLabel, 0, 0, 1, 1)
self.hourSpinBox = QtGui.QSpinBox(StartTimeDialog)
self.hourSpinBox.setObjectName("hourSpinBox")
self.dialogLayout.addWidget(self.hourSpinBox, 0, 1, 1, 1)
self.minuteLabel = QtGui.QLabel(StartTimeDialog)
self.minuteLabel.setObjectName("minuteLabel")
self.dialogLayout.addWidget(self.minuteLabel, 1, 0, 1, 1)
self.minuteSpinBox = QtGui.QSpinBox(StartTimeDialog)
self.minuteSpinBox.setObjectName("minuteSpinBox")
self.dialogLayout.addWidget(self.minuteSpinBox, 1, 1, 1, 1)
self.secondLabel = QtGui.QLabel(StartTimeDialog)
self.secondLabel.setObjectName("secondLabel")
self.dialogLayout.addWidget(self.secondLabel, 2, 0, 1, 1)
self.secondSpinBox = QtGui.QSpinBox(StartTimeDialog)
self.secondSpinBox.setObjectName("secondSpinBox")
self.dialogLayout.addWidget(self.secondSpinBox, 2, 1, 1, 1)
self.buttonBox = create_accept_reject_button_box(StartTimeDialog, True)
self.dialogLayout.addWidget(self.buttonBox, 4, 0, 1, 2)
self.retranslateUi(StartTimeDialog)
self.setMaximumHeight(self.sizeHint().height())
QtCore.QMetaObject.connectSlotsByName(StartTimeDialog)
def retranslateUi(self, StartTimeDialog):
self.setWindowTitle(translate('OpenLP.StartTimeForm',
'Item Start Time'))
self.hourLabel.setText(translate('OpenLP.StartTimeForm', 'Hours:'))
self.hourSpinBox.setSuffix(translate('OpenLP.StartTimeForm', 'h'))
self.minuteSpinBox.setSuffix(translate('OpenLP.StartTimeForm', 'm'))
self.secondSpinBox.setSuffix(translate('OpenLP.StartTimeForm', 's'))
self.minuteLabel.setText(translate('OpenLP.StartTimeForm', 'Minutes:'))
self.secondLabel.setText(translate('OpenLP.StartTimeForm', 'Seconds:'))

View File

@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 Tim Bentley, 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 QtGui
from starttimedialog import Ui_StartTimeDialog
class StartTimeForm(QtGui.QDialog, Ui_StartTimeDialog):
"""
The exception dialog
"""
def __init__(self, parent):
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
def exec_(self):
"""
Run the Dialog with correct heading.
"""
seconds = self.item[u'service_item'].start_time
hours = seconds / 3600
seconds -= 3600 * hours
minutes = seconds / 60
seconds -= 60 * minutes
self.hourSpinBox.setValue(hours)
self.minuteSpinBox.setValue(minutes)
self.secondSpinBox.setValue(seconds)
return QtGui.QDialog.exec_(self)

View File

@ -483,7 +483,8 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
Background Image button pushed. Background Image button pushed.
""" """
images_filter = get_images_filter() images_filter = get_images_filter()
images_filter = '%s;;%s (*.*) (*)' % (images_filter, UiStrings.AllFiles) images_filter = u'%s;;%s (*.*) (*)' % (
images_filter, UiStrings.AllFiles)
filename = QtGui.QFileDialog.getOpenFileName(self, filename = QtGui.QFileDialog.getOpenFileName(self,
translate('OpenLP.ThemeForm', 'Select Image'), u'', translate('OpenLP.ThemeForm', 'Select Image'), u'',
images_filter) images_filter)

View File

@ -63,28 +63,28 @@ class ThemeManager(QtGui.QWidget):
self.layout.setObjectName(u'layout') self.layout.setObjectName(u'layout')
self.toolbar = OpenLPToolbar(self) self.toolbar = OpenLPToolbar(self)
self.toolbar.addToolbarButton( self.toolbar.addToolbarButton(
UiStrings.NewType % UiStrings.Theme, translate('OpenLP.ThemeManager', 'New Theme'),
u':/themes/theme_new.png', u':/themes/theme_new.png',
UiStrings.CreateANew % UiStrings.Theme.toLower(), translate('OpenLP.ThemeManager', 'Create a new theme.'),
self.onAddTheme) self.onAddTheme)
self.toolbar.addToolbarButton( self.toolbar.addToolbarButton(
UiStrings.EditType % UiStrings.Theme, translate('OpenLP.ThemeManager', 'Edit Theme'),
u':/themes/theme_edit.png', u':/themes/theme_edit.png',
translate('OpenLP.ThemeManager', 'Edit a theme.'), translate('OpenLP.ThemeManager', 'Edit a theme.'),
self.onEditTheme) self.onEditTheme)
self.deleteToolbarAction = self.toolbar.addToolbarButton( self.deleteToolbarAction = self.toolbar.addToolbarButton(
UiStrings.DeleteType % UiStrings.Theme, translate('OpenLP.ThemeManager', 'Delete Theme'),
u':/general/general_delete.png', u':/general/general_delete.png',
translate('OpenLP.ThemeManager', 'Delete a theme.'), translate('OpenLP.ThemeManager', 'Delete a theme.'),
self.onDeleteTheme) self.onDeleteTheme)
self.toolbar.addSeparator() self.toolbar.addSeparator()
self.toolbar.addToolbarButton( self.toolbar.addToolbarButton(
UiStrings.ImportType % UiStrings.Theme, translate('OpenLP.ThemeManager', 'Import Theme'),
u':/general/general_import.png', u':/general/general_import.png',
translate('OpenLP.ThemeManager', 'Import a theme.'), translate('OpenLP.ThemeManager', 'Import a theme.'),
self.onImportTheme) self.onImportTheme)
self.toolbar.addToolbarButton( self.toolbar.addToolbarButton(
UiStrings.ExportType % UiStrings.Theme, translate('OpenLP.ThemeManager', 'Export Theme'),
u':/general/general_export.png', u':/general/general_export.png',
translate('OpenLP.ThemeManager', 'Export a theme.'), translate('OpenLP.ThemeManager', 'Export a theme.'),
self.onExportTheme) self.onExportTheme)
@ -314,7 +314,6 @@ class ThemeManager(QtGui.QWidget):
translate('OpenLP.ThemeManager', translate('OpenLP.ThemeManager',
'You must select a theme to edit.')): 'You must select a theme to edit.')):
item = self.themeListWidget.currentItem() item = self.themeListWidget.currentItem()
themeName = unicode(item.text())
theme = self.getThemeData( theme = self.getThemeData(
unicode(item.data(QtCore.Qt.UserRole).toString())) unicode(item.data(QtCore.Qt.UserRole).toString()))
if theme.background_type == u'image': if theme.background_type == u'image':
@ -406,8 +405,8 @@ class ThemeManager(QtGui.QWidget):
files = QtGui.QFileDialog.getOpenFileNames(self, files = QtGui.QFileDialog.getOpenFileNames(self,
translate('OpenLP.ThemeManager', 'Select Theme Import File'), translate('OpenLP.ThemeManager', 'Select Theme Import File'),
SettingsManager.get_last_dir(self.settingsSection), SettingsManager.get_last_dir(self.settingsSection),
translate('OpenLP.ThemeManager', 'Theme v1 (*.theme);;' unicode(translate('OpenLP.ThemeManager',
'Theme v2 (*.otz);;%s (*.*)') % UiStrings.AllFiles) 'OpenLP Themes (*.theme *.otz)')))
log.info(u'New Themes %s', unicode(files)) log.info(u'New Themes %s', unicode(files))
if files: if files:
for file in files: for file in files:
@ -530,6 +529,18 @@ class ThemeManager(QtGui.QWidget):
else: else:
outfile = open(fullpath, u'wb') outfile = open(fullpath, u'wb')
outfile.write(zip.read(file)) outfile.write(zip.read(file))
except (IOError, NameError):
critical_error_message_box(
translate('OpenLP.ThemeManager', 'Validation Error'),
translate('OpenLP.ThemeManager', 'File is not a valid theme.'))
log.exception(u'Importing theme from zip failed %s' % filename)
finally:
# Close the files, to be able to continue creating the theme.
if zip:
zip.close()
if outfile:
outfile.close()
# As all files are closed, we can create the Theme.
if filexml: if filexml:
theme = self._createThemeFromXml(filexml, self.path) theme = self._createThemeFromXml(filexml, self.path)
self.generateAndSaveImage(dir, themename, theme) self.generateAndSaveImage(dir, themename, theme)
@ -540,17 +551,6 @@ class ThemeManager(QtGui.QWidget):
'File is not a valid theme.')) 'File is not a valid theme.'))
log.exception(u'Theme file does not contain XML data %s' % log.exception(u'Theme file does not contain XML data %s' %
filename) filename)
except (IOError, NameError):
critical_error_message_box(
translate('OpenLP.ThemeManager', 'Validation Error'),
translate('OpenLP.ThemeManager',
'File is not a valid theme.'))
log.exception(u'Importing theme from zip failed %s' % filename)
finally:
if zip:
zip.close()
if outfile:
outfile.close()
def checkIfThemeExists(self, themeName): def checkIfThemeExists(self, themeName):
""" """

View File

@ -164,28 +164,34 @@ def _get_os_dir_path(dir_type):
""" """
Return a path based on which OS and environment we are running in. Return a path based on which OS and environment we are running in.
""" """
encoding = sys.getfilesystemencoding()
if sys.platform == u'win32': if sys.platform == u'win32':
if dir_type == AppLocation.DataDir: if dir_type == AppLocation.DataDir:
return os.path.join(os.getenv(u'APPDATA'), u'openlp', u'data') return os.path.join(unicode(os.getenv(u'APPDATA'), encoding),
return os.path.join(os.getenv(u'APPDATA'), u'openlp') u'openlp', u'data')
return os.path.join(unicode(os.getenv(u'APPDATA'), encoding),
u'openlp')
elif sys.platform == u'darwin': elif sys.platform == u'darwin':
if dir_type == AppLocation.DataDir: if dir_type == AppLocation.DataDir:
return os.path.join(os.getenv(u'HOME'), u'Library', return os.path.join(unicode(os.getenv(u'HOME'), encoding),
u'Application Support', u'openlp', u'Data') u'Library', u'Application Support', u'openlp', u'Data')
return os.path.join(os.getenv(u'HOME'), u'Library', return os.path.join(unicode(os.getenv(u'HOME'), encoding),
u'Application Support', u'openlp') u'Library', u'Application Support', u'openlp')
else: else:
if XDG_BASE_AVAILABLE: if XDG_BASE_AVAILABLE:
if dir_type == AppLocation.ConfigDir: if dir_type == AppLocation.ConfigDir:
return os.path.join(BaseDirectory.xdg_config_home, u'openlp') return os.path.join(unicode(BaseDirectory.xdg_config_home,
encoding), u'openlp')
elif dir_type == AppLocation.DataDir: elif dir_type == AppLocation.DataDir:
return os.path.join(BaseDirectory.xdg_data_home, u'openlp', return os.path.join(
u'data') unicode(BaseDirectory.xdg_data_home, encoding), u'openlp')
elif dir_type == AppLocation.CacheDir: elif dir_type == AppLocation.CacheDir:
return os.path.join(BaseDirectory.xdg_cache_home, u'openlp') return os.path.join(unicode(BaseDirectory.xdg_cache_home,
encoding), u'openlp')
if dir_type == AppLocation.DataDir: if dir_type == AppLocation.DataDir:
return os.path.join(os.getenv(u'HOME'), u'.openlp', u'data') return os.path.join(unicode(os.getenv(u'HOME'), encoding),
return os.path.join(os.getenv(u'HOME'), u'.openlp') u'.openlp', u'data')
return os.path.join(unicode(os.getenv(u'HOME'), encoding), u'.openlp')
def _get_frozen_path(frozen_option, non_frozen_option): def _get_frozen_path(frozen_option, non_frozen_option):
""" """
@ -376,13 +382,13 @@ def get_uno_command():
""" """
Returns the UNO command to launch an openoffice.org instance. Returns the UNO command to launch an openoffice.org instance.
""" """
COMMAND = u'soffice'
OPTIONS = u'-nologo -norestore -minimized -invisible -nofirststartwizard'
if UNO_CONNECTION_TYPE == u'pipe': if UNO_CONNECTION_TYPE == u'pipe':
return u'openoffice.org -nologo -norestore -minimized -invisible ' \ CONNECTION = u'"-accept=pipe,name=openlp_pipe;urp;"'
+ u'-nofirststartwizard -accept=pipe,name=openlp_pipe;urp;'
else: else:
return u'openoffice.org -nologo -norestore -minimized ' \ CONNECTION = u'"-accept=socket,host=localhost,port=2002;urp;"'
+ u'-invisible -nofirststartwizard ' \ return u'%s %s %s' % (COMMAND, OPTIONS, CONNECTION)
+ u'-accept=socket,host=localhost,port=2002;urp;'
def get_uno_instance(resolver): def get_uno_instance(resolver):
""" """

View File

@ -29,7 +29,6 @@ import logging
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import Plugin, StringContent, build_icon, translate from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.core.lib.ui import UiStrings
from openlp.plugins.bibles.lib import BibleManager, BiblesTab, BibleMediaItem from openlp.plugins.bibles.lib import BibleManager, BiblesTab, BibleMediaItem
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -129,9 +128,15 @@ class BiblePlugin(Plugin):
u'title': translate('BiblesPlugin', 'Bibles', 'container title') u'title': translate('BiblesPlugin', 'Bibles', 'container title')
} }
# Middle Header Bar # Middle Header Bar
## Import Action ## tooltips = {
self.textStrings[StringContent.Import] = { u'load': u'',
u'title': UiStrings.Import, u'import': translate('BiblesPlugin', 'Import a Bible'),
u'tooltip': translate('BiblesPlugin', 'Import a Bible') u'new': translate('BiblesPlugin', 'Add a new Bible'),
u'edit': translate('BiblesPlugin', 'Edit the selected Bible'),
u'delete': translate('BiblesPlugin', 'Delete the selected Bible'),
u'preview': translate('BiblesPlugin', 'Preview the selected Bible'),
u'live': translate('BiblesPlugin', 'Send the selected Bible live'),
u'service': translate('BiblesPlugin',
'Add the selected Bible to the service')
} }
Plugin.setPluginTextStrings(self) self.setPluginUiTextStrings(tooltips)

View File

@ -30,7 +30,6 @@ from forms import EditCustomForm
from openlp.core.lib import Plugin, StringContent, build_icon, translate from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.core.lib.db import Manager from openlp.core.lib.db import Manager
from openlp.core.lib.ui import UiStrings
from openlp.plugins.custom.lib import CustomMediaItem, CustomTab from openlp.plugins.custom.lib import CustomMediaItem, CustomTab
from openlp.plugins.custom.lib.db import CustomSlide, init_schema from openlp.plugins.custom.lib.db import CustomSlide, init_schema
@ -106,13 +105,20 @@ class CustomPlugin(Plugin):
u'title': translate('CustomsPlugin', 'Custom', 'container title') u'title': translate('CustomsPlugin', 'Custom', 'container title')
} }
# Middle Header Bar # Middle Header Bar
## Import Action ## tooltips = {
self.textStrings[StringContent.Import] = { u'load': translate('CustomsPlugin', 'Load a new Custom'),
u'title': UiStrings.Import, u'import': translate('CustomsPlugin', 'Import a Custom'),
u'tooltip': translate('CustomsPlugin', u'new': translate('CustomsPlugin', 'Add a new Custom'),
'Import a Custom') u'edit': translate('CustomsPlugin', 'Edit the selected Custom'),
u'delete': translate('CustomsPlugin', 'Delete the selected Custom'),
u'preview': translate('CustomsPlugin',
'Preview the selected Custom'),
u'live': translate('CustomsPlugin',
'Send the selected Custom live'),
u'service': translate('CustomsPlugin',
'Add the selected Custom to the service')
} }
Plugin.setPluginTextStrings(self) self.setPluginUiTextStrings(tooltips)
def finalise(self): def finalise(self):
""" """

View File

@ -69,4 +69,15 @@ class ImagePlugin(Plugin):
u'title': translate('ImagePlugin', 'Images', 'container title') u'title': translate('ImagePlugin', 'Images', 'container title')
} }
# Middle Header Bar # Middle Header Bar
Plugin.setPluginTextStrings(self) tooltips = {
u'load': translate('ImagePlugin', 'Load a new Image'),
u'import': u'',
u'new': translate('ImagePlugin', 'Add a new Image'),
u'edit': translate('ImagePlugin', 'Edit the selected Image'),
u'delete': translate('ImagePlugin', 'Delete the selected Image'),
u'preview': translate('ImagePlugin', 'Preview the selected Image'),
u'live': translate('ImagePlugin', 'Send the selected Image live'),
u'service': translate('ImagePlugin',
'Add the selected Image to the service')
}
self.setPluginUiTextStrings(tooltips)

View File

@ -32,6 +32,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \ from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \
SettingsManager, translate, check_item_selected, Receiver SettingsManager, translate, check_item_selected, Receiver
from openlp.core.lib.ui import UiStrings, critical_error_message_box from openlp.core.lib.ui import UiStrings, critical_error_message_box
from PyQt4.phonon import Phonon
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -48,9 +49,13 @@ class MediaMediaItem(MediaManagerItem):
u':/media/media_video.png').toImage() u':/media/media_video.png').toImage()
MediaManagerItem.__init__(self, parent, self, icon) MediaManagerItem.__init__(self, parent, self, icon)
self.singleServiceItem = False self.singleServiceItem = False
self.mediaObject = Phonon.MediaObject(self)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'video_background_replaced'), QtCore.SIGNAL(u'video_background_replaced'),
self.videobackgroundReplaced) self.videobackgroundReplaced)
QtCore.QObject.connect(self.mediaObject,
QtCore.SIGNAL(u'stateChanged(Phonon::State, Phonon::State)'),
self.videoStart)
def retranslateUi(self): def retranslateUi(self):
self.OnNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media') self.OnNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media')
@ -120,13 +125,22 @@ class MediaMediaItem(MediaManagerItem):
return False return False
filename = unicode(item.data(QtCore.Qt.UserRole).toString()) filename = unicode(item.data(QtCore.Qt.UserRole).toString())
if os.path.exists(filename): if os.path.exists(filename):
self.MediaState = None
self.mediaObject.stop()
self.mediaObject.clearQueue()
self.mediaObject.setCurrentSource(Phonon.MediaSource(filename))
self.mediaObject.play()
service_item.title = unicode( service_item.title = unicode(
translate('MediaPlugin.MediaItem', 'Media')) translate('MediaPlugin.MediaItem', 'Media'))
service_item.add_capability(ItemCapabilities.RequiresMedia) service_item.add_capability(ItemCapabilities.RequiresMedia)
service_item.add_capability(ItemCapabilities.AllowsVarableStartTime)
# force a nonexistent theme # force a nonexistent theme
service_item.theme = -1 service_item.theme = -1
frame = u':/media/image_clapperboard.png' frame = u':/media/image_clapperboard.png'
(path, name) = os.path.split(filename) (path, name) = os.path.split(filename)
while not self.MediaState:
Receiver.send_message(u'openlp_process_events')
service_item.media_length = self.mediaLength
service_item.add_from_command(path, name, frame) service_item.add_from_command(path, name, frame)
return True return True
else: else:
@ -164,3 +178,12 @@ class MediaMediaItem(MediaManagerItem):
item_name.setIcon(build_icon(img)) item_name.setIcon(build_icon(img))
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file)) item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
self.listView.addItem(item_name) self.listView.addItem(item_name)
def videoStart(self, newState, oldState):
"""
Start the video at a predetermined point.
"""
if newState == Phonon.PlayingState:
self.MediaState = newState
self.mediaLength = self.mediaObject.totalTime()/1000
self.mediaObject.stop()

View File

@ -95,4 +95,15 @@ class MediaPlugin(Plugin):
u'title': translate('MediaPlugin', 'Media', 'container title') u'title': translate('MediaPlugin', 'Media', 'container title')
} }
# Middle Header Bar # Middle Header Bar
Plugin.setPluginTextStrings(self) tooltips = {
u'load': translate('MediaPlugin', 'Load a new Media'),
u'import': u'',
u'new': translate('MediaPlugin', 'Add a new Media'),
u'edit': translate('MediaPlugin', 'Edit the selected Media'),
u'delete': translate('MediaPlugin', 'Delete the selected Media'),
u'preview': translate('MediaPlugin', 'Preview the selected Media'),
u'live': translate('MediaPlugin', 'Send the selected Media live'),
u'service': translate('MediaPlugin',
'Add the selected Media to the service')
}
self.setPluginUiTextStrings(tooltips)

View File

@ -147,8 +147,10 @@ class PowerpointDocument(PresentationDocument):
""" """
if self.check_thumbnails(): if self.check_thumbnails():
return return
self.presentation.Export(os.path.join(self.get_thumbnail_folder(), ''), for num in range(0, self.presentation.Slides.Count):
'png', 320, 240) self.presentation.Slides(num + 1).Export(os.path.join(
self.get_thumbnail_folder(), 'slide%d.png' % (num + 1)),
'png', 320, 240)
def close_presentation(self): def close_presentation(self):
""" """

View File

@ -154,8 +154,9 @@ class PptviewDocument(PresentationDocument):
being shut down being shut down
""" """
log.debug(u'ClosePresentation') log.debug(u'ClosePresentation')
self.controller.process.ClosePPT(self.pptid) if self.controller.process:
self.pptid = -1 self.controller.process.ClosePPT(self.pptid)
self.pptid = -1
self.controller.remove_doc(self) self.controller.remove_doc(self)
def is_loaded(self): def is_loaded(self):

View File

@ -167,4 +167,18 @@ class PresentationPlugin(Plugin):
'container title') 'container title')
} }
# Middle Header Bar # Middle Header Bar
Plugin.setPluginTextStrings(self) tooltips = {
u'load': translate('PresentationPlugin', 'Load a new Presentation'),
u'import': u'',
u'new': u'',
u'edit': u'',
u'delete': translate('PresentationPlugin',
'Delete the selected Presentation'),
u'preview': translate('PresentationPlugin',
'Preview the selected Presentation'),
u'live': translate('PresentationPlugin',
'Send the selected Presentation live'),
u'service': translate('PresentationPlugin',
'Add the selected Presentation to the service')
}
self.setPluginUiTextStrings(tooltips)

View File

@ -161,6 +161,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
def newSong(self): def newSong(self):
log.debug(u'New Song') log.debug(u'New Song')
self.song = None
self.initialise() self.initialise()
self.songTabWidget.setCurrentIndex(0) self.songTabWidget.setCurrentIndex(0)
self.titleEdit.setText(u'') self.titleEdit.setText(u'')

View File

@ -252,6 +252,7 @@ class SongExportForm(OpenLPWizard):
self.availableListWidget.clear() self.availableListWidget.clear()
self.selectedListWidget.clear() self.selectedListWidget.clear()
self.directoryLineEdit.clear() self.directoryLineEdit.clear()
self.searchLineEdit.clear()
# Load the list of songs. # Load the list of songs.
Receiver.send_message(u'cursor_busy') Receiver.send_message(u'cursor_busy')
songs = self.plugin.manager.get_all_objects(Song) songs = self.plugin.manager.get_all_objects(Song)
@ -340,19 +341,21 @@ class SongExportForm(OpenLPWizard):
def onUncheckButtonClicked(self): def onUncheckButtonClicked(self):
""" """
The *uncheckButton* has been clicked. Set all songs unchecked. The *uncheckButton* has been clicked. Set all visible songs unchecked.
""" """
for row in range(self.availableListWidget.count()): for row in range(self.availableListWidget.count()):
item = self.availableListWidget.item(row) item = self.availableListWidget.item(row)
item.setCheckState(QtCore.Qt.Unchecked) if not item.isHidden():
item.setCheckState(QtCore.Qt.Unchecked)
def onCheckButtonClicked(self): def onCheckButtonClicked(self):
""" """
The *checkButton* has been clicked. Set all songs checked. The *checkButton* has been clicked. Set all visible songs checked.
""" """
for row in range(self.availableListWidget.count()): for row in range(self.availableListWidget.count()):
item = self.availableListWidget.item(row) item = self.availableListWidget.item(row)
item.setCheckState(QtCore.Qt.Checked) if not item.isHidden():
item.setCheckState(QtCore.Qt.Checked)
def onDirectoryButtonClicked(self): def onDirectoryButtonClicked(self):
""" """

View File

@ -140,6 +140,12 @@ class SongImportForm(OpenLPWizard):
QtCore.QObject.connect(self.songBeamerRemoveButton, QtCore.QObject.connect(self.songBeamerRemoveButton,
QtCore.SIGNAL(u'clicked()'), QtCore.SIGNAL(u'clicked()'),
self.onSongBeamerRemoveButtonClicked) self.onSongBeamerRemoveButtonClicked)
QtCore.QObject.connect(self.songShowPlusAddButton,
QtCore.SIGNAL(u'clicked()'),
self.onSongShowPlusAddButtonClicked)
QtCore.QObject.connect(self.songShowPlusRemoveButton,
QtCore.SIGNAL(u'clicked()'),
self.onSongShowPlusRemoveButtonClicked)
def addCustomPages(self): def addCustomPages(self):
""" """
@ -188,6 +194,8 @@ class SongImportForm(OpenLPWizard):
self.addFileSelectItem(u'ew', single_select=True) self.addFileSelectItem(u'ew', single_select=True)
# Words of Worship # Words of Worship
self.addFileSelectItem(u'songBeamer') self.addFileSelectItem(u'songBeamer')
# Song Show Plus
self.addFileSelectItem(u'songShowPlus')
# Commented out for future use. # Commented out for future use.
# self.addFileSelectItem(u'csv', u'CSV', single_select=True) # self.addFileSelectItem(u'csv', u'CSV', single_select=True)
self.sourceLayout.addLayout(self.formatStack) self.sourceLayout.addLayout(self.formatStack)
@ -237,6 +245,8 @@ class SongImportForm(OpenLPWizard):
translate('SongsPlugin.ImportWizardForm', 'EasyWorship')) translate('SongsPlugin.ImportWizardForm', 'EasyWorship'))
self.formatComboBox.setItemText(10, self.formatComboBox.setItemText(10,
translate('SongsPlugin.ImportWizardForm', 'SongBeamer')) translate('SongsPlugin.ImportWizardForm', 'SongBeamer'))
self.formatComboBox.setItemText(11,
translate('SongsPlugin.ImportWizardForm', 'SongShow Plus'))
# self.formatComboBox.setItemText(11, # self.formatComboBox.setItemText(11,
# translate('SongsPlugin.ImportWizardForm', 'CSV')) # translate('SongsPlugin.ImportWizardForm', 'CSV'))
self.openLP2FilenameLabel.setText( self.openLP2FilenameLabel.setText(
@ -301,6 +311,10 @@ class SongImportForm(OpenLPWizard):
translate('SongsPlugin.ImportWizardForm', 'Add Files...')) translate('SongsPlugin.ImportWizardForm', 'Add Files...'))
self.songBeamerRemoveButton.setText( self.songBeamerRemoveButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) translate('SongsPlugin.ImportWizardForm', 'Remove File(s)'))
self.songShowPlusAddButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Add Files...'))
self.songShowPlusRemoveButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Remove File(s)'))
# self.csvFilenameLabel.setText( # self.csvFilenameLabel.setText(
# translate('SongsPlugin.ImportWizardForm', 'Filename:')) # translate('SongsPlugin.ImportWizardForm', 'Filename:'))
# self.csvBrowseButton.setText( # self.csvBrowseButton.setText(
@ -438,6 +452,16 @@ class SongImportForm(OpenLPWizard):
'file to import from.')) 'file to import from.'))
self.songBeamerAddButton.setFocus() self.songBeamerAddButton.setFocus()
return False return False
elif source_format == SongFormat.SongShowPlus:
if self.songShowPlusFileListWidget.count() == 0:
critical_error_message_box(
translate('SongsPlugin.ImportWizardForm',
'No SongShow Plus Files Selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to add at least one SongShow Plus '
'file to import from.'))
self.wordsOfWorshipAddButton.setFocus()
return False
return True return True
elif self.currentPage() == self.progressPage: elif self.currentPage() == self.progressPage:
return True return True
@ -456,7 +480,7 @@ class SongImportForm(OpenLPWizard):
The file extension filters. It should contain the file descriptions The file extension filters. It should contain the file descriptions
as well as the file extensions. For example:: as well as the file extensions. For example::
u'SongBeamer files (*.sng)' u'SongBeamer Files (*.sng)'
""" """
if filters: if filters:
filters += u';;' filters += u';;'
@ -585,7 +609,7 @@ class SongImportForm(OpenLPWizard):
'Select Songs of Fellowship Files'), 'Select Songs of Fellowship Files'),
self.songsOfFellowshipFileListWidget, u'%s (*.rtf)' self.songsOfFellowshipFileListWidget, u'%s (*.rtf)'
% translate('SongsPlugin.ImportWizardForm', % translate('SongsPlugin.ImportWizardForm',
'Songs Of Felloship Song Files') 'Songs Of Fellowship Song Files')
) )
def onSongsOfFellowshipRemoveButtonClicked(self): def onSongsOfFellowshipRemoveButtonClicked(self):
@ -635,7 +659,7 @@ class SongImportForm(OpenLPWizard):
translate('SongsPlugin.ImportWizardForm', translate('SongsPlugin.ImportWizardForm',
'Select SongBeamer Files'), 'Select SongBeamer Files'),
self.songBeamerFileListWidget, u'%s (*.sng)' % self.songBeamerFileListWidget, u'%s (*.sng)' %
translate('SongsPlugin.ImportWizardForm', 'SongBeamer files') translate('SongsPlugin.ImportWizardForm', 'SongBeamer Files')
) )
def onSongBeamerRemoveButtonClicked(self): def onSongBeamerRemoveButtonClicked(self):
@ -644,6 +668,24 @@ class SongImportForm(OpenLPWizard):
""" """
self.removeSelectedItems(self.songBeamerFileListWidget) self.removeSelectedItems(self.songBeamerFileListWidget)
def onSongShowPlusAddButtonClicked(self):
"""
Get SongShow Plus song database files
"""
self.getFiles(
translate('SongsPlugin.ImportWizardForm',
'Select SongShow Plus Files'),
self.songShowPlusFileListWidget, u'%s (*.sbsong)'
% translate('SongsPlugin.ImportWizardForm',
'SongShow Plus Song Files')
)
def onSongShowPlusRemoveButtonClicked(self):
"""
Remove selected SongShow Plus files from the import list
"""
self.removeSelectedItems(self.songShowPlusFileListWidget)
def setDefaults(self): def setDefaults(self):
""" """
Set default form values for the song import wizard. Set default form values for the song import wizard.
@ -663,6 +705,7 @@ class SongImportForm(OpenLPWizard):
self.easiSlidesFilenameEdit.setText(u'') self.easiSlidesFilenameEdit.setText(u'')
self.ewFilenameEdit.setText(u'') self.ewFilenameEdit.setText(u'')
self.songBeamerFileListWidget.clear() self.songBeamerFileListWidget.clear()
self.songShowPlusFileListWidget.clear()
#self.csvFilenameEdit.setText(u'') #self.csvFilenameEdit.setText(u'')
def preWizard(self): def preWizard(self):
@ -739,6 +782,12 @@ class SongImportForm(OpenLPWizard):
importer = self.plugin.importSongs(SongFormat.SongBeamer, importer = self.plugin.importSongs(SongFormat.SongBeamer,
filenames=self.getListOfFiles(self.songBeamerFileListWidget) filenames=self.getListOfFiles(self.songBeamerFileListWidget)
) )
elif source_format == SongFormat.SongShowPlus:
# Import ShongShow Plus songs
importer = self.plugin.importSongs(SongFormat.SongShowPlus,
filenames=self.getListOfFiles(
self.songShowPlusFileListWidget)
)
if importer.do_import(): if importer.do_import():
self.progressLabel.setText( self.progressLabel.setText(
translate('SongsPlugin.SongImportForm', 'Finished import.')) translate('SongsPlugin.SongImportForm', 'Finished import.'))

View File

@ -457,7 +457,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def onTopicDeleteButtonClick(self): def onTopicDeleteButtonClick(self):
""" """
Delete the Book is the Book is not attached to any songs. Delete the Book if the Book is not attached to any songs.
""" """
self._deleteItem(Topic, self.topicsListWidget, self.resetTopics, self._deleteItem(Topic, self.topicsListWidget, self.resetTopics,
translate('SongsPlugin.SongMaintenanceForm', 'Delete Topic'), translate('SongsPlugin.SongMaintenanceForm', 'Delete Topic'),
@ -470,7 +470,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def onBookDeleteButtonClick(self): def onBookDeleteButtonClick(self):
""" """
Delete the Book is the Book is not attached to any songs. Delete the Book if the Book is not attached to any songs.
""" """
self._deleteItem(Book, self.booksListWidget, self.resetBooks, self._deleteItem(Book, self.booksListWidget, self.resetBooks,
translate('SongsPlugin.SongMaintenanceForm', 'Delete Book'), translate('SongsPlugin.SongMaintenanceForm', 'Delete Book'),

View File

@ -81,14 +81,16 @@ class EasiSlidesImport(SongImport):
def _parse_song(self, song): def _parse_song(self, song):
self._success = True self._success = True
self._add_unicode_attribute(self.title, song.Title1, True) self._add_unicode_attribute(u'title', song.Title1, True)
self._add_unicode_attribute(self.alternate_title, song.Title2) self._add_unicode_attribute(u'alternate_title', song.Title2)
self._add_unicode_attribute(self.song_number, song.SongNumber) self._add_unicode_attribute(u'song_number', song.SongNumber)
if self.song_number == u'0': if self.song_number == u'0':
self.song_number = u'' self.song_number = u''
self._add_authors(song) self._add_authors(song)
self._add_copyright(song) self._add_copyright(song.Copyright)
self._add_unicode_attribute(self.song_book_name, song.BookReference) self._add_copyright(song.LicenceAdmin1)
self._add_copyright(song.LicenceAdmin2)
self._add_unicode_attribute(u'song_book_name', song.BookReference)
self._parse_and_add_lyrics(song) self._parse_and_add_lyrics(song)
return self._success return self._success
@ -110,7 +112,7 @@ class EasiSlidesImport(SongImport):
Signals that this attribute must exist in a valid song. Signals that this attribute must exist in a valid song.
""" """
try: try:
self_attribute = unicode(import_attribute).strip() setattr(self, self_attribute, unicode(import_attribute).strip())
except UnicodeDecodeError: except UnicodeDecodeError:
log.exception(u'UnicodeDecodeError decoding %s' % import_attribute) log.exception(u'UnicodeDecodeError decoding %s' % import_attribute)
self._success = False self._success = False
@ -124,7 +126,7 @@ class EasiSlidesImport(SongImport):
authors = unicode(song.Writer).split(u',') authors = unicode(song.Writer).split(u',')
for author in authors: for author in authors:
author = author.strip() author = author.strip()
if len(author) > 0: if len(author):
self.authors.append(author) self.authors.append(author)
except UnicodeDecodeError: except UnicodeDecodeError:
log.exception(u'Unicode decode error while decoding Writer') log.exception(u'Unicode decode error while decoding Writer')
@ -132,35 +134,18 @@ class EasiSlidesImport(SongImport):
except AttributeError: except AttributeError:
pass pass
def _add_copyright(self, song): def _add_copyright(self, element):
"""
Assign the copyright information from the import to the song being
created.
``song``
The current song being imported.
"""
copyright_list = []
self.__add_copyright_element(copyright_list, song.Copyright)
self.__add_copyright_element(copyright_list, song.LicenceAdmin1)
self.__add_copyright_element(copyright_list, song.LicenceAdmin2)
self.add_copyright(u' '.join(copyright_list))
def __add_copyright_element(self, copyright_list, element):
""" """
Add a piece of copyright to the total copyright information for the Add a piece of copyright to the total copyright information for the
song. song.
``copyright_list``
The array to add the information to.
``element`` ``element``
The imported variable to get the data from. The imported variable to get the data from.
""" """
try: try:
copyright_list.append(unicode(element).strip()) self.add_copyright(unicode(element).strip())
except UnicodeDecodeError: except UnicodeDecodeError:
log.exception(u'Unicode error decoding %s' % element) log.exception(u'Unicode error on decoding copyright: %s' % element)
self._success = False self._success = False
except AttributeError: except AttributeError:
pass pass
@ -285,10 +270,12 @@ class EasiSlidesImport(SongImport):
# as these appeared originally in the file # as these appeared originally in the file
for [reg, vt, vn, inst] in our_verse_order: for [reg, vt, vn, inst] in our_verse_order:
if self._listHas(verses, [reg, vt, vn, inst]): if self._listHas(verses, [reg, vt, vn, inst]):
# this is false, but needs user input
lang = None
versetag = u'%s%s' % (vt, vn) versetag = u'%s%s' % (vt, vn)
versetags.append(versetag) versetags.append(versetag)
lines = u'\n'.join(verses[reg][vt][vn][inst]) lines = u'\n'.join(verses[reg][vt][vn][inst])
self.verses.append([versetag, lines]) self.verses.append([versetag, lines, lang])
SeqTypes = { SeqTypes = {
u'p': u'P1', u'p': u'P1',

View File

@ -34,6 +34,7 @@ from wowimport import WowImport
from cclifileimport import CCLIFileImport from cclifileimport import CCLIFileImport
from ewimport import EasyWorshipSongImport from ewimport import EasyWorshipSongImport
from songbeamerimport import SongBeamerImport from songbeamerimport import SongBeamerImport
from songshowplusimport import SongShowPlusImport
# Imports that might fail # Imports that might fail
try: try:
from olp1import import OpenLP1SongImport from olp1import import OpenLP1SongImport
@ -67,10 +68,11 @@ class SongFormat(object):
CCLI = 5 CCLI = 5
SongsOfFellowship = 6 SongsOfFellowship = 6
Generic = 7 Generic = 7
#CSV = 8
EasiSlides = 8 EasiSlides = 8
EasyWorship = 9 EasyWorship = 9
SongBeamer = 10 SongBeamer = 10
SongShowPlus = 11
#CSV = 12
@staticmethod @staticmethod
def get_class(format): def get_class(format):
@ -102,6 +104,8 @@ class SongFormat(object):
return EasyWorshipSongImport return EasyWorshipSongImport
elif format == SongFormat.SongBeamer: elif format == SongFormat.SongBeamer:
return SongBeamerImport return SongBeamerImport
elif format == SongFormat.SongShowPlus:
return SongShowPlusImport
return None return None
@staticmethod @staticmethod
@ -120,7 +124,8 @@ class SongFormat(object):
SongFormat.Generic, SongFormat.Generic,
SongFormat.EasiSlides, SongFormat.EasiSlides,
SongFormat.EasyWorship, SongFormat.EasyWorship,
SongFormat.SongBeamer SongFormat.SongBeamer,
SongFormat.SongShowPlus
] ]
@staticmethod @staticmethod

View File

@ -0,0 +1,210 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 Tim Bentley, 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:`wowimport` module provides the functionality for importing Words of
Worship songs into the OpenLP database.
"""
import os
import logging
import struct
from openlp.plugins.songs.lib.songimport import SongImport
TITLE = 1
AUTHOR = 2
COPYRIGHT = 3
CCLI_NO = 5
VERSE = 12
CHORUS = 20
TOPIC = 29
COMMENTS = 30
VERSE_ORDER = 31
SONG_BOOK = 35
SONG_NUMBER = 36
CUSTOM_VERSE = 37
log = logging.getLogger(__name__)
class SongShowPlusImport(SongImport):
"""
The :class:`SongShowPlusImport` class provides the ability to import song
files from SongShow Plus.
**SongShow Plus Song File Format:**
The SongShow Plus song file format is as follows:
* Each piece of data in the song file has some information that precedes
it.
* The general format of this data is as follows:
4 Bytes, forming a 32 bit number, a key if you will, this describes what
the data is (see blockKey below)
4 Bytes, forming a 32 bit number, which is the number of bytes until the
next block starts
1 Byte, which tells how namy bytes follows
1 or 4 Bytes, describes how long the string is, if its 1 byte, the string
is less than 255
The next bytes are the actuall data.
The next block of data follows on.
This description does differ for verses. Which includes extra bytes
stating the verse type or number. In some cases a "custom" verse is used,
in that case, this block will in include 2 strings, with the associated
string length descriptors. The first string is the name of the verse, the
second is the verse content.
The file is ended with four null bytes.
Valid extensions for a SongShow Plus song file are:
* .sbsong
"""
otherList = {}
otherCount = 0
def __init__(self, master_manager, **kwargs):
"""
Initialise the import.
``master_manager``
The song manager for the running OpenLP installation.
"""
SongImport.__init__(self, master_manager)
if kwargs.has_key(u'filename'):
self.import_source = kwargs[u'filename']
if kwargs.has_key(u'filenames'):
self.import_source = kwargs[u'filenames']
log.debug(self.import_source)
def do_import(self):
"""
Receive a single file or a list of files to import.
"""
if isinstance(self.import_source, list):
self.import_wizard.progressBar.setMaximum(len(self.import_source))
for file in self.import_source:
author = u''
self.sspVerseOrderList = []
otherCount = 0
otherList = {}
file_name = os.path.split(file)[1]
self.import_wizard.incrementProgressBar(
u'Importing %s' % (file_name), 0)
songData = open(file, 'rb')
while (1):
blockKey, = struct.unpack("I", songData.read(4))
# The file ends with 4 NUL's
if blockKey == 0:
break
nextBlockStarts, = struct.unpack("I", songData.read(4))
if blockKey == VERSE or blockKey == CHORUS:
null, verseNo, = struct.unpack("BB", songData.read(2))
elif blockKey == CUSTOM_VERSE:
null, verseNameLength, = struct.unpack("BB",
songData.read(2))
verseName = songData.read(verseNameLength)
lengthDescriptorSize, = struct.unpack("B", songData.read(1))
# Detect if/how long the length descriptor is
if lengthDescriptorSize == 12:
lengthDescriptor, = struct.unpack("I", songData.read(4))
elif lengthDescriptorSize == 2:
lengthDescriptor = 1
elif lengthDescriptorSize == 9:
lengthDescriptor = 0
else:
lengthDescriptor, = struct.unpack("B", songData.read(1))
data = songData.read(lengthDescriptor)
if blockKey == TITLE:
self.title = unicode(data, u'cp1252')
elif blockKey == AUTHOR:
authors = data.split(" / ")
for author in authors:
if author.find(",") !=-1:
authorParts = author.split(", ")
author = authorParts[1] + " " + authorParts[0]
self.parse_author(unicode(author, u'cp1252'))
elif blockKey == COPYRIGHT:
self.add_copyright(unicode(data, u'cp1252'))
elif blockKey == CCLI_NO:
self.ccli_number = int(data)
elif blockKey == VERSE:
self.add_verse(unicode(data, u'cp1252'),
"V%s" % verseNo)
elif blockKey == CHORUS:
self.add_verse(unicode(data, u'cp1252'),
"C%s" % verseNo)
elif blockKey == TOPIC:
self.topics.append(unicode(data, u'cp1252'))
elif blockKey == COMMENTS:
self.comments = unicode(data, u'cp1252')
elif blockKey == VERSE_ORDER:
verseTag = self.toOpenLPVerseTag(data)
self.sspVerseOrderList.append(unicode(verseTag,
u'cp1252'))
elif blockKey == SONG_BOOK:
self.song_book_name = unicode(data, u'cp1252')
elif blockKey == SONG_NUMBER:
self.song_number = ord(data)
elif blockKey == CUSTOM_VERSE:
verseTag = self.toOpenLPVerseTag(verseName)
self.add_verse(unicode(data, u'cp1252'), verseTag)
else:
log.debug("Unrecognised blockKey: %s, data: %s"
%(blockKey, data))
self.verse_order_list = self.sspVerseOrderList
songData.close()
self.finish()
self.import_wizard.incrementProgressBar(
u'Importing %s' % (file_name))
return True
def toOpenLPVerseTag(self, verseName):
if verseName.find(" ") !=-1:
verseParts = verseName.split(" ")
verseType = verseParts[0]
verseNumber = verseParts[1]
else:
verseType = verseName
verseNumber = "1"
verseType = verseType.lower()
if verseType == "verse":
verseTag = "V"
elif verseType == "chorus":
verseTag = "C"
elif verseType == "bridge":
verseTag = "B"
elif verseType == "pre-chorus":
verseTag = "P"
elif verseType == "bridge":
verseTag = "B"
else:
if not self.otherList.has_key(verseName):
self.otherCount = self.otherCount + 1
self.otherList[verseName] = str(self.otherCount)
verseTag = "O"
verseNumber = self.otherList[verseName]
verseTag = verseTag + verseNumber
return verseTag

View File

@ -228,7 +228,18 @@ class SongsPlugin(Plugin):
u'title': translate('SongsPlugin', 'Songs', 'container title') u'title': translate('SongsPlugin', 'Songs', 'container title')
} }
# Middle Header Bar # Middle Header Bar
Plugin.setPluginTextStrings(self) tooltips = {
u'load': u'',
u'import': u'',
u'new': translate('SongsPlugin', 'Add a new Song'),
u'edit': translate('SongsPlugin', 'Edit the selected Song'),
u'delete': translate('SongsPlugin', 'Delete the selected Song'),
u'preview': translate('SongsPlugin', 'Preview the selected Song'),
u'live': translate('SongsPlugin', 'Send the selected Song live'),
u'service': translate('SongsPlugin',
'Add the selected Song to the service')
}
self.setPluginUiTextStrings(tooltips)
def finalise(self): def finalise(self):
""" """

View File

@ -68,6 +68,7 @@ Source: ..\..\dist\OpenLP\*; DestDir: {app}; Flags: ignoreversion recursesubdirs
[Icons] [Icons]
Name: {group}\{#AppName}; Filename: {app}\{#AppExeName} Name: {group}\{#AppName}; Filename: {app}\{#AppExeName}
Name: {group}\{#AppName} (Debug); Filename: {app}\{#AppExeName}; Parameters: -l debug
Name: {group}\{cm:ProgramOnTheWeb,{#AppName}}; Filename: {#AppURL} Name: {group}\{cm:ProgramOnTheWeb,{#AppName}}; Filename: {#AppURL}
Name: {group}\{cm:UninstallProgram,{#AppName}}; Filename: {uninstallexe} Name: {group}\{cm:UninstallProgram,{#AppName}}; Filename: {uninstallexe}
Name: {commondesktop}\{#AppName}; Filename: {app}\{#AppExeName}; Tasks: desktopicon Name: {commondesktop}\{#AppName}; Filename: {app}\{#AppExeName}; Tasks: desktopicon