This commit is contained in:
Tim Bentley 2012-03-25 07:25:37 +01:00
commit 120c6a0acb
54 changed files with 65540 additions and 22438 deletions

View File

@ -22,3 +22,4 @@ openlp/core/resources.py.old
resources/windows/warnOpenLP.txt resources/windows/warnOpenLP.txt
openlp.cfg openlp.cfg
.idea .idea
openlp.pro

View File

@ -33,7 +33,8 @@ from urllib import quote_plus as urlquote
from PyQt4 import QtCore from PyQt4 import QtCore
from sqlalchemy import Table, MetaData, Column, types, create_engine 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.orm import scoped_session, sessionmaker, mapper
from sqlalchemy.pool import NullPool from sqlalchemy.pool import NullPool

View File

@ -458,13 +458,18 @@ def build_lyrics_format_css(theme, width, height):
# fix tag incompatibilities # fix tag incompatibilities
if theme.display_horizontal_align == HorizontalType.Justify: if theme.display_horizontal_align == HorizontalType.Justify:
justify = u'' justify = u''
if theme.display_vertical_align == VerticalType.Bottom:
padding_bottom = u'0.5em'
else:
padding_bottom = u'0'
lyrics = u'%s word-wrap: break-word; ' \ lyrics = u'%s word-wrap: break-word; ' \
'text-align: %s; vertical-align: %s; font-family: %s; ' \ 'text-align: %s; vertical-align: %s; font-family: %s; ' \
'font-size: %spt; color: %s; line-height: %d%%; margin: 0;' \ 'font-size: %spt; color: %s; line-height: %d%%; margin: 0;' \
'padding: 0; padding-left: %spx; width: %spx; height: %spx; ' % \ 'padding: 0; padding-bottom: %s; padding-left: %spx; width: %spx;' \
'height: %spx; ' % \
(justify, align, valign, theme.font_main_name, theme.font_main_size, (justify, align, valign, theme.font_main_name, theme.font_main_size,
theme.font_main_color, 100 + int(theme.font_main_line_adjustment), theme.font_main_color, 100 + int(theme.font_main_line_adjustment),
left_margin, width, height) padding_bottom, left_margin, width, height)
if theme.font_main_outline: if theme.font_main_outline:
if webkit_version() <= 534.3: if webkit_version() <= 534.3:
lyrics += u' letter-spacing: 1px;' lyrics += u' letter-spacing: 1px;'

View File

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

View File

