This commit is contained in:
rimach 2012-03-20 22:21:47 +01:00
commit 8a029daf11
62 changed files with 64405 additions and 21493 deletions

View File

@ -33,7 +33,8 @@ from urllib import quote_plus as urlquote
from PyQt4 import QtCore
from sqlalchemy import Table, MetaData, Column, types, create_engine
from sqlalchemy.exc import SQLAlchemyError, InvalidRequestError, DBAPIError
from sqlalchemy.exc import SQLAlchemyError, InvalidRequestError, DBAPIError, \
OperationalError
from sqlalchemy.orm import scoped_session, sessionmaker, mapper
from sqlalchemy.pool import NullPool

View File

@ -217,6 +217,9 @@ class EventReceiver(QtCore.QObject):
Ask the plugin to process an individual service item after it has been
loaded.
``{plugin}_config_updated``
The config has changed so tell the plugin about it.
``alerts_text``
Displays an alert message.

View File

@ -166,7 +166,7 @@ class ImageManager(QtCore.QObject):
self.height = current_screen[u'size'].height()
# Mark the images as dirty for a rebuild by setting the image and byte
# stream to None.
for key, image in self._cache.iteritems():
for image in self._cache.values():
self._reset_image(image)
def update_images(self, image_type, background):
@ -176,7 +176,7 @@ class ImageManager(QtCore.QObject):
log.debug(u'update_images')
# Mark the images as dirty for a rebuild by setting the image and byte
# stream to None.
for key, image in self._cache.iteritems():
for image in self._cache.values():
if image.source == image_type:
image.background = background
self._reset_image(image)
@ -188,7 +188,7 @@ class ImageManager(QtCore.QObject):
log.debug(u'update_images')
# Mark the images as dirty for a rebuild by setting the image and byte
# stream to None.
for key, image in self._cache.iteritems():
for image in self._cache.values():
if image.source == image_type and image.name == name:
image.background = background
self._reset_image(image)

View File

@ -641,7 +641,7 @@ class MediaManagerItem(QtGui.QWidget):
if item:
self.autoSelectId = item.data(QtCore.Qt.UserRole).toInt()[0]
def search(self, string):
def search(self, string, showError=True):
"""
Performs a plugin specific search for items containing ``string``
"""

View File

@ -173,6 +173,9 @@ class Plugin(QtCore.QObject):
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'%s_add_service_item' % self.name),
self.processAddServiceEvent)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'%s_config_updated' % self.name),
self.configUpdated)
def checkPreConditions(self):
"""
@ -395,3 +398,9 @@ class Plugin(QtCore.QObject):
Add html code to htmlbuilder.
"""
return u''
def configUpdated(self):
"""
The plugin's config has changed
"""
pass

View File

