This commit is contained in:
Dmitriy Marmyshev 2013-04-02 12:52:47 +04:00
commit 15fee17827
187 changed files with 6501 additions and 3484 deletions

View File

@ -23,3 +23,7 @@ resources/windows/warnOpenLP.txt
openlp.cfg openlp.cfg
.idea .idea
openlp.pro openlp.pro
.kdev4
tests.kdev4
*.nja
*.orig

View File

@ -1 +1 @@
2.0 2.1.0-bzr2141

View File

@ -34,4 +34,3 @@ import core
import plugins import plugins
__all__ = [u'core', u'plugins'] __all__ = [u'core', u'plugins']

View File

@ -43,16 +43,14 @@ from traceback import format_exception
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, Settings, check_directory_exists from openlp.core.lib import Receiver, Settings, ScreenList, UiStrings, Registry, check_directory_exists
from openlp.core.lib.ui import UiStrings
from openlp.core.resources import qInitResources from openlp.core.resources import qInitResources
from openlp.core.ui.mainwindow import MainWindow from openlp.core.ui.mainwindow import MainWindow
from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm
from openlp.core.ui.firsttimeform import FirstTimeForm from openlp.core.ui.firsttimeform import FirstTimeForm
from openlp.core.ui.exceptionform import ExceptionForm from openlp.core.ui.exceptionform import ExceptionForm
from openlp.core.ui import SplashScreen, ScreenList from openlp.core.ui import SplashScreen
from openlp.core.utils import AppLocation, LanguageManager, VersionThread, \ from openlp.core.utils import AppLocation, LanguageManager, VersionThread, get_application_version
get_application_version
__all__ = [u'OpenLP', u'main'] __all__ = [u'OpenLP', u'main']
@ -94,15 +92,16 @@ class OpenLP(QtGui.QApplication):
""" """
Override exec method to allow the shared memory to be released on exit Override exec method to allow the shared memory to be released on exit
""" """
self.eventLoopIsActive = True self.is_event_loop_active = True
QtGui.QApplication.exec_() result = QtGui.QApplication.exec_()
self.sharedMemory.detach() self.shared_memory.detach()
return result
def run(self, args, testing=False): def run(self, args):
""" """
Run the OpenLP application. Run the OpenLP application.
""" """
self.eventLoopIsActive = False self.is_event_loop_active = False
# On Windows, the args passed into the constructor are ignored. Not # On Windows, the args passed into the constructor are ignored. Not
# very handy, so set the ones we want to use. On Linux and FreeBSD, in # very handy, so set the ones we want to use. On Linux and FreeBSD, in
# order to set the WM_CLASS property for X11, we pass "OpenLP" in as a # order to set the WM_CLASS property for X11, we pass "OpenLP" in as a
@ -111,90 +110,114 @@ class OpenLP(QtGui.QApplication):
if 'OpenLP' in args: if 'OpenLP' in args:
args.remove('OpenLP') args.remove('OpenLP')
self.args.extend(args) 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 # Decide how many screens we have and their size
screens = ScreenList.create(self.desktop()) screens = ScreenList.create(self.desktop())
# First time checks in settings # First time checks in settings
has_run_wizard = Settings().value(u'general/has run wizard', False) has_run_wizard = Settings().value(u'general/has run wizard')
if not has_run_wizard: if not has_run_wizard:
if FirstTimeForm(screens).exec_() == QtGui.QDialog.Accepted: if FirstTimeForm(screens).exec_() == QtGui.QDialog.Accepted:
Settings().setValue(u'general/has run wizard', True) Settings().setValue(u'general/has run wizard', True)
# Correct stylesheet bugs # Correct stylesheet bugs
if os.name == u'nt': application_stylesheet = u''
if not Settings().value(u'advanced/alternate rows'):
base_color = self.palette().color(QtGui.QPalette.Active, QtGui.QPalette.Base) base_color = self.palette().color(QtGui.QPalette.Active, QtGui.QPalette.Base)
application_stylesheet = \ alternate_rows_repair_stylesheet = \
u'QTableWidget, QListWidget, QTreeWidget {alternate-background-color: ' + base_color.name() + ';}\n' u'QTableWidget, QListWidget, QTreeWidget {alternate-background-color: ' + base_color.name() + ';}\n'
application_stylesheet += alternate_rows_repair_stylesheet
if os.name == u'nt':
application_stylesheet += nt_repair_stylesheet application_stylesheet += nt_repair_stylesheet
if application_stylesheet:
self.setStyleSheet(application_stylesheet) self.setStyleSheet(application_stylesheet)
show_splash = Settings().value(u'general/show splash', True) show_splash = Settings().value(u'general/show splash')
if show_splash: if show_splash:
self.splash = SplashScreen() self.splash = SplashScreen()
self.splash.show() self.splash.show()
# make sure Qt really display the splash screen # make sure Qt really display the splash screen
self.processEvents() self.processEvents()
# start the main app window # start the main app window
self.mainWindow = MainWindow(self) self.main_window = MainWindow()
self.mainWindow.show() self.main_window.show()
if show_splash: if show_splash:
# now kill the splashscreen # now kill the splashscreen
self.splash.finish(self.mainWindow) self.splash.finish(self.main_window)
log.debug(u'Splashscreen closed') log.debug(u'Splashscreen closed')
# make sure Qt really display the splash screen # make sure Qt really display the splash screen
self.processEvents() self.processEvents()
self.mainWindow.repaint() self.main_window.repaint()
self.processEvents() self.processEvents()
if not has_run_wizard: if not has_run_wizard:
self.mainWindow.firstTime() self.main_window.first_time()
update_check = Settings().value(u'general/update check', True) update_check = Settings().value(u'general/update check')
if update_check: if update_check:
VersionThread(self.mainWindow).start() VersionThread(self.main_window).start()
Receiver.send_message(u'live_display_blank_check') Receiver.send_message(u'live_display_blank_check')
self.mainWindow.appStartup() self.main_window.app_startup()
# Skip exec_() for gui tests return self.exec_()
if not testing:
return self.exec_()
def isAlreadyRunning(self): def close_splash_screen(self):
"""
Close the splash screen when requested.
"""
self.splash.close()
def is_already_running(self):
""" """
Look to see if OpenLP is already running and ask if a 2nd copy Look to see if OpenLP is already running and ask if a 2nd copy
is to be started. is to be started.
""" """
self.sharedMemory = QtCore.QSharedMemory('OpenLP') self.shared_memory = QtCore.QSharedMemory('OpenLP')
if self.sharedMemory.attach(): if self.shared_memory.attach():
status = QtGui.QMessageBox.critical(None, UiStrings().Error, UiStrings().OpenLPStart, status = QtGui.QMessageBox.critical(None, UiStrings().Error, UiStrings().OpenLPStart,
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)) QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No))
if status == QtGui.QMessageBox.No: if status == QtGui.QMessageBox.No:
return True return True
return False return False
else: else:
self.sharedMemory.create(1) self.shared_memory.create(1)
return False return False
def hookException(self, exctype, value, traceback): def hook_exception(self, exctype, value, traceback):
"""
Add an exception hook so that any uncaught exceptions are displayed in this window rather than somewhere where
users cannot see it and cannot report when we encounter these problems.
``exctype``
The class of exception.
``value``
The actual exception object.
``traceback``
A traceback object with the details of where the exception occurred.
"""
if not hasattr(self, u'mainWindow'): if not hasattr(self, u'mainWindow'):
log.exception(''.join(format_exception(exctype, value, traceback))) log.exception(''.join(format_exception(exctype, value, traceback)))
return return
if not hasattr(self, u'exceptionForm'): if not hasattr(self, u'exceptionForm'):
self.exceptionForm = ExceptionForm(self.mainWindow) self.exception_form = ExceptionForm(self.main_window)
self.exceptionForm.exceptionTextEdit.setPlainText(''.join(format_exception(exctype, value, traceback))) self.exception_form.exceptionTextEdit.setPlainText(''.join(format_exception(exctype, value, traceback)))
self.setNormalCursor() self.set_normal_cursor()
self.exceptionForm.exec_() self.exception_form.exec_()
def setBusyCursor(self): def process_events(self):
"""
Wrapper to make ProcessEvents visible and named correctly
"""
self.processEvents()
def set_busy_cursor(self):
""" """
Sets the Busy Cursor for the Application Sets the Busy Cursor for the Application
""" """
self.setOverrideCursor(QtCore.Qt.BusyCursor) self.setOverrideCursor(QtCore.Qt.BusyCursor)
self.processEvents() self.processEvents()
def setNormalCursor(self): def set_normal_cursor(self):
""" """
Sets the Normal Cursor for the Application Sets the Normal Cursor for the Application
""" """
self.restoreOverrideCursor() self.restoreOverrideCursor()
self.processEvents()
def event(self, event): def event(self, event):
""" """
@ -213,13 +236,13 @@ def set_up_logging(log_path):
""" """
Setup our logging using log_path Setup our logging using log_path
""" """
check_directory_exists(log_path) check_directory_exists(log_path, True)
filename = os.path.join(log_path, u'openlp.log') filename = os.path.join(log_path, u'openlp.log')
logfile = logging.FileHandler(filename, u'w') logfile = logging.FileHandler(filename, u'w')
logfile.setFormatter(logging.Formatter(u'%(asctime)s %(name)-55s %(levelname)-8s %(message)s')) logfile.setFormatter(logging.Formatter(u'%(asctime)s %(name)-55s %(levelname)-8s %(message)s'))
log.addHandler(logfile) log.addHandler(logfile)
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
print 'Logging to:', filename print('Logging to: %s' % filename)
def main(args=None): def main(args=None):
@ -239,16 +262,9 @@ def main(args=None):
parser.add_option('-d', '--dev-version', dest='dev_version', action='store_true', parser.add_option('-d', '--dev-version', dest='dev_version', action='store_true',
help='Ignore the version file and pull the version directly from Bazaar') 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('-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')
# Parse command line options and deal with them. # Parse command line options and deal with them.
# Use args supplied programatically if possible. # Use args supplied programatically if possible.
(options, args) = parser.parse_args(args) if args else parser.parse_args() (options, args) = parser.parse_args(args) if args else parser.parse_args()
if options.portable:
app_path = AppLocation.get_directory(AppLocation.AppDir)
set_up_logging(os.path.abspath(os.path.join(app_path, u'..', u'..', u'Other')))
log.info(u'Running portable')
else:
set_up_logging(AppLocation.get_directory(AppLocation.CacheDir))
qt_args = [] qt_args = []
if options.loglevel.lower() in ['d', 'debug']: if options.loglevel.lower() in ['d', 'debug']:
log.setLevel(logging.DEBUG) log.setLevel(logging.DEBUG)
@ -266,54 +282,52 @@ def main(args=None):
# Initialise the resources # Initialise the resources
qInitResources() qInitResources()
# Now create and actually run the application. # Now create and actually run the application.
app = OpenLP(qt_args) application = OpenLP(qt_args)
app.setOrganizationName(u'OpenLP') application.setOrganizationName(u'OpenLP')
app.setOrganizationDomain(u'openlp.org') application.setOrganizationDomain(u'openlp.org')
if options.portable: if options.portable:
app.setApplicationName(u'OpenLPPortable') application.setApplicationName(u'OpenLPPortable')
Settings.setDefaultFormat(Settings.IniFormat) Settings.setDefaultFormat(Settings.IniFormat)
# Get location OpenLPPortable.ini # Get location OpenLPPortable.ini
portable_settings_file = os.path.abspath(os.path.join(app_path, u'..', u'..', u'Data', u'OpenLP.ini')) application_path = AppLocation.get_directory(AppLocation.AppDir)
set_up_logging(os.path.abspath(os.path.join(application_path, u'..', u'..', u'Other')))
log.info(u'Running portable')
portable_settings_file = os.path.abspath(os.path.join(application_path, u'..', u'..', u'Data', u'OpenLP.ini'))
# Make this our settings file # Make this our settings file
log.info(u'INI file: %s', portable_settings_file) log.info(u'INI file: %s', portable_settings_file)
Settings.setFilename(portable_settings_file) Settings.set_filename(portable_settings_file)
portable_settings = Settings() portable_settings = Settings()
# Set our data path # Set our data path
data_path = os.path.abspath(os.path.join(app_path, data_path = os.path.abspath(os.path.join(application_path, u'..', u'..', u'Data',))
u'..', u'..', u'Data',))
log.info(u'Data path: %s', data_path) log.info(u'Data path: %s', data_path)
# Point to our data path # Point to our data path
portable_settings.setValue(u'advanced/data path', data_path) portable_settings.setValue(u'advanced/data path', data_path)
portable_settings.setValue(u'advanced/is portable', True) portable_settings.setValue(u'advanced/is portable', True)
portable_settings.sync() portable_settings.sync()
else: else:
app.setApplicationName(u'OpenLP') application.setApplicationName(u'OpenLP')
app.setApplicationVersion(get_application_version()[u'version']) set_up_logging(AppLocation.get_directory(AppLocation.CacheDir))
Registry.create()
Registry().register(u'application', application)
application.setApplicationVersion(get_application_version()[u'version'])
# Instance check # Instance check
if not options.testing: if application.is_already_running():
# Instance check sys.exit()
if app.isAlreadyRunning():
sys.exit()
# First time checks in settings # First time checks in settings
if not Settings().value(u'general/has run wizard', False): if not Settings().value(u'general/has run wizard'):
if not FirstTimeLanguageForm().exec_(): if not FirstTimeLanguageForm().exec_():
# if cancel then stop processing # if cancel then stop processing
sys.exit() sys.exit()
# i18n Set Language # i18n Set Language
language = LanguageManager.get_language() language = LanguageManager.get_language()
app_translator, default_translator = LanguageManager.get_translator(language) application_translator, default_translator = LanguageManager.get_translator(language)
if not app_translator.isEmpty(): if not application_translator.isEmpty():
app.installTranslator(app_translator) application.installTranslator(application_translator)
if not default_translator.isEmpty(): if not default_translator.isEmpty():
app.installTranslator(default_translator) application.installTranslator(default_translator)
else: else:
log.debug(u'Could not find default_translator.') log.debug(u'Could not find default_translator.')
if not options.no_error_form: if not options.no_error_form:
sys.excepthook = app.hookException sys.excepthook = application.hook_exception
# Do not run method app.exec_() when running gui tests sys.exit(application.run(qt_args))
if options.testing:
app.run(qt_args, testing=True)
# For gui tests we need access to window instances and their components
return app
else:
sys.exit(app.run(qt_args))

View File

@ -90,86 +90,8 @@ class ServiceItemAction(object):
Next = 3 Next = 3
class Settings(QtCore.QSettings): def translate(context, text, comment=None, encoding=QtCore.QCoreApplication.CodecForTr, n=-1,
""" translate=QtCore.QCoreApplication.translate):
Class to wrap QSettings.
* Exposes all the methods of QSettings.
* Adds functionality for OpenLP Portable. If the ``defaultFormat`` is set to
``IniFormat``, and the path to the Ini file is set using ``setFilename``,
then the Settings constructor (without any arguments) will create a Settings
object for accessing settings stored in that Ini file.
"""
__filePath__ = u''
@staticmethod
def setFilename(iniFile):
"""
Sets the complete path to an Ini file to be used by Settings objects.
Does not affect existing Settings objects.
"""
Settings.__filePath__ = iniFile
def __init__(self, *args):
if not args and Settings.__filePath__ and \
Settings.defaultFormat() == Settings.IniFormat:
QtCore.QSettings.__init__(self, Settings.__filePath__, Settings.IniFormat)
else:
QtCore.QSettings.__init__(self, *args)
def value(self, key, defaultValue):
"""
Returns the value for the given ``key``. The returned ``value`` is
of the same type as the ``defaultValue``.
``key``
The key to return the value from.
``defaultValue``
The value to be returned if the given ``key`` is not present in the
config. Note, the ``defaultValue``'s type defines the type the
returned is converted to. In other words, if the ``defaultValue`` is
a boolean, then the returned value will be converted to a boolean.
**Note**, this method only converts a few types and might need to be
extended if a certain type is missing!
"""
# Check for none as u'' is passed as default and is valid! This is
# needed because the settings export does not know the default values,
# thus just passes None.
if defaultValue is None and not super(Settings, self).contains(key):
return None
setting = super(Settings, self).value(key, defaultValue)
# On OS X (and probably on other platforms too) empty value from QSettings
# is represented as type PyQt4.QtCore.QPyNullVariant. This type has to be
# converted to proper 'None' Python type.
if isinstance(setting, QtCore.QPyNullVariant) and setting.isNull():
setting = None
# Handle 'None' type (empty value) properly.
if setting is None:
# An empty string saved to the settings results in a None type being
# returned. Convert it to empty unicode string.
if isinstance(defaultValue, unicode):
return u''
# An empty list saved to the settings results in a None type being
# returned.
else:
return []
# Convert the setting to the correct type.
if isinstance(defaultValue, bool):
if isinstance(setting, bool):
return setting
# Sometimes setting is string instead of a boolean.
return setting == u'true'
if isinstance(defaultValue, int):
return int(setting)
return setting
def translate(context, text, comment=None,
encoding=QtCore.QCoreApplication.CodecForTr, n=-1,
translate=QtCore.QCoreApplication.translate):
""" """
A special shortcut method to wrap around the Qt4 translation functions. A special shortcut method to wrap around the Qt4 translation functions.
This abstracts the translation procedure so that we can change it if at a This abstracts the translation procedure so that we can change it if at a
@ -415,17 +337,21 @@ def expand_tags(text):
return text return text
def check_directory_exists(dir): def check_directory_exists(directory, do_not_log=False):
""" """
Check a theme directory exists and if not create it Check a theme directory exists and if not create it
``dir`` ``directory``
Theme directory to make sure exists The directory to make sure exists
``do_not_log``
To not log anything. This is need for the start up, when the log isn't ready.
""" """
log.debug(u'check_directory_exists %s' % dir) if not do_not_log:
log.debug(u'check_directory_exists %s' % directory)
try: try:
if not os.path.exists(dir): if not os.path.exists(directory):
os.makedirs(dir) os.makedirs(directory)
except IOError: except IOError:
pass pass
@ -459,7 +385,11 @@ def create_separated_list(stringlist):
u'Locale list separator: start') % (stringlist[0], merged) u'Locale list separator: start') % (stringlist[0], merged)
from registry import Registry
from uistrings import UiStrings
from eventreceiver import Receiver from eventreceiver import Receiver
from screen import ScreenList
from settings import Settings
from listwidgetwithdnd import ListWidgetWithDnD from listwidgetwithdnd import ListWidgetWithDnD
from formattingtags import FormattingTags from formattingtags import FormattingTags
from spelltextedit import SpellTextEdit from spelltextedit import SpellTextEdit
@ -468,8 +398,7 @@ from plugin import PluginStatus, StringContent, Plugin
from pluginmanager import PluginManager from pluginmanager import PluginManager
from settingstab import SettingsTab from settingstab import SettingsTab
from serviceitem import ServiceItem, ServiceItemType, ItemCapabilities from serviceitem import ServiceItem, ServiceItemType, ItemCapabilities
from htmlbuilder import build_html, build_lyrics_format_css, \ from htmlbuilder import build_html, build_lyrics_format_css, build_lyrics_outline_css
build_lyrics_outline_css
from toolbar import OpenLPToolbar from toolbar import OpenLPToolbar
from dockwidget import OpenLPDockWidget from dockwidget import OpenLPDockWidget
from imagemanager import ImageManager from imagemanager import ImageManager

View File

@ -34,7 +34,6 @@ import logging
import os import os
from urllib import quote_plus as urlquote from urllib import quote_plus as urlquote
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, OperationalError from sqlalchemy.exc import SQLAlchemyError, InvalidRequestError, DBAPIError, OperationalError
from sqlalchemy.orm import scoped_session, sessionmaker, mapper from sqlalchemy.orm import scoped_session, sessionmaker, mapper
@ -46,6 +45,7 @@ from openlp.core.utils import AppLocation, delete_file
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def init_db(url, auto_flush=True, auto_commit=False): def init_db(url, auto_flush=True, auto_commit=False):
""" """
Initialise and return the session and metadata for a database Initialise and return the session and metadata for a database
@ -61,8 +61,7 @@ def init_db(url, auto_flush=True, auto_commit=False):
""" """
engine = create_engine(url, poolclass=NullPool) engine = create_engine(url, poolclass=NullPool)
metadata = MetaData(bind=engine) metadata = MetaData(bind=engine)
session = scoped_session(sessionmaker(autoflush=auto_flush, session = scoped_session(sessionmaker(autoflush=auto_flush, autocommit=auto_commit, bind=engine))
autocommit=auto_commit, bind=engine))
return session, metadata return session, metadata
@ -110,17 +109,19 @@ def upgrade_db(url, upgrade):
while hasattr(upgrade, u'upgrade_%d' % version): while hasattr(upgrade, u'upgrade_%d' % version):
log.debug(u'Running upgrade_%d', version) log.debug(u'Running upgrade_%d', version)
try: try:
getattr(upgrade, u'upgrade_%d' % version) (session, metadata, tables) upgrade_func = getattr(upgrade, u'upgrade_%d' % version)
upgrade_func(session, metadata, tables)
session.commit()
# Update the version number AFTER a commit so that we are sure the previous transaction happened
version_meta.value = unicode(version)
session.commit()
version += 1
except (SQLAlchemyError, DBAPIError): except (SQLAlchemyError, DBAPIError):
log.exception(u'Could not run database upgrade script ' log.exception(u'Could not run database upgrade script '
'"upgrade_%s", upgrade process has been halted.', version) '"upgrade_%s", upgrade process has been halted.', version)
break break
version_meta.value = unicode(version)
session.commit()
version += 1
else: else:
version_meta = Metadata.populate(key=u'version', version_meta = Metadata.populate(key=u'version', value=int(upgrade.__version__))
value=int(upgrade.__version__))
session.commit() session.commit()
return int(version_meta.value), upgrade.__version__ return int(version_meta.value), upgrade.__version__
@ -158,6 +159,7 @@ class BaseModel(object):
instance.__setattr__(key, value) instance.__setattr__(key, value)
return instance return instance
class Manager(object): class Manager(object):
""" """
Provide generic object persistence management Provide generic object persistence management
@ -186,7 +188,7 @@ class Manager(object):
self.db_url = u'' self.db_url = u''
self.is_dirty = False self.is_dirty = False
self.session = None self.session = None
db_type = settings.value(u'db type', u'sqlite') db_type = settings.value(u'db type')
if db_type == u'sqlite': if db_type == u'sqlite':
if db_file_name: if db_file_name:
self.db_url = u'sqlite:///%s/%s' % (AppLocation.get_section_data_path(plugin_name), db_file_name) self.db_url = u'sqlite:///%s/%s' % (AppLocation.get_section_data_path(plugin_name), db_file_name)
@ -194,12 +196,12 @@ class Manager(object):
self.db_url = u'sqlite:///%s/%s.sqlite' % (AppLocation.get_section_data_path(plugin_name), plugin_name) self.db_url = u'sqlite:///%s/%s.sqlite' % (AppLocation.get_section_data_path(plugin_name), plugin_name)
else: else:
self.db_url = u'%s://%s:%s@%s/%s' % (db_type, self.db_url = u'%s://%s:%s@%s/%s' % (db_type,
urlquote(settings.value(u'db username', u'')), urlquote(settings.value(u'db username')),
urlquote(settings.value(u'db password', u'')), urlquote(settings.value(u'db password')),
urlquote(settings.value(u'db hostname', u'')), urlquote(settings.value(u'db hostname')),
urlquote(settings.value(u'db database', u''))) urlquote(settings.value(u'db database')))
if db_type == u'mysql': if db_type == u'mysql':
db_encoding = settings.value(u'db encoding', u'utf8') db_encoding = settings.value(u'db encoding')
self.db_url += u'?charset=%s' % urlquote(db_encoding) self.db_url += u'?charset=%s' % urlquote(db_encoding)
settings.endGroup() settings.endGroup()
if upgrade_mod: if upgrade_mod:
@ -207,19 +209,17 @@ class Manager(object):
if db_ver > up_ver: if db_ver > up_ver:
critical_error_message_box( critical_error_message_box(
translate('OpenLP.Manager', 'Database Error'), translate('OpenLP.Manager', 'Database Error'),
translate('OpenLP.Manager', 'The database being ' translate('OpenLP.Manager', 'The database being loaded was created in a more recent version of '
'loaded was created in a more recent version of ' 'OpenLP. The database is version %d, while OpenLP expects version %d. The database will not '
'OpenLP. The database is version %d, while OpenLP ' 'be loaded.\n\nDatabase: %s') % (db_ver, up_ver, self.db_url)
'expects version %d. The database will not be loaded.'
'\n\nDatabase: %s') % \
(db_ver, up_ver, self.db_url)
) )
return return
try: try:
self.session = init_schema(self.db_url) self.session = init_schema(self.db_url)
except (SQLAlchemyError, DBAPIError): except (SQLAlchemyError, DBAPIError):
log.exception(u'Error loading database: %s', self.db_url) log.exception(u'Error loading database: %s', self.db_url)
critical_error_message_box(translate('OpenLP.Manager', 'Database Error'), critical_error_message_box(
translate('OpenLP.Manager', 'Database Error'),
translate('OpenLP.Manager', 'OpenLP cannot load your database.\n\nDatabase: %s') % self.db_url translate('OpenLP.Manager', 'OpenLP cannot load your database.\n\nDatabase: %s') % self.db_url
) )

View File

@ -35,11 +35,11 @@ import logging
from PyQt4 import QtGui from PyQt4 import QtGui
from openlp.core.lib import build_icon from openlp.core.lib import ScreenList, build_icon
from openlp.core.ui import ScreenList
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class OpenLPDockWidget(QtGui.QDockWidget): class OpenLPDockWidget(QtGui.QDockWidget):
""" """
Custom DockWidget class to handle events Custom DockWidget class to handle events

View File

@ -35,6 +35,7 @@ from PyQt4 import QtCore
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class EventReceiver(QtCore.QObject): class EventReceiver(QtCore.QObject):
""" """
Class to allow events to be passed from different parts of the system. This Class to allow events to be passed from different parts of the system. This
@ -46,24 +47,12 @@ class EventReceiver(QtCore.QObject):
``mainwindow_status_text`` ``mainwindow_status_text``
Changes the bottom status bar text on the mainwindow. Changes the bottom status bar text on the mainwindow.
``openlp_warning_message``
Displays a standalone Warning Message.
``openlp_error_message`` ``openlp_error_message``
Displays a standalone Error Message. Displays a standalone Error Message.
``openlp_information_message`` ``openlp_information_message``
Displays a standalone Information Message. Displays a standalone Information Message.
``cursor_busy``
Makes the cursor got to a busy form.
``cursor_normal``
Resets the cursor to default.
``openlp_process_events``
Requests the Application to flush the events queue.
``openlp_version_check`` ``openlp_version_check``
Version has changed so pop up window. Version has changed so pop up window.
@ -120,29 +109,6 @@ class EventReceiver(QtCore.QObject):
``slidecontroller_live_stop_loop`` ``slidecontroller_live_stop_loop``
Stop the loop on the main display. Stop the loop on the main display.
**Servicemanager related signals**
``servicemanager_new_service``
A new service is being loaded or created.
``servicemanager_previous_item``
Display the previous item in the service.
``servicemanager_preview_live``
Requests a Preview item from the Service Manager to update live and add
a new item to the preview panel.
``servicemanager_next_item``
Display the next item in the service.
``servicemanager_set_item``
Go live on a specific item, by index.
``service_item_update``
Passes back to the service manager the service item after it has been
processed by the plugin.
**Display signals** **Display signals**
``update_display_css`` ``update_display_css``
@ -200,12 +166,6 @@ class EventReceiver(QtCore.QObject):
``{plugin}_unblank`` ``{plugin}_unblank``
Requests a plugin to handle an unblank screen event. Requests a plugin to handle an unblank screen event.
``{plugin}_edit``
Requests a plugin edit a database item with the key as the payload.
``{plugin}_edit_clear``
Editing has been completed.
``{plugin}_load_list`` ``{plugin}_load_list``
Tells the the plugin to reload the media manager list. Tells the the plugin to reload the media manager list.

View File

@ -31,9 +31,8 @@ Provide HTML Tag management and Formatting Tag access class
""" """
import cPickle import cPickle
from PyQt4 import QtCore from openlp.core.lib import Settings, translate
from openlp.core.lib import translate, Settings
class FormattingTags(object): class FormattingTags(object):
""" """
@ -164,7 +163,7 @@ class FormattingTags(object):
FormattingTags.add_html_tags(temporary_tags) FormattingTags.add_html_tags(temporary_tags)
# Formatting Tags were also known as display tags. # Formatting Tags were also known as display tags.
user_expands = Settings().value(u'displayTags/html_tags', u'') user_expands = Settings().value(u'displayTags/html_tags')
# cPickle only accepts str not unicode strings # cPickle only accepts str not unicode strings
user_expands_string = str(user_expands) user_expands_string = str(user_expands)
if user_expands_string: if user_expands_string:

View File

@ -207,8 +207,8 @@ sup {
</html> </html>
""" """
def build_html(item, screen, islive, background, image=None,
plugins=None): def build_html(item, screen, is_live, background, image=None, plugins=None):
""" """
Build the full web paged structure for display Build the full web paged structure for display
@ -233,7 +233,7 @@ def build_html(item, screen, islive, background, image=None,
width = screen[u'size'].width() width = screen[u'size'].width()
height = screen[u'size'].height() height = screen[u'size'].height()
theme = item.themedata theme = item.themedata
webkitvers = webkit_version() webkit_ver = webkit_version()
# Image generated and poked in # Image generated and poked in
if background: if background:
bgimage_src = u'src="data:image/png;base64,%s"' % background bgimage_src = u'src="data:image/png;base64,%s"' % background
@ -253,28 +253,32 @@ def build_html(item, screen, islive, background, image=None,
css_additions += plugin.getDisplayCss() css_additions += plugin.getDisplayCss()
js_additions += plugin.getDisplayJavaScript() js_additions += plugin.getDisplayJavaScript()
html_additions += plugin.getDisplayHtml() html_additions += plugin.getDisplayHtml()
html = HTMLSRC % (build_background_css(item, width, height), html = HTMLSRC % (
build_background_css(item, width, height),
css_additions, css_additions,
build_footer_css(item, height), build_footer_css(item, height),
build_lyrics_css(item, webkitvers), build_lyrics_css(item, webkit_ver),
u'true' if theme and theme.display_slide_transition and islive else u'false', u'true' if theme and theme.display_slide_transition and is_live else u'false',
js_additions, js_additions,
bgimage_src, image_src, bgimage_src, image_src,
html_additions, html_additions,
build_lyrics_html(item, webkitvers)) build_lyrics_html(item, webkit_ver)
)
return html return html
def webkit_version(): def webkit_version():
""" """
Return the Webkit version in use. Return the Webkit version in use.
Note method added relatively recently, so return 0 if prior to this Note method added relatively recently, so return 0 if prior to this
""" """
try: try:
webkitvers = float(QtWebKit.qWebKitVersion()) webkit_ver = float(QtWebKit.qWebKitVersion())
log.debug(u'Webkit version = %s' % webkitvers) log.debug(u'Webkit version = %s' % webkit_ver)
except AttributeError: except AttributeError:
webkitvers = 0 webkit_ver = 0
return webkitvers return webkit_ver
def build_background_css(item, width, height): def build_background_css(item, width, height):
""" """
@ -310,7 +314,8 @@ def build_background_css(item, width, height):
% (width, width, width, theme.background_start_color, theme.background_end_color) % (width, width, width, theme.background_start_color, theme.background_end_color)
return background return background
def build_lyrics_css(item, webkitvers):
def build_lyrics_css(item, webkit_ver):
""" """
Build the lyrics display css Build the lyrics display css
@ -367,12 +372,12 @@ def build_lyrics_css(item, webkitvers):
# Up to 534.3 the text-shadow didn't get displayed when # Up to 534.3 the text-shadow didn't get displayed when
# webkit-text-stroke was used. So use an offset text layer underneath. # webkit-text-stroke was used. So use an offset text layer underneath.
# https://bugs.webkit.org/show_bug.cgi?id=19728 # https://bugs.webkit.org/show_bug.cgi?id=19728
if webkitvers >= 533.3: if webkit_ver >= 533.3:
lyricsmain += build_lyrics_outline_css(theme) lyricsmain += build_lyrics_outline_css(theme)
else: else:
outline = build_lyrics_outline_css(theme) outline = build_lyrics_outline_css(theme)
if theme.font_main_shadow: if theme.font_main_shadow:
if theme.font_main_outline and webkitvers <= 534.3: if theme.font_main_outline and webkit_ver <= 534.3:
shadow = u'padding-left: %spx; padding-top: %spx;' % \ shadow = u'padding-left: %spx; padding-top: %spx;' % \
(int(theme.font_main_shadow_size) + (int(theme.font_main_outline_size) * 2), (int(theme.font_main_shadow_size) + (int(theme.font_main_outline_size) * 2),
theme.font_main_shadow_size) theme.font_main_shadow_size)
@ -384,6 +389,7 @@ def build_lyrics_css(item, webkitvers):
lyrics_css = style % (lyricstable, lyrics, lyricsmain, outline, shadow) lyrics_css = style % (lyricstable, lyrics, lyricsmain, outline, shadow)
return lyrics_css return lyrics_css
def build_lyrics_outline_css(theme, is_shadow=False): def build_lyrics_outline_css(theme, is_shadow=False):
""" """
Build the css which controls the theme outline Build the css which controls the theme outline
@ -407,6 +413,7 @@ def build_lyrics_outline_css(theme, is_shadow=False):
else: else:
return u'' return u''
def build_lyrics_format_css(theme, width, height): def build_lyrics_format_css(theme, width, height):
""" """
Build the css which controls the theme format Build the css which controls the theme format
@ -451,6 +458,7 @@ def build_lyrics_format_css(theme, width, height):
lyrics += u' font-weight:bold; ' lyrics += u' font-weight:bold; '
return lyrics return lyrics
def build_lyrics_html(item, webkitvers): def build_lyrics_html(item, webkitvers):
""" """
Build the HTML required to show the lyrics Build the HTML required to show the lyrics
@ -480,6 +488,7 @@ def build_lyrics_html(item, webkitvers):
u'class="lyricscell lyricsmain"></div></div>' u'class="lyricscell lyricsmain"></div></div>'
return lyrics return lyrics
def build_footer_css(item, height): def build_footer_css(item, height):
""" """
Build the display of the item footer Build the display of the item footer

View File

@ -39,25 +39,31 @@ import Queue
from PyQt4 import QtCore from PyQt4 import QtCore
from openlp.core.lib import resize_image, image_to_byte, Receiver from openlp.core.lib import Receiver, Registry, ScreenList, resize_image, image_to_byte
from openlp.core.ui import ScreenList
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class ImageThread(QtCore.QThread): class ImageThread(QtCore.QThread):
""" """
A special Qt thread class to speed up the display of images. This is A special Qt thread class to speed up the display of images. This is
threaded so it loads the frames and generates byte stream in background. threaded so it loads the frames and generates byte stream in background.
""" """
def __init__(self, manager): def __init__(self, manager):
"""
Constructor for the thread class.
``manager``
The image manager.
"""
QtCore.QThread.__init__(self, None) QtCore.QThread.__init__(self, None)
self.imageManager = manager self.image_manager = manager
def run(self): def run(self):
""" """
Run the thread. Run the thread.
""" """
self.imageManager._process() self.image_manager._process()
class Priority(object): class Priority(object):
@ -182,71 +188,75 @@ class ImageManager(QtCore.QObject):
log.info(u'Image Manager loaded') log.info(u'Image Manager loaded')
def __init__(self): def __init__(self):
"""
Constructor for the image manager.
"""
QtCore.QObject.__init__(self) QtCore.QObject.__init__(self)
currentScreen = ScreenList().current Registry().register(u'image_manager', self)
self.width = currentScreen[u'size'].width() current_screen = ScreenList().current
self.height = currentScreen[u'size'].height() self.width = current_screen[u'size'].width()
self.height = current_screen[u'size'].height()
self._cache = {} self._cache = {}
self.imageThread = ImageThread(self) self.image_thread = ImageThread(self)
self._conversionQueue = PriorityQueue() self._conversion_queue = PriorityQueue()
self.stopManager = False self.stop_manager = False
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_updated'), self.processUpdates) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_updated'), self.process_updates)
def updateDisplay(self): def update_display(self):
""" """
Screen has changed size so rebuild the cache to new size. Screen has changed size so rebuild the cache to new size.
""" """
log.debug(u'updateDisplay') log.debug(u'update_display')
currentScreen = ScreenList().current current_screen = ScreenList().current
self.width = currentScreen[u'size'].width() self.width = current_screen[u'size'].width()
self.height = currentScreen[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 image in self._cache.values(): for image in self._cache.values():
self._resetImage(image) self._reset_image(image)
def updateImagesBorder(self, source, background): def update_images_border(self, source, background):
""" """
Border has changed so update all the images affected. Border has changed so update all the images affected.
""" """
log.debug(u'updateImages') log.debug(u'update_images_border')
# 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 image in self._cache.values(): for image in self._cache.values():
if image.source == source: if image.source == source:
image.background = background image.background = background
self._resetImage(image) self._reset_image(image)
def updateImageBorder(self, path, source, background): def update_image_border(self, path, source, background):
""" """
Border has changed so update the image affected. Border has changed so update the image affected.
""" """
log.debug(u'updateImage') log.debug(u'update_image_border')
# Mark the image as dirty for a rebuild by setting the image and byte # Mark the image as dirty for a rebuild by setting the image and byte
# stream to None. # stream to None.
image = self._cache[(path, source)] image = self._cache[(path, source)]
if image.source == source: if image.source == source:
image.background = background image.background = background
self._resetImage(image) self._reset_image(image)
def _resetImage(self, image): def _reset_image(self, image):
""" """
Mark the given :class:`Image` instance as dirty by setting its ``image`` Mark the given :class:`Image` instance as dirty by setting its ``image``
and ``image_bytes`` attributes to None. and ``image_bytes`` attributes to None.
""" """
image.image = None image.image = None
image.image_bytes = None image.image_bytes = None
self._conversionQueue.modify_priority(image, Priority.Normal) self._conversion_queue.modify_priority(image, Priority.Normal)
def processUpdates(self): def process_updates(self):
""" """
Flush the queue to updated any data to update Flush the queue to updated any data to update
""" """
# We want only one thread. # We want only one thread.
if not self.imageThread.isRunning(): if not self.image_thread.isRunning():
self.imageThread.start() self.image_thread.start()
def getImage(self, path, source): def get_image(self, path, source):
""" """
Return the ``QImage`` from the cache. If not present wait for the Return the ``QImage`` from the cache. If not present wait for the
background thread to process it. background thread to process it.
@ -254,9 +264,9 @@ class ImageManager(QtCore.QObject):
log.debug(u'getImage %s' % path) log.debug(u'getImage %s' % path)
image = self._cache[(path, source)] image = self._cache[(path, source)]
if image.image is None: if image.image is None:
self._conversionQueue.modify_priority(image, Priority.High) self._conversion_queue.modify_priority(image, Priority.High)
# make sure we are running and if not give it a kick # make sure we are running and if not give it a kick
self.processUpdates() self.process_updates()
while image.image is None: while image.image is None:
log.debug(u'getImage - waiting') log.debug(u'getImage - waiting')
time.sleep(0.1) time.sleep(0.1)
@ -265,74 +275,74 @@ class ImageManager(QtCore.QObject):
# byte stream was not generated yet. However, we only need to do # byte stream was not generated yet. However, we only need to do
# this, when the image was generated before it was requested # this, when the image was generated before it was requested
# (otherwise this is already taken care of). # (otherwise this is already taken care of).
self._conversionQueue.modify_priority(image, Priority.Low) self._conversion_queue.modify_priority(image, Priority.Low)
return image.image return image.image
def getImageBytes(self, path, source): def get_image_bytes(self, path, source):
""" """
Returns the byte string for an image. If not present wait for the Returns the byte string for an image. If not present wait for the
background thread to process it. background thread to process it.
""" """
log.debug(u'getImageBytes %s' % path) log.debug(u'get_image_bytes %s' % path)
image = self._cache[(path, source)] image = self._cache[(path, source)]
if image.image_bytes is None: if image.image_bytes is None:
self._conversionQueue.modify_priority(image, Priority.Urgent) self._conversion_queue.modify_priority(image, Priority.Urgent)
# make sure we are running and if not give it a kick # make sure we are running and if not give it a kick
self.processUpdates() self.process_updates()
while image.image_bytes is None: while image.image_bytes is None:
log.debug(u'getImageBytes - waiting') log.debug(u'getImageBytes - waiting')
time.sleep(0.1) time.sleep(0.1)
return image.image_bytes return image.image_bytes
def addImage(self, path, source, background): def add_image(self, path, source, background):
""" """
Add image to cache if it is not already there. Add image to cache if it is not already there.
""" """
log.debug(u'addImage %s' % path) log.debug(u'add_image %s' % path)
if not (path, source) in self._cache: if not (path, source) in self._cache:
image = Image(path, source, background) image = Image(path, source, background)
self._cache[(path, source)] = image self._cache[(path, source)] = image
self._conversionQueue.put((image.priority, image.secondary_priority, image)) self._conversion_queue.put((image.priority, image.secondary_priority, image))
# Check if the there are any images with the same path and check if the # Check if the there are any images with the same path and check if the
# timestamp has changed. # timestamp has changed.
for image in self._cache.values(): for image in self._cache.values():
if os.path.exists(path): if os.path.exists(path):
if image.path == path and image.timestamp != os.stat(path).st_mtime: if image.path == path and image.timestamp != os.stat(path).st_mtime:
image.timestamp = os.stat(path).st_mtime image.timestamp = os.stat(path).st_mtime
self._resetImage(image) self._reset_image(image)
# We want only one thread. # We want only one thread.
if not self.imageThread.isRunning(): if not self.image_thread.isRunning():
self.imageThread.start() self.image_thread.start()
def _process(self): def _process(self):
""" """
Controls the processing called from a ``QtCore.QThread``. Controls the processing called from a ``QtCore.QThread``.
""" """
log.debug(u'_process - started') log.debug(u'_process - started')
while not self._conversionQueue.empty() and not self.stopManager: while not self._conversion_queue.empty() and not self.stop_manager:
self._processCache() self._process_cache()
log.debug(u'_process - ended') log.debug(u'_process - ended')
def _processCache(self): def _process_cache(self):
""" """
Actually does the work. Actually does the work.
""" """
log.debug(u'_processCache') log.debug(u'_processCache')
image = self._conversionQueue.get()[2] image = self._conversion_queue.get()[2]
# Generate the QImage for the image. # Generate the QImage for the image.
if image.image is None: if image.image is None:
image.image = resize_image(image.path, self.width, self.height, image.background) image.image = resize_image(image.path, self.width, self.height, image.background)
# Set the priority to Lowest and stop here as we need to process # Set the priority to Lowest and stop here as we need to process
# more important images first. # more important images first.
if image.priority == Priority.Normal: if image.priority == Priority.Normal:
self._conversionQueue.modify_priority(image, Priority.Lowest) self._conversion_queue.modify_priority(image, Priority.Lowest)
return return
# For image with high priority we set the priority to Low, as the # For image with high priority we set the priority to Low, as the
# byte stream might be needed earlier the byte stream of image with # byte stream might be needed earlier the byte stream of image with
# Normal priority. We stop here as we need to process more important # Normal priority. We stop here as we need to process more important
# images first. # images first.
elif image.priority == Priority.High: elif image.priority == Priority.High:
self._conversionQueue.modify_priority(image, Priority.Low) self._conversion_queue.modify_priority(image, Priority.Low)
return return
# Generate the byte stream for the image. # Generate the byte stream for the image.
if image.image_bytes is None: if image.image_bytes is None:

View File

@ -35,6 +35,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver from openlp.core.lib import Receiver
class ListWidgetWithDnD(QtGui.QListWidget): class ListWidgetWithDnD(QtGui.QListWidget):
""" """
Provide a list widget to store objects and handle drag and drop events Provide a list widget to store objects and handle drag and drop events
@ -58,9 +59,8 @@ class ListWidgetWithDnD(QtGui.QListWidget):
def mouseMoveEvent(self, event): def mouseMoveEvent(self, event):
""" """
Drag and drop event does not care what data is selected Drag and drop event does not care what data is selected as the recipient will use events to request the data
as the recipient will use events to request the data move move just tell it what plugin to call
just tell it what plugin to call
""" """
if event.buttons() != QtCore.Qt.LeftButton: if event.buttons() != QtCore.Qt.LeftButton:
event.ignore() event.ignore()
@ -75,12 +75,18 @@ class ListWidgetWithDnD(QtGui.QListWidget):
drag.start(QtCore.Qt.CopyAction) drag.start(QtCore.Qt.CopyAction)
def dragEnterEvent(self, event): def dragEnterEvent(self, event):
"""
When something is dragged into this object, check if you should be able to drop it in here.
"""
if event.mimeData().hasUrls(): if event.mimeData().hasUrls():
event.accept() event.accept()
else: else:
event.ignore() event.ignore()
def dragMoveEvent(self, event): def dragMoveEvent(self, event):
"""
Make an object droppable, and set it to copy the contents of the object, not move it.
"""
if event.mimeData().hasUrls(): if event.mimeData().hasUrls():
event.setDropAction(QtCore.Qt.CopyAction) event.setDropAction(QtCore.Qt.CopyAction)
event.accept() event.accept()

View File

@ -35,13 +35,14 @@ import re
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import SettingsManager, OpenLPToolbar, ServiceItem, StringContent, build_icon, translate, \ from openlp.core.lib import OpenLPToolbar, ServiceItem, StringContent, Receiver, ListWidgetWithDnD, \
Receiver, ListWidgetWithDnD, ServiceItemContext, Settings ServiceItemContext, Settings, Registry, UiStrings, build_icon, translate
from openlp.core.lib.searchedit import SearchEdit from openlp.core.lib.searchedit import SearchEdit
from openlp.core.lib.ui import UiStrings, create_widget_action, critical_error_message_box from openlp.core.lib.ui import create_widget_action, critical_error_message_box
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class MediaManagerItem(QtGui.QWidget): class MediaManagerItem(QtGui.QWidget):
""" """
MediaManagerItem is a helper widget for plugins. MediaManagerItem is a helper widget for plugins.
@ -98,6 +99,7 @@ class MediaManagerItem(QtGui.QWidget):
self.plugin = plugin self.plugin = plugin
visible_title = self.plugin.getString(StringContent.VisibleName) visible_title = self.plugin.getString(StringContent.VisibleName)
self.title = unicode(visible_title[u'title']) self.title = unicode(visible_title[u'title'])
Registry().register(self.plugin.name, self)
self.settingsSection = self.plugin.name self.settingsSection = self.plugin.name
self.icon = None self.icon = None
if icon: if icon:
@ -327,32 +329,31 @@ class MediaManagerItem(QtGui.QWidget):
Add a file to the list widget to make it available for showing Add a file to the list widget to make it available for showing
""" """
files = QtGui.QFileDialog.getOpenFileNames(self, self.onNewPrompt, files = QtGui.QFileDialog.getOpenFileNames(self, self.onNewPrompt,
SettingsManager.get_last_dir(self.settingsSection), self.onNewFileMasks) Settings().value(self.settingsSection + u'/last directory'), self.onNewFileMasks)
log.info(u'New files(s) %s', files) log.info(u'New files(s) %s', files)
if files: if files:
Receiver.send_message(u'cursor_busy') self.application.set_busy_cursor()
self.validateAndLoad(files) self.validateAndLoad(files)
Receiver.send_message(u'cursor_normal') self.application.set_normal_cursor()
def loadFile(self, files): def loadFile(self, files):
""" """
Turn file from Drag and Drop into an array so the Validate code Turn file from Drag and Drop into an array so the Validate code can run it.
can run it.
``files`` ``files``
The list of files to be loaded The list of files to be loaded
""" """
new_files = [] new_files = []
error_shown = False error_shown = False
for file in files: for file_name in files:
type = file.split(u'.')[-1] file_type = file_name.split(u'.')[-1]
if type.lower() not in self.onNewFileMasks: if file_type.lower() not in self.onNewFileMasks:
if not error_shown: if not error_shown:
critical_error_message_box(translate('OpenLP.MediaManagerItem', 'Invalid File Type'), critical_error_message_box(translate('OpenLP.MediaManagerItem', 'Invalid File Type'),
translate('OpenLP.MediaManagerItem', 'Invalid File %s.\nSuffix not supported') % file) translate('OpenLP.MediaManagerItem', 'Invalid File %s.\nSuffix not supported') % file_name)
error_shown = True error_shown = True
else: else:
new_files.append(file) new_files.append(file_name)
if new_files: if new_files:
self.validateAndLoad(new_files) self.validateAndLoad(new_files)
@ -382,14 +383,16 @@ class MediaManagerItem(QtGui.QWidget):
self.listView.clear() self.listView.clear()
self.loadList(full_list) self.loadList(full_list)
last_dir = os.path.split(unicode(files[0]))[0] last_dir = os.path.split(unicode(files[0]))[0]
SettingsManager.set_last_dir(self.settingsSection, last_dir) Settings().setValue(self.settingsSection + u'/last directory', last_dir)
SettingsManager.set_list(self.settingsSection, Settings().setValue(u'%s/%s files' % (self.settingsSection, self.settingsSection), self.getFileList())
self.settingsSection, self.getFileList())
if duplicates_found: if duplicates_found:
critical_error_message_box(UiStrings().Duplicate, critical_error_message_box(UiStrings().Duplicate,
translate('OpenLP.MediaManagerItem', 'Duplicate files were found on import and were ignored.')) translate('OpenLP.MediaManagerItem', 'Duplicate files were found on import and were ignored.'))
def contextMenu(self, point): def contextMenu(self, point):
"""
Display a context menu
"""
item = self.listView.itemAt(point) item = self.listView.itemAt(point)
# Decide if we have to show the context menu or not. # Decide if we have to show the context menu or not.
if item is None: if item is None:
@ -412,6 +415,9 @@ class MediaManagerItem(QtGui.QWidget):
return file_list return file_list
def loadList(self, list): def loadList(self, list):
"""
Load a list. Needs to be implemented by the plugin.
"""
raise NotImplementedError(u'MediaManagerItem.loadList needs to be defined by the plugin') raise NotImplementedError(u'MediaManagerItem.loadList needs to be defined by the plugin')
def onNewClick(self): def onNewClick(self):
@ -427,6 +433,9 @@ class MediaManagerItem(QtGui.QWidget):
pass pass
def onDeleteClick(self): def onDeleteClick(self):
"""
Delete an item. Needs to be implemented by the plugin.
"""
raise NotImplementedError(u'MediaManagerItem.onDeleteClick needs to be defined by the plugin') raise NotImplementedError(u'MediaManagerItem.onDeleteClick needs to be defined by the plugin')
def onFocus(self): def onFocus(self):
@ -436,15 +445,18 @@ class MediaManagerItem(QtGui.QWidget):
""" """
pass pass
def generateSlideData(self, serviceItem, item=None, xmlVersion=False, def generateSlideData(self, serviceItem, item=None, xmlVersion=False, remote=False,
remote=False, context=ServiceItemContext.Live): context=ServiceItemContext.Live):
"""
Generate the slide data. Needs to be implemented by the plugin.
"""
raise NotImplementedError(u'MediaManagerItem.generateSlideData needs to be defined by the plugin') raise NotImplementedError(u'MediaManagerItem.generateSlideData needs to be defined by the plugin')
def onDoubleClicked(self): def onDoubleClicked(self):
""" """
Allows the list click action to be determined dynamically Allows the list click action to be determined dynamically
""" """
if Settings().value(u'advanced/double click live', False): if Settings().value(u'advanced/double click live'):
self.onLiveClick() self.onLiveClick()
else: else:
self.onPreviewClick() self.onPreviewClick()
@ -453,7 +465,7 @@ class MediaManagerItem(QtGui.QWidget):
""" """
Allows the change of current item in the list to be actioned Allows the change of current item in the list to be actioned
""" """
if Settings().value(u'advanced/single click preview', False) and self.quickPreviewAllowed \ if Settings().value(u'advanced/single click preview') and self.quickPreviewAllowed \
and self.listView.selectedIndexes() and self.autoSelectId == -1: and self.listView.selectedIndexes() and self.autoSelectId == -1:
self.onPreviewClick(True) self.onPreviewClick(True)
@ -470,7 +482,7 @@ class MediaManagerItem(QtGui.QWidget):
serviceItem = self.buildServiceItem() serviceItem = self.buildServiceItem()
if serviceItem: if serviceItem:
serviceItem.from_plugin = True serviceItem.from_plugin = True
self.plugin.previewController.addServiceItem(serviceItem) self.preview_controller.add_service_item(serviceItem)
if keepFocus: if keepFocus:
self.listView.setFocus() self.listView.setFocus()
@ -486,6 +498,9 @@ class MediaManagerItem(QtGui.QWidget):
self.goLive() self.goLive()
def goLive(self, item_id=None, remote=False): def goLive(self, item_id=None, remote=False):
"""
Make the currently selected item go live.
"""
log.debug(u'%s Live requested', self.plugin.name) log.debug(u'%s Live requested', self.plugin.name)
item = None item = None
if item_id: if item_id:
@ -496,9 +511,12 @@ class MediaManagerItem(QtGui.QWidget):
serviceItem.from_plugin = True serviceItem.from_plugin = True
if remote: if remote:
serviceItem.will_auto_start = True serviceItem.will_auto_start = True
self.plugin.liveController.addServiceItem(serviceItem) self.live_controller.add_service_item(serviceItem)
def createItemFromId(self, item_id): def createItemFromId(self, item_id):
"""
Create a media item from an item id.
"""
item = QtGui.QListWidgetItem() item = QtGui.QListWidgetItem()
item.setData(QtCore.Qt.UserRole, item_id) item.setData(QtCore.Qt.UserRole, item_id)
return item return item
@ -507,13 +525,13 @@ class MediaManagerItem(QtGui.QWidget):
""" """
Add a selected item to the current service Add a selected item to the current service
""" """
if not self.listView.selectedIndexes() and not self.remoteTriggered: if not self.listView.selectedIndexes():
QtGui.QMessageBox.information(self, UiStrings().NISp, QtGui.QMessageBox.information(self, UiStrings().NISp,
translate('OpenLP.MediaManagerItem', 'You must select one or more items to add.')) translate('OpenLP.MediaManagerItem', 'You must select one or more items to add.'))
else: else:
# Is it posssible to process multiple list items to generate # Is it possible to process multiple list items to generate
# multiple service items? # multiple service items?
if self.singleServiceItem or self.remoteTriggered: if self.singleServiceItem:
log.debug(u'%s Add requested', self.plugin.name) log.debug(u'%s Add requested', self.plugin.name)
self.addToService(replace=self.remoteTriggered) self.addToService(replace=self.remoteTriggered)
else: else:
@ -522,10 +540,13 @@ class MediaManagerItem(QtGui.QWidget):
self.addToService(item) self.addToService(item)
def addToService(self, item=None, replace=None, remote=False): def addToService(self, item=None, replace=None, remote=False):
"""
Add this item to the current service.
"""
serviceItem = self.buildServiceItem(item, True, remote=remote, context=ServiceItemContext.Service) serviceItem = self.buildServiceItem(item, True, remote=remote, context=ServiceItemContext.Service)
if serviceItem: if serviceItem:
serviceItem.from_plugin = False serviceItem.from_plugin = False
self.plugin.serviceManager.addServiceItem(serviceItem, replace=replace) self.service_manager.add_service_item(serviceItem, replace=replace)
def onAddEditClick(self): def onAddEditClick(self):
""" """
@ -536,13 +557,13 @@ class MediaManagerItem(QtGui.QWidget):
translate('OpenLP.MediaManagerItem', 'You must select one or more items.')) translate('OpenLP.MediaManagerItem', 'You must select one or more items.'))
else: else:
log.debug(u'%s Add requested', self.plugin.name) log.debug(u'%s Add requested', self.plugin.name)
serviceItem = self.plugin.serviceManager.getServiceItem() serviceItem = self.service_manager.get_service_item()
if not serviceItem: if not serviceItem:
QtGui.QMessageBox.information(self, UiStrings().NISs, QtGui.QMessageBox.information(self, UiStrings().NISs,
translate('OpenLP.MediaManagerItem', 'You must select an existing service item to add to.')) translate('OpenLP.MediaManagerItem', 'You must select an existing service item to add to.'))
elif self.plugin.name == serviceItem.name: elif self.plugin.name == serviceItem.name:
self.generateSlideData(serviceItem) self.generateSlideData(serviceItem)
self.plugin.serviceManager.addServiceItem(serviceItem, replace=True) self.service_manager.add_service_item(serviceItem, replace=True)
else: else:
# Turn off the remote edit update message indicator # Turn off the remote edit update message indicator
QtGui.QMessageBox.information(self, translate('OpenLP.MediaManagerItem', 'Invalid Service Item'), QtGui.QMessageBox.information(self, translate('OpenLP.MediaManagerItem', 'Invalid Service Item'),
@ -554,8 +575,7 @@ class MediaManagerItem(QtGui.QWidget):
""" """
serviceItem = ServiceItem(self.plugin) serviceItem = ServiceItem(self.plugin)
serviceItem.add_icon(self.plugin.iconPath) serviceItem.add_icon(self.plugin.iconPath)
if self.generateSlideData(serviceItem, item, xmlVersion, remote, if self.generateSlideData(serviceItem, item, xmlVersion, remote, context):
context):
return serviceItem return serviceItem
else: else:
return None return None
@ -618,3 +638,93 @@ class MediaManagerItem(QtGui.QWidget):
Performs a plugin specific search for items containing ``string`` Performs a plugin specific search for items containing ``string``
""" """
raise NotImplementedError(u'Plugin.search needs to be defined by the plugin') raise NotImplementedError(u'Plugin.search needs to be defined by the plugin')
def _get_main_window(self):
"""
Adds the main window to the class dynamically
"""
if not hasattr(self, u'_main_window'):
self._main_window = Registry().get(u'main_window')
return self._main_window
main_window = property(_get_main_window)
def _get_renderer(self):
"""
Adds the Renderer to the class dynamically
"""
if not hasattr(self, u'_renderer'):
self._renderer = Registry().get(u'renderer')
return self._renderer
renderer = property(_get_renderer)
def _get_live_controller(self):
"""
Adds the live controller to the class dynamically
"""
if not hasattr(self, u'_live_controller'):
self._live_controller = Registry().get(u'live_controller')
return self._live_controller
live_controller = property(_get_live_controller)
def _get_preview_controller(self):
"""
Adds the preview controller to the class dynamically
"""
if not hasattr(self, u'_preview_controller'):
self._preview_controller = Registry().get(u'preview_controller')
return self._preview_controller
preview_controller = property(_get_preview_controller)
def _get_plugin_manager(self):
"""
Adds the plugin manager to the class dynamically
"""
if not hasattr(self, u'_plugin_manager'):
self._plugin_manager = Registry().get(u'plugin_manager')
return self._plugin_manager
plugin_manager = property(_get_plugin_manager)
def _get_media_controller(self):
"""
Adds the media controller to the class dynamically
"""
if not hasattr(self, u'_media_controller'):
self._media_controller = Registry().get(u'media_controller')
return self._media_controller
media_controller = property(_get_media_controller)
def _get_service_manager(self):
"""
Adds the service manager to the class dynamically
"""
if not hasattr(self, u'_service_manager'):
self._service_manager = Registry().get(u'service_manager')
return self._service_manager
service_manager = property(_get_service_manager)
def _get_theme_manager(self):
"""
Adds the theme manager to the class dynamically
"""
if not hasattr(self, u'_theme_manager'):
self._theme_manager = Registry().get(u'theme_manager')
return self._theme_manager
theme_manager = property(_get_theme_manager)
def _get_application(self):
"""
Adds the openlp to the class dynamically
"""
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application)

View File

@ -33,12 +33,12 @@ import logging
from PyQt4 import QtCore from PyQt4 import QtCore
from openlp.core.lib import Receiver, Settings from openlp.core.lib import Receiver, Settings, Registry, UiStrings
from openlp.core.lib.ui import UiStrings
from openlp.core.utils import get_application_version from openlp.core.utils import get_application_version
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class PluginStatus(object): class PluginStatus(object):
""" """
Defines the status of the plugin Defines the status of the plugin
@ -119,8 +119,7 @@ class Plugin(QtCore.QObject):
""" """
log.info(u'loaded') log.info(u'loaded')
def __init__(self, name, plugin_helpers=None, media_item_class=None, def __init__(self, name, default_settings, media_item_class=None, settings_tab_class=None, version=None):
settings_tab_class=None, version=None):
""" """
This is the constructor for the plugin object. This provides an easy This is the constructor for the plugin object. This provides an easy
way for descendent plugins to populate common data. This method *must* way for descendent plugins to populate common data. This method *must*
@ -133,17 +132,17 @@ class Plugin(QtCore.QObject):
``name`` ``name``
Defaults to *None*. The name of the plugin. Defaults to *None*. The name of the plugin.
``version`` ``default_settings``
Defaults to *None*. The version of the plugin. A dict containing the plugin's settings. The value to each key is the default value to be used.
``plugin_helpers``
Defaults to *None*. A list of helper objects.
``media_item_class`` ``media_item_class``
The class name of the plugin's media item. The class name of the plugin's media item.
``settings_tab_class`` ``settings_tab_class``
The class name of the plugin's settings tab. The class name of the plugin's settings tab.
``version``
Defaults to *None*, which means that the same version number is used as OpenLP's version number.
""" """
log.debug(u'Plugin %s initialised' % name) log.debug(u'Plugin %s initialised' % name)
QtCore.QObject.__init__(self) QtCore.QObject.__init__(self)
@ -163,15 +162,15 @@ class Plugin(QtCore.QObject):
self.mediaItem = None self.mediaItem = None
self.weight = 0 self.weight = 0
self.status = PluginStatus.Inactive self.status = PluginStatus.Inactive
self.previewController = plugin_helpers[u'preview'] # Add the default status to the default settings.
self.liveController = plugin_helpers[u'live'] default_settings[name + u'/status'] = PluginStatus.Inactive
self.renderer = plugin_helpers[u'renderer'] default_settings[name + u'/last directory'] = u''
self.serviceManager = plugin_helpers[u'service'] # Append a setting for files in the mediamanager (note not all plugins
self.settingsForm = plugin_helpers[u'settings form'] # which have a mediamanager need this).
self.mediaDock = plugin_helpers[u'toolbox'] if media_item_class is not None:
self.pluginManager = plugin_helpers[u'pluginmanager'] default_settings[u'%s/%s files' % (name, name)] = []
self.formParent = plugin_helpers[u'formparent'] # Add settings to the dict of all settings.
self.mediaController = plugin_helpers[u'mediacontroller'] Settings.extend_default_settings(default_settings)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'%s_add_service_item' % self.name), QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'%s_add_service_item' % self.name),
self.processAddServiceEvent) self.processAddServiceEvent)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'%s_config_updated' % self.name), QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'%s_config_updated' % self.name),
@ -190,7 +189,7 @@ class Plugin(QtCore.QObject):
""" """
Sets the status of the plugin Sets the status of the plugin
""" """
self.status = Settings().value(self.settingsSection + u'/status', PluginStatus.Inactive) self.status = Settings().value(self.settingsSection + u'/status')
def toggleStatus(self, new_status): def toggleStatus(self, new_status):
""" """
@ -217,7 +216,7 @@ class Plugin(QtCore.QObject):
you need, and return it for integration into OpenLP. you need, and return it for integration into OpenLP.
""" """
if self.mediaItemClass: if self.mediaItemClass:
self.mediaItem = self.mediaItemClass(self.mediaDock.media_dock, self, self.icon) self.mediaItem = self.mediaItemClass(self.main_window.mediaDockManager.media_dock, self, self.icon)
def addImportMenuItem(self, importMenu): def addImportMenuItem(self, importMenu):
""" """
@ -287,20 +286,40 @@ class Plugin(QtCore.QObject):
""" """
if self.mediaItem: if self.mediaItem:
self.mediaItem.initialise() self.mediaItem.initialise()
self.mediaDock.insert_dock(self.mediaItem, self.icon, self.weight) self.main_window.mediaDockManager.insert_dock(self.mediaItem, self.icon, self.weight)
def finalise(self): def finalise(self):
""" """
Called by the plugin Manager to cleanup things. Called by the plugin Manager to cleanup things.
""" """
if self.mediaItem: if self.mediaItem:
self.mediaDock.remove_dock(self.mediaItem) self.main_window.mediaDockManager.remove_dock(self.mediaItem)
def appStartup(self): def app_startup(self):
""" """
Perform tasks on application startup Perform tasks on application startup
""" """
pass # FIXME: Remove after 2.2 release.
# This is needed to load the list of images/media/presentation from the config saved
# before the settings rewrite.
if self.mediaItemClass is not None:
# We need QSettings instead of Settings here to bypass our central settings dict.
# Do NOT do this anywhere else!
settings = QtCore.QSettings()
settings.beginGroup(self.settingsSection)
if settings.contains(u'%s count' % self.name):
list_count = int(settings.value(u'%s count' % self.name, 0))
loaded_list = []
if list_count:
for counter in range(list_count):
item = settings.value(u'%s %d' % (self.name, counter), u'')
if item:
loaded_list.append(item)
settings.remove(u'%s %d' % (self.name, counter))
settings.remove(u'%s count' % self.name)
# Now save the list to the config using our Settings class.
Settings().setValue(u'%s/%s files' % (self.settingsSection, self.name), loaded_list)
settings.endGroup()
def usesTheme(self, theme): def usesTheme(self, theme):
""" """
@ -389,3 +408,29 @@ class Plugin(QtCore.QObject):
The plugin's config has changed The plugin's config has changed
""" """
pass pass
def new_service_created(self):
"""
The plugin's needs to handle a new song creation
"""
pass
def _get_main_window(self):
"""
Adds the main window to the class dynamically
"""
if not hasattr(self, u'_main_window'):
self._main_window = Registry().get(u'main_window')
return self._main_window
main_window = property(_get_main_window)
def _get_application(self):
"""
Adds the openlp to the class dynamically
"""
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application)

View File

@ -33,23 +33,17 @@ import os
import sys import sys
import logging import logging
from openlp.core.lib import Plugin, PluginStatus from openlp.core.lib import Plugin, PluginStatus, Registry
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class PluginManager(object): class PluginManager(object):
""" """
This is the Plugin manager, which loads all the plugins, This is the Plugin manager, which loads all the plugins,
and executes all the hooks, as and when necessary. and executes all the hooks, as and when necessary.
""" """
log.info(u'Plugin manager loaded') log.info(u'Plugin manager loaded')
__instance__ = None
@staticmethod
def get_instance():
"""
Obtain a single instance of class.
"""
return PluginManager.__instance__
def __init__(self, plugin_dir): def __init__(self, plugin_dir):
""" """
@ -60,7 +54,7 @@ class PluginManager(object):
The directory to search for plugins. The directory to search for plugins.
""" """
log.info(u'Plugin manager Initialising') log.info(u'Plugin manager Initialising')
PluginManager.__instance__ = self Registry().register(u'plugin_manager', self)
if not plugin_dir in sys.path: if not plugin_dir in sys.path:
log.debug(u'Inserting %s into sys.path', plugin_dir) log.debug(u'Inserting %s into sys.path', plugin_dir)
sys.path.insert(0, plugin_dir) sys.path.insert(0, plugin_dir)
@ -69,7 +63,7 @@ class PluginManager(object):
self.plugins = [] self.plugins = []
log.info(u'Plugin manager Initialised') log.info(u'Plugin manager Initialised')
def find_plugins(self, plugin_dir, plugin_helpers): def find_plugins(self, plugin_dir):
""" """
Scan the directory ``plugin_dir`` for objects inheriting from the Scan the directory ``plugin_dir`` for objects inheriting from the
``Plugin`` class. ``Plugin`` class.
@ -77,9 +71,6 @@ class PluginManager(object):
``plugin_dir`` ``plugin_dir``
The directory to scan. The directory to scan.
``plugin_helpers``
A list of helper objects to pass to the plugins.
""" """
log.info(u'Finding plugins') log.info(u'Finding plugins')
startdepth = len(os.path.abspath(plugin_dir).split(os.sep)) startdepth = len(os.path.abspath(plugin_dir).split(os.sep))
@ -117,7 +108,7 @@ class PluginManager(object):
plugin_objects = [] plugin_objects = []
for p in plugin_classes: for p in plugin_classes:
try: try:
plugin = p(plugin_helpers) plugin = p()
log.debug(u'Loaded plugin %s', unicode(p)) log.debug(u'Loaded plugin %s', unicode(p))
plugin_objects.append(plugin) plugin_objects.append(plugin)
except TypeError: except TypeError:
@ -221,3 +212,13 @@ class PluginManager(object):
if plugin.name == name: if plugin.name == name:
return plugin return plugin
return None return None
def new_service_created(self):
"""
Loop through all the plugins and give them an opportunity to handle a new service
"""
log.info(u'plugins - new service created')
for plugin in self.plugins:
if plugin.isActive():
plugin.new_service_created()

View File

@ -0,0 +1,98 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2013 Raoul Snyman #
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
Provide Registry Services
"""
import logging
import sys
log = logging.getLogger(__name__)
class Registry(object):
"""
This is the Component Registry. It is a singleton object and is used to provide a
look up service for common objects.
"""
log.info(u'Registry loaded')
__instance__ = None
def __new__(cls):
"""
Re-implement the __new__ method to make sure we create a true singleton.
"""
if not cls.__instance__:
cls.__instance__ = object.__new__(cls)
return cls.__instance__
@classmethod
def create(cls):
"""
The constructor for the component registry providing a single registry of objects.
"""
log.info(u'Registry Initialising')
registry = cls()
registry.service_list = {}
registry.running_under_test = False
# Allow the tests to remove Registry entries but not the live system
if u'nosetest' in sys.argv[0]:
registry.running_under_test = True
return registry
def get(self, key):
"""
Extracts the registry value from the list based on the key passed in
"""
if key in self.service_list:
return self.service_list[key]
else:
log.error(u'Service %s not found in list' % key)
raise KeyError(u'Service %s not found in list' % key)
def register(self, key, reference):
"""
Registers a component against a key.
"""
if key in self.service_list:
log.error(u'Duplicate service exception %s' % key)
raise KeyError(u'Duplicate service exception %s' % key)
else:
self.service_list[key] = reference
def remove(self, key):
"""
Removes the registry value from the list based on the key passed in
(Only valid and active for testing framework)
"""
if self.running_under_test is False:
log.error(u'Invalid Method call for key %s' % key)
raise KeyError(u'Invalid Method call for key %s' % key)
return
if key in self.service_list:
del self.service_list[key]

View File

@ -31,10 +31,10 @@ import logging
from PyQt4 import QtGui, QtCore, QtWebKit from PyQt4 import QtGui, QtCore, QtWebKit
from openlp.core.lib import ServiceItem, expand_tags, build_lyrics_format_css, build_lyrics_outline_css, Receiver, \ from openlp.core.lib import FormattingTags, ImageSource, ItemCapabilities, Receiver, Registry, ScreenList, \
ItemCapabilities, FormattingTags, ImageSource ServiceItem, expand_tags, build_lyrics_format_css, build_lyrics_outline_css
from openlp.core.lib.theme import ThemeLevel from openlp.core.lib.theme import ThemeLevel
from openlp.core.ui import MainDisplay, ScreenList from openlp.core.ui import MainDisplay
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -48,6 +48,7 @@ VERSE = u'The Lord said to {r}Noah{/r}: \n' \
VERSE_FOR_LINE_COUNT = u'\n'.join(map(unicode, xrange(50))) VERSE_FOR_LINE_COUNT = u'\n'.join(map(unicode, xrange(50)))
FOOTER = [u'Arky Arky (Unknown)', u'Public Domain', u'CCLI 123456'] FOOTER = [u'Arky Arky (Unknown)', u'Public Domain', u'CCLI 123456']
class Renderer(object): class Renderer(object):
""" """
Class to pull all Renderer interactions into one place. The plugins will Class to pull all Renderer interactions into one place. The plugins will
@ -56,7 +57,7 @@ class Renderer(object):
""" """
log.info(u'Renderer Loaded') log.info(u'Renderer Loaded')
def __init__(self, image_manager, theme_manager): def __init__(self):
""" """
Initialise the renderer. Initialise the renderer.
@ -68,15 +69,14 @@ class Renderer(object):
The theme_manager instance, used to get the current theme details. The theme_manager instance, used to get the current theme details.
""" """
log.debug(u'Initialisation started') log.debug(u'Initialisation started')
self.theme_manager = theme_manager
self.image_manager = image_manager
self.screens = ScreenList() self.screens = ScreenList()
Registry().register(u'renderer', self)
self.theme_level = ThemeLevel.Global self.theme_level = ThemeLevel.Global
self.global_theme_name = u'' self.global_theme_name = u''
self.service_theme_name = u'' self.service_theme_name = u''
self.item_theme_name = u'' self.item_theme_name = u''
self.force_page = False self.force_page = False
self.display = MainDisplay(None, self.image_manager, False, self) self.display = MainDisplay(None, False, self)
self.display.setup() self.display.setup()
self._theme_dimensions = {} self._theme_dimensions = {}
self._calculate_default() self._calculate_default()
@ -93,7 +93,7 @@ class Renderer(object):
self._calculate_default() self._calculate_default()
if self.display: if self.display:
self.display.close() self.display.close()
self.display = MainDisplay(None, self.image_manager, False, self) self.display = MainDisplay(None, False, self)
self.display.setup() self.display.setup()
self._theme_dimensions = {} self._theme_dimensions = {}
@ -128,7 +128,7 @@ class Renderer(object):
The theme name. The theme name.
""" """
if theme_name not in self._theme_dimensions: if theme_name not in self._theme_dimensions:
theme_data = self.theme_manager.getThemeData(theme_name) theme_data = self.theme_manager.get_theme_data(theme_name)
main_rect = self.get_main_rectangle(theme_data) main_rect = self.get_main_rectangle(theme_data)
footer_rect = self.get_footer_rectangle(theme_data) footer_rect = self.get_footer_rectangle(theme_data)
self._theme_dimensions[theme_name] = [theme_data, main_rect, footer_rect] self._theme_dimensions[theme_name] = [theme_data, main_rect, footer_rect]
@ -136,7 +136,7 @@ class Renderer(object):
theme_data, main_rect, footer_rect = self._theme_dimensions[theme_name] theme_data, main_rect, footer_rect = self._theme_dimensions[theme_name]
# if No file do not update cache # if No file do not update cache
if theme_data.background_filename: if theme_data.background_filename:
self.image_manager.addImage(theme_data.background_filename, self.image_manager.add_image(theme_data.background_filename,
ImageSource.Theme, QtGui.QColor(theme_data.background_border_color)) ImageSource.Theme, QtGui.QColor(theme_data.background_border_color))
def pre_render(self, override_theme_data=None): def pre_render(self, override_theme_data=None):
@ -235,11 +235,10 @@ class Renderer(object):
serviceItem.add_from_text(VERSE_FOR_LINE_COUNT) serviceItem.add_from_text(VERSE_FOR_LINE_COUNT)
else: else:
serviceItem.add_from_text(VERSE) serviceItem.add_from_text(VERSE)
serviceItem.renderer = self
serviceItem.raw_footer = FOOTER serviceItem.raw_footer = FOOTER
# if No file do not update cache # if No file do not update cache
if theme_data.background_filename: if theme_data.background_filename:
self.image_manager.addImage(theme_data.background_filename, self.image_manager.add_image(theme_data.background_filename,
ImageSource.Theme, ImageSource.Theme,
QtGui.QColor(theme_data.background_border_color)) QtGui.QColor(theme_data.background_border_color))
theme_data, main, footer = self.pre_render(theme_data) theme_data, main, footer = self.pre_render(theme_data)
@ -316,7 +315,7 @@ class Renderer(object):
if text_contains_split: if text_contains_split:
text = slides[-1] + u'\n[---]\n' + text text = slides[-1] + u'\n[---]\n' + text
else: else:
text = slides[-1] + u'\n'+ text text = slides[-1] + u'\n' + text
text = text.replace(u'<br>', u'\n') text = text.replace(u'<br>', u'\n')
else: else:
pages.extend(slides) pages.extend(slides)
@ -544,7 +543,7 @@ class Renderer(object):
end_tags.reverse() end_tags.reverse()
# Remove the indexes. # Remove the indexes.
html_tags = [tag[1] for tag in html_tags] html_tags = [tag[1] for tag in html_tags]
return raw_text + u''.join(end_tags), u''.join(start_tags), u''.join(html_tags) return raw_text + u''.join(end_tags), u''.join(start_tags), u''.join(html_tags)
def _binary_chop(self, formatted, previous_html, previous_raw, html_list, raw_list, separator, line_end): def _binary_chop(self, formatted, previous_html, previous_raw, html_list, raw_list, separator, line_end):
""" """
@ -643,3 +642,24 @@ class Renderer(object):
# this parse we are to be wordy # this parse we are to be wordy
line = line.replace(u'\n', u' ') line = line.replace(u'\n', u' ')
return line.split(u' ') return line.split(u' ')
def _get_image_manager(self):
"""
Adds the image manager to the class dynamically
"""
if not hasattr(self, u'_image_manager'):
self._image_manager = Registry().get(u'image_manager')
return self._image_manager
image_manager = property(_get_image_manager)
def _get_theme_manager(self):
"""
Adds the theme manager to the class dynamically
"""
if not hasattr(self, u'_theme_manager'):
self._theme_manager = Registry().get(u'theme_manager')
return self._theme_manager
theme_manager = property(_get_theme_manager)

View File

@ -35,10 +35,11 @@ import copy
from PyQt4 import QtCore from PyQt4 import QtCore
from openlp.core.lib import Receiver, translate, Settings from openlp.core.lib import Receiver, translate
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class ScreenList(object): class ScreenList(object):
""" """
Wrapper to handle the parameters of the display screen. Wrapper to handle the parameters of the display screen.
@ -49,6 +50,9 @@ class ScreenList(object):
__instance__ = None __instance__ = None
def __new__(cls): def __new__(cls):
"""
Re-implement __new__ to create a true singleton.
"""
if not cls.__instance__: if not cls.__instance__:
cls.__instance__ = object.__new__(cls) cls.__instance__ = object.__new__(cls)
return cls.__instance__ return cls.__instance__
@ -69,7 +73,7 @@ class ScreenList(object):
screen_list.screen_list = [] screen_list.screen_list = []
screen_list.display_count = 0 screen_list.display_count = 0
screen_list.screen_count_changed() screen_list.screen_count_changed()
screen_list._load_screen_settings() screen_list.load_screen_settings()
QtCore.QObject.connect(desktop, QtCore.SIGNAL(u'resized(int)'), screen_list.screen_resolution_changed) QtCore.QObject.connect(desktop, QtCore.SIGNAL(u'resized(int)'), screen_list.screen_resolution_changed)
QtCore.QObject.connect(desktop, QtCore.SIGNAL(u'screenCountChanged(int)'), screen_list.screen_count_changed) QtCore.QObject.connect(desktop, QtCore.SIGNAL(u'screenCountChanged(int)'), screen_list.screen_count_changed)
return screen_list return screen_list
@ -135,8 +139,7 @@ class ScreenList(object):
""" """
screen_list = [] screen_list = []
for screen in self.screen_list: for screen in self.screen_list:
screen_name = u'%s %d' % (translate('OpenLP.ScreenList', 'Screen'), screen_name = u'%s %d' % (translate('OpenLP.ScreenList', 'Screen'), screen[u'number'] + 1)
screen[u'number'] + 1)
if screen[u'primary']: if screen[u'primary']:
screen_name = u'%s (%s)' % (screen_name, translate('OpenLP.ScreenList', 'primary')) screen_name = u'%s (%s)' % (screen_name, translate('OpenLP.ScreenList', 'primary'))
screen_list.append(screen_name) screen_list.append(screen_name)
@ -233,23 +236,34 @@ class ScreenList(object):
y = window.y() + (window.height() / 2) y = window.y() + (window.height() / 2)
for screen in self.screen_list: for screen in self.screen_list:
size = screen[u'size'] size = screen[u'size']
if x >= size.x() and x <= (size.x() + size.width()) and \ if x >= size.x() and x <= (size.x() + size.width()) and y >= size.y() and y <= (size.y() + size.height()):
y >= size.y() and y <= (size.y() + size.height()):
return screen[u'number'] return screen[u'number']
def _load_screen_settings(self): def load_screen_settings(self):
""" """
Loads the screen size and the monitor number from the settings. Loads the screen size and the monitor number from the settings.
""" """
from openlp.core.lib import Settings
# Add the screen settings to the settings dict. This has to be done here due to crycle dependency.
# Do not do this anywhere else.
screen_settings = {
u'general/x position': self.current[u'size'].x(),
u'general/y position': self.current[u'size'].y(),
u'general/monitor': self.display_count - 1,
u'general/height': self.current[u'size'].height(),
u'general/width': self.current[u'size'].width()
}
Settings.extend_default_settings(screen_settings)
settings = Settings() settings = Settings()
settings.beginGroup(u'general') settings.beginGroup(u'general')
self.set_current_display(settings.value(u'monitor', self.display_count - 1)) monitor = settings.value(u'monitor')
self.display = settings.value(u'display on monitor', True) self.set_current_display(monitor)
override_display = settings.value(u'override position', False) self.display = settings.value(u'display on monitor')
x = settings.value(u'x position', self.current[u'size'].x()) override_display = settings.value(u'override position')
y = settings.value(u'y position', self.current[u'size'].y()) x = settings.value(u'x position')
width = settings.value(u'width', self.current[u'size'].width()) y = settings.value(u'y position')
height = settings.value(u'height', self.current[u'size'].height()) width = settings.value(u'width')
height = settings.value(u'height')
self.override[u'size'] = QtCore.QRect(x, y, width, height) self.override[u'size'] = QtCore.QRect(x, y, width, height)
self.override[u'primary'] = False self.override[u'primary'] = False
settings.endGroup() settings.endGroup()

View File

@ -36,6 +36,7 @@ from openlp.core.lib.ui import create_widget_action
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class SearchEdit(QtGui.QLineEdit): class SearchEdit(QtGui.QLineEdit):
""" """
This is a specialised QLineEdit with a "clear" button inside for searches. This is a specialised QLineEdit with a "clear" button inside for searches.

View File

@ -37,10 +37,13 @@ import logging
import os import os
import uuid import uuid
from openlp.core.lib import build_icon, clean_tags, expand_tags, translate, ImageSource from PyQt4 import QtGui
from openlp.core.lib import ImageSource, Settings, Registry, build_icon, clean_tags, expand_tags, translate
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class ServiceItemType(object): class ServiceItemType(object):
""" """
Defines the type of service item Defines the type of service item
@ -146,7 +149,6 @@ class ServiceItem(object):
The plugin that this service item belongs to. The plugin that this service item belongs to.
""" """
if plugin: if plugin:
self.renderer = plugin.renderer
self.name = plugin.name self.name = plugin.name
self.title = u'' self.title = u''
self.shortname = u'' self.shortname = u''
@ -159,7 +161,7 @@ class ServiceItem(object):
self.service_item_type = None self.service_item_type = None
self._raw_frames = [] self._raw_frames = []
self._display_frames = [] self._display_frames = []
self._uuid = 0 self.unique_identifier = 0
self.notes = u'' self.notes = u''
self.from_plugin = False self.from_plugin = False
self.capabilities = [] self.capabilities = []
@ -181,7 +183,11 @@ class ServiceItem(object):
self.background_audio = [] self.background_audio = []
self.theme_overwritten = False self.theme_overwritten = False
self.temporary_edit = False self.temporary_edit = False
self.auto_play_slides_once = False
self.auto_play_slides_loop = False
self.timed_slide_interval = 0
self.will_auto_start = False self.will_auto_start = False
self.has_original_files = True
self._new_item() self._new_item()
def _new_item(self): def _new_item(self):
@ -189,7 +195,8 @@ class ServiceItem(object):
Method to set the internal id of the item. This is used to compare Method to set the internal id of the item. This is used to compare
service items to see if they are the same. service items to see if they are the same.
""" """
self._uuid = unicode(uuid.uuid1()) self.unique_identifier = unicode(uuid.uuid1())
self.validate_item()
def add_capability(self, capability): def add_capability(self, capability):
""" """
@ -286,7 +293,7 @@ class ServiceItem(object):
self.image_border = background self.image_border = background
self.service_item_type = ServiceItemType.Image self.service_item_type = ServiceItemType.Image
self._raw_frames.append({u'title': title, u'path': path}) self._raw_frames.append({u'title': title, u'path': path})
self.renderer.image_manager.addImage(path, ImageSource.ImagePlugin, self.image_border) self.image_manager.add_image(path, ImageSource.ImagePlugin, self.image_border)
self._new_item() self._new_item()
def add_from_text(self, raw_slide, verse_tag=None): def add_from_text(self, raw_slide, verse_tag=None):
@ -340,6 +347,9 @@ class ServiceItem(object):
u'search': self.search_string, u'search': self.search_string,
u'data': self.data_string, u'data': self.data_string,
u'xml_version': self.xml_version, u'xml_version': self.xml_version,
u'auto_play_slides_once': self.auto_play_slides_once,
u'auto_play_slides_loop': self.auto_play_slides_loop,
u'timed_slide_interval': self.timed_slide_interval,
u'start_time': self.start_time, u'start_time': self.start_time,
u'end_time': self.end_time, u'end_time': self.end_time,
u'media_length': self.media_length, u'media_length': self.media_length,
@ -394,7 +404,11 @@ class ServiceItem(object):
self.start_time = header.get(u'start_time', 0) self.start_time = header.get(u'start_time', 0)
self.end_time = header.get(u'end_time', 0) self.end_time = header.get(u'end_time', 0)
self.media_length = header.get(u'media_length', 0) self.media_length = header.get(u'media_length', 0)
self.auto_play_slides_once = header.get(u'auto_play_slides_once', False)
self.auto_play_slides_loop = header.get(u'auto_play_slides_loop', False)
self.timed_slide_interval = header.get(u'timed_slide_interval', 0)
self.will_auto_start = header.get(u'will_auto_start', False) self.will_auto_start = header.get(u'will_auto_start', False)
self.has_original_files = True
if u'background_audio' in header: if u'background_audio' in header:
self.background_audio = [] self.background_audio = []
for filename in header[u'background_audio']: for filename in header[u'background_audio']:
@ -405,20 +419,23 @@ class ServiceItem(object):
for slide in serviceitem[u'serviceitem'][u'data']: for slide in serviceitem[u'serviceitem'][u'data']:
self._raw_frames.append(slide) self._raw_frames.append(slide)
elif self.service_item_type == ServiceItemType.Image: elif self.service_item_type == ServiceItemType.Image:
settingsSection = serviceitem[u'serviceitem'][u'header'][u'name']
background = QtGui.QColor(Settings().value(settingsSection + u'/background color'))
if path: if path:
self.has_original_files = False
for text_image in serviceitem[u'serviceitem'][u'data']: for text_image in serviceitem[u'serviceitem'][u'data']:
filename = os.path.join(path, text_image) filename = os.path.join(path, text_image)
self.add_from_image(filename, text_image) self.add_from_image(filename, text_image, background)
else: else:
for text_image in serviceitem[u'serviceitem'][u'data']: for text_image in serviceitem[u'serviceitem'][u'data']:
self.add_from_image(text_image[u'path'], text_image[u'title']) self.add_from_image(text_image[u'path'], text_image[u'title'], background)
elif self.service_item_type == ServiceItemType.Command: elif self.service_item_type == ServiceItemType.Command:
for text_image in serviceitem[u'serviceitem'][u'data']: for text_image in serviceitem[u'serviceitem'][u'data']:
if path: if path:
self.has_original_files = False
self.add_from_command(path, text_image[u'title'], text_image[u'image']) self.add_from_command(path, text_image[u'title'], text_image[u'image'])
else: else:
self.add_from_command(text_image[u'path'], text_image[u'title'], text_image[u'image']) self.add_from_command(text_image[u'path'], text_image[u'title'], text_image[u'image'])
self._new_item() self._new_item()
def get_display_title(self): def get_display_title(self):
@ -437,14 +454,14 @@ class ServiceItem(object):
def merge(self, other): def merge(self, other):
""" """
Updates the _uuid with the value from the original one Updates the unique_identifier with the value from the original one
The _uuid is unique for a given service item but this allows one to The unique_identifier is unique for a given service item but this allows one to
replace an original version. replace an original version.
``other`` ``other``
The service item to be merged with The service item to be merged with
""" """
self._uuid = other._uuid self.unique_identifier = other.unique_identifier
self.notes = other.notes self.notes = other.notes
self.temporary_edit = other.temporary_edit self.temporary_edit = other.temporary_edit
# Copy theme over if present. # Copy theme over if present.
@ -461,13 +478,13 @@ class ServiceItem(object):
""" """
if not other: if not other:
return False return False
return self._uuid == other._uuid return self.unique_identifier == other.unique_identifier
def __ne__(self, other): def __ne__(self, other):
""" """
Confirms the service items are not for the same instance Confirms the service items are not for the same instance
""" """
return self._uuid != other._uuid return self.unique_identifier != other.unique_identifier
def is_media(self): def is_media(self):
""" """
@ -591,7 +608,7 @@ class ServiceItem(object):
``theme`` ``theme``
The new theme to be replaced in the service item The new theme to be replaced in the service item
""" """
self.theme_overwritten = (theme == None) self.theme_overwritten = (theme is None)
self.theme = theme self.theme = theme
self._new_item() self._new_item()
self.render() self.render()
@ -605,8 +622,45 @@ class ServiceItem(object):
if self.get_frame_path(frame=frame) in invalid_paths: if self.get_frame_path(frame=frame) in invalid_paths:
self.remove_frame(frame) self.remove_frame(frame)
def validate(self): def missing_frames(self):
""" """
Validates this service item Returns if there are any frames in the service item
""" """
return bool(self._raw_frames) return not bool(self._raw_frames)
def validate_item(self, suffix_list=None):
"""
Validates a service item to make sure it is valid
"""
self.is_valid = True
for frame in self._raw_frames:
if self.is_image() and not os.path.exists((frame[u'path'])):
self.is_valid = False
elif self.is_command():
file_name = os.path.join(frame[u'path'], frame[u'title'])
if not os.path.exists(file_name):
self.is_valid = False
if suffix_list and not self.is_text():
file_suffix = frame[u'title'].split(u'.')[-1]
if file_suffix.lower() not in suffix_list:
self.is_valid = False
def _get_renderer(self):
"""
Adds the Renderer to the class dynamically
"""
if not hasattr(self, u'_renderer'):
self._renderer = Registry().get(u'renderer')
return self._renderer
renderer = property(_get_renderer)
def _get_image_manager(self):
"""
Adds the image manager to the class dynamically
"""
if not hasattr(self, u'_image_manager'):
self._image_manager = Registry().get(u'image_manager')
return self._image_manager
image_manager = property(_get_image_manager)

365
openlp/core/lib/settings.py Normal file
View File

@ -0,0 +1,365 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2013 Raoul Snyman #
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
This class contains the core default settings.
"""
import datetime
import logging
import os
import sys
from PyQt4 import QtCore, QtGui
from openlp.core.lib import SlideLimits
from openlp.core.lib.theme import ThemeLevel
from openlp.core.lib import UiStrings
log = logging.getLogger(__name__)
# Fix for bug #1014422.
X11_BYPASS_DEFAULT = True
if sys.platform.startswith(u'linux'):
# Default to False on Gnome.
X11_BYPASS_DEFAULT = bool(not os.environ.get(u'GNOME_DESKTOP_SESSION_ID'))
# Default to False on Xfce.
if os.environ.get(u'DESKTOP_SESSION') == u'xfce':
X11_BYPASS_DEFAULT = False
class Settings(QtCore.QSettings):
"""
Class to wrap QSettings.
* Exposes all the methods of QSettings.
* Adds functionality for OpenLP Portable. If the ``defaultFormat`` is set to
``IniFormat``, and the path to the Ini file is set using ``set_filename``,
then the Settings constructor (without any arguments) will create a Settings
object for accessing settings stored in that Ini file.
``__default_settings__``
This dict contains all core settings with their default values.
``__obsolete_settings__``
Each entry is structured in the following way::
(u'general/enable slide loop', u'advanced/slide limits', [(SlideLimits.Wrap, True), (SlideLimits.End, False)])
The first entry is the *old key*; it will be removed.
The second entry is the *new key*; we will add it to the config. If this is just an empty string, we just remove
the old key.
The last entry is a list containing two-pair tuples. If the list is empty, no conversion is made. Otherwise each
pair describes how to convert the old setting's value::
(SlideLimits.Wrap, True)
This means, that if the value of ``general/enable slide loop`` is equal (``==``) ``True`` then we set
``advanced/slide limits`` to ``SlideLimits.Wrap``. **NOTE**, this means that the rules have to cover all cases!
So, if the type of the old value is bool, then there must be two rules.
"""
__default_settings__ = {
u'advanced/add page break': False,
u'advanced/alternate rows': not sys.platform.startswith(u'win'),
u'advanced/current media plugin': -1,
u'advanced/data path': u'',
u'advanced/default color': u'#ffffff',
u'advanced/default image': u':/graphics/openlp-splash-screen.png',
# 7 stands for now, 0 to 6 is Monday to Sunday.
u'advanced/default service day': 7,
u'advanced/default service enabled': True,
u'advanced/default service hour': 11,
u'advanced/default service minute': 0,
u'advanced/default service name': UiStrings().DefaultServiceName,
u'advanced/display size': 0,
u'advanced/double click live': False,
u'advanced/enable exit confirmation': True,
u'advanced/expand service item': False,
u'advanced/hide mouse': True,
u'advanced/is portable': False,
u'advanced/max recent files': 20,
u'advanced/print file meta data': False,
u'advanced/print notes': False,
u'advanced/print slide text': False,
u'advanced/recent file count': 4,
u'advanced/save current plugin': False,
u'advanced/slide limits': SlideLimits.End,
u'advanced/single click preview': False,
u'advanced/x11 bypass wm': X11_BYPASS_DEFAULT,
u'crashreport/last directory': u'',
u'displayTags/html_tags': u'',
u'general/audio repeat list': False,
u'general/auto open': False,
u'general/auto preview': False,
u'general/audio start paused': True,
u'general/auto unblank': False,
u'general/blank warning': False,
u'general/ccli number': u'',
u'general/has run wizard': False,
u'general/language': u'[en]',
# This defaults to yesterday in order to force the update check to run when you've never run it before.
u'general/last version test': datetime.datetime.now().date() - datetime.timedelta(days=1),
u'general/loop delay': 5,
u'general/recent files': [],
u'general/save prompt': False,
u'general/screen blank': False,
u'general/show splash': True,
u'general/songselect password': u'',
u'general/songselect username': u'',
u'general/update check': True,
u'general/view mode': u'default',
# The other display settings (display position and dimensions) are defined in the ScreenList class due to a
# circular dependency.
u'general/display on monitor': True,
u'general/override position': False,
u'media/players': u'webkit',
u'media/override player': QtCore.Qt.Unchecked,
u'players/background color': u'#000000',
u'servicemanager/last directory': u'',
u'servicemanager/last file': u'',
u'servicemanager/service theme': u'',
u'SettingsImport/file_date_created': datetime.datetime.now().strftime("%Y-%m-%d %H:%M"),
u'SettingsImport/Make_Changes': u'At_Own_RISK',
u'SettingsImport/type': u'OpenLP_settings_export',
u'SettingsImport/version': u'',
u'shortcuts/aboutItem': [QtGui.QKeySequence(u'Ctrl+F1')],
u'shortcuts/audioPauseItem': [],
u'shortcuts/displayTagItem': [],
u'shortcuts/blankScreen': [QtCore.Qt.Key_Period],
u'shortcuts/collapse': [QtCore.Qt.Key_Minus],
u'shortcuts/desktopScreen': [QtGui.QKeySequence(u'D')],
u'shortcuts/down': [QtCore.Qt.Key_Down],
u'shortcuts/escapeItem': [QtCore.Qt.Key_Escape],
u'shortcuts/expand': [QtCore.Qt.Key_Plus],
u'shortcuts/exportThemeItem': [],
u'shortcuts/fileNewItem': [QtGui.QKeySequence(u'Ctrl+N')],
u'shortcuts/fileSaveAsItem': [QtGui.QKeySequence(u'Ctrl+Shift+S')],
u'shortcuts/fileExitItem': [QtGui.QKeySequence(u'Alt+F4')],
u'shortcuts/fileSaveItem': [QtGui.QKeySequence(u'Ctrl+S')],
u'shortcuts/fileOpenItem': [QtGui.QKeySequence(u'Ctrl+O')],
u'shortcuts/importThemeItem': [],
u'shortcuts/importBibleItem': [],
u'shortcuts/modeDefaultItem': [],
u'shortcuts/modeLiveItem': [],
u'shortcuts/make_live': [QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return],
u'shortcuts/moveUp': [QtCore.Qt.Key_PageUp],
u'shortcuts/moveTop': [QtCore.Qt.Key_Home],
u'shortcuts/modeSetupItem': [],
u'shortcuts/moveBottom': [QtCore.Qt.Key_End],
u'shortcuts/moveDown': [QtCore.Qt.Key_PageDown],
u'shortcuts/nextTrackItem': [],
u'shortcuts/nextItem_live': [QtCore.Qt.Key_Down, QtCore.Qt.Key_PageDown],
u'shortcuts/nextService': [QtCore.Qt.Key_Right],
u'shortcuts/offlineHelpItem': [],
u'shortcuts/onlineHelpItem': [QtGui.QKeySequence(u'Alt+F1')],
u'shortcuts/previousItem_live': [QtCore.Qt.Key_Up, QtCore.Qt.Key_PageUp],
u'shortcuts/playSlidesLoop': [],
u'shortcuts/playSlidesOnce': [],
u'shortcuts/previousService': [QtCore.Qt.Key_Left],
u'shortcuts/printServiceItem': [QtGui.QKeySequence(u'Ctrl+P')],
u'shortcuts/songExportItem': [],
u'shortcuts/songUsageStatus': [QtCore.Qt.Key_F4],
u'shortcuts/settingsShortcutsItem': [],
u'shortcuts/settingsImportItem': [],
u'shortcuts/settingsPluginListItem': [QtGui.QKeySequence(u'Alt+F7')],
u'shortcuts/songUsageDelete': [],
u'shortcuts/settingsConfigureItem': [],
u'shortcuts/shortcutAction_B': [QtGui.QKeySequence(u'B')],
u'shortcuts/shortcutAction_C': [QtGui.QKeySequence(u'C')],
u'shortcuts/shortcutAction_E': [QtGui.QKeySequence(u'E')],
u'shortcuts/shortcutAction_I': [QtGui.QKeySequence(u'I')],
u'shortcuts/shortcutAction_O': [QtGui.QKeySequence(u'O')],
u'shortcuts/shortcutAction_P': [QtGui.QKeySequence(u'P')],
u'shortcuts/shortcutAction_V': [QtGui.QKeySequence(u'V')],
u'shortcuts/settingsExportItem': [],
u'shortcuts/songUsageReport': [],
u'shortcuts/songImportItem': [],
u'shortcuts/themeScreen': [QtGui.QKeySequence(u'T')],
u'shortcuts/toolsReindexItem': [],
u'shortcuts/toolsAlertItem': [u'F7'],
u'shortcuts/toolsFirstTimeWizard': [],
u'shortcuts/toolsOpenDataFolder': [],
u'shortcuts/toolsAddToolItem': [],
u'shortcuts/updateThemeImages': [],
u'shortcuts/up': [QtCore.Qt.Key_Up],
u'shortcuts/viewThemeManagerItem': [QtGui.QKeySequence(u'F10')],
u'shortcuts/viewMediaManagerItem': [QtGui.QKeySequence(u'F8')],
u'shortcuts/viewPreviewPanel': [QtGui.QKeySequence(u'F11')],
u'shortcuts/viewLivePanel': [QtGui.QKeySequence(u'F12')],
u'shortcuts/viewServiceManagerItem': [QtGui.QKeySequence(u'F9')],
u'shortcuts/webSiteItem': [],
u'themes/global theme': u'',
u'themes/last directory': u'',
u'themes/last directory export': u'',
u'themes/last directory import': u'',
u'themes/theme level': ThemeLevel.Song,
u'user interface/live panel': True,
u'user interface/live splitter geometry': QtCore.QByteArray(),
u'user interface/lock panel': False,
u'user interface/main window geometry': QtCore.QByteArray(),
u'user interface/main window position': QtCore.QPoint(0, 0),
u'user interface/main window splitter geometry': QtCore.QByteArray(),
u'user interface/main window state': QtCore.QByteArray(),
u'user interface/preview panel': True,
u'user interface/preview splitter geometry': QtCore.QByteArray()
}
__file_path__ = u''
__obsolete_settings__ = [
# Changed during 1.9.x development.
(u'bibles/bookname language', u'bibles/book name language', []),
(u'general/enable slide loop', u'advanced/slide limits', [(SlideLimits.Wrap, True), (SlideLimits.End, False)]),
(u'songs/ccli number', u'general/ccli number', []),
# Changed during 2.1.x development.
(u'advanced/stylesheet fix', u'', []),
(u'bibles/last directory 1', u'bibles/last directory import', []),
(u'media/background color', u'players/background color', []),
(u'themes/last directory', u'themes/last directory import', []),
(u'themes/last directory 1', u'themes/last directory export', []),
(u'songs/last directory 1', u'songs/last directory import', []),
(u'songusage/last directory 1', u'songusage/last directory export', []),
(u'user interface/mainwindow splitter geometry', u'user interface/main window splitter geometry', []),
(u'shortcuts/makeLive', u'shortcuts/make_live', [])
]
@staticmethod
def extend_default_settings(default_values):
"""
Static method to merge the given ``default_values`` with the ``Settings.__default_settings__``.
``default_values``
A dict with setting keys and their default values.
"""
Settings.__default_settings__ = dict(default_values.items() + Settings.__default_settings__.items())
@staticmethod
def set_filename(ini_file):
"""
Sets the complete path to an Ini file to be used by Settings objects.
Does not affect existing Settings objects.
"""
Settings.__file_path__ = ini_file
@staticmethod
def set_up_default_values():
"""
This static method is called on start up. It is used to perform any operation on the __default_settings__ dict.
"""
# Make sure the string is translated (when building the dict the string is not translated because the translate
# function was not set up as this stage).
Settings.__default_settings__[u'advanced/default service name'] = UiStrings().DefaultServiceName
def __init__(self, *args):
"""
Constructor which checks if this should be a native settings object, or an INI file.
"""
if not args and Settings.__file_path__ and Settings.defaultFormat() == Settings.IniFormat:
QtCore.QSettings.__init__(self, Settings.__file_path__, Settings.IniFormat)
else:
QtCore.QSettings.__init__(self, *args)
def remove_obsolete_settings(self):
"""
This method is only called to clean up the config. It removes old settings and it renames settings. See
``__obsolete_settings__`` for more details.
"""
for old_key, new_key, rules in Settings.__obsolete_settings__:
# Once removed we don't have to do this again.
if self.contains(old_key):
if new_key:
# Get the value of the old_key.
old_value = super(Settings, self).value(old_key)
# When we want to convert the value, we have to figure out the default value (because we cannot get
# the default value from the central settings dict.
if rules:
default_value = rules[0][1]
old_value = self._convert_value(old_value, default_value)
# Iterate over our rules and check what the old_value should be "converted" to.
for new, old in rules:
# If the value matches with the condition (rule), then use the provided value. This is used to
# convert values. E. g. an old value 1 results in True, and 0 in False.
if old == old_value:
old_value = new
break
self.setValue(new_key, old_value)
self.remove(old_key)
def value(self, key):
"""
Returns the value for the given ``key``. The returned ``value`` is of the same type as the default value in the
*Settings.__default_settings__* dict.
``key``
The key to return the value from.
"""
# if group() is not empty the group has not been specified together with the key.
if self.group():
default_value = Settings.__default_settings__[self.group() + u'/' + key]
else:
default_value = Settings.__default_settings__[key]
setting = super(Settings, self).value(key, default_value)
return self._convert_value(setting, default_value)
def _convert_value(self, setting, default_value):
"""
This converts the given ``setting`` to the type of the given ``default_value``.
``setting``
The setting to convert. This could be ``true`` for example.Settings()
``default_value``
Indication the type the setting should be converted to. For example ``True`` (type is boolean), meaning that
we convert the string ``true`` to a python boolean.
**Note**, this method only converts a few types and might need to be extended if a certain type is missing!
"""
# On OS X (and probably on other platforms too) empty value from QSettings is represented as type
# PyQt4.QtCore.QPyNullVariant. This type has to be converted to proper 'None' Python type.
if isinstance(setting, QtCore.QPyNullVariant) and setting.isNull():
setting = None
# Handle 'None' type (empty value) properly.
if setting is None:
# An empty string saved to the settings results in a None type being returned.
# Convert it to empty unicode string.
if isinstance(default_value, unicode):
return u''
# An empty list saved to the settings results in a None type being returned.
else:
return []
# Convert the setting to the correct type.
if isinstance(default_value, bool):
if isinstance(setting, bool):
return setting
# Sometimes setting is string instead of a boolean.
return setting == u'true'
if isinstance(default_value, int):
return int(setting)
return setting

View File

@ -27,121 +27,27 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
Provide handling for persisting OpenLP settings. OpenLP uses QSettings to Provide handling for persisting OpenLP settings. OpenLP uses QSettings to manage settings persistence. QSettings
manage settings persistence. QSettings provides a single API for saving and provides a single API for saving and retrieving settings from the application but writes to disk in an OS dependant
retrieving settings from the application but writes to disk in an OS dependant
format. format.
""" """
import os import os
from PyQt4 import QtCore
from openlp.core.lib import Settings
from openlp.core.utils import AppLocation from openlp.core.utils import AppLocation
class SettingsManager(object): class SettingsManager(object):
""" """
Class to provide helper functions for the loading and saving of application Class to provide helper functions for the loading and saving of application settings.
settings.
""" """
@staticmethod
def get_last_dir(section, num=None):
"""
Read the last directory used for plugin.
``section``
The section of code calling the method. This is used in the
settings key.
``num``
Defaults to *None*. A further qualifier.
"""
if num:
name = u'last directory %d' % num
else:
name = u'last directory'
return Settings().value(section + u'/' + name, u'')
@staticmethod
def set_last_dir(section, directory, num=None):
"""
Save the last directory used for plugin.
``section``
The section of code calling the method. This is used in the
settings key.
``directory``
The directory being stored in the settings.
``num``
Defaults to *None*. A further qualifier.
"""
if num:
name = u'last directory %d' % num
else:
name = u'last directory'
Settings().setValue(section + u'/' + name, directory)
@staticmethod
def set_list(section, name, list):
"""
Save a list to application settings.
``section``
The section of the settings to store this list.
``name``
The name of the list to save.
``list``
The list of values to save.
"""
settings = Settings()
settings.beginGroup(section)
old_count = settings.value(u'%s count' % name, 0)
new_count = len(list)
settings.setValue(u'%s count' % name, new_count)
for counter in range(new_count):
settings.setValue(u'%s %d' % (name, counter), list[counter - 1])
if old_count > new_count:
# Tidy up any old list items
for counter in range(new_count, old_count):
settings.remove(u'%s %d' % (name, counter))
settings.endGroup()
@staticmethod
def load_list(section, name):
"""
Load a list from the config file.
``section``
The section of the settings to load the list from.
``name``
The name of the list.
"""
settings = Settings()
settings.beginGroup(section)
list_count = settings.value(u'%s count' % name, 0)
list = []
if list_count:
for counter in range(list_count):
item = settings.value(u'%s %d' % (name, counter), u'')
if item:
list.append(item)
settings.endGroup()
return list
@staticmethod @staticmethod
def get_files(section=None, extension=None): def get_files(section=None, extension=None):
""" """
Get a list of files from the data files path. Get a list of files from the data files path.
``section`` ``section``
Defaults to *None*. The section of code getting the files - used Defaults to *None*. The section of code getting the files - used to load from a section's data subdirectory.
to load from a section's data subdirectory.
``extension`` ``extension``
Defaults to *None*. The extension to search for. Defaults to *None*. The extension to search for.
@ -154,8 +60,7 @@ class SettingsManager(object):
except OSError: except OSError:
return [] return []
if extension: if extension:
return [filename for filename in files return [filename for filename in files if extension == os.path.splitext(filename)[1]]
if extension == os.path.splitext(filename)[1]]
else: else:
# no filtering required # no filtering required
return files return files

View File

@ -26,9 +26,16 @@
# 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 #
############################################################################### ###############################################################################
"""
The :mod:`~openlp.core.lib.settingstab` module contains the base SettingsTab class which plugins use for adding their
own tab to the settings dialog.
"""
from PyQt4 import QtGui from PyQt4 import QtGui
from openlp.core.lib import Registry
class SettingsTab(QtGui.QWidget): class SettingsTab(QtGui.QWidget):
""" """
SettingsTab is a helper widget for plugins to define Tabs for the settings SettingsTab is a helper widget for plugins to define Tabs for the settings
@ -131,3 +138,54 @@ class SettingsTab(QtGui.QWidget):
Tab has just been made visible to the user Tab has just been made visible to the user
""" """
pass pass
def _get_service_manager(self):
"""
Adds the service manager to the class dynamically
"""
if not hasattr(self, u'_service_manager'):
self._service_manager = Registry().get(u'service_manager')
return self._service_manager
service_manager = property(_get_service_manager)
def _get_main_window(self):
"""
Adds the main window to the class dynamically
"""
if not hasattr(self, u'_main_window'):
self._main_window = Registry().get(u'main_window')
return self._main_window
main_window = property(_get_main_window)
def _get_renderer(self):
"""
Adds the Renderer to the class dynamically
"""
if not hasattr(self, u'_renderer'):
self._renderer = Registry().get(u'renderer')
return self._renderer
renderer = property(_get_renderer)
def _get_theme_manager(self):
"""
Adds the theme manager to the class dynamically
"""
if not hasattr(self, u'_theme_manager'):
self._theme_manager = Registry().get(u'theme_manager')
return self._theme_manager
theme_manager = property(_get_theme_manager)
def _get_media_controller(self):
"""
Adds the media controller to the class dynamically
"""
if not hasattr(self, u'_media_controller'):
self._media_controller = Registry().get(u'media_controller')
return self._media_controller
media_controller = property(_get_media_controller)

View File

@ -26,6 +26,10 @@
# 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 #
############################################################################### ###############################################################################
"""
The :mod:`~openlp.core.lib.spelltextedit` module contains a classes to add spell checking to an edit widget.
"""
import logging import logging
import re import re
@ -47,11 +51,15 @@ from openlp.core.lib.ui import create_action
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class SpellTextEdit(QtGui.QPlainTextEdit): class SpellTextEdit(QtGui.QPlainTextEdit):
""" """
Spell checking widget based on QPlanTextEdit. Spell checking widget based on QPlanTextEdit.
""" """
def __init__(self, parent=None, formattingTagsAllowed=True): def __init__(self, parent=None, formattingTagsAllowed=True):
"""
Constructor.
"""
global ENCHANT_AVAILABLE global ENCHANT_AVAILABLE
QtGui.QPlainTextEdit.__init__(self, parent) QtGui.QPlainTextEdit.__init__(self, parent)
self.formattingTagsAllowed = formattingTagsAllowed self.formattingTagsAllowed = formattingTagsAllowed
@ -171,6 +179,9 @@ class Highlighter(QtGui.QSyntaxHighlighter):
WORDS = u'(?iu)[\w\']+' WORDS = u'(?iu)[\w\']+'
def __init__(self, *args): def __init__(self, *args):
"""
Constructor
"""
QtGui.QSyntaxHighlighter.__init__(self, *args) QtGui.QSyntaxHighlighter.__init__(self, *args)
self.spellingDictionary = None self.spellingDictionary = None
@ -197,5 +208,8 @@ class SpellAction(QtGui.QAction):
correct = QtCore.pyqtSignal(unicode) correct = QtCore.pyqtSignal(unicode)
def __init__(self, *args): def __init__(self, *args):
"""
Constructor
"""
QtGui.QAction.__init__(self, *args) QtGui.QAction.__init__(self, *args)
self.triggered.connect(lambda x: self.correct.emit(self.text())) self.triggered.connect(lambda x: self.correct.emit(self.text()))

View File

@ -36,7 +36,7 @@ import logging
from xml.dom.minidom import Document from xml.dom.minidom import Document
from lxml import etree, objectify from lxml import etree, objectify
from openlp.core.lib import str_to_bool from openlp.core.lib import str_to_bool, ScreenList
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -86,6 +86,7 @@ BLANK_THEME_XML = \
</theme> </theme>
''' '''
class ThemeLevel(object): class ThemeLevel(object):
""" """
Provides an enumeration for the level a theme applies to Provides an enumeration for the level a theme applies to
@ -213,6 +214,7 @@ class ThemeXML(object):
""" """
FIRST_CAMEL_REGEX = re.compile(u'(.)([A-Z][a-z]+)') FIRST_CAMEL_REGEX = re.compile(u'(.)([A-Z][a-z]+)')
SECOND_CAMEL_REGEX = re.compile(u'([a-z0-9])([A-Z])') SECOND_CAMEL_REGEX = re.compile(u'([a-z0-9])([A-Z])')
def __init__(self): def __init__(self):
""" """
Initialise the theme object. Initialise the theme object.
@ -380,8 +382,7 @@ class ThemeXML(object):
# Create italics name element # Create italics name element
self.child_element(background, u'italics', unicode(italics)) self.child_element(background, u'italics', unicode(italics))
# Create indentation name element # Create indentation name element
self.child_element( self.child_element(background, u'line_adjustment', unicode(line_adjustment))
background, u'line_adjustment', unicode(line_adjustment))
# Create Location element # Create Location element
element = self.theme_xml.createElement(u'location') element = self.theme_xml.createElement(u'location')
element.setAttribute(u'override', unicode(override)) element.setAttribute(u'override', unicode(override))
@ -451,7 +452,6 @@ class ThemeXML(object):
Set the header and footer size into the current primary screen. Set the header and footer size into the current primary screen.
10 px on each side is removed to allow for a border. 10 px on each side is removed to allow for a border.
""" """
from openlp.core.ui import ScreenList
current_screen = ScreenList().current current_screen = ScreenList().current
self.font_main_y = 0 self.font_main_y = 0
self.font_main_width = current_screen[u'size'].width() - 20 self.font_main_width = current_screen[u'size'].width() - 20
@ -610,13 +610,15 @@ class ThemeXML(object):
self.add_background_gradient( self.add_background_gradient(
self.background_start_color, self.background_start_color,
self.background_end_color, self.background_end_color,
self.background_direction) self.background_direction
)
elif self.background_type == BackgroundType.to_string(BackgroundType.Image): elif self.background_type == BackgroundType.to_string(BackgroundType.Image):
filename = os.path.split(self.background_filename)[1] filename = os.path.split(self.background_filename)[1]
self.add_background_image(filename, self.background_border_color) self.add_background_image(filename, self.background_border_color)
elif self.background_type == BackgroundType.to_string(BackgroundType.Transparent): elif self.background_type == BackgroundType.to_string(BackgroundType.Transparent):
self.add_background_transparent() self.add_background_transparent()
self.add_font(self.font_main_name, self.add_font(
self.font_main_name,
self.font_main_color, self.font_main_color,
self.font_main_size, self.font_main_size,
self.font_main_override, u'main', self.font_main_override, u'main',
@ -632,14 +634,16 @@ class ThemeXML(object):
self.font_main_outline_size, self.font_main_outline_size,
self.font_main_shadow, self.font_main_shadow,
self.font_main_shadow_color, self.font_main_shadow_color,
self.font_main_shadow_size) self.font_main_shadow_size
self.add_font(self.font_footer_name, )
self.add_font(
self.font_footer_name,
self.font_footer_color, self.font_footer_color,
self.font_footer_size, self.font_footer_size,
self.font_footer_override, u'footer', self.font_footer_override, u'footer',
self.font_footer_bold, self.font_footer_bold,
self.font_footer_italics, self.font_footer_italics,
0, # line adjustment 0, # line adjustment
self.font_footer_x, self.font_footer_x,
self.font_footer_y, self.font_footer_y,
self.font_footer_width, self.font_footer_width,
@ -649,7 +653,10 @@ class ThemeXML(object):
self.font_footer_outline_size, self.font_footer_outline_size,
self.font_footer_shadow, self.font_footer_shadow,
self.font_footer_shadow_color, self.font_footer_shadow_color,
self.font_footer_shadow_size) self.font_footer_shadow_size
self.add_display(self.display_horizontal_align, )
self.add_display(
self.display_horizontal_align,
self.display_vertical_align, self.display_vertical_align,
self.display_slide_transition) self.display_slide_transition
)

View File

@ -37,6 +37,7 @@ from openlp.core.lib.ui import create_widget_action
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class OpenLPToolbar(QtGui.QToolBar): class OpenLPToolbar(QtGui.QToolBar):
""" """
Lots of toolbars around the place, so it makes sense to have a common way Lots of toolbars around the place, so it makes sense to have a common way
@ -85,4 +86,3 @@ class OpenLPToolbar(QtGui.QToolBar):
self.actions[handle].setVisible(visible) self.actions[handle].setVisible(visible)
else: else:
log.warn(u'No handle "%s" in actions list.', unicode(handle)) log.warn(u'No handle "%s" in actions list.', unicode(handle))

View File

@ -33,116 +33,12 @@ import logging
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, Receiver, translate from openlp.core.lib import Receiver, UiStrings, build_icon, translate
from openlp.core.utils.actions import ActionList from openlp.core.utils.actions import ActionList
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class UiStrings(object):
"""
Provide standard strings for objects to use.
"""
__instance__ = None
def __new__(cls):
"""
Override the default object creation method to return a single instance.
"""
if not cls.__instance__:
cls.__instance__ = object.__new__(cls)
return cls.__instance__
def __init__(self):
"""
These strings should need a good reason to be retranslated elsewhere.
Should some/more/less of these have an &amp; attached?
"""
self.About = translate('OpenLP.Ui', 'About')
self.Add = translate('OpenLP.Ui', '&Add')
self.Advanced = translate('OpenLP.Ui', 'Advanced')
self.AllFiles = translate('OpenLP.Ui', 'All Files')
self.Automatic = translate('OpenLP.Ui', 'Automatic')
self.BackgroundColor = translate('OpenLP.Ui', 'Background Color')
self.Bottom = translate('OpenLP.Ui', 'Bottom')
self.Browse = translate('OpenLP.Ui', 'Browse...')
self.Cancel = translate('OpenLP.Ui', 'Cancel')
self.CCLINumberLabel = translate('OpenLP.Ui', 'CCLI number:')
self.CreateService = translate('OpenLP.Ui', 'Create a new service.')
self.ConfirmDelete = translate('OpenLP.Ui', 'Confirm Delete')
self.Continuous = translate('OpenLP.Ui', 'Continuous')
self.Default = translate('OpenLP.Ui', 'Default')
self.DefaultColor = translate('OpenLP.Ui', 'Default Color:')
self.Delete = translate('OpenLP.Ui', '&Delete')
self.DisplayStyle = translate('OpenLP.Ui', 'Display style:')
self.Duplicate = translate('OpenLP.Ui', 'Duplicate Error')
self.Edit = translate('OpenLP.Ui', '&Edit')
self.EmptyField = translate('OpenLP.Ui', 'Empty Field')
self.Error = translate('OpenLP.Ui', 'Error')
self.Export = translate('OpenLP.Ui', 'Export')
self.File = translate('OpenLP.Ui', 'File')
self.FontSizePtUnit = translate('OpenLP.Ui', 'pt', 'Abbreviated font pointsize unit')
self.Help = translate('OpenLP.Ui', 'Help')
self.Hours = translate('OpenLP.Ui', 'h', 'The abbreviated unit for hours')
self.IFdSs = translate('OpenLP.Ui', 'Invalid Folder Selected', 'Singular')
self.IFSs = translate('OpenLP.Ui', 'Invalid File Selected', 'Singular')
self.IFSp = translate('OpenLP.Ui', 'Invalid Files Selected', 'Plural')
self.Image = translate('OpenLP.Ui', 'Image')
self.Import = translate('OpenLP.Ui', 'Import')
self.LayoutStyle = translate('OpenLP.Ui', 'Layout style:')
self.Live = translate('OpenLP.Ui', 'Live')
self.LiveBGError = translate('OpenLP.Ui', 'Live Background Error')
self.LiveToolbar = translate('OpenLP.Ui', 'Live Toolbar')
self.Load = translate('OpenLP.Ui', 'Load')
self.Minutes = translate('OpenLP.Ui', 'm', 'The abbreviated unit for minutes')
self.Middle = translate('OpenLP.Ui', 'Middle')
self.New = translate('OpenLP.Ui', 'New')
self.NewService = translate('OpenLP.Ui', 'New Service')
self.NewTheme = translate('OpenLP.Ui', 'New Theme')
self.NextTrack = translate('OpenLP.Ui', 'Next Track')
self.NFdSs = translate('OpenLP.Ui', 'No Folder Selected', 'Singular')
self.NFSs = translate('OpenLP.Ui', 'No File Selected', 'Singular')
self.NFSp = translate('OpenLP.Ui', 'No Files Selected', 'Plural')
self.NISs = translate('OpenLP.Ui', 'No Item Selected', 'Singular')
self.NISp = translate('OpenLP.Ui', 'No Items Selected', 'Plural')
self.OLPV1 = translate('OpenLP.Ui', 'openlp.org 1.x')
self.OLPV2 = translate('OpenLP.Ui', 'OpenLP 2')
self.OLPV2x = translate('OpenLP.Ui', 'OpenLP 2.1')
self.OpenLPStart = translate('OpenLP.Ui', 'OpenLP is already running. Do you wish to continue?')
self.OpenService = translate('OpenLP.Ui', 'Open service.')
self.PlaySlidesInLoop = translate('OpenLP.Ui','Play Slides in Loop')
self.PlaySlidesToEnd = translate('OpenLP.Ui','Play Slides to End')
self.Preview = translate('OpenLP.Ui', 'Preview')
self.PrintService = translate('OpenLP.Ui', 'Print Service')
self.ReplaceBG = translate('OpenLP.Ui', 'Replace Background')
self.ReplaceLiveBG = translate('OpenLP.Ui', 'Replace live background.')
self.ResetBG = translate('OpenLP.Ui', 'Reset Background')
self.ResetLiveBG = translate('OpenLP.Ui', 'Reset live background.')
self.Seconds = translate('OpenLP.Ui', 's', 'The abbreviated unit for seconds')
self.SaveAndPreview = translate('OpenLP.Ui', 'Save && Preview')
self.Search = translate('OpenLP.Ui', 'Search')
self.SearchThemes = translate('OpenLP.Ui', 'Search Themes...', 'Search bar place holder text ')
self.SelectDelete = translate('OpenLP.Ui', 'You must select an item to delete.')
self.SelectEdit = translate('OpenLP.Ui', 'You must select an item to edit.')
self.Settings = translate('OpenLP.Ui', 'Settings')
self.SaveService = translate('OpenLP.Ui', 'Save Service')
self.Service = translate('OpenLP.Ui', 'Service')
self.Split = translate('OpenLP.Ui', 'Optional &Split')
self.SplitToolTip = translate('OpenLP.Ui',
'Split a slide into two only if it does not fit on the screen as one slide.')
self.StartTimeCode = translate('OpenLP.Ui', 'Start %s')
self.StopPlaySlidesInLoop = translate('OpenLP.Ui', 'Stop Play Slides in Loop')
self.StopPlaySlidesToEnd = translate('OpenLP.Ui', 'Stop Play Slides to End')
self.Theme = translate('OpenLP.Ui', 'Theme', 'Singular')
self.Themes = translate('OpenLP.Ui', 'Themes', 'Plural')
self.Tools = translate('OpenLP.Ui', 'Tools')
self.Top = translate('OpenLP.Ui', 'Top')
self.UnsupportedFile = translate('OpenLP.Ui', 'Unsupported File')
self.VersePerSlide = translate('OpenLP.Ui', 'Verse Per Slide')
self.VersePerLine = translate('OpenLP.Ui', 'Verse Per Line')
self.Version = translate('OpenLP.Ui', 'Version')
self.View = translate('OpenLP.Ui', 'View')
self.ViewMode = translate('OpenLP.Ui', 'View Mode')
def add_welcome_page(parent, image): def add_welcome_page(parent, image):
""" """
@ -171,7 +67,7 @@ def add_welcome_page(parent, image):
parent.addPage(parent.welcomePage) parent.addPage(parent.welcomePage)
def create_button_box(dialog, name, standard_buttons, custom_buttons=[]): def create_button_box(dialog, name, standard_buttons, custom_buttons=None):
""" """
Creates a QDialogButtonBox with the given buttons. The ``accepted()`` and Creates a QDialogButtonBox with the given buttons. The ``accepted()`` and
``rejected()`` signals of the button box are connected with the dialogs ``rejected()`` signals of the button box are connected with the dialogs
@ -192,6 +88,8 @@ def create_button_box(dialog, name, standard_buttons, custom_buttons=[]):
QtGui.QAbstractButton it is added with QDialogButtonBox.ActionRole. QtGui.QAbstractButton it is added with QDialogButtonBox.ActionRole.
Otherwhise the item has to be a tuple of a button and a ButtonRole. Otherwhise the item has to be a tuple of a button and a ButtonRole.
""" """
if custom_buttons is None:
custom_buttons = []
buttons = QtGui.QDialogButtonBox.NoButton buttons = QtGui.QDialogButtonBox.NoButton
if u'ok' in standard_buttons: if u'ok' in standard_buttons:
buttons |= QtGui.QDialogButtonBox.Ok buttons |= QtGui.QDialogButtonBox.Ok

View File

@ -0,0 +1,146 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2013 Raoul Snyman #
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`uistrings` module provides standard strings for OpenLP.
"""
import logging
from openlp.core.lib import translate
log = logging.getLogger(__name__)
class UiStrings(object):
"""
Provide standard strings for objects to use.
"""
__instance__ = None
def __new__(cls):
"""
Override the default object creation method to return a single instance.
"""
if not cls.__instance__:
cls.__instance__ = object.__new__(cls)
return cls.__instance__
def __init__(self):
"""
These strings should need a good reason to be retranslated elsewhere.
Should some/more/less of these have an &amp; attached?
"""
self.About = translate('OpenLP.Ui', 'About')
self.Add = translate('OpenLP.Ui', '&Add')
self.Advanced = translate('OpenLP.Ui', 'Advanced')
self.AllFiles = translate('OpenLP.Ui', 'All Files')
self.Automatic = translate('OpenLP.Ui', 'Automatic')
self.BackgroundColor = translate('OpenLP.Ui', 'Background Color')
self.Bottom = translate('OpenLP.Ui', 'Bottom')
self.Browse = translate('OpenLP.Ui', 'Browse...')
self.Cancel = translate('OpenLP.Ui', 'Cancel')
self.CCLINumberLabel = translate('OpenLP.Ui', 'CCLI number:')
self.CreateService = translate('OpenLP.Ui', 'Create a new service.')
self.ConfirmDelete = translate('OpenLP.Ui', 'Confirm Delete')
self.Continuous = translate('OpenLP.Ui', 'Continuous')
self.Default = translate('OpenLP.Ui', 'Default')
self.DefaultColor = translate('OpenLP.Ui', 'Default Color:')
self.DefaultServiceName = translate('OpenLP.Ui', 'Service %Y-%m-%d %H-%M',
'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.Delete = translate('OpenLP.Ui', '&Delete')
self.DisplayStyle = translate('OpenLP.Ui', 'Display style:')
self.Duplicate = translate('OpenLP.Ui', 'Duplicate Error')
self.Edit = translate('OpenLP.Ui', '&Edit')
self.EmptyField = translate('OpenLP.Ui', 'Empty Field')
self.Error = translate('OpenLP.Ui', 'Error')
self.Export = translate('OpenLP.Ui', 'Export')
self.File = translate('OpenLP.Ui', 'File')
self.FontSizePtUnit = translate('OpenLP.Ui', 'pt', 'Abbreviated font pointsize unit')
self.Help = translate('OpenLP.Ui', 'Help')
self.Hours = translate('OpenLP.Ui', 'h', 'The abbreviated unit for hours')
self.IFdSs = translate('OpenLP.Ui', 'Invalid Folder Selected', 'Singular')
self.IFSs = translate('OpenLP.Ui', 'Invalid File Selected', 'Singular')
self.IFSp = translate('OpenLP.Ui', 'Invalid Files Selected', 'Plural')
self.Image = translate('OpenLP.Ui', 'Image')
self.Import = translate('OpenLP.Ui', 'Import')
self.LayoutStyle = translate('OpenLP.Ui', 'Layout style:')
self.Live = translate('OpenLP.Ui', 'Live')
self.LiveBGError = translate('OpenLP.Ui', 'Live Background Error')
self.LiveToolbar = translate('OpenLP.Ui', 'Live Toolbar')
self.Load = translate('OpenLP.Ui', 'Load')
self.Minutes = translate('OpenLP.Ui', 'm', 'The abbreviated unit for minutes')
self.Middle = translate('OpenLP.Ui', 'Middle')
self.New = translate('OpenLP.Ui', 'New')
self.NewService = translate('OpenLP.Ui', 'New Service')
self.NewTheme = translate('OpenLP.Ui', 'New Theme')
self.NextTrack = translate('OpenLP.Ui', 'Next Track')
self.NFdSs = translate('OpenLP.Ui', 'No Folder Selected', 'Singular')
self.NFSs = translate('OpenLP.Ui', 'No File Selected', 'Singular')
self.NFSp = translate('OpenLP.Ui', 'No Files Selected', 'Plural')
self.NISs = translate('OpenLP.Ui', 'No Item Selected', 'Singular')
self.NISp = translate('OpenLP.Ui', 'No Items Selected', 'Plural')
self.OLPV1 = translate('OpenLP.Ui', 'openlp.org 1.x')
self.OLPV2 = translate('OpenLP.Ui', 'OpenLP 2')
self.OLPV2x = translate('OpenLP.Ui', 'OpenLP 2.1')
self.OpenLPStart = translate('OpenLP.Ui', 'OpenLP is already running. Do you wish to continue?')
self.OpenService = translate('OpenLP.Ui', 'Open service.')
self.PlaySlidesInLoop = translate('OpenLP.Ui', 'Play Slides in Loop')
self.PlaySlidesToEnd = translate('OpenLP.Ui', 'Play Slides to End')
self.Preview = translate('OpenLP.Ui', 'Preview')
self.PrintService = translate('OpenLP.Ui', 'Print Service')
self.ReplaceBG = translate('OpenLP.Ui', 'Replace Background')
self.ReplaceLiveBG = translate('OpenLP.Ui', 'Replace live background.')
self.ResetBG = translate('OpenLP.Ui', 'Reset Background')
self.ResetLiveBG = translate('OpenLP.Ui', 'Reset live background.')
self.Seconds = translate('OpenLP.Ui', 's', 'The abbreviated unit for seconds')
self.SaveAndPreview = translate('OpenLP.Ui', 'Save && Preview')
self.Search = translate('OpenLP.Ui', 'Search')
self.SearchThemes = translate('OpenLP.Ui', 'Search Themes...', 'Search bar place holder text ')
self.SelectDelete = translate('OpenLP.Ui', 'You must select an item to delete.')
self.SelectEdit = translate('OpenLP.Ui', 'You must select an item to edit.')
self.Settings = translate('OpenLP.Ui', 'Settings')
self.SaveService = translate('OpenLP.Ui', 'Save Service')
self.Service = translate('OpenLP.Ui', 'Service')
self.Split = translate('OpenLP.Ui', 'Optional &Split')
self.SplitToolTip = translate('OpenLP.Ui',
'Split a slide into two only if it does not fit on the screen as one slide.')
self.StartTimeCode = translate('OpenLP.Ui', 'Start %s')
self.StopPlaySlidesInLoop = translate('OpenLP.Ui', 'Stop Play Slides in Loop')
self.StopPlaySlidesToEnd = translate('OpenLP.Ui', 'Stop Play Slides to End')
self.Theme = translate('OpenLP.Ui', 'Theme', 'Singular')
self.Themes = translate('OpenLP.Ui', 'Themes', 'Plural')
self.Tools = translate('OpenLP.Ui', 'Tools')
self.Top = translate('OpenLP.Ui', 'Top')
self.UnsupportedFile = translate('OpenLP.Ui', 'Unsupported File')
self.VersePerSlide = translate('OpenLP.Ui', 'Verse Per Slide')
self.VersePerLine = translate('OpenLP.Ui', 'Verse Per Line')
self.Version = translate('OpenLP.Ui', 'Version')
self.View = translate('OpenLP.Ui', 'View')
self.ViewMode = translate('OpenLP.Ui', 'View Mode')

View File

@ -26,5 +26,11 @@
# 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 #
############################################################################### ###############################################################################
"""
The :mod:`~openlp.core.theme` module contains all the themeing functions used by
OpenLP when displaying a song or a scripture.
"""
from openlp.core.theme.theme import Theme from openlp.core.theme.theme import Theme
__all__ = ['Theme']

View File

@ -37,11 +37,21 @@ from xml.etree.ElementTree import ElementTree, XML
from PyQt4 import QtGui from PyQt4 import QtGui
DELPHI_COLORS = { DELPHI_COLORS = {
u'clAqua': 0x00FFFF, u'clBlack': 0x000000, u'clBlue': 0x0000FF, u'clAqua': 0x00FFFF,
u'clFuchsia': 0xFF00FF, u'clGray': 0x808080, u'clGreen': 0x008000, u'clBlack': 0x000000,
u'clLime': 0x00FF00, u'clMaroon': 0x800000, u'clNavy': 0x000080, u'clBlue': 0x0000FF,
u'clOlive': 0x808000, u'clPurple': 0x800080, u'clRed': 0xFF0000, u'clFuchsia': 0xFF00FF,
u'clSilver': 0xC0C0C0, u'clTeal': 0x008080, u'clWhite': 0xFFFFFF, u'clGray': 0x808080,
u'clGreen': 0x008000,
u'clLime': 0x00FF00,
u'clMaroon': 0x800000,
u'clNavy': 0x000080,
u'clOlive': 0x808000,
u'clPurple': 0x800080,
u'clRed': 0xFF0000,
u'clSilver': 0xC0C0C0,
u'clTeal': 0x008080,
u'clWhite': 0xFFFFFF,
u'clYellow': 0xFFFF00 u'clYellow': 0xFFFF00
} }
@ -66,6 +76,7 @@ BLANK_STYLE_XML = \
</Theme> </Theme>
''' '''
class Theme(object): class Theme(object):
""" """
Provide a class wrapper storing data from an XML theme Provide a class wrapper storing data from an XML theme
@ -164,6 +175,7 @@ class Theme(object):
* ``0`` - normal * ``0`` - normal
* ``1`` - lyrics * ``1`` - lyrics
""" """
def __init__(self, xml): def __init__(self, xml):
""" """
Initialise a theme with data from xml Initialise a theme with data from xml
@ -205,10 +217,12 @@ class Theme(object):
val = element_text val = element_text
# strings need special handling to sort the colours out # strings need special handling to sort the colours out
if isinstance(element_text, basestring): if isinstance(element_text, basestring):
if element_text[0] == u'$': # might be a hex number if element_text[0] == u'$':
# might be a hex number
try: try:
val = int(element_text[1:], 16) val = int(element_text[1:], 16)
except ValueError: # nope except ValueError:
# nope
pass pass
elif element_text in DELPHI_COLORS: elif element_text in DELPHI_COLORS:
val = DELPHI_COLORS[element_text] val = DELPHI_COLORS[element_text]
@ -222,9 +236,9 @@ class Theme(object):
isinstance(val, int))): isinstance(val, int))):
# convert to a wx.Colour # convert to a wx.Colour
if not delphi_color_change: if not delphi_color_change:
val = QtGui.QColor(val&0xFF, (val>>8)&0xFF, (val>>16)&0xFF) val = QtGui.QColor(val & 0xFF, (val >> 8) & 0xFF, (val >> 16) & 0xFF)
else: else:
val = QtGui.QColor((val>>16)&0xFF, (val>>8)&0xFF, val&0xFF) val = QtGui.QColor((val >> 16) & 0xFF, (val >> 8) & 0xFF, val & 0xFF)
setattr(self, element.tag, val) setattr(self, element.tag, val)
def __str__(self): def __str__(self):

View File

@ -29,35 +29,30 @@
""" """
The :mod:`ui` module provides the core user interface for OpenLP The :mod:`ui` module provides the core user interface for OpenLP
""" """
from PyQt4 import QtGui
from openlp.core.lib import translate
class HideMode(object): class HideMode(object):
""" """
This is an enumeration class which specifies the different modes of hiding This is an enumeration class which specifies the different modes of hiding the display.
the display.
``Blank`` ``Blank``
This mode is used to hide all output, specifically by covering the This mode is used to hide all output, specifically by covering the display with a black screen.
display with a black screen.
``Theme`` ``Theme``
This mode is used to hide all output, but covers the display with the This mode is used to hide all output, but covers the display with the current theme background, as opposed to
current theme background, as opposed to black. black.
``Desktop`` ``Desktop``
This mode hides all output by minimising the display, leaving the user's This mode hides all output by minimising the display, leaving the user's desktop showing.
desktop showing.
""" """
Blank = 1 Blank = 1
Theme = 2 Theme = 2
Screen = 3 Screen = 3
class AlertLocation(object): class AlertLocation(object):
""" """
This is an enumeration class which controls where Alerts are placed on the This is an enumeration class which controls where Alerts are placed on the screen.
screen.
``Top`` ``Top``
Place the text at the top of the screen. Place the text at the top of the screen.
@ -72,10 +67,10 @@ class AlertLocation(object):
Middle = 1 Middle = 1
Bottom = 2 Bottom = 2
class DisplayControllerType(object): class DisplayControllerType(object):
""" """
This is an enumeration class which says where a display controller This is an enumeration class which says where a display controller originated from.
originated from.
""" """
Live = 0 Live = 0
Preview = 1 Preview = 1
@ -88,7 +83,6 @@ from themelayoutform import ThemeLayoutForm
from themeform import ThemeForm from themeform import ThemeForm
from filerenameform import FileRenameForm from filerenameform import FileRenameForm
from starttimeform import StartTimeForm from starttimeform import StartTimeForm
from screen import ScreenList
from maindisplay import MainDisplay, Display from maindisplay import MainDisplay, Display
from servicenoteform import ServiceNoteForm from servicenoteform import ServiceNoteForm
from serviceitemeditform import ServiceItemEditForm from serviceitemeditform import ServiceItemEditForm
@ -106,6 +100,8 @@ from mediadockmanager import MediaDockManager
from servicemanager import ServiceManager from servicemanager import ServiceManager
from thememanager import ThemeManager from thememanager import ThemeManager
__all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainDisplay', __all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainDisplay', 'SlideController', 'ServiceManager',
'SlideController', 'ServiceManager', 'ThemeManager', 'MediaDockManager', 'ThemeManager', 'MediaDockManager', 'ServiceItemEditForm', 'FirstTimeForm', 'FirstTimeLanguageForm', 'ThemeForm',
'ServiceItemEditForm', 'FirstTimeForm'] 'ThemeLayoutForm', 'FileRenameForm', 'StartTimeForm', 'MainDisplay', 'Display', 'ServiceNoteForm',
'SlideController', 'DisplayController', 'GeneralTab', 'ThemesTab', 'AdvancedTab', 'PluginForm',
'FormattingTagForm', 'ShortcutListForm']

View File

@ -29,11 +29,19 @@
from PyQt4 import QtGui from PyQt4 import QtGui
from openlp.core.lib import build_icon, translate from openlp.core.lib import UiStrings, build_icon, translate
from openlp.core.lib.ui import UiStrings, create_button, create_button_box from openlp.core.lib.ui import create_button, create_button_box
class Ui_AboutDialog(object): class Ui_AboutDialog(object):
"""
The actual GUI widgets for the About form.
"""
def setupUi(self, aboutDialog): def setupUi(self, aboutDialog):
"""
Set up the UI for the dialog.
"""
aboutDialog.setObjectName(u'aboutDialog') aboutDialog.setObjectName(u'aboutDialog')
aboutDialog.setWindowIcon(build_icon(u':/icon/openlp-logo-16x16.png')) aboutDialog.setWindowIcon(build_icon(u':/icon/openlp-logo-16x16.png'))
self.aboutDialogLayout = QtGui.QVBoxLayout(aboutDialog) self.aboutDialogLayout = QtGui.QVBoxLayout(aboutDialog)
@ -73,12 +81,15 @@ class Ui_AboutDialog(object):
self.aboutNotebook.addTab(self.licenseTab, u'') self.aboutNotebook.addTab(self.licenseTab, u'')
self.aboutDialogLayout.addWidget(self.aboutNotebook) self.aboutDialogLayout.addWidget(self.aboutNotebook)
self.volunteerButton = create_button(None, u'volunteerButton', icon=u':/system/system_volunteer.png') self.volunteerButton = create_button(None, u'volunteerButton', icon=u':/system/system_volunteer.png')
self.buttonBox = create_button_box(aboutDialog, u'buttonBox', [u'close'], [self.volunteerButton]) self.button_box = create_button_box(aboutDialog, u'button_box', [u'close'], [self.volunteerButton])
self.aboutDialogLayout.addWidget(self.buttonBox) self.aboutDialogLayout.addWidget(self.button_box)
self.retranslateUi(aboutDialog) self.retranslateUi(aboutDialog)
self.aboutNotebook.setCurrentIndex(0) self.aboutNotebook.setCurrentIndex(0)
def retranslateUi(self, aboutDialog): def retranslateUi(self, aboutDialog):
"""
Dynamically translate the UI.
"""
aboutDialog.setWindowTitle(u'%s OpenLP' % UiStrings().About) aboutDialog.setWindowTitle(u'%s OpenLP' % UiStrings().About)
self.aboutTextEdit.setPlainText(translate('OpenLP.AboutForm', self.aboutTextEdit.setPlainText(translate('OpenLP.AboutForm',
'OpenLP <version><revision> - Open Source Lyrics ' 'OpenLP <version><revision> - Open Source Lyrics '
@ -133,17 +144,17 @@ class Ui_AboutDialog(object):
u'en_ZA': [u'Raoul "superfly" Snyman', u'en_ZA': [u'Raoul "superfly" Snyman',
u'Johan "nuvolari" Mynhardt'], u'Johan "nuvolari" Mynhardt'],
u'el': [u'Alexander Siozos'], u'el': [u'Alexander Siozos'],
u'es': [u'Josu\xe9 Z\xfa\xf1iga',u'Christian Gonzalez'], u'es': [u'Josu\xe9 Z\xfa\xf1iga', u'Christian Gonzalez'],
u'et': [u'Mattias "mahfiaz" P\xf5ldaru'], u'et': [u'Mattias "mahfiaz" P\xf5ldaru'],
u'fi': [u'Jori "joribu" Brander', u'Tobbe "tobbeb" Bildo'], u'fi': [u'Jori "joribu" Brander', u'Tobbe "tobbeb" Bildo'],
u'fr': [u'Stephan\xe9 "stbrunner" Brunner', u'Jeremie "jnau05"', u'fr': [u'Stephan\xe9 "stbrunner" Brunner', u'Jeremie "jnau05"',
u'Carl "carl.fischer" Fischer'], u'Carl "carl.fischer" Fischer'],
u'hu': [u'Gyuris Gell\xe9rt'], u'hu': [u'Gyuris Gell\xe9rt'],
u'id': [u'Mico "bangmico" Siahaan' ,u' ign_christian'], u'id': [u'Mico "bangmico" Siahaan', u' ign_christian'],
u'ja': [u'Kunio "Kunio" Nakamaru', u'Chris Haris'], u'ja': [u'Kunio "Kunio" Nakamaru', u'Chris Haris'],
u'nb': [u'Atle "pendlaren" Weibell', u'Frode "frodus" Woldsund'], u'nb': [u'Atle "pendlaren" Weibell', u'Frode "frodus" Woldsund'],
u'nl': [u'Arjen "typovar" van Voorst'], u'nl': [u'Arjen "typovar" van Voorst'],
u'pt_BR': [u'David Mederiros',u'Rafael "rafaellerm" Lerm', u'pt_BR': [u'David Mederiros', u'Rafael "rafaellerm" Lerm',
u'Eduardo Levi Chaves', u'Eduardo Levi Chaves',
u'Gustavo Bim', u'Rog\xeanio Bel\xe9m', u'Samuel' u'Gustavo Bim', u'Rog\xeanio Bel\xe9m', u'Samuel'
u'Simon "samscudder" Scudder', u'Van Der Fran'], u'Simon "samscudder" Scudder', u'Van Der Fran'],
@ -259,7 +270,7 @@ class Ui_AboutDialog(object):
u'\n '.join(documentors))) u'\n '.join(documentors)))
self.aboutNotebook.setTabText(self.aboutNotebook.indexOf(self.creditsTab), self.aboutNotebook.setTabText(self.aboutNotebook.indexOf(self.creditsTab),
translate('OpenLP.AboutForm', 'Credits')) translate('OpenLP.AboutForm', 'Credits'))
copyright = translate('OpenLP.AboutForm', copyright_note = translate('OpenLP.AboutForm',
'Copyright \xa9 2004-2013 %s\n' 'Copyright \xa9 2004-2013 %s\n'
'Portions copyright \xa9 2004-2013 %s') % (u'Raoul Snyman', 'Portions copyright \xa9 2004-2013 %s') % (u'Raoul Snyman',
u'Tim Bentley, Gerald Britton, Jonathan Corwin, Samuel Findlay, ' u'Tim Bentley, Gerald Britton, Jonathan Corwin, Samuel Findlay, '
@ -651,7 +662,7 @@ class Ui_AboutDialog(object):
'linking proprietary applications with the library. If this is ' 'linking proprietary applications with the library. If this is '
'what you want to do, use the GNU Lesser General Public License ' 'what you want to do, use the GNU Lesser General Public License '
'instead of this License.') 'instead of this License.')
self.licenseTextEdit.setPlainText(u'%s\n\n%s\n\n%s\n\n\n%s' % (copyright, licence, disclaimer, gpltext)) self.licenseTextEdit.setPlainText(u'%s\n\n%s\n\n%s\n\n\n%s' % (copyright_note, licence, disclaimer, gpltext))
self.aboutNotebook.setTabText(self.aboutNotebook.indexOf(self.licenseTab), self.aboutNotebook.setTabText(self.aboutNotebook.indexOf(self.licenseTab),
translate('OpenLP.AboutForm', 'License')) translate('OpenLP.AboutForm', 'License'))
self.volunteerButton.setText(translate('OpenLP.AboutForm', 'Volunteer')) self.volunteerButton.setText(translate('OpenLP.AboutForm', 'Volunteer'))

View File

@ -26,6 +26,9 @@
# 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 #
############################################################################### ###############################################################################
"""
The About dialog.
"""
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
@ -33,6 +36,7 @@ from aboutdialog import Ui_AboutDialog
from openlp.core.lib import translate from openlp.core.lib import translate
from openlp.core.utils import get_application_version from openlp.core.utils import get_application_version
class AboutForm(QtGui.QDialog, Ui_AboutDialog): class AboutForm(QtGui.QDialog, Ui_AboutDialog):
""" """
The About dialog The About dialog

File diff suppressed because it is too large Load Diff

View File

@ -26,14 +26,24 @@
# 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 #
############################################################################### ###############################################################################
"""
The GUI widgets of the exception dialog.
"""
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate, build_icon from openlp.core.lib import translate
from openlp.core.lib.ui import create_button, create_button_box from openlp.core.lib.ui import create_button, create_button_box
class Ui_ExceptionDialog(object): class Ui_ExceptionDialog(object):
"""
The GUI widgets of the exception dialog.
"""
def setupUi(self, exceptionDialog): def setupUi(self, exceptionDialog):
"""
Set up the UI.
"""
exceptionDialog.setObjectName(u'exceptionDialog') exceptionDialog.setObjectName(u'exceptionDialog')
self.exceptionLayout = QtGui.QVBoxLayout(exceptionDialog) self.exceptionLayout = QtGui.QVBoxLayout(exceptionDialog)
self.exceptionLayout.setObjectName(u'exceptionLayout') self.exceptionLayout.setObjectName(u'exceptionLayout')
@ -66,19 +76,22 @@ class Ui_ExceptionDialog(object):
self.exceptionLayout.addWidget(self.exceptionTextEdit) self.exceptionLayout.addWidget(self.exceptionTextEdit)
self.sendReportButton = create_button(exceptionDialog, u'sendReportButton', self.sendReportButton = create_button(exceptionDialog, u'sendReportButton',
icon=u':/general/general_email.png', click=self.onSendReportButtonClicked) icon=u':/general/general_email.png', click=self.onSendReportButtonClicked)
self.saveReportButton = create_button(exceptionDialog,u'saveReportButton', self.saveReportButton = create_button(exceptionDialog, u'saveReportButton',
icon=u':/general/general_save.png', click=self.onSaveReportButtonClicked) icon=u':/general/general_save.png', click=self.onSaveReportButtonClicked)
self.attachFileButton = create_button(exceptionDialog, u'attachFileButton', self.attachFileButton = create_button(exceptionDialog, u'attachFileButton',
icon=u':/general/general_open.png', click=self.onAttachFileButtonClicked) icon=u':/general/general_open.png', click=self.onAttachFileButtonClicked)
self.buttonBox = create_button_box(exceptionDialog, u'buttonBox', self.button_box = create_button_box(exceptionDialog, u'button_box',
[u'close'], [self.sendReportButton, self.saveReportButton, self.attachFileButton]) [u'close'], [self.sendReportButton, self.saveReportButton, self.attachFileButton])
self.exceptionLayout.addWidget(self.buttonBox) self.exceptionLayout.addWidget(self.button_box)
self.retranslateUi(exceptionDialog) self.retranslateUi(exceptionDialog)
QtCore.QObject.connect(self.descriptionTextEdit, QtCore.QObject.connect(self.descriptionTextEdit,
QtCore.SIGNAL(u'textChanged()'), self.onDescriptionUpdated) QtCore.SIGNAL(u'textChanged()'), self.onDescriptionUpdated)
def retranslateUi(self, exceptionDialog): def retranslateUi(self, exceptionDialog):
"""
Translate the widgets on the fly.
"""
exceptionDialog.setWindowTitle(translate('OpenLP.ExceptionDialog', 'Error Occurred')) exceptionDialog.setWindowTitle(translate('OpenLP.ExceptionDialog', 'Error Occurred'))
self.descriptionExplanation.setText(translate('OpenLP.ExceptionDialog', self.descriptionExplanation.setText(translate('OpenLP.ExceptionDialog',
'Please enter a description of what you were doing to cause this ' 'Please enter a description of what you were doing to cause this '

View File

@ -26,6 +26,9 @@
# 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 #
############################################################################### ###############################################################################
"""
The actual exception dialog form.
"""
import logging import logging
import re import re
import os import os
@ -85,30 +88,39 @@ except AttributeError:
WEBKIT_VERSION = u'-' WEBKIT_VERSION = u'-'
from openlp.core.lib import translate, SettingsManager from openlp.core.lib import UiStrings, Settings, translate
from openlp.core.lib.ui import UiStrings
from openlp.core.utils import get_application_version from openlp.core.utils import get_application_version
from exceptiondialog import Ui_ExceptionDialog from exceptiondialog import Ui_ExceptionDialog
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog): class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
""" """
The exception dialog The exception dialog
""" """
def __init__(self, parent): def __init__(self, parent):
"""
Constructor.
"""
QtGui.QDialog.__init__(self, parent) QtGui.QDialog.__init__(self, parent)
self.setupUi(self) self.setupUi(self)
self.settingsSection = u'crashreport' self.settingsSection = u'crashreport'
def exec_(self): def exec_(self):
"""
Show the dialog.
"""
self.descriptionTextEdit.setPlainText(u'') self.descriptionTextEdit.setPlainText(u'')
self.onDescriptionUpdated() self.onDescriptionUpdated()
self.fileAttachment = None self.fileAttachment = None
return QtGui.QDialog.exec_(self) return QtGui.QDialog.exec_(self)
def _createReport(self): def _createReport(self):
"""
Create an exception report.
"""
openlp_version = get_application_version() openlp_version = get_application_version()
description = self.descriptionTextEdit.toPlainText() description = self.descriptionTextEdit.toPlainText()
traceback = self.exceptionTextEdit.toPlainText() traceback = self.exceptionTextEdit.toPlainText()
@ -129,9 +141,9 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
u'pyUNO bridge: %s\n' % UNO_VERSION u'pyUNO bridge: %s\n' % UNO_VERSION
if platform.system() == u'Linux': if platform.system() == u'Linux':
if os.environ.get(u'KDE_FULL_SESSION') == u'true': if os.environ.get(u'KDE_FULL_SESSION') == u'true':
system = system + u'Desktop: KDE SC\n' system += u'Desktop: KDE SC\n'
elif os.environ.get(u'GNOME_DESKTOP_SESSION_ID'): elif os.environ.get(u'GNOME_DESKTOP_SESSION_ID'):
system = system + u'Desktop: GNOME\n' system += u'Desktop: GNOME\n'
return (openlp_version, description, traceback, system, libraries) return (openlp_version, description, traceback, system, libraries)
def onSaveReportButtonClicked(self): def onSaveReportButtonClicked(self):
@ -147,12 +159,12 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
'--- Library Versions ---\n%s\n') '--- Library Versions ---\n%s\n')
filename = QtGui.QFileDialog.getSaveFileName(self, filename = QtGui.QFileDialog.getSaveFileName(self,
translate('OpenLP.ExceptionForm', 'Save Crash Report'), translate('OpenLP.ExceptionForm', 'Save Crash Report'),
SettingsManager.get_last_dir(self.settingsSection), Settings().value(self.settingsSection + u'/last directory'),
translate('OpenLP.ExceptionForm', translate('OpenLP.ExceptionForm',
'Text files (*.txt *.log *.text)')) 'Text files (*.txt *.log *.text)'))
if filename: if filename:
filename = unicode(filename).replace(u'/', os.path.sep) filename = unicode(filename).replace(u'/', os.path.sep)
SettingsManager.set_last_dir(self.settingsSection, os.path.dirname(filename)) Settings().setValue(self.settingsSection + u'/last directory', os.path.dirname(filename))
report_text = report_text % self._createReport() report_text = report_text % self._createReport()
try: try:
report_file = open(filename, u'w') report_file = open(filename, u'w')
@ -200,6 +212,9 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
QtGui.QDesktopServices.openUrl(mailto_url) QtGui.QDesktopServices.openUrl(mailto_url)
def onDescriptionUpdated(self): def onDescriptionUpdated(self):
"""
Update the minimum number of characters needed in the description.
"""
count = int(20 - len(self.descriptionTextEdit.toPlainText())) count = int(20 - len(self.descriptionTextEdit.toPlainText()))
if count < 0: if count < 0:
count = 0 count = 0
@ -210,14 +225,19 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
translate('OpenLP.ExceptionDialog', 'Description characters to enter : %s') % count) translate('OpenLP.ExceptionDialog', 'Description characters to enter : %s') % count)
def onAttachFileButtonClicked(self): def onAttachFileButtonClicked(self):
"""
Attache files to the bug report e-mail.
"""
files = QtGui.QFileDialog.getOpenFileName( files = QtGui.QFileDialog.getOpenFileName(
self, translate('ImagePlugin.ExceptionDialog', 'Select Attachment'), self, translate('ImagePlugin.ExceptionDialog', 'Select Attachment'),
SettingsManager.get_last_dir(u'exceptions'), u'%s (*.*) (*)' % UiStrings().AllFiles) Settings().value(self.settingsSection + u'/last directory'), u'%s (*.*) (*)' % UiStrings().AllFiles)
log.info(u'New files(s) %s', unicode(files)) log.info(u'New files(s) %s', unicode(files))
if files: if files:
self.fileAttachment = unicode(files) self.fileAttachment = unicode(files)
def __buttonState(self, state): def __buttonState(self, state):
"""
Toggle the button state.
"""
self.saveReportButton.setEnabled(state) self.saveReportButton.setEnabled(state)
self.sendReportButton.setEnabled(state) self.sendReportButton.setEnabled(state)

View File

@ -26,18 +26,27 @@
# 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 #
############################################################################### ###############################################################################
"""
The UI widgets for the rename dialog
"""
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate from openlp.core.lib import translate
from openlp.core.lib.ui import create_button_box from openlp.core.lib.ui import create_button_box
class Ui_FileRenameDialog(object): class Ui_FileRenameDialog(object):
"""
The UI widgets for the rename dialog
"""
def setupUi(self, fileRenameDialog): def setupUi(self, fileRenameDialog):
"""
Set up the UI
"""
fileRenameDialog.setObjectName(u'fileRenameDialog') fileRenameDialog.setObjectName(u'fileRenameDialog')
fileRenameDialog.resize(300, 10) fileRenameDialog.resize(300, 10)
self.dialogLayout = QtGui.QGridLayout(fileRenameDialog) self.dialogLayout = QtGui.QGridLayout(fileRenameDialog)
self.dialogLayout.setObjectName(u'dialogLayout') self.dialogLayout.setObjectName(u'dialog_layout')
self.fileNameLabel = QtGui.QLabel(fileRenameDialog) self.fileNameLabel = QtGui.QLabel(fileRenameDialog)
self.fileNameLabel.setObjectName(u'fileNameLabel') self.fileNameLabel.setObjectName(u'fileNameLabel')
self.dialogLayout.addWidget(self.fileNameLabel, 0, 0) self.dialogLayout.addWidget(self.fileNameLabel, 0, 0)
@ -45,10 +54,13 @@ class Ui_FileRenameDialog(object):
self.fileNameEdit.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp(r'[^/\\?*|<>\[\]":+%]+'), self)) self.fileNameEdit.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp(r'[^/\\?*|<>\[\]":+%]+'), self))
self.fileNameEdit.setObjectName(u'fileNameEdit') self.fileNameEdit.setObjectName(u'fileNameEdit')
self.dialogLayout.addWidget(self.fileNameEdit, 0, 1) self.dialogLayout.addWidget(self.fileNameEdit, 0, 1)
self.buttonBox = create_button_box(fileRenameDialog, u'buttonBox', [u'cancel', u'ok']) self.button_box = create_button_box(fileRenameDialog, u'button_box', [u'cancel', u'ok'])
self.dialogLayout.addWidget(self.buttonBox, 1, 0, 1, 2) self.dialogLayout.addWidget(self.button_box, 1, 0, 1, 2)
self.retranslateUi(fileRenameDialog) self.retranslateUi(fileRenameDialog)
self.setMaximumHeight(self.sizeHint().height()) self.setMaximumHeight(self.sizeHint().height())
def retranslateUi(self, fileRenameDialog): def retranslateUi(self, fileRenameDialog):
"""
Translate the UI on the fly.
"""
self.fileNameLabel.setText(translate('OpenLP.FileRenameForm', 'New File Name:')) self.fileNameLabel.setText(translate('OpenLP.FileRenameForm', 'New File Name:'))

View File

@ -26,6 +26,9 @@
# 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 #
############################################################################### ###############################################################################
"""
The file rename dialog.
"""
from PyQt4 import QtGui from PyQt4 import QtGui
@ -33,11 +36,15 @@ from filerenamedialog import Ui_FileRenameDialog
from openlp.core.lib import translate from openlp.core.lib import translate
class FileRenameForm(QtGui.QDialog, Ui_FileRenameDialog): class FileRenameForm(QtGui.QDialog, Ui_FileRenameDialog):
""" """
The exception dialog The file rename dialog
""" """
def __init__(self, parent): def __init__(self, parent):
"""
Constructor
"""
QtGui.QDialog.__init__(self, parent) QtGui.QDialog.__init__(self, parent)
self.setupUi(self) self.setupUi(self)

View File

@ -26,7 +26,9 @@
# 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 #
############################################################################### ###############################################################################
"""
This module contains the first time wizard.
"""
import io import io
import logging import logging
import os import os
@ -39,20 +41,21 @@ from ConfigParser import SafeConfigParser
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate, PluginStatus, Receiver, build_icon, check_directory_exists, Settings from openlp.core.lib import PluginStatus, Receiver, Settings, Registry, build_icon, check_directory_exists, translate
from openlp.core.utils import get_web_page, AppLocation, get_filesystem_encoding from openlp.core.utils import AppLocation, get_web_page, get_filesystem_encoding
from firsttimewizard import Ui_FirstTimeWizard, FirstTimePage from firsttimewizard import Ui_FirstTimeWizard, FirstTimePage
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class ThemeScreenshotThread(QtCore.QThread): class ThemeScreenshotThread(QtCore.QThread):
""" """
This thread downloads the theme screenshots. This thread downloads the theme screenshots.
""" """
def __init__(self, parent):
QtCore.QThread.__init__(self, parent)
def run(self): def run(self):
"""
Overridden method to run the thread.
"""
themes = self.parent().config.get(u'themes', u'files') themes = self.parent().config.get(u'themes', u'files')
themes = themes.split(u',') themes = themes.split(u',')
config = self.parent().config config = self.parent().config
@ -79,7 +82,10 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
log.info(u'ThemeWizardForm loaded') log.info(u'ThemeWizardForm loaded')
def __init__(self, screens, parent=None): def __init__(self, screens, parent=None):
QtGui.QWizard.__init__(self, parent) """
Create and set up the first time wizard.
"""
super(FirstTimeForm, self).__init__(parent)
self.setupUi(self) self.setupUi(self)
self.screens = screens self.screens = screens
# check to see if we have web access # check to see if we have web access
@ -90,7 +96,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
files = self.webAccess.read() files = self.webAccess.read()
self.config.readfp(io.BytesIO(files)) self.config.readfp(io.BytesIO(files))
self.updateScreenListCombo() self.updateScreenListCombo()
self.downloadCancelled = False self.was_download_cancelled = False
self.downloading = translate('OpenLP.FirstTimeWizard', 'Downloading %s...') self.downloading = translate('OpenLP.FirstTimeWizard', 'Downloading %s...')
QtCore.QObject.connect(self.cancelButton, QtCore.SIGNAL('clicked()'), QtCore.QObject.connect(self.cancelButton, QtCore.SIGNAL('clicked()'),
self.onCancelButtonClicked) self.onCancelButtonClicked)
@ -116,7 +122,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
unicode(gettempdir(), get_filesystem_encoding()), u'openlp')) unicode(gettempdir(), get_filesystem_encoding()), u'openlp'))
self.noInternetFinishButton.setVisible(False) self.noInternetFinishButton.setVisible(False)
# Check if this is a re-run of the wizard. # Check if this is a re-run of the wizard.
self.hasRunWizard = Settings().value(u'general/has run wizard', False) self.hasRunWizard = Settings().value(u'general/has run wizard')
# Sort out internet access for downloads # Sort out internet access for downloads
if self.webAccess: if self.webAccess:
songs = self.config.get(u'songs', u'languages') songs = self.config.get(u'songs', u'languages')
@ -146,13 +152,13 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
# Download the theme screenshots. # Download the theme screenshots.
self.themeScreenshotThread = ThemeScreenshotThread(self) self.themeScreenshotThread = ThemeScreenshotThread(self)
self.themeScreenshotThread.start() self.themeScreenshotThread.start()
Receiver.send_message(u'cursor_normal') self.application.set_normal_cursor()
def nextId(self): def nextId(self):
""" """
Determine the next page in the Wizard to go to. Determine the next page in the Wizard to go to.
""" """
Receiver.send_message(u'openlp_process_events') self.application.process_events()
if self.currentId() == FirstTimePage.Plugins: if self.currentId() == FirstTimePage.Plugins:
if not self.webAccess: if not self.webAccess:
return FirstTimePage.NoInternet return FirstTimePage.NoInternet
@ -163,14 +169,13 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
elif self.currentId() == FirstTimePage.NoInternet: elif self.currentId() == FirstTimePage.NoInternet:
return FirstTimePage.Progress return FirstTimePage.Progress
elif self.currentId() == FirstTimePage.Themes: elif self.currentId() == FirstTimePage.Themes:
Receiver.send_message(u'cursor_busy') self.application.set_busy_cursor()
Receiver.send_message(u'openlp_process_events')
while not self.themeScreenshotThread.isFinished(): while not self.themeScreenshotThread.isFinished():
time.sleep(0.1) time.sleep(0.1)
Receiver.send_message(u'openlp_process_events') self.application.process_events()
# Build the screenshot icons, as this can not be done in the thread. # Build the screenshot icons, as this can not be done in the thread.
self._buildThemeScreenshots() self._buildThemeScreenshots()
Receiver.send_message(u'cursor_normal') self.application.set_normal_cursor()
return FirstTimePage.Defaults return FirstTimePage.Defaults
else: else:
return self.currentId() + 1 return self.currentId() + 1
@ -181,7 +186,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
""" """
# Keep track of the page we are at. Triggering "Cancel" causes pageId # Keep track of the page we are at. Triggering "Cancel" causes pageId
# to be a -1. # to be a -1.
Receiver.send_message(u'openlp_process_events') self.application.process_events()
if pageId != -1: if pageId != -1:
self.lastId = pageId self.lastId = pageId
if pageId == FirstTimePage.Plugins: if pageId == FirstTimePage.Plugins:
@ -198,11 +203,11 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self.themeComboBox.addItem(item.text()) self.themeComboBox.addItem(item.text())
if self.hasRunWizard: if self.hasRunWizard:
# Add any existing themes to list. # Add any existing themes to list.
for theme in self.parent().themeManagerContents.getThemes(): for theme in self.theme_manager.get_themes():
index = self.themeComboBox.findText(theme) index = self.themeComboBox.findText(theme)
if index == -1: if index == -1:
self.themeComboBox.addItem(theme) self.themeComboBox.addItem(theme)
default_theme = Settings().value(u'themes/global theme', u'') default_theme = Settings().value(u'themes/global theme')
# Pre-select the current default theme. # Pre-select the current default theme.
index = self.themeComboBox.findText(default_theme) index = self.themeComboBox.findText(default_theme)
self.themeComboBox.setCurrentIndex(index) self.themeComboBox.setCurrentIndex(index)
@ -213,16 +218,15 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
if self.hasRunWizard: if self.hasRunWizard:
self.cancelButton.setVisible(False) self.cancelButton.setVisible(False)
elif pageId == FirstTimePage.Progress: elif pageId == FirstTimePage.Progress:
Receiver.send_message(u'cursor_busy') self.application.set_busy_cursor()
self.repaint() self.repaint()
Receiver.send_message(u'openlp_process_events') self.application.process_events()
# Try to give the wizard a chance to redraw itself # Try to give the wizard a chance to redraw itself
time.sleep(0.2) time.sleep(0.2)
self._preWizard() self._preWizard()
self._performWizard() self._performWizard()
self._postWizard() self._postWizard()
Receiver.send_message(u'cursor_normal') self.application.set_normal_cursor()
Receiver.send_message(u'openlp_process_events')
def updateScreenListCombo(self): def updateScreenListCombo(self):
""" """
@ -241,19 +245,18 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
(self.lastId <= FirstTimePage.Plugins and not self.hasRunWizard): (self.lastId <= FirstTimePage.Plugins and not self.hasRunWizard):
QtCore.QCoreApplication.exit() QtCore.QCoreApplication.exit()
sys.exit() sys.exit()
self.downloadCancelled = True self.was_download_cancelled = True
while self.themeScreenshotThread.isRunning(): while self.themeScreenshotThread.isRunning():
time.sleep(0.1) time.sleep(0.1)
Receiver.send_message(u'cursor_normal') self.application.set_normal_cursor()
def onNoInternetFinishButtonClicked(self): def onNoInternetFinishButtonClicked(self):
""" """
Process the triggering of the "Finish" button on the No Internet page. Process the triggering of the "Finish" button on the No Internet page.
""" """
Receiver.send_message(u'cursor_busy') self.application.set_busy_cursor()
self._performWizard() self._performWizard()
Receiver.send_message(u'cursor_normal') self.application.set_normal_cursor()
Receiver.send_message(u'openlp_process_events')
Settings().setValue(u'general/has run wizard', True) Settings().setValue(u'general/has run wizard', True)
self.close() self.close()
@ -267,7 +270,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
urlfile = urllib2.urlopen(url) urlfile = urllib2.urlopen(url)
filename = open(fpath, "wb") filename = open(fpath, "wb")
# Download until finished or canceled. # Download until finished or canceled.
while not self.downloadCancelled: while not self.was_download_cancelled:
data = urlfile.read(block_size) data = urlfile.read(block_size)
if not data: if not data:
break break
@ -276,7 +279,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self._downloadProgress(block_count, block_size) self._downloadProgress(block_count, block_size)
filename.close() filename.close()
# Delete file if cancelled, it may be a partial file. # Delete file if cancelled, it may be a partial file.
if self.downloadCancelled: if self.was_download_cancelled:
os.remove(fpath) os.remove(fpath)
def _buildThemeScreenshots(self): def _buildThemeScreenshots(self):
@ -297,11 +300,20 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
screenshot))) screenshot)))
def _getFileSize(self, url): def _getFileSize(self, url):
"""
Get the size of a file.
``url``
The URL of the file we want to download.
"""
site = urllib.urlopen(url) site = urllib.urlopen(url)
meta = site.info() meta = site.info()
return int(meta.getheaders("Content-Length")[0]) return int(meta.getheaders("Content-Length")[0])
def _downloadProgress(self, count, block_size): def _downloadProgress(self, count, block_size):
"""
Calculate and display the download progress.
"""
increment = (count * block_size) - self.previous_size increment = (count * block_size) - self.previous_size
self._incrementProgressBar(None, increment) self._incrementProgressBar(None, increment)
self.previous_size = count * block_size self.previous_size = count * block_size
@ -320,7 +332,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self.progressLabel.setText(status_text) self.progressLabel.setText(status_text)
if increment > 0: if increment > 0:
self.progressBar.setValue(self.progressBar.value() + increment) self.progressBar.setValue(self.progressBar.value() + increment)
Receiver.send_message(u'openlp_process_events') self.application.process_events()
def _preWizard(self): def _preWizard(self):
""" """
@ -328,10 +340,10 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
""" """
self.max_progress = 0 self.max_progress = 0
self.finishButton.setVisible(False) self.finishButton.setVisible(False)
Receiver.send_message(u'openlp_process_events') self.application.process_events()
# Loop through the songs list and increase for each selected item # Loop through the songs list and increase for each selected item
for i in xrange(self.songsListWidget.count()): for i in xrange(self.songsListWidget.count()):
Receiver.send_message(u'openlp_process_events') self.application.process_events()
item = self.songsListWidget.item(i) item = self.songsListWidget.item(i)
if item.checkState() == QtCore.Qt.Checked: if item.checkState() == QtCore.Qt.Checked:
filename = item.data(QtCore.Qt.UserRole) filename = item.data(QtCore.Qt.UserRole)
@ -340,7 +352,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
# Loop through the Bibles list and increase for each selected item # Loop through the Bibles list and increase for each selected item
iterator = QtGui.QTreeWidgetItemIterator(self.biblesTreeWidget) iterator = QtGui.QTreeWidgetItemIterator(self.biblesTreeWidget)
while iterator.value(): while iterator.value():
Receiver.send_message(u'openlp_process_events') self.application.process_events()
item = iterator.value() item = iterator.value()
if item.parent() and item.checkState(0) == QtCore.Qt.Checked: if item.parent() and item.checkState(0) == QtCore.Qt.Checked:
filename = item.data(0, QtCore.Qt.UserRole) filename = item.data(0, QtCore.Qt.UserRole)
@ -349,7 +361,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
iterator += 1 iterator += 1
# Loop through the themes list and increase for each selected item # Loop through the themes list and increase for each selected item
for i in xrange(self.themesListWidget.count()): for i in xrange(self.themesListWidget.count()):
Receiver.send_message(u'openlp_process_events') self.application.process_events()
item = self.themesListWidget.item(i) item = self.themesListWidget.item(i)
if item.checkState() == QtCore.Qt.Checked: if item.checkState() == QtCore.Qt.Checked:
filename = item.data(QtCore.Qt.UserRole) filename = item.data(QtCore.Qt.UserRole)
@ -357,7 +369,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self.max_progress += size self.max_progress += size
if self.max_progress: if self.max_progress:
# Add on 2 for plugins status setting plus a "finished" point. # Add on 2 for plugins status setting plus a "finished" point.
self.max_progress = self.max_progress + 2 self.max_progress += 2
self.progressBar.setValue(0) self.progressBar.setValue(0)
self.progressBar.setMinimum(0) self.progressBar.setMinimum(0)
self.progressBar.setMaximum(self.max_progress) self.progressBar.setMaximum(self.max_progress)
@ -369,7 +381,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self.progressPage.setTitle(translate('OpenLP.FirstTimeWizard', 'Setting Up')) self.progressPage.setTitle(translate('OpenLP.FirstTimeWizard', 'Setting Up'))
self.progressPage.setSubTitle(u'Setup complete.') self.progressPage.setSubTitle(u'Setup complete.')
self.repaint() self.repaint()
Receiver.send_message(u'openlp_process_events') self.application.process_events()
# Try to give the wizard a chance to repaint itself # Try to give the wizard a chance to repaint itself
time.sleep(0.1) time.sleep(0.1)
@ -396,7 +408,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self.finishButton.setEnabled(True) self.finishButton.setEnabled(True)
self.cancelButton.setVisible(False) self.cancelButton.setVisible(False)
self.nextButton.setVisible(False) self.nextButton.setVisible(False)
Receiver.send_message(u'openlp_process_events') self.application.process_events()
def _performWizard(self): def _performWizard(self):
""" """
@ -459,5 +471,28 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
Settings().setValue(u'themes/global theme', self.themeComboBox.currentText()) Settings().setValue(u'themes/global theme', self.themeComboBox.currentText())
def _setPluginStatus(self, field, tag): def _setPluginStatus(self, field, tag):
"""
Set the status of a plugin.
"""
status = PluginStatus.Active if field.checkState() == QtCore.Qt.Checked else PluginStatus.Inactive status = PluginStatus.Active if field.checkState() == QtCore.Qt.Checked else PluginStatus.Inactive
Settings().setValue(tag, status) Settings().setValue(tag, status)
def _get_theme_manager(self):
"""
Adds the theme manager to the class dynamically
"""
if not hasattr(self, u'_theme_manager'):
self._theme_manager = Registry().get(u'theme_manager')
return self._theme_manager
theme_manager = property(_get_theme_manager)
def _get_application(self):
"""
Adds the openlp to the class dynamically
"""
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application)

View File

@ -26,20 +26,29 @@
# 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 #
############################################################################### ###############################################################################
"""
The UI widgets of the language selection dialog.
"""
from PyQt4 import QtGui from PyQt4 import QtGui
from openlp.core.lib import translate from openlp.core.lib import translate
from openlp.core.lib.ui import create_button_box from openlp.core.lib.ui import create_button_box
class Ui_FirstTimeLanguageDialog(object): class Ui_FirstTimeLanguageDialog(object):
"""
The UI widgets of the language selection dialog.
"""
def setupUi(self, languageDialog): def setupUi(self, languageDialog):
"""
Set up the UI.
"""
languageDialog.setObjectName(u'languageDialog') languageDialog.setObjectName(u'languageDialog')
languageDialog.resize(300, 50) languageDialog.resize(300, 50)
self.dialogLayout = QtGui.QVBoxLayout(languageDialog) self.dialogLayout = QtGui.QVBoxLayout(languageDialog)
self.dialogLayout.setContentsMargins(8, 8, 8, 8) self.dialogLayout.setContentsMargins(8, 8, 8, 8)
self.dialogLayout.setSpacing(8) self.dialogLayout.setSpacing(8)
self.dialogLayout.setObjectName(u'dialogLayout') self.dialogLayout.setObjectName(u'dialog_layout')
self.infoLabel = QtGui.QLabel(languageDialog) self.infoLabel = QtGui.QLabel(languageDialog)
self.infoLabel.setObjectName(u'infoLabel') self.infoLabel.setObjectName(u'infoLabel')
self.dialogLayout.addWidget(self.infoLabel) self.dialogLayout.addWidget(self.infoLabel)
@ -53,12 +62,15 @@ class Ui_FirstTimeLanguageDialog(object):
self.languageComboBox.setObjectName("languageComboBox") self.languageComboBox.setObjectName("languageComboBox")
self.languageLayout.addWidget(self.languageComboBox) self.languageLayout.addWidget(self.languageComboBox)
self.dialogLayout.addLayout(self.languageLayout) self.dialogLayout.addLayout(self.languageLayout)
self.buttonBox = create_button_box(languageDialog, u'buttonBox', [u'cancel', u'ok']) self.button_box = create_button_box(languageDialog, u'button_box', [u'cancel', u'ok'])
self.dialogLayout.addWidget(self.buttonBox) self.dialogLayout.addWidget(self.button_box)
self.retranslateUi(languageDialog) self.retranslateUi(languageDialog)
self.setMaximumHeight(self.sizeHint().height()) self.setMaximumHeight(self.sizeHint().height())
def retranslateUi(self, languageDialog): def retranslateUi(self, languageDialog):
"""
Translate the UI on the fly.
"""
self.setWindowTitle(translate('OpenLP.FirstTimeLanguageForm', 'Select Translation')) self.setWindowTitle(translate('OpenLP.FirstTimeLanguageForm', 'Select Translation'))
self.infoLabel.setText( self.infoLabel.setText(
translate('OpenLP.FirstTimeLanguageForm', 'Choose the translation you\'d like to use in OpenLP.')) translate('OpenLP.FirstTimeLanguageForm', 'Choose the translation you\'d like to use in OpenLP.'))

View File

@ -26,18 +26,24 @@
# 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 #
############################################################################### ###############################################################################
"""
The language selection dialog.
"""
from PyQt4 import QtGui from PyQt4 import QtGui
from openlp.core.lib.ui import create_action from openlp.core.lib.ui import create_action
from openlp.core.utils import LanguageManager from openlp.core.utils import LanguageManager
from firsttimelanguagedialog import Ui_FirstTimeLanguageDialog from firsttimelanguagedialog import Ui_FirstTimeLanguageDialog
class FirstTimeLanguageForm(QtGui.QDialog, Ui_FirstTimeLanguageDialog): class FirstTimeLanguageForm(QtGui.QDialog, Ui_FirstTimeLanguageDialog):
""" """
The exception dialog The language selection dialog.
""" """
def __init__(self, parent=None): def __init__(self, parent=None):
"""
Constructor
"""
QtGui.QDialog.__init__(self, parent) QtGui.QDialog.__init__(self, parent)
self.setupUi(self) self.setupUi(self)
self.qmList = LanguageManager.get_qm_list() self.qmList = LanguageManager.get_qm_list()
@ -52,6 +58,9 @@ class FirstTimeLanguageForm(QtGui.QDialog, Ui_FirstTimeLanguageDialog):
return QtGui.QDialog.exec_(self) return QtGui.QDialog.exec_(self)
def accept(self): def accept(self):
"""
Run when the dialog is OKed.
"""
# It's the first row so must be Automatic # It's the first row so must be Automatic
if self.languageComboBox.currentIndex() == 0: if self.languageComboBox.currentIndex() == 0:
LanguageManager.auto_language = True LanguageManager.auto_language = True
@ -63,6 +72,9 @@ class FirstTimeLanguageForm(QtGui.QDialog, Ui_FirstTimeLanguageDialog):
return QtGui.QDialog.accept(self) return QtGui.QDialog.accept(self)
def reject(self): def reject(self):
"""
Run when the dialog is canceled.
"""
LanguageManager.auto_language = True LanguageManager.auto_language = True
LanguageManager.set_language(False, False) LanguageManager.set_language(False, False)
return QtGui.QDialog.reject(self) return QtGui.QDialog.reject(self)

View File

@ -26,7 +26,9 @@
# 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 #
############################################################################### ###############################################################################
"""
The UI widgets for the first time wizard.
"""
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
import sys import sys
@ -34,7 +36,11 @@ import sys
from openlp.core.lib import translate from openlp.core.lib import translate
from openlp.core.lib.ui import add_welcome_page from openlp.core.lib.ui import add_welcome_page
class FirstTimePage(object): class FirstTimePage(object):
"""
An enumeration class with each of the pages of the wizard.
"""
Welcome = 0 Welcome = 0
Plugins = 1 Plugins = 1
NoInternet = 2 NoInternet = 2
@ -46,13 +52,19 @@ class FirstTimePage(object):
class Ui_FirstTimeWizard(object): class Ui_FirstTimeWizard(object):
"""
The UI widgets for the first time wizard.
"""
def setupUi(self, FirstTimeWizard): def setupUi(self, FirstTimeWizard):
"""
Set up the UI.
"""
FirstTimeWizard.setObjectName(u'FirstTimeWizard') FirstTimeWizard.setObjectName(u'FirstTimeWizard')
FirstTimeWizard.resize(550, 386) FirstTimeWizard.resize(550, 386)
FirstTimeWizard.setModal(True) FirstTimeWizard.setModal(True)
FirstTimeWizard.setWizardStyle(QtGui.QWizard.ModernStyle) FirstTimeWizard.setWizardStyle(QtGui.QWizard.ModernStyle)
FirstTimeWizard.setOptions(QtGui.QWizard.IndependentPages | QtGui.QWizard.NoBackButtonOnStartPage | FirstTimeWizard.setOptions(QtGui.QWizard.IndependentPages | QtGui.QWizard.NoBackButtonOnStartPage |
QtGui.QWizard.NoBackButtonOnLastPage |QtGui.QWizard.HaveCustomButton1) QtGui.QWizard.NoBackButtonOnLastPage | QtGui.QWizard.HaveCustomButton1)
self.finishButton = self.button(QtGui.QWizard.FinishButton) self.finishButton = self.button(QtGui.QWizard.FinishButton)
self.noInternetFinishButton = self.button(QtGui.QWizard.CustomButton1) self.noInternetFinishButton = self.button(QtGui.QWizard.CustomButton1)
self.cancelButton = self.button(QtGui.QWizard.CancelButton) self.cancelButton = self.button(QtGui.QWizard.CancelButton)
@ -193,17 +205,20 @@ class Ui_FirstTimeWizard(object):
self.retranslateUi(FirstTimeWizard) self.retranslateUi(FirstTimeWizard)
def retranslateUi(self, FirstTimeWizard): def retranslateUi(self, FirstTimeWizard):
"""
Translate the UI on the fly
"""
FirstTimeWizard.setWindowTitle(translate( FirstTimeWizard.setWindowTitle(translate(
'OpenLP.FirstTimeWizard', 'First Time Wizard')) 'OpenLP.FirstTimeWizard', 'First Time Wizard'))
self.titleLabel.setText(u'<span style="font-size:14pt; font-weight:600;">%s</span>' % \ self.titleLabel.setText(u'<span style="font-size:14pt; font-weight:600;">%s</span>' %
translate('OpenLP.FirstTimeWizard', 'Welcome to the First Time Wizard')) translate('OpenLP.FirstTimeWizard', 'Welcome to the First Time Wizard'))
self.informationLabel.setText(translate('OpenLP.FirstTimeWizard', self.informationLabel.setText(translate('OpenLP.FirstTimeWizard',
'This wizard will help you to configure OpenLP for initial use.' 'This wizard will help you to configure OpenLP for initial use.'
' Click the next button below to start.')) ' Click the next button below to start.'))
self.pluginPage.setTitle(translate('OpenLP.FirstTimeWizard', 'Activate required Plugins')) self.pluginPage.setTitle(translate('OpenLP.FirstTimeWizard', 'Activate required Plugins'))
self.pluginPage.setSubTitle(translate('OpenLP.FirstTimeWizard','Select the Plugins you wish to use. ')) self.pluginPage.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Select the Plugins you wish to use. '))
self.songsCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Songs')) self.songsCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Songs'))
self.customCheckBox.setText(translate('OpenLP.FirstTimeWizard','Custom Slides')) self.customCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Custom Slides'))
self.bibleCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Bible')) self.bibleCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Bible'))
self.imageCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Images')) self.imageCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Images'))
# TODO Presentation plugin is not yet working on Mac OS X. # TODO Presentation plugin is not yet working on Mac OS X.

View File

@ -26,15 +26,23 @@
# 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 #
############################################################################### ###############################################################################
"""
The UI widgets for the formatting tags window.
"""
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate from openlp.core.lib import UiStrings, translate
from openlp.core.lib.ui import UiStrings, create_button_box from openlp.core.lib.ui import create_button_box
class Ui_FormattingTagDialog(object): class Ui_FormattingTagDialog(object):
"""
The UI widgets for the formatting tags window.
"""
def setupUi(self, formattingTagDialog): def setupUi(self, formattingTagDialog):
"""
Set up the UI
"""
formattingTagDialog.setObjectName(u'formattingTagDialog') formattingTagDialog.setObjectName(u'formattingTagDialog')
formattingTagDialog.resize(725, 548) formattingTagDialog.resize(725, 548)
self.listdataGridLayout = QtGui.QGridLayout(formattingTagDialog) self.listdataGridLayout = QtGui.QGridLayout(formattingTagDialog)
@ -109,12 +117,15 @@ class Ui_FormattingTagDialog(object):
self.savePushButton.setObjectName(u'savePushButton') self.savePushButton.setObjectName(u'savePushButton')
self.dataGridLayout.addWidget(self.savePushButton, 4, 2, 1, 1) self.dataGridLayout.addWidget(self.savePushButton, 4, 2, 1, 1)
self.listdataGridLayout.addWidget(self.editGroupBox, 2, 0, 1, 1) self.listdataGridLayout.addWidget(self.editGroupBox, 2, 0, 1, 1)
self.buttonBox = create_button_box(formattingTagDialog, u'buttonBox', [u'close']) self.button_box = create_button_box(formattingTagDialog, u'button_box', [u'close'])
self.listdataGridLayout.addWidget(self.buttonBox, 3, 0, 1, 1) self.listdataGridLayout.addWidget(self.button_box, 3, 0, 1, 1)
self.retranslateUi(formattingTagDialog) self.retranslateUi(formattingTagDialog)
def retranslateUi(self, formattingTagDialog): def retranslateUi(self, formattingTagDialog):
"""
Translate the UI on the fly
"""
formattingTagDialog.setWindowTitle(translate('OpenLP.FormattingTagDialog', 'Configure Formatting Tags')) formattingTagDialog.setWindowTitle(translate('OpenLP.FormattingTagDialog', 'Configure Formatting Tags'))
self.editGroupBox.setTitle(translate('OpenLP.FormattingTagDialog', 'Edit Selection')) self.editGroupBox.setTitle(translate('OpenLP.FormattingTagDialog', 'Edit Selection'))
self.savePushButton.setText(translate('OpenLP.FormattingTagDialog', 'Save')) self.savePushButton.setText(translate('OpenLP.FormattingTagDialog', 'Save'))

View File

@ -27,14 +27,13 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
The :mod:`formattingtagform` provides an Tag Edit facility. The Base set are The :mod:`formattingtagform` provides an Tag Edit facility. The Base set are protected and included each time loaded.
protected and included each time loaded. Custom tags can be defined and saved. Custom tags can be defined and saved. The Custom Tag arrays are saved in a pickle so QSettings works on them. Base Tags
The Custom Tag arrays are saved in a pickle so QSettings works on them. Base cannot be changed.
Tags cannot be changed.
""" """
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate, FormattingTags from openlp.core.lib import FormattingTags, translate
from openlp.core.lib.ui import critical_error_message_box from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui.formattingtagdialog import Ui_FormattingTagDialog from openlp.core.ui.formattingtagdialog import Ui_FormattingTagDialog
@ -49,11 +48,11 @@ class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog):
""" """
QtGui.QDialog.__init__(self, parent) QtGui.QDialog.__init__(self, parent)
self.setupUi(self) self.setupUi(self)
QtCore.QObject.connect(self.tagTableWidget, QtCore.SIGNAL(u'itemSelectionChanged()'),self.onRowSelected) QtCore.QObject.connect(self.tagTableWidget, QtCore.SIGNAL(u'itemSelectionChanged()'), self.onRowSelected)
QtCore.QObject.connect(self.newPushButton, QtCore.SIGNAL(u'clicked()'), self.onNewClicked) QtCore.QObject.connect(self.newPushButton, QtCore.SIGNAL(u'clicked()'), self.onNewClicked)
QtCore.QObject.connect(self.savePushButton, QtCore.SIGNAL(u'clicked()'), self.onSavedClicked) QtCore.QObject.connect(self.savePushButton, QtCore.SIGNAL(u'clicked()'), self.onSavedClicked)
QtCore.QObject.connect(self.deletePushButton, QtCore.SIGNAL(u'clicked()'), self.onDeleteClicked) QtCore.QObject.connect(self.deletePushButton, QtCore.SIGNAL(u'clicked()'), self.onDeleteClicked)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(u'rejected()'), self.close) QtCore.QObject.connect(self.button_box, QtCore.SIGNAL(u'rejected()'), self.close)
QtCore.QObject.connect(self.descriptionLineEdit, QtCore.SIGNAL(u'textEdited(QString)'), self.onTextEdited) QtCore.QObject.connect(self.descriptionLineEdit, QtCore.SIGNAL(u'textEdited(QString)'), self.onTextEdited)
QtCore.QObject.connect(self.tagLineEdit, QtCore.SIGNAL(u'textEdited(QString)'), self.onTextEdited) QtCore.QObject.connect(self.tagLineEdit, QtCore.SIGNAL(u'textEdited(QString)'), self.onTextEdited)
QtCore.QObject.connect(self.startTagLineEdit, QtCore.SIGNAL(u'textEdited(QString)'), self.onTextEdited) QtCore.QObject.connect(self.startTagLineEdit, QtCore.SIGNAL(u'textEdited(QString)'), self.onTextEdited)

View File

@ -26,16 +26,18 @@
# 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 #
############################################################################### ###############################################################################
"""
The general tab of the configuration dialog.
"""
import logging import logging
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, Settings, SettingsTab, translate from openlp.core.lib import Receiver, Settings, SettingsTab, ScreenList, UiStrings, translate
from openlp.core.lib.ui import UiStrings
from openlp.core.ui import ScreenList
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class GeneralTab(SettingsTab): class GeneralTab(SettingsTab):
""" """
GeneralTab is the general settings tab in the settings dialog. GeneralTab is the general settings tab in the settings dialog.
@ -247,28 +249,28 @@ class GeneralTab(SettingsTab):
settings.beginGroup(self.settingsSection) settings.beginGroup(self.settingsSection)
self.monitorComboBox.clear() self.monitorComboBox.clear()
self.monitorComboBox.addItems(self.screens.get_screen_list()) self.monitorComboBox.addItems(self.screens.get_screen_list())
monitorNumber = settings.value(u'monitor', self.screens.display_count - 1) monitorNumber = settings.value(u'monitor')
self.monitorComboBox.setCurrentIndex(monitorNumber) self.monitorComboBox.setCurrentIndex(monitorNumber)
self.numberEdit.setText(settings.value(u'ccli number', u'')) self.numberEdit.setText(settings.value(u'ccli number'))
self.usernameEdit.setText(settings.value(u'songselect username', u'')) self.usernameEdit.setText(settings.value(u'songselect username'))
self.passwordEdit.setText(settings.value(u'songselect password', u'')) self.passwordEdit.setText(settings.value(u'songselect password'))
self.saveCheckServiceCheckBox.setChecked(settings.value(u'save prompt', False)) self.saveCheckServiceCheckBox.setChecked(settings.value(u'save prompt'))
self.autoUnblankCheckBox.setChecked(settings.value(u'auto unblank', False)) self.autoUnblankCheckBox.setChecked(settings.value(u'auto unblank'))
self.displayOnMonitorCheck.setChecked(self.screens.display) self.displayOnMonitorCheck.setChecked(self.screens.display)
self.warningCheckBox.setChecked(settings.value(u'blank warning', False)) self.warningCheckBox.setChecked(settings.value(u'blank warning'))
self.autoOpenCheckBox.setChecked(settings.value(u'auto open', False)) self.autoOpenCheckBox.setChecked(settings.value(u'auto open'))
self.showSplashCheckBox.setChecked(settings.value(u'show splash', True)) self.showSplashCheckBox.setChecked(settings.value(u'show splash'))
self.checkForUpdatesCheckBox.setChecked(settings.value(u'update check', True)) self.checkForUpdatesCheckBox.setChecked(settings.value(u'update check'))
self.autoPreviewCheckBox.setChecked(settings.value(u'auto preview', False)) self.autoPreviewCheckBox.setChecked(settings.value(u'auto preview'))
self.timeoutSpinBox.setValue(settings.value(u'loop delay', 5)) self.timeoutSpinBox.setValue(settings.value(u'loop delay'))
self.monitorRadioButton.setChecked(not settings.value(u'override position', False)) self.monitorRadioButton.setChecked(not settings.value(u'override position',))
self.overrideRadioButton.setChecked(settings.value(u'override position', False)) self.overrideRadioButton.setChecked(settings.value(u'override position'))
self.customXValueEdit.setValue(settings.value(u'x position', self.screens.current[u'size'].x())) self.customXValueEdit.setValue(settings.value(u'x position'))
self.customYValueEdit.setValue(settings.value(u'y position', self.screens.current[u'size'].y())) self.customYValueEdit.setValue(settings.value(u'y position'))
self.customHeightValueEdit.setValue(settings.value(u'height', self.screens.current[u'size'].height())) self.customHeightValueEdit.setValue(settings.value(u'height'))
self.customWidthValueEdit.setValue(settings.value(u'width', self.screens.current[u'size'].width())) self.customWidthValueEdit.setValue(settings.value(u'width'))
self.startPausedCheckBox.setChecked(settings.value(u'audio start paused', True)) self.startPausedCheckBox.setChecked(settings.value(u'audio start paused'))
self.repeatListCheckBox.setChecked(settings.value(u'audio repeat list', False)) self.repeatListCheckBox.setChecked(settings.value(u'audio repeat list'))
settings.endGroup() settings.endGroup()
self.monitorComboBox.setDisabled(self.overrideRadioButton.isChecked()) self.monitorComboBox.setDisabled(self.overrideRadioButton.isChecked())
self.customXValueEdit.setEnabled(self.overrideRadioButton.isChecked()) self.customXValueEdit.setEnabled(self.overrideRadioButton.isChecked())

View File

@ -27,27 +27,30 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
The :mod:`maindisplay` module provides the functionality to display screens The :mod:`maindisplay` module provides the functionality to display screens and play multimedia within OpenLP.
and play multimedia within OpenLP.
Some of the code for this form is based on the examples at:
* `http://www.steveheffernan.com/html5-video-player/demo-video-player.html`_
* `http://html5demos.com/two-videos`_
""" """
import cgi import cgi
import logging import logging
import os
import sys import sys
from PyQt4 import QtCore, QtGui, QtWebKit, QtOpenGL from PyQt4 import QtCore, QtGui, QtWebKit, QtOpenGL
from PyQt4.phonon import Phonon from PyQt4.phonon import Phonon
from openlp.core.lib import Receiver, build_html, ServiceItem, image_to_byte, translate, PluginManager, expand_tags,\ from openlp.core.lib import Receiver, ServiceItem, Settings, ImageSource, Registry, build_html, expand_tags, \
Settings, ImageSource image_to_byte, translate
from openlp.core.lib.theme import BackgroundType from openlp.core.lib.theme import BackgroundType
from openlp.core.ui import HideMode, ScreenList, AlertLocation from openlp.core.lib import ScreenList
from openlp.core.ui import HideMode, AlertLocation
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
#http://www.steveheffernan.com/html5-video-player/demo-video-player.html
#http://html5demos.com/two-videos
class Display(QtGui.QGraphicsView): class Display(QtGui.QGraphicsView):
""" """
@ -56,6 +59,9 @@ class Display(QtGui.QGraphicsView):
Preview display. Preview display.
""" """
def __init__(self, parent, live, controller): def __init__(self, parent, live, controller):
"""
Constructor
"""
if live: if live:
QtGui.QGraphicsView.__init__(self) QtGui.QGraphicsView.__init__(self)
# Overwrite the parent() method. # Overwrite the parent() method.
@ -65,7 +71,6 @@ class Display(QtGui.QGraphicsView):
self.isLive = live self.isLive = live
self.controller = controller self.controller = controller
self.screen = {} self.screen = {}
self.plugins = PluginManager.get_instance().plugins
# FIXME: On Mac OS X (tested on 10.7) the display screen is corrupt with # FIXME: On Mac OS X (tested on 10.7) the display screen is corrupt with
# OpenGL. Only white blank screen is shown on the 2nd monitor all the # OpenGL. Only white blank screen is shown on the 2nd monitor all the
# time. We need to investigate more how to use OpenGL properly on Mac OS # time. We need to investigate more how to use OpenGL properly on Mac OS
@ -101,6 +106,9 @@ class Display(QtGui.QGraphicsView):
QtCore.Qt.ScrollBarAlwaysOff) QtCore.Qt.ScrollBarAlwaysOff)
def resizeEvent(self, event): def resizeEvent(self, event):
"""
React to resizing of this display
"""
self.webView.setGeometry(0, 0, self.width(), self.height()) self.webView.setGeometry(0, 0, self.width(), self.height())
def isWebLoaded(self): def isWebLoaded(self):
@ -115,9 +123,11 @@ class MainDisplay(Display):
""" """
This is the display screen as a specialized class from the Display class This is the display screen as a specialized class from the Display class
""" """
def __init__(self, parent, imageManager, live, controller): def __init__(self, parent, live, controller):
"""
Constructor
"""
Display.__init__(self, parent, live, controller) Display.__init__(self, parent, live, controller)
self.imageManager = imageManager
self.screens = ScreenList() self.screens = ScreenList()
self.rebuildCSS = False self.rebuildCSS = False
self.hideMode = None self.hideMode = None
@ -131,18 +141,8 @@ class MainDisplay(Display):
self.firstTime = True self.firstTime = True
self.webLoaded = True self.webLoaded = True
self.setStyleSheet(u'border: 0px; margin: 0px; padding: 0px;') self.setStyleSheet(u'border: 0px; margin: 0px; padding: 0px;')
windowFlags = QtCore.Qt.FramelessWindowHint | QtCore.Qt.Tool | \ windowFlags = QtCore.Qt.FramelessWindowHint | QtCore.Qt.Tool | QtCore.Qt.WindowStaysOnTopHint
QtCore.Qt.WindowStaysOnTopHint if Settings().value(u'advanced/x11 bypass wm'):
# Fix for bug #1014422.
x11_bypass_default = True
if sys.platform.startswith(u'linux'):
# Default to False on Gnome.
x11_bypass_default = bool(not
os.environ.get(u'GNOME_DESKTOP_SESSION_ID'))
# Default to False on XFce
if os.environ.get(u'DESKTOP_SESSION') == u'xfce':
x11_bypass_default = False
if Settings().value(u'advanced/x11 bypass wm', x11_bypass_default):
windowFlags |= QtCore.Qt.X11BypassWindowManagerHint windowFlags |= QtCore.Qt.X11BypassWindowManagerHint
# TODO: The following combination of windowFlags works correctly # TODO: The following combination of windowFlags works correctly
# on Mac OS X. For next OpenLP version we should test it on other # on Mac OS X. For next OpenLP version we should test it on other
@ -164,6 +164,9 @@ class MainDisplay(Display):
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_updated'), self.configChanged) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_updated'), self.configChanged)
def setTransparency(self, enabled): def setTransparency(self, enabled):
"""
Set the transparency of the window
"""
if enabled: if enabled:
self.setAutoFillBackground(False) self.setAutoFillBackground(False)
else: else:
@ -182,8 +185,8 @@ class MainDisplay(Display):
Call the plugins to rebuild the Live display CSS as the screen has Call the plugins to rebuild the Live display CSS as the screen has
not been rebuild on exit of config. not been rebuild on exit of config.
""" """
if self.rebuildCSS and self.plugins: if self.rebuildCSS and self.plugin_manager.plugins:
for plugin in self.plugins: for plugin in self.plugin_manager.plugins:
plugin.refreshCss(self.frame) plugin.refreshCss(self.frame)
self.rebuildCSS = False self.rebuildCSS = False
@ -204,10 +207,10 @@ class MainDisplay(Display):
if self.isLive: if self.isLive:
# Build the initial frame. # Build the initial frame.
background_color = QtGui.QColor() background_color = QtGui.QColor()
background_color.setNamedColor(Settings().value(u'advanced/default color', u'#ffffff')) background_color.setNamedColor(Settings().value(u'advanced/default color'))
if not background_color.isValid(): if not background_color.isValid():
background_color = QtCore.Qt.white background_color = QtCore.Qt.white
image_file = Settings().value(u'advanced/default image', u':/graphics/openlp-splash-screen.png') image_file = Settings().value(u'advanced/default image')
splash_image = QtGui.QImage(image_file) splash_image = QtGui.QImage(image_file)
self.initialFrame = QtGui.QImage( self.initialFrame = QtGui.QImage(
self.screen[u'size'].width(), self.screen[u'size'].width(),
@ -222,8 +225,8 @@ class MainDisplay(Display):
splash_image) splash_image)
serviceItem = ServiceItem() serviceItem = ServiceItem()
serviceItem.bg_image_bytes = image_to_byte(self.initialFrame) serviceItem.bg_image_bytes = image_to_byte(self.initialFrame)
self.webView.setHtml(build_html(serviceItem, self.screen, self.webView.setHtml(build_html(serviceItem, self.screen, self.isLive, None,
self.isLive, None, plugins=self.plugins)) plugins=self.plugin_manager.plugins))
self.__hideMouse() self.__hideMouse()
log.debug(u'Finished MainDisplay setup') log.debug(u'Finished MainDisplay setup')
@ -240,7 +243,7 @@ class MainDisplay(Display):
log.debug(u'text to display') log.debug(u'text to display')
# Wait for the webview to update before displaying text. # Wait for the webview to update before displaying text.
while not self.webLoaded: while not self.webLoaded:
Receiver.send_message(u'openlp_process_events') self.application.process_events()
self.setGeometry(self.screen[u'size']) self.setGeometry(self.screen[u'size'])
if animate: if animate:
self.frame.evaluateJavaScript(u'show_text("%s")' % slide.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"')) self.frame.evaluateJavaScript(u'show_text("%s")' % slide.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'))
@ -289,7 +292,7 @@ class MainDisplay(Display):
""" """
API for replacement backgrounds so Images are added directly to cache. API for replacement backgrounds so Images are added directly to cache.
""" """
self.imageManager.addImage(path, ImageSource.ImagePlugin, background) self.image_manager.add_image(path, ImageSource.ImagePlugin, background)
if not hasattr(self, u'serviceItem'): if not hasattr(self, u'serviceItem'):
return False return False
self.override[u'image'] = path self.override[u'image'] = path
@ -311,8 +314,8 @@ class MainDisplay(Display):
re-added to the image manager. re-added to the image manager.
""" """
log.debug(u'image to display') log.debug(u'image to display')
image = self.imageManager.getImageBytes(path, ImageSource.ImagePlugin) image = self.image_manager.get_image_bytes(path, ImageSource.ImagePlugin)
self.controller.mediaController.media_reset(self.controller) self.controller.media_controller.media_reset(self.controller)
self.displayImage(image) self.displayImage(image)
def displayImage(self, image): def displayImage(self, image):
@ -344,18 +347,18 @@ class MainDisplay(Display):
Generates a preview of the image displayed. Generates a preview of the image displayed.
""" """
log.debug(u'preview for %s', self.isLive) log.debug(u'preview for %s', self.isLive)
Receiver.send_message(u'openlp_process_events') self.application.process_events()
# We must have a service item to preview. # We must have a service item to preview.
if self.isLive and hasattr(self, u'serviceItem'): if self.isLive and hasattr(self, u'serviceItem'):
# Wait for the fade to finish before geting the preview. # Wait for the fade to finish before geting the preview.
# Important otherwise preview will have incorrect text if at all! # Important otherwise preview will have incorrect text if at all!
if self.serviceItem.themedata and self.serviceItem.themedata.display_slide_transition: if self.serviceItem.themedata and self.serviceItem.themedata.display_slide_transition:
while self.frame.evaluateJavaScript(u'show_text_complete()') == u'false': while self.frame.evaluateJavaScript(u'show_text_complete()') == u'false':
Receiver.send_message(u'openlp_process_events') self.application.process_events()
# Wait for the webview to update before getting the preview. # Wait for the webview to update before getting the preview.
# Important otherwise first preview will miss the background ! # Important otherwise first preview will miss the background !
while not self.webLoaded: while not self.webLoaded:
Receiver.send_message(u'openlp_process_events') self.application.process_events()
# if was hidden keep it hidden # if was hidden keep it hidden
if self.isLive: if self.isLive:
if self.hideMode: if self.hideMode:
@ -364,7 +367,7 @@ class MainDisplay(Display):
# Single screen active # Single screen active
if self.screens.display_count == 1: if self.screens.display_count == 1:
# Only make visible if setting enabled. # Only make visible if setting enabled.
if Settings().value(u'general/display on monitor', True): if Settings().value(u'general/display on monitor'):
self.setVisible(True) self.setVisible(True)
else: else:
self.setVisible(True) self.setVisible(True)
@ -392,17 +395,20 @@ class MainDisplay(Display):
self.override = {} self.override = {}
else: else:
# replace the background # replace the background
background = self.imageManager.getImageBytes(self.override[u'image'], ImageSource.ImagePlugin) background = self.image_manager.get_image_bytes(self.override[u'image'], ImageSource.ImagePlugin)
self.setTransparency(self.serviceItem.themedata.background_type == self.setTransparency(self.serviceItem.themedata.background_type ==
BackgroundType.to_string(BackgroundType.Transparent)) BackgroundType.to_string(BackgroundType.Transparent))
if self.serviceItem.themedata.background_filename: if self.serviceItem.themedata.background_filename:
self.serviceItem.bg_image_bytes = self.imageManager.getImageBytes( self.serviceItem.bg_image_bytes = self.image_manager.get_image_bytes(
self.serviceItem.themedata.background_filename,ImageSource.Theme) self.serviceItem.themedata.background_filename,
ImageSource.Theme
)
if image_path: if image_path:
image_bytes = self.imageManager.getImageBytes(image_path, ImageSource.ImagePlugin) image_bytes = self.image_manager.get_image_bytes(image_path, ImageSource.ImagePlugin)
else: else:
image_bytes = None image_bytes = None
html = build_html(self.serviceItem, self.screen, self.isLive, background, image_bytes, self.plugins) html = build_html(self.serviceItem, self.screen, self.isLive, background, image_bytes,
plugins=self.plugin_manager.plugins)
log.debug(u'buildHtml - pre setHtml') log.debug(u'buildHtml - pre setHtml')
self.webView.setHtml(html) self.webView.setHtml(html)
log.debug(u'buildHtml - post setHtml') log.debug(u'buildHtml - post setHtml')
@ -410,7 +416,7 @@ class MainDisplay(Display):
self.footer(serviceItem.foot_text) self.footer(serviceItem.foot_text)
# if was hidden keep it hidden # if was hidden keep it hidden
if self.hideMode and self.isLive and not serviceItem.is_media(): if self.hideMode and self.isLive and not serviceItem.is_media():
if Settings().value(u'general/auto unblank', False): if Settings().value(u'general/auto unblank'):
Receiver.send_message(u'slidecontroller_live_unblank') Receiver.send_message(u'slidecontroller_live_unblank')
else: else:
self.hideDisplay(self.hideMode) self.hideDisplay(self.hideMode)
@ -432,7 +438,7 @@ class MainDisplay(Display):
log.debug(u'hideDisplay mode = %d', mode) log.debug(u'hideDisplay mode = %d', mode)
if self.screens.display_count == 1: if self.screens.display_count == 1:
# Only make visible if setting enabled. # Only make visible if setting enabled.
if not Settings().value(u'general/display on monitor', True): if not Settings().value(u'general/display on monitor'):
return return
if mode == HideMode.Screen: if mode == HideMode.Screen:
self.frame.evaluateJavaScript(u'show_blank("desktop");') self.frame.evaluateJavaScript(u'show_blank("desktop");')
@ -456,7 +462,7 @@ class MainDisplay(Display):
log.debug(u'showDisplay') log.debug(u'showDisplay')
if self.screens.display_count == 1: if self.screens.display_count == 1:
# Only make visible if setting enabled. # Only make visible if setting enabled.
if not Settings().value(u'general/display on monitor', True): if not Settings().value(u'general/display on monitor'):
return return
self.frame.evaluateJavaScript('show_blank("show");') self.frame.evaluateJavaScript('show_blank("show");')
if self.isHidden(): if self.isHidden():
@ -470,13 +476,43 @@ class MainDisplay(Display):
""" """
Hide mouse cursor when moved over display. Hide mouse cursor when moved over display.
""" """
if Settings().value(u'advanced/hide mouse', True): if Settings().value(u'advanced/hide mouse'):
self.setCursor(QtCore.Qt.BlankCursor) self.setCursor(QtCore.Qt.BlankCursor)
self.frame.evaluateJavaScript('document.body.style.cursor = "none"') self.frame.evaluateJavaScript('document.body.style.cursor = "none"')
else: else:
self.setCursor(QtCore.Qt.ArrowCursor) self.setCursor(QtCore.Qt.ArrowCursor)
self.frame.evaluateJavaScript('document.body.style.cursor = "auto"') self.frame.evaluateJavaScript('document.body.style.cursor = "auto"')
def _get_plugin_manager(self):
"""
Adds the Renderer to the class dynamically
"""
if not hasattr(self, u'_plugin_manager'):
self._plugin_manager = Registry().get(u'plugin_manager')
return self._plugin_manager
plugin_manager = property(_get_plugin_manager)
def _get_image_manager(self):
"""
Adds the image manager to the class dynamically
"""
if not hasattr(self, u'_image_manager'):
self._image_manager = Registry().get(u'image_manager')
return self._image_manager
image_manager = property(_get_image_manager)
def _get_application(self):
"""
Adds the openlp to the class dynamically
"""
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application)
class AudioPlayer(QtCore.QObject): class AudioPlayer(QtCore.QObject):
""" """
@ -522,6 +558,9 @@ class AudioPlayer(QtCore.QObject):
self.mediaObject.enqueue(self.playlist[self.currentIndex]) self.mediaObject.enqueue(self.playlist[self.currentIndex])
def onFinished(self): def onFinished(self):
"""
When the audio track finishes.
"""
if self.repeat: if self.repeat:
log.debug(u'Repeat is enabled... here we go again!') log.debug(u'Repeat is enabled... here we go again!')
self.mediaObject.clearQueue() self.mediaObject.clearQueue()
@ -530,6 +569,9 @@ class AudioPlayer(QtCore.QObject):
self.play() self.play()
def connectVolumeSlider(self, slider): def connectVolumeSlider(self, slider):
"""
Connect the volume slider to the output channel.
"""
slider.setAudioOutput(self.audioObject) slider.setAudioOutput(self.audioObject)
def reset(self): def reset(self):
@ -576,6 +618,9 @@ class AudioPlayer(QtCore.QObject):
self.playlist.extend(map(Phonon.MediaSource, filenames)) self.playlist.extend(map(Phonon.MediaSource, filenames))
def next(self): def next(self):
"""
Skip forward to the next track in the list
"""
if not self.repeat and self.currentIndex + 1 >= len(self.playlist): if not self.repeat and self.currentIndex + 1 >= len(self.playlist):
return return
isPlaying = self.mediaObject.state() == Phonon.PlayingState isPlaying = self.mediaObject.state() == Phonon.PlayingState
@ -589,6 +634,9 @@ class AudioPlayer(QtCore.QObject):
self.mediaObject.play() self.mediaObject.play()
def goTo(self, index): def goTo(self, index):
"""
Go to a particular track in the list
"""
isPlaying = self.mediaObject.state() == Phonon.PlayingState isPlaying = self.mediaObject.state() == Phonon.PlayingState
self.mediaObject.clearQueue() self.mediaObject.clearQueue()
self.mediaObject.clear() self.mediaObject.clear()
@ -599,4 +647,7 @@ class AudioPlayer(QtCore.QObject):
#@todo is this used? #@todo is this used?
def connectSlot(self, signal, slot): def connectSlot(self, signal, slot):
"""
Connect a slot to a signal on the media object
"""
QtCore.QObject.connect(self.mediaObject, signal, slot) QtCore.QObject.connect(self.mediaObject, signal, slot)

View File

@ -26,7 +26,9 @@
# 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 #
############################################################################### ###############################################################################
"""
This is the main window, where all the action happens.
"""
import logging import logging
import os import os
import sys import sys
@ -39,18 +41,16 @@ from datetime import datetime
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import Renderer, build_icon, OpenLPDockWidget, PluginManager, Receiver, translate, ImageManager, \ from openlp.core.lib import Renderer, OpenLPDockWidget, PluginManager, Receiver, ImageManager, PluginStatus, Registry, \
PluginStatus Settings, ScreenList, build_icon, check_directory_exists, translate
from openlp.core.lib.ui import UiStrings, create_action from openlp.core.lib.ui import UiStrings, create_action
from openlp.core.lib import SlideLimits, Settings
from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, ThemeManager, SlideController, PluginForm, \ from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, ThemeManager, SlideController, PluginForm, \
MediaDockManager, ShortcutListForm, FormattingTagForm MediaDockManager, ShortcutListForm, FormattingTagForm
from openlp.core.ui.media import MediaController from openlp.core.ui.media import MediaController
from openlp.core.utils import AppLocation, add_actions, LanguageManager, get_application_version, \ from openlp.core.utils import AppLocation, LanguageManager, add_actions, get_application_version, \
get_filesystem_encoding get_filesystem_encoding
from openlp.core.utils.actions import ActionList, CategoryOrder from openlp.core.utils.actions import ActionList, CategoryOrder
from openlp.core.ui.firsttimeform import FirstTimeForm from openlp.core.ui.firsttimeform import FirstTimeForm
from openlp.core.ui import ScreenList
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -80,22 +80,26 @@ PROGRESSBAR_STYLE = """
} }
""" """
class Ui_MainWindow(object): class Ui_MainWindow(object):
def setupUi(self, mainWindow): """
This is the UI part of the main window.
"""
def setupUi(self, main_window):
""" """
Set up the user interface Set up the user interface
""" """
mainWindow.setObjectName(u'MainWindow') main_window.setObjectName(u'MainWindow')
mainWindow.setWindowIcon(build_icon(u':/icon/openlp-logo-64x64.png')) main_window.setWindowIcon(build_icon(u':/icon/openlp-logo-64x64.png'))
mainWindow.setDockNestingEnabled(True) main_window.setDockNestingEnabled(True)
# Set up the main container, which contains all the other form widgets. # Set up the main container, which contains all the other form widgets.
self.mainContent = QtGui.QWidget(mainWindow) self.mainContent = QtGui.QWidget(main_window)
self.mainContent.setObjectName(u'mainContent') self.mainContent.setObjectName(u'mainContent')
self.mainContentLayout = QtGui.QHBoxLayout(self.mainContent) self.mainContentLayout = QtGui.QHBoxLayout(self.mainContent)
self.mainContentLayout.setSpacing(0) self.mainContentLayout.setSpacing(0)
self.mainContentLayout.setMargin(0) self.mainContentLayout.setMargin(0)
self.mainContentLayout.setObjectName(u'mainContentLayout') self.mainContentLayout.setObjectName(u'mainContentLayout')
mainWindow.setCentralWidget(self.mainContent) main_window.setCentralWidget(self.mainContent)
self.controlSplitter = QtGui.QSplitter(self.mainContent) self.controlSplitter = QtGui.QSplitter(self.mainContent)
self.controlSplitter.setOrientation(QtCore.Qt.Horizontal) self.controlSplitter.setOrientation(QtCore.Qt.Horizontal)
self.controlSplitter.setObjectName(u'controlSplitter') self.controlSplitter.setObjectName(u'controlSplitter')
@ -103,13 +107,13 @@ class Ui_MainWindow(object):
# Create slide controllers # Create slide controllers
self.previewController = SlideController(self) self.previewController = SlideController(self)
self.liveController = SlideController(self, True) self.liveController = SlideController(self, True)
previewVisible = Settings().value(u'user interface/preview panel', True) previewVisible = Settings().value(u'user interface/preview panel')
self.previewController.panel.setVisible(previewVisible) self.previewController.panel.setVisible(previewVisible)
liveVisible = Settings().value(u'user interface/live panel', True) liveVisible = Settings().value(u'user interface/live panel')
panelLocked = Settings().value(u'user interface/lock panel', False) panelLocked = Settings().value(u'user interface/lock panel')
self.liveController.panel.setVisible(liveVisible) self.liveController.panel.setVisible(liveVisible)
# Create menu # Create menu
self.menuBar = QtGui.QMenuBar(mainWindow) self.menuBar = QtGui.QMenuBar(main_window)
self.menuBar.setObjectName(u'menuBar') self.menuBar.setObjectName(u'menuBar')
self.fileMenu = QtGui.QMenu(self.menuBar) self.fileMenu = QtGui.QMenu(self.menuBar)
self.fileMenu.setObjectName(u'fileMenu') self.fileMenu.setObjectName(u'fileMenu')
@ -135,10 +139,10 @@ class Ui_MainWindow(object):
# Help Menu # Help Menu
self.helpMenu = QtGui.QMenu(self.menuBar) self.helpMenu = QtGui.QMenu(self.menuBar)
self.helpMenu.setObjectName(u'helpMenu') self.helpMenu.setObjectName(u'helpMenu')
mainWindow.setMenuBar(self.menuBar) main_window.setMenuBar(self.menuBar)
self.statusBar = QtGui.QStatusBar(mainWindow) self.statusBar = QtGui.QStatusBar(main_window)
self.statusBar.setObjectName(u'statusBar') self.statusBar.setObjectName(u'statusBar')
mainWindow.setStatusBar(self.statusBar) main_window.setStatusBar(self.statusBar)
self.loadProgressBar = QtGui.QProgressBar(self.statusBar) self.loadProgressBar = QtGui.QProgressBar(self.statusBar)
self.loadProgressBar.setObjectName(u'loadProgressBar') self.loadProgressBar.setObjectName(u'loadProgressBar')
self.statusBar.addPermanentWidget(self.loadProgressBar) self.statusBar.addPermanentWidget(self.loadProgressBar)
@ -149,142 +153,142 @@ class Ui_MainWindow(object):
self.defaultThemeLabel.setObjectName(u'defaultThemeLabel') self.defaultThemeLabel.setObjectName(u'defaultThemeLabel')
self.statusBar.addPermanentWidget(self.defaultThemeLabel) self.statusBar.addPermanentWidget(self.defaultThemeLabel)
# Create the MediaManager # Create the MediaManager
self.mediaManagerDock = OpenLPDockWidget(mainWindow,u'mediaManagerDock', u':/system/system_mediamanager.png') self.mediaManagerDock = OpenLPDockWidget(main_window, u'mediaManagerDock', u':/system/system_mediamanager.png')
self.mediaManagerDock.setStyleSheet(MEDIA_MANAGER_STYLE) self.mediaManagerDock.setStyleSheet(MEDIA_MANAGER_STYLE)
# Create the media toolbox # Create the media toolbox
self.mediaToolBox = QtGui.QToolBox(self.mediaManagerDock) self.mediaToolBox = QtGui.QToolBox(self.mediaManagerDock)
self.mediaToolBox.setObjectName(u'mediaToolBox') self.mediaToolBox.setObjectName(u'mediaToolBox')
self.mediaManagerDock.setWidget(self.mediaToolBox) self.mediaManagerDock.setWidget(self.mediaToolBox)
mainWindow.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.mediaManagerDock) main_window.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.mediaManagerDock)
# Create the service manager # Create the service manager
self.serviceManagerDock = OpenLPDockWidget(mainWindow, u'serviceManagerDock', self.serviceManagerDock = OpenLPDockWidget(main_window, u'serviceManagerDock',
u':/system/system_servicemanager.png') u':/system/system_servicemanager.png')
self.serviceManagerContents = ServiceManager(mainWindow, self.serviceManagerDock) self.serviceManagerContents = ServiceManager(self.serviceManagerDock)
self.serviceManagerDock.setWidget(self.serviceManagerContents) self.serviceManagerDock.setWidget(self.serviceManagerContents)
mainWindow.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.serviceManagerDock) main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.serviceManagerDock)
# Create the theme manager # Create the theme manager
self.themeManagerDock = OpenLPDockWidget(mainWindow, u'themeManagerDock', u':/system/system_thememanager.png') self.themeManagerDock = OpenLPDockWidget(main_window, u'themeManagerDock', u':/system/system_thememanager.png')
self.themeManagerContents = ThemeManager(mainWindow, self.themeManagerDock) self.themeManagerContents = ThemeManager(self.themeManagerDock)
self.themeManagerContents.setObjectName(u'themeManagerContents') self.themeManagerContents.setObjectName(u'themeManagerContents')
self.themeManagerDock.setWidget(self.themeManagerContents) self.themeManagerDock.setWidget(self.themeManagerContents)
mainWindow.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.themeManagerDock) main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.themeManagerDock)
# Create the menu items # Create the menu items
action_list = ActionList.get_instance() action_list = ActionList.get_instance()
action_list.add_category(UiStrings().File, CategoryOrder.standardMenu) action_list.add_category(UiStrings().File, CategoryOrder.standardMenu)
self.fileNewItem = create_action(mainWindow, u'fileNewItem', self.fileNewItem = create_action(main_window, u'fileNewItem',
icon=u':/general/general_new.png', icon=u':/general/general_new.png',
shortcuts=[QtGui.QKeySequence(u'Ctrl+N')], shortcuts=[QtGui.QKeySequence(u'Ctrl+N')],
category=UiStrings().File, category=UiStrings().File,
triggers=self.serviceManagerContents.onNewServiceClicked) triggers=self.serviceManagerContents.on_new_service_clicked)
self.fileOpenItem = create_action(mainWindow, u'fileOpenItem', self.fileOpenItem = create_action(main_window, u'fileOpenItem',
icon=u':/general/general_open.png', icon=u':/general/general_open.png',
shortcuts=[QtGui.QKeySequence(u'Ctrl+O')], shortcuts=[QtGui.QKeySequence(u'Ctrl+O')],
category=UiStrings().File, category=UiStrings().File,
triggers=self.serviceManagerContents.onLoadServiceClicked) triggers=self.serviceManagerContents.on_load_service_clicked)
self.fileSaveItem = create_action(mainWindow, u'fileSaveItem', self.fileSaveItem = create_action(main_window, u'fileSaveItem',
icon=u':/general/general_save.png', icon=u':/general/general_save.png',
shortcuts=[QtGui.QKeySequence(u'Ctrl+S')], shortcuts=[QtGui.QKeySequence(u'Ctrl+S')],
category=UiStrings().File, category=UiStrings().File,
triggers=self.serviceManagerContents.saveFile) triggers=self.serviceManagerContents.save_file)
self.fileSaveAsItem = create_action(mainWindow, u'fileSaveAsItem', self.fileSaveAsItem = create_action(main_window, u'fileSaveAsItem',
shortcuts=[QtGui.QKeySequence(u'Ctrl+Shift+S')], shortcuts=[QtGui.QKeySequence(u'Ctrl+Shift+S')],
category=UiStrings().File, category=UiStrings().File,
triggers=self.serviceManagerContents.saveFileAs) triggers=self.serviceManagerContents.save_file_as)
self.printServiceOrderItem = create_action(mainWindow, self.printServiceOrderItem = create_action(main_window,
u'printServiceItem', shortcuts=[QtGui.QKeySequence(u'Ctrl+P')], u'printServiceItem', shortcuts=[QtGui.QKeySequence(u'Ctrl+P')],
category=UiStrings().File, category=UiStrings().File,
triggers=self.serviceManagerContents.printServiceOrder) triggers=self.serviceManagerContents.print_service_order)
self.fileExitItem = create_action(mainWindow, u'fileExitItem', self.fileExitItem = create_action(main_window, u'fileExitItem',
icon=u':/system/system_exit.png', icon=u':/system/system_exit.png',
shortcuts=[QtGui.QKeySequence(u'Alt+F4')], shortcuts=[QtGui.QKeySequence(u'Alt+F4')],
category=UiStrings().File, triggers=mainWindow.close) category=UiStrings().File, triggers=main_window.close)
# Give QT Extra Hint that this is the Exit Menu Item # Give QT Extra Hint that this is the Exit Menu Item
self.fileExitItem.setMenuRole(QtGui.QAction.QuitRole) self.fileExitItem.setMenuRole(QtGui.QAction.QuitRole)
action_list.add_category(UiStrings().Import, CategoryOrder.standardMenu) action_list.add_category(UiStrings().Import, CategoryOrder.standardMenu)
self.importThemeItem = create_action(mainWindow, u'importThemeItem', category=UiStrings().Import) self.importThemeItem = create_action(main_window, u'importThemeItem', category=UiStrings().Import)
self.importLanguageItem = create_action(mainWindow, u'importLanguageItem') self.importLanguageItem = create_action(main_window, u'importLanguageItem')
action_list.add_category(UiStrings().Export, CategoryOrder.standardMenu) action_list.add_category(UiStrings().Export, CategoryOrder.standardMenu)
self.exportThemeItem = create_action(mainWindow, u'exportThemeItem', category=UiStrings().Export) self.exportThemeItem = create_action(main_window, u'exportThemeItem', category=UiStrings().Export)
self.exportLanguageItem = create_action(mainWindow, u'exportLanguageItem') self.exportLanguageItem = create_action(main_window, u'exportLanguageItem')
action_list.add_category(UiStrings().View, CategoryOrder.standardMenu) action_list.add_category(UiStrings().View, CategoryOrder.standardMenu)
self.viewMediaManagerItem = create_action(mainWindow, self.viewMediaManagerItem = create_action(main_window,
u'viewMediaManagerItem', shortcuts=[QtGui.QKeySequence(u'F8')], u'viewMediaManagerItem', shortcuts=[QtGui.QKeySequence(u'F8')],
icon=u':/system/system_mediamanager.png', icon=u':/system/system_mediamanager.png',
checked=self.mediaManagerDock.isVisible(), checked=self.mediaManagerDock.isVisible(),
category=UiStrings().View, triggers=self.toggleMediaManager) category=UiStrings().View, triggers=self.toggleMediaManager)
self.viewThemeManagerItem = create_action(mainWindow, self.viewThemeManagerItem = create_action(main_window,
u'viewThemeManagerItem', shortcuts=[QtGui.QKeySequence(u'F10')], u'viewThemeManagerItem', shortcuts=[QtGui.QKeySequence(u'F10')],
icon=u':/system/system_thememanager.png', icon=u':/system/system_thememanager.png',
checked=self.themeManagerDock.isVisible(), checked=self.themeManagerDock.isVisible(),
category=UiStrings().View, triggers=self.toggleThemeManager) category=UiStrings().View, triggers=self.toggleThemeManager)
self.viewServiceManagerItem = create_action(mainWindow, self.viewServiceManagerItem = create_action(main_window,
u'viewServiceManagerItem', shortcuts=[QtGui.QKeySequence(u'F9')], u'viewServiceManagerItem', shortcuts=[QtGui.QKeySequence(u'F9')],
icon=u':/system/system_servicemanager.png', icon=u':/system/system_servicemanager.png',
checked=self.serviceManagerDock.isVisible(), checked=self.serviceManagerDock.isVisible(),
category=UiStrings().View, triggers=self.toggleServiceManager) category=UiStrings().View, triggers=self.toggleServiceManager)
self.viewPreviewPanel = create_action(mainWindow, u'viewPreviewPanel', self.viewPreviewPanel = create_action(main_window, u'viewPreviewPanel',
shortcuts=[QtGui.QKeySequence(u'F11')], checked=previewVisible, shortcuts=[QtGui.QKeySequence(u'F11')], checked=previewVisible,
category=UiStrings().View, triggers=self.setPreviewPanelVisibility) category=UiStrings().View, triggers=self.setPreviewPanelVisibility)
self.viewLivePanel = create_action(mainWindow, u'viewLivePanel', self.viewLivePanel = create_action(main_window, u'viewLivePanel',
shortcuts=[QtGui.QKeySequence(u'F12')], checked=liveVisible, shortcuts=[QtGui.QKeySequence(u'F12')], checked=liveVisible,
category=UiStrings().View, triggers=self.setLivePanelVisibility) category=UiStrings().View, triggers=self.setLivePanelVisibility)
self.lockPanel = create_action(mainWindow, u'lockPanel', self.lockPanel = create_action(main_window, u'lockPanel',
checked=panelLocked, triggers=self.setLockPanel) checked=panelLocked, triggers=self.setLockPanel)
action_list.add_category(UiStrings().ViewMode, action_list.add_category(UiStrings().ViewMode,
CategoryOrder.standardMenu) CategoryOrder.standardMenu)
self.modeDefaultItem = create_action(mainWindow, u'modeDefaultItem', checked=False, self.modeDefaultItem = create_action(main_window, u'modeDefaultItem', checked=False,
category=UiStrings().ViewMode) category=UiStrings().ViewMode)
self.modeSetupItem = create_action(mainWindow, u'modeSetupItem', checked=False, category=UiStrings().ViewMode) self.modeSetupItem = create_action(main_window, u'modeSetupItem', checked=False, category=UiStrings().ViewMode)
self.modeLiveItem = create_action(mainWindow, u'modeLiveItem', checked=True, category=UiStrings().ViewMode) self.modeLiveItem = create_action(main_window, u'modeLiveItem', checked=True, category=UiStrings().ViewMode)
self.modeGroup = QtGui.QActionGroup(mainWindow) self.modeGroup = QtGui.QActionGroup(main_window)
self.modeGroup.addAction(self.modeDefaultItem) self.modeGroup.addAction(self.modeDefaultItem)
self.modeGroup.addAction(self.modeSetupItem) self.modeGroup.addAction(self.modeSetupItem)
self.modeGroup.addAction(self.modeLiveItem) self.modeGroup.addAction(self.modeLiveItem)
self.modeDefaultItem.setChecked(True) self.modeDefaultItem.setChecked(True)
action_list.add_category(UiStrings().Tools, CategoryOrder.standardMenu) action_list.add_category(UiStrings().Tools, CategoryOrder.standardMenu)
self.toolsAddToolItem = create_action(mainWindow, self.toolsAddToolItem = create_action(main_window,
u'toolsAddToolItem', icon=u':/tools/tools_add.png', u'toolsAddToolItem', icon=u':/tools/tools_add.png',
category=UiStrings().Tools) category=UiStrings().Tools)
self.toolsOpenDataFolder = create_action(mainWindow, self.toolsOpenDataFolder = create_action(main_window,
u'toolsOpenDataFolder', icon=u':/general/general_open.png', u'toolsOpenDataFolder', icon=u':/general/general_open.png',
category=UiStrings().Tools) category=UiStrings().Tools)
self.toolsFirstTimeWizard = create_action(mainWindow, self.toolsFirstTimeWizard = create_action(main_window,
u'toolsFirstTimeWizard', icon=u':/general/general_revert.png', u'toolsFirstTimeWizard', icon=u':/general/general_revert.png',
category=UiStrings().Tools) category=UiStrings().Tools)
self.updateThemeImages = create_action(mainWindow, self.updateThemeImages = create_action(main_window,
u'updateThemeImages', category=UiStrings().Tools) u'updateThemeImages', category=UiStrings().Tools)
action_list.add_category(UiStrings().Settings, action_list.add_category(UiStrings().Settings,
CategoryOrder.standardMenu) CategoryOrder.standardMenu)
self.settingsPluginListItem = create_action(mainWindow, self.settingsPluginListItem = create_action(main_window,
u'settingsPluginListItem', u'settingsPluginListItem',
icon=u':/system/settings_plugin_list.png', icon=u':/system/settings_plugin_list.png',
shortcuts=[QtGui.QKeySequence(u'Alt+F7')], shortcuts=[QtGui.QKeySequence(u'Alt+F7')],
category=UiStrings().Settings, triggers=self.onPluginItemClicked) category=UiStrings().Settings, triggers=self.onPluginItemClicked)
# i18n Language Items # i18n Language Items
self.autoLanguageItem = create_action(mainWindow, u'autoLanguageItem', self.autoLanguageItem = create_action(main_window, u'autoLanguageItem',
checked=LanguageManager.auto_language) checked=LanguageManager.auto_language)
self.languageGroup = QtGui.QActionGroup(mainWindow) self.languageGroup = QtGui.QActionGroup(main_window)
self.languageGroup.setExclusive(True) self.languageGroup.setExclusive(True)
self.languageGroup.setObjectName(u'languageGroup') self.languageGroup.setObjectName(u'languageGroup')
add_actions(self.languageGroup, [self.autoLanguageItem]) add_actions(self.languageGroup, [self.autoLanguageItem])
qmList = LanguageManager.get_qm_list() qmList = LanguageManager.get_qm_list()
savedLanguage = LanguageManager.get_language() savedLanguage = LanguageManager.get_language()
for key in sorted(qmList.keys()): for key in sorted(qmList.keys()):
languageItem = create_action(mainWindow, key, checked=qmList[key] == savedLanguage) languageItem = create_action(main_window, key, checked=qmList[key] == savedLanguage)
add_actions(self.languageGroup, [languageItem]) add_actions(self.languageGroup, [languageItem])
self.settingsShortcutsItem = create_action(mainWindow, u'settingsShortcutsItem', self.settingsShortcutsItem = create_action(main_window, u'settingsShortcutsItem',
icon=u':/system/system_configure_shortcuts.png', category=UiStrings().Settings) icon=u':/system/system_configure_shortcuts.png', category=UiStrings().Settings)
# Formatting Tags were also known as display tags. # Formatting Tags were also known as display tags.
self.formattingTagItem = create_action(mainWindow, u'displayTagItem', self.formattingTagItem = create_action(main_window, u'displayTagItem',
icon=u':/system/tag_editor.png', category=UiStrings().Settings) icon=u':/system/tag_editor.png', category=UiStrings().Settings)
self.settingsConfigureItem = create_action(mainWindow, u'settingsConfigureItem', self.settingsConfigureItem = create_action(main_window, u'settingsConfigureItem',
icon=u':/system/system_settings.png', category=UiStrings().Settings) icon=u':/system/system_settings.png', category=UiStrings().Settings)
# Give QT Extra Hint that this is the Preferences Menu Item # Give QT Extra Hint that this is the Preferences Menu Item
self.settingsConfigureItem.setMenuRole(QtGui.QAction.PreferencesRole) self.settingsConfigureItem.setMenuRole(QtGui.QAction.PreferencesRole)
self.settingsImportItem = create_action(mainWindow, u'settingsImportItem', category=UiStrings().Settings) self.settingsImportItem = create_action(main_window, u'settingsImportItem', category=UiStrings().Settings)
self.settingsExportItem = create_action(mainWindow, u'settingsExportItem', category=UiStrings().Settings) self.settingsExportItem = create_action(main_window, u'settingsExportItem', category=UiStrings().Settings)
action_list.add_category(UiStrings().Help, CategoryOrder.standardMenu) action_list.add_category(UiStrings().Help, CategoryOrder.standardMenu)
self.aboutItem = create_action(mainWindow, u'aboutItem', icon=u':/system/system_about.png', self.aboutItem = create_action(main_window, u'aboutItem', icon=u':/system/system_about.png',
shortcuts=[QtGui.QKeySequence(u'Ctrl+F1')], shortcuts=[QtGui.QKeySequence(u'Ctrl+F1')],
category=UiStrings().Help, triggers=self.onAboutItemClicked) category=UiStrings().Help, triggers=self.onAboutItemClicked)
# Give QT Extra Hint that this is an About Menu Item # Give QT Extra Hint that this is an About Menu Item
@ -292,15 +296,15 @@ class Ui_MainWindow(object):
if os.name == u'nt': if os.name == u'nt':
self.localHelpFile = os.path.join( self.localHelpFile = os.path.join(
AppLocation.get_directory(AppLocation.AppDir), 'OpenLP.chm') AppLocation.get_directory(AppLocation.AppDir), 'OpenLP.chm')
self.offlineHelpItem = create_action(mainWindow, u'offlineHelpItem', self.offlineHelpItem = create_action(main_window, u'offlineHelpItem',
icon=u':/system/system_help_contents.png', icon=u':/system/system_help_contents.png',
shortcuts=[QtGui.QKeySequence(u'F1')], shortcuts=[QtGui.QKeySequence(u'F1')],
category=UiStrings().Help, triggers=self.onOfflineHelpClicked) category=UiStrings().Help, triggers=self.onOfflineHelpClicked)
self.onlineHelpItem = create_action(mainWindow, u'onlineHelpItem', self.onlineHelpItem = create_action(main_window, u'onlineHelpItem',
icon=u':/system/system_online_help.png', icon=u':/system/system_online_help.png',
shortcuts=[QtGui.QKeySequence(u'Alt+F1')], shortcuts=[QtGui.QKeySequence(u'Alt+F1')],
category=UiStrings().Help, triggers=self.onOnlineHelpClicked) category=UiStrings().Help, triggers=self.onOnlineHelpClicked)
self.webSiteItem = create_action(mainWindow, u'webSiteItem', category=UiStrings().Help) self.webSiteItem = create_action(main_window, u'webSiteItem', category=UiStrings().Help)
add_actions(self.fileImportMenu, (self.settingsImportItem, None, self.importThemeItem, self.importLanguageItem)) add_actions(self.fileImportMenu, (self.settingsImportItem, None, self.importThemeItem, self.importLanguageItem))
add_actions(self.fileExportMenu, (self.settingsExportItem, None, self.exportThemeItem, self.exportLanguageItem)) add_actions(self.fileExportMenu, (self.settingsExportItem, None, self.exportThemeItem, self.exportLanguageItem))
add_actions(self.fileMenu, (self.fileNewItem, self.fileOpenItem, add_actions(self.fileMenu, (self.fileNewItem, self.fileOpenItem,
@ -334,7 +338,7 @@ class Ui_MainWindow(object):
add_actions(self.menuBar, (self.fileMenu.menuAction(), self.viewMenu.menuAction(), self.toolsMenu.menuAction(), add_actions(self.menuBar, (self.fileMenu.menuAction(), self.viewMenu.menuAction(), self.toolsMenu.menuAction(),
self.settingsMenu.menuAction(), self.helpMenu.menuAction())) self.settingsMenu.menuAction(), self.helpMenu.menuAction()))
# Initialise the translation # Initialise the translation
self.retranslateUi(mainWindow) self.retranslateUi(main_window)
self.mediaToolBox.setCurrentIndex(0) self.mediaToolBox.setCurrentIndex(0)
# Connect up some signals and slots # Connect up some signals and slots
QtCore.QObject.connect(self.fileMenu, QtCore.SIGNAL(u'aboutToShow()'), self.updateRecentFilesMenu) QtCore.QObject.connect(self.fileMenu, QtCore.SIGNAL(u'aboutToShow()'), self.updateRecentFilesMenu)
@ -407,7 +411,8 @@ class Ui_MainWindow(object):
'Toggle the visibility of the service manager.')) 'Toggle the visibility of the service manager.'))
self.viewPreviewPanel.setText(translate('OpenLP.MainWindow', '&Preview Panel')) self.viewPreviewPanel.setText(translate('OpenLP.MainWindow', '&Preview Panel'))
self.viewPreviewPanel.setToolTip(translate('OpenLP.MainWindow', 'Toggle Preview Panel')) self.viewPreviewPanel.setToolTip(translate('OpenLP.MainWindow', 'Toggle Preview Panel'))
self.viewPreviewPanel.setStatusTip(translate('OpenLP.MainWindow', 'Toggle the visibility of the preview panel.')) self.viewPreviewPanel.setStatusTip(
translate('OpenLP.MainWindow', 'Toggle the visibility of the preview panel.'))
self.viewLivePanel.setText(translate('OpenLP.MainWindow', '&Live Panel')) self.viewLivePanel.setText(translate('OpenLP.MainWindow', '&Live Panel'))
self.viewLivePanel.setToolTip(translate('OpenLP.MainWindow', 'Toggle Live Panel')) self.viewLivePanel.setToolTip(translate('OpenLP.MainWindow', 'Toggle Live Panel'))
self.lockPanel.setText(translate('OpenLP.MainWindow', 'L&ock Panels')) self.lockPanel.setText(translate('OpenLP.MainWindow', 'L&ock Panels'))
@ -450,17 +455,16 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
""" """
log.info(u'MainWindow loaded') log.info(u'MainWindow loaded')
def __init__(self, application): def __init__(self):
""" """
This constructor sets up the interface, the various managers, and the This constructor sets up the interface, the various managers, and the
plugins. plugins.
""" """
QtGui.QMainWindow.__init__(self) QtGui.QMainWindow.__init__(self)
self.application = application Registry().register(u'main_window', self)
self.clipboard = self.application.clipboard() self.clipboard = self.application.clipboard()
self.arguments = self.application.args self.arguments = self.application.args
# Set up settings sections for the main application # Set up settings sections for the main application (not for use by plugins).
# (not for use by plugins)
self.uiSettingsSection = u'user interface' self.uiSettingsSection = u'user interface'
self.generalSettingsSection = u'general' self.generalSettingsSection = u'general'
self.advancedSettingsSection = u'advanced' self.advancedSettingsSection = u'advanced'
@ -471,17 +475,18 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.playersSettingsSection = u'players' self.playersSettingsSection = u'players'
self.displayTagsSection = u'displayTags' self.displayTagsSection = u'displayTags'
self.headerSection = u'SettingsImport' self.headerSection = u'SettingsImport'
Settings().set_up_default_values()
Settings().remove_obsolete_settings()
self.serviceNotSaved = False self.serviceNotSaved = False
self.aboutForm = AboutForm(self) self.aboutForm = AboutForm(self)
self.mediaController = MediaController(self) self.mediaController = MediaController(self)
self.settingsForm = SettingsForm(self, self) self.settingsForm = SettingsForm(self)
self.formattingTagForm = FormattingTagForm(self) self.formattingTagForm = FormattingTagForm(self)
self.shortcutForm = ShortcutListForm(self) self.shortcutForm = ShortcutListForm(self)
self.recentFiles = [] self.recentFiles = []
# Set up the path with plugins # Set up the path with plugins
plugin_path = AppLocation.get_directory(AppLocation.PluginsDir) plugin_path = AppLocation.get_directory(AppLocation.PluginsDir)
self.pluginManager = PluginManager(plugin_path) self.plugin_manager = PluginManager(plugin_path)
self.pluginHelpers = {}
self.imageManager = ImageManager() self.imageManager = ImageManager()
# Set up the interface # Set up the interface
self.setupUi(self) self.setupUi(self)
@ -496,9 +501,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.copyData = False self.copyData = False
# Set up signals and slots # Set up signals and slots
QtCore.QObject.connect(self.importThemeItem, QtCore.SIGNAL(u'triggered()'), QtCore.QObject.connect(self.importThemeItem, QtCore.SIGNAL(u'triggered()'),
self.themeManagerContents.onImportTheme) self.themeManagerContents.on_import_theme)
QtCore.QObject.connect(self.exportThemeItem, QtCore.SIGNAL(u'triggered()'), QtCore.QObject.connect(self.exportThemeItem, QtCore.SIGNAL(u'triggered()'),
self.themeManagerContents.onExportTheme) self.themeManagerContents.on_export_theme)
QtCore.QObject.connect(self.mediaManagerDock, QtCore.SIGNAL(u'visibilityChanged(bool)'), QtCore.QObject.connect(self.mediaManagerDock, QtCore.SIGNAL(u'visibilityChanged(bool)'),
self.viewMediaManagerItem.setChecked) self.viewMediaManagerItem.setChecked)
QtCore.QObject.connect(self.serviceManagerDock, QtCore.SIGNAL(u'visibilityChanged(bool)'), QtCore.QObject.connect(self.serviceManagerDock, QtCore.SIGNAL(u'visibilityChanged(bool)'),
@ -517,7 +522,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.onSettingsShortcutsItemClicked) self.onSettingsShortcutsItemClicked)
QtCore.QObject.connect(self.settingsImportItem, QtCore.SIGNAL(u'triggered()'), QtCore.QObject.connect(self.settingsImportItem, QtCore.SIGNAL(u'triggered()'),
self.onSettingsImportItemClicked) self.onSettingsImportItemClicked)
QtCore.QObject.connect(self.settingsExportItem,QtCore.SIGNAL(u'triggered()'), self.onSettingsExportItemClicked) QtCore.QObject.connect(self.settingsExportItem, QtCore.SIGNAL(u'triggered()'), self.onSettingsExportItemClicked)
# i18n set signals for languages # i18n set signals for languages
self.languageGroup.triggered.connect(LanguageManager.set_language) self.languageGroup.triggered.connect(LanguageManager.set_language)
QtCore.QObject.connect(self.modeDefaultItem, QtCore.SIGNAL(u'triggered()'), self.onModeDefaultItemClicked) QtCore.QObject.connect(self.modeDefaultItem, QtCore.SIGNAL(u'triggered()'), self.onModeDefaultItemClicked)
@ -527,14 +532,14 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'openlp_version_check'), self.versionNotice) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'openlp_version_check'), self.versionNotice)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'live_display_blank_check'), self.blankCheck) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'live_display_blank_check'), self.blankCheck)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_screen_changed'), self.screenChanged) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_screen_changed'), self.screenChanged)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'mainwindow_status_text'), self.showStatusMessage) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'mainwindow_status_text'),
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'cleanup'), self.cleanUp) self.showStatusMessage)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'cleanup'), self.clean_up)
# Media Manager # Media Manager
QtCore.QObject.connect(self.mediaToolBox, QtCore.SIGNAL(u'currentChanged(int)'), self.onMediaToolBoxChanged) QtCore.QObject.connect(self.mediaToolBox, QtCore.SIGNAL(u'currentChanged(int)'), self.onMediaToolBoxChanged)
Receiver.send_message(u'cursor_busy') self.application.set_busy_cursor()
# Simple message boxes # Simple message boxes
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'openlp_error_message'), self.onErrorMessage) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'openlp_error_message'), self.onErrorMessage)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'openlp_warning_message'), self.onWarningMessage)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'openlp_information_message'), QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'openlp_information_message'),
self.onInformationMessage) self.onInformationMessage)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'set_new_data_path'), self.setNewDataPath) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'set_new_data_path'), self.setNewDataPath)
@ -542,62 +547,58 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
# warning cyclic dependency # warning cyclic dependency
# renderer needs to call ThemeManager and # renderer needs to call ThemeManager and
# ThemeManager needs to call Renderer # ThemeManager needs to call Renderer
self.renderer = Renderer(self.imageManager, self.themeManagerContents) self.renderer = Renderer()
# Define the media Dock Manager # Define the media Dock Manager
self.mediaDockManager = MediaDockManager(self.mediaToolBox) self.mediaDockManager = MediaDockManager(self.mediaToolBox)
log.info(u'Load Plugins') log.info(u'Load Plugins')
# make the controllers available to the plugins self.plugin_manager.find_plugins(plugin_path)
self.pluginHelpers[u'preview'] = self.previewController
self.pluginHelpers[u'live'] = self.liveController
self.pluginHelpers[u'renderer'] = self.renderer
self.pluginHelpers[u'service'] = self.serviceManagerContents
self.pluginHelpers[u'settings form'] = self.settingsForm
self.pluginHelpers[u'toolbox'] = self.mediaDockManager
self.pluginHelpers[u'pluginmanager'] = self.pluginManager
self.pluginHelpers[u'formparent'] = self
self.pluginHelpers[u'mediacontroller'] = self.mediaController
self.pluginManager.find_plugins(plugin_path, self.pluginHelpers)
# hook methods have to happen after find_plugins. Find plugins needs # hook methods have to happen after find_plugins. Find plugins needs
# the controllers hence the hooks have moved from setupUI() to here # the controllers hence the hooks have moved from setupUI() to here
# Find and insert settings tabs # Find and insert settings tabs
log.info(u'hook settings') log.info(u'hook settings')
self.pluginManager.hook_settings_tabs(self.settingsForm) self.plugin_manager.hook_settings_tabs(self.settingsForm)
# Find and insert media manager items # Find and insert media manager items
log.info(u'hook media') log.info(u'hook media')
self.pluginManager.hook_media_manager() self.plugin_manager.hook_media_manager()
# Call the hook method to pull in import menus. # Call the hook method to pull in import menus.
log.info(u'hook menus') log.info(u'hook menus')
self.pluginManager.hook_import_menu(self.fileImportMenu) self.plugin_manager.hook_import_menu(self.fileImportMenu)
# Call the hook method to pull in export menus. # Call the hook method to pull in export menus.
self.pluginManager.hook_export_menu(self.fileExportMenu) self.plugin_manager.hook_export_menu(self.fileExportMenu)
# Call the hook method to pull in tools menus. # Call the hook method to pull in tools menus.
self.pluginManager.hook_tools_menu(self.toolsMenu) self.plugin_manager.hook_tools_menu(self.toolsMenu)
# Call the initialise method to setup plugins. # Call the initialise method to setup plugins.
log.info(u'initialise plugins') log.info(u'initialise plugins')
self.pluginManager.initialise_plugins() self.plugin_manager.initialise_plugins()
# Create the displays as all necessary components are loaded. # Create the displays as all necessary components are loaded.
self.previewController.screenSizeChanged() self.previewController.screenSizeChanged()
self.liveController.screenSizeChanged() self.liveController.screenSizeChanged()
log.info(u'Load data from Settings') log.info(u'Load data from Settings')
if Settings().value(u'advanced/save current plugin', False): if Settings().value(u'advanced/save current plugin'):
savedPlugin = Settings().value(u'advanced/current media plugin', -1) savedPlugin = Settings().value(u'advanced/current media plugin')
if savedPlugin != -1: if savedPlugin != -1:
self.mediaToolBox.setCurrentIndex(savedPlugin) self.mediaToolBox.setCurrentIndex(savedPlugin)
self.settingsForm.postSetUp() self.settingsForm.postSetUp()
# Once all components are initialised load the Themes # Once all components are initialised load the Themes
log.info(u'Load Themes') log.info(u'Load Themes')
self.themeManagerContents.loadThemes(True) self.themeManagerContents.load_themes(True)
# Hide/show the theme combobox on the service manager # Hide/show the theme combobox on the service manager
self.serviceManagerContents.themeChange() self.serviceManagerContents.theme_change()
# Reset the cursor # Reset the cursor
Receiver.send_message(u'cursor_normal') self.application.set_normal_cursor()
def setAutoLanguage(self, value): def setAutoLanguage(self, value):
"""
Set the language to automatic.
"""
self.languageGroup.setDisabled(value) self.languageGroup.setDisabled(value)
LanguageManager.auto_language = value LanguageManager.auto_language = value
LanguageManager.set_language(self.languageGroup.checkedAction()) LanguageManager.set_language(self.languageGroup.checkedAction())
def onMediaToolBoxChanged(self, index): def onMediaToolBoxChanged(self, index):
"""
Focus a widget when the media toolbox changes.
"""
widget = self.mediaToolBox.widget(index) widget = self.mediaToolBox.widget(index)
if widget: if widget:
widget.onFocus() widget.onFocus()
@ -628,11 +629,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
filename = args[0] filename = args[0]
if not isinstance(filename, unicode): if not isinstance(filename, unicode):
filename = unicode(filename, sys.getfilesystemencoding()) filename = unicode(filename, sys.getfilesystemencoding())
self.serviceManagerContents.loadFile(filename) self.serviceManagerContents.load_file(filename)
elif Settings().value( elif Settings().value(self.generalSettingsSection + u'/auto open'):
self.generalSettingsSection + u'/auto open', False): self.serviceManagerContents.load_Last_file()
self.serviceManagerContents.loadLastFile() view_mode = Settings().value(u'%s/view mode' % self.generalSettingsSection)
view_mode = Settings().value(u'%s/view mode' % self.generalSettingsSection, u'default')
if view_mode == u'default': if view_mode == u'default':
self.modeDefaultItem.setChecked(True) self.modeDefaultItem.setChecked(True)
elif view_mode == u'setup': elif view_mode == u'setup':
@ -642,24 +642,26 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.setViewMode(False, True, False, False, True) self.setViewMode(False, True, False, False, True)
self.modeLiveItem.setChecked(True) self.modeLiveItem.setChecked(True)
def appStartup(self): def app_startup(self):
""" """
Give all the plugins a chance to perform some tasks at startup Give all the plugins a chance to perform some tasks at startup
""" """
Receiver.send_message(u'openlp_process_events') self.application.process_events()
for plugin in self.pluginManager.plugins: for plugin in self.plugin_manager.plugins:
if plugin.isActive(): if plugin.isActive():
plugin.appStartup() plugin.app_startup()
Receiver.send_message(u'openlp_process_events') self.application.process_events()
def firstTime(self): def first_time(self):
# Import themes if first time """
Receiver.send_message(u'openlp_process_events') Import themes if first time
for plugin in self.pluginManager.plugins: """
if hasattr(plugin, u'firstTime'): self.application.process_events()
Receiver.send_message(u'openlp_process_events') for plugin in self.plugin_manager.plugins:
plugin.firstTime() if hasattr(plugin, u'first_time'):
Receiver.send_message(u'openlp_process_events') self.application.process_events()
plugin.first_time()
self.application.process_events()
temp_dir = os.path.join(unicode(gettempdir()), u'openlp') temp_dir = os.path.join(unicode(gettempdir()), u'openlp')
shutil.rmtree(temp_dir, True) shutil.rmtree(temp_dir, True)
@ -680,29 +682,30 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
QtGui.QMessageBox.No) QtGui.QMessageBox.No)
if answer == QtGui.QMessageBox.No: if answer == QtGui.QMessageBox.No:
return return
Receiver.send_message(u'cursor_busy')
screens = ScreenList() screens = ScreenList()
firstTime = FirstTimeForm(screens, self) first_run_wizard = FirstTimeForm(screens, self)
firstTime.exec_() first_run_wizard.exec_()
if firstTime.downloadCancelled: if first_run_wizard.was_download_cancelled:
return return
self.firstTime() self.application.set_busy_cursor()
for plugin in self.pluginManager.plugins: self.first_time()
for plugin in self.plugin_manager.plugins:
self.activePlugin = plugin self.activePlugin = plugin
oldStatus = self.activePlugin.status oldStatus = self.activePlugin.status
self.activePlugin.setStatus() self.activePlugin.setStatus()
if oldStatus != self.activePlugin.status: if oldStatus != self.activePlugin.status:
if self.activePlugin.status == PluginStatus.Active: if self.activePlugin.status == PluginStatus.Active:
self.activePlugin.toggleStatus(PluginStatus.Active) self.activePlugin.toggleStatus(PluginStatus.Active)
self.activePlugin.appStartup() self.activePlugin.app_startup()
else: else:
self.activePlugin.toggleStatus(PluginStatus.Inactive) self.activePlugin.toggleStatus(PluginStatus.Inactive)
self.themeManagerContents.configUpdated() self.themeManagerContents.configUpdated()
self.themeManagerContents.loadThemes(True) self.themeManagerContents.load_themes(True)
Receiver.send_message(u'theme_update_global', self.themeManagerContents.global_theme) Receiver.send_message(u'theme_update_global', self.themeManagerContents.global_theme)
# Check if any Bibles downloaded. If there are, they will be # Check if any Bibles downloaded. If there are, they will be
# processed. # processed.
Receiver.send_message(u'bibles_load_list', True) Receiver.send_message(u'bibles_load_list', True)
self.application.set_normal_cursor()
def blankCheck(self): def blankCheck(self):
""" """
@ -710,23 +713,30 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
""" """
settings = Settings() settings = Settings()
self.liveController.mainDisplaySetBackground() self.liveController.mainDisplaySetBackground()
if settings.value(u'%s/screen blank' % self.generalSettingsSection, if settings.value(u'%s/screen blank' % self.generalSettingsSection):
False): if settings.value(u'%s/blank warning' % self.generalSettingsSection):
if settings.value(u'%s/blank warning' % self.generalSettingsSection,
False):
QtGui.QMessageBox.question(self, translate('OpenLP.MainWindow', 'OpenLP Main Display Blanked'), QtGui.QMessageBox.question(self, translate('OpenLP.MainWindow', 'OpenLP Main Display Blanked'),
translate('OpenLP.MainWindow', 'The Main Display has been blanked out')) translate('OpenLP.MainWindow', 'The Main Display has been blanked out'))
def onErrorMessage(self, data): def onErrorMessage(self, data):
Receiver.send_message(u'close_splash') """
Display an error message
"""
self.application.close_splash_screen()
QtGui.QMessageBox.critical(self, data[u'title'], data[u'message']) QtGui.QMessageBox.critical(self, data[u'title'], data[u'message'])
def onWarningMessage(self, data): def warning_message(self, message):
Receiver.send_message(u'close_splash') """
QtGui.QMessageBox.warning(self, data[u'title'], data[u'message']) Display a warning message
"""
self.application.close_splash_screen()
QtGui.QMessageBox.warning(self, message[u'title'], message[u'message'])
def onInformationMessage(self, data): def onInformationMessage(self, data):
Receiver.send_message(u'close_splash') """
Display an informational message
"""
self.application.close_splash_screen()
QtGui.QMessageBox.information(self, data[u'title'], data[u'message']) QtGui.QMessageBox.information(self, data[u'title'], data[u'message'])
def onHelpWebSiteClicked(self): def onHelpWebSiteClicked(self):
@ -773,7 +783,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
""" """
Updates the new theme preview images. Updates the new theme preview images.
""" """
self.themeManagerContents.updatePreviewImages() self.themeManagerContents.update_preview_images()
def onFormattingTagItemClicked(self): def onFormattingTagItemClicked(self):
""" """
@ -813,8 +823,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
QtGui.QMessageBox.No) QtGui.QMessageBox.No)
if answer == QtGui.QMessageBox.No: if answer == QtGui.QMessageBox.No:
return return
import_file_name = QtGui.QFileDialog.getOpenFileName(self,translate('OpenLP.MainWindow', 'Open File'), '', import_file_name = QtGui.QFileDialog.getOpenFileName(self, translate('OpenLP.MainWindow', 'Open File'), '',
translate('OpenLP.MainWindow', 'OpenLP Export Settings Files (*.conf)')) translate('OpenLP.MainWindow', 'OpenLP Export Settings Files (*.conf)'))
if not import_file_name: if not import_file_name:
return return
setting_sections = [] setting_sections = []
@ -830,14 +840,21 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
setting_sections.extend([self.headerSection]) setting_sections.extend([self.headerSection])
setting_sections.extend([u'crashreport']) setting_sections.extend([u'crashreport'])
# Add plugin sections. # Add plugin sections.
for plugin in self.pluginManager.plugins: for plugin in self.plugin_manager.plugins:
setting_sections.extend([plugin.name]) setting_sections.extend([plugin.name])
# Copy the settings file to the tmp dir, because we do not want to change the original one.
temp_directory = os.path.join(unicode(gettempdir()), u'openlp')
check_directory_exists(temp_directory)
temp_config = os.path.join(temp_directory, os.path.basename(import_file_name))
shutil.copyfile(import_file_name, temp_config)
settings = Settings() settings = Settings()
import_settings = Settings(import_file_name, Settings.IniFormat) import_settings = Settings(temp_config, Settings.IniFormat)
# Remove/rename old settings to prepare the import.
import_settings.remove_obsolete_settings()
# Lets do a basic sanity check. If it contains this string we can # Lets do a basic sanity check. If it contains this string we can
# assume it was created by OpenLP and so we'll load what we can # assume it was created by OpenLP and so we'll load what we can
# from it, and just silently ignore anything we don't recognise # from it, and just silently ignore anything we don't recognise
if import_settings.value(u'SettingsImport/type', u'') != u'OpenLP_settings_export': if import_settings.value(u'SettingsImport/type') != u'OpenLP_settings_export':
QtGui.QMessageBox.critical(self, translate('OpenLP.MainWindow', 'Import settings'), QtGui.QMessageBox.critical(self, translate('OpenLP.MainWindow', 'Import settings'),
translate('OpenLP.MainWindow', 'The file you have selected does not appear to be a valid OpenLP ' translate('OpenLP.MainWindow', 'The file you have selected does not appear to be a valid OpenLP '
'settings file.\n\nProcessing has terminated and no changes have been made.'), 'settings file.\n\nProcessing has terminated and no changes have been made.'),
@ -860,7 +877,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
continue continue
# We have a good file, import it. # We have a good file, import it.
for section_key in import_keys: for section_key in import_keys:
value = import_settings.value(section_key, None) if u'eneral' in section_key:
section_key = section_key.lower()
value = import_settings.value(section_key)
if value is not None: if value is not None:
settings.setValue(u'%s' % (section_key), value) settings.setValue(u'%s' % (section_key), value)
now = datetime.now() now = datetime.now()
@ -877,7 +896,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
'be applied the next time you start OpenLP.'), 'be applied the next time you start OpenLP.'),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok)) QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
self.settingsImported = True self.settingsImported = True
self.cleanUp() self.clean_up()
QtCore.QCoreApplication.exit() QtCore.QCoreApplication.exit()
def onSettingsExportItemClicked(self): def onSettingsExportItemClicked(self):
@ -891,7 +910,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
return return
# Make sure it's a .conf file. # Make sure it's a .conf file.
if not export_file_name.endswith(u'conf'): if not export_file_name.endswith(u'conf'):
export_file_name = export_file_name + u'.conf' export_file_name += u'.conf'
temp_file = os.path.join(unicode(gettempdir(), temp_file = os.path.join(unicode(gettempdir(),
get_filesystem_encoding()), u'openlp', u'exportConf.tmp') get_filesystem_encoding()), u'openlp', u'exportConf.tmp')
self.saveSettings() self.saveSettings()
@ -905,7 +924,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
setting_sections.extend([self.themesSettingsSection]) setting_sections.extend([self.themesSettingsSection])
setting_sections.extend([self.displayTagsSection]) setting_sections.extend([self.displayTagsSection])
# Add plugin sections. # Add plugin sections.
for plugin in self.pluginManager.plugins: for plugin in self.plugin_manager.plugins:
setting_sections.extend([plugin.name]) setting_sections.extend([plugin.name])
# Delete old files if found. # Delete old files if found.
if os.path.exists(temp_file): if os.path.exists(temp_file):
@ -926,13 +945,15 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
export_settings.beginGroup(self.headerSection) export_settings.beginGroup(self.headerSection)
export_settings.setValue(u'Make_Changes', u'At_Own_RISK') export_settings.setValue(u'Make_Changes', u'At_Own_RISK')
export_settings.setValue(u'type', u'OpenLP_settings_export') export_settings.setValue(u'type', u'OpenLP_settings_export')
export_settings.setValue(u'file_date_created', export_settings.setValue(u'file_date_created', now.strftime("%Y-%m-%d %H:%M"))
now.strftime("%Y-%m-%d %H:%M"))
export_settings.setValue(u'version', application_version[u'full']) export_settings.setValue(u'version', application_version[u'full'])
export_settings.endGroup() export_settings.endGroup()
# Write all the sections and keys. # Write all the sections and keys.
for section_key in keys: for section_key in keys:
key_value = settings.value(section_key, None) # FIXME: We are conflicting with the standard "General" section.
if u'eneral' in section_key:
section_key = section_key.lower()
key_value = settings.value(section_key)
if key_value is not None: if key_value is not None:
export_settings.setValue(section_key, key_value) export_settings.setValue(section_key, key_value)
export_settings.sync() export_settings.sync()
@ -940,16 +961,15 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
# Read the temp file and output the user's CONF file with blanks to # Read the temp file and output the user's CONF file with blanks to
# make it more readable. # make it more readable.
temp_conf = open(temp_file, u'r') temp_conf = open(temp_file, u'r')
export_conf = open(export_file_name, u'w') export_conf = open(export_file_name, u'w')
for file_record in temp_conf: for file_record in temp_conf:
# Get rid of any invalid entries. # Get rid of any invalid entries.
if file_record.find(u'@Invalid()') == -1: if file_record.find(u'@Invalid()') == -1:
file_record = file_record.replace(u'%20', u' ') file_record = file_record.replace(u'%20', u' ')
export_conf.write(file_record) export_conf.write(file_record)
temp_conf.close() temp_conf.close()
export_conf.close() export_conf.close()
os.remove(temp_file) os.remove(temp_file)
return
def onModeDefaultItemClicked(self): def onModeDefaultItemClicked(self):
""" """
@ -989,14 +1009,14 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
renderer. renderer.
""" """
log.debug(u'screenChanged') log.debug(u'screenChanged')
Receiver.send_message(u'cursor_busy') self.application.set_busy_cursor()
self.imageManager.updateDisplay() self.imageManager.update_display()
self.renderer.update_display() self.renderer.update_display()
self.previewController.screenSizeChanged() self.previewController.screenSizeChanged()
self.liveController.screenSizeChanged() self.liveController.screenSizeChanged()
self.setFocus() self.setFocus()
self.activateWindow() self.activateWindow()
Receiver.send_message(u'cursor_normal') self.application.set_normal_cursor()
def closeEvent(self, event): def closeEvent(self, event):
""" """
@ -1004,59 +1024,59 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
""" """
# The MainApplication did not even enter the event loop (this happens # The MainApplication did not even enter the event loop (this happens
# when OpenLP is not fully loaded). Just ignore the event. # when OpenLP is not fully loaded). Just ignore the event.
if not self.application.eventLoopIsActive: if not self.application.is_event_loop_active:
event.ignore() event.ignore()
return return
# If we just did a settings import, close without saving changes. # If we just did a settings import, close without saving changes.
if self.settingsImported: if self.settingsImported:
self.cleanUp(False) self.clean_up(False)
event.accept() event.accept()
if self.serviceManagerContents.isModified(): if self.serviceManagerContents.is_modified():
ret = self.serviceManagerContents.saveModifiedService() ret = self.serviceManagerContents.save_modified_service()
if ret == QtGui.QMessageBox.Save: if ret == QtGui.QMessageBox.Save:
if self.serviceManagerContents.decideSaveMethod(): if self.serviceManagerContents.decide_save_method():
self.cleanUp() self.clean_up()
event.accept() event.accept()
else: else:
event.ignore() event.ignore()
elif ret == QtGui.QMessageBox.Discard: elif ret == QtGui.QMessageBox.Discard:
self.cleanUp() self.clean_up()
event.accept() event.accept()
else: else:
event.ignore() event.ignore()
else: else:
if Settings().value(u'advanced/enable exit confirmation', True): if Settings().value(u'advanced/enable exit confirmation'):
ret = QtGui.QMessageBox.question(self, translate('OpenLP.MainWindow', 'Close OpenLP'), ret = QtGui.QMessageBox.question(self, translate('OpenLP.MainWindow', 'Close OpenLP'),
translate('OpenLP.MainWindow', 'Are you sure you want to close OpenLP?'), translate('OpenLP.MainWindow', 'Are you sure you want to close OpenLP?'),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No), QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No),
QtGui.QMessageBox.Yes) QtGui.QMessageBox.Yes)
if ret == QtGui.QMessageBox.Yes: if ret == QtGui.QMessageBox.Yes:
self.cleanUp() self.clean_up()
event.accept() event.accept()
else: else:
event.ignore() event.ignore()
else: else:
self.cleanUp() self.clean_up()
event.accept() event.accept()
def cleanUp(self, save_settings=True): def clean_up(self, save_settings=True):
""" """
Runs all the cleanup code before OpenLP shuts down. Runs all the cleanup code before OpenLP shuts down.
``save_settings`` ``save_settings``
Switch to prevent saving settings. Defaults to **True**. Switch to prevent saving settings. Defaults to **True**.
""" """
self.imageManager.stopManager = True self.imageManager.stop_manager = True
while self.imageManager.imageThread.isRunning(): while self.imageManager.image_thread.isRunning():
time.sleep(0.1) time.sleep(0.1)
# Clean temporary files used by services # Clean temporary files used by services
self.serviceManagerContents.cleanUp() self.serviceManagerContents.clean_up()
if save_settings: if save_settings:
if Settings().value(u'advanced/save current plugin', False): if Settings().value(u'advanced/save current plugin'):
Settings().setValue(u'advanced/current media plugin', self.mediaToolBox.currentIndex()) Settings().setValue(u'advanced/current media plugin', self.mediaToolBox.currentIndex())
# Call the cleanup method to shutdown plugins. # Call the cleanup method to shutdown plugins.
log.info(u'cleanup plugins') log.info(u'cleanup plugins')
self.pluginManager.finalise_plugins() self.plugin_manager.finalise_plugins()
if save_settings: if save_settings:
# Save settings # Save settings
self.saveSettings() self.saveSettings()
@ -1110,18 +1130,33 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.setWindowTitle(title) self.setWindowTitle(title)
def showStatusMessage(self, message): def showStatusMessage(self, message):
"""
Show a message in the status bar
"""
self.statusBar.showMessage(message) self.statusBar.showMessage(message)
def defaultThemeChanged(self, theme): def defaultThemeChanged(self, theme):
"""
Update the default theme indicator in the status bar
"""
self.defaultThemeLabel.setText(translate('OpenLP.MainWindow', 'Default Theme: %s') % theme) self.defaultThemeLabel.setText(translate('OpenLP.MainWindow', 'Default Theme: %s') % theme)
def toggleMediaManager(self): def toggleMediaManager(self):
"""
Toggle the visibility of the media manager
"""
self.mediaManagerDock.setVisible(not self.mediaManagerDock.isVisible()) self.mediaManagerDock.setVisible(not self.mediaManagerDock.isVisible())
def toggleServiceManager(self): def toggleServiceManager(self):
"""
Toggle the visibility of the service manager
"""
self.serviceManagerDock.setVisible(not self.serviceManagerDock.isVisible()) self.serviceManagerDock.setVisible(not self.serviceManagerDock.isVisible())
def toggleThemeManager(self): def toggleThemeManager(self):
"""
Toggle the visibility of the theme manager
"""
self.themeManagerDock.setVisible(not self.themeManagerDock.isVisible()) self.themeManagerDock.setVisible(not self.themeManagerDock.isVisible())
def setPreviewPanelVisibility(self, visible): def setPreviewPanelVisibility(self, visible):
@ -1181,28 +1216,20 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
Load the main window settings. Load the main window settings.
""" """
log.debug(u'Loading QSettings') log.debug(u'Loading QSettings')
# Migrate Wrap Settings to Slide Limits Settings
if Settings().contains(self.generalSettingsSection + u'/enable slide loop'):
if Settings().value(self.generalSettingsSection + u'/enable slide loop', True):
Settings().setValue(self.advancedSettingsSection + u'/slide limits', SlideLimits.Wrap)
else:
Settings().setValue(self.advancedSettingsSection + u'/slide limits', SlideLimits.End)
Settings().remove(self.generalSettingsSection + u'/enable slide loop')
Receiver.send_message(u'slidecontroller_update_slide_limits')
settings = Settings() settings = Settings()
# Remove obsolete entries. # Remove obsolete entries.
settings.remove(u'custom slide') settings.remove(u'custom slide')
settings.remove(u'service') settings.remove(u'service')
settings.beginGroup(self.generalSettingsSection) settings.beginGroup(self.generalSettingsSection)
self.recentFiles = settings.value(u'recent files', self.recentFiles) self.recentFiles = settings.value(u'recent files')
settings.endGroup() settings.endGroup()
settings.beginGroup(self.uiSettingsSection) settings.beginGroup(self.uiSettingsSection)
self.move(settings.value(u'main window position', QtCore.QPoint(0, 0))) self.move(settings.value(u'main window position'))
self.restoreGeometry(settings.value(u'main window geometry', QtCore.QByteArray())) self.restoreGeometry(settings.value(u'main window geometry'))
self.restoreState(settings.value(u'main window state', QtCore.QByteArray())) self.restoreState(settings.value(u'main window state'))
self.liveController.splitter.restoreState(settings.value(u'live splitter geometry', QtCore.QByteArray())) self.liveController.splitter.restoreState(settings.value(u'live splitter geometry'))
self.previewController.splitter.restoreState(settings.value(u'preview splitter geometry', QtCore.QByteArray())) self.previewController.splitter.restoreState(settings.value(u'preview splitter geometry'))
self.controlSplitter.restoreState(settings.value(u'mainwindow splitter geometry', QtCore.QByteArray())) self.controlSplitter.restoreState(settings.value(u'main window splitter geometry'))
settings.endGroup() settings.endGroup()
def saveSettings(self): def saveSettings(self):
@ -1223,7 +1250,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
settings.setValue(u'main window geometry', self.saveGeometry()) settings.setValue(u'main window geometry', self.saveGeometry())
settings.setValue(u'live splitter geometry', self.liveController.splitter.saveState()) settings.setValue(u'live splitter geometry', self.liveController.splitter.saveState())
settings.setValue(u'preview splitter geometry', self.previewController.splitter.saveState()) settings.setValue(u'preview splitter geometry', self.previewController.splitter.saveState())
settings.setValue(u'mainwindow splitter geometry', self.controlSplitter.saveState()) settings.setValue(u'main window splitter geometry', self.controlSplitter.saveState())
settings.endGroup() settings.endGroup()
def updateRecentFilesMenu(self): def updateRecentFilesMenu(self):
@ -1231,7 +1258,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
Updates the recent file menu with the latest list of service files Updates the recent file menu with the latest list of service files
accessed. accessed.
""" """
recentFileCount = Settings().value(u'advanced/recent file count', 4) recentFileCount = Settings().value(u'advanced/recent file count')
existingRecentFiles = [recentFile for recentFile in self.recentFiles existingRecentFiles = [recentFile for recentFile in self.recentFiles
if os.path.isfile(unicode(recentFile))] if os.path.isfile(unicode(recentFile))]
recentFilesToDisplay = existingRecentFiles[0:recentFileCount] recentFilesToDisplay = existingRecentFiles[0:recentFileCount]
@ -1241,7 +1268,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
action = create_action(self, u'', action = create_action(self, u'',
text=u'&%d %s' % (fileId + 1, os.path.splitext(os.path.basename( text=u'&%d %s' % (fileId + 1, os.path.splitext(os.path.basename(
unicode(filename)))[0]), data=filename, unicode(filename)))[0]), data=filename,
triggers=self.serviceManagerContents.onRecentServiceClicked) triggers=self.serviceManagerContents.on_recent_service_clicked)
self.recentFilesMenu.addAction(action) self.recentFilesMenu.addAction(action)
clearRecentFilesAction = create_action(self, u'', clearRecentFilesAction = create_action(self, u'',
text=translate('OpenLP.MainWindow', 'Clear List', 'Clear List of recent files'), text=translate('OpenLP.MainWindow', 'Clear List', 'Clear List of recent files'),
@ -1261,7 +1288,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
# The maxRecentFiles value does not have an interface and so never gets # The maxRecentFiles value does not have an interface and so never gets
# actually stored in the settings therefore the default value of 20 will # actually stored in the settings therefore the default value of 20 will
# always be used. # always be used.
maxRecentFiles = Settings().value(u'advanced/max recent files', 20) maxRecentFiles = Settings().value(u'advanced/max recent files')
if filename: if filename:
# Add some cleanup to reduce duplication in the recent file list # Add some cleanup to reduce duplication in the recent file list
filename = os.path.abspath(filename) filename = os.path.abspath(filename)
@ -1288,14 +1315,14 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.loadProgressBar.show() self.loadProgressBar.show()
self.loadProgressBar.setMaximum(size) self.loadProgressBar.setMaximum(size)
self.loadProgressBar.setValue(0) self.loadProgressBar.setValue(0)
Receiver.send_message(u'openlp_process_events') self.application.process_events()
def incrementProgressBar(self): def incrementProgressBar(self):
""" """
Increase the Progress Bar value by 1 Increase the Progress Bar value by 1
""" """
self.loadProgressBar.setValue(self.loadProgressBar.value() + 1) self.loadProgressBar.setValue(self.loadProgressBar.value() + 1)
Receiver.send_message(u'openlp_process_events') self.application.process_events()
def finishedProgressBar(self): def finishedProgressBar(self):
""" """
@ -1310,35 +1337,43 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
if event.timerId() == self.timer_id: if event.timerId() == self.timer_id:
self.timer_id = 0 self.timer_id = 0
self.loadProgressBar.hide() self.loadProgressBar.hide()
Receiver.send_message(u'openlp_process_events') self.application.process_events()
def setNewDataPath(self, new_data_path): def setNewDataPath(self, new_data_path):
"""
Set the new data path
"""
self.newDataPath = new_data_path self.newDataPath = new_data_path
def setCopyData(self, copy_data): def setCopyData(self, copy_data):
"""
Set the flag to copy the data
"""
self.copyData = copy_data self.copyData = copy_data
def changeDataDirectory(self): def changeDataDirectory(self):
log.info(u'Changing data path to %s' % self.newDataPath ) """
Change the data directory.
"""
log.info(u'Changing data path to %s' % self.newDataPath)
old_data_path = unicode(AppLocation.get_data_path()) old_data_path = unicode(AppLocation.get_data_path())
# Copy OpenLP data to new location if requested. # Copy OpenLP data to new location if requested.
self.application.set_busy_cursor()
if self.copyData: if self.copyData:
log.info(u'Copying data to new path') log.info(u'Copying data to new path')
try: try:
Receiver.send_message(u'openlp_process_events')
Receiver.send_message(u'cursor_busy')
self.showStatusMessage( self.showStatusMessage(
translate('OpenLP.MainWindow', 'Copying OpenLP data to new data directory location - %s ' translate('OpenLP.MainWindow', 'Copying OpenLP data to new data directory location - %s '
'- Please wait for copy to finish').replace('%s', self.newDataPath)) '- Please wait for copy to finish').replace('%s', self.newDataPath))
dir_util.copy_tree(old_data_path, self.newDataPath) dir_util.copy_tree(old_data_path, self.newDataPath)
log.info(u'Copy sucessful') log.info(u'Copy sucessful')
except (IOError, os.error, DistutilsFileError), why: except (IOError, os.error, DistutilsFileError), why:
Receiver.send_message(u'cursor_normal') self.application.set_normal_cursor()
log.exception(u'Data copy failed %s' % unicode(why)) log.exception(u'Data copy failed %s' % unicode(why))
QtGui.QMessageBox.critical(self, translate('OpenLP.MainWindow', 'New Data Directory Error'), QtGui.QMessageBox.critical(self, translate('OpenLP.MainWindow', 'New Data Directory Error'),
translate('OpenLP.MainWindow', translate('OpenLP.MainWindow',
'OpenLP Data directory copy failed\n\n%s').replace('%s', unicode(why)), 'OpenLP Data directory copy failed\n\n%s').replace('%s', unicode(why)),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok)) QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
return False return False
else: else:
log.info(u'No data copy requested') log.info(u'No data copy requested')
@ -1348,3 +1383,14 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
# Check if the new data path is our default. # Check if the new data path is our default.
if self.newDataPath == AppLocation.get_directory(AppLocation.DataDir): if self.newDataPath == AppLocation.get_directory(AppLocation.DataDir):
settings.remove(u'advanced/data path') settings.remove(u'advanced/data path')
self.application.set_normal_cursor()
def _get_application(self):
"""
Adds the openlp to the class dynamically
"""
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application)

View File

@ -26,6 +26,9 @@
# 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 #
############################################################################### ###############################################################################
"""
The :mod:`~openlp.core.ui.media` module contains classes and objects for media player integration.
"""
import logging import logging
from openlp.core.lib import Settings from openlp.core.lib import Settings
@ -34,6 +37,7 @@ from PyQt4 import QtCore
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class MediaState(object): class MediaState(object):
""" """
An enumeration for possible States of the Media Player An enumeration for possible States of the Media Player
@ -70,23 +74,23 @@ class MediaInfo(object):
end_time = 0 end_time = 0
media_type = MediaType() media_type = MediaType()
def get_media_players(): def get_media_players():
""" """
This method extracts the configured media players and overridden player This method extracts the configured media players and overridden player
from the settings. from the settings.
""" """
log.debug(u'get_media_players') log.debug(u'get_media_players')
saved_players = Settings().value(u'media/players', u'webkit') saved_players = Settings().value(u'media/players')
reg_ex = QtCore.QRegExp(".*\[(.*)\].*") reg_ex = QtCore.QRegExp(".*\[(.*)\].*")
if Settings().value(u'media/override player', if Settings().value(u'media/override player') == QtCore.Qt.Checked:
QtCore.Qt.Unchecked)== QtCore.Qt.Checked:
if reg_ex.exactMatch(saved_players): if reg_ex.exactMatch(saved_players):
overridden_player = u'%s' % reg_ex.cap(1) overridden_player = u'%s' % reg_ex.cap(1)
else: else:
overridden_player = u'auto' overridden_player = u'auto'
else: else:
overridden_player = u'' overridden_player = u''
saved_players_list = saved_players.replace(u'[', u'').replace(u']',u'').split(u',') saved_players_list = saved_players.replace(u'[', u'').replace(u']', u'').split(u',')
return saved_players_list, overridden_player return saved_players_list, overridden_player
@ -103,10 +107,11 @@ def set_media_players(players_list, overridden_player=u'auto'):
""" """
log.debug(u'set_media_players') log.debug(u'set_media_players')
players = u','.join(players_list) players = u','.join(players_list)
if Settings().value(u'media/override player', QtCore.Qt.Unchecked) == QtCore.Qt.Checked and \ if Settings().value(u'media/override player') == QtCore.Qt.Checked and overridden_player != u'auto':
overridden_player != u'auto':
players = players.replace(overridden_player, u'[%s]' % overridden_player) players = players.replace(overridden_player, u'[%s]' % overridden_player)
Settings().setValue(u'media/players', players) Settings().setValue(u'media/players', players)
from mediacontroller import MediaController from mediacontroller import MediaController
from playertab import PlayerTab from playertab import PlayerTab
__all__ = [u'MediaController', u'PlayerTab']

View File

@ -26,22 +26,59 @@
# 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 #
############################################################################### ###############################################################################
"""
The :mod:`~openlp.core.ui.media.mediacontroller` module contains a base class for media components and other widgets
related to playing media, such as sliders.
"""
import logging import logging
import os import os
import sys import datetime
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import OpenLPToolbar, Receiver, translate, Settings from openlp.core.lib import OpenLPToolbar, Receiver, Settings, Registry, UiStrings, translate
from openlp.core.lib.ui import UiStrings, 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
get_media_players, set_media_players
from openlp.core.ui.media.mediaplayer import MediaPlayer from openlp.core.ui.media.mediaplayer import MediaPlayer
from openlp.core.utils import AppLocation from openlp.core.utils import AppLocation
from openlp.core.ui import DisplayControllerType from openlp.core.ui import DisplayControllerType
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class MediaSlider(QtGui.QSlider):
"""
Allows the mouse events of a slider to be overridden and extra functionality added
"""
def __init__(self, direction, manager, controller, parent=None):
"""
Constructor
"""
QtGui.QSlider.__init__(self, direction)
self.manager = manager
self.controller = controller
def mouseMoveEvent(self, event):
"""
Override event to allow hover time to be displayed.
"""
timevalue = QtGui.QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), event.x(), self.width())
self.setToolTip(u'%s' % datetime.timedelta(seconds=int(timevalue / 1000)))
QtGui.QSlider.mouseMoveEvent(self, event)
def mousePressEvent(self, event):
"""
Mouse Press event no new functionality
"""
QtGui.QSlider.mousePressEvent(self, event)
def mouseReleaseEvent(self, event):
"""
Set the slider position when the mouse is clicked and released on the slider.
"""
self.setValue(QtGui.QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), event.x(), self.width()))
QtGui.QSlider.mouseReleaseEvent(self, event)
class MediaController(object): class MediaController(object):
""" """
The implementation of the Media Controller. The Media Controller adds an own The implementation of the Media Controller. The Media Controller adds an own
@ -57,7 +94,11 @@ class MediaController(object):
""" """
def __init__(self, parent): def __init__(self, parent):
"""
Constructor
"""
self.mainWindow = parent self.mainWindow = parent
Registry().register(u'media_controller', self)
self.mediaPlayers = {} self.mediaPlayers = {}
self.displayControllers = {} self.displayControllers = {}
self.currentMediaPlayer = {} self.currentMediaPlayer = {}
@ -65,12 +106,12 @@ class MediaController(object):
self.timer = QtCore.QTimer() self.timer = QtCore.QTimer()
self.timer.setInterval(200) self.timer.setInterval(200)
# Signals # Signals
QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.media_state) self.timer.timeout.connect(self.media_state)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'playbackPlay'), self.media_play_msg) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'playbackPlay'), self.media_play_msg)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'playbackPause'), self.media_pause_msg) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'playbackPause'), self.media_pause_msg)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'playbackStop'), self.media_stop_msg) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'playbackStop'), self.media_stop_msg)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'seekSlider'), self.media_seek) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'seekSlider'), self.media_seek_msg)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'volumeSlider'), self.media_volume) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'volumeSlider'), self.media_volume_msg)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'media_hide'), self.media_hide) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'media_hide'), self.media_hide)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'media_blank'), self.media_blank) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'media_blank'), self.media_blank)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'media_unblank'), self.media_unblank) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'media_unblank'), self.media_unblank)
@ -100,14 +141,14 @@ class MediaController(object):
for item in player.audio_extensions_list: for item in player.audio_extensions_list:
if not item in self.audio_extensions_list: if not item in self.audio_extensions_list:
self.audio_extensions_list.append(item) self.audio_extensions_list.append(item)
self.mainWindow.serviceManagerContents.supportedSuffixes(item[2:]) self.service_manager.supported_suffixes(item[2:])
self.video_extensions_list = [] self.video_extensions_list = []
for player in self.mediaPlayers.values(): for player in self.mediaPlayers.values():
if player.isActive: if player.isActive:
for item in player.video_extensions_list: for item in player.video_extensions_list:
if item not in self.video_extensions_list: if item not in self.video_extensions_list:
self.video_extensions_list.extend(item) self.video_extensions_list.extend(item)
self.mainWindow.serviceManagerContents.supportedSuffixes(item[2:]) self.service_manager.supported_suffixes(item[2:])
def register_players(self, player): def register_players(self, player):
""" """
@ -241,9 +282,10 @@ class MediaController(object):
icon=u':/slides/media_playback_stop.png', icon=u':/slides/media_playback_stop.png',
tooltip=translate('OpenLP.SlideController', 'Stop playing media.'), triggers=controller.sendToPlugins) tooltip=translate('OpenLP.SlideController', 'Stop playing media.'), triggers=controller.sendToPlugins)
# Build the seekSlider. # Build the seekSlider.
controller.seekSlider = QtGui.QSlider(QtCore.Qt.Horizontal) controller.seekSlider = MediaSlider(QtCore.Qt.Horizontal, self, controller)
controller.seekSlider.setMaximum(1000) controller.seekSlider.setMaximum(1000)
controller.seekSlider.setTracking(False) controller.seekSlider.setTracking(True)
controller.seekSlider.setMouseTracking(True)
controller.seekSlider.setToolTip(translate('OpenLP.SlideController', 'Video position.')) controller.seekSlider.setToolTip(translate('OpenLP.SlideController', 'Video position.'))
controller.seekSlider.setGeometry(QtCore.QRect(90, 260, 221, 24)) controller.seekSlider.setGeometry(QtCore.QRect(90, 260, 221, 24))
controller.seekSlider.setObjectName(u'seekSlider') controller.seekSlider.setObjectName(u'seekSlider')
@ -266,7 +308,6 @@ class MediaController(object):
QtCore.QObject.connect(controller.seekSlider, QtCore.SIGNAL(u'valueChanged(int)'), controller.sendToPlugins) QtCore.QObject.connect(controller.seekSlider, QtCore.SIGNAL(u'valueChanged(int)'), controller.sendToPlugins)
QtCore.QObject.connect(controller.volumeSlider, QtCore.SIGNAL(u'valueChanged(int)'), controller.sendToPlugins) QtCore.QObject.connect(controller.volumeSlider, QtCore.SIGNAL(u'valueChanged(int)'), controller.sendToPlugins)
def setup_display(self, display, preview): def setup_display(self, display, preview):
""" """
After a new display is configured, all media related widget will be After a new display is configured, all media related widget will be
@ -344,12 +385,8 @@ class MediaController(object):
# stop running videos # stop running videos
self.media_reset(controller) self.media_reset(controller)
controller.media_info = MediaInfo() controller.media_info = MediaInfo()
if videoBehindText: controller.media_info.volume = controller.volumeSlider.value()
controller.media_info.volume = 0 controller.media_info.is_background = videoBehindText
controller.media_info.is_background = True
else:
controller.media_info.volume = controller.volumeSlider.value()
controller.media_info.is_background = False
controller.media_info.file_info = QtCore.QFileInfo(serviceItem.get_frame_path()) controller.media_info.file_info = QtCore.QFileInfo(serviceItem.get_frame_path())
display = self._define_display(controller) display = self._define_display(controller)
if controller.isLive: if controller.isLive:
@ -361,7 +398,7 @@ class MediaController(object):
controller.media_info.start_time = 0 controller.media_info.start_time = 0
controller.media_info.end_time = 0 controller.media_info.end_time = 0
else: else:
controller.media_info.start_time = display.serviceItem.start_time controller.media_info.start_time = serviceItem.start_time
controller.media_info.end_time = serviceItem.end_time controller.media_info.end_time = serviceItem.end_time
elif controller.previewDisplay: elif controller.previewDisplay:
isValid = self._check_file_type(controller, display, serviceItem) isValid = self._check_file_type(controller, display, serviceItem)
@ -382,7 +419,7 @@ class MediaController(object):
elif not hidden or controller.media_info.is_background or serviceItem.will_auto_start: elif not hidden or controller.media_info.is_background or serviceItem.will_auto_start:
autoplay = True autoplay = True
# Unblank on load set # Unblank on load set
elif Settings().value(u'general/auto unblank', False): elif Settings().value(u'general/auto unblank'):
autoplay = True autoplay = True
if autoplay: if autoplay:
if not self.media_play(controller): if not self.media_play(controller):
@ -400,7 +437,7 @@ class MediaController(object):
``serviceItem`` ``serviceItem``
The ServiceItem containing the details to be played. The ServiceItem containing the details to be played.
""" """
controller = self.displayControllers[DisplayControllerType.Plugin] controller = self.displayControllers[DisplayControllerType.Plugin]
log.debug(u'media_length') log.debug(u'media_length')
# stop running videos # stop running videos
self.media_reset(controller) self.media_reset(controller)
@ -472,8 +509,7 @@ class MediaController(object):
First element is the controller which should be used First element is the controller which should be used
""" """
log.debug(u'media_play_msg') log.debug(u'media_play_msg')
self.media_play(msg[0],status) self.media_play(msg[0], status)
def media_play(self, controller, status=True): def media_play(self, controller, status=True):
""" """
@ -483,9 +519,17 @@ class MediaController(object):
The controller to be played The controller to be played
""" """
log.debug(u'media_play') log.debug(u'media_play')
controller.seekSlider.blockSignals(True)
controller.volumeSlider.blockSignals(True)
display = self._define_display(controller) display = self._define_display(controller)
if not self.currentMediaPlayer[controller.controllerType].play(display): if not self.currentMediaPlayer[controller.controllerType].play(display):
controller.seekSlider.blockSignals(False)
controller.volumeSlider.blockSignals(False)
return False return False
if controller.media_info.is_background:
self.media_volume(controller, 0)
else:
self.media_volume(controller, controller.media_info.volume)
if status: if status:
display.frame.evaluateJavaScript(u'show_blank("desktop");') display.frame.evaluateJavaScript(u'show_blank("desktop");')
self.currentMediaPlayer[controller.controllerType].set_visible(display, True) self.currentMediaPlayer[controller.controllerType].set_visible(display, True)
@ -503,6 +547,8 @@ class MediaController(object):
# Start Timer for ui updates # Start Timer for ui updates
if not self.timer.isActive(): if not self.timer.isActive():
self.timer.start() self.timer.start()
controller.seekSlider.blockSignals(False)
controller.volumeSlider.blockSignals(False)
return True return True
def media_pause_msg(self, msg): def media_pause_msg(self, msg):
@ -513,7 +559,7 @@ class MediaController(object):
First element is the controller which should be used First element is the controller which should be used
""" """
log.debug(u'media_pause_msg') log.debug(u'media_pause_msg')
self.media_pause( msg[0]) self.media_pause(msg[0])
def media_pause(self, controller): def media_pause(self, controller):
""" """
@ -557,7 +603,7 @@ class MediaController(object):
controller.mediabar.actions[u'playbackStop'].setVisible(False) controller.mediabar.actions[u'playbackStop'].setVisible(False)
controller.mediabar.actions[u'playbackPause'].setVisible(False) controller.mediabar.actions[u'playbackPause'].setVisible(False)
def media_volume(self, msg): def media_volume_msg(self, msg):
""" """
Changes the volume of a running video Changes the volume of a running video
@ -566,11 +612,21 @@ class MediaController(object):
""" """
controller = msg[0] controller = msg[0]
vol = msg[1][0] vol = msg[1][0]
log.debug(u'media_volume %d' % vol) self.media_volume(controller, vol)
display = self._define_display(controller)
self.currentMediaPlayer[controller.controllerType].volume(display, vol)
def media_seek(self, msg): def media_volume(self, controller, volume):
"""
Changes the volume of a running video
``msg``
First element is the controller which should be used
"""
log.debug(u'media_volume %d' % volume)
display = self._define_display(controller)
self.currentMediaPlayer[controller.controllerType].volume(display, volume)
controller.volumeSlider.setValue(volume)
def media_seek_msg(self, msg):
""" """
Responds to the request to change the seek Slider of a loaded video Responds to the request to change the seek Slider of a loaded video
@ -581,6 +637,17 @@ class MediaController(object):
log.debug(u'media_seek') log.debug(u'media_seek')
controller = msg[0] controller = msg[0]
seekVal = msg[1][0] seekVal = msg[1][0]
self.media_seek(controller, seekVal)
def media_seek(self, controller, seekVal):
"""
Responds to the request to change the seek Slider of a loaded video
``msg``
First element is the controller which should be used
Second element is a list with the seek Value as first element
"""
log.debug(u'media_seek')
display = self._define_display(controller) display = self._define_display(controller)
self.currentMediaPlayer[controller.controllerType].seek(display, seekVal) self.currentMediaPlayer[controller.controllerType].seek(display, seekVal)
@ -610,7 +677,8 @@ class MediaController(object):
return return
controller = self.mainWindow.liveController controller = self.mainWindow.liveController
display = self._define_display(controller) display = self._define_display(controller)
if self.currentMediaPlayer[controller.controllerType].state == MediaState.Playing: if controller.controllerType in self.currentMediaPlayer and \
self.currentMediaPlayer[controller.controllerType].state == MediaState.Playing:
self.currentMediaPlayer[controller.controllerType].pause(display) self.currentMediaPlayer[controller.controllerType].pause(display)
self.currentMediaPlayer[controller.controllerType].set_visible(display, False) self.currentMediaPlayer[controller.controllerType].set_visible(display, False)
@ -656,6 +724,9 @@ class MediaController(object):
self.timer.start() self.timer.start()
def finalise(self): def finalise(self):
"""
Reset all the media controllers when OpenLP shuts down
"""
self.timer.stop() self.timer.stop()
for controller in self.displayControllers: for controller in self.displayControllers:
self.media_reset(self.displayControllers[controller]) self.media_reset(self.displayControllers[controller])
@ -670,3 +741,13 @@ class MediaController(object):
if controller.isLive: if controller.isLive:
return controller.display return controller.display
return controller.previewDisplay return controller.previewDisplay
def _get_service_manager(self):
"""
Adds the plugin manager to the class dynamically
"""
if not hasattr(self, u'_service_manager'):
self._service_manager = Registry().get(u'service_manager')
return self._service_manager
service_manager = property(_get_service_manager)

View File

@ -26,9 +26,13 @@
# 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 #
############################################################################### ###############################################################################
"""
The :mod:`~openlp.core.ui.media.mediaplayer` module contains the MediaPlayer class.
"""
from openlp.core.lib import Registry
from openlp.core.ui.media import MediaState from openlp.core.ui.media import MediaState
class MediaPlayer(object): class MediaPlayer(object):
""" """
This is the base class media Player class to provide OpenLP with a This is the base class media Player class to provide OpenLP with a
@ -36,6 +40,9 @@ class MediaPlayer(object):
""" """
def __init__(self, parent, name=u'media_player'): def __init__(self, parent, name=u'media_player'):
"""
Constructor
"""
self.parent = parent self.parent = parent
self.name = name self.name = name
self.available = self.check_available() self.available = self.check_available()
@ -143,3 +150,13 @@ class MediaPlayer(object):
Returns Information about the player Returns Information about the player
""" """
return u'' return u''
def _get_application(self):
"""
Adds the openlp to the class dynamically
"""
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application)

View File

@ -26,15 +26,17 @@
# 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 #
############################################################################### ###############################################################################
"""
The :mod:`~openlp.core.ui.media.phononplayer` contains the Phonon player component.
"""
import logging import logging
import mimetypes import mimetypes
from datetime import datetime from datetime import datetime
from PyQt4 import QtCore, QtGui from PyQt4 import QtGui
from PyQt4.phonon import Phonon from PyQt4.phonon import Phonon
from openlp.core.lib import Receiver, translate, Settings from openlp.core.lib import Settings, translate
from openlp.core.ui.media import MediaState from openlp.core.ui.media import MediaState
from openlp.core.ui.media.mediaplayer import MediaPlayer from openlp.core.ui.media.mediaplayer import MediaPlayer
@ -56,24 +58,25 @@ ADDITIONAL_EXT = {
u'video/x-matroska': [u'.mpv', u'.mkv'], u'video/x-matroska': [u'.mpv', u'.mkv'],
u'video/x-wmv': [u'.wmv'], u'video/x-wmv': [u'.wmv'],
u'video/x-mpg': [u'.mpg'], u'video/x-mpg': [u'.mpg'],
u'video/mpeg' : [u'.mp4', u'.mts', u'.mov'], u'video/mpeg': [u'.mp4', u'.mts', u'.mov'],
u'video/x-ms-wmv': [u'.wmv']} u'video/x-ms-wmv': [u'.wmv']}
VIDEO_CSS = u""" VIDEO_CSS = u"""
#videobackboard { #videobackboard {
z-index:3; z-index:3;
background-color: %s; background-color: %(bgcolor)s;
} }
#video1 { #video1 {
background-color: %s; background-color: %(bgcolor)s;
z-index:4; z-index:4;
} }
#video2 { #video2 {
background-color: %s; background-color: %(bgcolor)s;
z-index:4; z-index:4;
} }
""" """
class PhononPlayer(MediaPlayer): 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
@ -81,6 +84,9 @@ class PhononPlayer(MediaPlayer):
""" """
def __init__(self, parent): def __init__(self, parent):
"""
Constructor
"""
MediaPlayer.__init__(self, parent, u'phonon') MediaPlayer.__init__(self, parent, u'phonon')
self.original_name = u'Phonon' self.original_name = u'Phonon'
self.display_name = u'&Phonon' self.display_name = u'&Phonon'
@ -94,13 +100,16 @@ class PhononPlayer(MediaPlayer):
elif mimetype.startswith(u'video/'): elif mimetype.startswith(u'video/'):
self._addToList(self.video_extensions_list, mimetype) self._addToList(self.video_extensions_list, mimetype)
def _addToList(self, list, mimetype): def _addToList(self, mimetype_list, mimetype):
"""
Add mimetypes to the provided list
"""
# Add all extensions which mimetypes provides us for supported types. # Add all extensions which mimetypes provides us for supported types.
extensions = mimetypes.guess_all_extensions(unicode(mimetype)) extensions = mimetypes.guess_all_extensions(unicode(mimetype))
for extension in extensions: for extension in extensions:
ext = u'*%s' % extension ext = u'*%s' % extension
if ext not in list: if ext not in mimetype_list:
list.append(ext) mimetype_list.append(ext)
log.info(u'MediaPlugin: %s extensions: %s' % (mimetype, u' '.join(extensions))) log.info(u'MediaPlugin: %s extensions: %s' % (mimetype, u' '.join(extensions)))
# Add extensions for this mimetype from self.additional_extensions. # Add extensions for this mimetype from self.additional_extensions.
# This hack clears mimetypes' and operating system's shortcomings # This hack clears mimetypes' and operating system's shortcomings
@ -108,12 +117,15 @@ class PhononPlayer(MediaPlayer):
if mimetype in self.additional_extensions.keys(): if mimetype in self.additional_extensions.keys():
for extension in self.additional_extensions[mimetype]: for extension in self.additional_extensions[mimetype]:
ext = u'*%s' % extension ext = u'*%s' % extension
if ext not in list: if ext not in mimetype_list:
list.append(ext) mimetype_list.append(ext)
log.info(u'MediaPlugin: %s additional extensions: %s' % log.info(u'MediaPlugin: %s additional extensions: %s' %
(mimetype, u' '.join(self.additional_extensions[mimetype]))) (mimetype, u' '.join(self.additional_extensions[mimetype])))
def setup(self, display): def setup(self, display):
"""
Set up the player widgets
"""
display.phononWidget = Phonon.VideoWidget(display) display.phononWidget = Phonon.VideoWidget(display)
display.phononWidget.resize(display.size()) display.phononWidget.resize(display.size())
display.mediaObject = Phonon.MediaObject(display) display.mediaObject = Phonon.MediaObject(display)
@ -126,9 +138,15 @@ class PhononPlayer(MediaPlayer):
self.hasOwnWidget = True self.hasOwnWidget = True
def check_available(self): def check_available(self):
"""
Check if the player is available
"""
return True return True
def load(self, display): def load(self, display):
"""
Load a video into the display
"""
log.debug(u'load vid in Phonon Controller') log.debug(u'load vid in Phonon Controller')
controller = display.controller controller = display.controller
volume = controller.media_info.volume volume = controller.media_info.volume
@ -150,15 +168,21 @@ class PhononPlayer(MediaPlayer):
current_state = display.mediaObject.state() current_state = display.mediaObject.state()
if current_state == Phonon.ErrorState: if current_state == Phonon.ErrorState:
return False return False
Receiver.send_message(u'openlp_process_events') self.application.process_events()
if (datetime.now() - start).seconds > 5: if (datetime.now() - start).seconds > 5:
return False return False
return True return True
def resize(self, display): def resize(self, display):
"""
Resize the display
"""
display.phononWidget.resize(display.size()) display.phononWidget.resize(display.size())
def play(self, display): def play(self, display):
"""
Play the current media item
"""
controller = display.controller controller = display.controller
start_time = 0 start_time = 0
if display.mediaObject.state() != Phonon.PausedState and \ if display.mediaObject.state() != Phonon.PausedState and \
@ -177,25 +201,40 @@ class PhononPlayer(MediaPlayer):
return True return True
def pause(self, display): def pause(self, display):
"""
Pause the current media item
"""
display.mediaObject.pause() display.mediaObject.pause()
if self.media_state_wait(display, Phonon.PausedState): if self.media_state_wait(display, Phonon.PausedState):
self.state = MediaState.Paused self.state = MediaState.Paused
def stop(self, display): def stop(self, display):
"""
Stop the current media item
"""
display.mediaObject.stop() display.mediaObject.stop()
self.set_visible(display, False) self.set_visible(display, False)
self.state = MediaState.Stopped self.state = MediaState.Stopped
def volume(self, display, vol): def volume(self, display, vol):
"""
Set the volume
"""
# 1.0 is the highest value # 1.0 is the highest value
if display.hasAudio: if display.hasAudio:
vol = float(vol) / float(100) vol = float(vol) / float(100)
display.audio.setVolume(vol) display.audio.setVolume(vol)
def seek(self, display, seekVal): def seek(self, display, seekVal):
"""
Go to a particular point in the current media item
"""
display.mediaObject.seek(seekVal) display.mediaObject.seek(seekVal)
def reset(self, display): def reset(self, display):
"""
Reset the media player
"""
display.mediaObject.stop() display.mediaObject.stop()
display.mediaObject.clearQueue() display.mediaObject.clearQueue()
self.set_visible(display, False) self.set_visible(display, False)
@ -203,10 +242,16 @@ class PhononPlayer(MediaPlayer):
self.state = MediaState.Off self.state = MediaState.Off
def set_visible(self, display, status): def set_visible(self, display, status):
"""
Set the visibility of the widget
"""
if self.hasOwnWidget: if self.hasOwnWidget:
display.phononWidget.setVisible(status) display.phononWidget.setVisible(status)
def update_ui(self, display): def update_ui(self, display):
"""
Update the UI
"""
if display.mediaObject.state() == Phonon.PausedState and self.state != MediaState.Paused: if display.mediaObject.state() == Phonon.PausedState and self.state != MediaState.Paused:
self.stop(display) self.stop(display)
controller = display.controller controller = display.controller
@ -215,17 +260,21 @@ class PhononPlayer(MediaPlayer):
self.stop(display) self.stop(display)
self.set_visible(display, False) self.set_visible(display, False)
if not controller.seekSlider.isSliderDown(): if not controller.seekSlider.isSliderDown():
controller.seekSlider.setSliderPosition( controller.seekSlider.blockSignals(True)
display.mediaObject.currentTime()) controller.seekSlider.setSliderPosition(display.mediaObject.currentTime())
controller.seekSlider.blockSignals(False)
def get_media_display_css(self): def get_media_display_css(self):
""" """
Add css style sheets to htmlbuilder Add css style sheets to htmlbuilder
""" """
background = QtGui.QColor(Settings().value(u'players/background color', u'#000000')).name() background = QtGui.QColor(Settings().value(u'players/background color')).name()
return VIDEO_CSS % (background,background,background) return VIDEO_CSS % {u'bgcolor': background}
def get_info(self): def get_info(self):
"""
Return some info about this player
"""
return(translate('Media.player', 'Phonon is a media player which ' return(translate('Media.player', 'Phonon is a media player which '
'interacts with the operating system to provide media capabilities.') + 'interacts with the operating system to provide media capabilities.') +
u'<br/> <strong>' + translate('Media.player', 'Audio') + u'<br/> <strong>' + translate('Media.player', 'Audio') +

View File

@ -26,18 +26,24 @@
# 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 #
############################################################################### ###############################################################################
"""
The :mod:`~openlp.core.ui.media.playertab` module holds the configuration tab for the media stuff.
"""
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import SettingsTab, translate, Receiver, Settings from openlp.core.lib import SettingsTab, Receiver, Settings, UiStrings, translate
from openlp.core.lib.ui import UiStrings, create_button from openlp.core.lib.ui import create_button
from openlp.core.ui.media import get_media_players, set_media_players 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.
""" """
def setPlayerName(self, name): def setPlayerName(self, name):
"""
Set the player name
"""
self.playerName = name self.playerName = name
@ -45,16 +51,20 @@ class PlayerTab(SettingsTab):
""" """
MediaTab is the Media settings tab in the settings dialog. MediaTab is the Media settings tab in the settings dialog.
""" """
def __init__(self, parent, mainWindow): def __init__(self, parent):
self.parent = parent """
self.mainWindow = mainWindow Constructor
self.mediaPlayers = mainWindow.mediaController.mediaPlayers """
self.mediaPlayers = self.media_controller.mediaPlayers
self.savedUsedPlayers = None self.savedUsedPlayers = None
self.iconPath = u':/media/multimedia-player.png' self.iconPath = u':/media/multimedia-player.png'
player_translated = translate('OpenLP.PlayerTab', 'Players') player_translated = translate('OpenLP.PlayerTab', 'Players')
SettingsTab.__init__(self, parent, u'Players', player_translated) SettingsTab.__init__(self, parent, u'Players', player_translated)
def setupUi(self): def setupUi(self):
"""
Set up the UI
"""
self.setObjectName(u'MediaTab') self.setObjectName(u'MediaTab')
SettingsTab.setupUi(self) SettingsTab.setupUi(self)
self.bgColorGroupBox = QtGui.QGroupBox(self.leftColumn) self.bgColorGroupBox = QtGui.QGroupBox(self.leftColumn)
@ -116,6 +126,9 @@ class PlayerTab(SettingsTab):
self.onbackgroundColorButtonClicked) self.onbackgroundColorButtonClicked)
def retranslateUi(self): def retranslateUi(self):
"""
Translate the UI on the fly
"""
self.mediaPlayerGroupBox.setTitle(translate('OpenLP.PlayerTab', 'Available Media Players')) self.mediaPlayerGroupBox.setTitle(translate('OpenLP.PlayerTab', 'Available Media Players'))
self.playerOrderGroupBox.setTitle(translate('OpenLP.PlayerTab', 'Player Search Order')) self.playerOrderGroupBox.setTitle(translate('OpenLP.PlayerTab', 'Player Search Order'))
self.bgColorGroupBox.setTitle(UiStrings().BackgroundColor) self.bgColorGroupBox.setTitle(UiStrings().BackgroundColor)
@ -125,12 +138,18 @@ class PlayerTab(SettingsTab):
self.retranslatePlayers() self.retranslatePlayers()
def onbackgroundColorButtonClicked(self): def onbackgroundColorButtonClicked(self):
"""
Set the background color
"""
new_color = QtGui.QColorDialog.getColor(QtGui.QColor(self.bg_color), self) new_color = QtGui.QColorDialog.getColor(QtGui.QColor(self.bg_color), self)
if new_color.isValid(): if new_color.isValid():
self.bg_color = new_color.name() self.bg_color = new_color.name()
self.backgroundColorButton.setStyleSheet(u'background-color: %s' % self.bg_color) self.backgroundColorButton.setStyleSheet(u'background-color: %s' % self.bg_color)
def onPlayerCheckBoxChanged(self, check_state): def onPlayerCheckBoxChanged(self, check_state):
"""
Add or remove players depending on their status
"""
player = self.sender().playerName player = self.sender().playerName
if check_state == QtCore.Qt.Checked: if check_state == QtCore.Qt.Checked:
if player not in self.usedPlayers: if player not in self.usedPlayers:
@ -141,6 +160,9 @@ class PlayerTab(SettingsTab):
self.updatePlayerList() self.updatePlayerList()
def updatePlayerList(self): def updatePlayerList(self):
"""
Update the list of media players
"""
self.playerOrderlistWidget.clear() self.playerOrderlistWidget.clear()
for player in self.usedPlayers: for player in self.usedPlayers:
if player in self.playerCheckBoxes.keys(): if player in self.playerCheckBoxes.keys():
@ -152,6 +174,9 @@ class PlayerTab(SettingsTab):
self.playerOrderlistWidget.addItem(self.mediaPlayers[unicode(player)].original_name) self.playerOrderlistWidget.addItem(self.mediaPlayers[unicode(player)].original_name)
def onUpButtonClicked(self): def onUpButtonClicked(self):
"""
Move a media player up in the order
"""
row = self.playerOrderlistWidget.currentRow() row = self.playerOrderlistWidget.currentRow()
if row <= 0: if row <= 0:
return return
@ -161,6 +186,9 @@ class PlayerTab(SettingsTab):
self.usedPlayers.insert(row - 1, self.usedPlayers.pop(row)) self.usedPlayers.insert(row - 1, self.usedPlayers.pop(row))
def onDownButtonClicked(self): def onDownButtonClicked(self):
"""
Move a media player down in the order
"""
row = self.playerOrderlistWidget.currentRow() row = self.playerOrderlistWidget.currentRow()
if row == -1 or row > self.playerOrderlistWidget.count() - 1: if row == -1 or row > self.playerOrderlistWidget.count() - 1:
return return
@ -170,6 +198,9 @@ class PlayerTab(SettingsTab):
self.usedPlayers.insert(row + 1, self.usedPlayers.pop(row)) self.usedPlayers.insert(row + 1, self.usedPlayers.pop(row))
def load(self): def load(self):
"""
Load the settings
"""
if self.savedUsedPlayers: if self.savedUsedPlayers:
self.usedPlayers = self.savedUsedPlayers self.usedPlayers = self.savedUsedPlayers
self.usedPlayers = get_media_players()[0] self.usedPlayers = get_media_players()[0]
@ -177,12 +208,15 @@ class PlayerTab(SettingsTab):
settings = Settings() settings = Settings()
settings.beginGroup(self.settingsSection) settings.beginGroup(self.settingsSection)
self.updatePlayerList() self.updatePlayerList()
self.bg_color = settings.value(u'background color', u'#000000') self.bg_color = settings.value(u'background color')
self.initial_color = self.bg_color self.initial_color = self.bg_color
settings.endGroup() settings.endGroup()
self.backgroundColorButton.setStyleSheet(u'background-color: %s' % self.bg_color) self.backgroundColorButton.setStyleSheet(u'background-color: %s' % self.bg_color)
def save(self): def save(self):
"""
Save the settings
"""
player_string_changed = False player_string_changed = False
settings = Settings() settings = Settings()
settings.beginGroup(self.settingsSection) settings.beginGroup(self.settingsSection)
@ -194,7 +228,7 @@ class PlayerTab(SettingsTab):
set_media_players(self.usedPlayers, override_player) set_media_players(self.usedPlayers, override_player)
player_string_changed = True player_string_changed = True
if player_string_changed: if player_string_changed:
self.parent.resetSupportedSuffixes() self.service_manager.reset_supported_suffixes()
Receiver.send_message(u'mediaitem_media_rebuild') Receiver.send_message(u'mediaitem_media_rebuild')
Receiver.send_message(u'config_screen_changed') Receiver.send_message(u'config_screen_changed')
@ -211,7 +245,7 @@ class PlayerTab(SettingsTab):
checkbox.setToolTip(player.get_info()) checkbox.setToolTip(player.get_info())
checkbox.setPlayerName(player.name) checkbox.setPlayerName(player.name)
self.playerCheckBoxes[player.name] = checkbox self.playerCheckBoxes[player.name] = checkbox
QtCore.QObject.connect(checkbox,QtCore.SIGNAL(u'stateChanged(int)'), self.onPlayerCheckBoxChanged) QtCore.QObject.connect(checkbox, QtCore.SIGNAL(u'stateChanged(int)'), self.onPlayerCheckBoxChanged)
self.mediaPlayerLayout.addWidget(checkbox) self.mediaPlayerLayout.addWidget(checkbox)
if player.available and player.name in self.usedPlayers: if player.available and player.name in self.usedPlayers:
checkbox.setChecked(True) checkbox.setChecked(True)

View File

@ -26,3 +26,7 @@
# 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 #
############################################################################### ###############################################################################
"""
The :mod:`~openlp.core.ui.media.vendor` module contains any scripts or libraries
from 3rd party vendors which are required to make certain media modules work.
"""

View File

@ -26,16 +26,18 @@
# 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 #
############################################################################### ###############################################################################
"""
The :mod:`~openlp.core.ui.media.vlcplayer` module contains our VLC component wrapper
"""
from datetime import datetime from datetime import datetime
from distutils.version import LooseVersion from distutils.version import LooseVersion
import logging import logging
import os import os
import sys import sys
from PyQt4 import QtCore, QtGui from PyQt4 import QtGui
from openlp.core.lib import Receiver, translate, Settings from openlp.core.lib import Settings, translate
from openlp.core.ui.media import MediaState from openlp.core.ui.media import MediaState
from openlp.core.ui.media.mediaplayer import MediaPlayer from openlp.core.ui.media.mediaplayer import MediaPlayer
@ -80,8 +82,8 @@ VIDEO_EXT = [
u'*.nsc', u'*.nsc',
u'*.nsv', u'*.nsv',
u'*.nut', u'*.nut',
u'*.ra', u'*.ram', u'*.rm', u'*.rv' ,u'*.rmbv', u'*.ra', u'*.ram', u'*.rm', u'*.rv', u'*.rmbv',
u'*.a52', u'*.dts', u'*.aac', u'*.flac' ,u'*.dv', u'*.vid', u'*.a52', u'*.dts', u'*.aac', u'*.flac', u'*.dv', u'*.vid',
u'*.tta', u'*.tac', u'*.tta', u'*.tac',
u'*.ty', u'*.ty',
u'*.dts', u'*.dts',
@ -99,6 +101,9 @@ class VlcPlayer(MediaPlayer):
""" """
def __init__(self, parent): def __init__(self, parent):
"""
Constructor
"""
MediaPlayer.__init__(self, parent, u'vlc') MediaPlayer.__init__(self, parent, u'vlc')
self.original_name = u'VLC' self.original_name = u'VLC'
self.display_name = u'&VLC' self.display_name = u'&VLC'
@ -108,12 +113,16 @@ class VlcPlayer(MediaPlayer):
self.video_extensions_list = VIDEO_EXT self.video_extensions_list = VIDEO_EXT
def setup(self, display): def setup(self, display):
"""
Set up the media player
"""
display.vlcWidget = QtGui.QFrame(display) display.vlcWidget = QtGui.QFrame(display)
display.vlcWidget.setFrameStyle(QtGui.QFrame.NoFrame)
# creating a basic vlc instance # creating a basic vlc instance
command_line_options = u'--no-video-title-show' command_line_options = u'--no-video-title-show'
if not display.hasAudio: if not display.hasAudio:
command_line_options += u' --no-audio --no-video-title-show' command_line_options += u' --no-audio --no-video-title-show'
if Settings().value(u'advanced/hide mouse', True) and display.controller.isLive: if Settings().value(u'advanced/hide mouse') and display.controller.isLive:
command_line_options += u' --mouse-hide-timeout=0' command_line_options += u' --mouse-hide-timeout=0'
display.vlcInstance = vlc.Instance(command_line_options) display.vlcInstance = vlc.Instance(command_line_options)
display.vlcInstance.set_log_verbosity(2) display.vlcInstance.set_log_verbosity(2)
@ -140,9 +149,15 @@ class VlcPlayer(MediaPlayer):
self.hasOwnWidget = True self.hasOwnWidget = True
def check_available(self): def check_available(self):
"""
Return the availability of VLC
"""
return VLC_AVAILABLE return VLC_AVAILABLE
def load(self, display): def load(self, display):
"""
Load a video into VLC
"""
log.debug(u'load vid in Vlc Controller') log.debug(u'load vid in Vlc Controller')
controller = display.controller controller = display.controller
volume = controller.media_info.volume volume = controller.media_info.volume
@ -172,15 +187,21 @@ class VlcPlayer(MediaPlayer):
while not mediaState == display.vlcMedia.get_state(): while not mediaState == display.vlcMedia.get_state():
if display.vlcMedia.get_state() == vlc.State.Error: if display.vlcMedia.get_state() == vlc.State.Error:
return False return False
Receiver.send_message(u'openlp_process_events') self.application.process_events()
if (datetime.now() - start).seconds > 60: if (datetime.now() - start).seconds > 60:
return False return False
return True return True
def resize(self, display): def resize(self, display):
"""
Resize the player
"""
display.vlcWidget.resize(display.size()) display.vlcWidget.resize(display.size())
def play(self, display): def play(self, display):
"""
Play the current item
"""
controller = display.controller controller = display.controller
start_time = 0 start_time = 0
if self.state != MediaState.Paused and controller.media_info.start_time > 0: if self.state != MediaState.Paused and controller.media_info.start_time > 0:
@ -188,6 +209,7 @@ class VlcPlayer(MediaPlayer):
display.vlcMediaPlayer.play() display.vlcMediaPlayer.play()
if not self.media_state_wait(display, vlc.State.Playing): if not self.media_state_wait(display, vlc.State.Playing):
return False return False
self.volume(display, controller.media_info.volume)
if start_time > 0: if start_time > 0:
self.seek(display, controller.media_info.start_time * 1000) self.seek(display, controller.media_info.start_time * 1000)
controller.media_info.length = int(display.vlcMediaPlayer.get_media().get_duration() / 1000) controller.media_info.length = int(display.vlcMediaPlayer.get_media().get_duration() / 1000)
@ -197,6 +219,9 @@ class VlcPlayer(MediaPlayer):
return True return True
def pause(self, display): def pause(self, display):
"""
Pause the current item
"""
if display.vlcMedia.get_state() != vlc.State.Playing: if display.vlcMedia.get_state() != vlc.State.Playing:
return return
display.vlcMediaPlayer.pause() display.vlcMediaPlayer.pause()
@ -204,27 +229,45 @@ class VlcPlayer(MediaPlayer):
self.state = MediaState.Paused self.state = MediaState.Paused
def stop(self, display): def stop(self, display):
"""
Stop the current item
"""
display.vlcMediaPlayer.stop() display.vlcMediaPlayer.stop()
self.state = MediaState.Stopped self.state = MediaState.Stopped
def volume(self, display, vol): def volume(self, display, vol):
"""
Set the volume
"""
if display.hasAudio: if display.hasAudio:
display.vlcMediaPlayer.audio_set_volume(vol) display.vlcMediaPlayer.audio_set_volume(vol)
def seek(self, display, seekVal): def seek(self, display, seekVal):
"""
Go to a particular position
"""
if display.vlcMediaPlayer.is_seekable(): if display.vlcMediaPlayer.is_seekable():
display.vlcMediaPlayer.set_time(seekVal) display.vlcMediaPlayer.set_time(seekVal)
def reset(self, display): def reset(self, display):
"""
Reset the player
"""
display.vlcMediaPlayer.stop() display.vlcMediaPlayer.stop()
display.vlcWidget.setVisible(False) display.vlcWidget.setVisible(False)
self.state = MediaState.Off self.state = MediaState.Off
def set_visible(self, display, status): def set_visible(self, display, status):
"""
Set the visibility
"""
if self.hasOwnWidget: if self.hasOwnWidget:
display.vlcWidget.setVisible(status) display.vlcWidget.setVisible(status)
def update_ui(self, display): def update_ui(self, display):
"""
Update the UI
"""
# Stop video if playback is finished. # Stop video if playback is finished.
if display.vlcMedia.get_state() == vlc.State.Ended: if display.vlcMedia.get_state() == vlc.State.Ended:
self.stop(display) self.stop(display)
@ -234,9 +277,14 @@ class VlcPlayer(MediaPlayer):
self.stop(display) self.stop(display)
self.set_visible(display, False) self.set_visible(display, False)
if not controller.seekSlider.isSliderDown(): if not controller.seekSlider.isSliderDown():
controller.seekSlider.blockSignals(True)
controller.seekSlider.setSliderPosition(display.vlcMediaPlayer.get_time()) controller.seekSlider.setSliderPosition(display.vlcMediaPlayer.get_time())
controller.seekSlider.blockSignals(False)
def get_info(self): def get_info(self):
"""
Return some information about this player
"""
return(translate('Media.player', 'VLC is an external player which ' return(translate('Media.player', 'VLC is an external player which '
'supports a number of different formats.') + 'supports a number of different formats.') +
u'<br/> <strong>' + translate('Media.player', 'Audio') + u'<br/> <strong>' + translate('Media.player', 'Audio') +

View File

@ -26,12 +26,14 @@
# 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 #
############################################################################### ###############################################################################
"""
from PyQt4 import QtCore, QtGui The :mod:`~openlp.core.ui.media.webkit` module contains our WebKit video player
"""
from PyQt4 import QtGui
import logging import logging
from openlp.core.lib import translate, Settings from openlp.core.lib import Settings, translate
from openlp.core.ui.media import MediaState from openlp.core.ui.media import MediaState
from openlp.core.ui.media.mediaplayer import MediaPlayer from openlp.core.ui.media.mediaplayer import MediaPlayer
@ -40,14 +42,14 @@ log = logging.getLogger(__name__)
VIDEO_CSS = u""" VIDEO_CSS = u"""
#videobackboard { #videobackboard {
z-index:3; z-index:3;
background-color: %s; background-color: %(bgcolor)s;
} }
#video1 { #video1 {
background-color: %s; background-color: %(bgcolor)s;
z-index:4; z-index:4;
} }
#video2 { #video2 {
background-color: %s; background-color: %(bgcolor)s;
z-index:4; z-index:4;
} }
""" """
@ -234,33 +236,33 @@ FLASH_HTML = u"""
""" """
VIDEO_EXT = [ VIDEO_EXT = [
u'*.3gp' u'*.3gp',
, u'*.3gpp' u'*.3gpp',
, u'*.3g2' u'*.3g2',
, u'*.3gpp2' u'*.3gpp2',
, u'*.aac' u'*.aac',
, u'*.flv' u'*.flv',
, u'*.f4a' u'*.f4a',
, u'*.f4b' u'*.f4b',
, u'*.f4p' u'*.f4p',
, u'*.f4v' u'*.f4v',
, u'*.mov' u'*.mov',
, u'*.m4a' u'*.m4a',
, u'*.m4b' u'*.m4b',
, u'*.m4p' u'*.m4p',
, u'*.m4v' u'*.m4v',
, u'*.mkv' u'*.mkv',
, u'*.mp4' u'*.mp4',
, u'*.ogv' u'*.ogv',
, u'*.webm' u'*.webm',
, u'*.mpg', u'*.wmv', u'*.mpeg', u'*.avi' u'*.mpg', u'*.wmv', u'*.mpeg', u'*.avi',
, u'*.swf' u'*.swf'
] ]
AUDIO_EXT = [ AUDIO_EXT = [
u'*.mp3' u'*.mp3',
, u'*.ogg' u'*.ogg'
] ]
class WebkitPlayer(MediaPlayer): class WebkitPlayer(MediaPlayer):
@ -270,6 +272,9 @@ class WebkitPlayer(MediaPlayer):
""" """
def __init__(self, parent): def __init__(self, parent):
"""
Constructor
"""
MediaPlayer.__init__(self, parent, u'webkit') MediaPlayer.__init__(self, parent, u'webkit')
self.original_name = u'WebKit' self.original_name = u'WebKit'
self.display_name = u'&WebKit' self.display_name = u'&WebKit'
@ -282,8 +287,8 @@ class WebkitPlayer(MediaPlayer):
""" """
Add css style sheets to htmlbuilder Add css style sheets to htmlbuilder
""" """
background = QtGui.QColor(Settings().value(u'players/background color', u'#000000')).name() background = QtGui.QColor(Settings().value(u'players/background color')).name()
css = VIDEO_CSS % (background,background,background) css = VIDEO_CSS % {u'bgcolor': background}
return css + FLASH_CSS return css + FLASH_CSS
def get_media_display_javascript(self): def get_media_display_javascript(self):
@ -299,14 +304,23 @@ class WebkitPlayer(MediaPlayer):
return VIDEO_HTML + FLASH_HTML return VIDEO_HTML + FLASH_HTML
def setup(self, display): def setup(self, display):
"""
Set up the player
"""
display.webView.resize(display.size()) display.webView.resize(display.size())
display.webView.raise_() display.webView.raise_()
self.hasOwnWidget = False self.hasOwnWidget = False
def check_available(self): def check_available(self):
"""
Check the availability of the media player
"""
return True return True
def load(self, display): def load(self, display):
"""
Load a video
"""
log.debug(u'load vid in Webkit Controller') log.debug(u'load vid in Webkit Controller')
controller = display.controller controller = display.controller
if display.hasAudio and not controller.media_info.is_background: if display.hasAudio and not controller.media_info.is_background:
@ -329,9 +343,15 @@ class WebkitPlayer(MediaPlayer):
return True return True
def resize(self, display): def resize(self, display):
"""
Resize the player
"""
display.webView.resize(display.size()) display.webView.resize(display.size())
def play(self, display): def play(self, display):
"""
Play a video
"""
controller = display.controller controller = display.controller
display.webLoaded = True display.webLoaded = True
length = 0 length = 0
@ -352,6 +372,9 @@ class WebkitPlayer(MediaPlayer):
return True return True
def pause(self, display): def pause(self, display):
"""
Pause a video
"""
controller = display.controller controller = display.controller
if controller.media_info.is_flash: if controller.media_info.is_flash:
display.frame.evaluateJavaScript(u'show_flash("pause");') display.frame.evaluateJavaScript(u'show_flash("pause");')
@ -360,6 +383,9 @@ class WebkitPlayer(MediaPlayer):
self.state = MediaState.Paused self.state = MediaState.Paused
def stop(self, display): def stop(self, display):
"""
Stop a video
"""
controller = display.controller controller = display.controller
if controller.media_info.is_flash: if controller.media_info.is_flash:
display.frame.evaluateJavaScript(u'show_flash("stop");') display.frame.evaluateJavaScript(u'show_flash("stop");')
@ -368,6 +394,9 @@ class WebkitPlayer(MediaPlayer):
self.state = MediaState.Stopped self.state = MediaState.Stopped
def volume(self, display, vol): def volume(self, display, vol):
"""
Set the volume
"""
controller = display.controller controller = display.controller
# 1.0 is the highest value # 1.0 is the highest value
if display.hasAudio: if display.hasAudio:
@ -376,6 +405,9 @@ class WebkitPlayer(MediaPlayer):
display.frame.evaluateJavaScript(u'show_video(null, null, %s);' % str(vol)) display.frame.evaluateJavaScript(u'show_video(null, null, %s);' % str(vol))
def seek(self, display, seekVal): def seek(self, display, seekVal):
"""
Go to a position in the video
"""
controller = display.controller controller = display.controller
if controller.media_info.is_flash: if controller.media_info.is_flash:
seek = seekVal seek = seekVal
@ -385,6 +417,9 @@ class WebkitPlayer(MediaPlayer):
display.frame.evaluateJavaScript(u'show_video("seek", null, null, null, "%f");' % (seek)) display.frame.evaluateJavaScript(u'show_video("seek", null, null, null, "%f");' % (seek))
def reset(self, display): def reset(self, display):
"""
Reset the player
"""
controller = display.controller controller = display.controller
if controller.media_info.is_flash: if controller.media_info.is_flash:
display.frame.evaluateJavaScript(u'show_flash("close");') display.frame.evaluateJavaScript(u'show_flash("close");')
@ -393,6 +428,9 @@ class WebkitPlayer(MediaPlayer):
self.state = MediaState.Off self.state = MediaState.Off
def set_visible(self, display, status): def set_visible(self, display, status):
"""
Set the visibility
"""
controller = display.controller controller = display.controller
if status: if status:
is_visible = "visible" is_visible = "visible"
@ -404,6 +442,9 @@ class WebkitPlayer(MediaPlayer):
display.frame.evaluateJavaScript(u'show_video("setVisible", null, null, null, "%s");' % (is_visible)) display.frame.evaluateJavaScript(u'show_video("setVisible", null, null, null, "%s");' % (is_visible))
def update_ui(self, display): def update_ui(self, display):
"""
Update the UI
"""
controller = display.controller controller = display.controller
if controller.media_info.is_flash: if controller.media_info.is_flash:
currentTime = display.frame.evaluateJavaScript(u'show_flash("currentTime");') currentTime = display.frame.evaluateJavaScript(u'show_flash("currentTime");')
@ -411,21 +452,26 @@ class WebkitPlayer(MediaPlayer):
else: else:
if display.frame.evaluateJavaScript(u'show_video("isEnded");') == 'true': if display.frame.evaluateJavaScript(u'show_video("isEnded");') == 'true':
self.stop(display) self.stop(display)
(currentTime, ok) = display.frame.evaluateJavaScript(u'show_video("currentTime");') currentTime = display.frame.evaluateJavaScript(u'show_video("currentTime");')
# check if conversion was ok and value is not 'NaN' # check if conversion was ok and value is not 'NaN'
if ok and currentTime != float('inf'): if currentTime and currentTime != float('inf'):
currentTime = int(currentTime * 1000) currentTime = int(currentTime * 1000)
(length, ok) = display.frame.evaluateJavaScript(u'show_video("length");') length = display.frame.evaluateJavaScript(u'show_video("length");')
# check if conversion was ok and value is not 'NaN' # check if conversion was ok and value is not 'NaN'
if ok and length != float('inf'): if length and length != float('inf'):
length = int(length * 1000) length = int(length * 1000)
if currentTime > 0: if currentTime > 0:
controller.media_info.length = length controller.media_info.length = length
controller.seekSlider.setMaximum(length) controller.seekSlider.setMaximum(length)
if not controller.seekSlider.isSliderDown(): if not controller.seekSlider.isSliderDown():
controller.seekSlider.blockSignals(True)
controller.seekSlider.setSliderPosition(currentTime) controller.seekSlider.setSliderPosition(currentTime)
controller.seekSlider.blockSignals(False)
def get_info(self): def get_info(self):
"""
Return some information about this player
"""
return(translate('Media.player', 'Webkit is a media player which runs ' return(translate('Media.player', 'Webkit is a media player which runs '
'inside a web browser. This player allows text over video to be ' 'inside a web browser. This player allows text over video to be '
'rendered.') + 'rendered.') +

View File

@ -26,13 +26,16 @@
# 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 #
############################################################################### ###############################################################################
"""
The media manager dock.
"""
import logging import logging
from openlp.core.lib import StringContent from openlp.core.lib import StringContent
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class MediaDockManager(object): class MediaDockManager(object):
""" """
Provide a repository for MediaManagerItems Provide a repository for MediaManagerItems

View File

@ -26,14 +26,23 @@
# 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 #
############################################################################### ###############################################################################
"""
The UI widgets of the plugin view dialog
#"""
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate from openlp.core.lib import UiStrings, translate
from openlp.core.lib.ui import UiStrings, create_button_box from openlp.core.lib.ui import create_button_box
class Ui_PluginViewDialog(object): class Ui_PluginViewDialog(object):
"""
The UI of the plugin view dialog
"""
def setupUi(self, pluginViewDialog): def setupUi(self, pluginViewDialog):
"""
Set up the UI
"""
pluginViewDialog.setObjectName(u'pluginViewDialog') pluginViewDialog.setObjectName(u'pluginViewDialog')
pluginViewDialog.setWindowModality(QtCore.Qt.ApplicationModal) pluginViewDialog.setWindowModality(QtCore.Qt.ApplicationModal)
self.pluginLayout = QtGui.QVBoxLayout(pluginViewDialog) self.pluginLayout = QtGui.QVBoxLayout(pluginViewDialog)
@ -66,11 +75,14 @@ class Ui_PluginViewDialog(object):
self.pluginInfoLayout.addRow(self.aboutLabel, self.aboutTextBrowser) self.pluginInfoLayout.addRow(self.aboutLabel, self.aboutTextBrowser)
self.listLayout.addWidget(self.pluginInfoGroupBox) self.listLayout.addWidget(self.pluginInfoGroupBox)
self.pluginLayout.addLayout(self.listLayout) self.pluginLayout.addLayout(self.listLayout)
self.buttonBox = create_button_box(pluginViewDialog, u'buttonBox', [u'ok']) self.button_box = create_button_box(pluginViewDialog, u'button_box', [u'ok'])
self.pluginLayout.addWidget(self.buttonBox) self.pluginLayout.addWidget(self.button_box)
self.retranslateUi(pluginViewDialog) self.retranslateUi(pluginViewDialog)
def retranslateUi(self, pluginViewDialog): def retranslateUi(self, pluginViewDialog):
"""
Translate the UI on the fly
"""
pluginViewDialog.setWindowTitle(translate('OpenLP.PluginForm', 'Plugin List')) pluginViewDialog.setWindowTitle(translate('OpenLP.PluginForm', 'Plugin List'))
self.pluginInfoGroupBox.setTitle(translate('OpenLP.PluginForm', 'Plugin Details')) self.pluginInfoGroupBox.setTitle(translate('OpenLP.PluginForm', 'Plugin Details'))
self.versionLabel.setText(u'%s:' % UiStrings().Version) self.versionLabel.setText(u'%s:' % UiStrings().Version)

View File

@ -26,21 +26,27 @@
# 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 #
############################################################################### ###############################################################################
"""
The actual plugin view form
"""
import logging import logging
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import PluginStatus, Receiver, translate from openlp.core.lib import PluginStatus, Registry, translate
from plugindialog import Ui_PluginViewDialog from plugindialog import Ui_PluginViewDialog
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class PluginForm(QtGui.QDialog, Ui_PluginViewDialog): class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
""" """
The plugin form provides user control over the plugins OpenLP uses. The plugin form provides user control over the plugins OpenLP uses.
""" """
def __init__(self, parent=None): def __init__(self, parent=None):
"""
Constructor
"""
QtGui.QDialog.__init__(self, parent) QtGui.QDialog.__init__(self, parent)
self.activePlugin = None self.activePlugin = None
self.programaticChange = False self.programaticChange = False
@ -62,7 +68,7 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
self._clearDetails() self._clearDetails()
self.programaticChange = True self.programaticChange = True
pluginListWidth = 0 pluginListWidth = 0
for plugin in self.parent().pluginManager.plugins: for plugin in self.plugin_manager.plugins:
item = QtGui.QListWidgetItem(self.pluginListWidget) item = QtGui.QListWidgetItem(self.pluginListWidget)
# We do this just to make 100% sure the status is an integer as # We do this just to make 100% sure the status is an integer as
# sometimes when it's loaded from the config, it isn't cast to int. # sometimes when it's loaded from the config, it isn't cast to int.
@ -85,12 +91,18 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
self.pluginListWidget.setFixedWidth(pluginListWidth + self.pluginListWidget.iconSize().width() + 48) self.pluginListWidget.setFixedWidth(pluginListWidth + self.pluginListWidget.iconSize().width() + 48)
def _clearDetails(self): def _clearDetails(self):
"""
Clear the plugin details widgets
"""
self.statusComboBox.setCurrentIndex(-1) self.statusComboBox.setCurrentIndex(-1)
self.versionNumberLabel.setText(u'') self.versionNumberLabel.setText(u'')
self.aboutTextBrowser.setHtml(u'') self.aboutTextBrowser.setHtml(u'')
self.statusComboBox.setEnabled(False) self.statusComboBox.setEnabled(False)
def _setDetails(self): def _setDetails(self):
"""
Set the details of the currently selected plugin
"""
log.debug(u'PluginStatus: %s', str(self.activePlugin.status)) log.debug(u'PluginStatus: %s', str(self.activePlugin.status))
self.versionNumberLabel.setText(self.activePlugin.version) self.versionNumberLabel.setText(self.activePlugin.version)
self.aboutTextBrowser.setHtml(self.activePlugin.about()) self.aboutTextBrowser.setHtml(self.activePlugin.about())
@ -103,13 +115,15 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
self.programaticChange = False self.programaticChange = False
def onPluginListWidgetSelectionChanged(self): def onPluginListWidgetSelectionChanged(self):
"""
If the selected plugin changes, update the form
"""
if self.pluginListWidget.currentItem() is None: if self.pluginListWidget.currentItem() is None:
self._clearDetails() self._clearDetails()
return return
plugin_name_singular = \ plugin_name_singular = self.pluginListWidget.currentItem().text().split(u'(')[0][:-1]
self.pluginListWidget.currentItem().text().split(u'(')[0][:-1]
self.activePlugin = None self.activePlugin = None
for plugin in self.parent().pluginManager.plugins: for plugin in self.plugin_manager.plugins:
if plugin.status != PluginStatus.Disabled: if plugin.status != PluginStatus.Disabled:
if plugin.nameStrings[u'singular'] == plugin_name_singular: if plugin.nameStrings[u'singular'] == plugin_name_singular:
self.activePlugin = plugin self.activePlugin = plugin
@ -120,13 +134,16 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
self._clearDetails() self._clearDetails()
def onStatusComboBoxChanged(self, status): def onStatusComboBoxChanged(self, status):
"""
If the status of a plugin is altered, apply the change
"""
if self.programaticChange or status == PluginStatus.Disabled: if self.programaticChange or status == PluginStatus.Disabled:
return return
if status == PluginStatus.Inactive: if status == PluginStatus.Inactive:
Receiver.send_message(u'cursor_busy') self.application.set_busy_cursor()
self.activePlugin.toggleStatus(PluginStatus.Active) self.activePlugin.toggleStatus(PluginStatus.Active)
Receiver.send_message(u'cursor_normal') self.application.set_normal_cursor()
self.activePlugin.appStartup() self.activePlugin.app_startup()
else: else:
self.activePlugin.toggleStatus(PluginStatus.Inactive) self.activePlugin.toggleStatus(PluginStatus.Inactive)
status_text = translate('OpenLP.PluginForm', '%s (Inactive)') status_text = translate('OpenLP.PluginForm', '%s (Inactive)')
@ -138,3 +155,23 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
status_text = translate('OpenLP.PluginForm', '%s (Disabled)') status_text = translate('OpenLP.PluginForm', '%s (Disabled)')
self.pluginListWidget.currentItem().setText( self.pluginListWidget.currentItem().setText(
status_text % self.activePlugin.nameStrings[u'singular']) status_text % self.activePlugin.nameStrings[u'singular'])
def _get_plugin_manager(self):
"""
Adds the plugin manager to the class dynamically
"""
if not hasattr(self, u'_plugin_manager'):
self._plugin_manager = Registry().get(u'plugin_manager')
return self._plugin_manager
plugin_manager = property(_get_plugin_manager)
def _get_application(self):
"""
Adds the openlp to the class dynamically
"""
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application)

View File

@ -26,11 +26,13 @@
# 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 #
############################################################################### ###############################################################################
"""
The UI widgets of the print service dialog.
"""
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, translate, SpellTextEdit from openlp.core.lib import SpellTextEdit, UiStrings, build_icon, translate
from openlp.core.lib.ui import UiStrings
class ZoomSize(object): class ZoomSize(object):
""" """
@ -45,7 +47,13 @@ class ZoomSize(object):
class Ui_PrintServiceDialog(object): class Ui_PrintServiceDialog(object):
"""
The UI of the print service dialog
"""
def setupUi(self, printServiceDialog): def setupUi(self, printServiceDialog):
"""
Set up the UI
"""
printServiceDialog.setObjectName(u'printServiceDialog') printServiceDialog.setObjectName(u'printServiceDialog')
printServiceDialog.resize(664, 594) printServiceDialog.resize(664, 594)
self.mainLayout = QtGui.QVBoxLayout(printServiceDialog) self.mainLayout = QtGui.QVBoxLayout(printServiceDialog)
@ -122,9 +130,12 @@ class Ui_PrintServiceDialog(object):
self.optionsLayout.addWidget(self.optionsGroupBox) self.optionsLayout.addWidget(self.optionsGroupBox)
self.retranslateUi(printServiceDialog) self.retranslateUi(printServiceDialog)
QtCore.QObject.connect(self.optionsButton,QtCore.SIGNAL(u'toggled(bool)'), self.toggleOptions) QtCore.QObject.connect(self.optionsButton, QtCore.SIGNAL(u'toggled(bool)'), self.toggleOptions)
def retranslateUi(self, printServiceDialog): def retranslateUi(self, printServiceDialog):
"""
Translate the UI on the fly
"""
printServiceDialog.setWindowTitle(UiStrings().PrintService) printServiceDialog.setWindowTitle(UiStrings().PrintService)
self.zoomOutButton.setToolTip(translate('OpenLP.PrintServiceForm', 'Zoom Out')) self.zoomOutButton.setToolTip(translate('OpenLP.PrintServiceForm', 'Zoom Out'))
self.zoomOriginalButton.setToolTip(translate('OpenLP.PrintServiceForm', 'Zoom Original')) self.zoomOriginalButton.setToolTip(translate('OpenLP.PrintServiceForm', 'Zoom Original'))
@ -132,7 +143,7 @@ class Ui_PrintServiceDialog(object):
self.optionsButton.setText(translate('OpenLP.PrintServiceForm', 'Options')) self.optionsButton.setText(translate('OpenLP.PrintServiceForm', 'Options'))
self.titleLabel.setText(translate('OpenLP.PrintServiceForm', 'Title:')) self.titleLabel.setText(translate('OpenLP.PrintServiceForm', 'Title:'))
self.footerLabel.setText(translate('OpenLP.PrintServiceForm', 'Custom Footer Text:')) self.footerLabel.setText(translate('OpenLP.PrintServiceForm', 'Custom Footer Text:'))
self.optionsGroupBox.setTitle(translate('OpenLP.PrintServiceForm','Other Options')) self.optionsGroupBox.setTitle(translate('OpenLP.PrintServiceForm', 'Other Options'))
self.slideTextCheckBox.setText(translate('OpenLP.PrintServiceForm', 'Include slide text if available')) self.slideTextCheckBox.setText(translate('OpenLP.PrintServiceForm', 'Include slide text if available'))
self.pageBreakAfterText.setText(translate('OpenLP.PrintServiceForm', 'Add page break before each text item')) self.pageBreakAfterText.setText(translate('OpenLP.PrintServiceForm', 'Add page break before each text item'))
self.notesCheckBox.setText(translate('OpenLP.PrintServiceForm', 'Include service item notes')) self.notesCheckBox.setText(translate('OpenLP.PrintServiceForm', 'Include service item notes'))
@ -145,6 +156,5 @@ class Ui_PrintServiceDialog(object):
u'100%', u'100%',
u'75%', u'75%',
u'50%', u'50%',
u'25%'] u'25%'
) ])

View File

@ -26,6 +26,9 @@
# 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 #
############################################################################### ###############################################################################
"""
The actual print service dialog
"""
import cgi import cgi
import datetime import datetime
import os import os
@ -33,8 +36,7 @@ import os
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from lxml import html from lxml import html
from openlp.core.lib import translate, get_text_file_string, Receiver, Settings from openlp.core.lib import Receiver, Settings, UiStrings, Registry, translate, get_text_file_string
from openlp.core.lib.ui import UiStrings
from openlp.core.ui.printservicedialog import Ui_PrintServiceDialog, ZoomSize from openlp.core.ui.printservicedialog import Ui_PrintServiceDialog, ZoomSize
from openlp.core.utils import AppLocation from openlp.core.utils import AppLocation
@ -107,15 +109,16 @@ http://doc.trolltech.com/4.7/richtext-html-subset.html#css-properties
} }
""" """
class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
def __init__(self, mainWindow, serviceManager): class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
"""
The :class:`~openlp.core.ui.printserviceform.PrintServiceForm` class displays a dialog for printing the service.
"""
def __init__(self):
""" """
Constructor Constructor
""" """
QtGui.QDialog.__init__(self, mainWindow) QtGui.QDialog.__init__(self, self.main_window)
self.mainWindow = mainWindow
self.serviceManager = serviceManager
self.printer = QtGui.QPrinter() self.printer = QtGui.QPrinter()
self.printDialog = QtGui.QPrintDialog(self.printer, self) self.printDialog = QtGui.QPrintDialog(self.printer, self)
self.document = QtGui.QTextDocument() self.document = QtGui.QTextDocument()
@ -124,13 +127,13 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
# Load the settings for the dialog. # Load the settings for the dialog.
settings = Settings() settings = Settings()
settings.beginGroup(u'advanced') settings.beginGroup(u'advanced')
self.slideTextCheckBox.setChecked(settings.value(u'print slide text', False)) self.slideTextCheckBox.setChecked(settings.value(u'print slide text'))
self.pageBreakAfterText.setChecked(settings.value(u'add page break', False)) self.pageBreakAfterText.setChecked(settings.value(u'add page break'))
if not self.slideTextCheckBox.isChecked(): if not self.slideTextCheckBox.isChecked():
self.pageBreakAfterText.setDisabled(True) self.pageBreakAfterText.setDisabled(True)
self.metaDataCheckBox.setChecked(settings.value(u'print file meta data', False)) self.metaDataCheckBox.setChecked(settings.value(u'print file meta data'))
self.notesCheckBox.setChecked(settings.value(u'print notes', False)) self.notesCheckBox.setChecked(settings.value(u'print notes'))
self.zoomComboBox.setCurrentIndex(settings.value(u'display size', 0)) self.zoomComboBox.setCurrentIndex(settings.value(u'display size'))
settings.endGroup() settings.endGroup()
# Signals # Signals
QtCore.QObject.connect(self.printButton, QtCore.SIGNAL(u'triggered()'), self.printServiceOrder) QtCore.QObject.connect(self.printButton, QtCore.SIGNAL(u'triggered()'), self.printServiceOrder)
@ -141,10 +144,14 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
QtCore.QObject.connect(self.zoomComboBox, QtCore.SIGNAL(u'currentIndexChanged(int)'), self.displaySizeChanged) QtCore.QObject.connect(self.zoomComboBox, QtCore.SIGNAL(u'currentIndexChanged(int)'), self.displaySizeChanged)
QtCore.QObject.connect(self.plainCopy, QtCore.SIGNAL(u'triggered()'), self.copyText) QtCore.QObject.connect(self.plainCopy, QtCore.SIGNAL(u'triggered()'), self.copyText)
QtCore.QObject.connect(self.htmlCopy, QtCore.SIGNAL(u'triggered()'), self.copyHtmlText) QtCore.QObject.connect(self.htmlCopy, QtCore.SIGNAL(u'triggered()'), self.copyHtmlText)
QtCore.QObject.connect(self.slideTextCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), self.onSlideTextCheckBoxChanged) QtCore.QObject.connect(self.slideTextCheckBox, QtCore.SIGNAL(u'stateChanged(int)'),
self.onSlideTextCheckBoxChanged)
self.updatePreviewText() self.updatePreviewText()
def toggleOptions(self, checked): def toggleOptions(self, checked):
"""
Toggle various options
"""
self.optionsWidget.setVisible(checked) self.optionsWidget.setVisible(checked)
if checked: if checked:
left = self.optionsButton.pos().x() left = self.optionsButton.pos().x()
@ -171,7 +178,7 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
self._addElement(u'body', parent=html_data) self._addElement(u'body', parent=html_data)
self._addElement(u'h1', cgi.escape(self.titleLineEdit.text()), self._addElement(u'h1', cgi.escape(self.titleLineEdit.text()),
html_data.body, classId=u'serviceTitle') html_data.body, classId=u'serviceTitle')
for index, item in enumerate(self.serviceManager.serviceItems): for index, item in enumerate(self.service_manager.service_items):
self._addPreviewItem(html_data.body, item[u'service_item'], index) self._addPreviewItem(html_data.body, item[u'service_item'], index)
# Add the custom service notes: # Add the custom service notes:
if self.footerTextEdit.toPlainText(): if self.footerTextEdit.toPlainText():
@ -183,6 +190,9 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
self.previewWidget.updatePreview() self.previewWidget.updatePreview()
def _addPreviewItem(self, body, item, index): def _addPreviewItem(self, body, item, index):
"""
Add a preview item
"""
div = self._addElement(u'div', classId=u'item', parent=body) div = self._addElement(u'div', classId=u'item', parent=body)
# Add the title of the service item. # Add the title of the service item.
item_title = self._addElement(u'h2', parent=div, classId=u'itemTitle') item_title = self._addElement(u'h2', parent=div, classId=u'itemTitle')
@ -320,14 +330,14 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
# remove the icon from the text # remove the icon from the text
clipboard_text = clipboard_text.replace(u'\ufffc\xa0', u'') clipboard_text = clipboard_text.replace(u'\ufffc\xa0', u'')
# and put it all on the clipboard # and put it all on the clipboard
self.mainWindow.clipboard.setText(clipboard_text) self.main_window.clipboard.setText(clipboard_text)
def copyHtmlText(self): def copyHtmlText(self):
""" """
Copies the display text to the clipboard as Html Copies the display text to the clipboard as Html
""" """
self.update_song_usage() self.update_song_usage()
self.mainWindow.clipboard.setText(self.document.toHtml()) self.main_window.clipboard.setText(self.document.toHtml())
def printServiceOrder(self): def printServiceOrder(self):
""" """
@ -390,9 +400,32 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
settings.endGroup() settings.endGroup()
def update_song_usage(self): def update_song_usage(self):
"""
Update the song usage
"""
# 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 item in self.serviceManager.serviceItems: for item in self.service_manager.serviceItems:
# Trigger Audit requests # Trigger Audit requests
Receiver.send_message(u'print_service_started', [item[u'service_item']]) Receiver.send_message(u'print_service_started', [item[u'service_item']])
def _get_service_manager(self):
"""
Adds the service manager to the class dynamically
"""
if not hasattr(self, u'_service_manager'):
self._service_manager = Registry().get(u'service_manager')
return self._service_manager
service_manager = property(_get_service_manager)
def _get_main_window(self):
"""
Adds the main window to the class dynamically
"""
if not hasattr(self, u'_main_window'):
self._main_window = Registry().get(u'main_window')
return self._main_window
main_window = property(_get_main_window)

View File

@ -26,39 +26,51 @@
# 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 #
############################################################################### ###############################################################################
"""
The UI widgets for the service item edit dialog
"""
from PyQt4 import QtGui from PyQt4 import QtGui
from openlp.core.lib import translate from openlp.core.lib import translate
from openlp.core.lib.ui import create_button_box, create_button from openlp.core.lib.ui import create_button_box, create_button
class Ui_ServiceItemEditDialog(object): class Ui_ServiceItemEditDialog(object):
"""
The UI widgets for the service item edit dialog
"""
def setupUi(self, serviceItemEditDialog): def setupUi(self, serviceItemEditDialog):
"""
Set up the UI
"""
serviceItemEditDialog.setObjectName(u'serviceItemEditDialog') serviceItemEditDialog.setObjectName(u'serviceItemEditDialog')
self.dialogLayout = QtGui.QGridLayout(serviceItemEditDialog) self.dialog_layout = QtGui.QGridLayout(serviceItemEditDialog)
self.dialogLayout.setContentsMargins(8, 8, 8, 8) self.dialog_layout.setContentsMargins(8, 8, 8, 8)
self.dialogLayout.setSpacing(8) self.dialog_layout.setSpacing(8)
self.dialogLayout.setObjectName(u'dialogLayout') self.dialog_layout.setObjectName(u'dialog_layout')
self.listWidget = QtGui.QListWidget(serviceItemEditDialog) self.list_widget = QtGui.QListWidget(serviceItemEditDialog)
self.listWidget.setAlternatingRowColors(True) self.list_widget.setAlternatingRowColors(True)
self.listWidget.setObjectName(u'listWidget') self.list_widget.setObjectName(u'list_widget')
self.dialogLayout.addWidget(self.listWidget, 0, 0) self.dialog_layout.addWidget(self.list_widget, 0, 0)
self.buttonLayout = QtGui.QVBoxLayout() self.button_layout = QtGui.QVBoxLayout()
self.buttonLayout.setObjectName(u'buttonLayout') self.button_layout.setObjectName(u'button_layout')
self.deleteButton = create_button(serviceItemEditDialog, u'deleteButton', role=u'delete', self.delete_button = create_button(serviceItemEditDialog, u'deleteButton', role=u'delete',
click=serviceItemEditDialog.onDeleteButtonClicked) click=serviceItemEditDialog.on_delete_button_clicked)
self.buttonLayout.addWidget(self.deleteButton) self.button_layout.addWidget(self.delete_button)
self.buttonLayout.addStretch() self.button_layout.addStretch()
self.upButton = create_button(serviceItemEditDialog, u'upButton', role=u'up', self.up_button = create_button(serviceItemEditDialog, u'upButton', role=u'up',
click=serviceItemEditDialog.onUpButtonClicked) click=serviceItemEditDialog.on_up_button_clicked)
self.downButton = create_button(serviceItemEditDialog, u'downButton', role=u'down', self.down_button = create_button(serviceItemEditDialog, u'downButton', role=u'down',
click=serviceItemEditDialog.onDownButtonClicked) click=serviceItemEditDialog.on_down_button_clicked)
self.buttonLayout.addWidget(self.upButton) self.button_layout.addWidget(self.up_button)
self.buttonLayout.addWidget(self.downButton) self.button_layout.addWidget(self.down_button)
self.dialogLayout.addLayout(self.buttonLayout, 0, 1) self.dialog_layout.addLayout(self.button_layout, 0, 1)
self.buttonBox = create_button_box(serviceItemEditDialog, u'buttonBox', [u'cancel', u'save']) self.button_box = create_button_box(serviceItemEditDialog, u'button_box', [u'cancel', u'save'])
self.dialogLayout.addWidget(self.buttonBox, 1, 0, 1, 2) self.dialog_layout.addWidget(self.button_box, 1, 0, 1, 2)
self.retranslateUi(serviceItemEditDialog) self.retranslateUi(serviceItemEditDialog)
def retranslateUi(self, serviceItemEditDialog): def retranslateUi(self, serviceItemEditDialog):
"""
Translate the UI on the fly
"""
serviceItemEditDialog.setWindowTitle(translate('OpenLP.ServiceItemEditForm', 'Reorder Service Item')) serviceItemEditDialog.setWindowTitle(translate('OpenLP.ServiceItemEditForm', 'Reorder Service Item'))

View File

@ -26,100 +26,111 @@
# 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 #
############################################################################### ###############################################################################
"""
The service item edit dialog
"""
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import Registry
from serviceitemeditdialog import Ui_ServiceItemEditDialog from serviceitemeditdialog import Ui_ServiceItemEditDialog
class ServiceItemEditForm(QtGui.QDialog, Ui_ServiceItemEditDialog): class ServiceItemEditForm(QtGui.QDialog, Ui_ServiceItemEditDialog):
""" """
This is the form that is used to edit the verses of the song. This is the form that is used to edit the verses of the song.
""" """
def __init__(self, parent=None): def __init__(self):
""" """
Constructor Constructor
""" """
QtGui.QDialog.__init__(self, parent) QtGui.QDialog.__init__(self, self.main_window)
self.setupUi(self) self.setupUi(self)
self.itemList = [] self.item_list = []
QtCore.QObject.connect(self.listWidget, QtCore.SIGNAL(u'currentRowChanged(int)'), self.onCurrentRowChanged) QtCore.QObject.connect(self.list_widget, QtCore.SIGNAL(u'currentRowChanged(int)'),
self.on_current_row_changed)
def setServiceItem(self, item): def set_service_item(self, item):
"""
Set the service item to be edited.
"""
self.item = item self.item = item
self.itemList = [] self.item_list = []
if self.item.is_image(): if self.item.is_image():
self.data = True self.data = True
for frame in self.item._raw_frames: for frame in self.item._raw_frames:
self.itemList.append(frame) self.item_list.append(frame)
self.loadData() self.load_data()
self.listWidget.setCurrentItem(self.listWidget.currentItem()) self.list_widget.setCurrentItem(self.list_widget.currentItem())
def getServiceItem(self): def get_service_item(self):
"""
Get the modified service item.
"""
if self.data: if self.data:
self.item._raw_frames = [] self.item._raw_frames = []
if self.item.is_image(): if self.item.is_image():
for item in self.itemList: for item in self.item_list:
self.item.add_from_image(item[u'path'], item[u'title']) self.item.add_from_image(item[u'path'], item[u'title'])
self.item.render() self.item.render()
return self.item return self.item
def loadData(self): def load_data(self):
""" """
Loads the image list. Loads the image list.
""" """
self.listWidget.clear() self.list_widget.clear()
for frame in self.itemList: for frame in self.item_list:
item_name = QtGui.QListWidgetItem(frame[u'title']) item_name = QtGui.QListWidgetItem(frame[u'title'])
self.listWidget.addItem(item_name) self.list_widget.addItem(item_name)
def onDeleteButtonClicked(self): def on_delete_button_clicked(self):
""" """
Delete the current row. Delete the current row.
""" """
item = self.listWidget.currentItem() item = self.list_widget.currentItem()
if not item: if not item:
return return
row = self.listWidget.row(item) row = self.list_widget.row(item)
self.itemList.pop(row) self.item_list.pop(row)
self.loadData() self.load_data()
if row == self.listWidget.count(): if row == self.list_widget.count():
self.listWidget.setCurrentRow(row - 1) self.list_widget.setCurrentRow(row - 1)
else: else:
self.listWidget.setCurrentRow(row) self.list_widget.setCurrentRow(row)
def onUpButtonClicked(self): def on_up_button_clicked(self):
""" """
Move the current row up in the list. Move the current row up in the list.
""" """
self.__moveItem(u'up') self.__move_item(u'up')
def onDownButtonClicked(self): def on_down_button_clicked(self):
""" """
Move the current row down in the list Move the current row down in the list
""" """
self.__moveItem(u'down') self.__move_item(u'down')
def __moveItem(self, direction=u''): def __move_item(self, direction=u''):
""" """
Move the current item. Move the current item.
""" """
if not direction: if not direction:
return return
item = self.listWidget.currentItem() item = self.list_widget.currentItem()
if not item: if not item:
return return
row = self.listWidget.row(item) row = self.list_widget.row(item)
temp = self.itemList[row] temp = self.item_list[row]
self.itemList.pop(row) self.item_list.pop(row)
if direction == u'up': if direction == u'up':
row -= 1 row -= 1
else: else:
row += 1 row += 1
self.itemList.insert(row, temp) self.item_list.insert(row, temp)
self.loadData() self.load_data()
self.listWidget.setCurrentRow(row) self.list_widget.setCurrentRow(row)
def onCurrentRowChanged(self, row): def on_current_row_changed(self, row):
""" """
Called when the currentRow has changed. Called when the currentRow has changed.
@ -127,19 +138,29 @@ class ServiceItemEditForm(QtGui.QDialog, Ui_ServiceItemEditDialog):
The row number (int). The row number (int).
""" """
# Disable all buttons, as no row is selected or only one image is left. # Disable all buttons, as no row is selected or only one image is left.
if row == -1 or self.listWidget.count() == 1: if row == -1 or self.list_widget.count() == 1:
self.downButton.setEnabled(False) self.down_button.setEnabled(False)
self.upButton.setEnabled(False) self.up_button.setEnabled(False)
self.deleteButton.setEnabled(False) self.delete_button.setEnabled(False)
else: else:
# Check if we are at the end of the list. # Check if we are at the end of the list.
if self.listWidget.count() == row + 1: if self.list_widget.count() == row + 1:
self.downButton.setEnabled(False) self.down_button.setEnabled(False)
else: else:
self.downButton.setEnabled(True) self.down_button.setEnabled(True)
# Check if we are at the beginning of the list. # Check if we are at the beginning of the list.
if row == 0: if row == 0:
self.upButton.setEnabled(False) self.up_button.setEnabled(False)
else: else:
self.upButton.setEnabled(True) self.up_button.setEnabled(True)
self.deleteButton.setEnabled(True) self.delete_button.setEnabled(True)
def _get_main_window(self):
"""
Adds the main window to the class dynamically
"""
if not hasattr(self, u'_main_window'):
self._main_window = Registry().get(u'main_window')
return self._main_window
main_window = property(_get_main_window)

File diff suppressed because it is too large Load Diff

View File

@ -26,39 +26,61 @@
# 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 #
############################################################################### ###############################################################################
"""
The :mod:`~openlp.core.ui.servicenoteform` module contains the `ServiceNoteForm` class.
"""
from PyQt4 import QtGui from PyQt4 import QtGui
from openlp.core.lib import translate, SpellTextEdit from openlp.core.lib import SpellTextEdit, Registry, translate
from openlp.core.lib.ui import create_button_box from openlp.core.lib.ui import create_button_box
class ServiceNoteForm(QtGui.QDialog): class ServiceNoteForm(QtGui.QDialog):
""" """
This is the form that is used to edit the verses of the song. This is the form that is used to edit the verses of the song.
""" """
def __init__(self, parent=None): def __init__(self):
""" """
Constructor Constructor
""" """
QtGui.QDialog.__init__(self, parent) QtGui.QDialog.__init__(self, self.main_window)
self.setupUi() self.setupUi()
self.retranslateUi() self.retranslateUi()
def exec_(self): def exec_(self):
self.textEdit.setFocus() """
Execute the form and return the result.
"""
self.text_edit.setFocus()
return QtGui.QDialog.exec_(self) return QtGui.QDialog.exec_(self)
def setupUi(self): def setupUi(self):
"""
Set up the UI of the dialog
"""
self.setObjectName(u'serviceNoteEdit') self.setObjectName(u'serviceNoteEdit')
self.dialogLayout = QtGui.QVBoxLayout(self) self.dialog_layout = QtGui.QVBoxLayout(self)
self.dialogLayout.setContentsMargins(8, 8, 8, 8) self.dialog_layout.setContentsMargins(8, 8, 8, 8)
self.dialogLayout.setSpacing(8) self.dialog_layout.setSpacing(8)
self.dialogLayout.setObjectName(u'verticalLayout') self.dialog_layout.setObjectName(u'verticalLayout')
self.textEdit = SpellTextEdit(self, False) self.text_edit = SpellTextEdit(self, False)
self.textEdit.setObjectName(u'textEdit') self.text_edit.setObjectName(u'textEdit')
self.dialogLayout.addWidget(self.textEdit) self.dialog_layout.addWidget(self.text_edit)
self.buttonBox = create_button_box(self, u'buttonBox', [u'cancel', u'save']) self.button_box = create_button_box(self, u'button_box', [u'cancel', u'save'])
self.dialogLayout.addWidget(self.buttonBox) self.dialog_layout.addWidget(self.button_box)
def retranslateUi(self): def retranslateUi(self):
"""
Translate the UI on the fly
"""
self.setWindowTitle(translate('OpenLP.ServiceNoteForm', 'Service Item Notes')) self.setWindowTitle(translate('OpenLP.ServiceNoteForm', 'Service Item Notes'))
def _get_main_window(self):
"""
Adds the main window to the class dynamically
"""
if not hasattr(self, u'_main_window'):
self._main_window = Registry().get(u'main_window')
return self._main_window
main_window = property(_get_main_window)

View File

@ -26,19 +26,28 @@
# 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 #
############################################################################### ###############################################################################
"""
The UI widgets of the settings dialog.
"""
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate, build_icon from openlp.core.lib import translate, build_icon
from openlp.core.lib.ui import create_button_box from openlp.core.lib.ui import create_button_box
class Ui_SettingsDialog(object): class Ui_SettingsDialog(object):
"""
The UI widgets of the settings dialog.
"""
def setupUi(self, settingsDialog): def setupUi(self, settingsDialog):
"""
Set up the UI
"""
settingsDialog.setObjectName(u'settingsDialog') settingsDialog.setObjectName(u'settingsDialog')
settingsDialog.resize(800, 500) settingsDialog.resize(800, 500)
settingsDialog.setWindowIcon(build_icon(u':/system/system_settings.png')) settingsDialog.setWindowIcon(build_icon(u':/system/system_settings.png'))
self.dialogLayout = QtGui.QGridLayout(settingsDialog) self.dialogLayout = QtGui.QGridLayout(settingsDialog)
self.dialogLayout.setObjectName(u'dialogLayout') self.dialogLayout.setObjectName(u'dialog_layout')
self.dialogLayout.setMargin(8) self.dialogLayout.setMargin(8)
self.settingListWidget = QtGui.QListWidget(settingsDialog) self.settingListWidget = QtGui.QListWidget(settingsDialog)
self.settingListWidget.setUniformItemSizes(True) self.settingListWidget.setUniformItemSizes(True)
@ -49,10 +58,13 @@ class Ui_SettingsDialog(object):
self.stackedLayout = QtGui.QStackedLayout() self.stackedLayout = QtGui.QStackedLayout()
self.stackedLayout.setObjectName(u'stackedLayout') self.stackedLayout.setObjectName(u'stackedLayout')
self.dialogLayout.addLayout(self.stackedLayout, 0, 1, 1, 1) self.dialogLayout.addLayout(self.stackedLayout, 0, 1, 1, 1)
self.buttonBox = create_button_box(settingsDialog, u'buttonBox', [u'cancel', u'ok']) self.button_box = create_button_box(settingsDialog, u'button_box', [u'cancel', u'ok'])
self.dialogLayout.addWidget(self.buttonBox, 1, 1, 1, 1) self.dialogLayout.addWidget(self.button_box, 1, 1, 1, 1)
self.retranslateUi(settingsDialog) self.retranslateUi(settingsDialog)
QtCore.QObject.connect(self.settingListWidget, QtCore.SIGNAL(u'currentRowChanged(int)'), self.tabChanged) QtCore.QObject.connect(self.settingListWidget, QtCore.SIGNAL(u'currentRowChanged(int)'), self.tabChanged)
def retranslateUi(self, settingsDialog): def retranslateUi(self, settingsDialog):
"""
Translate the UI on the fly
"""
settingsDialog.setWindowTitle(translate('OpenLP.SettingsForm', 'Configure OpenLP')) settingsDialog.setWindowTitle(translate('OpenLP.SettingsForm', 'Configure OpenLP'))

View File

@ -31,36 +31,40 @@ The :mod:`settingsform` provides a user interface for the OpenLP settings
""" """
import logging import logging
from PyQt4 import QtCore, QtGui from PyQt4 import QtGui
from openlp.core.lib import Receiver, build_icon, PluginStatus from openlp.core.lib import Receiver, PluginStatus, Registry, build_icon
from openlp.core.ui import AdvancedTab, GeneralTab, ThemesTab from openlp.core.ui import AdvancedTab, GeneralTab, ThemesTab
from openlp.core.ui.media import PlayerTab from openlp.core.ui.media import PlayerTab
from settingsdialog import Ui_SettingsDialog from settingsdialog import Ui_SettingsDialog
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class SettingsForm(QtGui.QDialog, Ui_SettingsDialog): class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
""" """
Provide the form to manipulate the settings for OpenLP Provide the form to manipulate the settings for OpenLP
""" """
def __init__(self, mainWindow, parent=None): def __init__(self, parent=None):
""" """
Initialise the settings form Initialise the settings form
""" """
self.mainWindow = mainWindow Registry().register(u'settings_form', self)
QtGui.QDialog.__init__(self, parent) QtGui.QDialog.__init__(self, parent)
self.setupUi(self) self.setupUi(self)
# General tab # General tab
self.generalTab = GeneralTab(self) self.generalTab = GeneralTab(self)
# Themes tab # Themes tab
self.themesTab = ThemesTab(self, mainWindow) self.themesTab = ThemesTab(self)
# Advanced tab # Advanced tab
self.advancedTab = AdvancedTab(self) self.advancedTab = AdvancedTab(self)
# Advanced tab # Advanced tab
self.playerTab = PlayerTab(self, mainWindow) self.playerTab = PlayerTab(self)
def exec_(self): def exec_(self):
"""
Execute the form
"""
# load all the settings # load all the settings
self.settingListWidget.clear() self.settingListWidget.clear()
while self.stackedLayout.count(): while self.stackedLayout.count():
@ -140,5 +144,25 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
per save. per save.
""" """
if self.resetSuffixes: if self.resetSuffixes:
self.mainWindow.serviceManagerContents.resetSupportedSuffixes() self.service_manager.reset_supported_suffixes()
self.resetSuffixes = False self.resetSuffixes = False
def _get_main_window(self):
"""
Adds the main window to the class dynamically
"""
if not hasattr(self, u'_main_window'):
self._main_window = Registry().get(u'main_window')
return self._main_window
main_window = property(_get_main_window)
def _get_service_manager(self):
"""
Adds the plugin manager to the class dynamically
"""
if not hasattr(self, u'_service_manager'):
self._service_manager = Registry().get(u'service_manager')
return self._service_manager
service_manager = property(_get_service_manager)

View File

@ -26,17 +26,23 @@
# 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 #
############################################################################### ###############################################################################
"""
The list of shortcuts within a dialog.
"""
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate, build_icon from openlp.core.lib import translate, build_icon
from openlp.core.lib.ui import create_button_box from openlp.core.lib.ui import create_button_box
class CaptureShortcutButton(QtGui.QPushButton): class CaptureShortcutButton(QtGui.QPushButton):
""" """
A class to encapsulate a ``QPushButton``. A class to encapsulate a ``QPushButton``.
""" """
def __init__(self, *args): def __init__(self, *args):
"""
Constructor
"""
QtGui.QPushButton.__init__(self, *args) QtGui.QPushButton.__init__(self, *args)
self.setCheckable(True) self.setCheckable(True)
@ -51,7 +57,13 @@ class CaptureShortcutButton(QtGui.QPushButton):
class Ui_ShortcutListDialog(object): class Ui_ShortcutListDialog(object):
"""
The UI widgets for the shortcut dialog.
"""
def setupUi(self, shortcutListDialog): def setupUi(self, shortcutListDialog):
"""
Set up the UI
"""
shortcutListDialog.setObjectName(u'shortcutListDialog') shortcutListDialog.setObjectName(u'shortcutListDialog')
shortcutListDialog.resize(500, 438) shortcutListDialog.resize(500, 438)
self.shortcutListLayout = QtGui.QVBoxLayout(shortcutListDialog) self.shortcutListLayout = QtGui.QVBoxLayout(shortcutListDialog)
@ -107,12 +119,15 @@ class Ui_ShortcutListDialog(object):
self.alternateLabel.setObjectName(u'alternateLabel') self.alternateLabel.setObjectName(u'alternateLabel')
self.detailsLayout.addWidget(self.alternateLabel, 0, 2, 1, 1) self.detailsLayout.addWidget(self.alternateLabel, 0, 2, 1, 1)
self.shortcutListLayout.addLayout(self.detailsLayout) self.shortcutListLayout.addLayout(self.detailsLayout)
self.buttonBox = create_button_box(shortcutListDialog, u'buttonBox', [u'cancel', u'ok', u'defaults']) self.button_box = create_button_box(shortcutListDialog, u'button_box', [u'cancel', u'ok', u'defaults'])
self.buttonBox.setOrientation(QtCore.Qt.Horizontal) self.button_box.setOrientation(QtCore.Qt.Horizontal)
self.shortcutListLayout.addWidget(self.buttonBox) self.shortcutListLayout.addWidget(self.button_box)
self.retranslateUi(shortcutListDialog) self.retranslateUi(shortcutListDialog)
def retranslateUi(self, shortcutListDialog): def retranslateUi(self, shortcutListDialog):
"""
Translate the UI on the fly
"""
shortcutListDialog.setWindowTitle(translate('OpenLP.ShortcutListDialog', 'Configure Shortcuts')) shortcutListDialog.setWindowTitle(translate('OpenLP.ShortcutListDialog', 'Configure Shortcuts'))
self.descriptionLabel.setText( self.descriptionLabel.setText(
translate('OpenLP.ShortcutListDialog', 'Select an action and click one of the buttons below to start ' translate('OpenLP.ShortcutListDialog', 'Select an action and click one of the buttons below to start '

View File

@ -26,13 +26,14 @@
# 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 #
############################################################################### ###############################################################################
"""
The :mod:`~openlp.core.ui.shortcutlistform` module contains the form class"""
import logging import logging
import re import re
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, Settings from openlp.core.lib import Registry, Settings
from openlp.core.utils import translate from openlp.core.utils import translate
from openlp.core.utils.actions import ActionList from openlp.core.utils.actions import ActionList
from shortcutlistdialog import Ui_ShortcutListDialog from shortcutlistdialog import Ui_ShortcutListDialog
@ -41,12 +42,16 @@ REMOVE_AMPERSAND = re.compile(r'&{1}')
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog): class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
""" """
The shortcut list dialog The shortcut list dialog
""" """
def __init__(self, parent=None): def __init__(self, parent=None):
"""
Constructor
"""
QtGui.QDialog.__init__(self, parent) QtGui.QDialog.__init__(self, parent)
self.setupUi(self) self.setupUi(self)
self.changedActions = {} self.changedActions = {}
@ -63,7 +68,7 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
self.onClearPrimaryButtonClicked) self.onClearPrimaryButtonClicked)
QtCore.QObject.connect(self.clearAlternateButton, QtCore.SIGNAL(u'clicked(bool)'), QtCore.QObject.connect(self.clearAlternateButton, QtCore.SIGNAL(u'clicked(bool)'),
self.onClearAlternateButtonClicked) self.onClearAlternateButtonClicked)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(u'clicked(QAbstractButton*)'), QtCore.QObject.connect(self.button_box, QtCore.SIGNAL(u'clicked(QAbstractButton*)'),
self.onRestoreDefaultsClicked) self.onRestoreDefaultsClicked)
QtCore.QObject.connect(self.defaultRadioButton, QtCore.SIGNAL(u'clicked(bool)'), QtCore.QObject.connect(self.defaultRadioButton, QtCore.SIGNAL(u'clicked(bool)'),
self.onDefaultRadioButtonClicked) self.onDefaultRadioButtonClicked)
@ -71,6 +76,9 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
self.onCustomRadioButtonClicked) self.onCustomRadioButtonClicked)
def keyPressEvent(self, event): def keyPressEvent(self, event):
"""
Respond to certain key presses
"""
if event.key() == QtCore.Qt.Key_Space: if event.key() == QtCore.Qt.Key_Space:
self.keyReleaseEvent(event) self.keyReleaseEvent(event)
elif self.primaryPushButton.isChecked() or self.alternatePushButton.isChecked(): elif self.primaryPushButton.isChecked() or self.alternatePushButton.isChecked():
@ -80,6 +88,9 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
self.close() self.close()
def keyReleaseEvent(self, event): def keyReleaseEvent(self, event):
"""
Respond to certain key presses
"""
if not self.primaryPushButton.isChecked() and not self.alternatePushButton.isChecked(): if not self.primaryPushButton.isChecked() and not self.alternatePushButton.isChecked():
return return
key = event.key() key = event.key()
@ -105,6 +116,9 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
False, text=key_sequence.toString()) False, text=key_sequence.toString())
def exec_(self): def exec_(self):
"""
Execute the dialog
"""
self.changedActions = {} self.changedActions = {}
self.reloadShortcutList() self.reloadShortcutList()
self._adjustButton(self.primaryPushButton, False, False, u'') self._adjustButton(self.primaryPushButton, False, False, u'')
@ -273,7 +287,7 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
""" """
Restores all default shortcuts. Restores all default shortcuts.
""" """
if self.buttonBox.buttonRole(button) != QtGui.QDialogButtonBox.ResetRole: if self.button_box.buttonRole(button) != QtGui.QDialogButtonBox.ResetRole:
return return
if QtGui.QMessageBox.question(self, translate('OpenLP.ShortcutListDialog', 'Restore Default Shortcuts'), if QtGui.QMessageBox.question(self, translate('OpenLP.ShortcutListDialog', 'Restore Default Shortcuts'),
translate('OpenLP.ShortcutListDialog', 'Do you want to restore all ' translate('OpenLP.ShortcutListDialog', 'Do you want to restore all '
@ -421,10 +435,10 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
if action.shortcutContext() in [QtCore.Qt.WindowShortcut, if action.shortcutContext() in [QtCore.Qt.WindowShortcut,
QtCore.Qt.ApplicationShortcut]: QtCore.Qt.ApplicationShortcut]:
is_valid = False is_valid = False
if changing_action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]: if changing_action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]:
is_valid = False is_valid = False
if not is_valid: if not is_valid:
Receiver.send_message(u'openlp_warning_message', { self.main_window.warning_message( {
u'title': translate('OpenLP.ShortcutListDialog', 'Duplicate Shortcut'), u'title': translate('OpenLP.ShortcutListDialog', 'Duplicate Shortcut'),
u'message': translate('OpenLP.ShortcutListDialog', u'message': translate('OpenLP.ShortcutListDialog',
'The shortcut "%s" is already assigned to another action, ' 'The shortcut "%s" is already assigned to another action, '
@ -464,3 +478,13 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
button.setChecked(checked) button.setChecked(checked)
if enabled is not None: if enabled is not None:
button.setEnabled(enabled) button.setEnabled(enabled)
def _get_main_window(self):
"""
Adds the main window to the class dynamically
"""
if not hasattr(self, u'_main_window'):
self._main_window = Registry().get(u'main_window')
return self._main_window
main_window = property(_get_main_window)

View File

@ -26,7 +26,9 @@
# 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 #
############################################################################### ###############################################################################
"""
The :mod:`slidecontroller` module contains argubly the most important part of OpenLP - the slide controller
"""
import os import os
import logging import logging
import copy import copy
@ -34,14 +36,10 @@ from collections import deque
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import OpenLPToolbar, Receiver, ItemCapabilities, \ from openlp.core.lib import OpenLPToolbar, Receiver, ItemCapabilities, ServiceItem, ImageSource, SlideLimits, \
translate, build_icon, build_html, PluginManager, ServiceItem, \ ServiceItemAction, Settings, Registry, UiStrings, ScreenList, build_icon, build_html, translate
ImageSource, SlideLimits, ServiceItemAction, Settings from openlp.core.ui import HideMode, MainDisplay, Display, DisplayControllerType
from openlp.core.ui import HideMode, MainDisplay, Display, ScreenList from openlp.core.lib.ui import create_action
from openlp.core.lib.ui import UiStrings, create_action
from openlp.core.lib import SlideLimits, ServiceItemAction
from openlp.core.ui import HideMode, MainDisplay, Display, ScreenList, \
DisplayControllerType
from openlp.core.utils.actions import ActionList, CategoryOrder from openlp.core.utils.actions import ActionList, CategoryOrder
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -86,8 +84,6 @@ class SlideController(DisplayController):
self.ratio = float(self.screens.current[u'size'].width()) / float(self.screens.current[u'size'].height()) self.ratio = float(self.screens.current[u'size'].width()) / float(self.screens.current[u'size'].height())
except ZeroDivisionError: except ZeroDivisionError:
self.ratio = 1 self.ratio = 1
self.imageManager = self.parent().imageManager
self.mediaController = self.parent().mediaController
self.loopList = [ self.loopList = [
u'playSlidesMenu', u'playSlidesMenu',
u'loopSeparator', u'loopSeparator',
@ -98,6 +94,14 @@ class SlideController(DisplayController):
u'audioPauseItem', u'audioPauseItem',
u'audioTimeLabel' u'audioTimeLabel'
] ]
self.wideMenu = [
u'blankScreenButton',
u'themeScreenButton',
u'desktopScreenButton'
]
self.hideMenuList = [
u'hideMenu'
]
self.timer_id = 0 self.timer_id = 0
self.songEdit = False self.songEdit = False
self.selectedRow = 0 self.selectedRow = 0
@ -113,6 +117,7 @@ class SlideController(DisplayController):
# Type label for the top of the slide controller # Type label for the top of the slide controller
self.typeLabel = QtGui.QLabel(self.panel) self.typeLabel = QtGui.QLabel(self.panel)
if self.isLive: if self.isLive:
Registry().register(u'live_controller', self)
self.typeLabel.setText(UiStrings().Live) self.typeLabel.setText(UiStrings().Live)
self.split = 1 self.split = 1
self.typePrefix = u'live' self.typePrefix = u'live'
@ -121,6 +126,7 @@ class SlideController(DisplayController):
self.category = UiStrings().LiveToolbar self.category = UiStrings().LiveToolbar
ActionList.get_instance().add_category(unicode(self.category), CategoryOrder.standardToolbar) ActionList.get_instance().add_category(unicode(self.category), CategoryOrder.standardToolbar)
else: else:
Registry().register(u'preview_controller', self)
self.typeLabel.setText(UiStrings().Preview) self.typeLabel.setText(UiStrings().Preview)
self.split = 0 self.split = 0
self.typePrefix = u'preview' self.typePrefix = u'preview'
@ -197,6 +203,19 @@ class SlideController(DisplayController):
self.hideMenu.menu().addAction(self.blankScreen) self.hideMenu.menu().addAction(self.blankScreen)
self.hideMenu.menu().addAction(self.themeScreen) self.hideMenu.menu().addAction(self.themeScreen)
self.hideMenu.menu().addAction(self.desktopScreen) self.hideMenu.menu().addAction(self.desktopScreen)
# Wide menu of display control buttons.
self.blankScreenButton = QtGui.QToolButton(self.toolbar)
self.blankScreenButton.setObjectName(u'blankScreenButton')
self.toolbar.addToolbarWidget(self.blankScreenButton)
self.blankScreenButton.setDefaultAction(self.blankScreen)
self.themeScreenButton = QtGui.QToolButton(self.toolbar)
self.themeScreenButton.setObjectName(u'themeScreenButton')
self.toolbar.addToolbarWidget(self.themeScreenButton)
self.themeScreenButton.setDefaultAction(self.themeScreen)
self.desktopScreenButton = QtGui.QToolButton(self.toolbar)
self.desktopScreenButton.setObjectName(u'desktopScreenButton')
self.toolbar.addToolbarWidget(self.desktopScreenButton)
self.desktopScreenButton.setDefaultAction(self.desktopScreen)
self.toolbar.addToolbarAction(u'loopSeparator', separator=True) self.toolbar.addToolbarAction(u'loopSeparator', separator=True)
# Play Slides Menu # Play Slides Menu
self.playSlidesMenu = QtGui.QToolButton(self.toolbar) self.playSlidesMenu = QtGui.QToolButton(self.toolbar)
@ -211,7 +230,7 @@ class SlideController(DisplayController):
self.playSlidesOnce = create_action(self, u'playSlidesOnce', text=UiStrings().PlaySlidesToEnd, self.playSlidesOnce = create_action(self, u'playSlidesOnce', text=UiStrings().PlaySlidesToEnd,
icon=u':/media/media_time.png', checked=False, shortcuts=[], icon=u':/media/media_time.png', checked=False, shortcuts=[],
category=self.category, triggers=self.onPlaySlidesOnce) category=self.category, triggers=self.onPlaySlidesOnce)
if Settings().value(self.parent().generalSettingsSection + u'/enable slide loop', True): if Settings().value(self.parent().advancedSettingsSection + u'/slide limits') == SlideLimits.Wrap:
self.playSlidesMenu.setDefaultAction(self.playSlidesLoop) self.playSlidesMenu.setDefaultAction(self.playSlidesLoop)
else: else:
self.playSlidesMenu.setDefaultAction(self.playSlidesOnce) self.playSlidesMenu.setDefaultAction(self.playSlidesOnce)
@ -234,7 +253,7 @@ class SlideController(DisplayController):
tooltip=translate('OpenLP.SlideController', 'Edit and reload song preview.'), triggers=self.onEditSong) tooltip=translate('OpenLP.SlideController', 'Edit and reload song preview.'), triggers=self.onEditSong)
self.controllerLayout.addWidget(self.toolbar) self.controllerLayout.addWidget(self.toolbar)
# Build the Media Toolbar # Build the Media Toolbar
self.mediaController.register_controller(self) self.media_controller.register_controller(self)
if self.isLive: if self.isLive:
# Build the Song Toolbar # Build the Song Toolbar
self.songMenu = QtGui.QToolButton(self.toolbar) self.songMenu = QtGui.QToolButton(self.toolbar)
@ -261,7 +280,7 @@ class SlideController(DisplayController):
self.audioMenu.addAction(self.nextTrackItem) self.audioMenu.addAction(self.nextTrackItem)
self.trackMenu = self.audioMenu.addMenu(translate('OpenLP.SlideController', 'Tracks')) self.trackMenu = self.audioMenu.addMenu(translate('OpenLP.SlideController', 'Tracks'))
self.audioTimeLabel = QtGui.QLabel(u' 00:00 ', self.toolbar) self.audioTimeLabel = QtGui.QLabel(u' 00:00 ', self.toolbar)
self.audioTimeLabel.setAlignment(QtCore.Qt.AlignCenter|QtCore.Qt.AlignHCenter) self.audioTimeLabel.setAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignHCenter)
self.audioTimeLabel.setStyleSheet( self.audioTimeLabel.setStyleSheet(
u'background-color: palette(background); ' u'background-color: palette(background); '
u'border-top-color: palette(shadow); ' u'border-top-color: palette(shadow); '
@ -292,7 +311,7 @@ class SlideController(DisplayController):
self.slideLayout.setObjectName(u'SlideLayout') self.slideLayout.setObjectName(u'SlideLayout')
self.previewDisplay = Display(self, self.isLive, self) self.previewDisplay = Display(self, self.isLive, self)
self.previewDisplay.setGeometry(QtCore.QRect(0, 0, 300, 300)) self.previewDisplay.setGeometry(QtCore.QRect(0, 0, 300, 300))
self.previewDisplay.screen = {u'size':self.previewDisplay.geometry()} self.previewDisplay.screen = {u'size': self.previewDisplay.geometry()}
self.previewDisplay.setup() self.previewDisplay.setup()
self.slideLayout.insertWidget(0, self.previewDisplay) self.slideLayout.insertWidget(0, self.previewDisplay)
self.previewDisplay.hide() self.previewDisplay.hide()
@ -301,8 +320,7 @@ class SlideController(DisplayController):
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0) sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth( sizePolicy.setHeightForWidth(self.slidePreview.sizePolicy().hasHeightForWidth())
self.slidePreview.sizePolicy().hasHeightForWidth())
self.slidePreview.setSizePolicy(sizePolicy) self.slidePreview.setSizePolicy(sizePolicy)
self.slidePreview.setFrameShape(QtGui.QFrame.Box) self.slidePreview.setFrameShape(QtGui.QFrame.Box)
self.slidePreview.setFrameShadow(QtGui.QFrame.Plain) self.slidePreview.setFrameShadow(QtGui.QFrame.Plain)
@ -349,6 +367,7 @@ class SlideController(DisplayController):
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'slidecontroller_toggle_display'), self.toggleDisplay) QtCore.SIGNAL(u'slidecontroller_toggle_display'), self.toggleDisplay)
self.toolbar.setWidgetVisible(self.loopList, False) self.toolbar.setWidgetVisible(self.loopList, False)
self.toolbar.setWidgetVisible(self.wideMenu, False)
else: else:
QtCore.QObject.connect(self.previewListWidget, QtCore.QObject.connect(self.previewListWidget,
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onGoLiveClick) QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onGoLiveClick)
@ -357,8 +376,7 @@ class SlideController(DisplayController):
self.setLiveHotkeys(self) self.setLiveHotkeys(self)
self.__addActionsToWidget(self.previewListWidget) self.__addActionsToWidget(self.previewListWidget)
else: else:
self.previewListWidget.addActions( self.previewListWidget.addActions([self.nextItem, self.previousItem])
[self.nextItem, self.previousItem])
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'slidecontroller_%s_stop_loop' % self.typePrefix), self.onStopLoop) QtCore.SIGNAL(u'slidecontroller_%s_stop_loop' % self.typePrefix), self.onStopLoop)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
@ -438,6 +456,9 @@ class SlideController(DisplayController):
self.current_shortcut = u'' self.current_shortcut = u''
def setLiveHotkeys(self, parent=None): def setLiveHotkeys(self, parent=None):
"""
Set the live hotkeys
"""
self.previousService = create_action(parent, u'previousService', self.previousService = create_action(parent, u'previousService',
text=translate('OpenLP.SlideController', 'Previous Service'), text=translate('OpenLP.SlideController', 'Previous Service'),
shortcuts=[QtCore.Qt.Key_Left], context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category, shortcuts=[QtCore.Qt.Key_Left], context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category,
@ -448,12 +469,15 @@ class SlideController(DisplayController):
triggers=self.serviceNext) triggers=self.serviceNext)
self.escapeItem = create_action(parent, 'escapeItem', self.escapeItem = create_action(parent, 'escapeItem',
text=translate('OpenLP.SlideController', 'Escape Item'), text=translate('OpenLP.SlideController', 'Escape Item'),
shortcuts=[QtCore.Qt.Key_Escape],context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category, shortcuts=[QtCore.Qt.Key_Escape], context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category,
triggers=self.liveEscape) triggers=self.liveEscape)
def liveEscape(self): def liveEscape(self):
"""
If you press ESC on the live screen it should close the display temporarily.
"""
self.display.setVisible(False) self.display.setVisible(False)
self.mediaController.media_stop(self) self.media_controller.media_stop(self)
def toggleDisplay(self, action): def toggleDisplay(self, action):
""" """
@ -494,12 +518,12 @@ class SlideController(DisplayController):
self.keypress_loop = True self.keypress_loop = True
keypressCommand = self.keypress_queue.popleft() keypressCommand = self.keypress_queue.popleft()
if keypressCommand == ServiceItemAction.Previous: if keypressCommand == ServiceItemAction.Previous:
Receiver.send_message('servicemanager_previous_item') self.service_manager.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') self.service_manager.previous_item(last_slide=True)
else: else:
Receiver.send_message('servicemanager_next_item') self.service_manager.next_item()
self.keypress_loop = False self.keypress_loop = False
def screenSizeChanged(self): def screenSizeChanged(self):
@ -510,7 +534,7 @@ class SlideController(DisplayController):
# rebuild display as screen size changed # rebuild display as screen size changed
if self.display: if self.display:
self.display.close() self.display.close()
self.display = MainDisplay(self, self.imageManager, self.isLive, self) self.display = MainDisplay(self, self.isLive, self)
self.display.setup() self.display.setup()
if self.isLive: if self.isLive:
self.__addActionsToWidget(self.display) self.__addActionsToWidget(self.display)
@ -520,17 +544,20 @@ class SlideController(DisplayController):
self.ratio = float(self.screens.current[u'size'].width()) / float(self.screens.current[u'size'].height()) self.ratio = float(self.screens.current[u'size'].width()) / float(self.screens.current[u'size'].height())
except ZeroDivisionError: except ZeroDivisionError:
self.ratio = 1 self.ratio = 1
self.mediaController.setup_display(self.display, False) self.media_controller.setup_display(self.display, False)
self.previewSizeChanged() self.previewSizeChanged()
self.previewDisplay.setup() self.previewDisplay.setup()
serviceItem = ServiceItem() serviceItem = ServiceItem()
self.previewDisplay.webView.setHtml(build_html(serviceItem, self.previewDisplay.screen, None, self.isLive, self.previewDisplay.webView.setHtml(build_html(serviceItem, self.previewDisplay.screen, None, self.isLive,
plugins=PluginManager.get_instance().plugins)) plugins=self.plugin_manager.plugins))
self.mediaController.setup_display(self.previewDisplay,True) self.media_controller.setup_display(self.previewDisplay, True)
if self.serviceItem: if self.serviceItem:
self.refreshServiceItem() self.refreshServiceItem()
def __addActionsToWidget(self, widget): def __addActionsToWidget(self, widget):
"""
Add actions to the widget specified by `widget`
"""
widget.addActions([ widget.addActions([
self.previousItem, self.nextItem, self.previousItem, self.nextItem,
self.previousService, self.nextService, self.previousService, self.nextService,
@ -568,8 +595,24 @@ class SlideController(DisplayController):
width = self.parent().controlSplitter.sizes()[self.split] width = self.parent().controlSplitter.sizes()[self.split]
for framenumber in range(len(self.serviceItem.get_frames())): for framenumber in range(len(self.serviceItem.get_frames())):
self.previewListWidget.setRowHeight(framenumber, width / self.ratio) self.previewListWidget.setRowHeight(framenumber, width / self.ratio)
self.onControllerSizeChanged(self.controller.width(), self.controller.height())
def onControllerSizeChanged(self, width, height):
"""
Change layout of display control buttons on controller size change
"""
if self.isLive:
if width > 300 and self.hideMenu.isVisible():
self.toolbar.setWidgetVisible(self.hideMenuList, False)
self.toolbar.setWidgetVisible(self.wideMenu)
elif width < 300 and not self.hideMenu.isVisible():
self.toolbar.setWidgetVisible(self.wideMenu, False)
self.toolbar.setWidgetVisible(self.hideMenuList)
def onSongBarHandler(self): def onSongBarHandler(self):
"""
Some song handler
"""
request = self.sender().text() request = self.sender().text()
slide_no = self.slideList[request] slide_no = self.slideList[request]
self.__updatePreviewSelection(slide_no) self.__updatePreviewSelection(slide_no)
@ -585,7 +628,7 @@ class SlideController(DisplayController):
""" """
Updates the Slide Limits variable from the settings. Updates the Slide Limits variable from the settings.
""" """
self.slide_limits = Settings().value(self.parent().advancedSettingsSection + u'/slide limits', SlideLimits.End) self.slide_limits = Settings().value(self.parent().advancedSettingsSection + u'/slide limits')
def enableToolBar(self, item): def enableToolBar(self, item):
""" """
@ -613,7 +656,7 @@ class SlideController(DisplayController):
self.playSlidesLoop.setChecked(False) self.playSlidesLoop.setChecked(False)
self.playSlidesLoop.setIcon(build_icon(u':/media/media_time.png')) self.playSlidesLoop.setIcon(build_icon(u':/media/media_time.png'))
if item.is_text(): if item.is_text():
if Settings().value(self.parent().songsSettingsSection + u'/display songbar', True) and self.slideList: if Settings().value(self.parent().songsSettingsSection + u'/display songbar') and self.slideList:
self.songMenu.show() self.songMenu.show()
if item.is_capable(ItemCapabilities.CanLoop) and len(item.get_frames()) > 1: if item.is_capable(ItemCapabilities.CanLoop) and len(item.get_frames()) > 1:
self.toolbar.setWidgetVisible(self.loopList) self.toolbar.setWidgetVisible(self.loopList)
@ -654,12 +697,12 @@ class SlideController(DisplayController):
item.render() item.render()
self._processItem(item, self.selectedRow) self._processItem(item, self.selectedRow)
def addServiceItem(self, item): def add_service_item(self, item):
""" """
Method to install the service item into the controller Method to install the service item into the controller
Called by plugins Called by plugins
""" """
log.debug(u'addServiceItem live = %s' % self.isLive) log.debug(u'add_service_item live = %s' % self.isLive)
item.render() item.render()
slideno = 0 slideno = 0
if self.songEdit: if self.songEdit:
@ -692,6 +735,14 @@ class SlideController(DisplayController):
self.slideSelected() self.slideSelected()
else: else:
self._processItem(item, slidenum) self._processItem(item, slidenum)
if self.isLive and item.auto_play_slides_loop and item.timed_slide_interval > 0:
self.playSlidesLoop.setChecked(item.auto_play_slides_loop)
self.delaySpinBox.setValue(int(item.timed_slide_interval))
self.onPlaySlidesLoop()
elif self.isLive and item.auto_play_slides_once and item.timed_slide_interval > 0:
self.playSlidesOnce.setChecked(item.auto_play_slides_once)
self.delaySpinBox.setValue(int(item.timed_slide_interval))
self.onPlaySlidesOnce()
def _processItem(self, serviceItem, slideno): def _processItem(self, serviceItem, slideno):
""" """
@ -727,8 +778,8 @@ class SlideController(DisplayController):
action.setData(counter) action.setData(counter)
QtCore.QObject.connect(action, QtCore.SIGNAL(u'triggered(bool)'), self.onTrackTriggered) QtCore.QObject.connect(action, QtCore.SIGNAL(u'triggered(bool)'), self.onTrackTriggered)
self.display.audioPlayer.repeat = Settings().value( self.display.audioPlayer.repeat = Settings().value(
self.parent().generalSettingsSection + u'/audio repeat list', False) self.parent().generalSettingsSection + u'/audio repeat list')
if Settings().value(self.parent().generalSettingsSection + u'/audio start paused', True): if Settings().value(self.parent().generalSettingsSection + u'/audio start paused'):
self.audioPauseItem.setChecked(True) self.audioPauseItem.setChecked(True)
self.display.audioPlayer.pause() self.display.audioPlayer.pause()
else: else:
@ -768,9 +819,9 @@ class SlideController(DisplayController):
else: else:
# If current slide set background to image # If current slide set background to image
if framenumber == slideno: if framenumber == slideno:
self.serviceItem.bg_image_bytes = self.imageManager.getImageBytes(frame[u'path'], self.serviceItem.bg_image_bytes = self.image_manager.get_image_bytes(frame[u'path'],
ImageSource.ImagePlugin) ImageSource.ImagePlugin)
image = self.imageManager.getImage(frame[u'path'], ImageSource.ImagePlugin) image = self.image_manager.get_image(frame[u'path'], ImageSource.ImagePlugin)
label.setPixmap(QtGui.QPixmap.fromImage(image)) label.setPixmap(QtGui.QPixmap.fromImage(image))
self.previewListWidget.setCellWidget(framenumber, 0, label) self.previewListWidget.setCellWidget(framenumber, 0, label)
slideHeight = width * (1 / self.ratio) slideHeight = width * (1 / self.ratio)
@ -837,8 +888,7 @@ class SlideController(DisplayController):
Allow the main display to blank the main display at startup time Allow the main display to blank the main display at startup time
""" """
log.debug(u'mainDisplaySetBackground live = %s' % self.isLive) log.debug(u'mainDisplaySetBackground live = %s' % self.isLive)
display_type = Settings().value(self.parent().generalSettingsSection + u'/screen blank', display_type = Settings().value(self.parent().generalSettingsSection + u'/screen blank')
u'')
if self.screens.which_screen(self.window()) != self.screens.which_screen(self.display): if self.screens.which_screen(self.window()) != self.screens.which_screen(self.display):
# Order done to handle initial conversion # Order done to handle initial conversion
if display_type == u'themed': if display_type == u'themed':
@ -881,6 +931,7 @@ class SlideController(DisplayController):
Settings().remove(self.parent().generalSettingsSection + u'/screen blank') Settings().remove(self.parent().generalSettingsSection + u'/screen blank')
self.blankPlugin() self.blankPlugin()
self.updatePreview() self.updatePreview()
self.onToggleLoop()
def onThemeDisplay(self, checked=None): def onThemeDisplay(self, checked=None):
""" """
@ -899,6 +950,7 @@ class SlideController(DisplayController):
Settings().remove(self.parent().generalSettingsSection + u'/screen blank') Settings().remove(self.parent().generalSettingsSection + u'/screen blank')
self.blankPlugin() self.blankPlugin()
self.updatePreview() self.updatePreview()
self.onToggleLoop()
def onHideDisplay(self, checked=None): def onHideDisplay(self, checked=None):
""" """
@ -917,6 +969,7 @@ class SlideController(DisplayController):
Settings().remove(self.parent().generalSettingsSection + u'/screen blank') Settings().remove(self.parent().generalSettingsSection + u'/screen blank')
self.hidePlugin(checked) self.hidePlugin(checked)
self.updatePreview() self.updatePreview()
self.onToggleLoop()
def blankPlugin(self): def blankPlugin(self):
""" """
@ -933,8 +986,7 @@ class SlideController(DisplayController):
else: else:
if not self.serviceItem.is_command(): if not self.serviceItem.is_command():
Receiver.send_message(u'live_display_show') Receiver.send_message(u'live_display_show')
Receiver.send_message(u'%s_unblank' % self.serviceItem.name.lower(), Receiver.send_message(u'%s_unblank' % self.serviceItem.name.lower(), [self.serviceItem, self.isLive])
[self.serviceItem, self.isLive])
else: else:
if hide_mode: if hide_mode:
Receiver.send_message(u'live_display_hide', hide_mode) Receiver.send_message(u'live_display_hide', hide_mode)
@ -949,13 +1001,11 @@ class SlideController(DisplayController):
if self.serviceItem is not None: if self.serviceItem is not None:
if hide: if hide:
Receiver.send_message(u'live_display_hide', HideMode.Screen) Receiver.send_message(u'live_display_hide', HideMode.Screen)
Receiver.send_message(u'%s_hide' % self.serviceItem.name.lower(), Receiver.send_message(u'%s_hide' % self.serviceItem.name.lower(), [self.serviceItem, self.isLive])
[self.serviceItem, self.isLive])
else: else:
if not self.serviceItem.is_command(): if not self.serviceItem.is_command():
Receiver.send_message(u'live_display_show') Receiver.send_message(u'live_display_show')
Receiver.send_message(u'%s_unblank' % self.serviceItem.name.lower(), Receiver.send_message(u'%s_unblank' % self.serviceItem.name.lower(), [self.serviceItem, self.isLive])
[self.serviceItem, self.isLive])
else: else:
if hide: if hide:
Receiver.send_message(u'live_display_hide', HideMode.Screen) Receiver.send_message(u'live_display_hide', HideMode.Screen)
@ -995,6 +1045,7 @@ class SlideController(DisplayController):
self.selectedRow = row self.selectedRow = row
self.__checkUpdateSelectedSlide(row) self.__checkUpdateSelectedSlide(row)
Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix, row) Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix, row)
self.display.setFocus()
def onSlideChange(self, row): def onSlideChange(self, row):
""" """
@ -1086,6 +1137,9 @@ class SlideController(DisplayController):
self.slideSelected() self.slideSelected()
def __checkUpdateSelectedSlide(self, row): def __checkUpdateSelectedSlide(self, row):
"""
Check if this slide has been updated
"""
if row + 1 < self.previewListWidget.rowCount(): if row + 1 < self.previewListWidget.rowCount():
self.previewListWidget.scrollToItem(self.previewListWidget.item(row + 1, 0)) self.previewListWidget.scrollToItem(self.previewListWidget.item(row + 1, 0))
self.previewListWidget.selectRow(row) self.previewListWidget.selectRow(row)
@ -1094,7 +1148,8 @@ class SlideController(DisplayController):
""" """
Toggles the loop state. Toggles the loop state.
""" """
if self.playSlidesLoop.isChecked() or self.playSlidesOnce.isChecked(): hide_mode = self.hideMode()
if hide_mode is None and (self.playSlidesLoop.isChecked() or self.playSlidesOnce.isChecked()):
self.onStartLoop() self.onStartLoop()
else: else:
self.onStopLoop() self.onStopLoop()
@ -1128,11 +1183,11 @@ class SlideController(DisplayController):
self.playSlidesLoop.setText(UiStrings().StopPlaySlidesInLoop) self.playSlidesLoop.setText(UiStrings().StopPlaySlidesInLoop)
self.playSlidesOnce.setIcon(build_icon(u':/media/media_time.png')) self.playSlidesOnce.setIcon(build_icon(u':/media/media_time.png'))
self.playSlidesOnce.setText(UiStrings().PlaySlidesToEnd) self.playSlidesOnce.setText(UiStrings().PlaySlidesToEnd)
self.playSlidesMenu.setDefaultAction(self.playSlidesLoop)
self.playSlidesOnce.setChecked(False)
else: else:
self.playSlidesLoop.setIcon(build_icon(u':/media/media_time.png')) self.playSlidesLoop.setIcon(build_icon(u':/media/media_time.png'))
self.playSlidesLoop.setText(UiStrings().PlaySlidesInLoop) self.playSlidesLoop.setText(UiStrings().PlaySlidesInLoop)
self.playSlidesMenu.setDefaultAction(self.playSlidesLoop)
self.playSlidesOnce.setChecked(False)
self.onToggleLoop() self.onToggleLoop()
def onPlaySlidesOnce(self, checked=None): def onPlaySlidesOnce(self, checked=None):
@ -1149,17 +1204,23 @@ class SlideController(DisplayController):
self.playSlidesOnce.setText(UiStrings().StopPlaySlidesToEnd) self.playSlidesOnce.setText(UiStrings().StopPlaySlidesToEnd)
self.playSlidesLoop.setIcon(build_icon(u':/media/media_time.png')) self.playSlidesLoop.setIcon(build_icon(u':/media/media_time.png'))
self.playSlidesLoop.setText(UiStrings().PlaySlidesInLoop) self.playSlidesLoop.setText(UiStrings().PlaySlidesInLoop)
self.playSlidesMenu.setDefaultAction(self.playSlidesOnce)
self.playSlidesLoop.setChecked(False)
else: else:
self.playSlidesOnce.setIcon(build_icon(u':/media/media_time')) self.playSlidesOnce.setIcon(build_icon(u':/media/media_time'))
self.playSlidesOnce.setText(UiStrings().PlaySlidesToEnd) self.playSlidesOnce.setText(UiStrings().PlaySlidesToEnd)
self.playSlidesMenu.setDefaultAction(self.playSlidesOnce)
self.playSlidesLoop.setChecked(False)
self.onToggleLoop() self.onToggleLoop()
def setAudioItemsVisibility(self, visible): def setAudioItemsVisibility(self, visible):
"""
Set the visibility of the audio stuff
"""
self.toolbar.setWidgetVisible(self.audioList, visible) self.toolbar.setWidgetVisible(self.audioList, visible)
def onAudioPauseClicked(self, checked): def onAudioPauseClicked(self, checked):
"""
Pause the audio player
"""
if not self.audioPauseItem.isVisible(): if not self.audioPauseItem.isVisible():
return return
if checked: if checked:
@ -1179,20 +1240,22 @@ class SlideController(DisplayController):
From the preview display requires the service Item to be editied From the preview display requires the service Item to be editied
""" """
self.songEdit = True self.songEdit = True
Receiver.send_message(u'%s_edit' % self.serviceItem.name.lower(), u'P:%s' % self.serviceItem.edit_id) new_item = Registry().get(self.serviceItem.name).onRemoteEdit(self.serviceItem.edit_id, True)
if new_item:
self.add_service_item(new_item)
def onPreviewAddToService(self): def onPreviewAddToService(self):
""" """
From the preview display request the Item to be added to service From the preview display request the Item to be added to service
""" """
if self.serviceItem: if self.serviceItem:
self.parent().serviceManagerContents.addServiceItem(self.serviceItem) self.service_manager.add_service_item(self.serviceItem)
def onGoLiveClick(self): def onGoLiveClick(self):
""" """
triggered by clicking the Preview slide items triggered by clicking the Preview slide items
""" """
if Settings().value(u'advanced/double click live', False): if Settings().value(u'advanced/double click live'):
# Live and Preview have issues if we have video or presentations # Live and Preview have issues if we have video or presentations
# playing in both at the same time. # playing in both at the same time.
if self.serviceItem.is_command(): if self.serviceItem.is_command():
@ -1208,16 +1271,16 @@ class SlideController(DisplayController):
row = self.previewListWidget.currentRow() row = self.previewListWidget.currentRow()
if -1 < row < self.previewListWidget.rowCount(): if -1 < row < self.previewListWidget.rowCount():
if self.serviceItem.from_service: if self.serviceItem.from_service:
Receiver.send_message('servicemanager_preview_live', u'%s:%s' % (self.serviceItem._uuid, row)) self.service_manager.preview_live(self.serviceItem.unique_identifier, row)
else: else:
self.parent().liveController.addServiceManagerItem(self.serviceItem, row) self.live_controller.addServiceManagerItem(self.serviceItem, row)
def onMediaStart(self, item): def onMediaStart(self, item):
""" """
Respond to the arrival of a media service item Respond to the arrival of a media service item
""" """
log.debug(u'SlideController onMediaStart') log.debug(u'SlideController onMediaStart')
self.mediaController.video(self.controllerType, item, self.hideMode()) self.media_controller.video(self.controllerType, item, self.hideMode())
if not self.isLive: if not self.isLive:
self.previewDisplay.show() self.previewDisplay.show()
self.slidePreview.hide() self.slidePreview.hide()
@ -1227,7 +1290,7 @@ class SlideController(DisplayController):
Respond to a request to close the Video Respond to a request to close the Video
""" """
log.debug(u'SlideController onMediaClose') log.debug(u'SlideController onMediaClose')
self.mediaController.media_reset(self) self.media_controller.media_reset(self)
self.previewDisplay.hide() self.previewDisplay.hide()
self.slidePreview.show() self.slidePreview.show()
@ -1262,14 +1325,73 @@ class SlideController(DisplayController):
return None return None
def onNextTrackClicked(self): def onNextTrackClicked(self):
"""
Go to the next track when next is clicked
"""
self.display.audioPlayer.next() self.display.audioPlayer.next()
def onAudioTimeRemaining(self, time): def onAudioTimeRemaining(self, time):
"""
Update how much time is remaining
"""
seconds = self.display.audioPlayer.mediaObject.remainingTime() // 1000 seconds = self.display.audioPlayer.mediaObject.remainingTime() // 1000
minutes = seconds // 60 minutes = seconds // 60
seconds %= 60 seconds %= 60
self.audioTimeLabel.setText(u' %02d:%02d ' % (minutes, seconds)) self.audioTimeLabel.setText(u' %02d:%02d ' % (minutes, seconds))
def onTrackTriggered(self): def onTrackTriggered(self):
"""
Start playing a track
"""
action = self.sender() action = self.sender()
self.display.audioPlayer.goTo(action.data()) self.display.audioPlayer.goTo(action.data())
def _get_plugin_manager(self):
"""
Adds the plugin manager to the class dynamically
"""
if not hasattr(self, u'_plugin_manager'):
self._plugin_manager = Registry().get(u'plugin_manager')
return self._plugin_manager
plugin_manager = property(_get_plugin_manager)
def _get_image_manager(self):
"""
Adds the image manager to the class dynamically
"""
if not hasattr(self, u'_image_manager'):
self._image_manager = Registry().get(u'image_manager')
return self._image_manager
image_manager = property(_get_image_manager)
def _get_media_controller(self):
"""
Adds the media controller to the class dynamically
"""
if not hasattr(self, u'_media_controller'):
self._media_controller = Registry().get(u'media_controller')
return self._media_controller
media_controller = property(_get_media_controller)
def _get_service_manager(self):
"""
Adds the service manager to the class dynamically
"""
if not hasattr(self, u'_service_manager'):
self._service_manager = Registry().get(u'service_manager')
return self._service_manager
service_manager = property(_get_service_manager)
def _get_live_controller(self):
"""
Adds the live controller to the class dynamically
"""
if not hasattr(self, u'_live_controller'):
self._live_controller = Registry().get(u'live_controller')
return self._live_controller
live_controller = property(_get_live_controller)

View File

@ -26,17 +26,28 @@
# 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 #
############################################################################### ###############################################################################
from openlp.core.lib import Receiver """
The splash screen
"""
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
class SplashScreen(QtGui.QSplashScreen): class SplashScreen(QtGui.QSplashScreen):
"""
The splash screen
"""
def __init__(self): def __init__(self):
"""
Constructor
"""
QtGui.QSplashScreen.__init__(self) QtGui.QSplashScreen.__init__(self)
self.setupUi() self.setupUi()
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'close_splash'), self.close)
def setupUi(self): def setupUi(self):
"""
Set up the UI
"""
self.setObjectName(u'splashScreen') self.setObjectName(u'splashScreen')
self.setContextMenuPolicy(QtCore.Qt.PreventContextMenu) self.setContextMenuPolicy(QtCore.Qt.PreventContextMenu)
splash_image = QtGui.QPixmap(u':/graphics/openlp-splash-screen.png') splash_image = QtGui.QPixmap(u':/graphics/openlp-splash-screen.png')

View File

@ -26,18 +26,27 @@
# 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 #
############################################################################### ###############################################################################
"""
The UI widgets for the time dialog
"""
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate from openlp.core.lib import UiStrings, translate
from openlp.core.lib.ui import UiStrings, create_button_box from openlp.core.lib.ui import create_button_box
class Ui_StartTimeDialog(object): class Ui_StartTimeDialog(object):
"""
The UI widgets for the time dialog
"""
def setupUi(self, StartTimeDialog): def setupUi(self, StartTimeDialog):
"""
Set up the UI
"""
StartTimeDialog.setObjectName(u'StartTimeDialog') StartTimeDialog.setObjectName(u'StartTimeDialog')
StartTimeDialog.resize(350, 10) StartTimeDialog.resize(350, 10)
self.dialogLayout = QtGui.QGridLayout(StartTimeDialog) self.dialogLayout = QtGui.QGridLayout(StartTimeDialog)
self.dialogLayout.setObjectName(u'dialogLayout') self.dialogLayout.setObjectName(u'dialog_layout')
self.startLabel = QtGui.QLabel(StartTimeDialog) self.startLabel = QtGui.QLabel(StartTimeDialog)
self.startLabel.setObjectName(u'startLabel') self.startLabel.setObjectName(u'startLabel')
self.startLabel.setAlignment(QtCore.Qt.AlignHCenter) self.startLabel.setAlignment(QtCore.Qt.AlignHCenter)
@ -101,12 +110,15 @@ class Ui_StartTimeDialog(object):
self.secondFinishLabel.setAlignment(QtCore.Qt.AlignRight) self.secondFinishLabel.setAlignment(QtCore.Qt.AlignRight)
self.dialogLayout.addWidget(self.secondFinishLabel, 3, 3, 1, 1) self.dialogLayout.addWidget(self.secondFinishLabel, 3, 3, 1, 1)
self.dialogLayout.addWidget(self.secondSpinBox, 3, 1, 1, 1) self.dialogLayout.addWidget(self.secondSpinBox, 3, 1, 1, 1)
self.buttonBox = create_button_box(StartTimeDialog, u'buttonBox', [u'cancel', u'ok']) self.button_box = create_button_box(StartTimeDialog, u'button_box', [u'cancel', u'ok'])
self.dialogLayout.addWidget(self.buttonBox, 5, 2, 1, 2) self.dialogLayout.addWidget(self.button_box, 5, 2, 1, 2)
self.retranslateUi(StartTimeDialog) self.retranslateUi(StartTimeDialog)
self.setMaximumHeight(self.sizeHint().height()) self.setMaximumHeight(self.sizeHint().height())
def retranslateUi(self, StartTimeDialog): def retranslateUi(self, StartTimeDialog):
"""
Update the translations on the fly
"""
self.setWindowTitle(translate('OpenLP.StartTimeForm', 'Item Start and Finish Time')) self.setWindowTitle(translate('OpenLP.StartTimeForm', 'Item Start and Finish Time'))
self.hourSpinBox.setSuffix(UiStrings().Hours) self.hourSpinBox.setSuffix(UiStrings().Hours)
self.minuteSpinBox.setSuffix(UiStrings().Minutes) self.minuteSpinBox.setSuffix(UiStrings().Minutes)

View File

@ -26,20 +26,26 @@
# 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 #
############################################################################### ###############################################################################
"""
The actual start time form.
"""
from PyQt4 import QtGui from PyQt4 import QtGui
from starttimedialog import Ui_StartTimeDialog from starttimedialog import Ui_StartTimeDialog
from openlp.core.lib import translate from openlp.core.lib import UiStrings, Registry, translate
from openlp.core.lib.ui import UiStrings, critical_error_message_box from openlp.core.lib.ui import critical_error_message_box
class StartTimeForm(QtGui.QDialog, Ui_StartTimeDialog): class StartTimeForm(QtGui.QDialog, Ui_StartTimeDialog):
""" """
The exception dialog The start time dialog
""" """
def __init__(self, parent): def __init__(self):
QtGui.QDialog.__init__(self, parent) """
Constructor
"""
QtGui.QDialog.__init__(self, self.main_window)
self.setupUi(self) self.setupUi(self)
def exec_(self): def exec_(self):
@ -60,6 +66,9 @@ class StartTimeForm(QtGui.QDialog, Ui_StartTimeDialog):
return QtGui.QDialog.exec_(self) return QtGui.QDialog.exec_(self)
def accept(self): def accept(self):
"""
When the dialog succeeds, this is run
"""
start = self.hourSpinBox.value() * 3600 + \ start = self.hourSpinBox.value() * 3600 + \
self.minuteSpinBox.value() * 60 + \ self.minuteSpinBox.value() * 60 + \
self.secondSpinBox.value() self.secondSpinBox.value()
@ -79,8 +88,21 @@ class StartTimeForm(QtGui.QDialog, Ui_StartTimeDialog):
return QtGui.QDialog.accept(self) return QtGui.QDialog.accept(self)
def _time_split(self, seconds): def _time_split(self, seconds):
"""
Split time up into hours minutes and seconds from secongs
"""
hours = seconds / 3600 hours = seconds / 3600
seconds -= 3600 * hours seconds -= 3600 * hours
minutes = seconds / 60 minutes = seconds / 60
seconds -= 60 * minutes seconds -= 60 * minutes
return hours, minutes, seconds return hours, minutes, seconds
def _get_main_window(self):
"""
Adds the main window to the class dynamically
"""
if not hasattr(self, u'_main_window'):
self._main_window = Registry().get(u'main_window')
return self._main_window
main_window = property(_get_main_window)

View File

@ -26,21 +26,24 @@
# 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 #
############################################################################### ###############################################################################
"""
The Theme wizard
"""
import logging import logging
import os import os
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, translate from openlp.core.lib import Receiver, UiStrings, Registry, translate
from openlp.core.lib.theme import BackgroundType, BackgroundGradientType from openlp.core.lib.theme import BackgroundType, BackgroundGradientType
from openlp.core.lib.ui import UiStrings, critical_error_message_box from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui import ThemeLayoutForm from openlp.core.ui import ThemeLayoutForm
from openlp.core.utils import get_images_filter from openlp.core.utils import get_images_filter
from themewizard import Ui_ThemeWizard from themewizard import Ui_ThemeWizard
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
""" """
This is the Theme Import Wizard, which allows easy creation and editing of This is the Theme Import Wizard, which allows easy creation and editing of
@ -56,7 +59,6 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
The QWidget-derived parent of the wizard. The QWidget-derived parent of the wizard.
""" """
QtGui.QWizard.__init__(self, parent) QtGui.QWizard.__init__(self, parent)
self.thememanager = parent
self.setupUi(self) self.setupUi(self)
self.registerFields() self.registerFields()
self.updateThemeAllowed = True self.updateThemeAllowed = True
@ -72,14 +74,14 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
self.onGradientStartButtonClicked) self.onGradientStartButtonClicked)
QtCore.QObject.connect(self.gradientEndButton, QtCore.SIGNAL(u'clicked()'), self.onGradientEndButtonClicked) QtCore.QObject.connect(self.gradientEndButton, QtCore.SIGNAL(u'clicked()'), self.onGradientEndButtonClicked)
QtCore.QObject.connect(self.imageBrowseButton, QtCore.SIGNAL(u'clicked()'), self.onImageBrowseButtonClicked) QtCore.QObject.connect(self.imageBrowseButton, QtCore.SIGNAL(u'clicked()'), self.onImageBrowseButtonClicked)
QtCore.QObject.connect(self.mainColorButton, QtCore.SIGNAL(u'clicked()'), self.onMainColorButtonClicked) QtCore.QObject.connect(self.mainColorButton, QtCore.SIGNAL(u'clicked()'), self.onMainColorButtonClicked)
QtCore.QObject.connect(self.outlineColorButton, QtCore.SIGNAL(u'clicked()'), self.onOutlineColorButtonClicked) QtCore.QObject.connect(self.outlineColorButton, QtCore.SIGNAL(u'clicked()'), self.onOutlineColorButtonClicked)
QtCore.QObject.connect(self.shadowColorButton, QtCore.SIGNAL(u'clicked()'), self.onShadowColorButtonClicked) QtCore.QObject.connect(self.shadowColorButton, QtCore.SIGNAL(u'clicked()'), self.onShadowColorButtonClicked)
QtCore.QObject.connect(self.outlineCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), QtCore.QObject.connect(self.outlineCheckBox, QtCore.SIGNAL(u'stateChanged(int)'),
self.onOutlineCheckCheckBoxStateChanged) self.onOutlineCheckCheckBoxStateChanged)
QtCore.QObject.connect(self.shadowCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), QtCore.QObject.connect(self.shadowCheckBox, QtCore.SIGNAL(u'stateChanged(int)'),
self.onShadowCheckCheckBoxStateChanged) self.onShadowCheckCheckBoxStateChanged)
QtCore.QObject.connect(self.footerColorButton,QtCore.SIGNAL(u'clicked()'), self.onFooterColorButtonClicked) QtCore.QObject.connect(self.footerColorButton, QtCore.SIGNAL(u'clicked()'), self.onFooterColorButtonClicked)
QtCore.QObject.connect(self, QtCore.SIGNAL(u'customButtonClicked(int)'), self.onCustom1ButtonClicked) QtCore.QObject.connect(self, QtCore.SIGNAL(u'customButtonClicked(int)'), self.onCustom1ButtonClicked)
QtCore.QObject.connect(self.mainPositionCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), QtCore.QObject.connect(self.mainPositionCheckBox, QtCore.SIGNAL(u'stateChanged(int)'),
self.onMainPositionCheckBoxStateChanged) self.onMainPositionCheckBoxStateChanged)
@ -149,7 +151,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
# Do not trigger on start up # Do not trigger on start up
if self.currentPage != self.welcomePage: if self.currentPage != self.welcomePage:
self.updateTheme() self.updateTheme()
self.thememanager.generateImage(self.theme, True) self.theme_manager.generate_image(self.theme, True)
def updateLinesText(self, lines): def updateLinesText(self, lines):
""" """
@ -178,6 +180,9 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
pixmapHeight + 2 * frameWidth) pixmapHeight + 2 * frameWidth)
def validateCurrentPage(self): def validateCurrentPage(self):
"""
Validate the current page
"""
background_image = BackgroundType.to_string(BackgroundType.Image) background_image = BackgroundType.to_string(BackgroundType.Image)
if self.page(self.currentId()) == self.backgroundPage and \ if self.page(self.currentId()) == self.backgroundPage and \
self.theme.background_type == background_image and not self.imageFileEdit.text(): self.theme.background_type == background_image and not self.imageFileEdit.text():
@ -196,7 +201,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
self.setOption(QtGui.QWizard.HaveCustomButton1, enabled) self.setOption(QtGui.QWizard.HaveCustomButton1, enabled)
if self.page(pageId) == self.previewPage: if self.page(pageId) == self.previewPage:
self.updateTheme() self.updateTheme()
frame = self.thememanager.generateImage(self.theme) frame = self.theme_manager.generate_image(self.theme)
self.previewBoxLabel.setPixmap(frame) self.previewBoxLabel.setPixmap(frame)
self.displayAspectRatio = float(frame.width()) / frame.height() self.displayAspectRatio = float(frame.width()) / frame.height()
self.resizeEvent() self.resizeEvent()
@ -206,15 +211,15 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
Generate layout preview and display the form. Generate layout preview and display the form.
""" """
self.updateTheme() self.updateTheme()
width = self.thememanager.mainwindow.renderer.width width = self.renderer.width
height = self.thememanager.mainwindow.renderer.height height = self.renderer.height
pixmap = QtGui.QPixmap(width, height) pixmap = QtGui.QPixmap(width, height)
pixmap.fill(QtCore.Qt.white) pixmap.fill(QtCore.Qt.white)
paint = QtGui.QPainter(pixmap) paint = QtGui.QPainter(pixmap)
paint.setPen(QtGui.QPen(QtCore.Qt.blue, 2)) paint.setPen(QtGui.QPen(QtCore.Qt.blue, 2))
paint.drawRect(self.thememanager.mainwindow.renderer.get_main_rectangle(self.theme)) paint.drawRect(self.renderer.get_main_rectangle(self.theme))
paint.setPen(QtGui.QPen(QtCore.Qt.red, 2)) paint.setPen(QtGui.QPen(QtCore.Qt.red, 2))
paint.drawRect(self.thememanager.mainwindow.renderer.get_footer_rectangle(self.theme)) paint.drawRect(self.renderer.get_footer_rectangle(self.theme))
paint.end() paint.end()
self.themeLayoutForm.exec_(pixmap) self.themeLayoutForm.exec_(pixmap)
@ -444,18 +449,30 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
self.setBackgroundPageValues() self.setBackgroundPageValues()
def onMainColorButtonClicked(self): def onMainColorButtonClicked(self):
"""
Set the main colour value
"""
self.theme.font_main_color = self._colorButton(self.theme.font_main_color) self.theme.font_main_color = self._colorButton(self.theme.font_main_color)
self.setMainAreaPageValues() self.setMainAreaPageValues()
def onOutlineColorButtonClicked(self): def onOutlineColorButtonClicked(self):
"""
Set the outline colour value
"""
self.theme.font_main_outline_color = self._colorButton(self.theme.font_main_outline_color) self.theme.font_main_outline_color = self._colorButton(self.theme.font_main_outline_color)
self.setMainAreaPageValues() self.setMainAreaPageValues()
def onShadowColorButtonClicked(self): def onShadowColorButtonClicked(self):
"""
Set the shadow colour value
"""
self.theme.font_main_shadow_color = self._colorButton(self.theme.font_main_shadow_color) self.theme.font_main_shadow_color = self._colorButton(self.theme.font_main_shadow_color)
self.setMainAreaPageValues() self.setMainAreaPageValues()
def onFooterColorButtonClicked(self): def onFooterColorButtonClicked(self):
"""
Set the footer colour value
"""
self.theme.font_footer_color = self._colorButton(self.theme.font_footer_color) self.theme.font_footer_color = self._colorButton(self.theme.font_footer_color)
self.setFooterAreaPageValues() self.setFooterAreaPageValues()
@ -514,9 +531,9 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
filename = os.path.split(unicode(self.theme.background_filename))[1] filename = os.path.split(unicode(self.theme.background_filename))[1]
saveTo = os.path.join(self.path, self.theme.theme_name, filename) saveTo = os.path.join(self.path, self.theme.theme_name, filename)
saveFrom = self.theme.background_filename saveFrom = self.theme.background_filename
if not self.edit_mode and not self.thememanager.checkIfThemeExists(self.theme.theme_name): if not self.edit_mode and not self.theme_manager.check_if_theme_exists(self.theme.theme_name):
return return
self.thememanager.saveTheme(self.theme, saveFrom, saveTo) self.theme_manager.save_theme(self.theme, saveFrom, saveTo)
return QtGui.QDialog.accept(self) return QtGui.QDialog.accept(self)
def _colorButton(self, field): def _colorButton(self, field):
@ -527,3 +544,23 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
if new_color.isValid(): if new_color.isValid():
field = new_color.name() field = new_color.name()
return field return field
def _get_renderer(self):
"""
Adds the Renderer to the class dynamically
"""
if not hasattr(self, u'_renderer'):
self._renderer = Registry().get(u'renderer')
return self._renderer
renderer = property(_get_renderer)
def _get_theme_manager(self):
"""
Adds the theme manager to the class dynamically
"""
if not hasattr(self, u'_theme_manager'):
self._theme_manager = Registry().get(u'theme_manager')
return self._theme_manager
theme_manager = property(_get_theme_manager)

View File

@ -26,7 +26,9 @@
# 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 #
############################################################################### ###############################################################################
"""
The layout of the theme
"""
from PyQt4 import QtGui from PyQt4 import QtGui
from openlp.core.lib import translate from openlp.core.lib import translate
@ -34,7 +36,13 @@ from openlp.core.lib.ui import create_button_box
class Ui_ThemeLayoutDialog(object): class Ui_ThemeLayoutDialog(object):
"""
The layout of the theme
"""
def setupUi(self, themeLayoutDialog): def setupUi(self, themeLayoutDialog):
"""
Set up the UI
"""
themeLayoutDialog.setObjectName(u'themeLayoutDialogDialog') themeLayoutDialog.setObjectName(u'themeLayoutDialogDialog')
#themeLayoutDialog.resize(300, 200) #themeLayoutDialog.resize(300, 200)
self.previewLayout = QtGui.QVBoxLayout(themeLayoutDialog) self.previewLayout = QtGui.QVBoxLayout(themeLayoutDialog)
@ -58,12 +66,14 @@ class Ui_ThemeLayoutDialog(object):
self.footerColourLabel = QtGui.QLabel(self.previewArea) self.footerColourLabel = QtGui.QLabel(self.previewArea)
self.footerColourLabel.setObjectName(u'footerColourLabel') self.footerColourLabel.setObjectName(u'footerColourLabel')
self.previewLayout.addWidget(self.footerColourLabel) self.previewLayout.addWidget(self.footerColourLabel)
self.buttonBox = create_button_box(themeLayoutDialog, u'buttonBox', [u'ok']) self.button_box = create_button_box(themeLayoutDialog, u'button_box', [u'ok'])
self.previewLayout.addWidget(self.buttonBox) self.previewLayout.addWidget(self.button_box)
self.retranslateUi(themeLayoutDialog) self.retranslateUi(themeLayoutDialog)
def retranslateUi(self, themeLayoutDialog): def retranslateUi(self, themeLayoutDialog):
"""
Translate the UI on the fly
"""
themeLayoutDialog.setWindowTitle(translate('OpenLP.StartTimeForm', 'Theme Layout')) themeLayoutDialog.setWindowTitle(translate('OpenLP.StartTimeForm', 'Theme Layout'))
self.mainColourLabel.setText(translate('OpenLP.StartTimeForm', 'The blue box shows the main area.')) self.mainColourLabel.setText(translate('OpenLP.StartTimeForm', 'The blue box shows the main area.'))
self.footerColourLabel.setText(translate('OpenLP.StartTimeForm', 'The red box shows the footer.')) self.footerColourLabel.setText(translate('OpenLP.StartTimeForm', 'The red box shows the footer.'))

View File

@ -26,16 +26,22 @@
# 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 #
############################################################################### ###############################################################################
"""
The form layout
"""
from PyQt4 import QtGui, QtCore from PyQt4 import QtGui, QtCore
from themelayoutdialog import Ui_ThemeLayoutDialog from themelayoutdialog import Ui_ThemeLayoutDialog
class ThemeLayoutForm(QtGui.QDialog, Ui_ThemeLayoutDialog): class ThemeLayoutForm(QtGui.QDialog, Ui_ThemeLayoutDialog):
""" """
The exception dialog The exception dialog
""" """
def __init__(self, parent): def __init__(self, parent):
"""
Constructor
"""
QtGui.QDialog.__init__(self, parent) QtGui.QDialog.__init__(self, parent)
self.setupUi(self) self.setupUi(self)
@ -44,11 +50,7 @@ class ThemeLayoutForm(QtGui.QDialog, Ui_ThemeLayoutDialog):
Run the Dialog with correct heading. Run the Dialog with correct heading.
""" """
pixmap = image.scaledToHeight(400, QtCore.Qt.SmoothTransformation) pixmap = image.scaledToHeight(400, QtCore.Qt.SmoothTransformation)
self.themeDisplayLabel.setPixmap(image) self.themeDisplayLabel.setPixmap(pixmap)
displayAspectRatio = float(image.width()) / image.height() displayAspectRatio = float(image.width()) / image.height()
self.themeDisplayLabel.setFixedSize(400, 400 / displayAspectRatio ) self.themeDisplayLabel.setFixedSize(400, 400 / displayAspectRatio)
return QtGui.QDialog.exec_(self) return QtGui.QDialog.exec_(self)
def accept(self):
return QtGui.QDialog.accept(self)

View File

@ -26,7 +26,9 @@
# 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 #
############################################################################### ###############################################################################
"""
The Theme Manager manages adding, deleteing and modifying of themes.
"""
import os import os
import zipfile import zipfile
import shutil import shutil
@ -36,23 +38,28 @@ import re
from xml.etree.ElementTree import ElementTree, XML from xml.etree.ElementTree import ElementTree, XML
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import OpenLPToolbar, get_text_file_string, build_icon, Receiver, SettingsManager, translate, \ from openlp.core.lib import ImageSource, OpenLPToolbar, Receiver, Registry, SettingsManager, Settings, UiStrings, \
check_item_selected, check_directory_exists, create_thumb, validate_thumb, ImageSource, Settings get_text_file_string, build_icon, translate, check_item_selected, check_directory_exists, create_thumb, \
validate_thumb
from openlp.core.lib.theme import ThemeXML, BackgroundType, VerticalType, BackgroundGradientType from openlp.core.lib.theme import ThemeXML, BackgroundType, VerticalType, BackgroundGradientType
from openlp.core.lib.ui import UiStrings, critical_error_message_box, create_widget_action from openlp.core.lib.ui import critical_error_message_box, create_widget_action
from openlp.core.theme import Theme from openlp.core.theme import Theme
from openlp.core.ui import FileRenameForm, ThemeForm from openlp.core.ui import FileRenameForm, ThemeForm
from openlp.core.utils import AppLocation, delete_file, locale_compare, get_filesystem_encoding from openlp.core.utils import AppLocation, delete_file, locale_compare, get_filesystem_encoding
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class ThemeManager(QtGui.QWidget): class ThemeManager(QtGui.QWidget):
""" """
Manages the orders of Theme. Manages the orders of Theme.
""" """
def __init__(self, mainwindow, parent=None): def __init__(self, parent=None):
"""
Constructor
"""
QtGui.QWidget.__init__(self, parent) QtGui.QWidget.__init__(self, parent)
self.mainwindow = mainwindow Registry().register(u'theme_manager', self)
self.settingsSection = u'themes' self.settingsSection = u'themes'
self.themeForm = ThemeForm(self) self.themeForm = ThemeForm(self)
self.fileRenameForm = FileRenameForm(self) self.fileRenameForm = FileRenameForm(self)
@ -71,67 +78,67 @@ class ThemeManager(QtGui.QWidget):
text=translate('OpenLP.ThemeManager', 'Edit Theme'), text=translate('OpenLP.ThemeManager', 'Edit Theme'),
icon=u':/themes/theme_edit.png', icon=u':/themes/theme_edit.png',
tooltip=translate('OpenLP.ThemeManager', 'Edit a theme.'), tooltip=translate('OpenLP.ThemeManager', 'Edit a theme.'),
triggers=self.onEditTheme) triggers=self.on_edit_theme)
self.deleteToolbarAction = self.toolbar.addToolbarAction(u'deleteTheme', self.deleteToolbarAction = self.toolbar.addToolbarAction(u'delete_theme',
text=translate('OpenLP.ThemeManager', 'Delete Theme'), text=translate('OpenLP.ThemeManager', 'Delete Theme'),
icon=u':/general/general_delete.png', icon=u':/general/general_delete.png',
tooltip=translate('OpenLP.ThemeManager', 'Delete a theme.'), tooltip=translate('OpenLP.ThemeManager', 'Delete a theme.'),
triggers=self.onDeleteTheme) triggers=self.on_delete_theme)
self.toolbar.addSeparator() self.toolbar.addSeparator()
self.toolbar.addToolbarAction(u'importTheme', self.toolbar.addToolbarAction(u'importTheme',
text=translate('OpenLP.ThemeManager', 'Import Theme'), text=translate('OpenLP.ThemeManager', 'Import Theme'),
icon=u':/general/general_import.png', icon=u':/general/general_import.png',
tooltip=translate('OpenLP.ThemeManager', 'Import a theme.'), tooltip=translate('OpenLP.ThemeManager', 'Import a theme.'),
triggers=self.onImportTheme) triggers=self.on_import_theme)
self.toolbar.addToolbarAction(u'exportTheme', self.toolbar.addToolbarAction(u'exportTheme',
text=translate('OpenLP.ThemeManager', 'Export Theme'), text=translate('OpenLP.ThemeManager', 'Export Theme'),
icon=u':/general/general_export.png', icon=u':/general/general_export.png',
tooltip=translate('OpenLP.ThemeManager', 'Export a theme.'), tooltip=translate('OpenLP.ThemeManager', 'Export a theme.'),
triggers=self.onExportTheme) triggers=self.on_export_theme)
self.layout.addWidget(self.toolbar) self.layout.addWidget(self.toolbar)
self.themeWidget = QtGui.QWidgetAction(self.toolbar) self.theme_widget = QtGui.QWidgetAction(self.toolbar)
self.themeWidget.setObjectName(u'themeWidget') self.theme_widget.setObjectName(u'theme_widget')
# create theme manager list # create theme manager list
self.themeListWidget = QtGui.QListWidget(self) self.theme_list_widget = QtGui.QListWidget(self)
self.themeListWidget.setAlternatingRowColors(True) self.theme_list_widget.setAlternatingRowColors(True)
self.themeListWidget.setIconSize(QtCore.QSize(88, 50)) self.theme_list_widget.setIconSize(QtCore.QSize(88, 50))
self.themeListWidget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.theme_list_widget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.themeListWidget.setObjectName(u'themeListWidget') self.theme_list_widget.setObjectName(u'theme_list_widget')
self.layout.addWidget(self.themeListWidget) self.layout.addWidget(self.theme_list_widget)
QtCore.QObject.connect(self.themeListWidget, QtCore.SIGNAL('customContextMenuRequested(QPoint)'), QtCore.QObject.connect(self.theme_list_widget, QtCore.SIGNAL('customContextMenuRequested(QPoint)'),
self.contextMenu) self.context_menu)
# build the context menu # build the context menu
self.menu = QtGui.QMenu() self.menu = QtGui.QMenu()
self.editAction = create_widget_action(self.menu, self.edit_action = create_widget_action(self.menu,
text=translate('OpenLP.ThemeManager', '&Edit Theme'), text=translate('OpenLP.ThemeManager', '&Edit Theme'),
icon=u':/themes/theme_edit.png', triggers=self.onEditTheme) icon=u':/themes/theme_edit.png', triggers=self.on_edit_theme)
self.copyAction = create_widget_action(self.menu, self.copy_action = create_widget_action(self.menu,
text=translate('OpenLP.ThemeManager', '&Copy Theme'), text=translate('OpenLP.ThemeManager', '&Copy Theme'),
icon=u':/themes/theme_edit.png', triggers=self.onCopyTheme) icon=u':/themes/theme_edit.png', triggers=self.on_copy_theme)
self.renameAction = create_widget_action(self.menu, self.rename_action = create_widget_action(self.menu,
text=translate('OpenLP.ThemeManager', '&Rename Theme'), text=translate('OpenLP.ThemeManager', '&Rename Theme'),
icon=u':/themes/theme_edit.png', triggers=self.onRenameTheme) icon=u':/themes/theme_edit.png', triggers=self.on_rename_theme)
self.deleteAction = create_widget_action(self.menu, self.delete_action = create_widget_action(self.menu,
text=translate('OpenLP.ThemeManager', '&Delete Theme'), text=translate('OpenLP.ThemeManager', '&Delete Theme'),
icon=u':/general/general_delete.png', triggers=self.onDeleteTheme) icon=u':/general/general_delete.png', triggers=self.on_delete_theme)
self.menu.addSeparator() self.menu.addSeparator()
self.globalAction = create_widget_action(self.menu, self.global_action = create_widget_action(self.menu,
text=translate('OpenLP.ThemeManager', 'Set As &Global Default'), text=translate('OpenLP.ThemeManager', 'Set As &Global Default'),
icon=u':/general/general_export.png', icon=u':/general/general_export.png',
triggers=self.changeGlobalFromScreen) triggers=self.changeGlobalFromScreen)
self.exportAction = create_widget_action(self.menu, self.exportAction = create_widget_action(self.menu,
text=translate('OpenLP.ThemeManager', '&Export Theme'), text=translate('OpenLP.ThemeManager', '&Export Theme'),
icon=u':/general/general_export.png', triggers=self.onExportTheme) icon=u':/general/general_export.png', triggers=self.on_export_theme)
# Signals # Signals
QtCore.QObject.connect(self.themeListWidget, QtCore.QObject.connect(self.theme_list_widget,
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.changeGlobalFromScreen) QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.changeGlobalFromScreen)
QtCore.QObject.connect(self.themeListWidget, QtCore.QObject.connect(self.theme_list_widget,
QtCore.SIGNAL(u'currentItemChanged(QListWidgetItem *, QListWidgetItem *)'), self.checkListState) QtCore.SIGNAL(u'currentItemChanged(QListWidgetItem *, QListWidgetItem *)'), self.check_list_state)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'theme_update_global'), self.changeGlobalFromTab) QtCore.SIGNAL(u'theme_update_global'), self.change_global_from_tab)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_updated'), self.configUpdated) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_updated'), self.config_updated)
# Variables # Variables
self.themeList = [] self.theme_list = []
self.path = AppLocation.get_section_data_path(self.settingsSection) self.path = AppLocation.get_section_data_path(self.settingsSection)
check_directory_exists(self.path) check_directory_exists(self.path)
self.thumbPath = os.path.join(self.path, u'thumbnails') self.thumbPath = os.path.join(self.path, u'thumbnails')
@ -140,27 +147,28 @@ class ThemeManager(QtGui.QWidget):
self.oldBackgroundImage = None self.oldBackgroundImage = None
self.badV1NameChars = re.compile(r'[%+\[\]]') self.badV1NameChars = re.compile(r'[%+\[\]]')
# Last little bits of setting up # Last little bits of setting up
self.configUpdated() self.config_updated()
def firstTime(self): def first_time(self):
""" """
Import new themes downloaded by the first time wizard Import new themes downloaded by the first time wizard
""" """
Receiver.send_message(u'cursor_busy') self.application.set_busy_cursor()
files = SettingsManager.get_files(self.settingsSection, u'.otz') files = SettingsManager.get_files(self.settingsSection, u'.otz')
for file in files: for theme_file in files:
file = os.path.join(self.path, file) theme_file = os.path.join(self.path, theme_file)
self.unzipTheme(file, self.path) self.unzipTheme(theme_file, self.path)
delete_file(file) delete_file(theme_file)
Receiver.send_message(u'cursor_normal') self.application.set_normal_cursor()
def configUpdated(self):
def config_updated(self):
""" """
Triggered when Config dialog is updated. Triggered when Config dialog is updated.
""" """
self.global_theme = Settings().value(self.settingsSection + u'/global theme', u'') self.global_theme = Settings().value(self.settingsSection + u'/global theme')
def checkListState(self, item): def check_list_state(self, item):
""" """
If Default theme selected remove delete button. If Default theme selected remove delete button.
""" """
@ -174,41 +182,41 @@ class ThemeManager(QtGui.QWidget):
else: else:
self.deleteToolbarAction.setVisible(False) self.deleteToolbarAction.setVisible(False)
def contextMenu(self, point): def context_menu(self, point):
""" """
Build the Right Click Context menu and set state depending on Build the Right Click Context menu and set state depending on
the type of theme. the type of theme.
""" """
item = self.themeListWidget.itemAt(point) item = self.theme_list_widget.itemAt(point)
if item is None: if item is None:
return return
real_theme_name = item.data(QtCore.Qt.UserRole) real_theme_name = item.data(QtCore.Qt.UserRole)
theme_name = unicode(item.text()) theme_name = unicode(item.text())
visible = real_theme_name == theme_name visible = real_theme_name == theme_name
self.deleteAction.setVisible(visible) self.delete_action.setVisible(visible)
self.renameAction.setVisible(visible) self.rename_action.setVisible(visible)
self.globalAction.setVisible(visible) self.global_action.setVisible(visible)
self.menu.exec_(self.themeListWidget.mapToGlobal(point)) self.menu.exec_(self.theme_list_widget.mapToGlobal(point))
def changeGlobalFromTab(self, theme_name): def change_global_from_tab(self, theme_name):
""" """
Change the global theme when it is changed through the Themes settings Change the global theme when it is changed through the Themes settings
tab tab
""" """
log.debug(u'changeGlobalFromTab %s', theme_name) log.debug(u'change_global_from_tab %s', theme_name)
for count in range (0, self.themeListWidget.count()): for count in range(0, self.theme_list_widget.count()):
# reset the old name # reset the old name
item = self.themeListWidget.item(count) item = self.theme_list_widget.item(count)
old_name = item.text() old_name = item.text()
new_name = item.data(QtCore.Qt.UserRole) new_name = item.data(QtCore.Qt.UserRole)
if old_name != new_name: if old_name != new_name:
self.themeListWidget.item(count).setText(new_name) self.theme_list_widget.item(count).setText(new_name)
# Set the new name # Set the new name
if theme_name == new_name: if theme_name == new_name:
name = translate('OpenLP.ThemeManager', '%s (default)') % new_name name = translate('OpenLP.ThemeManager', '%s (default)') % new_name
self.themeListWidget.item(count).setText(name) self.theme_list_widget.item(count).setText(name)
self.deleteToolbarAction.setVisible( self.deleteToolbarAction.setVisible(
item not in self.themeListWidget.selectedItems()) item not in self.theme_list_widget.selectedItems())
def changeGlobalFromScreen(self, index=-1): def changeGlobalFromScreen(self, index=-1):
""" """
@ -216,21 +224,21 @@ class ThemeManager(QtGui.QWidget):
Theme Manager list Theme Manager list
""" """
log.debug(u'changeGlobalFromScreen %s', index) log.debug(u'changeGlobalFromScreen %s', index)
selected_row = self.themeListWidget.currentRow() selected_row = self.theme_list_widget.currentRow()
for count in range (0, self.themeListWidget.count()): for count in range(0, self.theme_list_widget.count()):
item = self.themeListWidget.item(count) item = self.theme_list_widget.item(count)
old_name = item.text() old_name = item.text()
# reset the old name # reset the old name
if old_name != item.data(QtCore.Qt.UserRole): if old_name != item.data(QtCore.Qt.UserRole):
self.themeListWidget.item(count).setText(item.data(QtCore.Qt.UserRole)) self.theme_list_widget.item(count).setText(item.data(QtCore.Qt.UserRole))
# Set the new name # Set the new name
if count == selected_row: if count == selected_row:
self.global_theme = self.themeListWidget.item(count).text() self.global_theme = self.theme_list_widget.item(count).text()
name = translate('OpenLP.ThemeManager', '%s (default)') % self.global_theme name = translate('OpenLP.ThemeManager', '%s (default)') % self.global_theme
self.themeListWidget.item(count).setText(name) self.theme_list_widget.item(count).setText(name)
Settings().setValue(self.settingsSection + u'/global theme', self.global_theme) Settings().setValue(self.settingsSection + u'/global theme', self.global_theme)
Receiver.send_message(u'theme_update_global', self.global_theme) Receiver.send_message(u'theme_update_global', self.global_theme)
self._pushThemes() self._push_themes()
def onAddTheme(self): def onAddTheme(self):
""" """
@ -241,45 +249,44 @@ class ThemeManager(QtGui.QWidget):
theme.set_default_header_footer() theme.set_default_header_footer()
self.themeForm.theme = theme self.themeForm.theme = theme
self.themeForm.exec_() self.themeForm.exec_()
self.loadThemes() self.load_themes()
def onRenameTheme(self): def on_rename_theme(self):
""" """
Renames an existing theme to a new name Renames an existing theme to a new name
""" """
if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to rename.'), if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to rename.'),
translate('OpenLP.ThemeManager', 'Rename Confirmation'), translate('OpenLP.ThemeManager', 'Rename Confirmation'),
translate('OpenLP.ThemeManager', 'Rename %s theme?'), False, False): translate('OpenLP.ThemeManager', 'Rename %s theme?'), False, False):
item = self.themeListWidget.currentItem() item = self.theme_list_widget.currentItem()
old_theme_name = item.data(QtCore.Qt.UserRole) old_theme_name = item.data(QtCore.Qt.UserRole)
self.fileRenameForm.fileNameEdit.setText(old_theme_name) self.fileRenameForm.fileNameEdit.setText(old_theme_name)
if self.fileRenameForm.exec_(): if self.fileRenameForm.exec_():
new_theme_name = self.fileRenameForm.fileNameEdit.text() new_theme_name = self.fileRenameForm.fileNameEdit.text()
if old_theme_name == new_theme_name: if old_theme_name == new_theme_name:
return return
if self.checkIfThemeExists(new_theme_name): if self.check_if_theme_exists(new_theme_name):
old_theme_data = self.getThemeData(old_theme_name) old_theme_data = self.get_theme_data(old_theme_name)
self.cloneThemeData(old_theme_data, new_theme_name) self.cloneThemeData(old_theme_data, new_theme_name)
self.deleteTheme(old_theme_name) self.delete_theme(old_theme_name)
for plugin in self.mainwindow.pluginManager.plugins: for plugin in self.plugin_manager.plugins:
if plugin.usesTheme(old_theme_name): if plugin.usesTheme(old_theme_name):
plugin.renameTheme(old_theme_name, new_theme_name) plugin.renameTheme(old_theme_name, new_theme_name)
self.mainwindow.renderer.update_theme( self.renderer.update_theme(new_theme_name, old_theme_name)
new_theme_name, old_theme_name) self.load_themes()
self.loadThemes()
def onCopyTheme(self): def on_copy_theme(self):
""" """
Copies an existing theme to a new name Copies an existing theme to a new name
""" """
item = self.themeListWidget.currentItem() item = self.theme_list_widget.currentItem()
old_theme_name = item.data(QtCore.Qt.UserRole) old_theme_name = item.data(QtCore.Qt.UserRole)
self.fileRenameForm.fileNameEdit.setText(translate('OpenLP.ThemeManager', self.fileRenameForm.fileNameEdit.setText(translate('OpenLP.ThemeManager',
'Copy of %s', 'Copy of <theme name>') % old_theme_name) 'Copy of %s', 'Copy of <theme name>') % old_theme_name)
if self.fileRenameForm.exec_(True): if self.fileRenameForm.exec_(True):
new_theme_name = self.fileRenameForm.fileNameEdit.text() new_theme_name = self.fileRenameForm.fileNameEdit.text()
if self.checkIfThemeExists(new_theme_name): if self.check_if_theme_exists(new_theme_name):
theme_data = self.getThemeData(old_theme_name) theme_data = self.get_theme_data(old_theme_name)
self.cloneThemeData(theme_data, new_theme_name) self.cloneThemeData(theme_data, new_theme_name)
def cloneThemeData(self, theme_data, new_theme_name): def cloneThemeData(self, theme_data, new_theme_name):
@ -295,100 +302,100 @@ class ThemeManager(QtGui.QWidget):
save_from = theme_data.background_filename save_from = theme_data.background_filename
theme_data.theme_name = new_theme_name theme_data.theme_name = new_theme_name
theme_data.extend_image_filename(self.path) theme_data.extend_image_filename(self.path)
self.saveTheme(theme_data, save_from, save_to) self.save_theme(theme_data, save_from, save_to)
self.loadThemes() self.load_themes()
def onEditTheme(self): def on_edit_theme(self):
""" """
Loads the settings for the theme that is to be edited and launches the Loads the settings for the theme that is to be edited and launches the
theme editing form so the user can make their changes. theme editing form so the user can make their changes.
""" """
if check_item_selected(self.themeListWidget, if check_item_selected(self.theme_list_widget,
translate('OpenLP.ThemeManager', 'You must select a theme to edit.')): translate('OpenLP.ThemeManager', 'You must select a theme to edit.')):
item = self.themeListWidget.currentItem() item = self.theme_list_widget.currentItem()
theme = self.getThemeData(item.data(QtCore.Qt.UserRole)) theme = self.get_theme_data(item.data(QtCore.Qt.UserRole))
if theme.background_type == u'image': if theme.background_type == u'image':
self.oldBackgroundImage = theme.background_filename self.oldBackgroundImage = theme.background_filename
self.themeForm.theme = theme self.themeForm.theme = theme
self.themeForm.exec_(True) self.themeForm.exec_(True)
self.oldBackgroundImage = None self.oldBackgroundImage = None
self.mainwindow.renderer.update_theme(theme.theme_name) self.renderer.update_theme(theme.theme_name)
self.loadThemes() self.load_themes()
def onDeleteTheme(self): def on_delete_theme(self):
""" """
Delete a theme Delete a theme
""" """
if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to delete.'), if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to delete.'),
translate('OpenLP.ThemeManager', 'Delete Confirmation'), translate('OpenLP.ThemeManager', 'Delete Confirmation'),
translate('OpenLP.ThemeManager', 'Delete %s theme?')): translate('OpenLP.ThemeManager', 'Delete %s theme?')):
item = self.themeListWidget.currentItem() item = self.theme_list_widget.currentItem()
theme = item.text() theme = item.text()
row = self.themeListWidget.row(item) row = self.theme_list_widget.row(item)
self.themeListWidget.takeItem(row) self.theme_list_widget.takeItem(row)
self.deleteTheme(theme) self.delete_theme(theme)
self.mainwindow.renderer.update_theme(theme, only_delete=True) self.renderer.update_theme(theme, only_delete=True)
# As we do not reload the themes, push out the change. Reload the # As we do not reload the themes, push out the change. Reload the
# list as the internal lists and events need to be triggered. # list as the internal lists and events need to be triggered.
self._pushThemes() self._push_themes()
def deleteTheme(self, theme): def delete_theme(self, theme):
""" """
Delete a theme. Delete a theme.
``theme`` ``theme``
The theme to delete. The theme to delete.
""" """
self.themeList.remove(theme) self.theme_list.remove(theme)
thumb = u'%s.png' % theme thumb = u'%s.png' % theme
delete_file(os.path.join(self.path, thumb)) delete_file(os.path.join(self.path, thumb))
delete_file(os.path.join(self.thumbPath, thumb)) delete_file(os.path.join(self.thumbPath, thumb))
try: try:
encoding = get_filesystem_encoding() encoding = get_filesystem_encoding()
shutil.rmtree(os.path.join(self.path, theme).encode(encoding)) shutil.rmtree(os.path.join(self.path, theme).encode(encoding))
except OSError: except OSError, shutil.Error:
log.exception(u'Error deleting theme %s', theme) log.exception(u'Error deleting theme %s', theme)
def onExportTheme(self): def on_export_theme(self):
""" """
Export the theme in a zip file Export the theme in a zip file
""" """
item = self.themeListWidget.currentItem() item = self.theme_list_widget.currentItem()
if item is None: if item is None:
critical_error_message_box(message=translate('OpenLP.ThemeManager', 'You have not selected a theme.')) critical_error_message_box(message=translate('OpenLP.ThemeManager', 'You have not selected a theme.'))
return return
theme = item.data(QtCore.Qt.UserRole) theme = item.data(QtCore.Qt.UserRole)
path = QtGui.QFileDialog.getExistingDirectory(self, path = QtGui.QFileDialog.getExistingDirectory(self,
translate('OpenLP.ThemeManager', 'Save Theme - (%s)') % theme, translate('OpenLP.ThemeManager', 'Save Theme - (%s)') % theme,
SettingsManager.get_last_dir(self.settingsSection, 1)) Settings().value(self.settingsSection + u'/last directory export'))
path = unicode(path) self.application.set_busy_cursor()
Receiver.send_message(u'cursor_busy')
if path: if path:
SettingsManager.set_last_dir(self.settingsSection, path, 1) Settings().setValue(self.settingsSection + u'/last directory export', path)
theme_path = os.path.join(path, theme + u'.otz') theme_path = os.path.join(path, theme + u'.otz')
zip = None theme_zip = None
try: try:
zip = zipfile.ZipFile(theme_path, u'w') theme_zip = zipfile.ZipFile(theme_path, u'w')
source = os.path.join(self.path, theme) source = os.path.join(self.path, theme)
for files in os.walk(source): for files in os.walk(source):
for name in files[2]: for name in files[2]:
zip.write( theme_zip.write(
os.path.join(source, name).encode(u'utf-8'), os.path.join(source, name).encode(u'utf-8'),
os.path.join(theme, name).encode(u'utf-8')) os.path.join(theme, name).encode(u'utf-8')
)
QtGui.QMessageBox.information(self, QtGui.QMessageBox.information(self,
translate('OpenLP.ThemeManager', 'Theme Exported'), translate('OpenLP.ThemeManager', 'Theme Exported'),
translate('OpenLP.ThemeManager', 'Your theme has been successfully exported.')) translate('OpenLP.ThemeManager', 'Your theme has been successfully exported.'))
except (IOError, OSError): except (IOError, OSError):
log.exception(u'Export Theme Failed') log.exception(u'Export Theme Failed')
critical_error_message_box( critical_error_message_box(translate('OpenLP.ThemeManager', 'Theme Export Failed'),
translate('OpenLP.ThemeManager', 'Theme Export Failed'),
translate('OpenLP.ThemeManager', 'Your theme could not be exported due to an error.')) translate('OpenLP.ThemeManager', 'Your theme could not be exported due to an error.'))
finally: finally:
if zip: if theme_zip:
zip.close() theme_zip.close()
Receiver.send_message(u'cursor_normal') self.application.set_normal_cursor()
def onImportTheme(self):
def on_import_theme(self):
""" """
Opens a file dialog to select the theme file(s) to import before Opens a file dialog to select the theme file(s) to import before
attempting to extract OpenLP themes from those files. This process attempting to extract OpenLP themes from those files. This process
@ -396,42 +403,41 @@ class ThemeManager(QtGui.QWidget):
""" """
files = QtGui.QFileDialog.getOpenFileNames(self, files = QtGui.QFileDialog.getOpenFileNames(self,
translate('OpenLP.ThemeManager', 'Select Theme Import File'), translate('OpenLP.ThemeManager', 'Select Theme Import File'),
SettingsManager.get_last_dir(self.settingsSection), Settings().value(self.settingsSection + u'/last directory import'),
translate('OpenLP.ThemeManager', 'OpenLP Themes (*.theme *.otz)')) translate('OpenLP.ThemeManager', 'OpenLP Themes (*.theme *.otz)'))
log.info(u'New Themes %s', unicode(files)) log.info(u'New Themes %s', unicode(files))
if not files: if not files:
return return
Receiver.send_message(u'cursor_busy') self.application.set_busy_cursor()
for file in files: for file_name in files:
SettingsManager.set_last_dir(self.settingsSection, unicode(file)) Settings().setValue(self.settingsSection + u'/last directory import', unicode(file_name))
self.unzipTheme(file, self.path) self.unzip_theme(file_name, self.path)
self.loadThemes() self.load_themes()
Receiver.send_message(u'cursor_normal') self.application.set_normal_cursor()
def loadThemes(self, firstTime=False): def load_themes(self, first_time=False):
""" """
Loads the theme lists and triggers updates accross the whole system Loads the theme lists and triggers updates accross the whole system
using direct calls or core functions and events for the plugins. using direct calls or core functions and events for the plugins.
The plugins will call back in to get the real list if they want it. The plugins will call back in to get the real list if they want it.
""" """
log.debug(u'Load themes from dir') log.debug(u'Load themes from dir')
self.themeList = [] self.theme_list = []
self.themeListWidget.clear() self.theme_list_widget.clear()
files = SettingsManager.get_files(self.settingsSection, u'.png') files = SettingsManager.get_files(self.settingsSection, u'.png')
if firstTime: if first_time:
self.firstTime() self.first_time()
files = SettingsManager.get_files(self.settingsSection, u'.png') files = SettingsManager.get_files(self.settingsSection, u'.png')
# No themes have been found so create one # No themes have been found so create one
if not files: if not files:
theme = ThemeXML() theme = ThemeXML()
theme.theme_name = UiStrings().Default theme.theme_name = UiStrings().Default
self._writeTheme(theme, None, None) self._write_theme(theme, None, None)
Settings().setValue(self.settingsSection + u'/global theme', theme.theme_name) Settings().setValue(self.settingsSection + u'/global theme', theme.theme_name)
self.configUpdated() self.config_updated()
files = SettingsManager.get_files(self.settingsSection, u'.png') files = SettingsManager.get_files(self.settingsSection, u'.png')
# Sort the themes by its name considering language specific # Sort the themes by its name considering language specific
files.sort(key=lambda file_name: unicode(file_name), files.sort(key=lambda file_name: unicode(file_name), cmp=locale_compare)
cmp=locale_compare)
# now process the file list of png files # now process the file list of png files
for name in files: for name in files:
# check to see file is in theme root directory # check to see file is in theme root directory
@ -450,23 +456,23 @@ class ThemeManager(QtGui.QWidget):
icon = create_thumb(theme, thumb) icon = create_thumb(theme, thumb)
item_name.setIcon(icon) item_name.setIcon(icon)
item_name.setData(QtCore.Qt.UserRole, text_name) item_name.setData(QtCore.Qt.UserRole, text_name)
self.themeListWidget.addItem(item_name) self.theme_list_widget.addItem(item_name)
self.themeList.append(text_name) self.theme_list.append(text_name)
self._pushThemes() self._push_themes()
def _pushThemes(self): def _push_themes(self):
""" """
Notify listeners that the theme list has been updated Notify listeners that the theme list has been updated
""" """
Receiver.send_message(u'theme_update_list', self.getThemes()) Receiver.send_message(u'theme_update_list', self.get_themes())
def getThemes(self): def get_themes(self):
""" """
Return the list of loaded themes Return the list of loaded themes
""" """
return self.themeList return self.theme_list
def getThemeData(self, theme_name): def get_theme_data(self, theme_name):
""" """
Returns a theme object from an XML file Returns a theme object from an XML file
@ -474,25 +480,26 @@ class ThemeManager(QtGui.QWidget):
Name of the theme to load from file Name of the theme to load from file
""" """
log.debug(u'getthemedata for theme %s', theme_name) log.debug(u'getthemedata for theme %s', theme_name)
xml_file = os.path.join(self.path, unicode(theme_name), xml_file = os.path.join(self.path, unicode(theme_name), unicode(theme_name) + u'.xml')
unicode(theme_name) + u'.xml')
xml = get_text_file_string(xml_file) xml = get_text_file_string(xml_file)
if not xml: if not xml:
log.debug(u'No theme data - using default theme') log.debug(u'No theme data - using default theme')
return ThemeXML() return ThemeXML()
else: else:
return self._createThemeFromXml(xml, self.path) return self._create_theme_fom_Xml(xml, self.path)
def overWriteMessageBox(self, theme_name): def over_write_message_box(self, theme_name):
ret = QtGui.QMessageBox.question(self, """
translate('OpenLP.ThemeManager', 'Theme Already Exists'), Display a warning box to the user that a theme already exists
"""
ret = QtGui.QMessageBox.question(self, translate('OpenLP.ThemeManager', 'Theme Already Exists'),
translate('OpenLP.ThemeManager', translate('OpenLP.ThemeManager',
'Theme %s already exists. Do you want to replace it?').replace('%s', theme_name), 'Theme %s already exists. Do you want to replace it?').replace('%s', theme_name),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No), QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No),
QtGui.QMessageBox.No) QtGui.QMessageBox.No)
return ret == QtGui.QMessageBox.Yes return ret == QtGui.QMessageBox.Yes
def unzipTheme(self, file_name, dir): def unzip_theme(self, file_name, directory):
""" """
Unzip the theme, remove the preview file if stored Unzip the theme, remove the preview file if stored
Generate a new preview file. Check the XML theme version and upgrade if Generate a new preview file. Check the XML theme version and upgrade if
@ -500,32 +507,31 @@ class ThemeManager(QtGui.QWidget):
""" """
log.debug(u'Unzipping theme %s', file_name) log.debug(u'Unzipping theme %s', file_name)
file_name = unicode(file_name) file_name = unicode(file_name)
zip = None theme_zip = None
out_file = None out_file = None
file_xml = None file_xml = None
abort_import = True abort_import = True
try: try:
zip = zipfile.ZipFile(file_name) theme_zip = zipfile.ZipFile(file_name)
xml_file = filter(lambda name: xml_file = filter(lambda name: os.path.splitext(name)[1].lower() == u'.xml', theme_zip.namelist())
os.path.splitext(name)[1].lower() == u'.xml', zip.namelist())
if len(xml_file) != 1: if len(xml_file) != 1:
log.exception(u'Theme contains "%s" XML files' % len(xml_file)) log.exception(u'Theme contains "%s" XML files' % len(xml_file))
raise Exception(u'validation') raise Exception('validation')
xml_tree = ElementTree(element=XML(zip.read(xml_file[0]))).getroot() xml_tree = ElementTree(element=XML(theme_zip.read(xml_file[0]))).getroot()
v1_background = xml_tree.find(u'BackgroundType') v1_background = xml_tree.find(u'BackgroundType')
if v1_background is not None: if v1_background is not None:
theme_name, file_xml, out_file, abort_import = self.unzipVersion122( theme_name, file_xml, out_file, abort_import = self.unzip_version_122(
dir, zip, xml_file[0], xml_tree, v1_background, out_file) directory, theme_zip, xml_file[0], xml_tree, v1_background, out_file)
else: else:
theme_name = xml_tree.find(u'name').text.strip() theme_name = xml_tree.find(u'name').text.strip()
theme_folder = os.path.join(dir, theme_name) theme_folder = os.path.join(directory, theme_name)
theme_exists = os.path.exists(theme_folder) theme_exists = os.path.exists(theme_folder)
if theme_exists and not self.overWriteMessageBox(theme_name): if theme_exists and not self.over_write_message_box(theme_name):
abort_import = True abort_import = True
return return
else: else:
abort_import = False abort_import = False
for name in zip.namelist(): for name in theme_zip.namelist():
try: try:
uname = unicode(name, u'utf-8') uname = unicode(name, u'utf-8')
except UnicodeDecodeError: except UnicodeDecodeError:
@ -537,15 +543,15 @@ class ThemeManager(QtGui.QWidget):
if split_name[-1] == u'' or len(split_name) == 1: if split_name[-1] == u'' or len(split_name) == 1:
# is directory or preview file # is directory or preview file
continue continue
full_name = os.path.join(dir, uname) full_name = os.path.join(directory, uname)
check_directory_exists(os.path.dirname(full_name)) check_directory_exists(os.path.dirname(full_name))
if os.path.splitext(uname)[1].lower() == u'.xml': if os.path.splitext(uname)[1].lower() == u'.xml':
file_xml = unicode(zip.read(name), u'utf-8') file_xml = unicode(theme_zip.read(name), u'utf-8')
out_file = open(full_name, u'w') out_file = open(full_name, u'w')
out_file.write(file_xml.encode(u'utf-8')) out_file.write(file_xml.encode(u'utf-8'))
else: else:
out_file = open(full_name, u'wb') out_file = open(full_name, u'wb')
out_file.write(zip.read(name)) out_file.write(theme_zip.read(name))
out_file.close() out_file.close()
except (IOError, zipfile.BadZipfile): except (IOError, zipfile.BadZipfile):
log.exception(u'Importing theme from zip failed %s' % file_name) log.exception(u'Importing theme from zip failed %s' % file_name)
@ -558,39 +564,38 @@ class ThemeManager(QtGui.QWidget):
raise raise
finally: finally:
# Close the files, to be able to continue creating the theme. # Close the files, to be able to continue creating the theme.
if zip: if theme_zip:
zip.close() theme_zip.close()
if out_file: if out_file:
out_file.close() out_file.close()
if not abort_import: if not abort_import:
# As all files are closed, we can create the Theme. # As all files are closed, we can create the Theme.
if file_xml: if file_xml:
theme = self._createThemeFromXml(file_xml, self.path) theme = self._create_theme_fom_Xml(file_xml, self.path)
self.generateAndSaveImage(dir, theme_name, theme) self.generate_and_save_image(directory, theme_name, theme)
# Only show the error message, when IOError was not raised (in # Only show the error message, when IOError was not raised (in
# this case the error message has already been shown). # this case the error message has already been shown).
elif zip is not None: elif theme_zip is not None:
critical_error_message_box( critical_error_message_box(
translate('OpenLP.ThemeManager', 'Validation Error'), translate('OpenLP.ThemeManager', 'Validation Error'),
translate('OpenLP.ThemeManager', 'File is not a valid theme.')) translate('OpenLP.ThemeManager', 'File is not a valid theme.'))
log.exception(u'Theme file does not contain XML data %s' % file_name) log.exception(u'Theme file does not contain XML data %s' % file_name)
def unzipVersion122(self, dir, zip, xml_file, xml_tree, background, def unzip_version_122(self, dir_name, zip_file, xml_file, xml_tree, background, out_file):
out_file):
""" """
Unzip openlp.org 1.2x theme file and upgrade the theme xml. When calling Unzip openlp.org 1.2x theme file and upgrade the theme xml. When calling
this method, please keep in mind, that some parameters are redundant. this method, please keep in mind, that some parameters are redundant.
""" """
theme_name = xml_tree.find(u'Name').text.strip() theme_name = xml_tree.find(u'Name').text.strip()
theme_name = self.badV1NameChars.sub(u'', theme_name) theme_name = self.badV1NameChars.sub(u'', theme_name)
theme_folder = os.path.join(dir, theme_name) theme_folder = os.path.join(dir_name, theme_name)
theme_exists = os.path.exists(theme_folder) theme_exists = os.path.exists(theme_folder)
if theme_exists and not self.overWriteMessageBox(theme_name): if theme_exists and not self.over_write_message_box(theme_name):
return '', '', '', True return '', '', '', True
themedir = os.path.join(dir, theme_name) themedir = os.path.join(dir_name, theme_name)
check_directory_exists(themedir) check_directory_exists(themedir)
file_xml = unicode(zip.read(xml_file), u'utf-8') file_xml = unicode(zip_file.read(xml_file), u'utf-8')
file_xml = self._migrateVersion122(file_xml) file_xml = self._migrate_version_122(file_xml)
out_file = open(os.path.join(themedir, theme_name + u'.xml'), u'w') out_file = open(os.path.join(themedir, theme_name + u'.xml'), u'w')
out_file.write(file_xml.encode(u'utf-8')) out_file.write(file_xml.encode(u'utf-8'))
out_file.close() out_file.close()
@ -598,18 +603,17 @@ class ThemeManager(QtGui.QWidget):
image_name = xml_tree.find(u'BackgroundParameter1').text.strip() image_name = xml_tree.find(u'BackgroundParameter1').text.strip()
# image file has same extension and is in subfolder # image file has same extension and is in subfolder
image_file = filter(lambda name: os.path.splitext(name)[1].lower() image_file = filter(lambda name: os.path.splitext(name)[1].lower()
== os.path.splitext(image_name)[1].lower() and name.find(r'/'), == os.path.splitext(image_name)[1].lower() and name.find(r'/'), zip_file.namelist())
zip.namelist())
if len(image_file) >= 1: if len(image_file) >= 1:
out_file = open(os.path.join(themedir, image_name), u'wb') out_file = open(os.path.join(themedir, image_name), u'wb')
out_file.write(zip.read(image_file[0])) out_file.write(zip_file.read(image_file[0]))
out_file.close() out_file.close()
else: else:
log.exception(u'Theme file does not contain image file "%s"' % image_name.decode(u'utf-8', u'replace')) log.exception(u'Theme file does not contain image file "%s"' % image_name.decode(u'utf-8', u'replace'))
raise Exception(u'validation') raise Exception(u'validation')
return theme_name, file_xml, out_file, False return theme_name, file_xml, out_file, False
def checkIfThemeExists(self, theme_name): def check_if_theme_exists(self, theme_name):
""" """
Check if theme already exists and displays error message Check if theme already exists and displays error message
@ -624,25 +628,25 @@ class ThemeManager(QtGui.QWidget):
return False return False
return True return True
def saveTheme(self, theme, image_from, image_to): def save_theme(self, theme, image_from, image_to):
""" """
Called by thememaintenance Dialog to save the theme Called by thememaintenance Dialog to save the theme
and to trigger the reload of the theme list and to trigger the reload of the theme list
""" """
self._writeTheme(theme, image_from, image_to) self._write_theme(theme, image_from, image_to)
if theme.background_type == BackgroundType.to_string(BackgroundType.Image): if theme.background_type == BackgroundType.to_string(BackgroundType.Image):
self.mainwindow.imageManager.updateImageBorder(theme.background_filename, self.image_manager.update_image_border(theme.background_filename,
ImageSource.Theme, QtGui.QColor(theme.background_border_color)) ImageSource.Theme, QtGui.QColor(theme.background_border_color))
self.mainwindow.imageManager.processUpdates() self.image_manager.process_updates()
def _writeTheme(self, theme, image_from, image_to): def _write_theme(self, theme, image_from, image_to):
""" """
Writes the theme to the disk and handles the background image if Writes the theme to the disk and handles the background image if
necessary necessary
""" """
name = theme.theme_name name = theme.theme_name
theme_pretty_xml = theme.extract_formatted_xml() theme_pretty_xml = theme.extract_formatted_xml()
log.debug(u'saveTheme %s %s', name, theme_pretty_xml.decode(u'utf-8')) log.debug(u'save_theme %s %s', name, theme_pretty_xml.decode(u'utf-8'))
theme_dir = os.path.join(self.path, name) theme_dir = os.path.join(self.path, name)
check_directory_exists(theme_dir) check_directory_exists(theme_dir)
theme_file = os.path.join(theme_dir, name + u'.xml') theme_file = os.path.join(theme_dir, name + u'.xml')
@ -661,13 +665,16 @@ class ThemeManager(QtGui.QWidget):
try: try:
encoding = get_filesystem_encoding() encoding = get_filesystem_encoding()
shutil.copyfile(unicode(image_from).encode(encoding), unicode(image_to).encode(encoding)) shutil.copyfile(unicode(image_from).encode(encoding), unicode(image_to).encode(encoding))
except IOError: except IOError, shutil.Error:
log.exception(u'Failed to save theme image') log.exception(u'Failed to save theme image')
self.generateAndSaveImage(self.path, name, theme) self.generate_and_save_image(self.path, name, theme)
def generateAndSaveImage(self, dir, name, theme): def generate_and_save_image(self, directory, name, theme):
log.debug(u'generateAndSaveImage %s %s', dir, name) """
frame = self.generateImage(theme) Generate and save a preview image
"""
log.debug(u'generate_and_save_image %s %s', directory, name)
frame = self.generate_image(theme)
sample_path_name = os.path.join(self.path, name + u'.png') sample_path_name = os.path.join(self.path, name + u'.png')
if os.path.exists(sample_path_name): if os.path.exists(sample_path_name):
os.unlink(sample_path_name) os.unlink(sample_path_name)
@ -676,18 +683,18 @@ class ThemeManager(QtGui.QWidget):
create_thumb(sample_path_name, thumb, False) create_thumb(sample_path_name, thumb, False)
log.debug(u'Theme image written to %s', sample_path_name) log.debug(u'Theme image written to %s', sample_path_name)
def updatePreviewImages(self): def update_preview_images(self):
""" """
Called to update the themes' preview images. Called to update the themes' preview images.
""" """
self.mainwindow.displayProgressBar(len(self.themeList)) self.main_window.displayProgressBar(len(self.theme_list))
for theme in self.themeList: for theme in self.theme_list:
self.mainwindow.incrementProgressBar() self.main_window.incrementProgressBar()
self.generateAndSaveImage(self.path, theme, self.getThemeData(theme)) self.generate_and_save_image(self.path, theme, self.get_theme_data(theme))
self.mainwindow.finishedProgressBar() self.main_window.finishedProgressBar()
self.loadThemes() self.load_themes()
def generateImage(self, theme_data, forcePage=False): def generate_image(self, theme_data, forcePage=False):
""" """
Call the renderer to build a Sample Image Call the renderer to build a Sample Image
@ -697,21 +704,21 @@ class ThemeManager(QtGui.QWidget):
``forcePage`` ``forcePage``
Flag to tell message lines per page need to be generated. Flag to tell message lines per page need to be generated.
""" """
log.debug(u'generateImage \n%s ', theme_data) log.debug(u'generate_image \n%s ', theme_data)
return self.mainwindow.renderer.generate_preview(theme_data, forcePage) return self.renderer.generate_preview(theme_data, forcePage)
def getPreviewImage(self, theme): def get_preview_image(self, theme):
""" """
Return an image representing the look of the theme Return an image representing the look of the theme
``theme`` ``theme``
The theme to return the image for The theme to return the image for
""" """
log.debug(u'getPreviewImage %s ', theme) log.debug(u'get_preview_image %s ', theme)
image = os.path.join(self.path, theme + u'.png') image = os.path.join(self.path, theme + u'.png')
return image return image
def _createThemeFromXml(self, theme_xml, path): def _create_theme_fom_Xml(self, theme_xml, path):
""" """
Return a theme object using information parsed from XML Return a theme object using information parsed from XML
@ -723,16 +730,14 @@ class ThemeManager(QtGui.QWidget):
theme.extend_image_filename(path) theme.extend_image_filename(path)
return theme return theme
def _validate_theme_action(self, select_text, confirm_title, confirm_text, def _validate_theme_action(self, select_text, confirm_title, confirm_text, testPlugin=True, confirm=True):
testPlugin=True, confirm=True):
""" """
Check to see if theme has been selected and the destructive action Check to see if theme has been selected and the destructive action
is allowed. is allowed.
""" """
self.global_theme = Settings().value( self.global_theme = Settings().value(self.settingsSection + u'/global theme')
self.settingsSection + u'/global theme', u'') if check_item_selected(self.theme_list_widget, select_text):
if check_item_selected(self.themeListWidget, select_text): item = self.theme_list_widget.currentItem()
item = self.themeListWidget.currentItem()
theme = item.text() theme = item.text()
# confirm deletion # confirm deletion
if confirm: if confirm:
@ -748,7 +753,7 @@ class ThemeManager(QtGui.QWidget):
return False return False
# check for use in the system else where. # check for use in the system else where.
if testPlugin: if testPlugin:
for plugin in self.mainwindow.pluginManager.plugins: for plugin in self.plugin_manager.plugins:
if plugin.usesTheme(theme): if plugin.usesTheme(theme):
critical_error_message_box(translate('OpenLP.ThemeManager', 'Validation Error'), critical_error_message_box(translate('OpenLP.ThemeManager', 'Validation Error'),
translate('OpenLP.ThemeManager', 'Theme %s is used in the %s plugin.') % translate('OpenLP.ThemeManager', 'Theme %s is used in the %s plugin.') %
@ -757,7 +762,7 @@ class ThemeManager(QtGui.QWidget):
return True return True
return False return False
def _migrateVersion122(self, xml_data): def _migrate_version_122(self, xml_data):
""" """
Convert the xml data from version 1 format to the current format. Convert the xml data from version 1 format to the current format.
@ -806,3 +811,52 @@ class ThemeManager(QtGui.QWidget):
new_theme.display_vertical_align = vAlignCorrection new_theme.display_vertical_align = vAlignCorrection
return new_theme.extract_xml() return new_theme.extract_xml()
def _get_renderer(self):
"""
Adds the Renderer to the class dynamically
"""
if not hasattr(self, u'_renderer'):
self._renderer = Registry().get(u'renderer')
return self._renderer
renderer = property(_get_renderer)
def _get_image_manager(self):
"""
Adds the image manager to the class dynamically
"""
if not hasattr(self, u'_image_manager'):
self._image_manager = Registry().get(u'image_manager')
return self._image_manager
image_manager = property(_get_image_manager)
def _get_plugin_manager(self):
"""
Adds the Renderer to the class dynamically
"""
if not hasattr(self, u'_plugin_manager'):
self._plugin_manager = Registry().get(u'plugin_manager')
return self._plugin_manager
plugin_manager = property(_get_plugin_manager)
def _get_main_window(self):
"""
Adds the main window to the class dynamically
"""
if not hasattr(self, u'_main_window'):
self._main_window = Registry().get(u'main_window')
return self._main_window
main_window = property(_get_main_window)
def _get_application(self):
"""
Adds the openlp to the class dynamically
"""
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application)

View File

@ -26,24 +26,32 @@
# 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 #
############################################################################### ###############################################################################
"""
The Themes configuration tab
"""
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, Settings, SettingsTab, translate from openlp.core.lib import Receiver, Settings, SettingsTab, UiStrings, translate
from openlp.core.lib.theme import ThemeLevel from openlp.core.lib.theme import ThemeLevel
from openlp.core.lib.ui import UiStrings, find_and_set_in_combo_box from openlp.core.lib.ui import find_and_set_in_combo_box
class ThemesTab(SettingsTab): class ThemesTab(SettingsTab):
""" """
ThemesTab is the theme settings tab in the settings dialog. ThemesTab is the theme settings tab in the settings dialog.
""" """
def __init__(self, parent, mainwindow): def __init__(self, parent):
self.mainwindow = mainwindow """
Constructor
"""
generalTranslated = translate('OpenLP.ThemesTab', 'Themes') generalTranslated = translate('OpenLP.ThemesTab', 'Themes')
SettingsTab.__init__(self, parent, u'Themes', generalTranslated) SettingsTab.__init__(self, parent, u'Themes', generalTranslated)
self.iconPath = u':/themes/theme_new.png' self.iconPath = u':/themes/theme_new.png'
def setupUi(self): def setupUi(self):
"""
Set up the UI
"""
self.setObjectName(u'ThemesTab') self.setObjectName(u'ThemesTab')
SettingsTab.setupUi(self) SettingsTab.setupUi(self)
self.GlobalGroupBox = QtGui.QGroupBox(self.leftColumn) self.GlobalGroupBox = QtGui.QGroupBox(self.leftColumn)
@ -99,6 +107,9 @@ class ThemesTab(SettingsTab):
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'theme_update_list'), self.updateThemeList) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'theme_update_list'), self.updateThemeList)
def retranslateUi(self): def retranslateUi(self):
"""
Translate the UI on the fly
"""
self.tabTitleVisible = UiStrings().Themes self.tabTitleVisible = UiStrings().Themes
self.GlobalGroupBox.setTitle(translate('OpenLP.ThemesTab', 'Global Theme')) self.GlobalGroupBox.setTitle(translate('OpenLP.ThemesTab', 'Global Theme'))
self.LevelGroupBox.setTitle(translate('OpenLP.ThemesTab', 'Theme Level')) self.LevelGroupBox.setTitle(translate('OpenLP.ThemesTab', 'Theme Level'))
@ -116,10 +127,13 @@ class ThemesTab(SettingsTab):
'any themes associated with either the service or the songs.')) 'any themes associated with either the service or the songs.'))
def load(self): def load(self):
"""
Load the theme settings into the tab
"""
settings = Settings() settings = Settings()
settings.beginGroup(self.settingsSection) settings.beginGroup(self.settingsSection)
self.theme_level = settings.value(u'theme level', ThemeLevel.Song) self.theme_level = settings.value(u'theme level')
self.global_theme = settings.value(u'global theme', u'') self.global_theme = settings.value(u'global theme')
settings.endGroup() settings.endGroup()
if self.theme_level == ThemeLevel.Global: if self.theme_level == ThemeLevel.Global:
self.GlobalLevelRadioButton.setChecked(True) self.GlobalLevelRadioButton.setChecked(True)
@ -129,30 +143,48 @@ class ThemesTab(SettingsTab):
self.SongLevelRadioButton.setChecked(True) self.SongLevelRadioButton.setChecked(True)
def save(self): def save(self):
"""
Save the settings
"""
settings = Settings() settings = Settings()
settings.beginGroup(self.settingsSection) settings.beginGroup(self.settingsSection)
settings.setValue(u'theme level', self.theme_level) settings.setValue(u'theme level', self.theme_level)
settings.setValue(u'global theme', self.global_theme) settings.setValue(u'global theme', self.global_theme)
settings.endGroup() settings.endGroup()
self.mainwindow.renderer.set_global_theme(self.global_theme) self.renderer.set_global_theme(self.global_theme)
self.mainwindow.renderer.set_theme_level(self.theme_level) self.renderer.set_theme_level(self.theme_level)
Receiver.send_message(u'theme_update_global', self.global_theme) Receiver.send_message(u'theme_update_global', self.global_theme)
def postSetUp(self): def postSetUp(self):
"""
After setting things up...
"""
Receiver.send_message(u'theme_update_global', self.global_theme) Receiver.send_message(u'theme_update_global', self.global_theme)
def onSongLevelButtonClicked(self): def onSongLevelButtonClicked(self):
"""
Set the theme level
"""
self.theme_level = ThemeLevel.Song self.theme_level = ThemeLevel.Song
def onServiceLevelButtonClicked(self): def onServiceLevelButtonClicked(self):
"""
Set the theme level
"""
self.theme_level = ThemeLevel.Service self.theme_level = ThemeLevel.Service
def onGlobalLevelButtonClicked(self): def onGlobalLevelButtonClicked(self):
"""
Set the theme level
"""
self.theme_level = ThemeLevel.Global self.theme_level = ThemeLevel.Global
def onDefaultComboBoxChanged(self, value): def onDefaultComboBoxChanged(self, value):
"""
Set the global default theme
"""
self.global_theme = self.DefaultComboBox.currentText() self.global_theme = self.DefaultComboBox.currentText()
self.mainwindow.renderer.set_global_theme(self.global_theme) self.renderer.set_global_theme(self.global_theme)
self.__previewGlobalTheme() self.__previewGlobalTheme()
def updateThemeList(self, theme_list): def updateThemeList(self, theme_list):
@ -165,12 +197,12 @@ class ThemesTab(SettingsTab):
[u'Bible Theme', u'Song Theme'] [u'Bible Theme', u'Song Theme']
""" """
# Reload as may have been triggered by the ThemeManager. # Reload as may have been triggered by the ThemeManager.
self.global_theme = Settings().value(self.settingsSection + u'/global theme', u'') self.global_theme = Settings().value(self.settingsSection + u'/global theme')
self.DefaultComboBox.clear() self.DefaultComboBox.clear()
self.DefaultComboBox.addItems(theme_list) self.DefaultComboBox.addItems(theme_list)
find_and_set_in_combo_box(self.DefaultComboBox, self.global_theme) find_and_set_in_combo_box(self.DefaultComboBox, self.global_theme)
self.mainwindow.renderer.set_global_theme(self.global_theme) self.renderer.set_global_theme(self.global_theme)
self.mainwindow.renderer.set_theme_level(self.theme_level) self.renderer.set_theme_level(self.theme_level)
if self.global_theme is not u'': if self.global_theme is not u'':
self.__previewGlobalTheme() self.__previewGlobalTheme()
@ -178,7 +210,7 @@ class ThemesTab(SettingsTab):
""" """
Utility method to update the global theme preview image. Utility method to update the global theme preview image.
""" """
image = self.mainwindow.themeManagerContents.getPreviewImage(self.global_theme) image = self.theme_manager.get_preview_image(self.global_theme)
preview = QtGui.QPixmap(unicode(image)) preview = QtGui.QPixmap(unicode(image))
if not preview.isNull(): if not preview.isNull():
preview = preview.scaled(300, 255, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation) preview = preview.scaled(300, 255, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)

View File

@ -26,15 +26,24 @@
# 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 #
############################################################################### ###############################################################################
"""
The Create/Edit theme wizard
"""
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate, build_icon from openlp.core.lib import UiStrings, build_icon, translate
from openlp.core.lib.theme import HorizontalType, BackgroundType, BackgroundGradientType from openlp.core.lib.theme import HorizontalType, BackgroundType, BackgroundGradientType
from openlp.core.lib.ui import UiStrings, add_welcome_page, create_valign_selection_widgets from openlp.core.lib.ui import add_welcome_page, create_valign_selection_widgets
class Ui_ThemeWizard(object): class Ui_ThemeWizard(object):
"""
The Create/Edit theme wizard
"""
def setupUi(self, themeWizard): def setupUi(self, themeWizard):
"""
Set up the UI
"""
themeWizard.setObjectName(u'OpenLP.ThemeWizard') themeWizard.setObjectName(u'OpenLP.ThemeWizard')
themeWizard.setModal(True) themeWizard.setModal(True)
themeWizard.setWizardStyle(QtGui.QWizard.ModernStyle) themeWizard.setWizardStyle(QtGui.QWizard.ModernStyle)
@ -372,7 +381,7 @@ class Ui_ThemeWizard(object):
QtCore.SLOT(u'setDisabled(bool)')) QtCore.SLOT(u'setDisabled(bool)'))
QtCore.QObject.connect(self.mainPositionCheckBox, QtCore.SIGNAL(u'toggled(bool)'), self.mainHeightSpinBox, QtCore.QObject.connect(self.mainPositionCheckBox, QtCore.SIGNAL(u'toggled(bool)'), self.mainHeightSpinBox,
QtCore.SLOT(u'setDisabled(bool)')) QtCore.SLOT(u'setDisabled(bool)'))
QtCore.QObject.connect(self.footerPositionCheckBox,QtCore.SIGNAL(u'toggled(bool)'), self.footerXSpinBox, QtCore.QObject.connect(self.footerPositionCheckBox, QtCore.SIGNAL(u'toggled(bool)'), self.footerXSpinBox,
QtCore.SLOT(u'setDisabled(bool)')) QtCore.SLOT(u'setDisabled(bool)'))
QtCore.QObject.connect(self.footerPositionCheckBox, QtCore.SIGNAL(u'toggled(bool)'), self.footerYSpinBox, QtCore.QObject.connect(self.footerPositionCheckBox, QtCore.SIGNAL(u'toggled(bool)'), self.footerYSpinBox,
QtCore.SLOT(u'setDisabled(bool)')) QtCore.SLOT(u'setDisabled(bool)'))
@ -382,8 +391,11 @@ class Ui_ThemeWizard(object):
QtCore.SLOT(u'setDisabled(bool)')) QtCore.SLOT(u'setDisabled(bool)'))
def retranslateUi(self, themeWizard): def retranslateUi(self, themeWizard):
"""
Translate the UI on the fly
"""
themeWizard.setWindowTitle(translate('OpenLP.ThemeWizard', 'Theme Wizard')) themeWizard.setWindowTitle(translate('OpenLP.ThemeWizard', 'Theme Wizard'))
self.titleLabel.setText(u'<span style="font-size:14pt; font-weight:600;">%s</span>' % \ self.titleLabel.setText(u'<span style="font-size:14pt; font-weight:600;">%s</span>' %
translate('OpenLP.ThemeWizard', 'Welcome to the Theme Wizard')) translate('OpenLP.ThemeWizard', 'Welcome to the Theme Wizard'))
self.informationLabel.setText( self.informationLabel.setText(
translate('OpenLP.ThemeWizard', 'This wizard will help you to ' translate('OpenLP.ThemeWizard', 'This wizard will help you to '

View File

@ -34,11 +34,12 @@ import os
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, Receiver, SettingsManager, translate from openlp.core.lib import Receiver, Registry, Settings, UiStrings, build_icon, translate
from openlp.core.lib.ui import UiStrings, add_welcome_page from openlp.core.lib.ui import add_welcome_page
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class WizardStrings(object): class WizardStrings(object):
""" """
Provide standard strings for wizards to use. Provide standard strings for wizards to use.
@ -80,6 +81,9 @@ class OpenLPWizard(QtGui.QWizard):
and feel. and feel.
""" """
def __init__(self, parent, plugin, name, image): def __init__(self, parent, plugin, name, image):
"""
Constructor
"""
QtGui.QWizard.__init__(self, parent) QtGui.QWizard.__init__(self, parent)
self.plugin = plugin self.plugin = plugin
self.setObjectName(name) self.setObjectName(name)
@ -215,7 +219,7 @@ class OpenLPWizard(QtGui.QWizard):
self.progressLabel.setText(status_text) self.progressLabel.setText(status_text)
if increment > 0: if increment > 0:
self.progressBar.setValue(self.progressBar.value() + increment) self.progressBar.setValue(self.progressBar.value() + increment)
Receiver.send_message(u'openlp_process_events') self.application.process_events()
def preWizard(self): def preWizard(self):
""" """
@ -233,9 +237,9 @@ class OpenLPWizard(QtGui.QWizard):
self.progressBar.setValue(self.progressBar.maximum()) self.progressBar.setValue(self.progressBar.maximum())
self.finishButton.setVisible(True) self.finishButton.setVisible(True)
self.cancelButton.setVisible(False) self.cancelButton.setVisible(False)
Receiver.send_message(u'openlp_process_events') self.application.process_events()
def getFileName(self, title, editbox, filters=u''): def getFileName(self, title, editbox, setting_name, filters=u''):
""" """
Opens a QFileDialog and saves the filename to the given editbox. Opens a QFileDialog and saves the filename to the given editbox.
@ -245,6 +249,9 @@ class OpenLPWizard(QtGui.QWizard):
``editbox`` ``editbox``
An editbox (QLineEdit). An editbox (QLineEdit).
``setting_name``
The place where to save the last opened directory.
``filters`` ``filters``
The file extension filters. It should contain the file description The file extension filters. It should contain the file description
as well as the file extension. For example:: as well as the file extension. For example::
@ -254,15 +261,13 @@ class OpenLPWizard(QtGui.QWizard):
if filters: if filters:
filters += u';;' filters += u';;'
filters += u'%s (*)' % UiStrings().AllFiles filters += u'%s (*)' % UiStrings().AllFiles
filename = unicode(QtGui.QFileDialog.getOpenFileName(self, title, filename = QtGui.QFileDialog.getOpenFileName(self, title,
os.path.dirname(SettingsManager.get_last_dir( os.path.dirname(Settings().value(self.plugin.settingsSection + u'/' + setting_name)), filters)
self.plugin.settingsSection, 1)), filters))
if filename: if filename:
editbox.setText(filename) editbox.setText(filename)
SettingsManager.set_last_dir(self.plugin.settingsSection, Settings().setValue(self.plugin.settingsSection + u'/' + setting_name, filename)
filename, 1)
def getFolder(self, title, editbox): def getFolder(self, title, editbox, setting_name):
""" """
Opens a QFileDialog and saves the selected folder to the given editbox. Opens a QFileDialog and saves the selected folder to the given editbox.
@ -271,10 +276,23 @@ class OpenLPWizard(QtGui.QWizard):
``editbox`` ``editbox``
An editbox (QLineEdit). An editbox (QLineEdit).
``setting_name``
The place where to save the last opened directory.
""" """
folder = unicode(QtGui.QFileDialog.getExistingDirectory(self, title, folder = QtGui.QFileDialog.getExistingDirectory(self, title,
os.path.dirname(SettingsManager.get_last_dir(self.plugin.settingsSection, 1)), Settings().value(self.plugin.settingsSection + u'/' + setting_name),
QtGui.QFileDialog.ShowDirsOnly)) QtGui.QFileDialog.ShowDirsOnly)
if folder: if folder:
editbox.setText(folder) editbox.setText(folder)
SettingsManager.set_last_dir(self.plugin.settingsSection, folder, 1) Settings().setValue(self.plugin.settingsSection + u'/' + setting_name, folder)
def _get_application(self):
"""
Adds the openlp to the class dynamically
"""
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application)

View File

@ -39,7 +39,7 @@ from subprocess import Popen, PIPE
import sys import sys
import urllib2 import urllib2
from openlp.core.lib import Settings from openlp.core.lib import Registry, Settings
from PyQt4 import QtGui, QtCore from PyQt4 import QtGui, QtCore
@ -61,14 +61,12 @@ UNO_CONNECTION_TYPE = u'pipe'
CONTROL_CHARS = re.compile(r'[\x00-\x1F\x7F-\x9F]', re.UNICODE) CONTROL_CHARS = re.compile(r'[\x00-\x1F\x7F-\x9F]', re.UNICODE)
INVALID_FILE_CHARS = re.compile(r'[\\/:\*\?"<>\|\+\[\]%]', re.UNICODE) INVALID_FILE_CHARS = re.compile(r'[\\/:\*\?"<>\|\+\[\]%]', re.UNICODE)
class VersionThread(QtCore.QThread): class VersionThread(QtCore.QThread):
""" """
A special Qt thread class to fetch the version of OpenLP from the website. A special Qt thread class to fetch the version of OpenLP from the website.
This is threaded so that it doesn't affect the loading time of OpenLP. This is threaded so that it doesn't affect the loading time of OpenLP.
""" """
def __init__(self, parent):
QtCore.QThread.__init__(self, parent)
def run(self): def run(self):
""" """
Run the thread. Run the thread.
@ -127,7 +125,7 @@ class AppLocation(object):
""" """
# Check if we have a different data location. # Check if we have a different data location.
if Settings().contains(u'advanced/data path'): if Settings().contains(u'advanced/data path'):
path = Settings().value(u'advanced/data path', u'') path = Settings().value(u'advanced/data path')
else: else:
path = AppLocation.get_directory(AppLocation.DataDir) path = AppLocation.get_directory(AppLocation.DataDir)
check_directory_exists(path) check_directory_exists(path)
@ -154,16 +152,14 @@ def _get_os_dir_path(dir_type):
return os.path.join(unicode(os.getenv(u'APPDATA'), encoding), u'openlp', u'data') return os.path.join(unicode(os.getenv(u'APPDATA'), encoding), u'openlp', u'data')
elif dir_type == AppLocation.LanguageDir: elif dir_type == AppLocation.LanguageDir:
return os.path.split(openlp.__file__)[0] return os.path.split(openlp.__file__)[0]
return os.path.join(unicode(os.getenv(u'APPDATA'), encoding), return os.path.join(unicode(os.getenv(u'APPDATA'), encoding), u'openlp')
u'openlp')
elif sys.platform == u'darwin': elif sys.platform == u'darwin':
if dir_type == AppLocation.DataDir: if dir_type == AppLocation.DataDir:
return os.path.join(unicode(os.getenv(u'HOME'), encoding), return os.path.join(unicode(os.getenv(u'HOME'), encoding),
u'Library', u'Application Support', u'openlp', u'Data') u'Library', u'Application Support', u'openlp', u'Data')
elif dir_type == AppLocation.LanguageDir: elif dir_type == AppLocation.LanguageDir:
return os.path.split(openlp.__file__)[0] return os.path.split(openlp.__file__)[0]
return os.path.join(unicode(os.getenv(u'HOME'), encoding), return os.path.join(unicode(os.getenv(u'HOME'), encoding), u'Library', u'Application Support', u'openlp')
u'Library', u'Application Support', u'openlp')
else: else:
if dir_type == AppLocation.LanguageDir: if dir_type == AppLocation.LanguageDir:
prefixes = [u'/usr/local', u'/usr'] prefixes = [u'/usr/local', u'/usr']
@ -277,20 +273,30 @@ def check_latest_version(current_version):
``current_version`` ``current_version``
The current version of OpenLP. The current version of OpenLP.
**Rules around versions and version files:**
* If a version number has a build (i.e. -bzr1234), then it is a nightly.
* If a version number's minor version is an odd number, it is a development release.
* If a version number's minor version is an even number, it is a stable release.
""" """
version_string = current_version[u'full'] version_string = current_version[u'full']
# set to prod in the distribution config file. # set to prod in the distribution config file.
settings = Settings() settings = Settings()
settings.beginGroup(u'general') settings.beginGroup(u'general')
last_test = settings.value(u'last version test', datetime.now().date()) last_test = settings.value(u'last version test')
this_test = datetime.now().date() this_test = datetime.now().date()
settings.setValue(u'last version test', this_test) settings.setValue(u'last version test', this_test)
settings.endGroup() settings.endGroup()
if last_test != this_test: if last_test != this_test:
if current_version[u'build']: if current_version[u'build']:
req = urllib2.Request(u'http://www.openlp.org/files/dev_version.txt') req = urllib2.Request(u'http://www.openlp.org/files/nightly_version.txt')
else: else:
req = urllib2.Request(u'http://www.openlp.org/files/version.txt') version_parts = current_version[u'version'].split(u'.')
if int(version_parts[1]) % 2 != 0:
req = urllib2.Request(u'http://www.openlp.org/files/dev_version.txt')
else:
req = urllib2.Request(u'http://www.openlp.org/files/version.txt')
req.add_header(u'User-Agent', u'OpenLP/%s' % current_version[u'full']) req.add_header(u'User-Agent', u'OpenLP/%s' % current_version[u'full'])
remote_version = None remote_version = None
try: try:
@ -322,8 +328,7 @@ def add_actions(target, actions):
def get_filesystem_encoding(): def get_filesystem_encoding():
""" """
Returns the name of the encoding used to convert Unicode filenames into Returns the name of the encoding used to convert Unicode filenames into system file names.
system file names.
""" """
encoding = sys.getfilesystemencoding() encoding = sys.getfilesystemencoding()
if encoding is None: if encoding is None:
@ -333,8 +338,7 @@ def get_filesystem_encoding():
def get_images_filter(): def get_images_filter():
""" """
Returns a filter string for a file dialog containing all the supported Returns a filter string for a file dialog containing all the supported image formats.
image formats.
""" """
global IMAGES_FILTER global IMAGES_FILTER
if not IMAGES_FILTER: if not IMAGES_FILTER:
@ -420,7 +424,7 @@ def get_web_page(url, header=None, update_openlp=False):
if not page: if not page:
return None return None
if update_openlp: if update_openlp:
Receiver.send_message(u'openlp_process_events') Registry().get(u'application').process_events()
log.debug(page) log.debug(page)
return page return page
@ -454,7 +458,7 @@ def get_uno_instance(resolver):
def format_time(text, local_time): def format_time(text, local_time):
""" """
Workaround for Python built-in time formatting fuction time.strftime(). Workaround for Python built-in time formatting function time.strftime().
time.strftime() accepts only ascii characters. This function accepts time.strftime() accepts only ascii characters. This function accepts
unicode string and passes individual % placeholders to time.strftime(). unicode string and passes individual % placeholders to time.strftime().
@ -462,10 +466,14 @@ def format_time(text, local_time):
``text`` ``text``
The text to be processed. The text to be processed.
``local_time`` ``local_time``
The time to be used to add to the string. This is a time object The time to be used to add to the string. This is a time object
""" """
def match_formatting(match): def match_formatting(match):
"""
Format the match
"""
return local_time.strftime(match.group()) return local_time.strftime(match.group())
return re.sub('\%[a-zA-Z]', match_formatting, text) return re.sub('\%[a-zA-Z]', match_formatting, text)
@ -478,22 +486,18 @@ def locale_compare(string1, string2):
or 0, depending on whether string1 collates before or after string2 or or 0, depending on whether string1 collates before or after string2 or
is equal to it. Comparison is case insensitive. is equal to it. Comparison is case insensitive.
""" """
# Function locale.strcoll() from standard Python library does not work # Function locale.strcoll() from standard Python library does not work properly on Windows.
# properly on Windows.
return locale.strcoll(string1.lower(), string2.lower()) return locale.strcoll(string1.lower(), string2.lower())
# For performance reasons provide direct reference to compare function # For performance reasons provide direct reference to compare function without wrapping it in another function making
# without wrapping it in another function making te string lowercase. # the string lowercase. This is needed for sorting songs.
# This is needed for sorting songs.
locale_direct_compare = locale.strcoll locale_direct_compare = locale.strcoll
from languagemanager import LanguageManager from languagemanager import LanguageManager
from actions import ActionList from actions import ActionList
__all__ = [u'AppLocation', u'get_application_version', u'check_latest_version', __all__ = [u'AppLocation', u'ActionList', u'LanguageManager', u'get_application_version', u'check_latest_version',
u'add_actions', u'get_filesystem_encoding', u'LanguageManager', u'add_actions', u'get_filesystem_encoding', u'get_web_page', u'get_uno_command', u'get_uno_instance',
u'ActionList', u'get_web_page', u'get_uno_command', u'get_uno_instance', u'delete_file', u'clean_filename', u'format_time', u'locale_compare', u'locale_direct_compare']
u'delete_file', u'clean_filename', u'format_time', u'locale_compare',
u'locale_direct_compare']

View File

@ -41,6 +41,9 @@ class ActionCategory(object):
category for the :class:`~openlp.core.utils.CategoryList` class. category for the :class:`~openlp.core.utils.CategoryList` class.
""" """
def __init__(self, name, weight=0): def __init__(self, name, weight=0):
"""
Constructor
"""
self.name = name self.name = name
self.weight = weight self.weight = weight
self.actions = CategoryActionList() self.actions = CategoryActionList()
@ -52,22 +55,37 @@ class CategoryActionList(object):
list of actions within a category. list of actions within a category.
""" """
def __init__(self): def __init__(self):
"""
Constructor
"""
self.index = 0 self.index = 0
self.actions = [] self.actions = []
def __getitem__(self, key): def __getitem__(self, key):
"""
Implement the __getitem__() method to make this class a dictionary type
"""
for weight, action in self.actions: for weight, action in self.actions:
if action.text() == key: if action.text() == key:
return action return action
raise KeyError(u'Action "%s" does not exist.' % key) raise KeyError(u'Action "%s" does not exist.' % key)
def __contains__(self, item): def __contains__(self, item):
"""
Implement the __contains__() method to make this class a dictionary type
"""
return self.has_key(item) return self.has_key(item)
def __len__(self): def __len__(self):
"""
Implement the __len__() method to make this class a dictionary type
"""
return len(self.actions) return len(self.actions)
def __iter__(self): def __iter__(self):
"""
Implement the __getitem__() method to make this class iterable
"""
return self return self
def __next__(self): def __next__(self):
@ -88,22 +106,34 @@ class CategoryActionList(object):
return self.__next__() return self.__next__()
def has_key(self, key): def has_key(self, key):
"""
Implement the has_key() method to make this class a dictionary type
"""
for weight, action in self.actions: for weight, action in self.actions:
if action.text() == key: if action.text() == key:
return True return True
return False return False
def append(self, name): def append(self, name):
"""
Append an action
"""
weight = 0 weight = 0
if self.actions: if self.actions:
weight = self.actions[-1][0] + 1 weight = self.actions[-1][0] + 1
self.add(name, weight) self.add(name, weight)
def add(self, action, weight=0): def add(self, action, weight=0):
"""
Add an action.
"""
self.actions.append((weight, action)) self.actions.append((weight, action))
self.actions.sort(key=lambda act: act[0]) self.actions.sort(key=lambda act: act[0])
def remove(self, remove_action): def remove(self, remove_action):
"""
Remove an action
"""
for action in self.actions: for action in self.actions:
if action[1] == remove_action: if action[1] == remove_action:
self.actions.remove(action) self.actions.remove(action)
@ -118,22 +148,37 @@ class CategoryList(object):
""" """
def __init__(self): def __init__(self):
"""
Constructor
"""
self.index = 0 self.index = 0
self.categories = [] self.categories = []
def __getitem__(self, key): def __getitem__(self, key):
"""
Implement the __getitem__() method to make this class like a dictionary
"""
for category in self.categories: for category in self.categories:
if category.name == key: if category.name == key:
return category return category
raise KeyError(u'Category "%s" does not exist.' % key) raise KeyError(u'Category "%s" does not exist.' % key)
def __contains__(self, item): def __contains__(self, item):
"""
Implement the __contains__() method to make this class like a dictionary
"""
return self.has_key(item) return self.has_key(item)
def __len__(self): def __len__(self):
"""
Implement the __len__() method to make this class like a dictionary
"""
return len(self.categories) return len(self.categories)
def __iter__(self): def __iter__(self):
"""
Implement the __iter__() method to make this class like a dictionary
"""
return self return self
def __next__(self): def __next__(self):
@ -154,12 +199,18 @@ class CategoryList(object):
return self.__next__() return self.__next__()
def has_key(self, key): def has_key(self, key):
"""
Implement the has_key() method to make this class like a dictionary
"""
for category in self.categories: for category in self.categories:
if category.name == key: if category.name == key:
return True return True
return False return False
def append(self, name, actions=None): def append(self, name, actions=None):
"""
Append a category
"""
weight = 0 weight = 0
if self.categories: if self.categories:
weight = self.categories[-1].weight + 1 weight = self.categories[-1].weight + 1
@ -169,6 +220,9 @@ class CategoryList(object):
self.add(name, weight) self.add(name, weight)
def add(self, name, weight=0, actions=None): def add(self, name, weight=0, actions=None):
"""
Add a category
"""
category = ActionCategory(name, weight) category = ActionCategory(name, weight)
if actions: if actions:
for action in actions: for action in actions:
@ -180,6 +234,9 @@ class CategoryList(object):
self.categories.sort(key=lambda cat: cat.weight) self.categories.sort(key=lambda cat: cat.weight)
def remove(self, name): def remove(self, name):
"""
Remove a category
"""
for category in self.categories: for category in self.categories:
if category.name == name: if category.name == name:
self.categories.remove(category) self.categories.remove(category)
@ -196,10 +253,16 @@ class ActionList(object):
shortcut_map = {} shortcut_map = {}
def __init__(self): def __init__(self):
"""
Constructor
"""
self.categories = CategoryList() self.categories = CategoryList()
@staticmethod @staticmethod
def get_instance(): def get_instance():
"""
Get the instance of this class.
"""
if ActionList.instance is None: if ActionList.instance is None:
ActionList.instance = ActionList() ActionList.instance = ActionList()
return ActionList.instance return ActionList.instance
@ -233,7 +296,7 @@ class ActionList(object):
# Load the shortcut from the config. # Load the shortcut from the config.
settings = Settings() settings = Settings()
settings.beginGroup(u'shortcuts') settings.beginGroup(u'shortcuts')
shortcuts = settings.value(action.objectName(), action.shortcuts()) shortcuts = settings.value(action.objectName())
settings.endGroup() settings.endGroup()
if not shortcuts: if not shortcuts:
action.setShortcuts([]) action.setShortcuts([])

View File

@ -27,8 +27,7 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
The :mod:`languagemanager` module provides all the translation settings and The :mod:`languagemanager` module provides all the translation settings and language file loading for OpenLP.
language file loading for OpenLP.
""" """
import logging import logging
import re import re
@ -37,10 +36,11 @@ import sys
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.utils import AppLocation from openlp.core.utils import AppLocation
from openlp.core.lib import translate, Settings from openlp.core.lib import Settings, translate
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class LanguageManager(object): class LanguageManager(object):
""" """
Helper for Language selection Helper for Language selection
@ -98,7 +98,7 @@ class LanguageManager(object):
""" """
Retrieve a saved language to use from settings Retrieve a saved language to use from settings
""" """
language = Settings().value(u'general/language', u'[en]') language = Settings().value(u'general/language')
language = str(language) language = str(language)
log.info(u'Language file: \'%s\' Loaded from conf file' % language) log.info(u'Language file: \'%s\' Loaded from conf file' % language)
if re.match(r'[[].*[]]', language): if re.match(r'[[].*[]]', language):

View File

@ -29,12 +29,13 @@
import logging import logging
from PyQt4 import QtCore from PyQt4 import QtGui
from openlp.core.lib import Plugin, StringContent, build_icon, translate, Settings from openlp.core.lib import Plugin, Settings, StringContent, build_icon, translate
from openlp.core.lib.db import Manager from openlp.core.lib.db import Manager
from openlp.core.lib.ui import create_action, UiStrings from openlp.core.lib.ui import create_action, UiStrings
from openlp.core.lib.theme import VerticalType from openlp.core.lib.theme import VerticalType
from openlp.core.ui import AlertLocation
from openlp.core.utils.actions import ActionList from openlp.core.utils.actions import ActionList
from openlp.plugins.alerts.lib import AlertsManager, AlertsTab from openlp.plugins.alerts.lib import AlertsManager, AlertsTab
from openlp.plugins.alerts.lib.db import init_schema from openlp.plugins.alerts.lib.db import init_schema
@ -113,11 +114,22 @@ HTML = """
<div id="alert" style="visibility:hidden"></div> <div id="alert" style="visibility:hidden"></div>
""" """
__default_settings__ = {
u'alerts/font face': QtGui.QFont().family(),
u'alerts/font size': 40,
u'alerts/db type': u'sqlite',
u'alerts/location': AlertLocation.Bottom,
u'alerts/background color': u'#660000',
u'alerts/font color': u'#ffffff',
u'alerts/timeout': 5
}
class AlertsPlugin(Plugin): class AlertsPlugin(Plugin):
log.info(u'Alerts Plugin loaded') log.info(u'Alerts Plugin loaded')
def __init__(self, plugin_helpers): def __init__(self):
Plugin.__init__(self, u'alerts', plugin_helpers, settings_tab_class=AlertsTab) Plugin.__init__(self, u'alerts', __default_settings__, settings_tab_class=AlertsTab)
self.weight = -3 self.weight = -3
self.iconPath = u':/plugins/plugin_alerts.png' self.iconPath = u':/plugins/plugin_alerts.png'
self.icon = build_icon(self.iconPath) self.icon = build_icon(self.iconPath)
@ -139,7 +151,7 @@ class AlertsPlugin(Plugin):
text=translate('AlertsPlugin', '&Alert'), icon=u':/plugins/plugin_alerts.png', text=translate('AlertsPlugin', '&Alert'), icon=u':/plugins/plugin_alerts.png',
statustip=translate('AlertsPlugin', 'Show an alert message.'), statustip=translate('AlertsPlugin', 'Show an alert message.'),
visible=False, shortcuts=[u'F7'], triggers=self.onAlertsTrigger) visible=False, shortcuts=[u'F7'], triggers=self.onAlertsTrigger)
self.serviceManager.mainwindow.toolsMenu.addAction(self.toolsAlertItem) self.main_window.toolsMenu.addAction(self.toolsAlertItem)
def initialise(self): def initialise(self):
log.info(u'Alerts Initialising') log.info(u'Alerts Initialising')

View File

@ -26,5 +26,31 @@
# 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 #
############################################################################### ###############################################################################
"""
Forms in OpenLP are made up of two classes. One class holds all the graphical
elements, like buttons and lists, and the other class holds all the functional
code, like slots and loading and saving.
The first class, commonly known as the **Dialog** class, is typically named
``Ui_<name>Dialog``. It is a slightly modified version of the class that the
``pyuic4`` command produces from Qt4's .ui file. Typical modifications will be
converting most strings from "" to u'' and using OpenLP's ``translate()``
function for translating strings.
The second class, commonly known as the **Form** class, is typically named
``<name>Form``. This class is the one which is instantiated and used. It uses
dual inheritance to inherit from (usually) QtGui.QDialog and the Ui class
mentioned above, like so::
class AuthorsForm(QtGui.QDialog, Ui_AuthorsDialog):
def __init__(self, parent=None):
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
This allows OpenLP to use ``self.object`` for all the GUI elements while keeping
them separate from the functionality, so that it is easier to recreate the GUI
from the .ui files later if necessary.
"""
from alertform import AlertForm from alertform import AlertForm

View File

@ -77,9 +77,9 @@ class Ui_AlertDialog(object):
displayIcon = build_icon(u':/general/general_live.png') displayIcon = build_icon(u':/general/general_live.png')
self.displayButton = create_button(alertDialog, u'displayButton', icon=displayIcon, enabled=False) self.displayButton = create_button(alertDialog, u'displayButton', icon=displayIcon, enabled=False)
self.displayCloseButton = create_button(alertDialog, u'displayCloseButton', icon=displayIcon, enabled=False) self.displayCloseButton = create_button(alertDialog, u'displayCloseButton', icon=displayIcon, enabled=False)
self.buttonBox = create_button_box(alertDialog, u'buttonBox', [u'close'], self.button_box = create_button_box(alertDialog, u'button_box', [u'close'],
[self.displayButton, self.displayCloseButton]) [self.displayButton, self.displayCloseButton])
self.alertDialogLayout.addWidget(self.buttonBox, 2, 0, 1, 2) self.alertDialogLayout.addWidget(self.button_box, 2, 0, 1, 2)
self.retranslateUi(alertDialog) self.retranslateUi(alertDialog)
def retranslateUi(self, alertDialog): def retranslateUi(self, alertDialog):

View File

@ -34,6 +34,7 @@ from openlp.plugins.alerts.lib.db import AlertItem
from alertdialog import Ui_AlertDialog from alertdialog import Ui_AlertDialog
class AlertForm(QtGui.QDialog, Ui_AlertDialog): class AlertForm(QtGui.QDialog, Ui_AlertDialog):
""" """
Provide UI for the alert system Provide UI for the alert system
@ -45,7 +46,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
self.manager = plugin.manager self.manager = plugin.manager
self.plugin = plugin self.plugin = plugin
self.item_id = None self.item_id = None
QtGui.QDialog.__init__(self, plugin.formParent) super(AlertForm, self).__init__(self.plugin.main_window)
self.setupUi(self) self.setupUi(self)
QtCore.QObject.connect(self.displayButton, QtCore.SIGNAL(u'clicked()'), self.onDisplayClicked) QtCore.QObject.connect(self.displayButton, QtCore.SIGNAL(u'clicked()'), self.onDisplayClicked)
QtCore.QObject.connect(self.displayCloseButton, QtCore.SIGNAL(u'clicked()'), self.onDisplayCloseClicked) QtCore.QObject.connect(self.displayCloseButton, QtCore.SIGNAL(u'clicked()'), self.onDisplayCloseClicked)
@ -57,6 +58,9 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
QtCore.QObject.connect(self.alertListWidget, QtCore.SIGNAL(u'currentRowChanged(int)'), self.onCurrentRowChanged) QtCore.QObject.connect(self.alertListWidget, QtCore.SIGNAL(u'currentRowChanged(int)'), self.onCurrentRowChanged)
def exec_(self): def exec_(self):
"""
Execute the dialog and return the exit code.
"""
self.displayButton.setEnabled(False) self.displayButton.setEnabled(False)
self.displayCloseButton.setEnabled(False) self.displayCloseButton.setEnabled(False)
self.alertTextEdit.setText(u'') self.alertTextEdit.setText(u'')
@ -77,9 +81,15 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
self.alertListWidget.setCurrentRow(self.alertListWidget.row(item_name)) self.alertListWidget.setCurrentRow(self.alertListWidget.row(item_name))
def onDisplayClicked(self): def onDisplayClicked(self):
"""
Display the current alert text.
"""
self.triggerAlert(self.alertTextEdit.text()) self.triggerAlert(self.alertTextEdit.text())
def onDisplayCloseClicked(self): def onDisplayCloseClicked(self):
"""
Close the alert preview.
"""
if self.triggerAlert(self.alertTextEdit.text()): if self.triggerAlert(self.alertTextEdit.text()):
self.close() self.close()
@ -97,6 +107,9 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
self.alertTextEdit.setText(u'') self.alertTextEdit.setText(u'')
def onNewClick(self): def onNewClick(self):
"""
Create a new alert.
"""
if not self.alertTextEdit.text(): if not self.alertTextEdit.text():
QtGui.QMessageBox.information(self, QtGui.QMessageBox.information(self,
translate('AlertsPlugin.AlertForm', 'New Alert'), translate('AlertsPlugin.AlertForm', 'New Alert'),

View File

@ -26,6 +26,10 @@
# 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 #
############################################################################### ###############################################################################
"""
The :mod:`~openlp.plugins.alerts.lib.alertsmanager` module contains the part of
the plugin which manages storing and displaying of alerts.
"""
import logging import logging

View File

@ -29,9 +29,8 @@
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import SettingsTab, translate, Receiver, Settings from openlp.core.lib import SettingsTab, Receiver, Settings, UiStrings, translate
from openlp.core.ui import AlertLocation from openlp.core.lib.ui import create_valign_selection_widgets
from openlp.core.lib.ui import UiStrings, create_valign_selection_widgets
class AlertsTab(SettingsTab): class AlertsTab(SettingsTab):
""" """
@ -141,12 +140,12 @@ class AlertsTab(SettingsTab):
def load(self): def load(self):
settings = Settings() settings = Settings()
settings.beginGroup(self.settingsSection) settings.beginGroup(self.settingsSection)
self.timeout = settings.value(u'timeout', 5) self.timeout = settings.value(u'timeout')
self.font_color = settings.value(u'font color', u'#ffffff') self.font_color = settings.value(u'font color')
self.font_size = settings.value(u'font size', 40) self.font_size = settings.value(u'font size')
self.bg_color = settings.value(u'background color', u'#660000') self.bg_color = settings.value(u'background color')
self.font_face = settings.value(u'font face', QtGui.QFont().family()) self.font_face = settings.value(u'font face')
self.location = settings.value(u'location', AlertLocation.Bottom) self.location = settings.value(u'location')
settings.endGroup() settings.endGroup()
self.fontSizeSpinBox.setValue(self.font_size) self.fontSizeSpinBox.setValue(self.font_size)
self.timeoutSpinBox.setValue(self.timeout) self.timeoutSpinBox.setValue(self.timeout)
@ -163,7 +162,7 @@ class AlertsTab(SettingsTab):
settings = Settings() settings = Settings()
settings.beginGroup(self.settingsSection) settings.beginGroup(self.settingsSection)
# Check value has changed as no event handles this field # Check value has changed as no event handles this field
if settings.value(u'location', 1) != self.verticalComboBox.currentIndex(): if settings.value(u'location') != self.verticalComboBox.currentIndex():
self.changed = True self.changed = True
settings.setValue(u'background color', self.bg_color) settings.setValue(u'background color', self.bg_color)
settings.setValue(u'font color', self.font_color) settings.setValue(u'font color', self.font_color)

View File

@ -29,21 +29,47 @@
import logging import logging
from PyQt4 import QtCore, QtGui from PyQt4 import QtGui
from openlp.core.lib import Plugin, StringContent, build_icon, translate, Settings 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 UiStrings, create_action
from openlp.core.utils.actions import ActionList from openlp.core.utils.actions import ActionList
from openlp.plugins.bibles.lib import BibleManager, BiblesTab, BibleMediaItem from openlp.plugins.bibles.lib import BibleManager, BiblesTab, BibleMediaItem, LayoutStyle, DisplayStyle, \
LanguageSelection
from openlp.plugins.bibles.lib.mediaitem import BibleSearch
from openlp.plugins.bibles.forms import BibleUpgradeForm from openlp.plugins.bibles.forms import BibleUpgradeForm
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
__default_settings__ = {
u'bibles/db type': u'sqlite',
u'bibles/last search type': BibleSearch.Reference,
u'bibles/verse layout style': LayoutStyle.VersePerSlide,
u'bibles/book name language': LanguageSelection.Bible,
u'bibles/display brackets': DisplayStyle.NoBrackets,
u'bibles/display new chapter': False,
u'bibles/second bibles': True,
u'bibles/advanced bible': u'',
u'bibles/quick bible': u'',
u'bibles/proxy name': u'',
u'bibles/proxy address': u'',
u'bibles/proxy username': u'',
u'bibles/proxy password': u'',
u'bibles/bible theme': u'',
u'bibles/verse separator': u'',
u'bibles/range separator': u'',
u'bibles/list separator': u'',
u'bibles/end separator': u'',
u'bibles/last directory import': u''
}
class BiblePlugin(Plugin): class BiblePlugin(Plugin):
log.info(u'Bible Plugin loaded') log.info(u'Bible Plugin loaded')
def __init__(self, plugin_helpers): def __init__(self):
Plugin.__init__(self, u'bibles', plugin_helpers, BibleMediaItem, BiblesTab) Plugin.__init__(self, u'bibles', __default_settings__, BibleMediaItem, BiblesTab)
self.weight = -9 self.weight = -9
self.iconPath = u':/plugins/plugin_bibles.png' self.iconPath = u':/plugins/plugin_bibles.png'
self.icon = build_icon(self.iconPath) self.icon = build_icon(self.iconPath)
@ -76,24 +102,19 @@ class BiblePlugin(Plugin):
#action_list.remove_action(self.exportBibleItem, UiStrings().Export) #action_list.remove_action(self.exportBibleItem, UiStrings().Export)
self.exportBibleItem.setVisible(False) self.exportBibleItem.setVisible(False)
def appStartup(self): def app_startup(self):
""" """
Perform tasks on application startup Perform tasks on application startup
""" """
Plugin.app_startup(self)
if self.manager.old_bible_databases: if self.manager.old_bible_databases:
if QtGui.QMessageBox.information(self.formParent, if QtGui.QMessageBox.information(self.main_window,
translate('OpenLP', 'Information'), translate('OpenLP', 'Information'),
translate('OpenLP', 'Bible format has changed.\nYou have to upgrade your existing Bibles.\n' translate('OpenLP', 'Bible format has changed.\nYou have to upgrade your existing Bibles.\n'
'Should OpenLP upgrade now?'), 'Should OpenLP upgrade now?'),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)) == \ QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)) == \
QtGui.QMessageBox.Yes: QtGui.QMessageBox.Yes:
self.onToolsUpgradeItemTriggered() self.onToolsUpgradeItemTriggered()
settings = Settings()
settings.beginGroup(self.settingsSection)
if settings.contains(u'bookname language'):
settings.setValue(u'book name language', settings.value(u'bookname language', 0))
settings.remove(u'bookname language')
settings.endGroup()
def addImportMenuItem(self, import_menu): def addImportMenuItem(self, import_menu):
self.importBibleItem = create_action(import_menu, u'importBibleItem', self.importBibleItem = create_action(import_menu, u'importBibleItem',
@ -128,7 +149,7 @@ class BiblePlugin(Plugin):
Upgrade older bible databases. Upgrade older bible databases.
""" """
if not hasattr(self, u'upgrade_wizard'): if not hasattr(self, u'upgrade_wizard'):
self.upgrade_wizard = BibleUpgradeForm(self.formParent, self.manager, self) self.upgrade_wizard = BibleUpgradeForm(self.main_window, self.manager, self)
# If the import was not cancelled then reload. # If the import was not cancelled then reload.
if self.upgrade_wizard.exec_(): if self.upgrade_wizard.exec_():
self.mediaItem.reloadBibles() self.mediaItem.reloadBibles()

View File

@ -34,9 +34,9 @@ import os
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, translate, Settings from openlp.core.lib import Settings, UiStrings, translate
from openlp.core.lib.db import delete_database from openlp.core.lib.db import delete_database
from openlp.core.lib.ui import UiStrings, critical_error_message_box from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui.wizard import OpenLPWizard, WizardStrings from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
from openlp.core.utils import AppLocation, locale_compare from openlp.core.utils import AppLocation, locale_compare
from openlp.plugins.bibles.lib.manager import BibleFormat from openlp.plugins.bibles.lib.manager import BibleFormat
@ -469,34 +469,34 @@ class BibleImportForm(OpenLPWizard):
""" """
Show the file open dialog for the OSIS file. Show the file open dialog for the OSIS file.
""" """
self.getFileName(WizardStrings.OpenTypeFile % WizardStrings.OSIS, self.osisFileEdit) self.getFileName(WizardStrings.OpenTypeFile % WizardStrings.OSIS, self.osisFileEdit, u'last directory import')
def onCsvBooksBrowseButtonClicked(self): def onCsvBooksBrowseButtonClicked(self):
""" """
Show the file open dialog for the books CSV file. Show the file open dialog for the books CSV file.
""" """
self.getFileName(WizardStrings.OpenTypeFile % WizardStrings.CSV, self.csvBooksEdit, u'%s (*.csv)' self.getFileName(WizardStrings.OpenTypeFile % WizardStrings.CSV, self.csvBooksEdit, u'last directory import',
% translate('BiblesPlugin.ImportWizardForm', 'CSV File')) u'%s (*.csv)' % translate('BiblesPlugin.ImportWizardForm', 'CSV File'))
def onCsvVersesBrowseButtonClicked(self): def onCsvVersesBrowseButtonClicked(self):
""" """
Show the file open dialog for the verses CSV file. Show the file open dialog for the verses CSV file.
""" """
self.getFileName(WizardStrings.OpenTypeFile % WizardStrings.CSV, self.csvVersesEdit, u'%s (*.csv)' self.getFileName(WizardStrings.OpenTypeFile % WizardStrings.CSV, self.csvVersesEdit, u'last directory import',
% translate('BiblesPlugin.ImportWizardForm', 'CSV File')) u'%s (*.csv)' % translate('BiblesPlugin.ImportWizardForm', 'CSV File'))
def onOpenSongBrowseButtonClicked(self): def onOpenSongBrowseButtonClicked(self):
""" """
Show the file open dialog for the OpenSong file. Show the file open dialog for the OpenSong file.
""" """
self.getFileName(WizardStrings.OpenTypeFile % WizardStrings.OS, self.openSongFileEdit) self.getFileName(WizardStrings.OpenTypeFile % WizardStrings.OS, self.openSongFileEdit, u'last directory import')
def onOpenlp1BrowseButtonClicked(self): def onOpenlp1BrowseButtonClicked(self):
""" """
Show the file open dialog for the openlp.org 1.x file. Show the file open dialog for the openlp.org 1.x file.
""" """
self.getFileName(WizardStrings.OpenTypeFile % UiStrings().OLPV1, self.openlp1FileEdit, u'%s (*.bible)' % self.getFileName(WizardStrings.OpenTypeFile % UiStrings().OLPV1, self.openlp1FileEdit, u'last directory import',
translate('BiblesPlugin.ImportWizardForm', 'openlp.org 1.x Bible Files')) u'%s (*.bible)' % translate('BiblesPlugin.ImportWizardForm', 'openlp.org 1.x Bible Files'))
def registerFields(self): def registerFields(self):
""" """
@ -533,9 +533,9 @@ class BibleImportForm(OpenLPWizard):
self.setField(u'opensong_file', '') self.setField(u'opensong_file', '')
self.setField(u'web_location', WebDownload.Crosswalk) self.setField(u'web_location', WebDownload.Crosswalk)
self.setField(u'web_biblename', self.webTranslationComboBox.currentIndex()) self.setField(u'web_biblename', self.webTranslationComboBox.currentIndex())
self.setField(u'proxy_server', settings.value(u'proxy address', u'')) self.setField(u'proxy_server', settings.value(u'proxy address'))
self.setField(u'proxy_username', settings.value(u'proxy username', u'')) self.setField(u'proxy_username', settings.value(u'proxy username'))
self.setField(u'proxy_password', settings.value(u'proxy password', u'')) self.setField(u'proxy_password', settings.value(u'proxy password'))
self.setField(u'openlp1_location', '') self.setField(u'openlp1_location', '')
self.setField(u'license_version', self.versionNameEdit.text()) self.setField(u'license_version', self.versionNameEdit.text())
self.setField(u'license_copyright', self.copyrightEdit.text()) self.setField(u'license_copyright', self.copyrightEdit.text())
@ -578,7 +578,7 @@ class BibleImportForm(OpenLPWizard):
self.progressLabel.setText(translate('BiblesPlugin.ImportWizardForm', 'Registering Bible...')) self.progressLabel.setText(translate('BiblesPlugin.ImportWizardForm', 'Registering Bible...'))
else: else:
self.progressLabel.setText(WizardStrings.StartingImport) self.progressLabel.setText(WizardStrings.StartingImport)
Receiver.send_message(u'openlp_process_events') self.application.process_events()
def performWizard(self): def performWizard(self):
""" """

View File

@ -36,8 +36,8 @@ from tempfile import gettempdir
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, SettingsManager, translate, check_directory_exists, Settings from openlp.core.lib import Receiver, Settings, UiStrings, translate, check_directory_exists
from openlp.core.lib.ui import UiStrings, critical_error_message_box from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui.wizard import OpenLPWizard, WizardStrings from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
from openlp.core.utils import AppLocation, delete_file, get_filesystem_encoding from openlp.core.utils import AppLocation, delete_file, get_filesystem_encoding
from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta, OldBibleDB, BiblesResourcesDB from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta, OldBibleDB, BiblesResourcesDB
@ -116,11 +116,9 @@ class BibleUpgradeForm(OpenLPWizard):
Show the file open dialog for the OSIS file. Show the file open dialog for the OSIS file.
""" """
filename = QtGui.QFileDialog.getExistingDirectory(self, filename = QtGui.QFileDialog.getExistingDirectory(self,
translate('BiblesPlugin.UpgradeWizardForm', 'Select a Backup Directory'), translate('BiblesPlugin.UpgradeWizardForm', 'Select a Backup Directory'), u'')
os.path.dirname(SettingsManager.get_last_dir(self.plugin.settingsSection, 1)))
if filename: if filename:
self.backupDirectoryEdit.setText(filename) self.backupDirectoryEdit.setText(filename)
SettingsManager.set_last_dir(self.plugin.settingsSection, filename, 1)
def onNoBackupCheckBoxToggled(self, checked): def onNoBackupCheckBoxToggled(self, checked):
""" """
@ -337,7 +335,7 @@ class BibleUpgradeForm(OpenLPWizard):
""" """
OpenLPWizard.preWizard(self) OpenLPWizard.preWizard(self)
self.progressLabel.setText(translate('BiblesPlugin.UpgradeWizardForm', 'Starting upgrade...')) self.progressLabel.setText(translate('BiblesPlugin.UpgradeWizardForm', 'Starting upgrade...'))
Receiver.send_message(u'openlp_process_events') self.application.process_events()
def performWizard(self): def performWizard(self):
""" """
@ -467,7 +465,7 @@ class BibleUpgradeForm(OpenLPWizard):
self.newbibles[number].create_verse(db_book.id, self.newbibles[number].create_verse(db_book.id,
int(verse[u'chapter']), int(verse[u'chapter']),
int(verse[u'verse']), unicode(verse[u'text'])) int(verse[u'verse']), unicode(verse[u'text']))
Receiver.send_message(u'openlp_process_events') self.application.process_events()
self.newbibles[number].session.commit() self.newbibles[number].session.commit()
else: else:
language_id = self.newbibles[number].get_object(BibleMeta, u'language_id') language_id = self.newbibles[number].get_object(BibleMeta, u'language_id')
@ -513,7 +511,7 @@ class BibleUpgradeForm(OpenLPWizard):
self.newbibles[number].create_verse(db_book.id, self.newbibles[number].create_verse(db_book.id,
int(verse[u'chapter']), int(verse[u'chapter']),
int(verse[u'verse']), unicode(verse[u'text'])) int(verse[u'verse']), unicode(verse[u'text']))
Receiver.send_message(u'openlp_process_events') self.application.process_events()
self.newbibles[number].session.commit() self.newbibles[number].session.commit()
if not self.success.get(number, True): if not self.success.get(number, True):
self.incrementProgressBar(translate('BiblesPlugin.UpgradeWizardForm', self.incrementProgressBar(translate('BiblesPlugin.UpgradeWizardForm',

View File

@ -80,8 +80,8 @@ class Ui_BookNameDialog(object):
self.apocryphaCheckBox.setCheckState(QtCore.Qt.Checked) self.apocryphaCheckBox.setCheckState(QtCore.Qt.Checked)
self.optionsLayout.addWidget(self.apocryphaCheckBox) self.optionsLayout.addWidget(self.apocryphaCheckBox)
self.bookNameLayout.addWidget(self.optionsGroupBox) self.bookNameLayout.addWidget(self.optionsGroupBox)
self.buttonBox = create_button_box(bookNameDialog, u'buttonBox', [u'cancel', u'ok']) self.button_box = create_button_box(bookNameDialog, u'button_box', [u'cancel', u'ok'])
self.bookNameLayout.addWidget(self.buttonBox) self.bookNameLayout.addWidget(self.button_box)
self.retranslateUi(bookNameDialog) self.retranslateUi(bookNameDialog)

View File

@ -44,7 +44,7 @@ class Ui_EditBibleDialog(object):
self.dialogLayout = QtGui.QVBoxLayout(editBibleDialog) self.dialogLayout = QtGui.QVBoxLayout(editBibleDialog)
self.dialogLayout.setSpacing(8) self.dialogLayout.setSpacing(8)
self.dialogLayout.setContentsMargins(8, 8, 8, 8) self.dialogLayout.setContentsMargins(8, 8, 8, 8)
self.dialogLayout.setObjectName(u'dialogLayout') self.dialogLayout.setObjectName(u'dialog_layout')
self.bibleTabWidget = QtGui.QTabWidget(editBibleDialog) self.bibleTabWidget = QtGui.QTabWidget(editBibleDialog)
self.bibleTabWidget.setObjectName(u'BibleTabWidget') self.bibleTabWidget.setObjectName(u'BibleTabWidget')
# Meta tab # Meta tab
@ -121,8 +121,8 @@ class Ui_EditBibleDialog(object):
self.bibleTabWidget.addTab(self.bookNameTab, u'') self.bibleTabWidget.addTab(self.bookNameTab, u'')
# Last few bits # Last few bits
self.dialogLayout.addWidget(self.bibleTabWidget) self.dialogLayout.addWidget(self.bibleTabWidget)
self.buttonBox = create_button_box(editBibleDialog, u'buttonBox', [u'cancel', u'save']) self.button_box = create_button_box(editBibleDialog, u'button_box', [u'cancel', u'save'])
self.dialogLayout.addWidget(self.buttonBox) self.dialogLayout.addWidget(self.button_box)
self.retranslateUi(editBibleDialog) self.retranslateUi(editBibleDialog)
QtCore.QMetaObject.connectSlotsByName(editBibleDialog) QtCore.QMetaObject.connectSlotsByName(editBibleDialog)

View File

@ -32,8 +32,8 @@ import re
from PyQt4 import QtGui from PyQt4 import QtGui
from openlp.core.lib import Receiver, translate from openlp.core.lib import Registry, UiStrings, translate
from openlp.core.lib.ui import UiStrings, critical_error_message_box from openlp.core.lib.ui import critical_error_message_box
from editbibledialog import Ui_EditBibleDialog from editbibledialog import Ui_EditBibleDialog
from openlp.plugins.bibles.lib import BibleStrings from openlp.plugins.bibles.lib import BibleStrings
from openlp.plugins.bibles.lib.db import BiblesResourcesDB from openlp.plugins.bibles.lib.db import BiblesResourcesDB
@ -122,8 +122,7 @@ class EditBibleForm(QtGui.QDialog, Ui_EditBibleDialog):
if book.name != custom_names[abbr]: if book.name != custom_names[abbr]:
if not self.validateBook(custom_names[abbr], abbr): if not self.validateBook(custom_names[abbr], abbr):
return return
Receiver.send_message(u'openlp_process_events') self.application.set_busy_cursor()
Receiver.send_message(u'cursor_busy')
self.manager.save_meta_data(self.bible, version, copyright, permissions, book_name_language) self.manager.save_meta_data(self.bible, version, copyright, permissions, book_name_language)
if not self.webbible: if not self.webbible:
for abbr, book in self.books.iteritems(): for abbr, book in self.books.iteritems():
@ -132,7 +131,7 @@ class EditBibleForm(QtGui.QDialog, Ui_EditBibleDialog):
book.name = custom_names[abbr] book.name = custom_names[abbr]
self.manager.update_book(self.bible, book) self.manager.update_book(self.bible, book)
self.bible = None self.bible = None
Receiver.send_message(u'cursor_normal') self.application.set_normal_cursor()
QtGui.QDialog.accept(self) QtGui.QDialog.accept(self)
def validateMeta(self, name, copyright): def validateMeta(self, name, copyright):
@ -189,3 +188,13 @@ class EditBibleForm(QtGui.QDialog, Ui_EditBibleDialog):
% new_book_name) % new_book_name)
return False return False
return True return True
def _get_application(self):
"""
Adds the openlp to the class dynamically
"""
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application)

View File

@ -62,8 +62,8 @@ class Ui_LanguageDialog(object):
self.languageComboBox.setObjectName(u'languageComboBox') self.languageComboBox.setObjectName(u'languageComboBox')
self.languageHBoxLayout.addWidget(self.languageComboBox) self.languageHBoxLayout.addWidget(self.languageComboBox)
self.languageLayout.addLayout(self.languageHBoxLayout) self.languageLayout.addLayout(self.languageHBoxLayout)
self.buttonBox = create_button_box(languageDialog, u'buttonBox', [u'cancel', u'ok']) self.button_box = create_button_box(languageDialog, u'button_box', [u'cancel', u'ok'])
self.languageLayout.addWidget(self.buttonBox) self.languageLayout.addWidget(self.button_box)
self.retranslateUi(languageDialog) self.retranslateUi(languageDialog)

View File

@ -33,8 +33,8 @@ plugin.
import logging import logging
import re import re
from openlp.core.lib import translate, Settings from openlp.core.lib import Settings, translate
from openlp.plugins.bibles.lib.db import BiblesResourcesDB
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -187,10 +187,10 @@ def update_reference_separators():
settings = Settings() settings = Settings()
settings.beginGroup(u'bibles') settings.beginGroup(u'bibles')
custom_separators = [ custom_separators = [
settings.value(u'verse separator', u''), settings.value(u'verse separator'),
settings.value(u'range separator', u''), settings.value(u'range separator'),
settings.value(u'list separator', u''), settings.value(u'list separator'),
settings.value(u'end separator', u'')] settings.value(u'end separator')]
settings.endGroup() settings.endGroup()
for index, role in enumerate([u'v', u'r', u'l', u'e']): for index, role in enumerate([u'v', u'r', u'l', u'e']):
if custom_separators[index].strip(u'|') == u'': if custom_separators[index].strip(u'|') == u'':

View File

@ -31,8 +31,8 @@ import logging
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, SettingsTab, translate, Settings from openlp.core.lib import Receiver, SettingsTab, Settings, UiStrings, translate
from openlp.core.lib.ui import UiStrings, find_and_set_in_combo_box from openlp.core.lib.ui import find_and_set_in_combo_box
from openlp.plugins.bibles.lib import LayoutStyle, DisplayStyle, update_reference_separators, \ from openlp.plugins.bibles.lib import LayoutStyle, DisplayStyle, update_reference_separators, \
get_reference_separator, LanguageSelection get_reference_separator, LanguageSelection
@ -331,16 +331,16 @@ class BiblesTab(SettingsTab):
def load(self): def load(self):
settings = Settings() settings = Settings()
settings.beginGroup(self.settingsSection) settings.beginGroup(self.settingsSection)
self.show_new_chapters = settings.value(u'display new chapter', False) self.show_new_chapters = settings.value(u'display new chapter')
self.display_style = settings.value(u'display brackets', 0) self.display_style = settings.value(u'display brackets')
self.layout_style = settings.value(u'verse layout style', 0) self.layout_style = settings.value(u'verse layout style')
self.bible_theme = settings.value(u'bible theme', u'') self.bible_theme = settings.value(u'bible theme')
self.second_bibles = settings.value(u'second bibles', True) self.second_bibles = settings.value(u'second bibles')
self.newChaptersCheckBox.setChecked(self.show_new_chapters) self.newChaptersCheckBox.setChecked(self.show_new_chapters)
self.displayStyleComboBox.setCurrentIndex(self.display_style) self.displayStyleComboBox.setCurrentIndex(self.display_style)
self.layoutStyleComboBox.setCurrentIndex(self.layout_style) self.layoutStyleComboBox.setCurrentIndex(self.layout_style)
self.bibleSecondCheckBox.setChecked(self.second_bibles) self.bibleSecondCheckBox.setChecked(self.second_bibles)
verse_separator = settings.value(u'verse separator', u'') verse_separator = settings.value(u'verse separator')
if (verse_separator.strip(u'|') == u'') or (verse_separator == get_reference_separator(u'sep_v_default')): if (verse_separator.strip(u'|') == u'') or (verse_separator == get_reference_separator(u'sep_v_default')):
self.verseSeparatorLineEdit.setText(get_reference_separator(u'sep_v_default')) self.verseSeparatorLineEdit.setText(get_reference_separator(u'sep_v_default'))
self.verseSeparatorLineEdit.setPalette(self.getGreyTextPalette(True)) self.verseSeparatorLineEdit.setPalette(self.getGreyTextPalette(True))
@ -349,7 +349,7 @@ class BiblesTab(SettingsTab):
self.verseSeparatorLineEdit.setText(verse_separator) self.verseSeparatorLineEdit.setText(verse_separator)
self.verseSeparatorLineEdit.setPalette(self.getGreyTextPalette(False)) self.verseSeparatorLineEdit.setPalette(self.getGreyTextPalette(False))
self.verseSeparatorCheckBox.setChecked(True) self.verseSeparatorCheckBox.setChecked(True)
range_separator = settings.value(u'range separator', u'') range_separator = settings.value(u'range separator')
if (range_separator.strip(u'|') == u'') or (range_separator == get_reference_separator(u'sep_r_default')): if (range_separator.strip(u'|') == u'') or (range_separator == get_reference_separator(u'sep_r_default')):
self.rangeSeparatorLineEdit.setText(get_reference_separator(u'sep_r_default')) self.rangeSeparatorLineEdit.setText(get_reference_separator(u'sep_r_default'))
self.rangeSeparatorLineEdit.setPalette(self.getGreyTextPalette(True)) self.rangeSeparatorLineEdit.setPalette(self.getGreyTextPalette(True))
@ -358,7 +358,7 @@ class BiblesTab(SettingsTab):
self.rangeSeparatorLineEdit.setText(range_separator) self.rangeSeparatorLineEdit.setText(range_separator)
self.rangeSeparatorLineEdit.setPalette(self.getGreyTextPalette(False)) self.rangeSeparatorLineEdit.setPalette(self.getGreyTextPalette(False))
self.rangeSeparatorCheckBox.setChecked(True) self.rangeSeparatorCheckBox.setChecked(True)
list_separator = settings.value(u'list separator', u'') list_separator = settings.value(u'list separator')
if (list_separator.strip(u'|') == u'') or (list_separator == get_reference_separator(u'sep_l_default')): if (list_separator.strip(u'|') == u'') or (list_separator == get_reference_separator(u'sep_l_default')):
self.listSeparatorLineEdit.setText(get_reference_separator(u'sep_l_default')) self.listSeparatorLineEdit.setText(get_reference_separator(u'sep_l_default'))
self.listSeparatorLineEdit.setPalette(self.getGreyTextPalette(True)) self.listSeparatorLineEdit.setPalette(self.getGreyTextPalette(True))
@ -367,7 +367,7 @@ class BiblesTab(SettingsTab):
self.listSeparatorLineEdit.setText(list_separator) self.listSeparatorLineEdit.setText(list_separator)
self.listSeparatorLineEdit.setPalette(self.getGreyTextPalette(False)) self.listSeparatorLineEdit.setPalette(self.getGreyTextPalette(False))
self.listSeparatorCheckBox.setChecked(True) self.listSeparatorCheckBox.setChecked(True)
end_separator = settings.value(u'end separator', u'') end_separator = settings.value(u'end separator')
if (end_separator.strip(u'|') == u'') or (end_separator == get_reference_separator(u'sep_e_default')): if (end_separator.strip(u'|') == u'') or (end_separator == get_reference_separator(u'sep_e_default')):
self.endSeparatorLineEdit.setText(get_reference_separator(u'sep_e_default')) self.endSeparatorLineEdit.setText(get_reference_separator(u'sep_e_default'))
self.endSeparatorLineEdit.setPalette(self.getGreyTextPalette(True)) self.endSeparatorLineEdit.setPalette(self.getGreyTextPalette(True))
@ -376,7 +376,7 @@ class BiblesTab(SettingsTab):
self.endSeparatorLineEdit.setText(end_separator) self.endSeparatorLineEdit.setText(end_separator)
self.endSeparatorLineEdit.setPalette(self.getGreyTextPalette(False)) self.endSeparatorLineEdit.setPalette(self.getGreyTextPalette(False))
self.endSeparatorCheckBox.setChecked(True) self.endSeparatorCheckBox.setChecked(True)
self.language_selection = settings.value(u'book name language', 0) self.language_selection = settings.value(u'book name language')
self.languageSelectionComboBox.setCurrentIndex(self.language_selection) self.languageSelectionComboBox.setCurrentIndex(self.language_selection)
settings.endGroup() settings.endGroup()

View File

@ -62,7 +62,7 @@ import logging
import chardet import chardet
import csv import csv
from openlp.core.lib import Receiver, translate from openlp.core.lib import translate
from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -118,7 +118,7 @@ class CSVBible(BibleDB):
book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) book_details = BiblesResourcesDB.get_book_by_id(book_ref_id)
self.create_book(unicode(line[2], details['encoding']), book_ref_id, book_details[u'testament_id']) self.create_book(unicode(line[2], details['encoding']), book_ref_id, book_details[u'testament_id'])
book_list[int(line[0])] = unicode(line[2], details['encoding']) book_list[int(line[0])] = unicode(line[2], details['encoding'])
Receiver.send_message(u'openlp_process_events') self.application.process_events()
except (IOError, IndexError): except (IOError, IndexError):
log.exception(u'Loading books from file failed') log.exception(u'Loading books from file failed')
success = False success = False
@ -157,7 +157,7 @@ class CSVBible(BibleDB):
verse_text = unicode(line[3], u'cp1252') verse_text = unicode(line[3], u'cp1252')
self.create_verse(book.id, line[1], line[2], verse_text) self.create_verse(book.id, line[1], line[2], verse_text)
self.wizard.incrementProgressBar(translate('BiblesPlugin.CSVBible', 'Importing verses... done.')) self.wizard.incrementProgressBar(translate('BiblesPlugin.CSVBible', 'Importing verses... done.'))
Receiver.send_message(u'openlp_process_events') self.application.process_events()
self.session.commit() self.session.commit()
except IOError: except IOError:
log.exception(u'Loading verses from file failed') log.exception(u'Loading verses from file failed')

View File

@ -34,11 +34,11 @@ import re
import sqlite3 import sqlite3
from PyQt4 import QtCore from PyQt4 import QtCore
from sqlalchemy import Column, ForeignKey, or_, Table, types, func from sqlalchemy import Column, ForeignKey, Table, or_, types, func
from sqlalchemy.orm import class_mapper, mapper, relation from sqlalchemy.orm import class_mapper, mapper, relation
from sqlalchemy.orm.exc import UnmappedClassError from sqlalchemy.orm.exc import UnmappedClassError
from openlp.core.lib import Receiver, translate from openlp.core.lib import Receiver, Registry, translate
from openlp.core.lib.db import BaseModel, init_db, Manager from openlp.core.lib.db import BaseModel, init_db, Manager
from openlp.core.lib.ui import critical_error_message_box from openlp.core.lib.ui import critical_error_message_box
from openlp.core.utils import AppLocation, clean_filename from openlp.core.utils import AppLocation, clean_filename
@ -360,7 +360,7 @@ class BibleDB(QtCore.QObject, Manager):
``book`` ``book``
The name of the book, according to the selected language. The name of the book, according to the selected language.
``language_selection`` ``language_selection``
The language selection the user has chosen in the settings The language selection the user has chosen in the settings
section of the Bible. section of the Bible.
@ -549,6 +549,16 @@ class BibleDB(QtCore.QObject, Manager):
verses = self.session.query(Verse).all() verses = self.session.query(Verse).all()
log.debug(verses) log.debug(verses)
def _get_application(self):
"""
Adds the openlp to the class dynamically
"""
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application)
class BiblesResourcesDB(QtCore.QObject, Manager): class BiblesResourcesDB(QtCore.QObject, Manager):
""" """
@ -778,7 +788,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
The source of the webbible. The source of the webbible.
""" """
log.debug(u'BiblesResourcesDB.get_webbibles("%s")', source) log.debug(u'BiblesResourcesDB.get_webbibles("%s")', source)
if not isinstance(source, unicode): if not isinstance(source, unicode):
source = unicode(source) source = unicode(source)
source = BiblesResourcesDB.get_download_source(source) source = BiblesResourcesDB.get_download_source(source)
bibles = BiblesResourcesDB.run_sql(u'SELECT id, name, abbreviation, ' bibles = BiblesResourcesDB.run_sql(u'SELECT id, name, abbreviation, '
@ -953,7 +963,7 @@ class AlternativeBookNamesDB(QtCore.QObject, Manager):
return cursor.fetchall() return cursor.fetchall()
@staticmethod @staticmethod
def get_book_reference_id(name, language_id=None): def get_book_reference_id(name, language_id=None):
""" """
Return a book_reference_id if the name matches. Return a book_reference_id if the name matches.

Some files were not shown because too many files have changed in this diff Show More