@ -289,7 +289,7 @@ class Renderer(object):
def _calculate_default(self): def _calculate_default(self):
""" """
Calculate the default dimentions of the screen. Calculate the default dimensions of the screen.
""" """
screen_size = self.screens.current[u'size'] screen_size = self.screens.current[u'size']
self.width = screen_size.width() self.width = screen_size.width()
@ -380,6 +380,7 @@ class Renderer(object):
(build_lyrics_format_css(self.theme_data, self.page_width, (build_lyrics_format_css(self.theme_data, self.page_width,
self.page_height), build_lyrics_outline_css(self.theme_data)) self.page_height), build_lyrics_outline_css(self.theme_data))
self.web.setHtml(html) self.web.setHtml(html)
self.empty_height = self.web_frame.contentsSize().height()
def _paginate_slide(self, lines, line_end): def _paginate_slide(self, lines, line_end):
""" """
@ -600,7 +601,7 @@ class Renderer(object):
""" """
self.web_frame.evaluateJavaScript(u'show_text("%s")' % self.web_frame.evaluateJavaScript(u'show_text("%s")' %
text.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"')) text.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'))
return self.web_frame.contentsSize().height() <= self.page_height return self.web_frame.contentsSize().height() <= self.empty_height
def _words_split(self, line): def _words_split(self, line):
""" """

View File

@ -300,6 +300,7 @@ class ServiceItem(object):
``path`` ``path``
Defaults to *None*. Any path data, usually for images. 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'] header = serviceitem[u'serviceitem'][u'header']
self.title = header[u'title'] self.title = header[u'title']
self.name = header[u'name'] self.name = header[u'name']

View File

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

View File

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

View File

@ -24,17 +24,21 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 # # with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
import logging
from PyQt4 import QtCore
log = logging.getLogger(__name__)
class MediaState(object): class MediaState(object):
""" """
An enumeration for possible States of the Media Player (copied partially An enumeration for possible States of the Media Player
from Phonon::State)
""" """
Loading = 0 Off = 0
Stopped = 1 Loaded = 1
Playing = 2 Playing = 2
Paused = 4 Paused = 3
Off = 6 Stopped = 4
class MediaType(object): class MediaType(object):
@ -62,4 +66,48 @@ class MediaInfo(object):
end_time = 0 end_time = 0
media_type = MediaType() media_type = MediaType()
def get_media_players():
"""
This method extract the configured media players and overridden player from
the settings
``players_list``
this is a python list with all active media players
``overridden_player``
here an special media player is choosen for all media actions
"""
log.debug(u'get_media_players')
players = unicode(QtCore.QSettings().value(u'media/players').toString())
if not players:
players = u'webkit'
reg_ex = QtCore.QRegExp(".*\[(.*)\].*")
if QtCore.QSettings().value(u'media/override player',
QtCore.QVariant(QtCore.Qt.Unchecked)).toInt()[0] == QtCore.Qt.Checked:
if reg_ex.exactMatch(players):
overridden_player = u'%s' % reg_ex.cap(1)
else:
overridden_player = u'auto'
else:
overridden_player = u''
players_list = players.replace(u'[', u'').replace(u']', u'').split(u',')
return players_list, overridden_player
def set_media_players(players_list, overridden_player=u'auto'):
"""
This method saves the configured media players and overridden player to the
settings
``players_list``
this is a python list with all active media players
``overridden_player``
here an special media player is choosen for all media actions
"""
log.debug(u'set_media_players')
players = u','.join(players_list)
if QtCore.QSettings().value(u'media/override player',
QtCore.QVariant(QtCore.Qt.Unchecked)).toInt()[0] == \
QtCore.Qt.Checked and overridden_player != u'auto':
players = players.replace(overridden_player, u'[%s]' % overridden_player)
QtCore.QSettings().setValue(u'media/players', QtCore.QVariant(players))
from mediacontroller import MediaController from mediacontroller import MediaController

View File

@ -32,7 +32,8 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import OpenLPToolbar, Receiver, translate from openlp.core.lib import OpenLPToolbar, Receiver, translate
from openlp.core.lib.mediaplayer import MediaPlayer from openlp.core.lib.mediaplayer import MediaPlayer
from openlp.core.lib.ui import critical_error_message_box from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui.media import MediaState, MediaInfo, MediaType from openlp.core.ui.media import MediaState, MediaInfo, MediaType, \
get_media_players, set_media_players
from openlp.core.utils import AppLocation from openlp.core.utils import AppLocation
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -47,7 +48,6 @@ class MediaController(object):
self.parent = parent self.parent = parent
self.mediaPlayers = {} self.mediaPlayers = {}
self.controller = [] self.controller = []
self.overriddenPlayer = ''
self.curDisplayMediaPlayer = {} self.curDisplayMediaPlayer = {}
# Timer for video state # Timer for video state
self.timer = QtCore.QTimer() self.timer = QtCore.QTimer()
@ -73,8 +73,6 @@ class MediaController(object):
QtCore.SIGNAL(u'media_blank'), self.video_blank) QtCore.SIGNAL(u'media_blank'), self.video_blank)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'media_unblank'), self.video_unblank) QtCore.SIGNAL(u'media_unblank'), self.video_unblank)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'media_override_player'), self.override_player)
# Signals for background video # Signals for background video
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'songs_hide'), self.video_hide) QtCore.SIGNAL(u'songs_hide'), self.video_hide)
@ -84,11 +82,7 @@ class MediaController(object):
QtCore.SIGNAL(u'mediaitem_media_rebuild'), self.set_active_players) QtCore.SIGNAL(u'mediaitem_media_rebuild'), self.set_active_players)
def set_active_players(self): def set_active_players(self):
playerSettings = str(QtCore.QSettings().value(u'media/players', savedPlayers = get_media_players()[0]
QtCore.QVariant(u'webkit')).toString())
if len(playerSettings) == 0:
playerSettings = u'webkit'
savedPlayers = playerSettings.split(u',')
for player in self.mediaPlayers.keys(): for player in self.mediaPlayers.keys():
if player in savedPlayers: if player in savedPlayers:
self.mediaPlayers[player].isActive = True self.mediaPlayers[player].isActive = True
@ -129,18 +123,14 @@ class MediaController(object):
controller = controller_class(self) controller = controller_class(self)
self.register_controllers(controller) self.register_controllers(controller)
if self.mediaPlayers: if self.mediaPlayers:
playerSettings = str(QtCore.QSettings().value(u'media/players', savedPlayers, overriddenPlayer = get_media_players()
QtCore.QVariant(u'webkit')).toString())
savedPlayers = playerSettings.split(u',')
invalidMediaPlayers = [mediaPlayer for mediaPlayer in savedPlayers \ invalidMediaPlayers = [mediaPlayer for mediaPlayer in savedPlayers \
if not mediaPlayer in self.mediaPlayers or \ if not mediaPlayer in self.mediaPlayers or \
not self.mediaPlayers[mediaPlayer].check_available()] not self.mediaPlayers[mediaPlayer].check_available()]
if len(invalidMediaPlayers) > 0: if len(invalidMediaPlayers) > 0:
for invalidPlayer in invalidMediaPlayers: for invalidPlayer in invalidMediaPlayers:
savedPlayers.remove(invalidPlayer) savedPlayers.remove(invalidPlayer)
newPlayerSetting = u','.join(savedPlayers) set_media_players(savedPlayers, overriddenPlayer)
QtCore.QSettings().setValue(u'media/players',
QtCore.QVariant(newPlayerSetting))
self.set_active_players() self.set_active_players()
return True return True
else: else:
@ -286,7 +276,8 @@ class MediaController(object):
controller.mediabar.setVisible(value) controller.mediabar.setVisible(value)
if controller.isLive and controller.display: if controller.isLive and controller.display:
if self.curDisplayMediaPlayer and value: 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) controller.display.setTransparency(False)
# Special controls: Here media type specific Controls will be enabled # Special controls: Here media type specific Controls will be enabled
# (e.g. for DVD control, ...) # (e.g. for DVD control, ...)
@ -366,13 +357,9 @@ class MediaController(object):
""" """
Select the correct media Player type from the prioritized Player list Select the correct media Player type from the prioritized Player list
""" """
playerSettings = str(QtCore.QSettings().value(u'media/players', usedPlayers, overriddenPlayer = get_media_players()
QtCore.QVariant(u'webkit')).toString()) if overriddenPlayer and overriddenPlayer != u'auto':
usedPlayers = playerSettings.split(u',') usedPlayers = [overriddenPlayer]
if QtCore.QSettings().value(u'media/override player',
QtCore.QVariant(QtCore.Qt.Unchecked)) == QtCore.Qt.Checked:
if self.overriddenPlayer != '':
usedPlayers = [self.overriddenPlayer]
if controller.media_info.file_info.isFile(): if controller.media_info.file_info.isFile():
suffix = u'*.%s' % \ suffix = u'*.%s' % \
controller.media_info.file_info.suffix().toLower() controller.media_info.file_info.suffix().toLower()
@ -583,16 +570,6 @@ class MediaController(object):
video_list.append(item) video_list.append(item)
return video_list return video_list
def override_player(self, override_player_index):
playerSettings = str(QtCore.QSettings().value(u'media/players',
QtCore.QVariant(u'webkit')).toString())
usedPlayers = playerSettings.split(u',')
if override_player_index >= 0 and \
override_player_index < len(usedPlayers):
self.overridenPlayer = usedPlayers[override_player_index]
else:
self.overriddenPlayer = ''
def finalise(self): def finalise(self):
self.timer.stop() self.timer.stop()
for controller in self.controller: for controller in self.controller:

View File

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

View File

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

View File

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

View File

@ -563,7 +563,8 @@ class SlideController(Controller):
Receiver.send_message('servicemanager_previous_item') Receiver.send_message('servicemanager_previous_item')
elif keypressCommand == ServiceItemAction.PreviousLastSlide: elif keypressCommand == ServiceItemAction.PreviousLastSlide:
# Go to the last slide of the previous item # 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: else:
Receiver.send_message('servicemanager_next_item') Receiver.send_message('servicemanager_next_item')
self.keypress_loop = False self.keypress_loop = False
@ -1190,7 +1191,8 @@ class SlideController(Controller):
if self.slide_limits == SlideLimits.Wrap: if self.slide_limits == SlideLimits.Wrap:
row = self.previewListWidget.rowCount() - 1 row = self.previewListWidget.rowCount() - 1
elif self.isLive and self.slide_limits == SlideLimits.Next: elif self.isLive and self.slide_limits == SlideLimits.Next:
self.keypress_queue.append(ServiceItemAction.PreviousLastSlide) self.keypress_queue.append(
ServiceItemAction.PreviousLastSlide)
self._process_queue() self._process_queue()
return return
else: else:

View File

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

View File

@ -53,6 +53,8 @@ APPLICATION_VERSION = {}
IMAGES_FILTER = None IMAGES_FILTER = None
UNO_CONNECTION_TYPE = u'pipe' UNO_CONNECTION_TYPE = u'pipe'
#UNO_CONNECTION_TYPE = u'socket' #UNO_CONNECTION_TYPE = u'socket'
CONTROL_CHARS = re.compile(r'[\x00-\x1F\x7F-\x9F]', re.UNICODE)
INVALID_FILE_CHARS = re.compile(r'[\\/:\*\?"<>\|\+\[\]%]', re.UNICODE)
VERSION_SPLITTER = re.compile(r'([0-9]+).([0-9]+).([0-9]+)(?:-bzr([0-9]+))?') VERSION_SPLITTER = re.compile(r'([0-9]+).([0-9]+).([0-9]+)(?:-bzr([0-9]+))?')
class VersionThread(QtCore.QThread): class VersionThread(QtCore.QThread):
@ -400,7 +402,7 @@ def clean_filename(filename):
""" """
if not isinstance(filename, unicode): if not isinstance(filename, unicode):
filename = unicode(filename, u'utf-8') filename = unicode(filename, u'utf-8')
return re.sub(r'[/\\?*|<>\[\]":<>+%\n]+', u'_', filename).strip(u'_') return INVALID_FILE_CHARS.sub(u'_', CONTROL_CHARS.sub(u'', filename))
def delete_file(file_path_name): def delete_file(file_path_name):
""" """