@ -300,6 +300,7 @@ class ServiceItem(object):
``path``
Defaults to *None*. Any path data, usually for images.
"""
log.debug(u'set_from_service called with path %s' % path)
header = serviceitem[u'serviceitem'][u'header']
self.title = header[u'title']
self.name = header[u'name']
@ -325,7 +326,10 @@ class ServiceItem(object):
if u'media_length' in header:
self.media_length = header[u'media_length']
if u'background_audio' in header:
self.background_audio = header[u'background_audio']
self.background_audio = []
for filename in header[u'background_audio']:
# Give them real file paths
self.background_audio.append(os.path.join(path, filename))
self.theme_overwritten = header.get(u'theme_overwritten', False)
if self.service_item_type == ServiceItemType.Text:
for slide in serviceitem[u'serviceitem'][u'data']:

View File

@ -53,13 +53,10 @@ class AdvancedTab(SettingsTab):
self.defaultServiceMinute = 0
self.defaultServiceName = unicode(translate('OpenLP.AdvancedTab',
'Service %Y-%m-%d %H-%M',
'This is the default default service name template, which can be '
'found under Advanced in Settings, Configure OpenLP. Please do not '
'include any of the following characters: /\\?*|<>\[\]":+\n'
'You can use any of the directives as shown on page '
'http://docs.python.org/library/datetime.html'
'#strftime-strptime-behavior , but if possible, please keep '
'the resulting string sortable by name.'))
'This may not contain any of the following characters: '
'/\\?*|<>\[\]":+\n'
'See http://docs.python.org/library/datetime.html'
'#strftime-strptime-behavior for more information.'))
self.defaultImage = u':/graphics/openlp-splash-screen.png'
self.defaultColor = u'#ffffff'
self.icon_path = u':/system/system_settings.png'

View File

@ -295,7 +295,8 @@ class GeneralTab(SettingsTab):
QtCore.QVariant(False)).toBool())
self.timeoutSpinBox.setValue(settings.value(u'loop delay',
QtCore.QVariant(5)).toInt()[0])
self.monitorRadioButton.setChecked(not settings.value(u'override position',
self.monitorRadioButton.setChecked(
not settings.value(u'override position',
QtCore.QVariant(False)).toBool())
self.overrideRadioButton.setChecked(settings.value(u'override position',
QtCore.QVariant(False)).toBool())
@ -313,11 +314,14 @@ class GeneralTab(SettingsTab):
u'audio repeat list', QtCore.QVariant(False)).toBool())
settings.endGroup()
self.monitorComboBox.setDisabled(self.overrideRadioButton.isChecked())
self.displayOnMonitorCheck.setDisabled(self.overrideRadioButton.isChecked())
self.displayOnMonitorCheck.setDisabled(
self.overrideRadioButton.isChecked())
self.customXValueEdit.setEnabled(self.overrideRadioButton.isChecked())
self.customYValueEdit.setEnabled(self.overrideRadioButton.isChecked())
self.customHeightValueEdit.setEnabled(self.overrideRadioButton.isChecked())
self.customWidthValueEdit.setEnabled(self.overrideRadioButton.isChecked())
self.customHeightValueEdit.setEnabled(
self.overrideRadioButton.isChecked())
self.customWidthValueEdit.setEnabled(
self.overrideRadioButton.isChecked())
self.display_changed = False
settings.beginGroup(self.settingsSection)

View File

@ -150,6 +150,11 @@ class MediaController(object):
if self.curDisplayMediaPlayer[display] \
.state == MediaState.Playing:
return
# no players are active anymore
for display in self.curDisplayMediaPlayer.keys():
if self.curDisplayMediaPlayer[display] \
.state != MediaState.Paused:
display.controller.seekSlider.setSliderPosition(0)
self.timer.stop()
def get_media_display_css(self):
@ -271,7 +276,8 @@ class MediaController(object):
controller.mediabar.setVisible(value)
if controller.isLive and controller.display:
if self.curDisplayMediaPlayer and value:
if self.curDisplayMediaPlayer[controller.display] != self.mediaPlayers[u'webkit']:
if self.curDisplayMediaPlayer[controller.display] != \
self.mediaPlayers[u'webkit']:
controller.display.setTransparency(False)
# Special controls: Here media type specific Controls will be enabled
# (e.g. for DVD control, ...)
@ -437,6 +443,7 @@ class MediaController(object):
display.frame.evaluateJavaScript(u'show_blank("black");')
self.curDisplayMediaPlayer[display].stop(display)
self.curDisplayMediaPlayer[display].set_visible(display, False)
controller.seekSlider.setSliderPosition(0)
def video_volume(self, msg):
"""

View File

