diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py
index ef2520dac..7a1d1a679 100644
--- a/openlp/core/lib/__init__.py
+++ b/openlp/core/lib/__init__.py
@@ -223,6 +223,28 @@ def resize_image(image, width, height, background=QtCore.Qt.black):
painter.drawImage((width - realw) / 2, (height - realh) / 2, preview)
return new_image
+def check_search_result(treeWidget, search_results):
+ """
+ Checks if the given ``search_results`` is empty and adds a
+ "No Search Results" item to the given ``treeWidget``.
+
+ ``treeWidget``
+ The ``QTreeWidget`` where the "No Search Results" item should be added
+ to, if the ``search_results`` is empty.
+
+ ``search_results``
+ This can either be a list or a dict.
+ """
+ if search_results or treeWidget.count():
+ return
+ message = translate('OpenLP.MediaManagerItem', 'No Search Results')
+ item = QtGui.QListWidgetItem(message)
+ item.setFlags(QtCore.Qt.NoItemFlags)
+ font = QtGui.QFont()
+ font.setItalic(True)
+ item.setFont(font)
+ treeWidget.addItem(item)
+
def check_item_selected(list_widget, message):
"""
Check if a list item is selected so an action may be performed on it
diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py
index 42dab1e42..a160fec43 100644
--- a/openlp/core/lib/db.py
+++ b/openlp/core/lib/db.py
@@ -87,8 +87,8 @@ class BaseModel(object):
Creates an instance of a class and populates it, returning the instance
"""
instance = cls()
- for key in kwargs:
- instance.__setattr__(key, kwargs[key])
+ for key, value in kwargs.iteritems():
+ instance.__setattr__(key, value)
return instance
diff --git a/openlp/core/lib/eventreceiver.py b/openlp/core/lib/eventreceiver.py
index bee195b0f..f193ccd16 100644
--- a/openlp/core/lib/eventreceiver.py
+++ b/openlp/core/lib/eventreceiver.py
@@ -111,10 +111,6 @@ class EventReceiver(QtCore.QObject):
``servicemanager_set_item``
Go live on a specific item, by index
- ``servicemanager_list_request``
- Request the service list. Responds with servicemanager_list_response
- containing a array of dictionaries
-
``maindisplay_blank``
Blank the maindisplay window
diff --git a/openlp/core/lib/searchedit.py b/openlp/core/lib/searchedit.py
index 94152ef2f..b524855ba 100644
--- a/openlp/core/lib/searchedit.py
+++ b/openlp/core/lib/searchedit.py
@@ -74,10 +74,10 @@ class SearchEdit(QtGui.QLineEdit):
if hasattr(self, u'menuButton'):
leftPadding = self.menuButton.width()
self.setStyleSheet(
- u'QLineEdit { padding-left: %spx; padding-right: %spx; } ' % \
+ u'QLineEdit { padding-left: %spx; padding-right: %spx; } ' %
(leftPadding, rightPadding))
else:
- self.setStyleSheet(u'QLineEdit { padding-right: %spx; } ' % \
+ self.setStyleSheet(u'QLineEdit { padding-right: %spx; } ' %
rightPadding)
msz = self.minimumSizeHint()
self.setMinimumSize(
diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py
index a2cb014a4..c1ae95b8b 100644
--- a/openlp/core/lib/serviceitem.py
+++ b/openlp/core/lib/serviceitem.py
@@ -269,11 +269,9 @@ class ServiceItem(object):
}
service_data = []
if self.service_item_type == ServiceItemType.Text:
- for slide in self._raw_frames:
- service_data.append(slide)
+ service_data = [slide for slide in self._raw_frames]
elif self.service_item_type == ServiceItemType.Image:
- for slide in self._raw_frames:
- service_data.append(slide[u'title'])
+ service_data = [slide[u'title'] for slide in self._raw_frames]
elif self.service_item_type == ServiceItemType.Command:
for slide in self._raw_frames:
service_data.append(
diff --git a/openlp/core/ui/displaytagdialog.py b/openlp/core/ui/displaytagdialog.py
index 8e71a60ff..9bf6cb4d1 100644
--- a/openlp/core/ui/displaytagdialog.py
+++ b/openlp/core/ui/displaytagdialog.py
@@ -112,11 +112,14 @@ class Ui_DisplayTagDialog(object):
self.endTagLineEdit = QtGui.QLineEdit(self.editGroupBox)
self.endTagLineEdit.setObjectName(u'endTagLineEdit')
self.dataGridLayout.addWidget(self.endTagLineEdit, 4, 1, 1, 1)
- self.updatePushButton = QtGui.QPushButton(self.editGroupBox)
- self.updatePushButton.setObjectName(u'updatePushButton')
- self.dataGridLayout.addWidget(self.updatePushButton, 4, 2, 1, 1)
+ self.savePushButton = QtGui.QPushButton(self.editGroupBox)
+ self.savePushButton.setObjectName(u'savePushButton')
+ self.dataGridLayout.addWidget(self.savePushButton, 4, 2, 1, 1)
self.listdataGridLayout.addWidget(self.editGroupBox, 2, 0, 1, 1)
- self.buttonBox = create_accept_reject_button_box(displayTagDialog)
+ self.buttonBox = QtGui.QDialogButtonBox(displayTagDialog)
+ closeButton = QtGui.QDialogButtonBox.Close
+ self.buttonBox.setObjectName('displayTagDialogButtonBox')
+ self.buttonBox.setStandardButtons(closeButton)
self.listdataGridLayout.addWidget(self.buttonBox, 3, 0, 1, 1)
self.retranslateUi(displayTagDialog)
@@ -127,8 +130,8 @@ class Ui_DisplayTagDialog(object):
'Configure Display Tags'))
self.editGroupBox.setTitle(
translate('OpenLP.DisplayTagDialog', 'Edit Selection'))
- self.updatePushButton.setText(
- translate('OpenLP.DisplayTagDialog', 'Update'))
+ self.savePushButton.setText(
+ translate('OpenLP.DisplayTagDialog', 'Save'))
self.descriptionLabel.setText(
translate('OpenLP.DisplayTagDialog', 'Description'))
self.tagLabel.setText(translate('OpenLP.DisplayTagDialog', 'Tag'))
@@ -151,4 +154,4 @@ class Ui_DisplayTagDialog(object):
self.tagTableWidget.setColumnWidth(0, 120)
self.tagTableWidget.setColumnWidth(1, 40)
self.tagTableWidget.setColumnWidth(2, 240)
- self.tagTableWidget.setColumnWidth(3, 240)
\ No newline at end of file
+ self.tagTableWidget.setColumnWidth(3, 240)
diff --git a/openlp/core/ui/displaytagform.py b/openlp/core/ui/displaytagform.py
index 24cd14bd0..b8169b9be 100644
--- a/openlp/core/ui/displaytagform.py
+++ b/openlp/core/ui/displaytagform.py
@@ -54,10 +54,12 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
QtCore.SIGNAL(u'pressed()'), self.onDefaultPushed)
QtCore.QObject.connect(self.newPushButton,
QtCore.SIGNAL(u'pressed()'), self.onNewPushed)
- QtCore.QObject.connect(self.updatePushButton,
- QtCore.SIGNAL(u'pressed()'), self.onUpdatePushed)
+ QtCore.QObject.connect(self.savePushButton,
+ QtCore.SIGNAL(u'pressed()'), self.onSavedPushed)
QtCore.QObject.connect(self.deletePushButton,
QtCore.SIGNAL(u'pressed()'), self.onDeletePushed)
+ QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(u'rejected()'),
+ self.close)
def exec_(self):
"""
@@ -87,30 +89,6 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
for t in user_tags:
DisplayTags.add_html_tag(t)
- def accept(self):
- """
- Save Custom tags in a pickle .
- """
- temp = []
- for tag in DisplayTags.get_html_tags():
- if not tag[u'protected']:
- temp.append(tag)
- if temp:
- ctemp = cPickle.dumps(temp)
- QtCore.QSettings().setValue(u'displayTags/html_tags',
- QtCore.QVariant(ctemp))
- else:
- QtCore.QSettings().setValue(u'displayTags/html_tags',
- QtCore.QVariant(u''))
- return QtGui.QDialog.accept(self)
-
- def reject(self):
- """
- Reset Custom tags from Settings.
- """
- self._resetTable()
- return QtGui.QDialog.reject(self)
-
def onRowSelected(self):
"""
Table Row selected so display items and set field state.
@@ -127,14 +105,14 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
self.tagLineEdit.setEnabled(False)
self.startTagLineEdit.setEnabled(False)
self.endTagLineEdit.setEnabled(False)
- self.updatePushButton.setEnabled(False)
+ self.savePushButton.setEnabled(False)
self.deletePushButton.setEnabled(False)
else:
self.descriptionLineEdit.setEnabled(True)
self.tagLineEdit.setEnabled(True)
self.startTagLineEdit.setEnabled(True)
self.endTagLineEdit.setEnabled(True)
- self.updatePushButton.setEnabled(True)
+ self.savePushButton.setEnabled(True)
self.deletePushButton.setEnabled(True)
def onNewPushed(self):
@@ -174,9 +152,9 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
self.selected = -1
self._resetTable()
- def onUpdatePushed(self):
+ def onSavedPushed(self):
"""
- Update Custom Tag details if not duplicate.
+ Update Custom Tag details if not duplicate and save the data.
"""
html_expands = DisplayTags.get_html_tags()
if self.selected != -1:
@@ -197,6 +175,17 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
html[u'end tag'] = u'{/%s}' % tag
self.selected = -1
self._resetTable()
+ temp = []
+ for tag in DisplayTags.get_html_tags():
+ if not tag[u'protected']:
+ temp.append(tag)
+ if temp:
+ ctemp = cPickle.dumps(temp)
+ QtCore.QSettings().setValue(u'displayTags/html_tags',
+ QtCore.QVariant(ctemp))
+ else:
+ QtCore.QSettings().setValue(u'displayTags/html_tags',
+ QtCore.QVariant(u''))
def _resetTable(self):
"""
@@ -205,7 +194,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
self.tagTableWidget.clearContents()
self.tagTableWidget.setRowCount(0)
self.newPushButton.setEnabled(True)
- self.updatePushButton.setEnabled(False)
+ self.savePushButton.setEnabled(False)
self.deletePushButton.setEnabled(False)
for linenumber, html in enumerate(DisplayTags.get_html_tags()):
self.tagTableWidget.setRowCount(
diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py
index 622d60f79..279122937 100644
--- a/openlp/core/ui/exceptionform.py
+++ b/openlp/core/ui/exceptionform.py
@@ -130,9 +130,12 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
file.close()
file = open(filename, u'wb')
file.write(report.encode(u'utf-8'))
- file.close()
+ finally:
+ file.close()
except IOError:
log.exception(u'Failed to write crash report')
+ finally:
+ file.close()
def onSendReportButtonPressed(self):
"""
@@ -185,4 +188,5 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
def __buttonState(self, state):
self.saveReportButton.setEnabled(state)
- self.sendReportButton.setEnabled(state)
\ No newline at end of file
+ self.sendReportButton.setEnabled(state)
+
diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py
index aadc1c175..a115d8905 100644
--- a/openlp/core/ui/mainwindow.py
+++ b/openlp/core/ui/mainwindow.py
@@ -38,7 +38,7 @@ from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \
ThemeManager, SlideController, PluginForm, MediaDockManager, \
ShortcutListForm, DisplayTagForm
from openlp.core.utils import AppLocation, add_actions, LanguageManager, \
- get_application_version
+ get_application_version, delete_file
from openlp.core.utils.actions import ActionList, CategoryOrder
log = logging.getLogger(__name__)
@@ -657,8 +657,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
plugin.firstTime()
Receiver.send_message(u'openlp_process_events')
temp_dir = os.path.join(unicode(gettempdir()), u'openlp')
+ if not os.path.exists(temp_dir):
+ return
for filename in os.listdir(temp_dir):
- os.remove(os.path.join(temp_dir, filename))
+ delete_file(os.path.join(temp_dir, filename))
os.removedirs(temp_dir)
def blankCheck(self):
diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py
index d39c4ec6f..b5e8bbc54 100644
--- a/openlp/core/ui/servicemanager.py
+++ b/openlp/core/ui/servicemanager.py
@@ -274,8 +274,6 @@ class ServiceManager(QtGui.QWidget):
QtCore.SIGNAL(u'servicemanager_previous_item'), self.previousItem)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'servicemanager_set_item'), self.onSetItem)
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'servicemanager_list_request'), self.listRequest)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'config_updated'), self.configUpdated)
QtCore.QObject.connect(Receiver.get_receiver(),
@@ -1307,23 +1305,6 @@ class ServiceManager(QtGui.QWidget):
else:
return parentitem.data(0, QtCore.Qt.UserRole).toInt()[0]
- def listRequest(self, message=None):
- data = []
- item = self.findServiceItem()[0]
- if item >= 0 and item < len(self.serviceItems):
- curitem = self.serviceItems[item]
- else:
- curitem = None
- for item in self.serviceItems:
- service_item = item[u'service_item']
- data_item = {}
- data_item[u'title'] = unicode(service_item.get_display_title())
- data_item[u'plugin'] = unicode(service_item.name)
- data_item[u'notes'] = unicode(service_item.notes)
- data_item[u'selected'] = (item == curitem)
- data.append(data_item)
- Receiver.send_message(u'servicemanager_list_response', data)
-
def printServiceOrder(self):
"""
Print a Service Order Sheet.
diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py
index 7d21b57c4..461828d9e 100644
--- a/openlp/plugins/bibles/lib/mediaitem.py
+++ b/openlp/plugins/bibles/lib/mediaitem.py
@@ -29,7 +29,7 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
- translate
+ translate, check_search_result
from openlp.core.lib.searchedit import SearchEdit
from openlp.core.lib.ui import UiStrings, add_widget_completer, \
media_item_combo_box, critical_error_message_box, find_and_set_in_combo_box
@@ -61,6 +61,7 @@ class BibleMediaItem(MediaManagerItem):
self.quickPreviewAllowed = True
self.search_results = {}
self.second_search_results = {}
+ check_search_result(self.listView, self.search_results)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'bibles_load_list'), self.reloadBibles)
@@ -522,8 +523,9 @@ class BibleMediaItem(MediaManagerItem):
self.__checkSecondBible(bible, second_bible)
elif self.search_results:
self.displayResults(bible, second_bible)
- Receiver.send_message(u'cursor_normal')
self.advancedSearchButton.setEnabled(True)
+ check_search_result(self.listView, self.search_results)
+ Receiver.send_message(u'cursor_normal')
Receiver.send_message(u'openlp_process_events')
def onQuickSearchButton(self):
@@ -563,6 +565,7 @@ class BibleMediaItem(MediaManagerItem):
elif self.search_results:
self.displayResults(bible, second_bible)
self.quickSearchButton.setEnabled(True)
+ check_search_result(self.listView, self.search_results)
Receiver.send_message(u'cursor_normal')
Receiver.send_message(u'openlp_process_events')
diff --git a/openlp/plugins/remotes/html/openlp.js b/openlp/plugins/remotes/html/openlp.js
index e6efbb2c5..811ce0cac 100644
--- a/openlp/plugins/remotes/html/openlp.js
+++ b/openlp/plugins/remotes/html/openlp.js
@@ -48,6 +48,7 @@ window.OpenLP = {
$.each(data.results.items, function (idx, value) {
var li = $("
").append(
$("").attr("value", parseInt(idx, 10)).text(value["title"]));
+ li.attr("uuid", value["id"])
li.children("a").click(OpenLP.setItem);
ul.append(li);
});
@@ -119,10 +120,10 @@ window.OpenLP = {
$("#service-manager div[data-role=content] ul[data-role=listview] li").attr("data-theme", "c").removeClass("ui-btn-up-e").addClass("ui-btn-up-c");
$("#service-manager div[data-role=content] ul[data-role=listview] li a").each(function () {
var item = $(this);
- if (item.text() == OpenLP.currentItem) {
- while (item[0].tagName != "LI") {
- item = item.parent();
- }
+ while (item[0].tagName != "LI") {
+ item = item.parent();
+ }
+ if (item.attr("uuid") == OpenLP.currentItem) {
item.attr("data-theme", "e").removeClass("ui-btn-up-c").addClass("ui-btn-up-e");
return false;
}
diff --git a/openlp/plugins/remotes/html/stage.css b/openlp/plugins/remotes/html/stage.css
new file mode 100644
index 000000000..a773c2393
--- /dev/null
+++ b/openlp/plugins/remotes/html/stage.css
@@ -0,0 +1,66 @@
+/*****************************************************************************
+ * OpenLP - Open Source Lyrics Projection *
+ * ------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2010 Raoul Snyman *
+ * Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael *
+ * Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, *
+ * Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, *
+ * Maikel Stuivenberg, Martin Thompson, Jon Tibble, 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 *
+ *****************************************************************************/
+
+body {
+ background-color: black;
+ font-family: sans-serif;
+ overflow: hidden;
+}
+
+#currentslide {
+ font-size: 40pt;
+ color: white;
+}
+
+#nextslide {
+ font-size: 30pt;
+ color: grey;
+ padding-top: 25px;
+}
+
+#right {
+ float: right;
+}
+
+#clock {
+ font-size: 40pt;
+ color: yellow;
+ text-align: right;
+}
+
+#notes {
+ font-size: 36pt;
+ color: salmon;
+ text-align: right;
+}
+
+#verseorder {
+ font-size: 30pt;
+ color: green;
+ text-align: left;
+}
+
+.currenttag {
+ color: lightgreen;
+ font-weight: bold;
+}
diff --git a/openlp/plugins/remotes/html/stage.html b/openlp/plugins/remotes/html/stage.html
new file mode 100644
index 000000000..99090b6f9
--- /dev/null
+++ b/openlp/plugins/remotes/html/stage.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+ OpenLP 2.0 Remote
+
+
+
+
+
+
+
+
+
+
+
diff --git a/openlp/plugins/remotes/html/stage.js b/openlp/plugins/remotes/html/stage.js
new file mode 100644
index 000000000..8b8a83f6a
--- /dev/null
+++ b/openlp/plugins/remotes/html/stage.js
@@ -0,0 +1,104 @@
+/*****************************************************************************
+ * OpenLP - Open Source Lyrics Projection *
+ * ------------------------------------------------------------------------- *
+ * Copyright (c) 2008-2010 Raoul Snyman *
+ * Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael *
+ * Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, *
+ * Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, *
+ * Maikel Stuivenberg, Martin Thompson, Jon Tibble, 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 *
+ *****************************************************************************/
+window.OpenLP = {
+ loadService: function (event) {
+ $.getJSON(
+ "/api/service/list",
+ function (data, status) {
+ OpenLP.nextSong = "";
+ $("#notes").html("");
+ for (idx in data.results.items) {
+ idx = parseInt(idx, 10);
+ if ((data.results.items[idx]["selected"]) &&
+ (data.results.items.length > idx + 1)) {
+ $("#notes").html(data.results.items[idx]["notes"]);
+ OpenLP.nextSong = data.results.items[idx + 1]["title"];
+ break;
+ }
+ }
+ OpenLP.updateSlide();
+ }
+ );
+ },
+ loadSlides: function (event) {
+ $.getJSON(
+ "/api/controller/live/text",
+ function (data, status) {
+ OpenLP.currentSlides = data.results.slides;
+ OpenLP.currentSlide = 0;
+ var div = $("#verseorder");
+ div.html("");
+ for (idx in data.results.slides) {
+ idx = parseInt(idx, 10);
+ div.append(" ");
+ var tag = data.results.slides[idx]["tag"];
+ if (tag == 'None')
+ tag = idx;
+ $("#verseorder span").last().attr("id", "tag" + idx).text(tag);
+ if (data.results.slides[idx]["selected"])
+ OpenLP.currentSlide = idx;
+ }
+ OpenLP.loadService();
+ }
+ );
+ },
+ updateSlide: function() {
+ $("#verseorder span").removeClass("currenttag");
+ $("#tag" + OpenLP.currentSlide).addClass("currenttag");
+ $("#currentslide").html(OpenLP.currentSlides[OpenLP.currentSlide]["text"]);
+ if (OpenLP.currentSlide < OpenLP.currentSlides.length - 1)
+ $("#nextslide").html(OpenLP.currentSlides[OpenLP.currentSlide + 1]["text"]);
+ else
+ $("#nextslide").html("Next: " + OpenLP.nextSong);
+ },
+ updateClock: function() {
+ var div = $("#clock");
+ var t = new Date();
+ var h = t.getHours();
+ if (h > 12)
+ h = h - 12;
+ var m = t.getMinutes();
+ if (m < 10)
+ m = '0' + m + '';
+ div.html(h + ":" + m);
+ },
+ pollServer: function () {
+ $.getJSON(
+ "/api/poll",
+ function (data, status) {
+ OpenLP.updateClock();
+ if (OpenLP.currentItem != data.results.item) {
+ OpenLP.currentItem = data.results.item;
+ OpenLP.loadSlides();
+ }
+ else if (OpenLP.currentSlide != data.results.slide) {
+ OpenLP.currentSlide = parseInt(data.results.slide, 10);
+ OpenLP.updateSlide();
+ }
+ }
+ );
+ }
+}
+$.ajaxSetup({ cache: false });
+setInterval("OpenLP.pollServer();", 500);
+OpenLP.pollServer();
diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py
index caf4ba396..70f02ff36 100644
--- a/openlp/plugins/remotes/lib/httpserver.py
+++ b/openlp/plugins/remotes/lib/httpserver.py
@@ -34,6 +34,9 @@ the remotes.
``/``
Go to the web interface.
+``/stage``
+ Show the stage view.
+
``/files/{filename}``
Serve a static file.
@@ -241,6 +244,7 @@ class HttpConnection(object):
self.parent = parent
self.routes = [
(u'^/$', self.serve_file),
+ (u'^/(stage)$', self.serve_file),
(r'^/files/(.*)$', self.serve_file),
(r'^/api/poll$', self.poll),
(r'^/api/controller/(live|preview)/(.*)$', self.controller),
@@ -256,18 +260,18 @@ class HttpConnection(object):
def _get_service_items(self):
service_items = []
service_manager = self.parent.parent.serviceManager
- item = service_manager.findServiceItem()[0]
- if item >= 0 and item < len(service_manager.serviceItems):
- curitem = service_manager.serviceItems[item]
+ if self.parent.current_item:
+ cur_uuid = self.parent.current_item._uuid
else:
- curitem = None
+ cur_uuid = None
for item in service_manager.serviceItems:
service_item = item[u'service_item']
service_items.append({
+ u'id': unicode(service_item._uuid),
u'title': unicode(service_item.get_display_title()),
u'plugin': unicode(service_item.name),
u'notes': unicode(service_item.notes),
- u'selected': (item == curitem)
+ u'selected': (service_item._uuid == cur_uuid)
})
return service_items
@@ -312,6 +316,8 @@ class HttpConnection(object):
log.debug(u'serve file request %s' % filename)
if not filename:
filename = u'index.html'
+ elif filename == u'stage':
+ filename = u'stage.html'
path = os.path.normpath(os.path.join(self.parent.html_dir, filename))
if not path.startswith(self.parent.html_dir):
return HttpResponse(code=u'404 Not Found')
@@ -349,7 +355,7 @@ class HttpConnection(object):
"""
result = {
u'slide': self.parent.current_slide or 0,
- u'item': self.parent.current_item.title \
+ u'item': self.parent.current_item._uuid \
if self.parent.current_item else u''
}
return HttpResponse(json.dumps({u'results': result}),
diff --git a/openlp/plugins/remotes/lib/remotetab.py b/openlp/plugins/remotes/lib/remotetab.py
index 297437d93..bfb05d486 100644
--- a/openlp/plugins/remotes/lib/remotetab.py
+++ b/openlp/plugins/remotes/lib/remotetab.py
@@ -24,10 +24,12 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
-from PyQt4 import QtCore, QtGui
+from PyQt4 import QtCore, QtGui, QtNetwork
from openlp.core.lib import SettingsTab, translate
+ZERO_URL = u'0.0.0.0'
+
class RemoteTab(SettingsTab):
"""
RemoteTab is the Remotes settings tab in the settings dialog.
@@ -51,13 +53,29 @@ class RemoteTab(SettingsTab):
self.addressEdit.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp(
u'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'), self))
self.addressEdit.setObjectName(u'addressEdit')
+ QtCore.QObject.connect(self.addressEdit,
+ QtCore.SIGNAL(u'textChanged(const QString&)'), self.setUrls)
self.serverSettingsLayout.addRow(self.addressLabel, self.addressEdit)
self.portLabel = QtGui.QLabel(self.serverSettingsGroupBox)
self.portLabel.setObjectName(u'portLabel')
self.portSpinBox = QtGui.QSpinBox(self.serverSettingsGroupBox)
self.portSpinBox.setMaximum(32767)
self.portSpinBox.setObjectName(u'portSpinBox')
+ QtCore.QObject.connect(self.portSpinBox,
+ QtCore.SIGNAL(u'valueChanged(int)'), self.setUrls)
self.serverSettingsLayout.addRow(self.portLabel, self.portSpinBox)
+ self.remoteUrlLabel = QtGui.QLabel(self.serverSettingsGroupBox)
+ self.remoteUrlLabel.setObjectName(u'remoteUrlLabel')
+ self.remoteUrl = QtGui.QLabel(self.serverSettingsGroupBox)
+ self.remoteUrl.setObjectName(u'remoteUrl')
+ self.remoteUrl.setOpenExternalLinks(True)
+ self.serverSettingsLayout.addRow(self.remoteUrlLabel, self.remoteUrl)
+ self.stageUrlLabel = QtGui.QLabel(self.serverSettingsGroupBox)
+ self.stageUrlLabel.setObjectName(u'stageUrlLabel')
+ self.stageUrl = QtGui.QLabel(self.serverSettingsGroupBox)
+ self.stageUrl.setObjectName(u'stageUrl')
+ self.stageUrl.setOpenExternalLinks(True)
+ self.serverSettingsLayout.addRow(self.stageUrlLabel, self.stageUrl)
self.leftLayout.addWidget(self.serverSettingsGroupBox)
self.leftLayout.addStretch()
self.rightLayout.addStretch()
@@ -69,6 +87,34 @@ class RemoteTab(SettingsTab):
'Serve on IP address:'))
self.portLabel.setText(translate('RemotePlugin.RemoteTab',
'Port number:'))
+ self.remoteUrlLabel.setText(translate('RemotePlugin.RemoteTab',
+ 'Remote URL:'))
+ self.stageUrlLabel.setText(translate('RemotePlugin.RemoteTab',
+ 'Stage view URL:'))
+
+ def setUrls(self):
+ ipAddress = None
+ if self.addressEdit.text() == ZERO_URL:
+ for ip in QtNetwork.QNetworkInterface.allAddresses():
+ if ip.protocol() == 0 and ip != QtNetwork.QHostAddress.LocalHost:
+ ipAddress = ip.toString()
+ break
+ else:
+ ipAddress = self.addressEdit.text()
+ if not ipAddress:
+ self.remoteUrlLabel.setVisible(False)
+ self.remoteUrl.setVisible(False)
+ self.stageUrlLabel.setVisible(False)
+ self.stageUrl.setVisible(False)
+ return
+ self.remoteUrlLabel.setVisible(True)
+ self.remoteUrl.setVisible(True)
+ self.stageUrlLabel.setVisible(True)
+ self.stageUrl.setVisible(True)
+ url = u'http://%s:%s/' % (ipAddress, self.portSpinBox.value())
+ self.remoteUrl.setText(u'%s' % (url, url))
+ url = url + u'stage'
+ self.stageUrl.setText(u'%s' % (url, url))
def load(self):
self.portSpinBox.setValue(
@@ -76,7 +122,8 @@ class RemoteTab(SettingsTab):
QtCore.QVariant(4316)).toInt()[0])
self.addressEdit.setText(
QtCore.QSettings().value(self.settingsSection + u'/ip address',
- QtCore.QVariant(u'0.0.0.0')).toString())
+ QtCore.QVariant(ZERO_URL)).toString())
+ self.setUrls()
def save(self):
QtCore.QSettings().setValue(self.settingsSection + u'/port',
diff --git a/openlp/plugins/songs/forms/songexportform.py b/openlp/plugins/songs/forms/songexportform.py
index 745ee3f67..dbd0eb9af 100644
--- a/openlp/plugins/songs/forms/songexportform.py
+++ b/openlp/plugins/songs/forms/songexportform.py
@@ -329,7 +329,7 @@ class SongExportForm(OpenLPWizard):
self.availableListWidget, unicode(text))
]
for item in self._findListWidgetItems(self.availableListWidget):
- item.setHidden(False if item in search_result else True)
+ item.setHidden(item not in search_result)
def onUncheckButtonClicked(self):
"""
@@ -360,4 +360,5 @@ class SongExportForm(OpenLPWizard):
SettingsManager.get_last_dir(self.plugin.settingsSection, 1),
options=QtGui.QFileDialog.ShowDirsOnly))
SettingsManager.set_last_dir(self.plugin.settingsSection, path, 1)
- self.directoryLineEdit.setText(path)
\ No newline at end of file
+ self.directoryLineEdit.setText(path)
+
diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py
index a3015d422..3b014d4b0 100644
--- a/openlp/plugins/songs/lib/mediaitem.py
+++ b/openlp/plugins/songs/lib/mediaitem.py
@@ -32,7 +32,7 @@ from PyQt4 import QtCore, QtGui
from sqlalchemy.sql import or_
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
- translate, check_item_selected, PluginStatus
+ translate, check_item_selected, PluginStatus, check_search_result
from openlp.core.lib.searchedit import SearchEdit
from openlp.core.lib.ui import UiStrings
from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
@@ -199,6 +199,7 @@ class SongMediaItem(MediaManagerItem):
search_results = self.parent.manager.get_all_objects(Song,
Song.theme_name == search_keywords)
self.displayResultsSong(search_results)
+ check_search_result(self.listView, search_results)
def onSongListLoad(self):
"""
diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py
index 853caef0e..f3c5705da 100644
--- a/openlp/plugins/songs/songsplugin.py
+++ b/openlp/plugins/songs/songsplugin.py
@@ -229,12 +229,14 @@ class SongsPlugin(Plugin):
If the first time wizard has run, this function is run to import all the
new songs into the database.
"""
+ self.onToolsReindexItemTriggered()
db_dir = unicode(os.path.join(gettempdir(), u'openlp'))
+ if not os.path.exists(db_dir):
+ return
song_dbs = []
for sfile in os.listdir(db_dir):
if sfile.startswith(u'songs_') and sfile.endswith(u'.sqlite'):
song_dbs.append(os.path.join(db_dir, sfile))
- self.onToolsReindexItemTriggered()
if len(song_dbs) == 0:
return
progress = QtGui.QProgressDialog(self.formparent)