View File

@ -27,7 +27,7 @@
import logging 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 import Plugin, StringContent, build_icon, translate
from openlp.core.lib.ui import create_action, UiStrings from openlp.core.lib.ui import create_action, UiStrings

View File

@ -183,13 +183,8 @@ def update_reference_separators():
""" """
default_separators = unicode(translate('BiblesPlugin', default_separators = unicode(translate('BiblesPlugin',
':|v|V|verse|verses;;-|to;;,|and;;end', ':|v|V|verse|verses;;-|to;;,|and;;end',
'This are 4 values seperated each by two semicolons representing the ' 'Double-semicolon delimited separators for parsing references. '
'seperators for parsing references. This values are verse separators, ' 'Consult the developers for further information.')).split(u';;')
'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';;')
settings = QtCore.QSettings() settings = QtCore.QSettings()
settings.beginGroup(u'bibles') settings.beginGroup(u'bibles')
custom_separators = [ custom_separators = [

View File

@ -177,7 +177,7 @@ class CustomMediaItem(MediaManagerItem):
UiStrings().ConfirmDelete, UiStrings().ConfirmDelete,
translate('CustomPlugin.MediaItem', translate('CustomPlugin.MediaItem',
'Are you sure you want to delete the %n selected custom' 'Are you sure you want to delete the %n selected custom'
' slides(s)?', '', ' slide(s)?', '',
QtCore.QCoreApplication.CodecForTr, len(items)), QtCore.QCoreApplication.CodecForTr, len(items)),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes |
QtGui.QMessageBox.No), QtGui.QMessageBox.No),

View File

@ -189,7 +189,7 @@ class ImageMediaItem(MediaManagerItem):
# Continue with the existing images. # Continue with the existing images.
for bitem in items: for bitem in items:
filename = unicode(bitem.data(QtCore.Qt.UserRole).toString()) 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) service_item.add_from_image(filename, name, background)
return True return True
@ -220,7 +220,7 @@ class ImageMediaItem(MediaManagerItem):
bitem = self.listView.item(item.row()) bitem = self.listView.item(item.row())
filename = unicode(bitem.data(QtCore.Qt.UserRole).toString()) filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())
if os.path.exists(filename): if os.path.exists(filename):
(path, name) = os.path.split(filename) name = os.path.split(filename)[1]
if self.plugin.liveController.display.directImage(name, if self.plugin.liveController.display.directImage(name,
filename, background): filename, background):
self.resetAction.setVisible(True) self.resetAction.setVisible(True)

