This commit is contained in:
Raoul Snyman 2011-08-30 21:42:12 +02:00
commit 8b8b4fbf51
11 changed files with 313 additions and 300 deletions

View File

@ -25,254 +25,15 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
import os
import sys
import logging
# Import uuid now, to avoid the rare bug described in the support system:
# http://support.openlp.org/issues/102
# If https://bugs.gentoo.org/show_bug.cgi?id=317557 is fixed, the import can be
# removed.
import uuid
from optparse import OptionParser
from traceback import format_exception
from PyQt4 import QtCore, QtGui
from openlp.core import main
from openlp.core.lib import Receiver, check_directory_exists
from openlp.core.lib.ui import UiStrings
from openlp.core.resources import qInitResources
from openlp.core.ui.mainwindow import MainWindow
from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm
from openlp.core.ui.firsttimeform import FirstTimeForm
from openlp.core.ui.exceptionform import ExceptionForm
from openlp.core.ui import SplashScreen, ScreenList
from openlp.core.utils import AppLocation, LanguageManager, VersionThread, \
get_application_version, DelayStartThread
log = logging.getLogger()
application_stylesheet = u"""
QMainWindow::separator
{
border: none;
}
QDockWidget::title
{
border: 1px solid palette(dark);
padding-left: 5px;
padding-top: 2px;
margin: 1px 0;
}
QToolBar
{
border: none;
margin: 0;
padding: 0;
}
"""
class OpenLP(QtGui.QApplication):
"""
The core application class. This class inherits from Qt's QApplication
class in order to provide the core of the application.
"""
args = []
def exec_(self):
"""
Override exec method to allow the shared memory to be released on exit
"""
QtGui.QApplication.exec_()
self.sharedMemory.detach()
def run(self, args):
"""
Run the OpenLP application.
"""
# On Windows, the args passed into the constructor are
# ignored. Not very handy, so set the ones we want to use.
self.args.extend(args)
# provide a listener for widgets to reqest a screen update.
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'openlp_process_events'), self.processEvents)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'cursor_busy'), self.setBusyCursor)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'cursor_normal'), self.setNormalCursor)
# Decide how many screens we have and their size
screens = ScreenList(self.desktop())
# First time checks in settings
has_run_wizard = QtCore.QSettings().value(
u'general/has run wizard', QtCore.QVariant(False)).toBool()
if not has_run_wizard:
if FirstTimeForm(screens).exec_() == QtGui.QDialog.Accepted:
QtCore.QSettings().setValue(u'general/has run wizard',
QtCore.QVariant(True))
if os.name == u'nt':
self.setStyleSheet(application_stylesheet)
show_splash = QtCore.QSettings().value(
u'general/show splash', QtCore.QVariant(True)).toBool()
if show_splash:
self.splash = SplashScreen()
self.splash.show()
# make sure Qt really display the splash screen
self.processEvents()
# start the main app window
self.mainWindow = MainWindow(self.clipboard(), self.args)
self.mainWindow.show()
if show_splash:
# now kill the splashscreen
self.splash.finish(self.mainWindow)
log.debug(u'Splashscreen closed')
# make sure Qt really display the splash screen
self.processEvents()
self.mainWindow.repaint()
self.processEvents()
if not has_run_wizard:
self.mainWindow.firstTime()
update_check = QtCore.QSettings().value(
u'general/update check', QtCore.QVariant(True)).toBool()
if update_check:
VersionThread(self.mainWindow).start()
Receiver.send_message(u'maindisplay_blank_check')
self.mainWindow.appStartup()
DelayStartThread(self.mainWindow).start()
return self.exec_()
def isAlreadyRunning(self):
"""
Look to see if OpenLP is already running and ask if a 2nd copy
is to be started.
"""
self.sharedMemory = QtCore.QSharedMemory('OpenLP')
if self.sharedMemory.attach():
status = QtGui.QMessageBox.critical(None,
UiStrings().Error, UiStrings().OpenLPStart,
QtGui.QMessageBox.StandardButtons(
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No))
if status == QtGui.QMessageBox.No:
return True
return False
else:
self.sharedMemory.create(1)
return False
def hookException(self, exctype, value, traceback):
if not hasattr(self, u'mainWindow'):
log.exception(''.join(format_exception(exctype, value, traceback)))
return
if not hasattr(self, u'exceptionForm'):
self.exceptionForm = ExceptionForm(self.mainWindow)
self.exceptionForm.exceptionTextEdit.setPlainText(
''.join(format_exception(exctype, value, traceback)))
self.setNormalCursor()
self.exceptionForm.exec_()
def setBusyCursor(self):
"""
Sets the Busy Cursor for the Application
"""
self.setOverrideCursor(QtCore.Qt.BusyCursor)
self.processEvents()
def setNormalCursor(self):
"""
Sets the Normal Cursor for the Application
"""
self.restoreOverrideCursor()
def event(self, event):
"""
Enables direct file opening on OS X
"""
if event.type() == QtCore.QEvent.FileOpen:
file_name = event.file()
log.debug(u'Got open file event for %s!', file_name)
self.args.insert(0, unicode(file_name))
return True
else:
return QtGui.QApplication.event(self, event)
def main():
"""
The main function which parses command line options and then runs
the PyQt4 Application.
"""
# Set up command line options.
usage = 'Usage: %prog [options] [qt-options]'
parser = OptionParser(usage=usage)
parser.add_option('-e', '--no-error-form', dest='no_error_form',
action='store_true', help='Disable the error notification form.')
parser.add_option('-l', '--log-level', dest='loglevel',
default='warning', metavar='LEVEL', help='Set logging to LEVEL '
'level. Valid values are "debug", "info", "warning".')
parser.add_option('-p', '--portable', dest='portable',
action='store_true', help='Specify if this should be run as a '
'portable app, off a USB flash drive (not implemented).')
parser.add_option('-d', '--dev-version', dest='dev_version',
action='store_true', help='Ignore the version file and pull the '
'version directly from Bazaar')
parser.add_option('-s', '--style', dest='style',
help='Set the Qt4 style (passed directly to Qt4).')
# Set up logging
log_path = AppLocation.get_directory(AppLocation.CacheDir)
check_directory_exists(log_path)
filename = os.path.join(log_path, u'openlp.log')
logfile = logging.FileHandler(filename, u'w')
logfile.setFormatter(logging.Formatter(
u'%(asctime)s %(name)-55s %(levelname)-8s %(message)s'))
log.addHandler(logfile)
logging.addLevelName(15, u'Timer')
# Parse command line options and deal with them.
(options, args) = parser.parse_args()
qt_args = []
if options.loglevel.lower() in ['d', 'debug']:
log.setLevel(logging.DEBUG)
print 'Logging to:', filename
elif options.loglevel.lower() in ['w', 'warning']:
log.setLevel(logging.WARNING)
else:
log.setLevel(logging.INFO)
if options.style:
qt_args.extend(['-style', options.style])
# Throw the rest of the arguments at Qt, just in case.
qt_args.extend(args)
# Initialise the resources
qInitResources()
# Now create and actually run the application.
app = OpenLP(qt_args)
# Instance check
if app.isAlreadyRunning():
sys.exit()
app.setOrganizationName(u'OpenLP')
app.setOrganizationDomain(u'openlp.org')
app.setApplicationName(u'OpenLP')
app.setApplicationVersion(get_application_version()[u'version'])
# First time checks in settings
if not QtCore.QSettings().value(u'general/has run wizard',
QtCore.QVariant(False)).toBool():
if not FirstTimeLanguageForm().exec_():
# if cancel then stop processing
sys.exit()
if sys.platform == u'darwin':
OpenLP.addLibraryPath(QtGui.QApplication.applicationDirPath()
+ "/qt4_plugins")
# i18n Set Language
language = LanguageManager.get_language()
app_translator, default_translator = \
LanguageManager.get_translator(language)
if not app_translator.isEmpty():
app.installTranslator(app_translator)
if not default_translator.isEmpty():
app.installTranslator(default_translator)
else:
log.debug(u'Could not find default_translator.')
if not options.no_error_form:
sys.excepthook = app.hookException
sys.exit(app.run(qt_args))
if __name__ == u'__main__':
"""

View File

@ -24,9 +24,265 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
__all__ = ('OpenLP', 'main')
import os
import sys
import logging
from optparse import OptionParser
from traceback import format_exception
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, check_directory_exists
from openlp.core.lib.ui import UiStrings
from openlp.core.resources import qInitResources
from openlp.core.ui.mainwindow import MainWindow
from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm
from openlp.core.ui.firsttimeform import FirstTimeForm
from openlp.core.ui.exceptionform import ExceptionForm
from openlp.core.ui import SplashScreen, ScreenList
from openlp.core.utils import AppLocation, LanguageManager, VersionThread, \
get_application_version, DelayStartThread
log = logging.getLogger()
"""
The :mod:`core` module provides all core application functions
All the core functions of the OpenLP application including the GUI, settings,
logging and a plugin framework are contained within the openlp.core module.
"""
application_stylesheet = u"""
QMainWindow::separator
{
border: none;
}
QDockWidget::title
{
border: 1px solid palette(dark);
padding-left: 5px;
padding-top: 2px;
margin: 1px 0;
}
QToolBar
{
border: none;
margin: 0;
padding: 0;
}
"""
class OpenLP(QtGui.QApplication):
"""
The core application class. This class inherits from Qt's QApplication
class in order to provide the core of the application.
"""
args = []
def exec_(self):
"""
Override exec method to allow the shared memory to be released on exit
"""
QtGui.QApplication.exec_()
self.sharedMemory.detach()
def run(self, args, testing=False):
"""
Run the OpenLP application.
"""
# On Windows, the args passed into the constructor are
# ignored. Not very handy, so set the ones we want to use.
self.args.extend(args)
# provide a listener for widgets to reqest a screen update.
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'openlp_process_events'), self.processEvents)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'cursor_busy'), self.setBusyCursor)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'cursor_normal'), self.setNormalCursor)
# Decide how many screens we have and their size
screens = ScreenList(self.desktop())
# First time checks in settings
has_run_wizard = QtCore.QSettings().value(
u'general/has run wizard', QtCore.QVariant(False)).toBool()
if not has_run_wizard:
if FirstTimeForm(screens).exec_() == QtGui.QDialog.Accepted:
QtCore.QSettings().setValue(u'general/has run wizard',
QtCore.QVariant(True))
if os.name == u'nt':
self.setStyleSheet(application_stylesheet)
show_splash = QtCore.QSettings().value(
u'general/show splash', QtCore.QVariant(True)).toBool()
if show_splash:
self.splash = SplashScreen()
self.splash.show()
# make sure Qt really display the splash screen
self.processEvents()
# start the main app window
self.mainWindow = MainWindow(self.clipboard(), self.args)
self.mainWindow.show()
if show_splash:
# now kill the splashscreen
self.splash.finish(self.mainWindow)
log.debug(u'Splashscreen closed')
# make sure Qt really display the splash screen
self.processEvents()
self.mainWindow.repaint()
self.processEvents()
if not has_run_wizard:
self.mainWindow.firstTime()
update_check = QtCore.QSettings().value(
u'general/update check', QtCore.QVariant(True)).toBool()
if update_check:
VersionThread(self.mainWindow).start()
Receiver.send_message(u'maindisplay_blank_check')
self.mainWindow.appStartup()
DelayStartThread(self.mainWindow).start()
# Skip exec_() for gui tests
if not testing:
return self.exec_()
def isAlreadyRunning(self):
"""
Look to see if OpenLP is already running and ask if a 2nd copy
is to be started.
"""
self.sharedMemory = QtCore.QSharedMemory('OpenLP')
if self.sharedMemory.attach():
status = QtGui.QMessageBox.critical(None,
UiStrings().Error, UiStrings().OpenLPStart,
QtGui.QMessageBox.StandardButtons(
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No))
if status == QtGui.QMessageBox.No:
return True
return False
else:
self.sharedMemory.create(1)
return False
def hookException(self, exctype, value, traceback):
if not hasattr(self, u'mainWindow'):
log.exception(''.join(format_exception(exctype, value, traceback)))
return
if not hasattr(self, u'exceptionForm'):
self.exceptionForm = ExceptionForm(self.mainWindow)
self.exceptionForm.exceptionTextEdit.setPlainText(
''.join(format_exception(exctype, value, traceback)))
self.setNormalCursor()
self.exceptionForm.exec_()
def setBusyCursor(self):
"""
Sets the Busy Cursor for the Application
"""
self.setOverrideCursor(QtCore.Qt.BusyCursor)
self.processEvents()
def setNormalCursor(self):
"""
Sets the Normal Cursor for the Application
"""
self.restoreOverrideCursor()
def event(self, event):
"""
Enables direct file opening on OS X
"""
if event.type() == QtCore.QEvent.FileOpen:
file_name = event.file()
log.debug(u'Got open file event for %s!', file_name)
self.args.insert(0, unicode(file_name))
return True
else:
return QtGui.QApplication.event(self, event)
def main(args=None):
"""
The main function which parses command line options and then runs
the PyQt4 Application.
"""
# Set up command line options.
usage = 'Usage: %prog [options] [qt-options]'
parser = OptionParser(usage=usage)
parser.add_option('-e', '--no-error-form', dest='no_error_form',
action='store_true', help='Disable the error notification form.')
parser.add_option('-l', '--log-level', dest='loglevel',
default='warning', metavar='LEVEL', help='Set logging to LEVEL '
'level. Valid values are "debug", "info", "warning".')
parser.add_option('-p', '--portable', dest='portable',
action='store_true', help='Specify if this should be run as a '
'portable app, off a USB flash drive (not implemented).')
parser.add_option('-d', '--dev-version', dest='dev_version',
action='store_true', help='Ignore the version file and pull the '
'version directly from Bazaar')
parser.add_option('-s', '--style', dest='style',
help='Set the Qt4 style (passed directly to Qt4).')
parser.add_option('--testing', dest='testing',
action='store_true', help='Run by testing framework')
# Set up logging
log_path = AppLocation.get_directory(AppLocation.CacheDir)
check_directory_exists(log_path)
filename = os.path.join(log_path, u'openlp.log')
logfile = logging.FileHandler(filename, u'w')
logfile.setFormatter(logging.Formatter(
u'%(asctime)s %(name)-55s %(levelname)-8s %(message)s'))
log.addHandler(logfile)
logging.addLevelName(15, u'Timer')
# Parse command line options and deal with them.
# Use args supplied programatically if possible.
(options, args) = parser.parse_args(args) if args else parser.parse_args()
qt_args = []
if options.loglevel.lower() in ['d', 'debug']:
log.setLevel(logging.DEBUG)
print 'Logging to:', filename
elif options.loglevel.lower() in ['w', 'warning']:
log.setLevel(logging.WARNING)
else:
log.setLevel(logging.INFO)
if options.style:
qt_args.extend(['-style', options.style])
# Throw the rest of the arguments at Qt, just in case.
qt_args.extend(args)
# Initialise the resources
qInitResources()
# Now create and actually run the application.
app = OpenLP(qt_args)
app.setOrganizationName(u'OpenLP')
app.setOrganizationDomain(u'openlp.org')
app.setApplicationName(u'OpenLP')
app.setApplicationVersion(get_application_version()[u'version'])
# Instance check
if app.isAlreadyRunning():
sys.exit()
# First time checks in settings
if not QtCore.QSettings().value(u'general/has run wizard',
QtCore.QVariant(False)).toBool():
if not FirstTimeLanguageForm().exec_():
# if cancel then stop processing
sys.exit()
# i18n Set Language
language = LanguageManager.get_language()
app_translator, default_translator = \
LanguageManager.get_translator(language)
if not app_translator.isEmpty():
app.installTranslator(app_translator)
if not default_translator.isEmpty():
app.installTranslator(default_translator)
else:
log.debug(u'Could not find default_translator.')
if not options.no_error_form:
sys.excepthook = app.hookException
# Do not run method app.exec_() when running gui tests
if options.testing:
app.run(qt_args, testing=True)
else:
sys.exit(app.run(qt_args))

View File

@ -377,7 +377,7 @@ class MediaManagerItem(QtGui.QWidget):
"""
names = []
for count in range(0, self.listView.count()):
names.append(self.listView.item(count).text())
names.append(unicode(self.listView.item(count).text()))
newFiles = []
duplicatesFound = False
for file in files:
@ -396,7 +396,7 @@ class MediaManagerItem(QtGui.QWidget):
critical_error_message_box(
UiStrings().Duplicate,
unicode(translate('OpenLP.MediaManagerItem',
'Duplicate files found on import and ignored.')))
'Duplicate files were found on import and were ignored.')))
def contextMenu(self, point):
item = self.listView.itemAt(point)

