forked from openlp/openlp
r1309
This commit is contained in:
commit
e0b1b003df
|
@ -239,7 +239,8 @@ def resize_image(image, width, height, background=QtCore.Qt.black):
|
|||
Resize an image to fit on the current screen.
|
||||
|
||||
``image``
|
||||
The image to resize.
|
||||
The image to resize. It has to be either a ``QImage`` instance or the
|
||||
path to the image.
|
||||
|
||||
``width``
|
||||
The new image width.
|
||||
|
|
|
@ -85,8 +85,7 @@ class ImageManager(QtCore.QObject):
|
|||
for key in self._cache.keys():
|
||||
image = self._cache[key]
|
||||
image.dirty = True
|
||||
image.image = resize_image(image.path,
|
||||
self.width, self.height)
|
||||
image.image = resize_image(image.path, self.width, self.height)
|
||||
self._cache_dirty = True
|
||||
# only one thread please
|
||||
if not self._thread_running:
|
||||
|
@ -128,8 +127,7 @@ class ImageManager(QtCore.QObject):
|
|||
image = Image()
|
||||
image.name = name
|
||||
image.path = path
|
||||
image.image = resize_image(path,
|
||||
self.width, self.height)
|
||||
image.image = resize_image(path, self.width, self.height)
|
||||
self._cache[name] = image
|
||||
else:
|
||||
log.debug(u'Image in cache %s:%s' % (name, path))
|
||||
|
|
|
@ -252,7 +252,6 @@ class MediaManagerItem(QtGui.QWidget):
|
|||
self.pageLayout.addWidget(self.listView)
|
||||
# define and add the context menu
|
||||
self.listView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
|
||||
name_string = self.plugin.getString(StringContent.Name)
|
||||
if self.hasEditIcon:
|
||||
self.listView.addAction(
|
||||
context_menu_action(
|
||||
|
|
|
@ -335,37 +335,39 @@ class Plugin(QtCore.QObject):
|
|||
"""
|
||||
return self.textStrings[name]
|
||||
|
||||
def setPluginTextStrings(self):
|
||||
def setPluginUiTextStrings(self, tooltips):
|
||||
"""
|
||||
Called to define all translatable texts of the plugin
|
||||
"""
|
||||
## Load Action ##
|
||||
self._setSingularTextString(StringContent.Load,
|
||||
UiStrings.Load, UiStrings.LoadANew)
|
||||
self.__setNameTextString(StringContent.Load,
|
||||
UiStrings.Load, tooltips[u'load'])
|
||||
## Import Action ##
|
||||
self.__setNameTextString(StringContent.Import,
|
||||
UiStrings.Import, tooltips[u'import'])
|
||||
## New Action ##
|
||||
self._setSingularTextString(StringContent.New,
|
||||
UiStrings.Add, UiStrings.AddANew)
|
||||
self.__setNameTextString(StringContent.New,
|
||||
UiStrings.Add, tooltips[u'new'])
|
||||
## Edit Action ##
|
||||
self._setSingularTextString(StringContent.Edit,
|
||||
UiStrings.Edit, UiStrings.EditSelect)
|
||||
self.__setNameTextString(StringContent.Edit,
|
||||
UiStrings.Edit, tooltips[u'edit'])
|
||||
## Delete Action ##
|
||||
self._setSingularTextString(StringContent.Delete,
|
||||
UiStrings.Delete, UiStrings.DeleteSelect)
|
||||
self.__setNameTextString(StringContent.Delete,
|
||||
UiStrings.Delete, tooltips[u'delete'])
|
||||
## Preview Action ##
|
||||
self._setSingularTextString(StringContent.Preview,
|
||||
UiStrings.Preview, UiStrings.PreviewSelect)
|
||||
self.__setNameTextString(StringContent.Preview,
|
||||
UiStrings.Preview, tooltips[u'preview'])
|
||||
## Send Live Action ##
|
||||
self._setSingularTextString(StringContent.Live,
|
||||
UiStrings.Live, UiStrings.SendSelectLive)
|
||||
self.__setNameTextString(StringContent.Live,
|
||||
UiStrings.Live, tooltips[u'live'])
|
||||
## Add to Service Action ##
|
||||
self._setSingularTextString(StringContent.Service,
|
||||
UiStrings.Service, UiStrings.AddSelectService)
|
||||
self.__setNameTextString(StringContent.Service,
|
||||
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
|
||||
use of the singular name of the plugin object so must only be called
|
||||
after this has been set.
|
||||
"""
|
||||
self.textStrings[name] = { u'title': title, u'tooltip': tooltip %
|
||||
self.getString(StringContent.Name)[u'singular']}
|
||||
self.textStrings[name] = {u'title': title, u'tooltip': tooltip}
|
||||
|
|
|
@ -203,12 +203,12 @@ class RenderManager(object):
|
|||
# set the default image size for previews
|
||||
self.calculate_default(self.screens.preview[u'size'])
|
||||
verse = u'The Lord said to {r}Noah{/r}: \n' \
|
||||
'There\'s gonna be a {su}floody{/su}, {sb}floody{/sb}\n' \
|
||||
'The Lord said to {g}Noah{/g}:\n' \
|
||||
'There\'s gonna be a {st}floody{/st}, {it}floody{/it}\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{/pk}{o}e{/o}{pp}n{/pp} of the Lord\n'
|
||||
'There\'s gonna be a {su}floody{/su}, {sb}floody{/sb}\n' \
|
||||
'The Lord said to {g}Noah{/g}:\n' \
|
||||
'There\'s gonna be a {st}floody{/st}, {it}floody{/it}\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{/pk}{o}e{/o}{pp}n{/pp} of the Lord\n'
|
||||
# make big page for theme edit dialog to get line count
|
||||
if self.force_page:
|
||||
verse = verse + verse + verse
|
||||
|
|
|
@ -28,11 +28,13 @@ The :mod:`serviceitem` provides the service item functionality including the
|
|||
type and capability of an item.
|
||||
"""
|
||||
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
import uuid
|
||||
|
||||
from openlp.core.lib import build_icon, clean_tags, expand_tags
|
||||
from openlp.core.lib.ui import UiStrings
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -60,6 +62,7 @@ class ItemCapabilities(object):
|
|||
AddIfNewItem = 9
|
||||
ProvidesOwnDisplay = 10
|
||||
AllowsDetailedTitleDisplay = 11
|
||||
AllowsVarableStartTime = 12
|
||||
|
||||
|
||||
class ServiceItem(object):
|
||||
|
@ -105,6 +108,8 @@ class ServiceItem(object):
|
|||
self.data_string = u''
|
||||
self.edit_id = None
|
||||
self.xml_version = None
|
||||
self.start_time = 0
|
||||
self.media_length = 0
|
||||
self._new_item()
|
||||
|
||||
def _new_item(self):
|
||||
|
@ -257,7 +262,9 @@ class ServiceItem(object):
|
|||
u'capabilities': self.capabilities,
|
||||
u'search': self.search_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 = []
|
||||
if self.service_item_type == ServiceItemType.Text:
|
||||
|
@ -301,6 +308,10 @@ class ServiceItem(object):
|
|||
self.data_string = header[u'data']
|
||||
if u'xml_version' in header:
|
||||
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:
|
||||
for slide in serviceitem[u'serviceitem'][u'data']:
|
||||
self._raw_frames.append(slide)
|
||||
|
@ -420,3 +431,24 @@ class ServiceItem(object):
|
|||
return self._raw_frames[row][u'path']
|
||||
except IndexError:
|
||||
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)
|
||||
|
|
|
@ -170,17 +170,17 @@ class HorizontalType(object):
|
|||
Type enumeration for horizontal alignment.
|
||||
"""
|
||||
Left = 0
|
||||
Center = 1
|
||||
Right = 2
|
||||
Center = 2
|
||||
Right = 1
|
||||
|
||||
@staticmethod
|
||||
def to_string(horizontal_type):
|
||||
"""
|
||||
Return a string representation of a horizontal type.
|
||||
"""
|
||||
if horizontal_type == Horizontal.Right:
|
||||
if horizontal_type == HorizontalType.Right:
|
||||
return u'right'
|
||||
elif horizontal_type == Horizontal.Center:
|
||||
elif horizontal_type == HorizontalType.Center:
|
||||
return u'center'
|
||||
else:
|
||||
return u'left'
|
||||
|
|
|
@ -41,44 +41,32 @@ class UiStrings(object):
|
|||
# These strings should need a good reason to be retranslated elsewhere.
|
||||
# Should some/more/less of these have an & attached?
|
||||
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')
|
||||
AllFiles = translate('OpenLP.Ui', 'All Files')
|
||||
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')
|
||||
DeleteSelect = unicode(translate('OpenLP.Ui', 'Delete the selected %s.'))
|
||||
DeleteType = unicode(translate('OpenLP.Ui', 'Delete %s'))
|
||||
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')
|
||||
ExportType = unicode(translate('OpenLP.Ui', 'Export %s'))
|
||||
Import = translate('OpenLP.Ui', 'Import')
|
||||
ImportType = unicode(translate('OpenLP.Ui', 'Import %s'))
|
||||
LengthTime = unicode(translate('OpenLP.Ui', 'Length %s'))
|
||||
Live = translate('OpenLP.Ui', 'Live')
|
||||
Load = translate('OpenLP.Ui', 'Load')
|
||||
LoadANew = unicode(translate('OpenLP.Ui', 'Load a new %s.'))
|
||||
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')
|
||||
OpenType = unicode(translate('OpenLP.Ui', 'Open %s'))
|
||||
OpenService = translate('OpenLP.Ui', 'Open Service')
|
||||
Preview = translate('OpenLP.Ui', 'Preview')
|
||||
PreviewSelect = unicode(translate('OpenLP.Ui', 'Preview the selected %s.'))
|
||||
ReplaceBG = translate('OpenLP.Ui', 'Replace Background')
|
||||
ReplaceLiveBG = translate('OpenLP.Ui', 'Replace Live Background')
|
||||
ResetBG = translate('OpenLP.Ui', 'Reset Background')
|
||||
ResetLiveBG = translate('OpenLP.Ui', 'Reset Live Background')
|
||||
SaveType = unicode(translate('OpenLP.Ui', 'Save %s'))
|
||||
SendSelectLive = unicode(translate('OpenLP.Ui',
|
||||
'Send the selected %s live.'))
|
||||
SaveService = translate('OpenLP.Ui', 'Save Service')
|
||||
Service = translate('OpenLP.Ui', 'Service')
|
||||
StartTimeCode = unicode(translate('OpenLP.Ui', 'Start %s'))
|
||||
Theme = translate('OpenLP.Ui', 'Theme')
|
||||
Themes = translate('OpenLP.Ui', 'Themes')
|
||||
|
||||
|
||||
def add_welcome_page(parent, image):
|
||||
"""
|
||||
Generate an opening welcome page for a wizard using a provided image.
|
||||
|
|
|
@ -53,6 +53,7 @@ class HideMode(object):
|
|||
|
||||
from themeform import ThemeForm
|
||||
from filerenameform import FileRenameForm
|
||||
from starttimeform import StartTimeForm
|
||||
from maindisplay import MainDisplay
|
||||
from servicenoteform import ServiceNoteForm
|
||||
from serviceitemeditform import ServiceItemEditForm
|
||||
|
|
|
@ -106,6 +106,9 @@ class MainDisplay(DisplayWidget):
|
|||
self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self.mediaObject)
|
||||
Phonon.createPath(self.mediaObject, self.videoWidget)
|
||||
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.setGeometry(0, 0,
|
||||
self.screen[u'size'].width(), self.screen[u'size'].height())
|
||||
|
@ -341,6 +344,13 @@ class MainDisplay(DisplayWidget):
|
|||
Receiver.send_message(u'maindisplay_active')
|
||||
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):
|
||||
"""
|
||||
Called by webView event to show display is fully loaded
|
||||
|
|
|
@ -319,17 +319,16 @@ class Ui_MainWindow(object):
|
|||
self.themeManagerDock.setWindowTitle(
|
||||
translate('OpenLP.MainWindow', 'Theme Manager'))
|
||||
self.FileNewItem.setText(translate('OpenLP.MainWindow', '&New'))
|
||||
self.FileNewItem.setToolTip(UiStrings.NewType % UiStrings.Service)
|
||||
self.FileNewItem.setStatusTip(
|
||||
UiStrings.CreateANew % UiStrings.Service.toLower())
|
||||
self.FileNewItem.setToolTip(UiStrings.NewService)
|
||||
self.FileNewItem.setStatusTip(UiStrings.CreateService)
|
||||
self.FileNewItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+N'))
|
||||
self.FileOpenItem.setText(translate('OpenLP.MainWindow', '&Open'))
|
||||
self.FileOpenItem.setToolTip(UiStrings.OpenType % UiStrings.Service)
|
||||
self.FileOpenItem.setToolTip(UiStrings.OpenService)
|
||||
self.FileOpenItem.setStatusTip(
|
||||
translate('OpenLP.MainWindow', 'Open an existing service.'))
|
||||
self.FileOpenItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+O'))
|
||||
self.FileSaveItem.setText(translate('OpenLP.MainWindow', '&Save'))
|
||||
self.FileSaveItem.setToolTip(UiStrings.SaveType % UiStrings.Service)
|
||||
self.FileSaveItem.setToolTip(UiStrings.SaveService)
|
||||
self.FileSaveItem.setStatusTip(
|
||||
translate('OpenLP.MainWindow', 'Save the current service to disk.'))
|
||||
self.FileSaveItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+S'))
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
import datetime
|
||||
import mutagen
|
||||
import os
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
|
@ -113,16 +111,9 @@ class PrintServiceOrderForm(QtGui.QDialog, Ui_PrintServiceOrderDialog):
|
|||
item.notes.replace(u'\n', u'<br />'))
|
||||
# Add play length of media files.
|
||||
if item.is_media() and self.printMetaDataCheckBox.isChecked():
|
||||
path = os.path.join(item.get_frames()[0][u'path'],
|
||||
item.get_frames()[0][u'title'])
|
||||
if not os.path.isfile(path):
|
||||
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)))
|
||||
text += u'<p><b>%s</b> %s</p>' % (translate(
|
||||
'OpenLP.ServiceManager', u'Playing time:'),
|
||||
unicode(datetime.timedelta(seconds=item.media_length)))
|
||||
if self.customNoteEdit.toPlainText():
|
||||
text += u'<h4>%s</h4>%s' % (translate('OpenLP.ServiceManager',
|
||||
u'Custom Service Notes:'), self.customNoteEdit.toPlainText())
|
||||
|
|
|
@ -36,7 +36,7 @@ from openlp.core.lib import OpenLPToolbar, ServiceItem, context_menu_action, \
|
|||
Receiver, build_icon, ItemCapabilities, SettingsManager, translate, \
|
||||
ThemeLevel
|
||||
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.utils import AppLocation, delete_file, file_is_unicode, \
|
||||
split_filename
|
||||
|
@ -88,6 +88,7 @@ class ServiceManager(QtGui.QWidget):
|
|||
self._fileName = u''
|
||||
self.serviceNoteForm = ServiceNoteForm(self.mainwindow)
|
||||
self.serviceItemEditForm = ServiceItemEditForm(self.mainwindow)
|
||||
self.startTimeForm = StartTimeForm(self.mainwindow)
|
||||
# start with the layout
|
||||
self.layout = QtGui.QVBoxLayout(self)
|
||||
self.layout.setSpacing(0)
|
||||
|
@ -95,18 +96,14 @@ class ServiceManager(QtGui.QWidget):
|
|||
# Create the top toolbar
|
||||
self.toolbar = OpenLPToolbar(self)
|
||||
self.toolbar.addToolbarButton(
|
||||
UiStrings.NewType % UiStrings.Service,
|
||||
u':/general/general_new.png',
|
||||
UiStrings.CreateANew % UiStrings.Service.toLower(),
|
||||
self.onNewServiceClicked)
|
||||
UiStrings.NewService, u':/general/general_new.png',
|
||||
UiStrings.CreateService, self.onNewServiceClicked)
|
||||
self.toolbar.addToolbarButton(
|
||||
UiStrings.OpenType % UiStrings.Service,
|
||||
u':/general/general_open.png',
|
||||
UiStrings.OpenService, u':/general/general_open.png',
|
||||
translate('OpenLP.ServiceManager', 'Load an existing service'),
|
||||
self.onLoadServiceClicked)
|
||||
self.toolbar.addToolbarButton(
|
||||
UiStrings.SaveType % UiStrings.Service,
|
||||
u':/general/general_save.png',
|
||||
UiStrings.SaveService, u':/general/general_save.png',
|
||||
translate('OpenLP.ServiceManager', 'Save this service'),
|
||||
self.saveFile)
|
||||
self.toolbar.addSeparator()
|
||||
|
@ -270,16 +267,19 @@ class ServiceManager(QtGui.QWidget):
|
|||
self.notesAction = self.menu.addAction(
|
||||
translate('OpenLP.ServiceManager', '&Notes'))
|
||||
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(
|
||||
translate('OpenLP.ServiceManager', '&Delete From Service'))
|
||||
self.deleteAction.setIcon(build_icon(u':/general/general_delete.png'))
|
||||
self.sep1 = self.menu.addAction(u'')
|
||||
self.sep1.setSeparator(True)
|
||||
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.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.sep2 = self.menu.addAction(u'')
|
||||
self.sep2.setSeparator(True)
|
||||
|
@ -465,7 +465,7 @@ class ServiceManager(QtGui.QWidget):
|
|||
save the file.
|
||||
"""
|
||||
fileName = unicode(QtGui.QFileDialog.getSaveFileName(self.mainwindow,
|
||||
UiStrings.SaveType % UiStrings.Service,
|
||||
UiStrings.SaveService,
|
||||
SettingsManager.get_last_dir(
|
||||
self.mainwindow.serviceSettingsSection),
|
||||
translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz)')))
|
||||
|
@ -563,6 +563,7 @@ class ServiceManager(QtGui.QWidget):
|
|||
self.editAction.setVisible(False)
|
||||
self.maintainAction.setVisible(False)
|
||||
self.notesAction.setVisible(False)
|
||||
self.timeAction.setVisible(False)
|
||||
if serviceItem[u'service_item'].is_capable(ItemCapabilities.AllowsEdit)\
|
||||
and serviceItem[u'service_item'].edit_id:
|
||||
self.editAction.setVisible(True)
|
||||
|
@ -571,6 +572,9 @@ class ServiceManager(QtGui.QWidget):
|
|||
self.maintainAction.setVisible(True)
|
||||
if item.parent() is None:
|
||||
self.notesAction.setVisible(True)
|
||||
if serviceItem[u'service_item']\
|
||||
.is_capable(ItemCapabilities.AllowsVarableStartTime):
|
||||
self.timeAction.setVisible(True)
|
||||
self.themeMenu.menuAction().setVisible(False)
|
||||
if serviceItem[u'service_item'].is_text():
|
||||
self.themeMenu.menuAction().setVisible(True)
|
||||
|
@ -583,6 +587,8 @@ class ServiceManager(QtGui.QWidget):
|
|||
self.onDeleteFromService()
|
||||
if action == self.notesAction:
|
||||
self.onServiceItemNoteForm()
|
||||
if action == self.timeAction:
|
||||
self.onStartTimeForm()
|
||||
if action == self.previewAction:
|
||||
self.makePreview()
|
||||
if action == self.liveAction:
|
||||
|
@ -597,6 +603,16 @@ class ServiceManager(QtGui.QWidget):
|
|||
self.serviceNoteForm.textEdit.toPlainText()
|
||||
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):
|
||||
item = self.findServiceItem()[0]
|
||||
self.serviceItemEditForm.setServiceItem(
|
||||
|
@ -843,6 +859,11 @@ class ServiceManager(QtGui.QWidget):
|
|||
text = frame[u'title'].replace(u'\n', u' ')
|
||||
child.setText(0, text[:40])
|
||||
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 item[u'expanded'] and serviceItemChild == count:
|
||||
self.serviceManagerList.setCurrentItem(child)
|
||||
|
|
|
@ -36,7 +36,6 @@ class Ui_SettingsDialog(object):
|
|||
settingsDialog.setWindowIcon(
|
||||
build_icon(u':/system/system_settings.png'))
|
||||
self.settingsLayout = QtGui.QVBoxLayout(settingsDialog)
|
||||
margins = self.settingsLayout.contentsMargins()
|
||||
self.settingsLayout.setObjectName(u'settingsLayout')
|
||||
self.settingsTabWidget = QtGui.QTabWidget(settingsDialog)
|
||||
self.settingsTabWidget.setObjectName(u'settingsTabWidget')
|
||||
|
|
|
@ -36,7 +36,7 @@ class Ui_ShortcutListDialog(object):
|
|||
self.treeWidget = QtGui.QTreeWidget(shortcutListDialog)
|
||||
self.treeWidget.setAlternatingRowColors(True)
|
||||
self.treeWidget.setObjectName(u'treeWidget')
|
||||
self.treeWidget.setColumnCount(2)
|
||||
self.treeWidget.setColumnCount(3)
|
||||
self.dialogLayout.addWidget(self.treeWidget)
|
||||
self.defaultButton = QtGui.QRadioButton(shortcutListDialog)
|
||||
self.defaultButton.setChecked(True)
|
||||
|
@ -78,7 +78,8 @@ class Ui_ShortcutListDialog(object):
|
|||
translate('OpenLP.ShortcutListDialog', 'Customize Shortcuts'))
|
||||
self.treeWidget.setHeaderLabels([
|
||||
translate('OpenLP.ShortcutListDialog', 'Action'),
|
||||
translate('OpenLP.ShortcutListDialog', 'Shortcut')])
|
||||
translate('OpenLP.ShortcutListDialog', 'Shortcut'),
|
||||
translate('OpenLP.ShortcutListDialog', 'Alternate')])
|
||||
self.defaultButton.setText(
|
||||
translate('OpenLP.ShortcutListDialog', 'Default: %s'))
|
||||
self.customButton.setText(
|
||||
|
|
|
@ -95,8 +95,13 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||
item = QtGui.QTreeWidgetItem([category.name])
|
||||
for action in category.actions:
|
||||
actionText = REMOVE_AMPERSAND.sub('', unicode(action.text()))
|
||||
shortcutText = action.shortcut().toString()
|
||||
actionItem = QtGui.QTreeWidgetItem([actionText, shortcutText])
|
||||
if (len(action.shortcuts()) == 2):
|
||||
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())
|
||||
item.addChild(actionItem)
|
||||
item.setExpanded(True)
|
||||
|
|
|
@ -380,7 +380,7 @@ class SlideController(QtGui.QWidget):
|
|||
self.previousItem.setShortcuts([QtCore.Qt.Key_Up, QtCore.Qt.Key_PageUp])
|
||||
self.previousItem.setShortcutContext(
|
||||
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.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
|
||||
actionList.add_action(self.nextItem, u'Live')
|
||||
|
|
|
@ -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:'))
|
|
@ -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)
|
||||
|
|
@ -483,7 +483,8 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
|
|||
Background Image button pushed.
|
||||
"""
|
||||
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,
|
||||
translate('OpenLP.ThemeForm', 'Select Image'), u'',
|
||||
images_filter)
|
||||
|
|
|
@ -63,28 +63,28 @@ class ThemeManager(QtGui.QWidget):
|
|||
self.layout.setObjectName(u'layout')
|
||||
self.toolbar = OpenLPToolbar(self)
|
||||
self.toolbar.addToolbarButton(
|
||||
UiStrings.NewType % UiStrings.Theme,
|
||||
translate('OpenLP.ThemeManager', 'New Theme'),
|
||||
u':/themes/theme_new.png',
|
||||
UiStrings.CreateANew % UiStrings.Theme.toLower(),
|
||||
translate('OpenLP.ThemeManager', 'Create a new theme.'),
|
||||
self.onAddTheme)
|
||||
self.toolbar.addToolbarButton(
|
||||
UiStrings.EditType % UiStrings.Theme,
|
||||
translate('OpenLP.ThemeManager', 'Edit Theme'),
|
||||
u':/themes/theme_edit.png',
|
||||
translate('OpenLP.ThemeManager', 'Edit a theme.'),
|
||||
self.onEditTheme)
|
||||
self.deleteToolbarAction = self.toolbar.addToolbarButton(
|
||||
UiStrings.DeleteType % UiStrings.Theme,
|
||||
translate('OpenLP.ThemeManager', 'Delete Theme'),
|
||||
u':/general/general_delete.png',
|
||||
translate('OpenLP.ThemeManager', 'Delete a theme.'),
|
||||
self.onDeleteTheme)
|
||||
self.toolbar.addSeparator()
|
||||
self.toolbar.addToolbarButton(
|
||||
UiStrings.ImportType % UiStrings.Theme,
|
||||
translate('OpenLP.ThemeManager', 'Import Theme'),
|
||||
u':/general/general_import.png',
|
||||
translate('OpenLP.ThemeManager', 'Import a theme.'),
|
||||
self.onImportTheme)
|
||||
self.toolbar.addToolbarButton(
|
||||
UiStrings.ExportType % UiStrings.Theme,
|
||||
translate('OpenLP.ThemeManager', 'Export Theme'),
|
||||
u':/general/general_export.png',
|
||||
translate('OpenLP.ThemeManager', 'Export a theme.'),
|
||||
self.onExportTheme)
|
||||
|
@ -314,7 +314,6 @@ class ThemeManager(QtGui.QWidget):
|
|||
translate('OpenLP.ThemeManager',
|
||||
'You must select a theme to edit.')):
|
||||
item = self.themeListWidget.currentItem()
|
||||
themeName = unicode(item.text())
|
||||
theme = self.getThemeData(
|
||||
unicode(item.data(QtCore.Qt.UserRole).toString()))
|
||||
if theme.background_type == u'image':
|
||||
|
@ -406,8 +405,8 @@ class ThemeManager(QtGui.QWidget):
|
|||
files = QtGui.QFileDialog.getOpenFileNames(self,
|
||||
translate('OpenLP.ThemeManager', 'Select Theme Import File'),
|
||||
SettingsManager.get_last_dir(self.settingsSection),
|
||||
translate('OpenLP.ThemeManager', 'Theme v1 (*.theme);;'
|
||||
'Theme v2 (*.otz);;%s (*.*)') % UiStrings.AllFiles)
|
||||
unicode(translate('OpenLP.ThemeManager',
|
||||
'OpenLP Themes (*.theme *.otz)')))
|
||||
log.info(u'New Themes %s', unicode(files))
|
||||
if files:
|
||||
for file in files:
|
||||
|
@ -530,6 +529,18 @@ class ThemeManager(QtGui.QWidget):
|
|||
else:
|
||||
outfile = open(fullpath, u'wb')
|
||||
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:
|
||||
theme = self._createThemeFromXml(filexml, self.path)
|
||||
self.generateAndSaveImage(dir, themename, theme)
|
||||
|
@ -540,17 +551,6 @@ class ThemeManager(QtGui.QWidget):
|
|||
'File is not a valid theme.'))
|
||||
log.exception(u'Theme file does not contain XML data %s' %
|
||||
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):
|
||||
"""
|
||||
|
|
|
@ -164,28 +164,34 @@ def _get_os_dir_path(dir_type):
|
|||
"""
|
||||
Return a path based on which OS and environment we are running in.
|
||||
"""
|
||||
encoding = sys.getfilesystemencoding()
|
||||
if sys.platform == u'win32':
|
||||
if dir_type == AppLocation.DataDir:
|
||||
return os.path.join(os.getenv(u'APPDATA'), u'openlp', u'data')
|
||||
return os.path.join(os.getenv(u'APPDATA'), u'openlp')
|
||||
return os.path.join(unicode(os.getenv(u'APPDATA'), encoding),
|
||||
u'openlp', u'data')
|
||||
return os.path.join(unicode(os.getenv(u'APPDATA'), encoding),
|
||||
u'openlp')
|
||||
elif sys.platform == u'darwin':
|
||||
if dir_type == AppLocation.DataDir:
|
||||
return os.path.join(os.getenv(u'HOME'), u'Library',
|
||||
u'Application Support', u'openlp', u'Data')
|
||||
return os.path.join(os.getenv(u'HOME'), u'Library',
|
||||
u'Application Support', u'openlp')
|
||||
return os.path.join(unicode(os.getenv(u'HOME'), encoding),
|
||||
u'Library', u'Application Support', u'openlp', u'Data')
|
||||
return os.path.join(unicode(os.getenv(u'HOME'), encoding),
|
||||
u'Library', u'Application Support', u'openlp')
|
||||
else:
|
||||
if XDG_BASE_AVAILABLE:
|
||||
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:
|
||||
return os.path.join(BaseDirectory.xdg_data_home, u'openlp',
|
||||
u'data')
|
||||
return os.path.join(
|
||||
unicode(BaseDirectory.xdg_data_home, encoding), u'openlp')
|
||||
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:
|
||||
return os.path.join(os.getenv(u'HOME'), u'.openlp', u'data')
|
||||
return os.path.join(os.getenv(u'HOME'), u'.openlp')
|
||||
return os.path.join(unicode(os.getenv(u'HOME'), encoding),
|
||||
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):
|
||||
"""
|
||||
|
@ -376,13 +382,13 @@ def get_uno_command():
|
|||
"""
|
||||
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':
|
||||
return u'openoffice.org -nologo -norestore -minimized -invisible ' \
|
||||
+ u'-nofirststartwizard -accept=pipe,name=openlp_pipe;urp;'
|
||||
CONNECTION = u'"-accept=pipe,name=openlp_pipe;urp;"'
|
||||
else:
|
||||
return u'openoffice.org -nologo -norestore -minimized ' \
|
||||
+ u'-invisible -nofirststartwizard ' \
|
||||
+ u'-accept=socket,host=localhost,port=2002;urp;'
|
||||
CONNECTION = u'"-accept=socket,host=localhost,port=2002;urp;"'
|
||||
return u'%s %s %s' % (COMMAND, OPTIONS, CONNECTION)
|
||||
|
||||
def get_uno_instance(resolver):
|
||||
"""
|
||||
|
|
|
@ -29,7 +29,6 @@ import logging
|
|||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
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
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
@ -129,9 +128,15 @@ class BiblePlugin(Plugin):
|
|||
u'title': translate('BiblesPlugin', 'Bibles', 'container title')
|
||||
}
|
||||
# Middle Header Bar
|
||||
## Import Action ##
|
||||
self.textStrings[StringContent.Import] = {
|
||||
u'title': UiStrings.Import,
|
||||
u'tooltip': translate('BiblesPlugin', 'Import a Bible')
|
||||
tooltips = {
|
||||
u'load': u'',
|
||||
u'import': 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)
|
||||
|
|
|
@ -30,7 +30,6 @@ from forms import EditCustomForm
|
|||
|
||||
from openlp.core.lib import Plugin, StringContent, build_icon, translate
|
||||
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.db import CustomSlide, init_schema
|
||||
|
||||
|
@ -106,13 +105,20 @@ class CustomPlugin(Plugin):
|
|||
u'title': translate('CustomsPlugin', 'Custom', 'container title')
|
||||
}
|
||||
# Middle Header Bar
|
||||
## Import Action ##
|
||||
self.textStrings[StringContent.Import] = {
|
||||
u'title': UiStrings.Import,
|
||||
u'tooltip': translate('CustomsPlugin',
|
||||
'Import a Custom')
|
||||
tooltips = {
|
||||
u'load': translate('CustomsPlugin', 'Load a new Custom'),
|
||||
u'import': translate('CustomsPlugin', 'Import a Custom'),
|
||||
u'new': translate('CustomsPlugin', 'Add a new 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):
|
||||
"""
|
||||
|
|
|
@ -69,4 +69,15 @@ class ImagePlugin(Plugin):
|
|||
u'title': translate('ImagePlugin', 'Images', 'container title')
|
||||
}
|
||||
# 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)
|
||||
|
|
|
@ -32,6 +32,7 @@ from PyQt4 import QtCore, QtGui
|
|||
from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \
|
||||
SettingsManager, translate, check_item_selected, Receiver
|
||||
from openlp.core.lib.ui import UiStrings, critical_error_message_box
|
||||
from PyQt4.phonon import Phonon
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -48,9 +49,13 @@ class MediaMediaItem(MediaManagerItem):
|
|||
u':/media/media_video.png').toImage()
|
||||
MediaManagerItem.__init__(self, parent, self, icon)
|
||||
self.singleServiceItem = False
|
||||
self.mediaObject = Phonon.MediaObject(self)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'video_background_replaced'),
|
||||
self.videobackgroundReplaced)
|
||||
QtCore.QObject.connect(self.mediaObject,
|
||||
QtCore.SIGNAL(u'stateChanged(Phonon::State, Phonon::State)'),
|
||||
self.videoStart)
|
||||
|
||||
def retranslateUi(self):
|
||||
self.OnNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media')
|
||||
|
@ -120,13 +125,22 @@ class MediaMediaItem(MediaManagerItem):
|
|||
return False
|
||||
filename = unicode(item.data(QtCore.Qt.UserRole).toString())
|
||||
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(
|
||||
translate('MediaPlugin.MediaItem', 'Media'))
|
||||
service_item.add_capability(ItemCapabilities.RequiresMedia)
|
||||
service_item.add_capability(ItemCapabilities.AllowsVarableStartTime)
|
||||
# force a nonexistent theme
|
||||
service_item.theme = -1
|
||||
frame = u':/media/image_clapperboard.png'
|
||||
(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)
|
||||
return True
|
||||
else:
|
||||
|
@ -164,3 +178,12 @@ class MediaMediaItem(MediaManagerItem):
|
|||
item_name.setIcon(build_icon(img))
|
||||
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
|
||||
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()
|
||||
|
|
|
@ -95,4 +95,15 @@ class MediaPlugin(Plugin):
|
|||
u'title': translate('MediaPlugin', 'Media', 'container title')
|
||||
}
|
||||
# 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)
|
||||
|
|
|
@ -147,8 +147,10 @@ class PowerpointDocument(PresentationDocument):
|
|||
"""
|
||||
if self.check_thumbnails():
|
||||
return
|
||||
self.presentation.Export(os.path.join(self.get_thumbnail_folder(), ''),
|
||||
'png', 320, 240)
|
||||
for num in range(0, self.presentation.Slides.Count):
|
||||
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):
|
||||
"""
|
||||
|
|
|
@ -154,8 +154,9 @@ class PptviewDocument(PresentationDocument):
|
|||
being shut down
|
||||
"""
|
||||
log.debug(u'ClosePresentation')
|
||||
self.controller.process.ClosePPT(self.pptid)
|
||||
self.pptid = -1
|
||||
if self.controller.process:
|
||||
self.controller.process.ClosePPT(self.pptid)
|
||||
self.pptid = -1
|
||||
self.controller.remove_doc(self)
|
||||
|
||||
def is_loaded(self):
|
||||
|
|
|
@ -167,4 +167,18 @@ class PresentationPlugin(Plugin):
|
|||
'container title')
|
||||
}
|
||||
# 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)
|
||||
|
|
|
@ -161,6 +161,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||
|
||||
def newSong(self):
|
||||
log.debug(u'New Song')
|
||||
self.song = None
|
||||
self.initialise()
|
||||
self.songTabWidget.setCurrentIndex(0)
|
||||
self.titleEdit.setText(u'')
|
||||
|
|
|
@ -252,6 +252,7 @@ class SongExportForm(OpenLPWizard):
|
|||
self.availableListWidget.clear()
|
||||
self.selectedListWidget.clear()
|
||||
self.directoryLineEdit.clear()
|
||||
self.searchLineEdit.clear()
|
||||
# Load the list of songs.
|
||||
Receiver.send_message(u'cursor_busy')
|
||||
songs = self.plugin.manager.get_all_objects(Song)
|
||||
|
@ -340,19 +341,21 @@ class SongExportForm(OpenLPWizard):
|
|||
|
||||
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()):
|
||||
item = self.availableListWidget.item(row)
|
||||
item.setCheckState(QtCore.Qt.Unchecked)
|
||||
if not item.isHidden():
|
||||
item.setCheckState(QtCore.Qt.Unchecked)
|
||||
|
||||
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()):
|
||||
item = self.availableListWidget.item(row)
|
||||
item.setCheckState(QtCore.Qt.Checked)
|
||||
if not item.isHidden():
|
||||
item.setCheckState(QtCore.Qt.Checked)
|
||||
|
||||
def onDirectoryButtonClicked(self):
|
||||
"""
|
||||
|
|
|
@ -140,6 +140,12 @@ class SongImportForm(OpenLPWizard):
|
|||
QtCore.QObject.connect(self.songBeamerRemoveButton,
|
||||
QtCore.SIGNAL(u'clicked()'),
|
||||
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):
|
||||
"""
|
||||
|
@ -188,6 +194,8 @@ class SongImportForm(OpenLPWizard):
|
|||
self.addFileSelectItem(u'ew', single_select=True)
|
||||
# Words of Worship
|
||||
self.addFileSelectItem(u'songBeamer')
|
||||
# Song Show Plus
|
||||
self.addFileSelectItem(u'songShowPlus')
|
||||
# Commented out for future use.
|
||||
# self.addFileSelectItem(u'csv', u'CSV', single_select=True)
|
||||
self.sourceLayout.addLayout(self.formatStack)
|
||||
|
@ -237,6 +245,8 @@ class SongImportForm(OpenLPWizard):
|
|||
translate('SongsPlugin.ImportWizardForm', 'EasyWorship'))
|
||||
self.formatComboBox.setItemText(10,
|
||||
translate('SongsPlugin.ImportWizardForm', 'SongBeamer'))
|
||||
self.formatComboBox.setItemText(11,
|
||||
translate('SongsPlugin.ImportWizardForm', 'SongShow Plus'))
|
||||
# self.formatComboBox.setItemText(11,
|
||||
# translate('SongsPlugin.ImportWizardForm', 'CSV'))
|
||||
self.openLP2FilenameLabel.setText(
|
||||
|
@ -301,6 +311,10 @@ class SongImportForm(OpenLPWizard):
|
|||
translate('SongsPlugin.ImportWizardForm', 'Add Files...'))
|
||||
self.songBeamerRemoveButton.setText(
|
||||
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(
|
||||
# translate('SongsPlugin.ImportWizardForm', 'Filename:'))
|
||||
# self.csvBrowseButton.setText(
|
||||
|
@ -438,6 +452,16 @@ class SongImportForm(OpenLPWizard):
|
|||
'file to import from.'))
|
||||
self.songBeamerAddButton.setFocus()
|
||||
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
|
||||
elif self.currentPage() == self.progressPage:
|
||||
return True
|
||||
|
@ -456,7 +480,7 @@ class SongImportForm(OpenLPWizard):
|
|||
The file extension filters. It should contain the file descriptions
|
||||
as well as the file extensions. For example::
|
||||
|
||||
u'SongBeamer files (*.sng)'
|
||||
u'SongBeamer Files (*.sng)'
|
||||
"""
|
||||
if filters:
|
||||
filters += u';;'
|
||||
|
@ -585,7 +609,7 @@ class SongImportForm(OpenLPWizard):
|
|||
'Select Songs of Fellowship Files'),
|
||||
self.songsOfFellowshipFileListWidget, u'%s (*.rtf)'
|
||||
% translate('SongsPlugin.ImportWizardForm',
|
||||
'Songs Of Felloship Song Files')
|
||||
'Songs Of Fellowship Song Files')
|
||||
)
|
||||
|
||||
def onSongsOfFellowshipRemoveButtonClicked(self):
|
||||
|
@ -635,7 +659,7 @@ class SongImportForm(OpenLPWizard):
|
|||
translate('SongsPlugin.ImportWizardForm',
|
||||
'Select SongBeamer Files'),
|
||||
self.songBeamerFileListWidget, u'%s (*.sng)' %
|
||||
translate('SongsPlugin.ImportWizardForm', 'SongBeamer files')
|
||||
translate('SongsPlugin.ImportWizardForm', 'SongBeamer Files')
|
||||
)
|
||||
|
||||
def onSongBeamerRemoveButtonClicked(self):
|
||||
|
@ -644,6 +668,24 @@ class SongImportForm(OpenLPWizard):
|
|||
"""
|
||||
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):
|
||||
"""
|
||||
Set default form values for the song import wizard.
|
||||
|
@ -663,6 +705,7 @@ class SongImportForm(OpenLPWizard):
|
|||
self.easiSlidesFilenameEdit.setText(u'')
|
||||
self.ewFilenameEdit.setText(u'')
|
||||
self.songBeamerFileListWidget.clear()
|
||||
self.songShowPlusFileListWidget.clear()
|
||||
#self.csvFilenameEdit.setText(u'')
|
||||
|
||||
def preWizard(self):
|
||||
|
@ -739,6 +782,12 @@ class SongImportForm(OpenLPWizard):
|
|||
importer = self.plugin.importSongs(SongFormat.SongBeamer,
|
||||
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():
|
||||
self.progressLabel.setText(
|
||||
translate('SongsPlugin.SongImportForm', 'Finished import.'))
|
||||
|
|
|
@ -457,7 +457,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
|||
|
||||
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,
|
||||
translate('SongsPlugin.SongMaintenanceForm', 'Delete Topic'),
|
||||
|
@ -470,7 +470,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
|||
|
||||
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,
|
||||
translate('SongsPlugin.SongMaintenanceForm', 'Delete Book'),
|
||||
|
|
|
@ -81,14 +81,16 @@ class EasiSlidesImport(SongImport):
|
|||
|
||||
def _parse_song(self, song):
|
||||
self._success = True
|
||||
self._add_unicode_attribute(self.title, song.Title1, True)
|
||||
self._add_unicode_attribute(self.alternate_title, song.Title2)
|
||||
self._add_unicode_attribute(self.song_number, song.SongNumber)
|
||||
self._add_unicode_attribute(u'title', song.Title1, True)
|
||||
self._add_unicode_attribute(u'alternate_title', song.Title2)
|
||||
self._add_unicode_attribute(u'song_number', song.SongNumber)
|
||||
if self.song_number == u'0':
|
||||
self.song_number = u''
|
||||
self._add_authors(song)
|
||||
self._add_copyright(song)
|
||||
self._add_unicode_attribute(self.song_book_name, song.BookReference)
|
||||
self._add_copyright(song.Copyright)
|
||||
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)
|
||||
return self._success
|
||||
|
||||
|
@ -110,7 +112,7 @@ class EasiSlidesImport(SongImport):
|
|||
Signals that this attribute must exist in a valid song.
|
||||
"""
|
||||
try:
|
||||
self_attribute = unicode(import_attribute).strip()
|
||||
setattr(self, self_attribute, unicode(import_attribute).strip())
|
||||
except UnicodeDecodeError:
|
||||
log.exception(u'UnicodeDecodeError decoding %s' % import_attribute)
|
||||
self._success = False
|
||||
|
@ -124,7 +126,7 @@ class EasiSlidesImport(SongImport):
|
|||
authors = unicode(song.Writer).split(u',')
|
||||
for author in authors:
|
||||
author = author.strip()
|
||||
if len(author) > 0:
|
||||
if len(author):
|
||||
self.authors.append(author)
|
||||
except UnicodeDecodeError:
|
||||
log.exception(u'Unicode decode error while decoding Writer')
|
||||
|
@ -132,35 +134,18 @@ class EasiSlidesImport(SongImport):
|
|||
except AttributeError:
|
||||
pass
|
||||
|
||||
def _add_copyright(self, song):
|
||||
"""
|
||||
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):
|
||||
def _add_copyright(self, element):
|
||||
"""
|
||||
Add a piece of copyright to the total copyright information for the
|
||||
song.
|
||||
|
||||
``copyright_list``
|
||||
The array to add the information to.
|
||||
|
||||
``element``
|
||||
The imported variable to get the data from.
|
||||
"""
|
||||
try:
|
||||
copyright_list.append(unicode(element).strip())
|
||||
self.add_copyright(unicode(element).strip())
|
||||
except UnicodeDecodeError:
|
||||
log.exception(u'Unicode error decoding %s' % element)
|
||||
log.exception(u'Unicode error on decoding copyright: %s' % element)
|
||||
self._success = False
|
||||
except AttributeError:
|
||||
pass
|
||||
|
@ -285,10 +270,12 @@ class EasiSlidesImport(SongImport):
|
|||
# as these appeared originally in the file
|
||||
for [reg, vt, vn, inst] in our_verse_order:
|
||||
if self._listHas(verses, [reg, vt, vn, inst]):
|
||||
# this is false, but needs user input
|
||||
lang = None
|
||||
versetag = u'%s%s' % (vt, vn)
|
||||
versetags.append(versetag)
|
||||
lines = u'\n'.join(verses[reg][vt][vn][inst])
|
||||
self.verses.append([versetag, lines])
|
||||
self.verses.append([versetag, lines, lang])
|
||||
|
||||
SeqTypes = {
|
||||
u'p': u'P1',
|
||||
|
|
|
@ -34,6 +34,7 @@ from wowimport import WowImport
|
|||
from cclifileimport import CCLIFileImport
|
||||
from ewimport import EasyWorshipSongImport
|
||||
from songbeamerimport import SongBeamerImport
|
||||
from songshowplusimport import SongShowPlusImport
|
||||
# Imports that might fail
|
||||
try:
|
||||
from olp1import import OpenLP1SongImport
|
||||
|
@ -67,10 +68,11 @@ class SongFormat(object):
|
|||
CCLI = 5
|
||||
SongsOfFellowship = 6
|
||||
Generic = 7
|
||||
#CSV = 8
|
||||
EasiSlides = 8
|
||||
EasyWorship = 9
|
||||
SongBeamer = 10
|
||||
SongShowPlus = 11
|
||||
#CSV = 12
|
||||
|
||||
@staticmethod
|
||||
def get_class(format):
|
||||
|
@ -102,6 +104,8 @@ class SongFormat(object):
|
|||
return EasyWorshipSongImport
|
||||
elif format == SongFormat.SongBeamer:
|
||||
return SongBeamerImport
|
||||
elif format == SongFormat.SongShowPlus:
|
||||
return SongShowPlusImport
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
|
@ -120,7 +124,8 @@ class SongFormat(object):
|
|||
SongFormat.Generic,
|
||||
SongFormat.EasiSlides,
|
||||
SongFormat.EasyWorship,
|
||||
SongFormat.SongBeamer
|
||||
SongFormat.SongBeamer,
|
||||
SongFormat.SongShowPlus
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -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
|
|
@ -228,7 +228,18 @@ class SongsPlugin(Plugin):
|
|||
u'title': translate('SongsPlugin', 'Songs', 'container title')
|
||||
}
|
||||
# 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):
|
||||
"""
|
||||
|
|
|
@ -68,6 +68,7 @@ Source: ..\..\dist\OpenLP\*; DestDir: {app}; Flags: ignoreversion recursesubdirs
|
|||
|
||||
[Icons]
|
||||
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:UninstallProgram,{#AppName}}; Filename: {uninstallexe}
|
||||
Name: {commondesktop}\{#AppName}; Filename: {app}\{#AppExeName}; Tasks: desktopicon
|
||||
|
|
Loading…
Reference in New Issue