forked from openlp/openlp
HEAD
This commit is contained in:
commit
d4aab974d2
@ -32,7 +32,7 @@ import logging
|
||||
import os.path
|
||||
import types
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
from PyQt4 import QtCore, QtGui, Qt
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -318,6 +318,34 @@ def check_directory_exists(dir):
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
def create_separated_list(stringlist):
|
||||
"""
|
||||
Returns a string that represents a join of a list of strings with a
|
||||
localized separator. This function corresponts to
|
||||
QLocale::createSeparatedList which was introduced in Qt 4.8 and implements
|
||||
the algorithm from http://www.unicode.org/reports/tr35/#ListPatterns
|
||||
|
||||
``stringlist``
|
||||
List of unicode strings
|
||||
"""
|
||||
if Qt.qVersion() >= u'4.8':
|
||||
return unicode(QtCore.QLocale.createSeparatedList(stringlist))
|
||||
if not stringlist:
|
||||
return u''
|
||||
elif len(stringlist) == 1:
|
||||
return stringlist[0]
|
||||
elif len(stringlist) == 2:
|
||||
return unicode(translate('OpenLP.core.lib', '%1 and %2',
|
||||
'Locale list separator: 2 items').arg(stringlist[0], stringlist[1]))
|
||||
else:
|
||||
merged = unicode(translate('OpenLP.core.lib', '%1, and %2',
|
||||
u'Locale list separator: end').arg(stringlist[-2], stringlist[-1]))
|
||||
for index in reversed(range(1, len(stringlist) - 2)):
|
||||
merged = unicode(translate('OpenLP.core.lib', '%1, %2',
|
||||
u'Locale list separator: middle').arg(stringlist[index], merged))
|
||||
return unicode(translate('OpenLP.core.lib', '%1, %2',
|
||||
u'Locale list separator: start').arg(stringlist[0], merged))
|
||||
|
||||
from eventreceiver import Receiver
|
||||
from listwidgetwithdnd import ListWidgetWithDnD
|
||||
from formattingtags import FormattingTags
|
||||
|
@ -239,6 +239,17 @@ class Manager(object):
|
||||
self.session.commit()
|
||||
self.is_dirty = True
|
||||
return True
|
||||
except OperationalError:
|
||||
# This exception clause is for users running MySQL which likes
|
||||
# to terminate connections on its own without telling anyone.
|
||||
# See bug #927473
|
||||
log.exception(u'Probably a MySQL issue - "MySQL has gone away"')
|
||||
self.session.rollback()
|
||||
self.session.add(object_instance)
|
||||
if commit:
|
||||
self.session.commit()
|
||||
self.is_dirty = True
|
||||
return True
|
||||
except InvalidRequestError:
|
||||
self.session.rollback()
|
||||
log.exception(u'Object save failed')
|
||||
@ -260,6 +271,17 @@ class Manager(object):
|
||||
self.session.commit()
|
||||
self.is_dirty = True
|
||||
return True
|
||||
except OperationalError:
|
||||
# This exception clause is for users running MySQL which likes
|
||||
# to terminate connections on its own without telling anyone.
|
||||
# See bug #927473
|
||||
log.exception(u'Probably a MySQL issue, "MySQL has gone away"')
|
||||
self.session.rollback()
|
||||
self.session.add_all(object_list)
|
||||
if commit:
|
||||
self.session.commit()
|
||||
self.is_dirty = True
|
||||
return True
|
||||
except InvalidRequestError:
|
||||
self.session.rollback()
|
||||
log.exception(u'Object list save failed')
|
||||
@ -278,7 +300,15 @@ class Manager(object):
|
||||
if not key:
|
||||
return object_class()
|
||||
else:
|
||||
return self.session.query(object_class).get(key)
|
||||
try:
|
||||
return self.session.query(object_class).get(key)
|
||||
except OperationalError:
|
||||
# This exception clause is for users running MySQL which likes
|
||||
# to terminate connections on its own without telling anyone.
|
||||
# See bug #927473
|
||||
log.exception(u'Probably a MySQL issue, "MySQL has gone away"')
|
||||
self.session.rollback()
|
||||
return self.session.query(object_class).get(key)
|
||||
|
||||
def get_object_filtered(self, object_class, filter_clause):
|
||||
"""
|
||||
@ -290,7 +320,15 @@ class Manager(object):
|
||||
``filter_clause``
|
||||
The criteria to select the object by
|
||||
"""
|
||||
return self.session.query(object_class).filter(filter_clause).first()
|
||||
try:
|
||||
return self.session.query(object_class).filter(filter_clause).first()
|
||||
except OperationalError:
|
||||
# This exception clause is for users running MySQL which likes
|
||||
# to terminate connections on its own without telling anyone.
|
||||
# See bug #927473
|
||||
log.exception(u'Probably a MySQL issue, "MySQL has gone away"')
|
||||
self.session.rollback()
|
||||
return self.session.query(object_class).filter(filter_clause).first()
|
||||
|
||||
def get_all_objects(self, object_class, filter_clause=None,
|
||||
order_by_ref=None):
|
||||
@ -311,10 +349,18 @@ class Manager(object):
|
||||
if filter_clause is not None:
|
||||
query = query.filter(filter_clause)
|
||||
if isinstance(order_by_ref, list):
|
||||
return query.order_by(*order_by_ref).all()
|
||||
query = query.order_by(*order_by_ref)
|
||||
elif order_by_ref is not None:
|
||||
return query.order_by(order_by_ref).all()
|
||||
return query.all()
|
||||
query = query.order_by(order_by_ref)
|
||||
try:
|
||||
return query.all()
|
||||
except OperationalError:
|
||||
# This exception clause is for users running MySQL which likes
|
||||
# to terminate connections on its own without telling anyone.
|
||||
# See bug #927473
|
||||
log.exception(u'Probably a MySQL issue, "MySQL has gone away"')
|
||||
self.session.rollback()
|
||||
return query.all()
|
||||
|
||||
def get_object_count(self, object_class, filter_clause=None):
|
||||
"""
|
||||
@ -330,7 +376,15 @@ class Manager(object):
|
||||
query = self.session.query(object_class)
|
||||
if filter_clause is not None:
|
||||
query = query.filter(filter_clause)
|
||||
return query.count()
|
||||
try:
|
||||
return query.count()
|
||||
except OperationalError:
|
||||
# This exception clause is for users running MySQL which likes
|
||||
# to terminate connections on its own without telling anyone.
|
||||
# See bug #927473
|
||||
log.exception(u'Probably a MySQL issue, "MySQL has gone away"')
|
||||
self.session.rollback()
|
||||
return query.count()
|
||||
|
||||
def delete_object(self, object_class, key):
|
||||
"""
|
||||
@ -349,6 +403,16 @@ class Manager(object):
|
||||
self.session.commit()
|
||||
self.is_dirty = True
|
||||
return True
|
||||
except OperationalError:
|
||||
# This exception clause is for users running MySQL which likes
|
||||
# to terminate connections on its own without telling anyone.
|
||||
# See bug #927473
|
||||
log.exception(u'Probably a MySQL issue, "MySQL has gone away"')
|
||||
self.session.rollback()
|
||||
self.session.delete(object_instance)
|
||||
self.session.commit()
|
||||
self.is_dirty = True
|
||||
return True
|
||||
except InvalidRequestError:
|
||||
self.session.rollback()
|
||||
log.exception(u'Failed to delete object')
|
||||
@ -378,6 +442,19 @@ class Manager(object):
|
||||
self.session.commit()
|
||||
self.is_dirty = True
|
||||
return True
|
||||
except OperationalError:
|
||||
# This exception clause is for users running MySQL which likes
|
||||
# to terminate connections on its own without telling anyone.
|
||||
# See bug #927473
|
||||
log.exception(u'Probably a MySQL issue, "MySQL has gone away"')
|
||||
self.session.rollback()
|
||||
query = self.session.query(object_class)
|
||||
if filter_clause is not None:
|
||||
query = query.filter(filter_clause)
|
||||
query.delete(synchronize_session=False)
|
||||
self.session.commit()
|
||||
self.is_dirty = True
|
||||
return True
|
||||
except InvalidRequestError:
|
||||
self.session.rollback()
|
||||
log.exception(u'Failed to delete %s records', object_class.__name__)
|
||||
|
@ -1254,7 +1254,7 @@ class SlideController(Controller):
|
||||
if wrap is None:
|
||||
if self.slide_limits == SlideLimits.Wrap:
|
||||
row = 0
|
||||
elif self.slide_limits == SlideLimits.Next:
|
||||
elif self.isLive and self.slide_limits == SlideLimits.Next:
|
||||
self.serviceNext()
|
||||
return
|
||||
else:
|
||||
@ -1281,7 +1281,7 @@ class SlideController(Controller):
|
||||
if row == -1:
|
||||
if self.slide_limits == SlideLimits.Wrap:
|
||||
row = self.previewListWidget.rowCount() - 1
|
||||
elif self.slide_limits == SlideLimits.Next:
|
||||
elif self.isLive and self.slide_limits == SlideLimits.Next:
|
||||
self.keypress_queue.append(ServiceItemAction.PreviousLastSlide)
|
||||
self._process_queue()
|
||||
return
|
||||
|
@ -31,7 +31,7 @@ import locale
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
|
||||
translate
|
||||
translate, create_separated_list
|
||||
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, \
|
||||
@ -868,7 +868,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||
service_item.add_capability(ItemCapabilities.CanLoop)
|
||||
service_item.add_capability(ItemCapabilities.CanWordSplit)
|
||||
# Service Item: Title
|
||||
service_item.title = u', '.join(raw_title)
|
||||
service_item.title = create_separated_list(raw_title)
|
||||
# Service Item: Theme
|
||||
if len(self.settings.bible_theme) == 0:
|
||||
service_item.theme = None
|
||||
|
@ -32,7 +32,8 @@ import shutil
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.lib import PluginStatus, Receiver, MediaType, translate
|
||||
from openlp.core.lib import PluginStatus, Receiver, MediaType, translate, \
|
||||
create_separated_list
|
||||
from openlp.core.lib.ui import UiStrings, add_widget_completer, \
|
||||
critical_error_message_box, find_and_set_in_combo_box
|
||||
from openlp.core.utils import AppLocation
|
||||
@ -633,7 +634,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
||||
VerseType.translated_tag(verse[0]), verse[1:]))
|
||||
for count, item in enumerate(order):
|
||||
if item not in verses:
|
||||
valid = u', '.join(verse_names)
|
||||
valid = create_separated_list(verse_names)
|
||||
critical_error_message_box(
|
||||
message=unicode(translate('SongsPlugin.EditSongForm',
|
||||
'The verse order is invalid. There is no verse '
|
||||
|
@ -33,7 +33,8 @@ import logging
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.lib import build_icon, Receiver, SettingsManager, translate
|
||||
from openlp.core.lib import build_icon, Receiver, SettingsManager, translate, \
|
||||
create_separated_list
|
||||
from openlp.core.lib.ui import UiStrings, critical_error_message_box
|
||||
from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
|
||||
from openlp.plugins.songs.lib.db import Song
|
||||
@ -255,7 +256,7 @@ class SongExportForm(OpenLPWizard):
|
||||
# No need to export temporary songs.
|
||||
if song.temporary:
|
||||
continue
|
||||
authors = u', '.join([author.display_name
|
||||
authors = create_separated_list([author.display_name
|
||||
for author in song.authors])
|
||||
title = u'%s (%s)' % (unicode(song.title), authors)
|
||||
item = QtGui.QListWidgetItem(title)
|
||||
|
@ -35,7 +35,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, create_separated_list
|
||||
from openlp.core.lib.ui import UiStrings, context_menu_action, \
|
||||
context_menu_separator
|
||||
from openlp.core.utils import AppLocation
|
||||
@ -247,7 +247,8 @@ class SongMediaItem(MediaManagerItem):
|
||||
continue
|
||||
author_list = [author.display_name for author in song.authors]
|
||||
song_title = unicode(song.title)
|
||||
song_detail = u'%s (%s)' % (song_title, u', '.join(author_list))
|
||||
song_detail = u'%s (%s)' % (song_title,
|
||||
create_separated_list(author_list))
|
||||
song_name = QtGui.QListWidgetItem(song_detail)
|
||||
song_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(song.id))
|
||||
self.listView.addItem(song_name)
|
||||
@ -469,7 +470,7 @@ class SongMediaItem(MediaManagerItem):
|
||||
service_item.title = song.title
|
||||
author_list = [unicode(author.display_name) for author in song.authors]
|
||||
service_item.raw_footer.append(song.title)
|
||||
service_item.raw_footer.append(u', '.join(author_list))
|
||||
service_item.raw_footer.append(create_separated_list(author_list))
|
||||
service_item.raw_footer.append(song.copyright)
|
||||
if QtCore.QSettings().value(u'general/ccli number',
|
||||
QtCore.QVariant(u'')).toString():
|
||||
|
@ -107,10 +107,11 @@ Sqlalchemy Migrate
|
||||
|
||||
import os
|
||||
import sys
|
||||
from shutil import copy
|
||||
from shutil import rmtree
|
||||
from shutil import copy, rmtree
|
||||
from subprocess import Popen, PIPE
|
||||
from ConfigParser import SafeConfigParser as ConfigParser
|
||||
|
||||
# Executable paths
|
||||
python_exe = sys.executable
|
||||
innosetup_exe = os.path.join(os.getenv(u'PROGRAMFILES'), 'Inno Setup 5',
|
||||
u'ISCC.exe')
|
||||
@ -157,6 +158,10 @@ pptviewlib_path = os.path.join(source_path, u'plugins', u'presentations',
|
||||
u'lib', u'pptviewlib')
|
||||
hooks_path = os.path.join(branch_path , u'resources', u'pyinstaller')
|
||||
|
||||
# Transifex details -- will be read in from the file.
|
||||
transifex_filename = os.path.abspath(os.path.join(branch_path, '..',
|
||||
'transifex.conf'))
|
||||
|
||||
def update_code():
|
||||
os.chdir(branch_path)
|
||||
print u'Reverting any changes to the code...'
|
||||
@ -264,8 +269,22 @@ def copy_windows_files():
|
||||
|
||||
def update_translations():
|
||||
print u'Updating translations...'
|
||||
if not os.path.exists(transifex_filename):
|
||||
raise Exception(u'Could not find Transifex credentials file: %s' \
|
||||
% transifex_filename)
|
||||
config = ConfigParser()
|
||||
config.read(transifex_filename)
|
||||
if not config.has_section('transifex'):
|
||||
raise Exception(u'No section named "transifex" found.')
|
||||
if not config.has_option('transifex', 'username'):
|
||||
raise Exception(u'No option named "username" found.')
|
||||
if not config.has_option('transifex', 'password'):
|
||||
raise Exception(u'No option named "password" found.')
|
||||
username = config.get('transifex', 'username')
|
||||
password = config.get('transifex', 'password')
|
||||
os.chdir(script_path)
|
||||
translation_utils = Popen((python_exe, i18n_utils, u'-qdpu'))
|
||||
translation_utils = Popen([python_exe, i18n_utils, u'-qdpu', '-U',
|
||||
username, '-P', password])
|
||||
code = translation_utils.wait()
|
||||
if code != 0:
|
||||
raise Exception(u'Error running translation_utils.py')
|
||||
|
Loading…
Reference in New Issue
Block a user