View File

@ -37,6 +37,7 @@ from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \
from openlp.core.lib.ui import UiStrings, critical_error_message_box, \ from openlp.core.lib.ui import UiStrings, critical_error_message_box, \
media_item_combo_box media_item_combo_box
from openlp.core.ui import Controller, Display from openlp.core.ui import Controller, Display
from openlp.core.ui.media import get_media_players, set_media_players
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -142,8 +143,11 @@ class MediaMediaItem(MediaManagerItem):
self.overridePlayerChanged) self.overridePlayerChanged)
def overridePlayerChanged(self, index): def overridePlayerChanged(self, index):
# index - 1, because the first item is "Automatic". player = get_media_players()[0]
Receiver.send_message(u'media_override_player', index - 1) if index == 0:
set_media_players(player)
else:
set_media_players(player, player[index-1])
def onResetClick(self): def onResetClick(self):
""" """
@ -239,29 +243,31 @@ class MediaMediaItem(MediaManagerItem):
self.plugin.mediaController.setup_display( \ self.plugin.mediaController.setup_display( \
self.mediaController.previewDisplay) self.mediaController.previewDisplay)
def populateDisplayTypes(self): def populateDisplayTypes(self):
""" """
Load the combobox with the enabled media players, Load the combobox with the enabled media players,
allowing user to select a specific player if settings allow allowing user to select a specific player if settings allow
""" """
# block signals to avoid unnecessary overridePlayerChanged Signales
# while combo box creation
self.displayTypeComboBox.blockSignals(True)
self.displayTypeComboBox.clear() self.displayTypeComboBox.clear()
playerSettings = str(QtCore.QSettings().value(u'media/players', usedPlayers, overridePlayer = get_media_players()
QtCore.QVariant(u'webkit')).toString())
usedPlayers = playerSettings.split(u',')
mediaPlayers = self.plugin.mediaController.mediaPlayers mediaPlayers = self.plugin.mediaController.mediaPlayers
currentIndex = 0
for player in usedPlayers: for player in usedPlayers:
# load the drop down selection # load the drop down selection
self.displayTypeComboBox.addItem(mediaPlayers[player].original_name) self.displayTypeComboBox.addItem(mediaPlayers[player].original_name)
if overridePlayer == player:
currentIndex = len(self.displayTypeComboBox)
if self.displayTypeComboBox.count() > 1: if self.displayTypeComboBox.count() > 1:
self.displayTypeComboBox.insertItem(0, self.automatic) self.displayTypeComboBox.insertItem(0, self.automatic)
self.displayTypeComboBox.setCurrentIndex(0) self.displayTypeComboBox.setCurrentIndex(currentIndex)
if QtCore.QSettings().value(self.settingsSection + u'/override player', if overridePlayer:
QtCore.QVariant(QtCore.Qt.Unchecked)) == QtCore.Qt.Checked:
self.mediaWidget.show() self.mediaWidget.show()
else: else:
self.mediaWidget.hide() self.mediaWidget.hide()
self.displayTypeComboBox.blockSignals(False)
def onDeleteClick(self): def onDeleteClick(self):
""" """