@ -57,7 +57,7 @@ ADDITIONAL_EXT = {
class PhononPlayer(MediaPlayer):
"""
A specialised version of the MediaPlayer class, which provides a Phonon
A specialised version of the MediaPlayer class, which provides a Phonon
display.
"""
@ -192,6 +192,9 @@ class PhononPlayer(MediaPlayer):
display.phononWidget.setVisible(status)
def update_ui(self, display):
if display.mediaObject.state() == Phonon.PausedState and \
self.state != MediaState.Paused:
self.stop(display)
controller = display.controller
if controller.media_info.end_time > 0:
if display.mediaObject.currentTime() > \

View File

@ -83,7 +83,7 @@ VIDEO_EXT = [
class VlcPlayer(MediaPlayer):
"""
A specialised version of the MediaPlayer class, which provides a QtWebKit
A specialised version of the MediaPlayer class, which provides a VLC
display.
"""
@ -122,7 +122,7 @@ class VlcPlayer(MediaPlayer):
display.vlcMediaPlayer.set_hwnd(int(display.vlcWidget.winId()))
elif sys.platform == "darwin": # for MacOS
display.vlcMediaPlayer.set_agl(int(display.vlcWidget.winId()))
else:
else:
# for Linux using the X Server
display.vlcMediaPlayer.set_xwindow(int(display.vlcWidget.winId()))
self.hasOwnWidget = True
@ -210,6 +210,8 @@ class VlcPlayer(MediaPlayer):
display.vlcWidget.setVisible(status)
def update_ui(self, display):
if display.vlcMedia.get_state() == vlc.State.Ended:
self.stop(display)
controller = display.controller
if controller.media_info.end_time > 0:
if display.vlcMediaPlayer.get_time() > \

View File

@ -126,7 +126,7 @@ VIDEO_JS = u"""
vid.src = '';
vid2.src = '';
break;
case 'length':
case 'length':
return vid.duration;
case 'currentTime':
return vid.currentTime;
@ -134,6 +134,8 @@ VIDEO_JS = u"""
// doesnt work currently
vid.currentTime = varVal;
break;
case 'isEnded':
return vid.ended;
case 'setVisible':
vid.style.visibility = varVal;
break;
@ -211,6 +213,8 @@ FLASH_JS = u"""
case 'seek':
// flashMovie.GotoFrame(varVal);
break;
case 'isEnded':
return false;//TODO check flash end
case 'setVisible':
text.style.visibility = varVal;
break;
@ -254,7 +258,7 @@ AUDIO_EXT = [
class WebkitPlayer(MediaPlayer):
"""
A specialised version of the MediaPlayer class, which provides a QtWebKit
A specialised version of the MediaPlayer class, which provides a QtWebKit
display.
"""
@ -356,7 +360,6 @@ class WebkitPlayer(MediaPlayer):
display.frame.evaluateJavaScript(u'show_flash("stop");')
else:
display.frame.evaluateJavaScript(u'show_video("stop");')
controller.seekSlider.setSliderPosition(0)
self.state = MediaState.Stopped
def volume(self, display, vol):
@ -408,6 +411,9 @@ class WebkitPlayer(MediaPlayer):
length = display.frame.evaluateJavaScript( \
u'show_flash("length");').toInt()[0]
else:
if display.frame.evaluateJavaScript( \
u'show_video("isEnded");').toString() == 'true':
self.stop(display)
(currentTime, ok) = display.frame.evaluateJavaScript( \
u'show_video("currentTime");').toFloat()
# check if conversion was ok and value is not 'NaN'

View File

@ -405,7 +405,7 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
# Only continue when we include the song's text.
if not self.slideTextCheckBox.isChecked():
return
for index, item in enumerate(self.serviceManager.serviceItems):
for item in self.serviceManager.serviceItems:
# Trigger Audit requests
Receiver.send_message(u'print_service_started',
[item[u'service_item']])

View File

@ -461,7 +461,7 @@ class ServiceManager(QtGui.QWidget):
log.debug(temp_file_name)
path_file_name = unicode(self.fileName())
path, file_name = os.path.split(path_file_name)
basename, extension = os.path.splitext(file_name)
basename = os.path.splitext(file_name)[0]
service_file_name = '%s.osd' % basename
log.debug(u'ServiceManager.saveFile - %s', path_file_name)
SettingsManager.set_last_dir(
@ -483,8 +483,7 @@ class ServiceManager(QtGui.QWidget):
for i, filename in \
enumerate(service_item[u'header'][u'background_audio']):
new_file = os.path.join(u'audio',
item[u'service_item']._uuid,
os.path.split(filename)[1])
item[u'service_item']._uuid, filename)
audio_files.append((filename, new_file))
service_item[u'header'][u'background_audio'][i] = new_file
# Add the service item to the service.
@ -610,16 +609,11 @@ class ServiceManager(QtGui.QWidget):
time = time.replace(hour=service_hour, minute=service_minute)
default_pattern = unicode(QtCore.QSettings().value(
u'advanced/default service name',
translate('OpenLP.AdvancedTab',
'Service %Y-%m-%d %H-%M',
'This is the default default service name template, which can '
'be found under Advanced in Settings, Configure OpenLP. '
'Please do not include any of the following characters: '
'/\\?*|<>\[\]":+\n'
'You can use any of the directives as shown on page '
'http://docs.python.org/library/datetime.html'
'#strftime-strptime-behavior , but if possible, please keep '
'the resulting string sortable by name.')).toString())
translate('OpenLP.AdvancedTab', 'Service %Y-%m-%d %H-%M',
'This may not contain any of the following characters: '
'/\\?*|<>\[\]":+\nSee http://docs.python.org/library/'
'datetime.html#strftime-strptime-behavior for more '
'information.')).toString())
default_filename = time.strftime(default_pattern)
else:
default_filename = u''
@ -1359,15 +1353,15 @@ class ServiceManager(QtGui.QWidget):
Handle of the event pint passed
"""
link = event.mimeData()
if event.mimeData().hasUrls():
if link.hasUrls():
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()
for url in event.mimeData().urls():
for url in link.urls():
filename = unicode(url.toLocalFile())
if filename.endswith(u'.osz'):
self.onLoadServiceClicked(filename)
elif event.mimeData().hasText():
plugin = unicode(event.mimeData().text())
elif link.hasText():
plugin = unicode(link.text())
item = self.serviceManagerList.itemAt(event.pos())
# ServiceManager started the drag and drop
if plugin == u'ServiceManager':

View File

@ -57,7 +57,7 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
def exec_(self):
# load all the settings
self.settingListWidget.clear()
for tabIndex in range(0, self.stackedLayout.count() + 1):
while self.stackedLayout.count():
# take at 0 and the rest shuffle up.
self.stackedLayout.takeAt(0)
self.insertTab(self.generalTab, 0, PluginStatus.Active)

View File

@ -186,7 +186,7 @@ class SlideController(Controller):
tooltip=translate('OpenLP.SlideController', 'Move to next.'),
shortcuts=[QtCore.Qt.Key_Down, QtCore.Qt.Key_PageDown],
context=QtCore.Qt.WidgetWithChildrenShortcut,
category=self.category, triggers=self.onSlideSelectedNext)
category=self.category, triggers=self.onSlideSelectedNextAction)
self.toolbar.addAction(self.nextItem)
self.toolbar.addSeparator()
if self.isLive:
@ -563,7 +563,8 @@ class SlideController(Controller):
Receiver.send_message('servicemanager_previous_item')
elif keypressCommand == ServiceItemAction.PreviousLastSlide:
# Go to the last slide of the previous item
Receiver.send_message('servicemanager_previous_item', u'last slide')
Receiver.send_message('servicemanager_previous_item',
u'last slide')
else:
Receiver.send_message('servicemanager_next_item')
self.keypress_loop = False
@ -1139,6 +1140,13 @@ class SlideController(Controller):
rect.y(), rect.width(), rect.height())
self.slidePreview.setPixmap(winimg)
def onSlideSelectedNextAction(self, checked):
"""
Wrapper function from create_action so we can throw away the
incorrect parameter
"""
self.onSlideSelectedNext()
def onSlideSelectedNext(self, wrap=None):
"""
Go to the next slide.
@ -1183,7 +1191,8 @@ class SlideController(Controller):
if self.slide_limits == SlideLimits.Wrap:
row = self.previewListWidget.rowCount() - 1
elif self.isLive and self.slide_limits == SlideLimits.Next:
self.keypress_queue.append(ServiceItemAction.PreviousLastSlide)
self.keypress_queue.append(
ServiceItemAction.PreviousLastSlide)
self._process_queue()
return
else:

View File

@ -153,7 +153,6 @@ class ThemeManager(QtGui.QWidget):
Import new themes downloaded by the first time wizard
"""
Receiver.send_message(u'cursor_busy')
encoding = get_filesystem_encoding()
files = SettingsManager.get_files(self.settingsSection, u'.otz')
for file in files:
file = os.path.join(self.path, file)

