This commit is contained in:
Andreas Preikschat 2011-03-29 20:03:42 +02:00
commit dabf9d36fe
26 changed files with 486 additions and 244 deletions

View File

@ -42,7 +42,7 @@ master_doc = 'index'
# General information about the project.
project = u'OpenLP'
copyright = u'2010, Raoul Snyman'
copyright = u'2004 - 2011, Raoul Snyman'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@ -92,19 +92,30 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
if sys.argv[2] == 'qthelp' or sys.argv[2] == 'htmlhelp':
html_theme = 'openlp_qthelp'
else:
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
if sys.argv[2] == 'html':
html_theme_options = {
'sidebarbgcolor': '#3a60a9',
'relbarbgcolor': '#203b6f',
'footerbgcolor': '#26437c',
'headtextcolor': '#203b6f',
'linkcolor': '#26437c',
'sidebarlinkcolor': '#ceceff'
}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
html_theme_path = [os.path.join(os.path.abspath('..'), 'themes')]
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
html_title = u'OpenLP 2.0 Reference Manual'
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
@ -125,7 +136,7 @@ html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
@ -165,7 +176,7 @@ html_static_path = ['_static']
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'OpenLPdoc'
htmlhelp_basename = 'OpenLP'
# -- Options for LaTeX output --------------------------------------------------
@ -179,7 +190,7 @@ htmlhelp_basename = 'OpenLPdoc'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'OpenLP.tex', u'OpenLP Documentation',
('index', 'OpenLP.tex', u'OpenLP Reference Manual',
u'Wesley Stout', 'manual'),
]
@ -212,6 +223,6 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'openlp', u'OpenLP Documentation',
('index', 'openlp', u'OpenLP Reference Manual',
[u'Wesley Stout'], 1)
]

View File

@ -38,6 +38,7 @@ from traceback import format_exception
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, check_directory_exists
from openlp.core.lib.ui import UiStrings
from openlp.core.resources import qInitResources
from openlp.core.ui.mainwindow import MainWindow
from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm
@ -77,6 +78,13 @@ class OpenLP(QtGui.QApplication):
class in order to provide the core of the application.
"""
def exec_(self):
"""
Override exec method to allow the shared memory to be released on exit
"""
QtGui.QApplication.exec_()
self.sharedMemory.detach()
def run(self):
"""
Run the OpenLP application.
@ -107,7 +115,8 @@ class OpenLP(QtGui.QApplication):
# make sure Qt really display the splash screen
self.processEvents()
# start the main app window
self.mainWindow = MainWindow(screens, self.clipboard())
self.mainWindow = MainWindow(screens, self.clipboard(),
self.arguments())
self.mainWindow.show()
if show_splash:
# now kill the splashscreen
@ -122,6 +131,24 @@ class OpenLP(QtGui.QApplication):
VersionThread(self.mainWindow).start()
return self.exec_()
def isAlreadyRunning(self):
"""
Look to see if OpenLP is already running and ask if a 2nd copy
is to be started.
"""
self.sharedMemory = QtCore.QSharedMemory('OpenLP')
if self.sharedMemory.attach():
status = QtGui.QMessageBox.critical(None,
UiStrings.Error, UiStrings.OpenLPStart,
QtGui.QMessageBox.StandardButtons(
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No))
if status == QtGui.QMessageBox.No:
return True
return False
else:
self.sharedMemory.create(1)
return False
def hookException(self, exctype, value, traceback):
if not hasattr(self, u'mainWindow'):
log.exception(''.join(format_exception(exctype, value, traceback)))
@ -194,6 +221,9 @@ def main():
qInitResources()
# Now create and actually run the application.
app = OpenLP(qt_args)
# Instance check
if app.isAlreadyRunning():
sys.exit()
app.setOrganizationName(u'OpenLP')
app.setOrganizationDomain(u'openlp.org')
app.setApplicationName(u'OpenLP')

View File

@ -101,6 +101,10 @@ class EventReceiver(QtCore.QObject):
``servicemanager_previous_item``
Display the previous item in the service
``servicemanager_preview_live``
Requests a Preview item from the Service Manager to update live and
add a new item to the preview panel
``servicemanager_next_item``
Display the next item in the service

View File

@ -85,7 +85,12 @@ body {
}
/* lyric css */
%s
sup {
font-size:0.6em;
vertical-align:top;
position:relative;
top:-0.3em;
}
</style>
<script language="javascript">
var timer = null;

View File

@ -145,7 +145,8 @@ class RenderManager(object):
else:
self.theme = self.service_theme
else:
if theme:
# Images have a theme of -1
if theme and theme != -1:
self.theme = theme
elif theme_level == ThemeLevel.Song or \
theme_level == ThemeLevel.Service:

View File

@ -109,7 +109,9 @@ class ServiceItem(object):
self.edit_id = None
self.xml_version = None
self.start_time = 0
self.end_time = 0
self.media_length = 0
self.from_service = False
self._new_item()
def _new_item(self):
@ -261,6 +263,7 @@ class ServiceItem(object):
u'data': self.data_string,
u'xml_version': self.xml_version,
u'start_time': self.start_time,
u'end_time': self.end_time,
u'media_length': self.media_length
}
service_data = []
@ -307,6 +310,8 @@ class ServiceItem(object):
self.xml_version = header[u'xml_version']
if u'start_time' in header:
self.start_time = header[u'start_time']
if u'end_time' in header:
self.end_time = header[u'end_time']
if u'media_length' in header:
self.media_length = header[u'media_length']
if self.service_item_type == ServiceItemType.Text:
@ -449,4 +454,3 @@ class ServiceItem(object):
return end
else:
return u'%s : %s' % (start, end)