View File

@ -29,7 +29,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import SettingsTab, translate, Receiver from openlp.core.lib import SettingsTab, translate, Receiver
from openlp.core.lib.ui import UiStrings, create_up_down_push_button_set from openlp.core.lib.ui import UiStrings, create_up_down_push_button_set
from openlp.core.ui.media import get_media_players, set_media_players
class MediaQCheckBox(QtGui.QCheckBox): class MediaQCheckBox(QtGui.QCheckBox):
""" """
MediaQCheckBox adds an extra property, playerName to the QCheckBox class. MediaQCheckBox adds an extra property, playerName to the QCheckBox class.
@ -138,7 +138,7 @@ class MediaTab(SettingsTab):
self.usedPlayers.append(player) self.usedPlayers.append(player)
else: else:
if player in self.usedPlayers: if player in self.usedPlayers:
self.usedPlayers.takeAt(self.usedPlayers.indexOf(player)) self.usedPlayers.remove(player)
self.updatePlayerList() self.updatePlayerList()
def updatePlayerList(self): def updatePlayerList(self):
@ -160,7 +160,7 @@ class MediaTab(SettingsTab):
item = self.playerOrderlistWidget.takeItem(row) item = self.playerOrderlistWidget.takeItem(row)
self.playerOrderlistWidget.insertItem(row - 1, item) self.playerOrderlistWidget.insertItem(row - 1, item)
self.playerOrderlistWidget.setCurrentRow(row - 1) self.playerOrderlistWidget.setCurrentRow(row - 1)
self.usedPlayers.move(row, row - 1) self.usedPlayers.insert(row - 1, self.usedPlayers.pop(row))
def onDownButtonClicked(self): def onDownButtonClicked(self):
row = self.playerOrderlistWidget.currentRow() row = self.playerOrderlistWidget.currentRow()
@ -169,12 +169,12 @@ class MediaTab(SettingsTab):
item = self.playerOrderlistWidget.takeItem(row) item = self.playerOrderlistWidget.takeItem(row)
self.playerOrderlistWidget.insertItem(row + 1, item) self.playerOrderlistWidget.insertItem(row + 1, item)
self.playerOrderlistWidget.setCurrentRow(row + 1) self.playerOrderlistWidget.setCurrentRow(row + 1)
self.usedPlayers.move(row, row + 1) self.usedPlayers.insert(row + 1, self.usedPlayers.pop(row))
def load(self): def load(self):
self.usedPlayers = QtCore.QSettings().value( if self.savedUsedPlayers:
self.settingsSection + u'/players', self.usedPlayers = self.savedUsedPlayers
QtCore.QVariant(u'webkit')).toString().split(u',') self.usedPlayers = get_media_players()[0]
self.savedUsedPlayers = self.usedPlayers self.savedUsedPlayers = self.usedPlayers
for key in self.mediaPlayers: for key in self.mediaPlayers:
player = self.mediaPlayers[key] player = self.mediaPlayers[key]
@ -191,18 +191,14 @@ class MediaTab(SettingsTab):
def save(self): def save(self):
override_changed = False override_changed = False
player_string_changed = False player_string_changed = False
old_players = QtCore.QSettings().value( old_players, override_player = get_media_players()
self.settingsSection + u'/players', if self.usedPlayers != old_players:
QtCore.QVariant(u'webkit')).toString()
new_players = self.usedPlayers.join(u',')
if old_players != new_players:
# clean old Media stuff # clean old Media stuff
QtCore.QSettings().setValue(self.settingsSection + u'/players', set_media_players(self.usedPlayers, override_player)
QtCore.QVariant(new_players))
player_string_changed = True player_string_changed = True
override_changed = True override_changed = True
setting_key = self.settingsSection + u'/override player' setting_key = self.settingsSection + u'/override player'
if QtCore.QSettings().value(setting_key) != \ if QtCore.QSettings().value(setting_key).toInt()[0] != \
self.overridePlayerCheckBox.checkState(): self.overridePlayerCheckBox.checkState():
QtCore.QSettings().setValue(setting_key, QtCore.QSettings().setValue(setting_key,
QtCore.QVariant(self.overridePlayerCheckBox.checkState())) QtCore.QVariant(self.overridePlayerCheckBox.checkState()))