View File

@ -27,7 +27,7 @@
import logging
from PyQt4 import QtCore, QtGui
from PyQt4 import QtGui
from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.core.lib.ui import create_action, UiStrings

View File

@ -183,13 +183,8 @@ def update_reference_separators():
"""
default_separators = unicode(translate('BiblesPlugin',
':|v|V|verse|verses;;-|to;;,|and;;end',
'This are 4 values seperated each by two semicolons representing the '
'seperators for parsing references. This values are verse separators, '
'range separators, list separators and end mark. Alternative values '
'to be seperated by a vertical bar "|". In this case the first value '
'is the default and used for the display format. If a semicolon should '
'be used you have to give an alternative separator afterwards to allow '
'OpenLP correct splitting of the translation.')).split(u';;')
'Double-semicolon delimited separators for parsing references. '
'Consult the developers for further information.')).split(u';;')
settings = QtCore.QSettings()
settings.beginGroup(u'bibles')
custom_separators = [

View File

@ -1025,12 +1025,13 @@ class BibleMediaItem(MediaManagerItem):
return u'{su}[%s]{/su}' % verse_text
return u'{su}%s{/su}' % verse_text
def search(self, string):
def search(self, string, showError):
"""
Search for some Bible verses (by reference).
"""
bible = unicode(self.quickVersionComboBox.currentText())
search_results = self.plugin.manager.get_verses(bible, string, False)
search_results = self.plugin.manager.get_verses(bible, string, False,
showError)
if search_results:
versetext = u' '.join([verse.text for verse in search_results])
return [[string, versetext]]

View File

@ -177,7 +177,7 @@ class CustomMediaItem(MediaManagerItem):
UiStrings().ConfirmDelete,
translate('CustomPlugin.MediaItem',
'Are you sure you want to delete the %n selected custom'
' slides(s)?', '',
' slide(s)?', '',
QtCore.QCoreApplication.CodecForTr, len(items)),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes |
QtGui.QMessageBox.No),
@ -267,7 +267,7 @@ class CustomMediaItem(MediaManagerItem):
self.searchTextEdit.clear()
self.onSearchTextButtonClick()
def search(self, string):
def search(self, string, showError):
search_results = self.manager.get_all_objects(CustomSlide,
or_(func.lower(CustomSlide.title).like(u'%' +
string.lower() + u'%'),

View File

@ -189,7 +189,7 @@ class ImageMediaItem(MediaManagerItem):
# Continue with the existing images.
for bitem in items:
filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())
(path, name) = os.path.split(filename)
name = os.path.split(filename)[1]
service_item.add_from_image(filename, name, background)
return True
@ -220,7 +220,7 @@ class ImageMediaItem(MediaManagerItem):
bitem = self.listView.item(item.row())
filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())
if os.path.exists(filename):
(path, name) = os.path.split(filename)
name = os.path.split(filename)[1]
if self.plugin.liveController.display.directImage(name,
filename, background):
self.resetAction.setVisible(True)
@ -234,7 +234,7 @@ class ImageMediaItem(MediaManagerItem):
'There was a problem replacing your background, '
'the image file "%s" no longer exists.')) % filename)
def search(self, string):
def search(self, string, showError):
files = SettingsManager.load_list(self.settingsSection, u'images')
results = []
string = string.lower()

View File

@ -316,7 +316,7 @@ class MediaMediaItem(MediaManagerItem):
media = filter(lambda x: os.path.splitext(x)[1] in ext, media)
return media
def search(self, string):
def search(self, string, showError):
files = SettingsManager.load_list(self.settingsSection, u'media')
results = []
string = string.lower()

View File

@ -322,7 +322,7 @@ class PresentationMediaItem(MediaManagerItem):
return controller
return None
def search(self, string):
def search(self, string, showError):
files = SettingsManager.load_list(
self.settingsSection, u'presentations')
results = []

View File

@ -4,12 +4,12 @@
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, #
# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, #
# Jeffrey Smith, Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode #
# Woldsund #
# Copyright (c) 2008-2012 Raoul Snyman #
# Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, #
# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias #
# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# 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 #

View File

@ -1,12 +1,12 @@
/*****************************************************************************
* 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, *
* Jeffrey Smith, Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode *
* Woldsund *
* Copyright (c) 2008-2012 Raoul Snyman *
* Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan *
* Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, *
* Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias *
* Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, *
* 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 *

View File

@ -1,12 +1,12 @@
/*****************************************************************************
* 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, *
* Jeffrey Smith, Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode *
* Woldsund *
* Copyright (c) 2008-2012 Raoul Snyman *
* Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan *
* Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, *
* Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias *
* Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, *
* 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 *
@ -72,7 +72,9 @@ window.OpenLP = {
);
},
loadController: function (event) {
event.preventDefault();
if (event) {
event.preventDefault();
}
$.getJSON(
"/api/controller/live/text",
function (data, status) {
@ -91,6 +93,7 @@ window.OpenLP = {
li.children("a").click(OpenLP.setSlide);
ul.append(li);
}
OpenLP.currentItem = data.results.item;
ul.listview("refresh");
}
);
@ -208,9 +211,8 @@ window.OpenLP = {
},
showAlert: function (event) {
event.preventDefault();
var text = "{\"request\": {\"text\": \"" +
$("#alert-text").val().replace(/\\/g, "\\\\").replace(/"/g, "\\\"") +
"\"}}";
var alert = OpenLP.escapeString($("#alert-text").val())
var text = "{\"request\": {\"text\": \"" + alert + "\"}}";
$.getJSON(
"/api/alert",
{"data": text},
@ -221,9 +223,8 @@ window.OpenLP = {
},
search: function (event) {
event.preventDefault();
var text = "{\"request\": {\"text\": \"" +
$("#search-text").val().replace(/\\/g, "\\\\").replace(/"/g, "\\\"") +
"\"}}";
var query = OpenLP.escapeString($("#search-text").val())
var text = "{\"request\": {\"text\": \"" + query + "\"}}";
$.getJSON(
"/api/" + $("#search-plugin").val() + "/search",
{"data": text},
@ -280,6 +281,9 @@ window.OpenLP = {
);
$("#options").dialog("close");
$.mobile.changePage("#service-manager");
},
escapeString: function (string) {
return string.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")
}
}
// Service Manager

View File

@ -1,12 +1,12 @@
/*****************************************************************************
* 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, *
* Jeffrey Smith, Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode *
* Woldsund *
* Copyright (c) 2008-2012 Raoul Snyman *
* Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan *
* Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, *
* Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias *
* Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, *
* 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 *
@ -46,7 +46,7 @@ body {
}
#clock {
font-size: 40pt;
font-size: 30pt;
color: yellow;
text-align: right;
}

View File

@ -4,12 +4,12 @@
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, #
# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, #
# Jeffrey Smith, Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode #
# Woldsund #
# Copyright (c) 2008-2012 Raoul Snyman #
# Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, #
# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias #
# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# 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 #

View File

@ -1,12 +1,12 @@
/*****************************************************************************
* 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, *
* Jeffrey Smith, Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode *
* Woldsund *
* Copyright (c) 2008-2012 Raoul Snyman *
* Portions copyright (c) 2008-2012 Tim Bentley, Gerald Britton, Jonathan *
* Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, *
* Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias *
* Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, *
* 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 *

View File

@ -111,15 +111,12 @@ the remotes.
{"results": {"items": [{...}, {...}]}}
"""
import json
import logging
import os
import urlparse
import re
try:
import json
except ImportError:
import simplejson as json
import urllib
import urlparse
from PyQt4 import QtCore, QtNetwork
from mako.template import Template
@ -314,11 +311,14 @@ class HttpConnection(object):
"""
log.debug(u'ready to read socket')
if self.socket.canReadLine():
data = self.socket.readLine()
data = QtCore.QByteArray.fromPercentEncoding(data)
data = unicode(data, 'utf8')
log.debug(u'received: ' + data)
words = data.split(u' ')
data = str(self.socket.readLine())
try:
log.debug(u'received: ' + data)
except UnicodeDecodeError:
# Malicious request containing non-ASCII characters.
self.close()
return
words = data.split(' ')
response = None
if words[0] == u'GET':
url = urlparse.urlparse(words[1])
@ -426,9 +426,19 @@ class HttpConnection(object):
"""
Send an alert.
"""
text = json.loads(self.url_params[u'data'][0])[u'request'][u'text']
Receiver.send_message(u'alerts_text', [text])
return HttpResponse(json.dumps({u'results': {u'success': True}}),
plugin = self.parent.plugin.pluginManager.get_plugin_by_name("alerts")
if plugin.status == PluginStatus.Active:
try:
text = json.loads(
self.url_params[u'data'][0])[u'request'][u'text']
except KeyError, ValueError:
return HttpResponse(code=u'400 Bad Request')
text = urllib.unquote(text)
Receiver.send_message(u'alerts_text', [text])
success = True
else:
success = False
return HttpResponse(json.dumps({u'results': {u'success': success}}),
{u'Content-Type': u'application/json'})
def controller(self, type, action):
@ -463,9 +473,14 @@ class HttpConnection(object):
item[u'selected'] = (self.parent.current_slide == index)
data.append(item)
json_data = {u'results': {u'slides': data}}
if current_item:
json_data[u'results'][u'item'] = self.parent.current_item._uuid
else:
if self.url_params and self.url_params.get(u'data'):
data = json.loads(self.url_params[u'data'][0])
try:
data = json.loads(self.url_params[u'data'][0])
except KeyError, ValueError:
return HttpResponse(code=u'400 Bad Request')
log.info(data)
# This slot expects an int within a list.
id = data[u'request'][u'id']
@ -485,7 +500,10 @@ class HttpConnection(object):
else:
event += u'_item'
if self.url_params and self.url_params.get(u'data'):
data = json.loads(self.url_params[u'data'][0])
try:
data = json.loads(self.url_params[u'data'][0])
except KeyError, ValueError:
return HttpResponse(code=u'400 Bad Request')
Receiver.send_message(event, data[u'request'][u'id'])
else:
Receiver.send_message(event)
@ -518,11 +536,15 @@ class HttpConnection(object):
``type``
The plugin name to search in.
"""
text = json.loads(self.url_params[u'data'][0])[u'request'][u'text']
try:
text = json.loads(self.url_params[u'data'][0])[u'request'][u'text']
except KeyError, ValueError:
return HttpResponse(code=u'400 Bad Request')
text = urllib.unquote(text)
plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type)
if plugin.status == PluginStatus.Active and \
plugin.mediaItem and plugin.mediaItem.hasSearch:
results = plugin.mediaItem.search(text)
results = plugin.mediaItem.search(text, False)
else:
results = []
return HttpResponse(
@ -533,20 +555,28 @@ class HttpConnection(object):
"""
Go live on an item of type ``type``.
"""
id = json.loads(self.url_params[u'data'][0])[u'request'][u'id']
try:
id = json.loads(self.url_params[u'data'][0])[u'request'][u'id']
except KeyError, ValueError:
return HttpResponse(code=u'400 Bad Request')
plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type)
if plugin.status == PluginStatus.Active and plugin.mediaItem:
plugin.mediaItem.goLive(id, remote=True)
return HttpResponse(code=u'200 OK')
def add_to_service(self, type):
"""
Add item of type ``type`` to the end of the service.
"""
id = json.loads(self.url_params[u'data'][0])[u'request'][u'id']
try:
id = json.loads(self.url_params[u'data'][0])[u'request'][u'id']
except KeyError, ValueError:
return HttpResponse(code=u'400 Bad Request')
plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type)
if plugin.status == PluginStatus.Active and plugin.mediaItem:
item_id = plugin.mediaItem.createItemFromId(id)
plugin.mediaItem.addToService(item_id, remote=True)
return HttpResponse(code=u'200 OK')
def send_response(self, response):
http = u'HTTP/1.1 %s\r\n' % response.code