View File

@ -57,6 +57,7 @@ class UiStrings(object):
Export = translate('OpenLP.Ui', 'Export')
FontSizePtUnit = translate('OpenLP.Ui', 'pt',
'Abbreviated font pointsize unit')
Hours = translate('OpenLP.Ui', 'h', 'The abbreviated unit for hours')
Image = translate('OpenLP.Ui', 'Image')
Import = translate('OpenLP.Ui', 'Import')
LengthTime = unicode(translate('OpenLP.Ui', 'Length %s'))
@ -64,6 +65,7 @@ class UiStrings(object):
LiveBGError = translate('OpenLP.Ui', 'Live Background Error')
LivePanel = translate('OpenLP.Ui', 'Live Panel')
Load = translate('OpenLP.Ui', 'Load')
Minutes = translate('OpenLP.Ui', 'm', 'The abbreviated unit for minutes')
Middle = translate('OpenLP.Ui', 'Middle')
New = translate('OpenLP.Ui', 'New')
NewService = translate('OpenLP.Ui', 'New Service')
@ -74,6 +76,8 @@ class UiStrings(object):
NISp = translate('OpenLP.Ui', 'No Items Selected', 'Plural')
OLPV1 = translate('OpenLP.Ui', 'openlp.org 1.x')
OLPV2 = translate('OpenLP.Ui', 'OpenLP 2.0')
OpenLPStart = translate('OpenLP.Ui', 'OpenLP is already running. Do you '
'wish to continue?')
OpenService = translate('OpenLP.Ui', 'Open Service')
Preview = translate('OpenLP.Ui', 'Preview')
PreviewPanel = translate('OpenLP.Ui', 'Preview Panel')
@ -82,7 +86,7 @@ class UiStrings(object):
ReplaceLiveBG = translate('OpenLP.Ui', 'Replace Live Background')
ResetBG = translate('OpenLP.Ui', 'Reset Background')
ResetLiveBG = translate('OpenLP.Ui', 'Reset Live Background')
S = translate('OpenLP.Ui', 's', 'The abbreviated unit for seconds')
Seconds = translate('OpenLP.Ui', 's', 'The abbreviated unit for seconds')
SaveAndPreview = translate('OpenLP.Ui', 'Save && Preview')
Search = translate('OpenLP.Ui', 'Search')
SelectDelete = translate('OpenLP.Ui', 'You must select an item to delete.')

View File