View File

@ -229,53 +229,47 @@ class Renderer(object):
lines = self._lines_split(text)
pages = self._paginate_slide(lines, line_end)
# Songs and Custom
if item.is_capable(ItemCapabilities.HasVirtualSplit):
if item.is_capable(ItemCapabilities.HasVirtualSplit) and \
len(pages) > 1 and u'[---]' in text:
pages = []
while True:
# Check if the first two potential virtual slides will fit
# (as a whole) on one slide.
html_text = expand_tags(
u'\n'.join(text.split(u'\n[---]\n', 2)[:-1]))
slides = text.split(u'\n[---]\n', 2)
# If there are (at least) two occurrences of [---] we use
# the first two slides (and neglect the last for now).
if len(slides) == 3:
html_text = expand_tags(u'\n'.join(slides[:2]))
# We check both slides to determine if the virtual break is
# needed (there is only one virtual break).
else:
html_text = expand_tags(u'\n'.join(slides))
html_text = html_text.replace(u'\n', u'<br>')
if self._text_fits_on_slide(html_text):
# The first two virtual slides fit (as a whole) on one
# slide. Replace the occurrences of [---].
text = text.replace(u'\n[---]', u'', 2)
# slide. Replace the first occurrence of [---].
text = text.replace(u'\n[---]', u'', 1)
else:
# The first two virtual slides did not fit as a whole.
# Check if the first virtual slide will fit.
html_text = expand_tags(text.split(u'\n[---]\n', 1)[1])
html_text = html_text.replace(u'\n', u'<br>')
if self._text_fits_on_slide(html_text):
# The first virtual slide fits, so remove it.
text = text.replace(u'\n[---]', u'', 1)
# The first virtual slide fits, which means we have to
# render the first virtual slide.
text_contains_break = u'[---]' in text
if text_contains_break:
text_to_render, text = text.split(u'\n[---]\n', 1)
else:
# The first virtual slide does not fit, which means
# we have to render the first virtual slide.
text_contains_break = u'[---]' in text
if text_contains_break:
html_text, text = text.split(u'\n[---]\n', 1)
text_to_render = text
text = u''
lines = text_to_render.strip(u'\n').split(u'\n')
slides = self._paginate_slide(lines, line_end)
if len(slides) > 1 and text:
# Add all slides apart from the last one the list.
pages.extend(slides[:-1])
if text_contains_break:
text = slides[-1] + u'\n[---]\n' + text
else:
html_text = text
text = u''
lines = expand_tags(html_text)
lines = lines.strip(u'\n').split(u'\n')
slides = self._paginate_slide(lines, line_end)
if len(slides) > 1 and text:
# Add all slides apart from the last one the
# list.
pages.extend(slides[:-1])
if text_contains_break:
text = slides[-1] + u'\n[---]\n' + text
else:
text = slides[-1] + u'\n'+ text
text = text.replace(u'<br>', u'\n')
else:
pages.extend(slides)
text = slides[-1] + u'\n'+ text
text = text.replace(u'<br>', u'\n')
else:
pages.extend(slides)
if u'[---]' not in text:
lines = expand_tags(text)
lines = lines.strip(u'\n').split(u'\n')
lines = text.strip(u'\n').split(u'\n')
pages.extend(self._paginate_slide(lines, line_end))
break
new_pages = []