View File

@ -27,7 +27,7 @@
from PyQt4 import QtCore, QtGui, QtNetwork
from openlp.core.lib import SettingsTab, translate
from openlp.core.lib import SettingsTab, translate, Receiver
ZERO_URL = u'0.0.0.0'
@ -87,7 +87,8 @@ class RemoteTab(SettingsTab):
self.qrLayout = QtGui.QVBoxLayout(self.androidAppGroupBox)
self.qrLayout.setObjectName(u'qrLayout')
self.qrCodeLabel = QtGui.QLabel(self.androidAppGroupBox)
self.qrCodeLabel.setPixmap(QtGui.QPixmap(u':/remotes/android_app_qr.png'))
self.qrCodeLabel.setPixmap(QtGui.QPixmap(
u':/remotes/android_app_qr.png'))
self.qrCodeLabel.setAlignment(QtCore.Qt.AlignCenter)
self.qrCodeLabel.setObjectName(u'qrCodeLabel')
self.qrLayout.addWidget(self.qrCodeLabel)
@ -160,12 +161,20 @@ class RemoteTab(SettingsTab):
self.setUrls()
def save(self):
changed = False
if QtCore.QSettings().value(self.settingsSection + u'/ip address',
QtCore.QVariant(ZERO_URL).toString() != self.addressEdit.text() or
QtCore.QSettings().value(self.settingsSection + u'/port',
QtCore.QVariant(4316).toInt()[0]) != self.portSpinBox.value()):
changed = True
QtCore.QSettings().setValue(self.settingsSection + u'/port',
QtCore.QVariant(self.portSpinBox.value()))
QtCore.QSettings().setValue(self.settingsSection + u'/ip address',
QtCore.QVariant(self.addressEdit.text()))
QtCore.QSettings().setValue(self.settingsSection + u'/twelve hour',
QtCore.QVariant(self.twelveHour))
if changed:
Receiver.send_message(u'remotes_config_updated')
def onTwelveHourCheckBoxChanged(self, check_state):
self.twelveHour = False