@ -57,6 +57,7 @@ except ImportError:
from openlp.core.lib import translate, SettingsManager
from openlp.core.lib.mailto import mailto
from openlp.core.lib.ui import UiStrings
from openlp.core.utils import get_application_version
from exceptiondialog import Ui_ExceptionDialog
@ -78,7 +79,7 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
return QtGui.QDialog.exec_(self)
def _createReport(self):
openlp_version = self.parent().applicationVersion[u'full']
openlp_version = get_application_version()
description = unicode(self.descriptionTextEdit.toPlainText())
traceback = unicode(self.exceptionTextEdit.toPlainText())
system = unicode(translate('OpenLP.ExceptionForm',

View File

@ -105,6 +105,9 @@ class GeneralTab(SettingsTab):
self.saveCheckServiceCheckBox = QtGui.QCheckBox(self.settingsGroupBox)
self.saveCheckServiceCheckBox.setObjectName(u'saveCheckServiceCheckBox')
self.settingsLayout.addRow(self.saveCheckServiceCheckBox)
self.autoUnblankCheckBox = QtGui.QCheckBox(self.settingsGroupBox)
self.autoUnblankCheckBox.setObjectName(u'autoUnblankCheckBox')
self.settingsLayout.addRow(self.autoUnblankCheckBox)
self.autoPreviewCheckBox = QtGui.QCheckBox(self.settingsGroupBox)
self.autoPreviewCheckBox.setObjectName(u'autoPreviewCheckBox')
self.settingsLayout.addRow(self.autoPreviewCheckBox)
@ -224,6 +227,8 @@ class GeneralTab(SettingsTab):
translate('OpenLP.GeneralTab', 'Application Settings'))
self.saveCheckServiceCheckBox.setText(translate('OpenLP.GeneralTab',
'Prompt to save before starting a new service'))
self.autoUnblankCheckBox.setText(translate('OpenLP.GeneralTab',
'Unblank display when adding new live item'))
self.autoPreviewCheckBox.setText(translate('OpenLP.GeneralTab',
'Automatically preview next item in service'))
self.timeoutLabel.setText(translate('OpenLP.GeneralTab',
@ -262,6 +267,8 @@ class GeneralTab(SettingsTab):
u'songselect password', QtCore.QVariant(u'')).toString()))
self.saveCheckServiceCheckBox.setChecked(settings.value(u'save prompt',
QtCore.QVariant(False)).toBool())
self.autoUnblankCheckBox.setChecked(settings.value(u'auto unblank',
QtCore.QVariant(False)).toBool())
self.monitorComboBox.setCurrentIndex(self.monitorNumber)
self.displayOnMonitorCheck.setChecked(self.screens.display)
self.warningCheckBox.setChecked(settings.value(u'blank warning',
@ -312,6 +319,8 @@ class GeneralTab(SettingsTab):
QtCore.QVariant(self.checkForUpdatesCheckBox.isChecked()))
settings.setValue(u'save prompt',
QtCore.QVariant(self.saveCheckServiceCheckBox.isChecked()))
settings.setValue(u'auto unblank',
QtCore.QVariant(self.autoUnblankCheckBox.isChecked()))
settings.setValue(u'auto preview',
QtCore.QVariant(self.autoPreviewCheckBox.isChecked()))
settings.setValue(u'loop delay',

View File

@ -367,7 +367,7 @@ class MainDisplay(DisplayWidget):
self.mediaObject.setCurrentSource(Phonon.MediaSource(videoPath))
# Need the timer to trigger set the trigger to 200ms
# Value taken from web documentation.
if self.serviceItem.start_time != 0:
if self.serviceItem.end_time != 0:
self.mediaObject.setTickInterval(200)
self.mediaObject.play()
self.webView.setVisible(False)
@ -401,9 +401,9 @@ class MainDisplay(DisplayWidget):
def videoTick(self, tick):
"""
Triggered on video tick every 200 milli seconds
Will be used to manage stop time later
"""
pass
if tick > self.serviceItem.end_time * 1000:
self.videoFinished()
def isWebLoaded(self):
"""
@ -489,6 +489,10 @@ class MainDisplay(DisplayWidget):
self.footer(serviceItem.foot_text)
# if was hidden keep it hidden
if self.hideMode and self.isLive:
if QtCore.QSettings().value(u'general/auto unblank',
QtCore.QVariant(False)).toBool():
Receiver.send_message(u'slidecontroller_live_unblank')
else:
self.hideDisplay(self.hideMode)
# display hidden for video end we have a new item so must be shown
if self.videoHide and self.isLive:

View File

@ -469,7 +469,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
actionList = ActionList()
def __init__(self, screens, clipboard):
def __init__(self, screens, clipboard, arguments):
"""
This constructor sets up the interface, the various managers, and the
plugins.
@ -477,6 +477,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
QtGui.QMainWindow.__init__(self)
self.screens = screens
self.clipboard = clipboard
self.arguments = arguments
# Set up settings sections for the main application
# (not for use by plugins)
self.uiSettingsSection = u'user interface'
@ -660,7 +661,16 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
if self.liveController.display.isVisible():
self.liveController.display.setFocus()
self.activateWindow()
if QtCore.QSettings().value(
# On Windows, arguments contains the entire commandline
# So args[0]=='python' args[1]=='openlp.pyw'
# Therefore this approach is not going to work
# Bypass for now.
if len(self.arguments) and os.name != u'nt':
args = []
for a in self.arguments:
args.extend([a])
self.ServiceManagerContents.loadFile(unicode(args[0]))
elif QtCore.QSettings().value(
self.generalSettingsSection + u'/auto open',
QtCore.QVariant(False)).toBool():
self.ServiceManagerContents.loadLastFile()

View File

@ -33,12 +33,12 @@ from openlp.core.ui.printservicedialog import Ui_PrintServiceDialog, ZoomSize
class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
def __init__(self, parent, serviceManager):
def __init__(self, mainWindow, serviceManager):
"""
Constructor
"""
QtGui.QDialog.__init__(self, parent)
self.parent = parent
QtGui.QDialog.__init__(self, mainWindow)
self.mainWindow = mainWindow
self.serviceManager = serviceManager
self.printer = QtGui.QPrinter()
self.printDialog = QtGui.QPrintDialog(self.printer, self)
@ -134,9 +134,12 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
item.notes.replace(u'\n', u'<br />'))
# Add play length of media files.
if item.is_media() and self.metaDataCheckBox.isChecked():
tme = item.media_length
if item.end_time > 0:
tme = item.end_time - item.start_time
text += u'<p><strong>%s</strong> %s</p>' % (translate(
'OpenLP.ServiceManager', u'Playing time:'),
unicode(datetime.timedelta(seconds=item.media_length)))
unicode(datetime.timedelta(seconds=tme)))
if self.footerTextEdit.toPlainText():
text += u'<h4>%s</h4>%s' % (translate('OpenLP.ServiceManager',
u'Custom Service Notes:'), self.footerTextEdit.toPlainText())
@ -181,13 +184,14 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
"""
Copies the display text to the clipboard as plain text
"""
self.parent.clipboard.setText(self.document.toPlainText())
self.mainWindow.clipboard.setText(
self.document.toPlainText())
def copyHtmlText(self):
"""
Copies the display text to the clipboard as Html
"""
self.parent.clipboard.setText(self.document.toHtml())
self.mainWindow.clipboard.setText(self.document.toHtml())
def printServiceOrder(self):
"""

View File

@ -141,4 +141,3 @@ class ServiceItemEditForm(QtGui.QDialog, Ui_ServiceItemEditDialog):
else:
self.upButton.setEnabled(True)
self.deleteButton.setEnabled(True)

View File

@ -231,13 +231,15 @@ class ServiceManager(QtGui.QWidget):
QtCore.QObject.connect(self.themeComboBox,
QtCore.SIGNAL(u'activated(int)'), self.onThemeComboBoxSelected)
QtCore.QObject.connect(self.serviceManagerList,
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.makeLive)
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onMakeLive)
QtCore.QObject.connect(self.serviceManagerList,
QtCore.SIGNAL(u'itemCollapsed(QTreeWidgetItem*)'), self.collapsed)
QtCore.QObject.connect(self.serviceManagerList,
QtCore.SIGNAL(u'itemExpanded(QTreeWidgetItem*)'), self.expanded)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'theme_update_list'), self.updateThemeList)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'servicemanager_preview_live'), self.previewLive)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'servicemanager_next_item'), self.nextItem)
QtCore.QObject.connect(Receiver.get_receiver(),
@ -561,6 +563,7 @@ class ServiceManager(QtGui.QWidget):
self.newFile()
for item in items:
serviceItem = ServiceItem()
serviceItem.from_service = True
serviceItem.render_manager = self.mainwindow.renderManager
serviceItem.set_from_service(item, self.servicePath)
self.validateItem(serviceItem)
@ -658,10 +661,6 @@ class ServiceManager(QtGui.QWidget):
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):
@ -672,6 +671,19 @@ class ServiceManager(QtGui.QWidget):
self.addServiceItem(self.serviceItemEditForm.getServiceItem(),
replace=True, expand=self.serviceItems[item][u'expanded'])
def previewLive(self, message):
"""
Called by the SlideController to request a preview item be made live
and allows the next preview to be updated if relevent.
"""
id, row = message.split(u':')
for sitem in self.serviceItems:
if sitem[u'service_item']._uuid == id:
item = self.serviceManagerList.topLevelItem(sitem[u'order'] - 1)
self.serviceManagerList.setCurrentItem(item)
self.makeLive(int(row))
return
def nextItem(self):
"""
Called by the SlideController to select the next service item.
@ -1027,6 +1039,7 @@ class ServiceManager(QtGui.QWidget):
if expand is None:
expand = self.expandTabs
item.render()
item.from_service = True
if replace:
sitem, child = self.findServiceItem()
item.merge(self.serviceItems[sitem][u'service_item'])
@ -1081,11 +1094,24 @@ class ServiceManager(QtGui.QWidget):
else:
return self.serviceItems[item][u'service_item']
def makeLive(self):
def onMakeLive(self):
"""
Send the current item to the Live slide controller but triggered
by a tablewidget click event.
"""
self.makeLive()
def makeLive(self, row=-1):
"""
Send the current item to the Live slide controller
``row``
Row number to be displayed if from preview.
-1 is passed if the value is not set
"""
item, child = self.findServiceItem()
if row != -1:
child = row
if self.serviceItems[item][u'service_item'].is_valid:
self.mainwindow.liveController.addServiceManagerItem(
self.serviceItems[item][u'service_item'], child)

View File

@ -185,7 +185,7 @@ class SlideController(QtGui.QWidget):
self.delaySpinBox.setMinimum(1)
self.delaySpinBox.setMaximum(180)
self.toolbar.addToolbarWidget(u'Image SpinBox', self.delaySpinBox)
self.delaySpinBox.setSuffix(UiStrings.S)
self.delaySpinBox.setSuffix(UiStrings.Seconds)
self.delaySpinBox.setToolTip(translate('OpenLP.SlideController',
'Delay between slides in seconds'))
else:
@ -1014,6 +1014,10 @@ class SlideController(QtGui.QWidget):
"""
row = self.previewListWidget.currentRow()
if row > -1 and row < self.previewListWidget.rowCount():
if self.serviceItem.from_service:
Receiver.send_message('servicemanager_preview_live',
u'%s:%s' % (self.serviceItem._uuid, row))
else:
self.parent.liveController.addServiceManagerItem(
self.serviceItem, row)

View File

@ -32,39 +32,90 @@ from openlp.core.lib.ui import UiStrings, create_accept_reject_button_box
class Ui_StartTimeDialog(object):
def setupUi(self, StartTimeDialog):
StartTimeDialog.setObjectName(u'StartTimeDialog')
StartTimeDialog.resize(300, 10)
StartTimeDialog.resize(350, 10)
self.dialogLayout = QtGui.QGridLayout(StartTimeDialog)
self.dialogLayout.setObjectName(u'dialogLayout')
self.startLabel = QtGui.QLabel(StartTimeDialog)
self.startLabel.setObjectName(u'startLabel')
self.startLabel.setAlignment(QtCore.Qt.AlignHCenter)
self.dialogLayout.addWidget(self.startLabel, 0, 1, 1, 1)
self.finishLabel = QtGui.QLabel(StartTimeDialog)
self.finishLabel.setObjectName(u'finishLabel')
self.finishLabel.setAlignment(QtCore.Qt.AlignHCenter)
self.dialogLayout.addWidget(self.finishLabel, 0, 2, 1, 1)
self.lengthLabel = QtGui.QLabel(StartTimeDialog)
self.lengthLabel.setObjectName(u'startLabel')
self.lengthLabel.setAlignment(QtCore.Qt.AlignHCenter)
self.dialogLayout.addWidget(self.lengthLabel, 0, 3, 1, 1)
self.hourLabel = QtGui.QLabel(StartTimeDialog)
self.hourLabel.setObjectName("hourLabel")
self.dialogLayout.addWidget(self.hourLabel, 0, 0, 1, 1)
self.hourLabel.setObjectName(u'hourLabel')
self.dialogLayout.addWidget(self.hourLabel, 1, 0, 1, 1)
self.hourSpinBox = QtGui.QSpinBox(StartTimeDialog)
self.hourSpinBox.setObjectName("hourSpinBox")
self.dialogLayout.addWidget(self.hourSpinBox, 0, 1, 1, 1)
self.hourSpinBox.setObjectName(u'hourSpinBox')
self.hourSpinBox.setMinimum(0)
self.hourSpinBox.setMaximum(4)
self.dialogLayout.addWidget(self.hourSpinBox, 1, 1, 1, 1)
self.hourFinishSpinBox = QtGui.QSpinBox(StartTimeDialog)
self.hourFinishSpinBox.setObjectName(u'hourFinishSpinBox')
self.hourFinishSpinBox.setMinimum(0)
self.hourFinishSpinBox.setMaximum(4)
self.dialogLayout.addWidget(self.hourFinishSpinBox, 1, 2, 1, 1)
self.hourFinishLabel = QtGui.QLabel(StartTimeDialog)
self.hourFinishLabel.setObjectName(u'hourLabel')
self.hourFinishLabel.setAlignment(QtCore.Qt.AlignRight)
self.dialogLayout.addWidget(self.hourFinishLabel, 1, 3, 1, 1)
self.minuteLabel = QtGui.QLabel(StartTimeDialog)
self.minuteLabel.setObjectName("minuteLabel")
self.dialogLayout.addWidget(self.minuteLabel, 1, 0, 1, 1)
self.minuteLabel.setObjectName(u'minuteLabel')
self.dialogLayout.addWidget(self.minuteLabel, 2, 0, 1, 1)
self.minuteSpinBox = QtGui.QSpinBox(StartTimeDialog)
self.minuteSpinBox.setObjectName("minuteSpinBox")
self.dialogLayout.addWidget(self.minuteSpinBox, 1, 1, 1, 1)
self.minuteSpinBox.setObjectName(u'minuteSpinBox')
self.minuteSpinBox.setMinimum(0)
self.minuteSpinBox.setMaximum(59)
self.dialogLayout.addWidget(self.minuteSpinBox, 2, 1, 1, 1)
self.minuteFinishSpinBox = QtGui.QSpinBox(StartTimeDialog)
self.minuteFinishSpinBox.setObjectName(u'minuteFinishSpinBox')
self.minuteFinishSpinBox.setMinimum(0)
self.minuteFinishSpinBox.setMaximum(59)
self.dialogLayout.addWidget(self.minuteFinishSpinBox, 2, 2, 1, 1)
self.minuteFinishLabel = QtGui.QLabel(StartTimeDialog)
self.minuteFinishLabel.setObjectName(u'minuteLabel')
self.minuteFinishLabel.setAlignment(QtCore.Qt.AlignRight)
self.dialogLayout.addWidget(self.minuteFinishLabel, 2, 3, 1, 1)
self.secondLabel = QtGui.QLabel(StartTimeDialog)
self.secondLabel.setObjectName("secondLabel")
self.dialogLayout.addWidget(self.secondLabel, 2, 0, 1, 1)
self.secondLabel.setObjectName(u'secondLabel')
self.dialogLayout.addWidget(self.secondLabel, 3, 0, 1, 1)
self.secondSpinBox = QtGui.QSpinBox(StartTimeDialog)
self.secondSpinBox.setObjectName("secondSpinBox")
self.dialogLayout.addWidget(self.secondSpinBox, 2, 1, 1, 1)
self.secondSpinBox.setObjectName(u'secondSpinBox')
self.secondSpinBox.setMinimum(0)
self.secondSpinBox.setMaximum(59)
self.secondFinishSpinBox = QtGui.QSpinBox(StartTimeDialog)
self.secondFinishSpinBox.setObjectName(u'secondFinishSpinBox')
self.secondFinishSpinBox.setMinimum(0)
self.secondFinishSpinBox.setMaximum(59)
self.dialogLayout.addWidget(self.secondFinishSpinBox, 3, 2, 1, 1)
self.secondFinishLabel = QtGui.QLabel(StartTimeDialog)
self.secondFinishLabel.setObjectName(u'secondLabel')
self.secondFinishLabel.setAlignment(QtCore.Qt.AlignRight)
self.dialogLayout.addWidget(self.secondFinishLabel, 3, 3, 1, 1)
self.dialogLayout.addWidget(self.secondSpinBox, 3, 1, 1, 1)
self.buttonBox = create_accept_reject_button_box(StartTimeDialog, True)
self.dialogLayout.addWidget(self.buttonBox, 4, 0, 1, 2)
self.dialogLayout.addWidget(self.buttonBox, 5, 2, 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'))
'Item Start and Finish Time'))
self.hourSpinBox.setSuffix(UiStrings.Hours)
self.minuteSpinBox.setSuffix(UiStrings.Minutes)
self.secondSpinBox.setSuffix(UiStrings.Seconds)
self.hourFinishSpinBox.setSuffix(UiStrings.Hours)
self.minuteFinishSpinBox.setSuffix(UiStrings.Minutes)
self.secondFinishSpinBox.setSuffix(UiStrings.Seconds)
self.hourLabel.setText(translate('OpenLP.StartTimeForm', 'Hours:'))
self.hourSpinBox.setSuffix(translate('OpenLP.StartTimeForm', 'h'))
self.minuteSpinBox.setSuffix(translate('OpenLP.StartTimeForm', 'm'))
self.secondSpinBox.setSuffix(UiStrings.S)
self.minuteLabel.setText(translate('OpenLP.StartTimeForm', 'Minutes:'))
self.secondLabel.setText(translate('OpenLP.StartTimeForm', 'Seconds:'))
self.startLabel.setText(translate('OpenLP.StartTimeForm', 'Start'))
self.finishLabel.setText(translate('OpenLP.StartTimeForm', 'Finish'))
self.lengthLabel.setText(translate('OpenLP.StartTimeForm', 'Length'))

View File

@ -28,6 +28,9 @@ from PyQt4 import QtGui
from starttimedialog import Ui_StartTimeDialog
from openlp.core.lib import translate
from openlp.core.lib.ui import UiStrings, critical_error_message_box
class StartTimeForm(QtGui.QDialog, Ui_StartTimeDialog):
"""
The exception dialog
@ -40,13 +43,51 @@ class StartTimeForm(QtGui.QDialog, Ui_StartTimeDialog):
"""
Run the Dialog with correct heading.
"""
seconds = self.item[u'service_item'].start_time
hour, minutes, seconds = self._time_split(
self.item[u'service_item'].start_time)
self.hourSpinBox.setValue(hour)
self.minuteSpinBox.setValue(minutes)
self.secondSpinBox.setValue(seconds)
hours, minutes, seconds = self._time_split(
self.item[u'service_item'].media_length)
self.hourFinishSpinBox.setValue(hours)
self.minuteFinishSpinBox.setValue(minutes)
self.secondFinishSpinBox.setValue(seconds)
self.hourFinishLabel.setText(u'%s%s' % (unicode(hour), UiStrings.Hours))
self.minuteFinishLabel.setText(u'%s%s' %
(unicode(minutes), UiStrings.Minutes))
self.secondFinishLabel.setText(u'%s%s' %
(unicode(seconds), UiStrings.Seconds))
return QtGui.QDialog.exec_(self)
def accept(self):
start = self.hourSpinBox.value() * 3600 + \
self.minuteSpinBox.value() * 60 + \
self.secondSpinBox.value()
end = self.hourFinishSpinBox.value() * 3600 + \
self.minuteFinishSpinBox.value() * 60 + \
self.secondFinishSpinBox.value()
if end > self.item[u'service_item'].media_length:
critical_error_message_box(
title=translate('OpenLP.StartTimeForm',
'Time Validation Error'),
message=translate('OpenLP.StartTimeForm',
'End time is set after the end of the media item'))
return
elif start > end:
critical_error_message_box(
title=translate('OpenLP.StartTimeForm',
'Time Validation Error'),
message=translate('OpenLP.StartTimeForm',
'Start time is after the End Time of the media item'))
return
self.item[u'service_item'].start_time = start
self.item[u'service_item'].end_time = end
return QtGui.QDialog.accept(self)
def _time_split(self, seconds):
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)
return hours, minutes, seconds