View File

@ -600,8 +600,8 @@ class ServiceManager(QtGui.QWidget):
fileTo = None
try:
zip = zipfile.ZipFile(fileName)
for file in zip.namelist():
ucsfile = file_is_unicode(file)
for zipinfo in zip.infolist():
ucsfile = file_is_unicode(zipinfo.filename)
if not ucsfile:
critical_error_message_box(
message=translate('OpenLP.ServiceManager',
@ -611,18 +611,10 @@ class ServiceManager(QtGui.QWidget):
osfile = unicode(QtCore.QDir.toNativeSeparators(ucsfile))
if not osfile.startswith(u'audio'):
osfile = os.path.split(osfile)[1]
else:
path = os.path.join(self.servicePath,
os.path.split(osfile)[0])
if not os.path.exists(path):
os.makedirs(path)
filePath = os.path.join(self.servicePath, osfile)
fileTo = open(filePath, u'wb')
fileTo.write(zip.read(file))
fileTo.flush()
fileTo.close()
if filePath.endswith(u'osd'):
p_file = filePath
zipinfo.filename = osfile
zip.extract(zipinfo, self.servicePath)
if osfile.endswith(u'osd'):
p_file = os.path.join(self.servicePath, osfile)
if 'p_file' in locals():
Receiver.send_message(u'cursor_busy')
fileTo = open(p_file, u'r')

View File

@ -218,7 +218,7 @@ class BSExtract(object):
send_error_message(u'parse')
return None
content = content.find(u'div').findAll(u'div')
verse_number = re.compile(r'v(\d{1,2})(\d{3})(\d{3}) verse')
verse_number = re.compile(r'v(\d{1,2})(\d{3})(\d{3}) verse.*')
verses = {}
for verse in content:
Receiver.send_message(u'openlp_process_events')

View File

@ -184,10 +184,11 @@ class VerseType(object):
verse_index = VerseType.from_translated_string(verse_name)
if verse_index is None:
verse_index = VerseType.from_string(verse_name)
if verse_index is None:
verse_index = VerseType.from_translated_tag(verse_name)
if verse_index is None:
verse_index = VerseType.from_tag(verse_name)
elif len(verse_name) == 1:
if verse_index is None:
verse_index = VerseType.from_translated_tag(verse_name)
if verse_index is None:
verse_index = VerseType.from_tag(verse_name)
return verse_index
def retrieve_windows_encoding(recommendation=None):

View File

@ -88,6 +88,8 @@ class SongMediaItem(MediaManagerItem):
dest_file = os.path.join(
AppLocation.get_section_data_path(self.plugin.name),
u'audio', str(song.id), os.path.split(bga)[1])
if not os.path.exists(os.path.split(dest_file)[0]):
os.makedirs(os.path.split(dest_file)[0])
shutil.copyfile(os.path.join(
AppLocation.get_section_data_path(
u'servicemanager'), bga),

View File

@ -190,7 +190,10 @@ class OpenSongImport(SongImport):
# the verse tag
verse_tag = content
verse_num = u'1'
verse_index = VerseType.from_loose_input(verse_tag)
if len(verse_tag) == 0:
verse_index = 0
else:
verse_index = VerseType.from_loose_input(verse_tag)
verse_tag = VerseType.Tags[verse_index]
inst = 1
if [verse_tag, verse_num, inst] in our_verse_order \

View File

@ -103,6 +103,8 @@ class SongShowPlusImport(SongImport):
return
self.import_wizard.progressBar.setMaximum(len(self.import_source))
for file in self.import_source:
if self.stop_import_flag:
return
self.sspVerseOrderList = []
otherCount = 0
otherList = {}

View File

@ -105,6 +105,8 @@ class WowImport(SongImport):
if isinstance(self.import_source, list):
self.import_wizard.progressBar.setMaximum(len(self.import_source))
for file in self.import_source:
if self.stop_import_flag:
return
file_name = os.path.split(file)[1]
# Get the song title
self.title = file_name.rpartition(u'.')[0]