View File

@ -86,3 +86,11 @@ class RemotesPlugin(Plugin):
self.textStrings[StringContent.VisibleName] = {
u'title': translate('RemotePlugin', 'Remote', 'container title')
}
def configUpdated(self):
"""
Called when Config is changed to restart the server on new address or
port
"""
self.finalise()
self.initialise()

View File

@ -589,7 +589,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
verse_names.append(u'%s%s' % (
VerseType.translated_tag(verse[0]), verse[1:]))
verses_not_used = []
for count, verse in enumerate(verses):
for verse in verses:
if not verse in order:
verses_not_used.append(verse)
self.warningLabel.setVisible(len(verses_not_used) > 0)
@ -680,7 +680,6 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.verseListWidget.rowCount())
if not result:
return False
item = int(self.songBookComboBox.currentIndex())
text = unicode(self.songBookComboBox.currentText())
if self.songBookComboBox.findText(text, QtCore.Qt.MatchExactly) < 0:
if QtGui.QMessageBox.question(self,

View File

@ -159,6 +159,12 @@ class CCLIFileImport(SongImport):
song_author = u''
song_topics = u''
for line in textList:
if line.startswith(u'[S '):
ccli, line = line.split(u']', 1)
if ccli.startswith(u'[S A'):
self.ccliNumber = ccli[4:].strip()
else:
self.ccliNumber = ccli[3:].strip()
if line.startswith(u'Title='):
self.title = line[6:].strip()
elif line.startswith(u'Author='):
@ -166,9 +172,7 @@ class CCLIFileImport(SongImport):
elif line.startswith(u'Copyright='):
self.copyright = line[10:].strip()
elif line.startswith(u'Themes='):
song_topics = line[7:].strip()
elif line.startswith(u'[S A'):
self.ccliNumber = line[4:-3].strip()
song_topics = line[7:].strip().replace(u' | ', u'/t')
elif line.startswith(u'Fields='):
# Fields contain single line indicating verse, chorus, etc,
# /t delimited, same as with words field. store seperately
@ -193,6 +197,7 @@ class CCLIFileImport(SongImport):
check_first_verse_line = True
verse_text = unicode(words_list[counter])
verse_text = verse_text.replace(u'/n', u'\n')
verse_text = verse_text.replace(u' | ', u'\n')
verse_lines = verse_text.split(u'\n', 1)
if check_first_verse_line:
if verse_lines[0].startswith(u'(PRE-CHORUS'):
@ -243,7 +248,7 @@ class CCLIFileImport(SongImport):
<Empty line>
Song CCLI number
# e.g. CCLI Number (e.g.CCLI-Liednummer: 2672885)
Song copyright
Song copyright (if it begins ©, otherwise after authors)
# e.g. © 1999 Integrity's Hosanna! Music | LenSongs Publishing
Song authors # e.g. Lenny LeBlanc | Paul Baloche
Licencing info
@ -322,11 +327,17 @@ class CCLIFileImport(SongImport):
#line_number=2, copyright
if line_number == 2:
line_number += 1
self.copyright = clean_line
if clean_line.startswith(u'©'):
self.copyright = clean_line
else:
song_author = clean_line
#n=3, authors
elif line_number == 3:
line_number += 1
song_author = clean_line
if song_author:
self.copyright = clean_line
else:
song_author = clean_line
#line_number=4, comments lines before last line
elif line_number == 4 and not clean_line.startswith(u'CCL'):
self.comments += clean_line

View File

@ -36,7 +36,7 @@ from sqlalchemy.sql import or_
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
translate, check_item_selected, PluginStatus, create_separated_list
from openlp.core.lib.ui import UiStrings, create_action, create_widget_action
from openlp.core.lib.ui import UiStrings, create_widget_action
from openlp.core.utils import AppLocation
from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
SongImportForm, SongExportForm
@ -586,7 +586,7 @@ class SongMediaItem(MediaManagerItem):
Receiver.send_message(u'service_item_update',
u'%s:%s:%s' % (editId, item._uuid, temporary))
def search(self, string):
def search(self, string, showError):
"""
Search for some songs
"""

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

6878
resources/i18n/da.ts Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

6797
resources/i18n/fi.ts Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

6801
resources/i18n/it.ts Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

6799
resources/i18n/pl.ts Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -185,11 +185,11 @@ def download_translations():
**Note:** URLs and headers need to remain strings, not unicode.
"""
global username, password
if not username:
username = raw_input(u'Transifex username: ')
if not password:
password = getpass(u'Transifex password: ')
print_quiet(u'Download translation files from Transifex')
if not username:
username = raw_input(u' Transifex username: ')
if not password:
password = getpass(u' Transifex password: ')
# First get the list of languages
url = SERVER_URL + 'resource/ents/'
base64string = base64.encodestring(