View File

@ -91,7 +91,7 @@ class LanguageManager(object):
"""
Retrieve a saved language to use from settings
"""
settings = QtCore.QSettings(u'OpenLP', u'OpenLP')
settings = QtCore.QSettings()
language = unicode(settings.value(
u'general/language', QtCore.QVariant(u'[en]')).toString())
log.info(u'Language file: \'%s\' Loaded from conf file' % language)

View File

@ -112,7 +112,7 @@ class AlertsTab(SettingsTab):
self.FontSizeSpinBox.setSuffix(UiStrings.FontSizePtUnit)
self.TimeoutLabel.setText(
translate('AlertsPlugin.AlertsTab', 'Alert timeout:'))
self.TimeoutSpinBox.setSuffix(UiStrings.S)
self.TimeoutSpinBox.setSuffix(UiStrings.Seconds)
self.PreviewGroupBox.setTitle(UiStrings.Preview)
self.FontPreview.setText(UiStrings.OLPV2)

View File

@ -45,7 +45,7 @@ class EditCustomSlideForm(QtGui.QDialog, Ui_CustomSlideEditDialog):
self.setupUi(self)
# Connecting signals and slots
QtCore.QObject.connect(self.splitButton,
QtCore.SIGNAL(u'pressed()'), self.onSplitButtonPressed)
QtCore.SIGNAL(u'clicked()'), self.onSplitButtonPressed)
def setText(self, text):
"""

View File

@ -30,15 +30,16 @@ import chardet
import codecs
from openlp.core.lib import translate
from openlp.plugins.songs.lib import VerseType
from songimport import SongImport
log = logging.getLogger(__name__)
class CCLIFileImport(SongImport):
"""
The :class:`CCLIFileImport` class provides OpenLP with the ability to
import CCLI SongSelect song files in both .txt and .usr formats.
See http://www.ccli.com/ for more details.
The :class:`CCLIFileImport` class provides OpenLP with the ability to import
CCLI SongSelect song files in both .txt and .usr formats. See
`<http://www.ccli.com/>`_ for more details.
"""
def __init__(self, manager, **kwargs):
@ -55,7 +56,7 @@ class CCLIFileImport(SongImport):
def do_import(self):
"""
Import either a .usr or a .txt SongSelect file
Import either a ``.usr`` or a ``.txt`` SongSelect file.
"""
log.debug(u'Starting CCLI File Import')
song_total = len(self.import_source)
@ -67,6 +68,7 @@ class CCLIFileImport(SongImport):
(song_count, song_total))
filename = unicode(filename)
log.debug(u'Importing CCLI File: %s', filename)
self.set_defaults()
lines = []
if os.path.isfile(filename):
detect_file = open(filename, u'r')
@ -81,12 +83,10 @@ class CCLIFileImport(SongImport):
lines = infile.readlines()
ext = os.path.splitext(filename)[1]
if ext.lower() == u'.usr':
log.info(u'SongSelect .usr format file found %s: ',
filename)
log.info(u'SongSelect .usr format file found: %s', filename)
self.do_import_usr_file(lines)
elif ext.lower() == u'.txt':
log.info(u'SongSelect .txt format file found %s: ',
filename)
log.info(u'SongSelect .txt format file found: %s', filename)
self.do_import_txt_file(lines)
else:
log.info(u'Extension %s is not valid', filename)
@ -97,9 +97,8 @@ class CCLIFileImport(SongImport):
def do_import_usr_file(self, textList):
"""
The :func:`do_import_usr_file` method provides OpenLP
with the ability to import CCLI SongSelect songs in
*USR* file format
The :func:`do_import_usr_file` method provides OpenLP with the ability
to import CCLI SongSelect songs in *USR* file format.
``textList``
An array of strings containing the usr file content.
@ -108,35 +107,46 @@ class CCLIFileImport(SongImport):
``[File]``
USR file format first line
``Type=``
Indicates the file type
e.g. *Type=SongSelect Import File*
``Version=3.0``
File format version
``[S A2672885]``
Contains the CCLI Song number e.g. *2672885*
``Title=``
Contains the song title (e.g. *Title=Above All*)
``Author=``
Contains a | delimited list of the song authors
e.g. *Author=LeBlanc, Lenny | Baloche, Paul*
``Copyright=``
Contains a | delimited list of the song copyrights
e.g. Copyright=1999 Integrity's Hosanna! Music |
LenSongs Publishing (Verwaltet von Gerth Medien
Musikverlag)
``Admin=``
Contains the song administrator
e.g. *Admin=Gerth Medien Musikverlag*
``Themes=``
Contains a /t delimited list of the song themes
e.g. *Themes=Cross/tKingship/tMajesty/tRedeemer*
``Keys=``
Contains the keys in which the music is played??
e.g. *Keys=A*
``Fields=``
Contains a list of the songs fields in order /t delimited
e.g. *Fields=Vers 1/tVers 2/tChorus 1/tAndere 1*
``Words=``
Contains the songs various lyrics in order as shown by the
*Fields* description
@ -144,16 +154,19 @@ class CCLIFileImport(SongImport):
"""
log.debug(u'USR file text: %s', textList)
self.set_defaults()
song_author = u''
song_topics = u''
for line in textList:
if line.startswith(u'Title='):
song_name = line[6:].strip()
self.title = line[6:].strip()
elif line.startswith(u'Author='):
song_author = line[7:].strip()
elif line.startswith(u'Copyright='):
song_copyright = line[10:].strip()
self.copyright = line[10:].strip()
elif line.startswith(u'Themes='):
song_topics = line[7:].strip()
elif line.startswith(u'[S A'):
song_ccli = line[4:-3].strip()
self.ccli_number = line[4:-3].strip()
elif line.startswith(u'Fields='):
# Fields contain single line indicating verse, chorus, etc,
# /t delimited, same as with words field. store seperately
@ -161,35 +174,35 @@ class CCLIFileImport(SongImport):
song_fields = line[7:].strip()
elif line.startswith(u'Words='):
song_words = line[6:].strip()
#Unhandled usr keywords:Type,Version,Admin,Themes,Keys
#Process Fields and words sections
# Unhandled usr keywords: Type, Version, Admin, Keys
# Process Fields and words sections.
check_first_verse_line = False
field_list = song_fields.split(u'/t')
words_list = song_words.split(u'/t')
for counter in range(0, len(field_list)):
if field_list[counter].startswith(u'Ver'):
verse_type = u'V'
verse_type = VerseType.Tags[VerseType.Verse]
elif field_list[counter].startswith(u'Ch'):
verse_type = u'C'
verse_type = VerseType.Tags[VerseType.Chorus]
elif field_list[counter].startswith(u'Br'):
verse_type = u'B'
else: #Other
verse_type = u'O'
verse_type = VerseType.Tags[VerseType.Bridge]
else:
verse_type = VerseType.Tags[VerseType.Other]
check_first_verse_line = True
verse_text = unicode(words_list[counter])
verse_text = verse_text.replace(u'/n', u'\n')
verse_lines = verse_text.split(u'\n', 1)
if check_first_verse_line:
if verse_lines[0].startswith(u'(PRE-CHORUS'):
verse_type = u'P'
verse_type = VerseType.Tags[VerseType.PreChorus]
log.debug(u'USR verse PRE-CHORUS: %s', verse_lines[0])
verse_text = verse_lines[1]
elif verse_lines[0].startswith(u'(BRIDGE'):
verse_type = u'B'
verse_type = VerseType.Tags[VerseType.Bridge]
log.debug(u'USR verse BRIDGE')
verse_text = verse_lines[1]
elif verse_lines[0].startswith(u'('):
verse_type = u'O'
verse_type = VerseType.Tags[VerseType.Other]
verse_text = verse_lines[1]
if len(verse_text) > 0:
self.add_verse(verse_text, verse_type)
@ -204,16 +217,13 @@ class CCLIFileImport(SongImport):
self.add_author(u' '.join(reversed(separated)))
else:
self.add_author(author)
self.title = song_name
self.copyright = song_copyright
self.ccli_number = song_ccli
self.topics = [topic.strip() for topic in song_topics.split(u'/t')]
self.finish()
def do_import_txt_file(self, textList):
"""
The :func:`do_import_txt_file` method provides OpenLP
with the ability to import CCLI SongSelect songs in
*TXT* file format
The :func:`do_import_txt_file` method provides OpenLP with the ability
to import CCLI SongSelect songs in *TXT* file format.
``textList``
An array of strings containing the txt file content.
@ -243,12 +253,10 @@ class CCLIFileImport(SongImport):
"""
log.debug(u'TXT file text: %s', textList)
self.set_defaults()
line_number = 0
check_first_verse_line = False
verse_text = u''
song_comments = u''
song_copyright = u''
song_author = u''
verse_start = False
for line in textList:
clean_line = line.strip()
@ -258,12 +266,12 @@ class CCLIFileImport(SongImport):
elif verse_start:
if verse_text:
self.add_verse(verse_text, verse_type)
verse_text = ''
verse_text = u''
verse_start = False
else:
#line_number=0, song title
if line_number == 0:
song_name = clean_line
self.title = clean_line
line_number += 1
#line_number=1, verses
elif line_number == 1:
@ -271,37 +279,37 @@ class CCLIFileImport(SongImport):
if clean_line.startswith(u'CCLI'):
line_number += 1
ccli_parts = clean_line.split(' ')
song_ccli = ccli_parts[len(ccli_parts)-1]
self.ccli_number = ccli_parts[len(ccli_parts) - 1]
elif not verse_start:
# We have the verse descriptor
verse_desc_parts = clean_line.split(' ')
verse_desc_parts = clean_line.split(u' ')
if len(verse_desc_parts) == 2:
if verse_desc_parts[0].startswith(u'Ver'):
verse_type = u'V'
verse_type = VerseType.Tags[VerseType.Verse]
elif verse_desc_parts[0].startswith(u'Ch'):
verse_type = u'C'
verse_type = VerseType.Tags[VerseType.Chorus]
elif verse_desc_parts[0].startswith(u'Br'):
verse_type = u'B'
verse_type = VerseType.Tags[VerseType.Bridge]
else:
# we need to analyse the next line for
# verse type, so set flag
verse_type = u'O'
verse_type = VerseType.Tags[VerseType.Other]
check_first_verse_line = True
verse_number = verse_desc_parts[1]
else:
verse_type = u'O'
verse_type = VerseType.Tags[VerseType.Other]
verse_number = 1
verse_start = True
else:
# check first line for verse type
if check_first_verse_line:
if line.startswith(u'(PRE-CHORUS'):
verse_type = u'P'
verse_type = VerseType.Tags[VerseType.PreChorus]
elif line.startswith(u'(BRIDGE'):
verse_type = u'B'
verse_type = VerseType.Tags[VerseType.Bridge]
# Handle all other misc types
elif line.startswith(u'('):
verse_type = u'O'
verse_type = VerseType.Tags[VerseType.Other]
else:
verse_text = verse_text + line
check_first_verse_line = False
@ -313,24 +321,19 @@ class CCLIFileImport(SongImport):
#line_number=2, copyright
if line_number == 2:
line_number += 1
song_copyright = clean_line
self.copyright = clean_line
#n=3, authors
elif line_number == 3:
line_number += 1
song_author = clean_line
#line_number=4, comments lines before last line
elif (line_number == 4) and \
(not clean_line.startswith(u'CCL')):
song_comments = song_comments + clean_line
elif line_number == 4 and not clean_line.startswith(u'CCL'):
self.comments += clean_line
# split on known separators
author_list = song_author.split(u'/')
if len(author_list) < 2:
author_list = song_author.split(u'|')
#Clean spaces before and after author names
# Clean spaces before and after author names.
for author_name in author_list:
self.add_author(author_name.strip())
self.title = song_name
self.copyright = song_copyright
self.ccli_number = song_ccli
self.comments = song_comments
self.finish()

View File

@ -394,10 +394,7 @@ if __name__ == '__main__':
--template Info.plist.master \
--expandto %(target_directory)s/Info.plist' \
% { 'config_file' : options.config, 'target_directory' : os.getcwd() })
os.system('python expander.py --config %(config_file)s \
--template version.master \
--expandto %(target_directory)s/.version' \
% { 'config_file' : options.config, 'target_directory' : os.getcwd() })
os.system('python get_version.py > .version')
# prepare variables
app_name_lower = settings['openlp_appname'].lower()

View File

@ -0,0 +1,36 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
from bzrlib.branch import Branch
def get_version(path):
b = Branch.open_containing(path)[0]
b.lock_read()
result = '0.0.0'
try:
# Get the branch's latest revision number.
revno = b.revno()
# Convert said revision number into a bzr revision id.
revision_id = b.dotted_revno_to_revision_id((revno,))
# Get a dict of tags, with the revision id as the key.
tags = b.tags.get_reverse_tag_dict()
# Check if the latest
if revision_id in tags:
result = tags[revision_id][0]
else:
result = '%s-bzr%s' % (sorted(b.tags.get_tag_dict().keys())[-1], revno)
finally:
b.unlock()
return result
def get_path():
if len(sys.argv) > 1:
return os.path.abspath(sys.argv[1])
else:
return os.path.abspath('.')
if __name__ == u'__main__':
path = get_path()
print get_version(path)

View File

@ -2,7 +2,6 @@
openlp_appname = OpenLP
openlp_dmgname = OpenLP-1.9.4-bzrXXXX
openlp_version = XXXX
openlp_full_version = 1.9.4-latest
openlp_basedir = /Users/openlp/trunk
openlp_icon_file = openlp-logo-with-text.icns
openlp_dmg_icon_file = openlp-logo-420x420.png

View File

@ -1 +0,0 @@
%(openlp_full_version)s