diff --git a/documentation/api/source/plugins/remotes.rst b/documentation/api/source/plugins/remotes.rst
index 0bcd37119..0bb05b8b9 100644
--- a/documentation/api/source/plugins/remotes.rst
+++ b/documentation/api/source/plugins/remotes.rst
@@ -17,3 +17,9 @@ Helper Classes & Functions
.. automodule:: openlp.plugins.remotes.lib
:members:
+
+.. autoclass:: openlp.plugins.remotes.lib.httpserver.HttpConnection
+ :members:
+
+.. autoclass:: openlp.plugins.remotes.lib.httpserver.HttpResponse
+ :members:
diff --git a/openlp.pyw b/openlp.pyw
index 416b2bb13..04f65a5dd 100755
--- a/openlp.pyw
+++ b/openlp.pyw
@@ -184,13 +184,15 @@ class OpenLP(QtGui.QApplication):
# make sure Qt really display the splash screen
self.processEvents()
# start the main app window
- self.mainWindow = MainWindow(screens, app_version, self.clipboard(),
- not has_run_wizard)
+ self.mainWindow = MainWindow(screens, app_version, self.clipboard())
self.mainWindow.show()
if show_splash:
# now kill the splashscreen
self.splash.finish(self.mainWindow)
self.mainWindow.repaint()
+ self.processEvents()
+ if not has_run_wizard:
+ self.mainWindow.firstTime()
update_check = QtCore.QSettings().value(
u'general/update check', QtCore.QVariant(True)).toBool()
if update_check:
diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py
index 2dd87f6f5..b360ab13d 100644
--- a/openlp/core/lib/serviceitem.py
+++ b/openlp/core/lib/serviceitem.py
@@ -62,7 +62,7 @@ class ItemCapabilities(object):
AddIfNewItem = 9
ProvidesOwnDisplay = 10
AllowsDetailedTitleDisplay = 11
- AllowsVarableStartTime = 12
+ AllowsVariableStartTime = 12
class ServiceItem(object):
@@ -183,6 +183,10 @@ class ServiceItem(object):
else:
log.error(u'Invalid value renderer :%s' % self.service_item_type)
self.title = clean_tags(self.title)
+ # The footer should never be None, but to be compatible with older
+ # release of OpenLP, we have to correct this to avoid tracebacks.
+ if self.raw_footer is None:
+ self.raw_footer = []
self.foot_text = \
u'
'.join([footer for footer in self.raw_footer if footer])
@@ -443,4 +447,4 @@ class ServiceItem(object):
elif not start and end:
return end
else:
- return u'%s : %s' % (start, end)
+ return u'%s : %s' % (start, end)
\ No newline at end of file
diff --git a/openlp/core/ui/firsttimeform.py b/openlp/core/ui/firsttimeform.py
index b049e2ea7..08e240b5c 100644
--- a/openlp/core/ui/firsttimeform.py
+++ b/openlp/core/ui/firsttimeform.py
@@ -33,8 +33,7 @@ from ConfigParser import SafeConfigParser
from PyQt4 import QtCore, QtGui
-from openlp.core.lib import translate, PluginStatus, check_directory_exists, \
- Receiver, build_icon
+from openlp.core.lib import translate, PluginStatus, Receiver, build_icon
from openlp.core.utils import get_web_page, AppLocation
from firsttimewizard import Ui_FirstTimeWizard, FirstTimePage
@@ -95,7 +94,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
language = unicode(self.config.get(
u'bibles_%s' % lang, u'title'), u'utf8')
langItem = QtGui.QTreeWidgetItem(
- self.biblesTreeWidget, QtCore.QStringList(language))
+ self.biblesTreeWidget, QtCore.QStringList(language))
bibles = self.config.get(u'bibles_%s' % lang, u'translations')
bibles = bibles.split(u',')
for bible in bibles:
@@ -104,24 +103,27 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
filename = unicode(self.config.get(
u'bible_%s' % bible, u'filename'))
item = QtGui.QTreeWidgetItem(
- langItem, QtCore.QStringList(title))
- item.setData(0, QtCore.Qt.UserRole, QtCore.QVariant(filename))
+ langItem, QtCore.QStringList(title))
+ item.setData(0, QtCore.Qt.UserRole,
+ QtCore.QVariant(filename))
item.setCheckState(0, QtCore.Qt.Unchecked)
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
self.biblesTreeWidget.expandAll()
themes = self.config.get(u'themes', u'files')
themes = themes.split(u',')
+ if not os.path.exists(os.path.join(gettempdir(), u'openlp')):
+ os.makedirs(os.path.join(gettempdir(), u'openlp'))
for theme in themes:
title = self.config.get(u'theme_%s' % theme, u'title')
filename = self.config.get(u'theme_%s' % theme, u'filename')
screenshot = self.config.get(u'theme_%s' % theme, u'screenshot')
urllib.urlretrieve(u'%s/%s' % (self.web, screenshot),
- os.path.join(gettempdir(), screenshot))
+ os.path.join(gettempdir(), u'openlp', screenshot))
item = QtGui.QListWidgetItem(title, self.themesListWidget)
item.setData(QtCore.Qt.UserRole,
QtCore.QVariant(filename))
item.setIcon(build_icon(
- os.path.join(gettempdir(), screenshot)))
+ os.path.join(gettempdir(), u'openlp', screenshot)))
item.setCheckState(QtCore.Qt.Unchecked)
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
@@ -222,7 +224,8 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
'Enabling selected plugins...'))
self._setPluginStatus(self.songsCheckBox, u'songs/status')
self._setPluginStatus(self.bibleCheckBox, u'bibles/status')
- self._setPluginStatus(self.presentationCheckBox, u'presentations/status')
+ self._setPluginStatus(self.presentationCheckBox,
+ u'presentations/status')
self._setPluginStatus(self.imageCheckBox, u'images/status')
self._setPluginStatus(self.mediaCheckBox, u'media/status')
self._setPluginStatus(self.remoteCheckBox, u'remotes/status')
@@ -230,29 +233,18 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self._setPluginStatus(self.songUsageCheckBox, u'songusage/status')
self._setPluginStatus(self.alertCheckBox, u'alerts/status')
# Build directories for downloads
- songs_destination = AppLocation.get_section_data_path(u'songs')
+ songs_destination = os.path.join(unicode(gettempdir()), u'openlp')
bibles_destination = AppLocation.get_section_data_path(u'bibles')
themes_destination = AppLocation.get_section_data_path(u'themes')
- # Install songs
+ # Download songs
for i in xrange(self.songsListWidget.count()):
item = self.songsListWidget.item(i)
if item.checkState() == QtCore.Qt.Checked:
filename = item.data(QtCore.Qt.UserRole).toString()
self._incrementProgressBar(self.downloading % filename)
- destination = os.path.join(songs_destination, u'songs.sqlite')
- if os.path.exists(destination):
- if QtGui.QMessageBox.question(self,
- translate('OpenLP.FirstTimeWizard',
- 'Overwrite Existing Songs?'),
- translate('OpenLP.FirstTimeWizard', 'Your songs '
- 'database already exists and your current songs will '
- 'be permanently lost, are you sure you want to '
- 'replace it ?'),
- QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
- QtGui.QMessageBox.No) != QtGui.QMessageBox.Yes:
- continue
+ destination = os.path.join(songs_destination, unicode(filename))
urllib.urlretrieve(u'%s%s' % (self.web, filename), destination)
- # Install Bibles
+ # Download Bibles
bibles_iterator = QtGui.QTreeWidgetItemIterator(self.biblesTreeWidget)
while bibles_iterator.value():
item = bibles_iterator.value()
@@ -262,7 +254,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
urllib.urlretrieve(u'%s%s' % (self.web, bible),
os.path.join(bibles_destination, bible))
bibles_iterator += 1
- # Install themes
+ # Download themes
for i in xrange(self.themesListWidget.count()):
item = self.themesListWidget.item(i)
if item.checkState() == QtCore.Qt.Checked:
@@ -285,4 +277,3 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
status = PluginStatus.Active if field.checkState() \
== QtCore.Qt.Checked else PluginStatus.Inactive
QtCore.QSettings().setValue(tag, QtCore.QVariant(status))
-
diff --git a/openlp/core/ui/firsttimelanguagedialog.py b/openlp/core/ui/firsttimelanguagedialog.py
index ae44abeb5..93751763f 100644
--- a/openlp/core/ui/firsttimelanguagedialog.py
+++ b/openlp/core/ui/firsttimelanguagedialog.py
@@ -46,7 +46,8 @@ class Ui_FirstTimeLanguageDialog(object):
self.languageLabel.setObjectName(u'languageLabel')
self.languageLayout.addWidget(self.languageLabel)
self.languageComboBox = QtGui.QComboBox(languageDialog)
- self.languageComboBox.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
+ self.languageComboBox.setSizeAdjustPolicy(
+ QtGui.QComboBox.AdjustToContents)
self.languageComboBox.setObjectName("languageComboBox")
self.languageLayout.addWidget(self.languageComboBox)
self.dialogLayout.addLayout(self.languageLayout)
diff --git a/openlp/core/ui/firsttimelanguageform.py b/openlp/core/ui/firsttimelanguageform.py
index a8ce3bd57..22057fbfc 100644
--- a/openlp/core/ui/firsttimelanguageform.py
+++ b/openlp/core/ui/firsttimelanguageform.py
@@ -26,7 +26,6 @@
from PyQt4 import QtGui
-from openlp.core.lib import translate
from openlp.core.utils import LanguageManager
from firsttimelanguagedialog import Ui_FirstTimeLanguageDialog
diff --git a/openlp/core/ui/generaltab.py b/openlp/core/ui/generaltab.py
index e705d5ec3..1dbbb3559 100644
--- a/openlp/core/ui/generaltab.py
+++ b/openlp/core/ui/generaltab.py
@@ -237,6 +237,12 @@ class GeneralTab(SettingsTab):
# Reload the tab, as the screen resolution/count may have changed.
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'config_screen_changed'), self.load)
+ # Remove for now
+ self.usernameLabel.setVisible(False)
+ self.usernameEdit.setVisible(False)
+ self.passwordLabel.setVisible(False)
+ self.passwordEdit.setVisible(False)
+
def retranslateUi(self):
"""
diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py
index 72ebe422a..76c891636 100644
--- a/openlp/core/ui/maindisplay.py
+++ b/openlp/core/ui/maindisplay.py
@@ -67,6 +67,7 @@ class MainDisplay(DisplayWidget):
self.isLive = live
self.alertTab = None
self.hideMode = None
+ self.videoHide = False
self.override = {}
mainIcon = build_icon(u':/icon/openlp-logo-16x16.png')
self.setWindowIcon(mainIcon)
@@ -90,7 +91,7 @@ class MainDisplay(DisplayWidget):
"""
Set up and build the output screen
"""
- log.debug(u'Start setup for monitor %s (live = %s)' %
+ log.debug(u'Start setup for monitor %s (live = %s)' %
(self.screens.monitor_number, self.isLive))
self.usePhonon = QtCore.QSettings().value(
u'media/use phonon', QtCore.QVariant(True)).toBool()
@@ -110,6 +111,12 @@ class MainDisplay(DisplayWidget):
QtCore.QObject.connect(self.mediaObject,
QtCore.SIGNAL(u'stateChanged(Phonon::State, Phonon::State)'),
self.videoStart)
+ QtCore.QObject.connect(self.mediaObject,
+ QtCore.SIGNAL(u'finished()'),
+ self.videoFinished)
+ QtCore.QObject.connect(self.mediaObject,
+ QtCore.SIGNAL(u'tick(qint64)'),
+ self.videoTick)
log.debug(u'Setup webView for monitor %s' % self.screens.monitor_number)
self.webView = QtWebKit.QWebView(self)
self.webView.setGeometry(0, 0,
@@ -143,23 +150,22 @@ class MainDisplay(DisplayWidget):
if not background_color.isValid():
background_color = QtCore.Qt.white
splash_image = QtGui.QImage(image_file)
- initialFrame = QtGui.QImage(
+ self.initialFrame = QtGui.QImage(
self.screens.current[u'size'].width(),
self.screens.current[u'size'].height(),
QtGui.QImage.Format_ARGB32_Premultiplied)
painter_image = QtGui.QPainter()
- painter_image.begin(initialFrame)
- painter_image.fillRect(initialFrame.rect(), background_color)
+ painter_image.begin(self.initialFrame)
+ painter_image.fillRect(self.initialFrame.rect(), background_color)
painter_image.drawImage(
(self.screens.current[u'size'].width() -
splash_image.width()) / 2,
(self.screens.current[u'size'].height()
- splash_image.height()) / 2, splash_image)
serviceItem = ServiceItem()
- serviceItem.bg_image_bytes = image_to_byte(initialFrame)
+ serviceItem.bg_image_bytes = image_to_byte(self.initialFrame)
self.webView.setHtml(build_html(serviceItem, self.screen,
self.alertTab, self.isLive, None))
- self.initialFrame = True
self.__hideMouse()
# To display or not to display?
if not self.screen[u'primary']:
@@ -181,6 +187,7 @@ class MainDisplay(DisplayWidget):
# Wait for the webview to update before displaying text.
while not self.webLoaded:
Receiver.send_message(u'openlp_process_events')
+ self.setGeometry(self.screen[u'size'])
self.frame.evaluateJavaScript(u'show_text("%s")' % \
slide.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'))
return self.preview()
@@ -208,12 +215,18 @@ class MainDisplay(DisplayWidget):
else:
shrinkItem = self
if text:
- shrinkItem.resize(self.width(), int(height.toString()))
+ alert_height = int(height.toString())
+ shrinkItem.resize(self.width(), alert_height)
shrinkItem.setVisible(True)
+ if self.alertTab.location == 1:
+ shrinkItem.move(self.screen[u'size'].left(),
+ (self.screen[u'size'].height() - alert_height) / 2)
+ elif self.alertTab.location == 2:
+ shrinkItem.move(self.screen[u'size'].left(),
+ self.screen[u'size'].height() - alert_height)
else:
shrinkItem.setVisible(False)
- shrinkItem.resize(self.screen[u'size'].width(),
- self.screen[u'size'].height())
+ self.setGeometry(self.screen[u'size'])
def directImage(self, name, path):
"""
@@ -243,6 +256,7 @@ class MainDisplay(DisplayWidget):
"""
Display an image, as is.
"""
+ self.setGeometry(self.screen[u'size'])
if image:
js = u'show_image("data:image/png;base64,%s");' % image
else:
@@ -262,6 +276,7 @@ class MainDisplay(DisplayWidget):
self.displayImage(self.serviceItem.bg_image_bytes)
else:
self.displayImage(None)
+ # clear the cache
self.override = {}
# Update the preview frame.
if self.isLive:
@@ -336,6 +351,7 @@ class MainDisplay(DisplayWidget):
"""
log.debug(u'video')
self.webLoaded = True
+ self.setGeometry(self.screen[u'size'])
# We are running a background theme
self.override[u'theme'] = u''
self.override[u'video'] = True
@@ -349,6 +365,10 @@ class MainDisplay(DisplayWidget):
self.mediaObject.stop()
self.mediaObject.clearQueue()
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:
+ self.mediaObject.setTickInterval(200)
self.mediaObject.play()
self.webView.setVisible(False)
self.videoWidget.setVisible(True)
@@ -363,8 +383,26 @@ class MainDisplay(DisplayWidget):
Start the video at a predetermined point.
"""
if newState == Phonon.PlayingState:
+ # set start time in milliseconds
self.mediaObject.seek(self.serviceItem.start_time * 1000)
+ def videoFinished(self):
+ """
+ Blank the Video when it has finished so the final frame is not left
+ hanging
+ """
+ self.videoStop()
+ self.hideDisplay(HideMode.Blank)
+ self.phononActive = False
+ self.videoHide = True
+
+ def videoTick(self, tick):
+ """
+ Triggered on video tick every 200 milli seconds
+ Will be used to manage stop time later
+ """
+ pass
+
def isWebLoaded(self):
"""
Called by webView event to show display is fully loaded
@@ -396,7 +434,14 @@ class MainDisplay(DisplayWidget):
if self.hideMode:
self.hideDisplay(self.hideMode)
else:
- self.setVisible(True)
+ # Single screen active
+ if self.screens.monitor_number == 0:
+ # Only make visible if setting enabled
+ if QtCore.QSettings().value(u'general/display on monitor',
+ QtCore.QVariant(True)).toBool():
+ self.setVisible(True)
+ else:
+ self.setVisible(True)
preview = QtGui.QImage(self.screen[u'size'].width(),
self.screen[u'size'].height(),
QtGui.QImage.Format_ARGB32_Premultiplied)
@@ -413,7 +458,7 @@ class MainDisplay(DisplayWidget):
"""
log.debug(u'buildHtml')
self.webLoaded = False
- self.initialFrame = False
+ self.initialFrame = None
self.serviceItem = serviceItem
background = None
# We have an image override so keep the image till the theme changes
@@ -422,10 +467,12 @@ class MainDisplay(DisplayWidget):
if u'video' in self.override:
Receiver.send_message(u'video_background_replaced')
self.override = {}
+ # We have a different theme.
elif self.override[u'theme'] != serviceItem.themedata.theme_name:
Receiver.send_message(u'live_theme_changed')
self.override = {}
else:
+ # replace the background
background = self.imageManager. \
get_image_bytes(self.override[u'image'])
if self.serviceItem.themedata.background_filename:
@@ -441,6 +488,10 @@ class MainDisplay(DisplayWidget):
# if was hidden keep it hidden
if self.hideMode and self.isLive:
self.hideDisplay(self.hideMode)
+ # display hidden for video end we have a new item so must be shown
+ if self.videoHide and self.isLive:
+ self.videoHide = False
+ self.showDisplay()
self.__hideMouse()
def footer(self, text):
diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py
index cb324a872..294cca49b 100644
--- a/openlp/core/ui/mainwindow.py
+++ b/openlp/core/ui/mainwindow.py
@@ -25,6 +25,8 @@
###############################################################################
import logging
+import os
+from tempfile import gettempdir
from PyQt4 import QtCore, QtGui
@@ -215,8 +217,6 @@ class Ui_MainWindow(object):
self.ModeDefaultItem.setChecked(True)
self.ToolsAddToolItem = icon_action(mainWindow, u'ToolsAddToolItem',
u':/tools/tools_add.png')
- # Hide the entry, as it does not have any functionality yet.
- self.ToolsAddToolItem.setVisible(False)
mainWindow.actionList.add_action(self.ToolsAddToolItem, u'Tools')
self.ToolsOpenDataFolder = icon_action(mainWindow,
u'ToolsOpenDataFolder', u':/general/general_open.png')
@@ -298,6 +298,13 @@ class Ui_MainWindow(object):
QtCore.QObject.connect(self.FileExitItem,
QtCore.SIGNAL(u'triggered()'), mainWindow.close)
QtCore.QMetaObject.connectSlotsByName(mainWindow)
+ # Hide the entry, as it does not have any functionality yet.
+ self.ToolsAddToolItem.setVisible(False)
+ self.ImportLanguageItem.setVisible(False)
+ self.ExportLanguageItem.setVisible(False)
+ self.SettingsShortcutsItem.setVisible(False)
+ self.HelpDocumentationItem.setVisible(False)
+ self.HelpOnlineHelpItem.setVisible(False)
def retranslateUi(self, mainWindow):
"""
@@ -461,14 +468,13 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
actionList = ActionList()
- def __init__(self, screens, applicationVersion, clipboard, firstTime):
+ def __init__(self, screens, applicationVersion, clipboard):
"""
This constructor sets up the interface, the various managers, and the
plugins.
"""
QtGui.QMainWindow.__init__(self)
self.screens = screens
- self.actionList = ActionList()
self.applicationVersion = applicationVersion
self.clipboard = clipboard
# Set up settings sections for the main application
@@ -478,6 +484,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.serviceSettingsSection = u'servicemanager'
self.songsSettingsSection = u'songs'
self.serviceNotSaved = False
+ self.actionList = ActionList()
self.settingsmanager = SettingsManager(screens)
self.aboutForm = AboutForm(self, applicationVersion)
self.settingsForm = SettingsForm(self.screens, self, self)
@@ -624,10 +631,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.MediaToolBox.setCurrentIndex(savedPlugin)
self.settingsForm.postSetUp()
Receiver.send_message(u'cursor_normal')
- # Import themes if first time
- if firstTime:
- self.themeManagerContents.firstTime()
-
def setAutoLanguage(self, value):
self.LanguageGroup.setDisabled(value)
@@ -670,6 +673,20 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.setViewMode(False, True, False, False, True)
self.ModeLiveItem.setChecked(True)
+ def firstTime(self):
+ # Import themes if first time
+ Receiver.send_message(u'openlp_process_events')
+ self.themeManagerContents.firstTime()
+ for plugin in self.pluginManager.plugins:
+ if hasattr(plugin, u'firstTime'):
+ Receiver.send_message(u'openlp_process_events')
+ plugin.firstTime()
+ Receiver.send_message(u'openlp_process_events')
+ temp_dir = os.path.join(unicode(gettempdir()), u'openlp')
+ for filename in os.listdir(temp_dir):
+ os.remove(os.path.join(temp_dir, filename))
+ os.removedirs(temp_dir)
+
def blankCheck(self):
"""
Check and display message if screen blank on setup.
diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py
index fa2bc50f5..56aa1bea1 100644
--- a/openlp/core/ui/servicemanager.py
+++ b/openlp/core/ui/servicemanager.py
@@ -49,6 +49,19 @@ class ServiceManagerList(QtGui.QTreeWidget):
QtGui.QTreeWidget.__init__(self, parent)
self.mainwindow = mainwindow
+ def keyPressEvent(self, event):
+ if isinstance(event, QtGui.QKeyEvent):
+ # here accept the event and do something
+ if event.key() == QtCore.Qt.Key_Up:
+ self.mainwindow.onMoveSelectionUp()
+ event.accept()
+ elif event.key() == QtCore.Qt.Key_Down:
+ self.mainwindow.onMoveSelectionDown()
+ event.accept()
+ event.ignore()
+ else:
+ event.ignore()
+
def mouseMoveEvent(self, event):
"""
Drag and drop event does not care what data is selected
@@ -197,13 +210,13 @@ class ServiceManager(QtGui.QWidget):
u':/services/service_expand_all.png',
translate('OpenLP.ServiceManager',
'Expand all the service items.'),
- self.onExpandAll)
+ self.onExpandAll, shortcut=QtCore.Qt.Key_Plus)
self.serviceManagerList.collapse = self.orderToolbar.addToolbarButton(
translate('OpenLP.ServiceManager', '&Collapse all'),
u':/services/service_collapse_all.png',
translate('OpenLP.ServiceManager',
'Collapse all the service items.'),
- self.onCollapseAll)
+ self.onCollapseAll, shortcut=QtCore.Qt.Key_Minus)
self.orderToolbar.addSeparator()
self.serviceManagerList.makeLive = self.orderToolbar.addToolbarButton(
translate('OpenLP.ServiceManager', 'Go Live'),
@@ -293,7 +306,9 @@ class ServiceManager(QtGui.QWidget):
self.serviceManagerList.moveTop,
self.serviceManagerList.moveBottom,
self.serviceManagerList.up,
- self.serviceManagerList.down
+ self.serviceManagerList.down,
+ self.serviceManagerList.expand,
+ self.serviceManagerList.collapse
])
self.configUpdated()
@@ -306,6 +321,9 @@ class ServiceManager(QtGui.QWidget):
actionList.add_action(self.serviceManagerList.makeLive, u'Service')
actionList.add_action(self.serviceManagerList.up, u'Service')
actionList.add_action(self.serviceManagerList.down, u'Service')
+ actionList.add_action(self.serviceManagerList.expand, u'Service')
+ actionList.add_action(self.serviceManagerList.collapse, u'Service')
+
def setModified(self, modified=True):
"""
@@ -600,7 +618,7 @@ class ServiceManager(QtGui.QWidget):
if item.parent() is None:
self.notesAction.setVisible(True)
if serviceItem[u'service_item']\
- .is_capable(ItemCapabilities.AllowsVarableStartTime):
+ .is_capable(ItemCapabilities.AllowsVariableStartTime):
self.timeAction.setVisible(True)
self.themeMenu.menuAction().setVisible(False)
if serviceItem[u'service_item'].is_text():
@@ -887,7 +905,7 @@ class ServiceManager(QtGui.QWidget):
child.setText(0, text[:40])
child.setData(0, QtCore.Qt.UserRole, QtCore.QVariant(count))
if item[u'service_item'] \
- .is_capable(ItemCapabilities.AllowsVarableStartTime):
+ .is_capable(ItemCapabilities.AllowsVariableStartTime):
tip = item[u'service_item'].get_media_time()
if tip:
child.setToolTip(0, tip)
@@ -1238,4 +1256,4 @@ class ServiceManager(QtGui.QWidget):
Print a Service Order Sheet.
"""
settingDialog = PrintServiceForm(self.mainwindow, self)
- settingDialog.exec_()
+ settingDialog.exec_()
\ No newline at end of file
diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py
index 381712977..54b48cdf6 100644
--- a/openlp/core/utils/__init__.py
+++ b/openlp/core/utils/__init__.py
@@ -391,7 +391,7 @@ def get_uno_command():
Returns the UNO command to launch an openoffice.org instance.
"""
COMMAND = u'soffice'
- OPTIONS = u'-nologo -norestore -minimized -invisible -nofirststartwizard'
+ OPTIONS = u'-nologo -norestore -minimized -nodefault -nofirststartwizard'
if UNO_CONNECTION_TYPE == u'pipe':
CONNECTION = u'"-accept=pipe,name=openlp_pipe;urp;"'
else:
diff --git a/openlp/plugins/bibles/bibleplugin.py b/openlp/plugins/bibles/bibleplugin.py
index 61bca84aa..e4dd2f768 100644
--- a/openlp/plugins/bibles/bibleplugin.py
+++ b/openlp/plugins/bibles/bibleplugin.py
@@ -50,7 +50,8 @@ class BiblePlugin(Plugin):
self.manager = BibleManager(self)
Plugin.initialise(self)
self.importBibleItem.setVisible(True)
- self.exportBibleItem.setVisible(True)
+ # Set to invisible until we can export bibles
+ self.exportBibleItem.setVisible(False)
def finalise(self):
"""
diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py
index e2dde59fd..52baab14c 100644
--- a/openlp/plugins/bibles/lib/http.py
+++ b/openlp/plugins/bibles/lib/http.py
@@ -227,6 +227,10 @@ class BGExtract(object):
cleanup = [(re.compile('\s+'), lambda match: ' ')]
verses = BeautifulSoup(str(soup), markupMassage=cleanup)
verse_list = {}
+ # Cater for inconsistent mark up in the first verse of a chapter.
+ first_verse = verses.find(u'versenum')
+ if first_verse:
+ verse_list[1] = unicode(first_verse.contents[0])
for verse in verses(u'sup', u'versenum'):
raw_verse_num = verse.next
clean_verse_num = 0
diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py
index dcbad3e63..c11e10588 100644
--- a/openlp/plugins/bibles/lib/manager.py
+++ b/openlp/plugins/bibles/lib/manager.py
@@ -25,14 +25,14 @@
###############################################################################
import logging
+import os
from PyQt4 import QtCore
from openlp.core.lib import Receiver, SettingsManager, translate
-from openlp.core.utils import AppLocation
+from openlp.core.utils import AppLocation, delete_file
from openlp.plugins.bibles.lib import parse_reference
from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta
-
from csvbible import CSVBible
from http import HTTPBible
from opensong import OpenSongBible
@@ -144,6 +144,10 @@ class BibleManager(object):
for filename in files:
bible = BibleDB(self.parent, path=self.path, file=filename)
name = bible.get_name()
+ # Remove corrupted files.
+ if name is None:
+ delete_file(os.path.join(self.path, filename))
+ continue
log.debug(u'Bible Name: "%s"', name)
self.db_cache[name] = bible
# Look to see if lazy load bible exists and get create getter.
diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py
index 40ea7abb1..9511fabee 100644
--- a/openlp/plugins/media/lib/mediaitem.py
+++ b/openlp/plugins/media/lib/mediaitem.py
@@ -132,14 +132,18 @@ class MediaMediaItem(MediaManagerItem):
self.mediaObject.play()
service_item.title = unicode(self.plugin.nameStrings[u'singular'])
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
+ file_size = os.path.getsize(filename)
+ # File too big for processing
+ if file_size <= 52428800: # 50MiB
+ while not self.mediaState:
+ Receiver.send_message(u'openlp_process_events')
+ service_item.media_length = self.mediaLength
+ service_item.add_capability(
+ ItemCapabilities.AllowsVariableStartTime)
service_item.add_from_command(path, name, frame)
return True
else:
@@ -185,4 +189,4 @@ class MediaMediaItem(MediaManagerItem):
if newState == Phonon.PlayingState:
self.mediaState = newState
self.mediaLength = self.mediaObject.totalTime()/1000
- self.mediaObject.stop()
+ self.mediaObject.stop()
\ No newline at end of file
diff --git a/openlp/plugins/presentations/lib/messagelistener.py b/openlp/plugins/presentations/lib/messagelistener.py
index 4db78f7a5..6554c033a 100644
--- a/openlp/plugins/presentations/lib/messagelistener.py
+++ b/openlp/plugins/presentations/lib/messagelistener.py
@@ -80,7 +80,8 @@ class Controller(object):
if self.doc.is_active():
return
if not self.doc.is_loaded():
- self.doc.load_presentation()
+ if not self.doc.load_presentation():
+ return
if self.is_live:
self.doc.start_presentation()
if self.doc.slidenumber > 1:
diff --git a/openlp/plugins/presentations/lib/powerpointcontroller.py b/openlp/plugins/presentations/lib/powerpointcontroller.py
index 4dc9e8f3a..f220f558a 100644
--- a/openlp/plugins/presentations/lib/powerpointcontroller.py
+++ b/openlp/plugins/presentations/lib/powerpointcontroller.py
@@ -77,8 +77,11 @@ class PowerpointController(PresentationController):
"""
Loads PowerPoint process
"""
- self.process = Dispatch(u'PowerPoint.Application')
- self.process.Visible = True
+ log.debug(u'start_process')
+ if not self.process:
+ self.process = Dispatch(u'PowerPoint.Application')
+ if float(self.process.Version) < 13:
+ self.process.Visible = True
self.process.WindowState = 2
def kill(self):
@@ -120,13 +123,14 @@ class PowerpointDocument(PresentationDocument):
``presentation``
The file name of the presentations to run.
"""
- log.debug(u'LoadPresentation')
+ log.debug(u'load_presentation')
if not self.controller.process or not self.controller.process.Visible:
self.controller.start_process()
try:
self.controller.process.Presentations.Open(self.filepath, False,
False, True)
except pywintypes.com_error:
+ log.debug(u'PPT open failed')
return False
self.presentation = self.controller.process.Presentations(
self.controller.process.Presentations.Count)
@@ -145,6 +149,7 @@ class PowerpointDocument(PresentationDocument):
However, for the moment, we want a physical file since it makes life
easier elsewhere.
"""
+ log.debug(u'create_thumbnails')
if self.check_thumbnails():
return
for num in range(0, self.presentation.Slides.Count):
@@ -170,6 +175,7 @@ class PowerpointDocument(PresentationDocument):
"""
Returns ``True`` if a presentation is loaded.
"""
+ log.debug(u'is_loaded')
try:
if not self.controller.process.Visible:
return False
@@ -186,6 +192,7 @@ class PowerpointDocument(PresentationDocument):
"""
Returns ``True`` if a presentation is currently active.
"""
+ log.debug(u'is_active')
if not self.is_loaded():
return False
try:
@@ -201,6 +208,7 @@ class PowerpointDocument(PresentationDocument):
"""
Unblanks (restores) the presentation.
"""
+ log.debug(u'unblank_screen')
self.presentation.SlideShowSettings.Run()
self.presentation.SlideShowWindow.View.State = 1
self.presentation.SlideShowWindow.Activate()
@@ -209,12 +217,14 @@ class PowerpointDocument(PresentationDocument):
"""
Blanks the screen.
"""
+ log.debug(u'blank_screen')
self.presentation.SlideShowWindow.View.State = 3
def is_blank(self):
"""
Returns ``True`` if screen is blank.
"""
+ log.debug(u'is_blank')
if self.is_active():
return self.presentation.SlideShowWindow.View.State == 3
else:
@@ -224,6 +234,7 @@ class PowerpointDocument(PresentationDocument):
"""
Stops the current presentation and hides the output.
"""
+ log.debug(u'stop_presentation')
self.presentation.SlideShowWindow.View.Exit()
if os.name == u'nt':
@@ -231,6 +242,7 @@ class PowerpointDocument(PresentationDocument):
"""
Starts a presentation from the beginning.
"""
+ log.debug(u'start_presentation')
#SlideShowWindow measures its size/position by points, not pixels
try:
dpi = win32ui.GetActiveWindow().GetDC().GetDeviceCaps(88)
@@ -253,30 +265,35 @@ class PowerpointDocument(PresentationDocument):
"""
Returns the current slide number.
"""
+ log.debug(u'get_slide_number')
return self.presentation.SlideShowWindow.View.CurrentShowPosition
def get_slide_count(self):
"""
Returns total number of slides.
"""
+ log.debug(u'get_slide_count')
return self.presentation.Slides.Count
def goto_slide(self, slideno):
"""
Moves to a specific slide in the presentation.
"""
+ log.debug(u'goto_slide')
self.presentation.SlideShowWindow.View.GotoSlide(slideno)
def next_step(self):
"""
Triggers the next effect of slide on the running presentation.
"""
+ log.debug(u'next_step')
self.presentation.SlideShowWindow.View.Next()
def previous_step(self):
"""
Triggers the previous slide on the running presentation.
"""
+ log.debug(u'previous_step')
self.presentation.SlideShowWindow.View.Previous()
def get_slide_text(self, slide_no):
diff --git a/openlp/plugins/presentations/lib/pptviewcontroller.py b/openlp/plugins/presentations/lib/pptviewcontroller.py
index 0900d1d9d..5ec560167 100644
--- a/openlp/plugins/presentations/lib/pptviewcontroller.py
+++ b/openlp/plugins/presentations/lib/pptviewcontroller.py
@@ -84,7 +84,8 @@ class PptviewController(PresentationController):
dllpath = os.path.join(self.plugin.pluginManager.basepath,
u'presentations', u'lib', u'pptviewlib', u'pptviewlib.dll')
self.process = cdll.LoadLibrary(dllpath)
- #self.process.SetDebug(1)
+ if log.isEnabledFor(logging.DEBUG):
+ self.process.SetDebug(1)
def kill(self):
"""
@@ -140,8 +141,10 @@ class PptviewDocument(PresentationDocument):
PPTviewLib creates large BMP's, but we want small PNG's for consistency.
Convert them here.
"""
+ log.debug(u'create_thumbnails')
if self.check_thumbnails():
return
+ log.debug(u'create_thumbnails proceeding')
for idx in range(self.get_slide_count()):
path = u'%s\\slide%s.bmp' % (self.get_temp_folder(),
unicode(idx + 1))
diff --git a/openlp/plugins/presentations/lib/pptviewlib/ppttest.py b/openlp/plugins/presentations/lib/pptviewlib/ppttest.py
index 1e10def7d..f8d0fabd9 100644
--- a/openlp/plugins/presentations/lib/pptviewlib/ppttest.py
+++ b/openlp/plugins/presentations/lib/pptviewlib/ppttest.py
@@ -133,7 +133,7 @@ class PPTViewer(QtGui.QWidget):
def OpenClick(self):
oldid = self.pptid;
rect = RECT(100,100,900,700)
- filename = unicode(self.PPTEdit.text())
+ filename = str(self.PPTEdit.text().replace(u'/', u'\\'))
print filename
self.pptid = pptdll.OpenPPT(filename, None, rect, 'c:\\temp\\slide')
print "id: " + unicode(self.pptid)
diff --git a/openlp/plugins/remotes/__init__.py b/openlp/plugins/remotes/__init__.py
index b5077f435..70445293a 100644
--- a/openlp/plugins/remotes/__init__.py
+++ b/openlp/plugins/remotes/__init__.py
@@ -26,4 +26,68 @@
"""
The :mod:`remotes` plugin allows OpenLP to be controlled from another machine
over a network connection.
+
+Routes:
+
+``/``
+ Go to the web interface.
+
+``/files/{filename}``
+ Serve a static file.
+
+``/api/poll``
+ Poll to see if there are any changes. Returns a JSON-encoded dict of
+ any changes that occurred::
+
+ {"results": {"type": "controller"}}
+
+ Or, if there were no results, False::
+
+ {"results": False}
+
+``/api/controller/{live|preview}/{action}``
+ Perform ``{action}`` on the live or preview controller. Valid actions
+ are:
+
+ ``next``
+ Load the next slide.
+
+ ``previous``
+ Load the previous slide.
+
+ ``jump``
+ Jump to a specific slide. Requires an id return in a JSON-encoded
+ dict like so::
+
+ {"request": {"id": 1}}
+
+ ``first``
+ Load the first slide.
+
+ ``last``
+ Load the last slide.
+
+ ``text``
+ Request the text of the current slide.
+
+``/api/service/{action}``
+ Perform ``{action}`` on the service manager (e.g. go live). Data is
+ passed as a json-encoded ``data`` parameter. Valid actions are:
+
+ ``next``
+ Load the next item in the service.
+
+ ``previous``
+ Load the previews item in the service.
+
+ ``jump``
+ Jump to a specific item in the service. Requires an id returned in
+ a JSON-encoded dict like so::
+
+ {"request": {"id": 1}}
+
+ ``list``
+ Request a list of items in the service.
+
+
"""
diff --git a/openlp/plugins/remotes/html/images/ajax-loader.png b/openlp/plugins/remotes/html/images/ajax-loader.png
new file mode 100644
index 000000000..811a2cdd1
Binary files /dev/null and b/openlp/plugins/remotes/html/images/ajax-loader.png differ
diff --git a/openlp/plugins/remotes/html/images/form-check-off.png b/openlp/plugins/remotes/html/images/form-check-off.png
new file mode 100644
index 000000000..54e2fe0f8
Binary files /dev/null and b/openlp/plugins/remotes/html/images/form-check-off.png differ
diff --git a/openlp/plugins/remotes/html/images/form-check-on.png b/openlp/plugins/remotes/html/images/form-check-on.png
new file mode 100644
index 000000000..e6daaaf8b
Binary files /dev/null and b/openlp/plugins/remotes/html/images/form-check-on.png differ
diff --git a/openlp/plugins/remotes/html/images/form-radio-off.png b/openlp/plugins/remotes/html/images/form-radio-off.png
new file mode 100644
index 000000000..32bd43392
Binary files /dev/null and b/openlp/plugins/remotes/html/images/form-radio-off.png differ
diff --git a/openlp/plugins/remotes/html/images/form-radio-on.png b/openlp/plugins/remotes/html/images/form-radio-on.png
new file mode 100644
index 000000000..ddc404970
Binary files /dev/null and b/openlp/plugins/remotes/html/images/form-radio-on.png differ
diff --git a/openlp/plugins/remotes/html/images/icon-search-black.png b/openlp/plugins/remotes/html/images/icon-search-black.png
new file mode 100644
index 000000000..5721120f8
Binary files /dev/null and b/openlp/plugins/remotes/html/images/icon-search-black.png differ
diff --git a/openlp/plugins/remotes/html/images/icons-18-black.png b/openlp/plugins/remotes/html/images/icons-18-black.png
new file mode 100644
index 000000000..3657baea8
Binary files /dev/null and b/openlp/plugins/remotes/html/images/icons-18-black.png differ
diff --git a/openlp/plugins/remotes/html/images/icons-18-white.png b/openlp/plugins/remotes/html/images/icons-18-white.png
new file mode 100644
index 000000000..ccca7b44b
Binary files /dev/null and b/openlp/plugins/remotes/html/images/icons-18-white.png differ
diff --git a/openlp/plugins/remotes/html/images/icons-36-black.png b/openlp/plugins/remotes/html/images/icons-36-black.png
new file mode 100644
index 000000000..79b6d601b
Binary files /dev/null and b/openlp/plugins/remotes/html/images/icons-36-black.png differ
diff --git a/openlp/plugins/remotes/html/images/icons-36-white.png b/openlp/plugins/remotes/html/images/icons-36-white.png
new file mode 100644
index 000000000..e1b9c04ea
Binary files /dev/null and b/openlp/plugins/remotes/html/images/icons-36-white.png differ
diff --git a/openlp/plugins/remotes/html/images/ui-icon-blank.png b/openlp/plugins/remotes/html/images/ui-icon-blank.png
new file mode 100644
index 000000000..a685fe537
Binary files /dev/null and b/openlp/plugins/remotes/html/images/ui-icon-blank.png differ
diff --git a/openlp/plugins/remotes/html/images/ui-icon-unblank.png b/openlp/plugins/remotes/html/images/ui-icon-unblank.png
new file mode 100644
index 000000000..590361f44
Binary files /dev/null and b/openlp/plugins/remotes/html/images/ui-icon-unblank.png differ
diff --git a/openlp/plugins/remotes/html/index.html b/openlp/plugins/remotes/html/index.html
index 94bb24d32..bb3352f1f 100644
--- a/openlp/plugins/remotes/html/index.html
+++ b/openlp/plugins/remotes/html/index.html
@@ -1,57 +1,73 @@
-
-
-
Quick Links: Service Manager | Slide Controller | Miscellaneous
-(Click service item to go live.)
- -(Click verse to display.)
- -