View File

@ -72,7 +72,9 @@ window.OpenLP = {
); );
}, },
loadController: function (event) { loadController: function (event) {
event.preventDefault(); if (event) {
event.preventDefault();
}
$.getJSON( $.getJSON(
"/api/controller/live/text", "/api/controller/live/text",
function (data, status) { function (data, status) {
@ -91,6 +93,7 @@ window.OpenLP = {
li.children("a").click(OpenLP.setSlide); li.children("a").click(OpenLP.setSlide);
ul.append(li); ul.append(li);
} }
OpenLP.currentItem = data.results.item;
ul.listview("refresh"); ul.listview("refresh");
} }
); );
@ -208,9 +211,8 @@ window.OpenLP = {
}, },
showAlert: function (event) { showAlert: function (event) {
event.preventDefault(); event.preventDefault();
var text = "{\"request\": {\"text\": \"" + var alert = OpenLP.escapeString($("#alert-text").val())
$("#alert-text").val().replace(/\\/g, "\\\\").replace(/"/g, "\\\"") + var text = "{\"request\": {\"text\": \"" + alert + "\"}}";
"\"}}";
$.getJSON( $.getJSON(
"/api/alert", "/api/alert",
{"data": text}, {"data": text},
@ -221,9 +223,8 @@ window.OpenLP = {
}, },
search: function (event) { search: function (event) {
event.preventDefault(); event.preventDefault();
var text = "{\"request\": {\"text\": \"" + var query = OpenLP.escapeString($("#search-text").val())
$("#search-text").val().replace(/\\/g, "\\\\").replace(/"/g, "\\\"") + var text = "{\"request\": {\"text\": \"" + query + "\"}}";
"\"}}";
$.getJSON( $.getJSON(
"/api/" + $("#search-plugin").val() + "/search", "/api/" + $("#search-plugin").val() + "/search",
{"data": text}, {"data": text},
@ -280,6 +281,9 @@ window.OpenLP = {
); );
$("#options").dialog("close"); $("#options").dialog("close");
$.mobile.changePage("#service-manager"); $.mobile.changePage("#service-manager");
},
escapeString: function (string) {
return string.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")
} }
} }
// Service Manager // Service Manager

View File

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

View File

@ -87,7 +87,8 @@ class RemoteTab(SettingsTab):
self.qrLayout = QtGui.QVBoxLayout(self.androidAppGroupBox) self.qrLayout = QtGui.QVBoxLayout(self.androidAppGroupBox)
self.qrLayout.setObjectName(u'qrLayout') self.qrLayout.setObjectName(u'qrLayout')
self.qrCodeLabel = QtGui.QLabel(self.androidAppGroupBox) 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.setAlignment(QtCore.Qt.AlignCenter)
self.qrCodeLabel.setObjectName(u'qrCodeLabel') self.qrCodeLabel.setObjectName(u'qrCodeLabel')
self.qrLayout.addWidget(self.qrCodeLabel) self.qrLayout.addWidget(self.qrCodeLabel)

View File

@ -361,7 +361,12 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
def onAuthorAddButtonClicked(self): def onAuthorAddButtonClicked(self):
item = int(self.authorsComboBox.currentIndex()) item = int(self.authorsComboBox.currentIndex())
text = unicode(self.authorsComboBox.currentText()) text = unicode(self.authorsComboBox.currentText()).strip(u' \r\n\t')
# This if statement is for OS X, which doesn't seem to work well with
# the QCompleter autocompletion class. See bug #812628.
if text in self.authors:
# Index 0 is a blank string, so add 1
item = self.authors.index(text) + 1
if item == 0 and text: if item == 0 and text:
if QtGui.QMessageBox.question(self, if QtGui.QMessageBox.question(self,
translate('SongsPlugin.EditSongForm', 'Add Author'), translate('SongsPlugin.EditSongForm', 'Add Author'),
@ -589,7 +594,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
verse_names.append(u'%s%s' % ( verse_names.append(u'%s%s' % (
VerseType.translated_tag(verse[0]), verse[1:])) VerseType.translated_tag(verse[0]), verse[1:]))
verses_not_used = [] verses_not_used = []
for count, verse in enumerate(verses): for verse in verses:
if not verse in order: if not verse in order:
verses_not_used.append(verse) verses_not_used.append(verse)
self.warningLabel.setVisible(len(verses_not_used) > 0) self.warningLabel.setVisible(len(verses_not_used) > 0)
@ -680,7 +685,6 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.verseListWidget.rowCount()) self.verseListWidget.rowCount())
if not result: if not result:
return False return False
item = int(self.songBookComboBox.currentIndex())
text = unicode(self.songBookComboBox.currentText()) text = unicode(self.songBookComboBox.currentText())
if self.songBookComboBox.findText(text, QtCore.Qt.MatchExactly) < 0: if self.songBookComboBox.findText(text, QtCore.Qt.MatchExactly) < 0:
if QtGui.QMessageBox.question(self, if QtGui.QMessageBox.question(self,

View File

@ -29,6 +29,7 @@ import re
from PyQt4 import QtGui from PyQt4 import QtGui
from openlp.core.lib import translate from openlp.core.lib import translate
from openlp.core.utils import CONTROL_CHARS
from db import Author from db import Author
from ui import SongStrings from ui import SongStrings
@ -256,6 +257,13 @@ def clean_string(string):
Strips punctuation from the passed string to assist searching Strips punctuation from the passed string to assist searching
""" """
return WHITESPACE.sub(u' ', APOSTROPHE.sub(u'', string)).lower() return WHITESPACE.sub(u' ', APOSTROPHE.sub(u'', string)).lower()
def clean_title(title):
"""
Cleans the song title by removing Unicode control chars groups C0 & C1,
as well as any trailing spaces
"""
return CONTROL_CHARS.sub(u'', title).rstrip()
def clean_song(manager, song): def clean_song(manager, song):
""" """
@ -275,10 +283,14 @@ def clean_song(manager, song):
song.alternate_title = unicode(song.alternate_title) song.alternate_title = unicode(song.alternate_title)
if isinstance(song.lyrics, buffer): if isinstance(song.lyrics, buffer):
song.lyrics = unicode(song.lyrics) song.lyrics = unicode(song.lyrics)
song.title = song.title.rstrip() if song.title else u'' if song.title:
if song.alternate_title is None: song.title = clean_title(song.title)
else:
song.title = u''
if song.alternate_title:
song.alternate_title = clean_title(song.alternate_title)
else:
song.alternate_title = u'' song.alternate_title = u''
song.alternate_title = song.alternate_title.strip()
song.search_title = clean_string(song.title) + u'@' + \ song.search_title = clean_string(song.title) + u'@' + \
clean_string(song.alternate_title) clean_string(song.alternate_title)
# Only do this, if we the song is a 1.9.4 song (or older). # Only do this, if we the song is a 1.9.4 song (or older).

View File

@ -36,7 +36,7 @@ from sqlalchemy.sql import or_
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \ from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
translate, check_item_selected, PluginStatus, create_separated_list 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.core.utils import AppLocation
from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \ from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
SongImportForm, SongExportForm SongImportForm, SongExportForm

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. **Note:** URLs and headers need to remain strings, not unicode.
""" """
global username, password 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') 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 # First get the list of languages
url = SERVER_URL + 'resource/ents/' url = SERVER_URL + 'resource/ents/'
base64string = base64.encodestring( base64string = base64.encodestring(