Merge trunk.

This commit is contained in:
Patrick Zimmermann 2013-02-12 22:51:04 +01:00
commit e16a3c6dea
151 changed files with 3004 additions and 1713 deletions

View File

@ -25,3 +25,5 @@ openlp.cfg
openlp.pro
.kdev4
tests.kdev4
*.nja
*.orig

View File

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

View File

@ -43,7 +43,7 @@ from traceback import format_exception
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, Settings, check_directory_exists, ScreenList, UiStrings, Registry
from openlp.core.lib import Receiver, Settings, ScreenList, UiStrings, Registry, check_directory_exists
from openlp.core.resources import qInitResources
from openlp.core.ui.mainwindow import MainWindow
from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm
@ -92,15 +92,16 @@ class OpenLP(QtGui.QApplication):
"""
Override exec method to allow the shared memory to be released on exit
"""
self.eventLoopIsActive = True
QtGui.QApplication.exec_()
self.sharedMemory.detach()
self.is_event_loop_active = True
result = QtGui.QApplication.exec_()
self.shared_memory.detach()
return result
def run(self, args, testing=False):
def run(self, args):
"""
Run the OpenLP application.
"""
self.eventLoopIsActive = False
self.is_event_loop_active = False
# 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
# order to set the WM_CLASS property for X11, we pass "OpenLP" in as a
@ -109,10 +110,6 @@ class OpenLP(QtGui.QApplication):
if 'OpenLP' in args:
args.remove('OpenLP')
self.args.extend(args)
# provide a listener for widgets to reqest a screen update.
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'openlp_process_events'), self.processEvents)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'cursor_busy'), self.setBusyCursor)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'cursor_normal'), self.setNormalCursor)
# Decide how many screens we have and their size
screens = ScreenList.create(self.desktop())
# First time checks in settings
@ -121,11 +118,15 @@ class OpenLP(QtGui.QApplication):
if FirstTimeForm(screens).exec_() == QtGui.QDialog.Accepted:
Settings().setValue(u'general/has run wizard', True)
# 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)
application_stylesheet = \
alternate_rows_repair_stylesheet = \
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
if application_stylesheet:
self.setStyleSheet(application_stylesheet)
show_splash = Settings().value(u'general/show splash')
if show_splash:
@ -134,65 +135,89 @@ class OpenLP(QtGui.QApplication):
# make sure Qt really display the splash screen
self.processEvents()
# start the main app window
self.mainWindow = MainWindow(self)
self.mainWindow.show()
self.main_window = MainWindow()
self.main_window.show()
if show_splash:
# now kill the splashscreen
self.splash.finish(self.mainWindow)
self.splash.finish(self.main_window)
log.debug(u'Splashscreen closed')
# make sure Qt really display the splash screen
self.processEvents()
self.mainWindow.repaint()
self.main_window.repaint()
self.processEvents()
if not has_run_wizard:
self.mainWindow.firstTime()
self.main_window.first_time()
update_check = Settings().value(u'general/update check')
if update_check:
VersionThread(self.mainWindow).start()
VersionThread(self.main_window).start()
Receiver.send_message(u'live_display_blank_check')
self.mainWindow.appStartup()
# Skip exec_() for gui tests
if not testing:
return self.exec_()
self.main_window.app_startup()
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
is to be started.
"""
self.sharedMemory = QtCore.QSharedMemory('OpenLP')
if self.sharedMemory.attach():
self.shared_memory = QtCore.QSharedMemory('OpenLP')
if self.shared_memory.attach():
status = QtGui.QMessageBox.critical(None, UiStrings().Error, UiStrings().OpenLPStart,
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No))
if status == QtGui.QMessageBox.No:
return True
return False
else:
self.sharedMemory.create(1)
self.shared_memory.create(1)
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'):
log.exception(''.join(format_exception(exctype, value, traceback)))
return
if not hasattr(self, u'exceptionForm'):
self.exceptionForm = ExceptionForm(self.mainWindow)
self.exceptionForm.exceptionTextEdit.setPlainText(''.join(format_exception(exctype, value, traceback)))
self.setNormalCursor()
self.exceptionForm.exec_()
self.exception_form = ExceptionForm(self.main_window)
self.exception_form.exceptionTextEdit.setPlainText(''.join(format_exception(exctype, value, traceback)))
self.set_normal_cursor()
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
"""
self.setOverrideCursor(QtCore.Qt.BusyCursor)
self.processEvents()
def setNormalCursor(self):
def set_normal_cursor(self):
"""
Sets the Normal Cursor for the Application
"""
self.restoreOverrideCursor()
self.processEvents()
def event(self, event):
"""
@ -217,7 +242,7 @@ def set_up_logging(log_path):
logfile.setFormatter(logging.Formatter(u'%(asctime)s %(name)-55s %(levelname)-8s %(message)s'))
log.addHandler(logfile)
if log.isEnabledFor(logging.DEBUG):
print 'Logging to:', filename
print('Logging to: %s' % filename)
def main(args=None):
@ -237,7 +262,6 @@ def main(args=None):
parser.add_option('-d', '--dev-version', dest='dev_version', action='store_true',
help='Ignore the version file and pull the version directly from Bazaar')
parser.add_option('-s', '--style', dest='style', help='Set the Qt4 style (passed directly to Qt4).')
parser.add_option('--testing', dest='testing', action='store_true', help='Run by testing framework')
# Parse command line options and deal with them.
# Use args supplied programatically if possible.
(options, args) = parser.parse_args(args) if args else parser.parse_args()
@ -258,38 +282,37 @@ def main(args=None):
# Initialise the resources
qInitResources()
# Now create and actually run the application.
app = OpenLP(qt_args)
app.setOrganizationName(u'OpenLP')
app.setOrganizationDomain(u'openlp.org')
application = OpenLP(qt_args)
application.setOrganizationName(u'OpenLP')
application.setOrganizationDomain(u'openlp.org')
if options.portable:
app.setApplicationName(u'OpenLPPortable')
application.setApplicationName(u'OpenLPPortable')
Settings.setDefaultFormat(Settings.IniFormat)
# Get location OpenLPPortable.ini
app_path = AppLocation.get_directory(AppLocation.AppDir)
set_up_logging(os.path.abspath(os.path.join(app_path, u'..', u'..', u'Other')))
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(app_path, u'..', u'..', u'Data', u'OpenLP.ini'))
portable_settings_file = os.path.abspath(os.path.join(application_path, u'..', u'..', u'Data', u'OpenLP.ini'))
# Make this our settings file
log.info(u'INI file: %s', portable_settings_file)
Settings.set_filename(portable_settings_file)
portable_settings = Settings()
# Set our data path
data_path = os.path.abspath(os.path.join(app_path, u'..', u'..', u'Data',))
data_path = os.path.abspath(os.path.join(application_path, u'..', u'..', u'Data',))
log.info(u'Data path: %s', data_path)
# Point to our data path
portable_settings.setValue(u'advanced/data path', data_path)
portable_settings.setValue(u'advanced/is portable', True)
portable_settings.sync()
else:
app.setApplicationName(u'OpenLP')
application.setApplicationName(u'OpenLP')
set_up_logging(AppLocation.get_directory(AppLocation.CacheDir))
registry = Registry.create()
app.setApplicationVersion(get_application_version()[u'version'])
Registry.create()
Registry().register(u'application', application)
application.setApplicationVersion(get_application_version()[u'version'])
# Instance check
if not options.testing:
# Instance check
if app.isAlreadyRunning():
sys.exit()
if application.is_already_running():
sys.exit()
# First time checks in settings
if not Settings().value(u'general/has run wizard'):
if not FirstTimeLanguageForm().exec_():
@ -297,19 +320,14 @@ def main(args=None):
sys.exit()
# i18n Set Language
language = LanguageManager.get_language()
app_translator, default_translator = LanguageManager.get_translator(language)
if not app_translator.isEmpty():
app.installTranslator(app_translator)
application_translator, default_translator = LanguageManager.get_translator(language)
if not application_translator.isEmpty():
application.installTranslator(application_translator)
if not default_translator.isEmpty():
app.installTranslator(default_translator)
application.installTranslator(default_translator)
else:
log.debug(u'Could not find default_translator.')
if not options.no_error_form:
sys.excepthook = app.hookException
# Do not run method app.exec_() when running gui tests
if options.testing:
app.run(qt_args, testing=True)
# For gui tests we need access to window instances and their components
return app
else:
sys.exit(app.run(qt_args))
sys.excepthook = application.hook_exception
sys.exit(application.run(qt_args))

View File

@ -90,9 +90,8 @@ class ServiceItemAction(object):
Next = 3
def translate(context, text, comment=None,
encoding=QtCore.QCoreApplication.CodecForTr, n=-1,
translate=QtCore.QCoreApplication.translate):
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.
This abstracts the translation procedure so that we can change it if at a

View File

@ -45,6 +45,7 @@ from openlp.core.utils import AppLocation, delete_file
log = logging.getLogger(__name__)
def init_db(url, auto_flush=True, auto_commit=False):
"""
Initialise and return the session and metadata for a database
@ -60,8 +61,7 @@ def init_db(url, auto_flush=True, auto_commit=False):
"""
engine = create_engine(url, poolclass=NullPool)
metadata = MetaData(bind=engine)
session = scoped_session(sessionmaker(autoflush=auto_flush,
autocommit=auto_commit, bind=engine))
session = scoped_session(sessionmaker(autoflush=auto_flush, autocommit=auto_commit, bind=engine))
return session, metadata
@ -109,14 +109,17 @@ def upgrade_db(url, upgrade):
while hasattr(upgrade, u'upgrade_%d' % version):
log.debug(u'Running upgrade_%d', version)
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):
log.exception(u'Could not run database upgrade script '
'"upgrade_%s", upgrade process has been halted.', version)
break
version_meta.value = unicode(version)
session.commit()
version += 1
else:
version_meta = Metadata.populate(key=u'version', value=int(upgrade.__version__))
session.commit()
@ -156,6 +159,7 @@ class BaseModel(object):
instance.__setattr__(key, value)
return instance
class Manager(object):
"""
Provide generic object persistence management
@ -205,19 +209,17 @@ class Manager(object):
if db_ver > up_ver:
critical_error_message_box(
translate('OpenLP.Manager', 'Database Error'),
translate('OpenLP.Manager', 'The database being '
'loaded was created in a more recent version of '
'OpenLP. The database is version %d, while OpenLP '
'expects version %d. The database will not be loaded.'
'\n\nDatabase: %s') % \
(db_ver, up_ver, self.db_url)
translate('OpenLP.Manager', 'The database being loaded was created in a more recent version of '
'OpenLP. The database is version %d, while OpenLP expects version %d. The database will not '
'be loaded.\n\nDatabase: %s') % (db_ver, up_ver, self.db_url)
)
return
try:
self.session = init_schema(self.db_url)
except (SQLAlchemyError, DBAPIError):
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
)

View File

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

View File

@ -35,6 +35,7 @@ from PyQt4 import QtCore
log = logging.getLogger(__name__)
class EventReceiver(QtCore.QObject):
"""
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``
Changes the bottom status bar text on the mainwindow.
``openlp_warning_message``
Displays a standalone Warning Message.
``openlp_error_message``
Displays a standalone Error Message.
``openlp_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``
Version has changed so pop up window.
@ -120,29 +109,6 @@ class EventReceiver(QtCore.QObject):
``slidecontroller_live_stop_loop``
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**
``update_display_css``

View File

@ -31,7 +31,8 @@ Provide HTML Tag management and Formatting Tag access class
"""
import cPickle
from openlp.core.lib import translate, Settings
from openlp.core.lib import Settings, translate
class FormattingTags(object):
"""

View File

@ -207,8 +207,8 @@ sup {
</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
@ -233,7 +233,7 @@ def build_html(item, screen, islive, background, image=None,
width = screen[u'size'].width()
height = screen[u'size'].height()
theme = item.themedata
webkitvers = webkit_version()
webkit_ver = webkit_version()
# Image generated and poked in
if 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()
js_additions += plugin.getDisplayJavaScript()
html_additions += plugin.getDisplayHtml()
html = HTMLSRC % (build_background_css(item, width, height),
html = HTMLSRC % (
build_background_css(item, width, height),
css_additions,
build_footer_css(item, height),
build_lyrics_css(item, webkitvers),
u'true' if theme and theme.display_slide_transition and islive else u'false',
build_lyrics_css(item, webkit_ver),
u'true' if theme and theme.display_slide_transition and is_live else u'false',
js_additions,
bgimage_src, image_src,
html_additions,
build_lyrics_html(item, webkitvers))
build_lyrics_html(item, webkit_ver)
)
return html
def webkit_version():
"""
Return the Webkit version in use.
Note method added relatively recently, so return 0 if prior to this
"""
try:
webkitvers = float(QtWebKit.qWebKitVersion())
log.debug(u'Webkit version = %s' % webkitvers)
webkit_ver = float(QtWebKit.qWebKitVersion())
log.debug(u'Webkit version = %s' % webkit_ver)
except AttributeError:
webkitvers = 0
return webkitvers
webkit_ver = 0
return webkit_ver
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)
return background
def build_lyrics_css(item, webkitvers):
def build_lyrics_css(item, webkit_ver):
"""
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
# webkit-text-stroke was used. So use an offset text layer underneath.
# https://bugs.webkit.org/show_bug.cgi?id=19728
if webkitvers >= 533.3:
if webkit_ver >= 533.3:
lyricsmain += build_lyrics_outline_css(theme)
else:
outline = build_lyrics_outline_css(theme)
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;' % \
(int(theme.font_main_shadow_size) + (int(theme.font_main_outline_size) * 2),
theme.font_main_shadow_size)
@ -384,6 +389,7 @@ def build_lyrics_css(item, webkitvers):
lyrics_css = style % (lyricstable, lyrics, lyricsmain, outline, shadow)
return lyrics_css
def build_lyrics_outline_css(theme, is_shadow=False):
"""
Build the css which controls the theme outline
@ -407,6 +413,7 @@ def build_lyrics_outline_css(theme, is_shadow=False):
else:
return u''
def build_lyrics_format_css(theme, width, height):
"""
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; '
return lyrics
def build_lyrics_html(item, webkitvers):
"""
Build the HTML required to show the lyrics
@ -480,6 +488,7 @@ def build_lyrics_html(item, webkitvers):
u'class="lyricscell lyricsmain"></div></div>'
return lyrics
def build_footer_css(item, height):
"""
Build the display of the item footer

View File

@ -39,24 +39,31 @@ import Queue
from PyQt4 import QtCore
from openlp.core.lib import resize_image, image_to_byte, Receiver, Registry, ScreenList
from openlp.core.lib import Receiver, Registry, ScreenList, resize_image, image_to_byte
log = logging.getLogger(__name__)
class ImageThread(QtCore.QThread):
"""
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.
"""
def __init__(self, manager):
"""
Constructor for the thread class.
``manager``
The image manager.
"""
QtCore.QThread.__init__(self, None)
self.imageManager = manager
self.image_manager = manager
def run(self):
"""
Run the thread.
"""
self.imageManager._process()
self.image_manager._process()
class Priority(object):
@ -181,72 +188,75 @@ class ImageManager(QtCore.QObject):
log.info(u'Image Manager loaded')
def __init__(self):
"""
Constructor for the image manager.
"""
QtCore.QObject.__init__(self)
Registry().register(u'image_manager', self)
currentScreen = ScreenList().current
self.width = currentScreen[u'size'].width()
self.height = currentScreen[u'size'].height()
current_screen = ScreenList().current
self.width = current_screen[u'size'].width()
self.height = current_screen[u'size'].height()
self._cache = {}
self.imageThread = ImageThread(self)
self._conversionQueue = PriorityQueue()
self.stopManager = False
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_updated'), self.processUpdates)
self.image_thread = ImageThread(self)
self._conversion_queue = PriorityQueue()
self.stop_manager = False
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.
"""
log.debug(u'updateDisplay')
currentScreen = ScreenList().current
self.width = currentScreen[u'size'].width()
self.height = currentScreen[u'size'].height()
log.debug(u'update_display')
current_screen = ScreenList().current
self.width = current_screen[u'size'].width()
self.height = current_screen[u'size'].height()
# Mark the images as dirty for a rebuild by setting the image and byte
# stream to None.
for 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.
"""
log.debug(u'updateImages')
log.debug(u'update_images_border')
# Mark the images as dirty for a rebuild by setting the image and byte
# stream to None.
for image in self._cache.values():
if image.source == source:
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.
"""
log.debug(u'updateImage')
log.debug(u'update_image_border')
# Mark the image as dirty for a rebuild by setting the image and byte
# stream to None.
image = self._cache[(path, source)]
if image.source == source:
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``
and ``image_bytes`` attributes to None.
"""
image.image = 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
"""
# We want only one thread.
if not self.imageThread.isRunning():
self.imageThread.start()
if not self.image_thread.isRunning():
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
background thread to process it.
@ -254,9 +264,9 @@ class ImageManager(QtCore.QObject):
log.debug(u'getImage %s' % path)
image = self._cache[(path, source)]
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
self.processUpdates()
self.process_updates()
while image.image is None:
log.debug(u'getImage - waiting')
time.sleep(0.1)
@ -265,74 +275,74 @@ class ImageManager(QtCore.QObject):
# byte stream was not generated yet. However, we only need to do
# this, when the image was generated before it was requested
# (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
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
background thread to process it.
"""
log.debug(u'getImageBytes %s' % path)
log.debug(u'get_image_bytes %s' % path)
image = self._cache[(path, source)]
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
self.processUpdates()
self.process_updates()
while image.image_bytes is None:
log.debug(u'getImageBytes - waiting')
time.sleep(0.1)
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.
"""
log.debug(u'addImage %s' % path)
log.debug(u'add_image %s' % path)
if not (path, source) in self._cache:
image = Image(path, source, background)
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
# timestamp has changed.
for image in self._cache.values():
if os.path.exists(path):
if image.path == path and 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.
if not self.imageThread.isRunning():
self.imageThread.start()
if not self.image_thread.isRunning():
self.image_thread.start()
def _process(self):
"""
Controls the processing called from a ``QtCore.QThread``.
"""
log.debug(u'_process - started')
while not self._conversionQueue.empty() and not self.stopManager:
self._processCache()
while not self._conversion_queue.empty() and not self.stop_manager:
self._process_cache()
log.debug(u'_process - ended')
def _processCache(self):
def _process_cache(self):
"""
Actually does the work.
"""
log.debug(u'_processCache')
image = self._conversionQueue.get()[2]
image = self._conversion_queue.get()[2]
# Generate the QImage for the image.
if image.image is None:
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
# more important images first.
if image.priority == Priority.Normal:
self._conversionQueue.modify_priority(image, Priority.Lowest)
self._conversion_queue.modify_priority(image, Priority.Lowest)
return
# 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
# Normal priority. We stop here as we need to process more important
# images first.
elif image.priority == Priority.High:
self._conversionQueue.modify_priority(image, Priority.Low)
self._conversion_queue.modify_priority(image, Priority.Low)
return
# Generate the byte stream for the image.
if image.image_bytes is None:

View File

@ -35,6 +35,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver
class ListWidgetWithDnD(QtGui.QListWidget):
"""
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):
"""
Drag and drop event does not care what data is selected
as the recipient will use events to request the data move
just tell it what plugin to call
Drag and drop event does not care what data is selected as the recipient will use events to request the data
move just tell it what plugin to call
"""
if event.buttons() != QtCore.Qt.LeftButton:
event.ignore()
@ -75,12 +75,18 @@ class ListWidgetWithDnD(QtGui.QListWidget):
drag.start(QtCore.Qt.CopyAction)
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():
event.accept()
else:
event.ignore()
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():
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()

View File

@ -35,14 +35,14 @@ import re
from PyQt4 import QtCore, QtGui
from openlp.core.lib import OpenLPToolbar, ServiceItem, StringContent, build_icon, translate, Receiver, \
ListWidgetWithDnD, ServiceItemContext, Settings, Registry, UiStrings
from openlp.core.lib import OpenLPToolbar, ServiceItem, StringContent, Receiver, ListWidgetWithDnD, \
ServiceItemContext, Settings, Registry, UiStrings, build_icon, translate
from openlp.core.lib.searchedit import SearchEdit
from openlp.core.lib.ui import create_widget_action, critical_error_message_box
log = logging.getLogger(__name__)
class MediaManagerItem(QtGui.QWidget):
"""
MediaManagerItem is a helper widget for plugins.
@ -332,9 +332,9 @@ class MediaManagerItem(QtGui.QWidget):
Settings().value(self.settingsSection + u'/last directory'), self.onNewFileMasks)
log.info(u'New files(s) %s', files)
if files:
Receiver.send_message(u'cursor_busy')
self.application.set_busy_cursor()
self.validateAndLoad(files)
Receiver.send_message(u'cursor_normal')
self.application.set_normal_cursor()
def loadFile(self, files):
"""
@ -345,15 +345,15 @@ class MediaManagerItem(QtGui.QWidget):
"""
new_files = []
error_shown = False
for file in files:
type = file.split(u'.')[-1]
if type.lower() not in self.onNewFileMasks:
for file_name in files:
file_type = file_name.split(u'.')[-1]
if file_type.lower() not in self.onNewFileMasks:
if not error_shown:
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
else:
new_files.append(file)
new_files.append(file_name)
if new_files:
self.validateAndLoad(new_files)
@ -390,6 +390,9 @@ class MediaManagerItem(QtGui.QWidget):
translate('OpenLP.MediaManagerItem', 'Duplicate files were found on import and were ignored.'))
def contextMenu(self, point):
"""
Display a context menu
"""
item = self.listView.itemAt(point)
# Decide if we have to show the context menu or not.
if item is None:
@ -412,6 +415,9 @@ class MediaManagerItem(QtGui.QWidget):
return file_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')
def onNewClick(self):
@ -427,6 +433,9 @@ class MediaManagerItem(QtGui.QWidget):
pass
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')
def onFocus(self):
@ -438,6 +447,9 @@ class MediaManagerItem(QtGui.QWidget):
def generateSlideData(self, serviceItem, item=None, xmlVersion=False, remote=False,
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')
def onDoubleClicked(self):
@ -486,6 +498,9 @@ class MediaManagerItem(QtGui.QWidget):
self.goLive()
def goLive(self, item_id=None, remote=False):
"""
Make the currently selected item go live.
"""
log.debug(u'%s Live requested', self.plugin.name)
item = None
if item_id:
@ -499,6 +514,9 @@ class MediaManagerItem(QtGui.QWidget):
self.live_controller.add_service_item(serviceItem)
def createItemFromId(self, item_id):
"""
Create a media item from an item id.
"""
item = QtGui.QListWidgetItem()
item.setData(QtCore.Qt.UserRole, item_id)
return item
@ -522,6 +540,9 @@ class MediaManagerItem(QtGui.QWidget):
self.addToService(item)
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)
if serviceItem:
serviceItem.from_plugin = False
@ -688,3 +709,22 @@ class MediaManagerItem(QtGui.QWidget):
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

@ -38,6 +38,7 @@ from openlp.core.utils import get_application_version
log = logging.getLogger(__name__)
class PluginStatus(object):
"""
Defines the status of the plugin
@ -294,7 +295,7 @@ class Plugin(QtCore.QObject):
if self.mediaItem:
self.main_window.mediaDockManager.remove_dock(self.mediaItem)
def appStartup(self):
def app_startup(self):
"""
Perform tasks on application startup
"""
@ -320,7 +321,6 @@ class Plugin(QtCore.QObject):
Settings().setValue(u'%s/%s files' % (self.settingsSection, self.name), loaded_list)
settings.endGroup()
def usesTheme(self, theme):
"""
Called to find out if a plugin is currently using a theme.
@ -409,6 +409,12 @@ class Plugin(QtCore.QObject):
"""
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
@ -419,3 +425,12 @@ class Plugin(QtCore.QObject):
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

@ -37,6 +37,7 @@ from openlp.core.lib import Plugin, PluginStatus, Registry
log = logging.getLogger(__name__)
class PluginManager(object):
"""
This is the Plugin manager, which loads all the plugins,
@ -211,3 +212,13 @@ class PluginManager(object):
if plugin.name == name:
return plugin
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

@ -34,6 +34,7 @@ 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
@ -43,6 +44,9 @@ class Registry(object):
__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__
@ -61,7 +65,6 @@ class Registry(object):
registry.running_under_test = True
return registry
def get(self, key):
"""
Extracts the registry value from the list based on the key passed in
@ -87,10 +90,9 @@ class Registry(object):
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 == False:
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]
del self.service_list[key]

View File

@ -31,8 +31,8 @@ import logging
from PyQt4 import QtGui, QtCore, QtWebKit
from openlp.core.lib import ServiceItem, expand_tags, build_lyrics_format_css, build_lyrics_outline_css, Receiver, \
ItemCapabilities, FormattingTags, ImageSource, Registry, ScreenList
from openlp.core.lib import FormattingTags, ImageSource, ItemCapabilities, Receiver, Registry, ScreenList, \
ServiceItem, expand_tags, build_lyrics_format_css, build_lyrics_outline_css
from openlp.core.lib.theme import ThemeLevel
from openlp.core.ui import MainDisplay
@ -128,7 +128,7 @@ class Renderer(object):
The theme name.
"""
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)
footer_rect = self.get_footer_rectangle(theme_data)
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]
# if No file do not update cache
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))
def pre_render(self, override_theme_data=None):
@ -238,7 +238,7 @@ class Renderer(object):
serviceItem.raw_footer = FOOTER
# if No file do not update cache
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))
theme_data, main, footer = self.pre_render(theme_data)
@ -315,7 +315,7 @@ class Renderer(object):
if text_contains_split:
text = slides[-1] + u'\n[---]\n' + text
else:
text = slides[-1] + u'\n'+ text
text = slides[-1] + u'\n' + text
text = text.replace(u'<br>', u'\n')
else:
pages.extend(slides)
@ -543,7 +543,7 @@ class Renderer(object):
end_tags.reverse()
# Remove the indexes.
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):
"""
@ -661,4 +661,5 @@ class Renderer(object):
self._theme_manager = Registry().get(u'theme_manager')
return self._theme_manager
theme_manager = property(_get_theme_manager)
theme_manager = property(_get_theme_manager)

View File

@ -37,7 +37,6 @@ from PyQt4 import QtCore
from openlp.core.lib import Receiver, translate
log = logging.getLogger(__name__)
@ -51,6 +50,9 @@ class ScreenList(object):
__instance__ = None
def __new__(cls):
"""
Re-implement __new__ to create a true singleton.
"""
if not cls.__instance__:
cls.__instance__ = object.__new__(cls)
return cls.__instance__
@ -137,8 +139,7 @@ class ScreenList(object):
"""
screen_list = []
for screen in self.screen_list:
screen_name = u'%s %d' % (translate('OpenLP.ScreenList', 'Screen'),
screen[u'number'] + 1)
screen_name = u'%s %d' % (translate('OpenLP.ScreenList', 'Screen'), screen[u'number'] + 1)
if screen[u'primary']:
screen_name = u'%s (%s)' % (screen_name, translate('OpenLP.ScreenList', 'primary'))
screen_list.append(screen_name)
@ -235,8 +236,7 @@ class ScreenList(object):
y = window.y() + (window.height() / 2)
for screen in self.screen_list:
size = screen[u'size']
if x >= size.x() and x <= (size.x() + size.width()) and \
y >= size.y() and y <= (size.y() + size.height()):
if x >= size.x() and x <= (size.x() + size.width()) and y >= size.y() and y <= (size.y() + size.height()):
return screen[u'number']
def load_screen_settings(self):

View File

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

View File

@ -39,10 +39,11 @@ import uuid
from PyQt4 import QtGui
from openlp.core.lib import build_icon, clean_tags, expand_tags, translate, ImageSource, Settings, Registry
from openlp.core.lib import ImageSource, Settings, Registry, build_icon, clean_tags, expand_tags, translate
log = logging.getLogger(__name__)
class ServiceItemType(object):
"""
Defines the type of service item
@ -292,7 +293,7 @@ class ServiceItem(object):
self.image_border = background
self.service_item_type = ServiceItemType.Image
self._raw_frames.append({u'title': title, u'path': path})
self.image_manager.addImage(path, ImageSource.ImagePlugin, self.image_border)
self.image_manager.add_image(path, ImageSource.ImagePlugin, self.image_border)
self._new_item()
def add_from_text(self, raw_slide, verse_tag=None):
@ -607,7 +608,7 @@ class ServiceItem(object):
``theme``
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._new_item()
self.render()
@ -662,4 +663,4 @@ class ServiceItem(object):
self._image_manager = Registry().get(u'image_manager')
return self._image_manager
image_manager = property(_get_image_manager)
image_manager = property(_get_image_manager)

View File

@ -74,7 +74,8 @@ class Settings(QtCore.QSettings):
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.
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::
@ -86,65 +87,68 @@ class Settings(QtCore.QSettings):
So, if the type of the old value is bool, then there must be two rules.
"""
__default_settings__ = {
u'advanced/x11 bypass wm': X11_BYPASS_DEFAULT,
u'advanced/default service enabled': True,
u'advanced/enable exit confirmation': True,
u'advanced/save current plugin': False,
u'advanced/single click preview': False,
# 7 stands for now, 0 to 6 is Monday to Sunday.
u'advanced/default service day': 7,
u'advanced/max recent files': 20,
u'advanced/is portable': False,
u'advanced/hide mouse': True,
u'advanced/add page break': False,
u'advanced/alternate rows': not sys.platform.startswith(u'win'),
u'advanced/current media plugin': -1,
u'advanced/double click live': False,
u'advanced/data path': u'',
u'advanced/default service hour': 11,
u'advanced/default color': u'#ffffff',
u'advanced/default image': u':/graphics/openlp-splash-screen.png',
u'advanced/expand service item': False,
u'advanced/recent file count': 4,
u'advanced/default service name': UiStrings().DefaultServiceName,
# 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/slide limits': SlideLimits.End,
u'advanced/print slide text': False,
u'advanced/add page break': False,
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/display size': 0,
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/update check': True,
u'general/language': u'[en]',
u'general/songselect password': u'',
u'general/recent files': [],
u'general/save prompt': False,
u'general/auto preview': False,
u'general/view mode': u'default',
u'general/auto open': False,
u'general/enable slide loop': True,
u'general/show splash': True,
u'general/screen blank': False,
# The oder display settings (display position and dimensions) are defined in the ScreenList class due to crycle
# dependency.
u'general/override position': False,
u'general/loop delay': 5,
u'general/songselect username': u'',
u'general/audio repeat list': False,
u'general/auto unblank': False,
u'general/display on monitor': True,
u'general/audio start paused': True,
# 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/blank warning': False,
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/service theme': u'',
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/file_date_created': datetime.datetime.now().strftime("%Y-%m-%d %H:%M"),
u'SettingsImport/version': u'',
u'shortcuts/aboutItem': [QtGui.QKeySequence(u'Ctrl+F1')],
u'shortcuts/audioPauseItem': [],
@ -213,39 +217,37 @@ class Settings(QtCore.QSettings):
u'shortcuts/viewLivePanel': [QtGui.QKeySequence(u'F12')],
u'shortcuts/viewServiceManagerItem': [QtGui.QKeySequence(u'F9')],
u'shortcuts/webSiteItem': [],
u'themes/theme level': ThemeLevel.Song,
u'themes/global theme': u'',
u'themes/last directory': u'',
u'themes/last directory export': u'',
u'themes/last directory import': u'',
u'user interface/main window position': QtCore.QPoint(0, 0),
u'user interface/preview panel': True,
u'themes/theme level': ThemeLevel.Song,
u'user interface/live panel': True,
u'user interface/main window geometry': QtCore.QByteArray(),
u'user interface/preview splitter geometry': QtCore.QByteArray(),
u'user interface/lock panel': False,
u'user interface/mainwindow splitter geometry': QtCore.QByteArray(),
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'media/players': u'webkit',
u'media/override player': QtCore.Qt.Unchecked,
# Old settings (not used anymore). Have to be here, so that old setting.config backups can be imported.
u'advanced/stylesheet fix': u'',
u'servicemanager/last directory': u''
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'servicemanager/last directory', u'', []),
(u'songs/last directory 1', u'songs/last directory import', []),
(u'bibles/last directory 1', u'bibles/last directory import', []),
(u'songusage/last directory 1', u'songusage/last directory export', []),
(u'shortcuts/makeLive', u'shortcuts/make_live', []),
(u'advanced/stylesheet fix', u'', []),
(u'media/background color', u'players/background color', [])
(u'user interface/mainwindow splitter geometry', u'user interface/main window splitter geometry', []),
(u'shortcuts/makeLive', u'shortcuts/make_live', [])
]
@staticmethod
@ -277,6 +279,9 @@ class Settings(QtCore.QSettings):
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:
@ -293,6 +298,11 @@ class Settings(QtCore.QSettings):
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
@ -308,8 +318,6 @@ class Settings(QtCore.QSettings):
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.
**Note**, this method only converts a few types and might need to be extended if a certain type is missing!
``key``
The key to return the value from.
"""
@ -319,6 +327,21 @@ class Settings(QtCore.QSettings):
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():
@ -341,4 +364,3 @@ class Settings(QtCore.QSettings):
if isinstance(default_value, int):
return int(setting)
return setting

View File

@ -33,9 +33,6 @@ format.
"""
import os
from PyQt4 import QtCore
from openlp.core.lib import Settings
from openlp.core.utils import AppLocation

View File

@ -26,9 +26,16 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# 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 openlp.core.lib import Registry
class SettingsTab(QtGui.QWidget):
"""
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
"""
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 #
# 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 re
@ -47,11 +51,15 @@ from openlp.core.lib.ui import create_action
log = logging.getLogger(__name__)
class SpellTextEdit(QtGui.QPlainTextEdit):
"""
Spell checking widget based on QPlanTextEdit.
"""
def __init__(self, parent=None, formattingTagsAllowed=True):
"""
Constructor.
"""
global ENCHANT_AVAILABLE
QtGui.QPlainTextEdit.__init__(self, parent)
self.formattingTagsAllowed = formattingTagsAllowed
@ -171,6 +179,9 @@ class Highlighter(QtGui.QSyntaxHighlighter):
WORDS = u'(?iu)[\w\']+'
def __init__(self, *args):
"""
Constructor
"""
QtGui.QSyntaxHighlighter.__init__(self, *args)
self.spellingDictionary = None
@ -197,5 +208,8 @@ class SpellAction(QtGui.QAction):
correct = QtCore.pyqtSignal(unicode)
def __init__(self, *args):
"""
Constructor
"""
QtGui.QAction.__init__(self, *args)
self.triggered.connect(lambda x: self.correct.emit(self.text()))

View File

@ -86,6 +86,7 @@ BLANK_THEME_XML = \
</theme>
'''
class ThemeLevel(object):
"""
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]+)')
SECOND_CAMEL_REGEX = re.compile(u'([a-z0-9])([A-Z])')
def __init__(self):
"""
Initialise the theme object.
@ -608,13 +610,15 @@ class ThemeXML(object):
self.add_background_gradient(
self.background_start_color,
self.background_end_color,
self.background_direction)
self.background_direction
)
elif self.background_type == BackgroundType.to_string(BackgroundType.Image):
filename = os.path.split(self.background_filename)[1]
self.add_background_image(filename, self.background_border_color)
elif self.background_type == BackgroundType.to_string(BackgroundType.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_size,
self.font_main_override, u'main',
@ -630,14 +634,16 @@ class ThemeXML(object):
self.font_main_outline_size,
self.font_main_shadow,
self.font_main_shadow_color,
self.font_main_shadow_size)
self.add_font(self.font_footer_name,
self.font_main_shadow_size
)
self.add_font(
self.font_footer_name,
self.font_footer_color,
self.font_footer_size,
self.font_footer_override, u'footer',
self.font_footer_bold,
self.font_footer_italics,
0, # line adjustment
0, # line adjustment
self.font_footer_x,
self.font_footer_y,
self.font_footer_width,
@ -647,7 +653,10 @@ class ThemeXML(object):
self.font_footer_outline_size,
self.font_footer_shadow,
self.font_footer_shadow_color,
self.font_footer_shadow_size)
self.add_display(self.display_horizontal_align,
self.font_footer_shadow_size
)
self.add_display(
self.display_horizontal_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__)
class OpenLPToolbar(QtGui.QToolBar):
"""
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)
else:
log.warn(u'No handle "%s" in actions list.', unicode(handle))

View File

@ -33,7 +33,7 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, translate, Receiver, UiStrings
from openlp.core.lib import Receiver, UiStrings, build_icon, translate
from openlp.core.utils.actions import ActionList
@ -67,7 +67,7 @@ def add_welcome_page(parent, image):
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
``rejected()`` signals of the button box are connected with the dialogs
@ -88,6 +88,8 @@ def create_button_box(dialog, name, standard_buttons, custom_buttons=[]):
QtGui.QAbstractButton it is added with QDialogButtonBox.ActionRole.
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
if u'ok' in standard_buttons:
buttons |= QtGui.QDialogButtonBox.Ok

View File

@ -111,8 +111,8 @@ class UiStrings(object):
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.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')
@ -144,4 +144,3 @@ class UiStrings(object):
self.Version = translate('OpenLP.Ui', 'Version')
self.View = translate('OpenLP.Ui', 'View')
self.ViewMode = translate('OpenLP.Ui', 'View Mode')

View File

@ -32,3 +32,5 @@ OpenLP when displaying a song or a scripture.
"""
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
DELPHI_COLORS = {
u'clAqua': 0x00FFFF, u'clBlack': 0x000000, u'clBlue': 0x0000FF,
u'clFuchsia': 0xFF00FF, 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'clAqua': 0x00FFFF,
u'clBlack': 0x000000,
u'clBlue': 0x0000FF,
u'clFuchsia': 0xFF00FF,
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
}
@ -66,6 +76,7 @@ BLANK_STYLE_XML = \
</Theme>
'''
class Theme(object):
"""
Provide a class wrapper storing data from an XML theme
@ -164,6 +175,7 @@ class Theme(object):
* ``0`` - normal
* ``1`` - lyrics
"""
def __init__(self, xml):
"""
Initialise a theme with data from xml
@ -205,10 +217,12 @@ class Theme(object):
val = element_text
# strings need special handling to sort the colours out
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:
val = int(element_text[1:], 16)
except ValueError: # nope
except ValueError:
# nope
pass
elif element_text in DELPHI_COLORS:
val = DELPHI_COLORS[element_text]
@ -222,9 +236,9 @@ class Theme(object):
isinstance(val, int))):
# convert to a wx.Colour
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:
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)
def __str__(self):

View File

@ -31,7 +31,6 @@ The :mod:`ui` module provides the core user interface for OpenLP
"""
class HideMode(object):
"""
This is an enumeration class which specifies the different modes of hiding the display.
@ -101,6 +100,8 @@ from mediadockmanager import MediaDockManager
from servicemanager import ServiceManager
from thememanager import ThemeManager
__all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainDisplay',
'SlideController', 'ServiceManager', 'ThemeManager', 'MediaDockManager',
'ServiceItemEditForm', 'FirstTimeForm']
__all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainDisplay', 'SlideController', 'ServiceManager',
'ThemeManager', 'MediaDockManager', 'ServiceItemEditForm', 'FirstTimeForm', 'FirstTimeLanguageForm', 'ThemeForm',
'ThemeLayoutForm', 'FileRenameForm', 'StartTimeForm', 'MainDisplay', 'Display', 'ServiceNoteForm',
'SlideController', 'DisplayController', 'GeneralTab', 'ThemesTab', 'AdvancedTab', 'PluginForm',
'FormattingTagForm', 'ShortcutListForm']

View File

@ -29,12 +29,19 @@
from PyQt4 import QtGui
from openlp.core.lib import build_icon, translate, UiStrings
from openlp.core.lib import UiStrings, build_icon, translate
from openlp.core.lib.ui import create_button, create_button_box
class Ui_AboutDialog(object):
"""
The actual GUI widgets for the About form.
"""
def setupUi(self, aboutDialog):
"""
Set up the UI for the dialog.
"""
aboutDialog.setObjectName(u'aboutDialog')
aboutDialog.setWindowIcon(build_icon(u':/icon/openlp-logo-16x16.png'))
self.aboutDialogLayout = QtGui.QVBoxLayout(aboutDialog)
@ -80,6 +87,9 @@ class Ui_AboutDialog(object):
self.aboutNotebook.setCurrentIndex(0)
def retranslateUi(self, aboutDialog):
"""
Dynamically translate the UI.
"""
aboutDialog.setWindowTitle(u'%s OpenLP' % UiStrings().About)
self.aboutTextEdit.setPlainText(translate('OpenLP.AboutForm',
'OpenLP <version><revision> - Open Source Lyrics '
@ -134,17 +144,17 @@ class Ui_AboutDialog(object):
u'en_ZA': [u'Raoul "superfly" Snyman',
u'Johan "nuvolari" Mynhardt'],
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'fi': [u'Jori "joribu" Brander', u'Tobbe "tobbeb" Bildo'],
u'fr': [u'Stephan\xe9 "stbrunner" Brunner', u'Jeremie "jnau05"',
u'Carl "carl.fischer" Fischer'],
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'nb': [u'Atle "pendlaren" Weibell', u'Frode "frodus" Woldsund'],
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'Gustavo Bim', u'Rog\xeanio Bel\xe9m', u'Samuel'
u'Simon "samscudder" Scudder', u'Van Der Fran'],
@ -260,7 +270,7 @@ class Ui_AboutDialog(object):
u'\n '.join(documentors)))
self.aboutNotebook.setTabText(self.aboutNotebook.indexOf(self.creditsTab),
translate('OpenLP.AboutForm', 'Credits'))
copyright = translate('OpenLP.AboutForm',
copyright_note = translate('OpenLP.AboutForm',
'Copyright \xa9 2004-2013 %s\n'
'Portions copyright \xa9 2004-2013 %s') % (u'Raoul Snyman',
u'Tim Bentley, Gerald Britton, Jonathan Corwin, Samuel Findlay, '
@ -652,7 +662,7 @@ class Ui_AboutDialog(object):
'linking proprietary applications with the library. If this is '
'what you want to do, use the GNU Lesser General Public 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),
translate('OpenLP.AboutForm', 'License'))
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 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The About dialog.
"""
from PyQt4 import QtCore, QtGui
@ -33,6 +36,7 @@ from aboutdialog import Ui_AboutDialog
from openlp.core.lib import translate
from openlp.core.utils import get_application_version
class AboutForm(QtGui.QDialog, Ui_AboutDialog):
"""
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 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The GUI widgets of the exception dialog.
"""
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate
from openlp.core.lib.ui import create_button, create_button_box
class Ui_ExceptionDialog(object):
"""
The GUI widgets of the exception dialog.
"""
def setupUi(self, exceptionDialog):
"""
Set up the UI.
"""
exceptionDialog.setObjectName(u'exceptionDialog')
self.exceptionLayout = QtGui.QVBoxLayout(exceptionDialog)
self.exceptionLayout.setObjectName(u'exceptionLayout')
@ -66,7 +76,7 @@ class Ui_ExceptionDialog(object):
self.exceptionLayout.addWidget(self.exceptionTextEdit)
self.sendReportButton = create_button(exceptionDialog, u'sendReportButton',
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)
self.attachFileButton = create_button(exceptionDialog, u'attachFileButton',
icon=u':/general/general_open.png', click=self.onAttachFileButtonClicked)
@ -79,6 +89,9 @@ class Ui_ExceptionDialog(object):
QtCore.SIGNAL(u'textChanged()'), self.onDescriptionUpdated)
def retranslateUi(self, exceptionDialog):
"""
Translate the widgets on the fly.
"""
exceptionDialog.setWindowTitle(translate('OpenLP.ExceptionDialog', 'Error Occurred'))
self.descriptionExplanation.setText(translate('OpenLP.ExceptionDialog',
'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 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The actual exception dialog form.
"""
import logging
import re
import os
@ -85,29 +88,39 @@ except AttributeError:
WEBKIT_VERSION = u'-'
from openlp.core.lib import translate, UiStrings, Settings
from openlp.core.lib import UiStrings, Settings, translate
from openlp.core.utils import get_application_version
from exceptiondialog import Ui_ExceptionDialog
log = logging.getLogger(__name__)
class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
"""
The exception dialog
"""
def __init__(self, parent):
"""
Constructor.
"""
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
self.settingsSection = u'crashreport'
def exec_(self):
"""
Show the dialog.
"""
self.descriptionTextEdit.setPlainText(u'')
self.onDescriptionUpdated()
self.fileAttachment = None
return QtGui.QDialog.exec_(self)
def _createReport(self):
"""
Create an exception report.
"""
openlp_version = get_application_version()
description = self.descriptionTextEdit.toPlainText()
traceback = self.exceptionTextEdit.toPlainText()
@ -128,9 +141,9 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
u'pyUNO bridge: %s\n' % UNO_VERSION
if platform.system() == u'Linux':
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'):
system = system + u'Desktop: GNOME\n'
system += u'Desktop: GNOME\n'
return (openlp_version, description, traceback, system, libraries)
def onSaveReportButtonClicked(self):
@ -199,6 +212,9 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
QtGui.QDesktopServices.openUrl(mailto_url)
def onDescriptionUpdated(self):
"""
Update the minimum number of characters needed in the description.
"""
count = int(20 - len(self.descriptionTextEdit.toPlainText()))
if count < 0:
count = 0
@ -209,6 +225,9 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
translate('OpenLP.ExceptionDialog', 'Description characters to enter : %s') % count)
def onAttachFileButtonClicked(self):
"""
Attache files to the bug report e-mail.
"""
files = QtGui.QFileDialog.getOpenFileName(
self, translate('ImagePlugin.ExceptionDialog', 'Select Attachment'),
Settings().value(self.settingsSection + u'/last directory'), u'%s (*.*) (*)' % UiStrings().AllFiles)
@ -217,6 +236,8 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
self.fileAttachment = unicode(files)
def __buttonState(self, state):
"""
Toggle the button state.
"""
self.saveReportButton.setEnabled(state)
self.sendReportButton.setEnabled(state)

View File

@ -26,14 +26,23 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The UI widgets for the rename dialog
"""
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate
from openlp.core.lib.ui import create_button_box
class Ui_FileRenameDialog(object):
"""
The UI widgets for the rename dialog
"""
def setupUi(self, fileRenameDialog):
"""
Set up the UI
"""
fileRenameDialog.setObjectName(u'fileRenameDialog')
fileRenameDialog.resize(300, 10)
self.dialogLayout = QtGui.QGridLayout(fileRenameDialog)
@ -51,4 +60,7 @@ class Ui_FileRenameDialog(object):
self.setMaximumHeight(self.sizeHint().height())
def retranslateUi(self, fileRenameDialog):
"""
Translate the UI on the fly.
"""
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 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The file rename dialog.
"""
from PyQt4 import QtGui
@ -33,11 +36,15 @@ from filerenamedialog import Ui_FileRenameDialog
from openlp.core.lib import translate
class FileRenameForm(QtGui.QDialog, Ui_FileRenameDialog):
"""
The exception dialog
The file rename dialog
"""
def __init__(self, parent):
"""
Constructor
"""
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)

View File

@ -26,7 +26,9 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
This module contains the first time wizard.
"""
import io
import logging
import os
@ -39,26 +41,27 @@ from ConfigParser import SafeConfigParser
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate, PluginStatus, Receiver, build_icon, check_directory_exists, Settings
from openlp.core.utils import get_web_page, AppLocation, get_filesystem_encoding
from openlp.core.lib import PluginStatus, Receiver, Settings, Registry, build_icon, check_directory_exists, translate
from openlp.core.utils import AppLocation, get_web_page, get_filesystem_encoding
from firsttimewizard import Ui_FirstTimeWizard, FirstTimePage
log = logging.getLogger(__name__)
class ThemeScreenshotThread(QtCore.QThread):
"""
This thread downloads the theme screenshots.
"""
def __init__(self, parent):
QtCore.QThread.__init__(self, parent)
def run(self):
"""
Overridden method to run the thread.
"""
themes = self.parent().config.get(u'themes', u'files')
themes = themes.split(u',')
config = self.parent().config
for theme in themes:
# Stop if the wizard has been cancelled.
if self.parent().downloadCancelled:
if self.parent().was_download_cancelled:
return
title = config.get(u'theme_%s' % theme, u'title')
filename = config.get(u'theme_%s' % theme, u'filename')
@ -79,18 +82,21 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
log.info(u'ThemeWizardForm loaded')
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.screens = screens
# check to see if we have web access
self.web = u'http://openlp.org/files/frw/'
self.config = SafeConfigParser()
self.webAccess = get_web_page(u'%s%s' % (self.web, u'download.cfg'))
if self.webAccess:
files = self.webAccess.read()
self.web_access = get_web_page(u'%s%s' % (self.web, u'download.cfg'))
if self.web_access:
files = self.web_access.read()
self.config.readfp(io.BytesIO(files))
self.updateScreenListCombo()
self.downloadCancelled = False
self.was_download_cancelled = False
self.downloading = translate('OpenLP.FirstTimeWizard', 'Downloading %s...')
QtCore.QObject.connect(self.cancelButton, QtCore.SIGNAL('clicked()'),
self.onCancelButtonClicked)
@ -112,13 +118,12 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
Set up display at start of theme edit.
"""
self.restart()
check_directory_exists(os.path.join(
unicode(gettempdir(), get_filesystem_encoding()), u'openlp'))
check_directory_exists(os.path.join(unicode(gettempdir(), get_filesystem_encoding()), u'openlp'))
self.noInternetFinishButton.setVisible(False)
# Check if this is a re-run of the wizard.
self.hasRunWizard = Settings().value(u'general/has run wizard')
# Sort out internet access for downloads
if self.webAccess:
if self.web_access:
songs = self.config.get(u'songs', u'languages')
songs = songs.split(u',')
for song in songs:
@ -146,15 +151,15 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
# Download the theme screenshots.
self.themeScreenshotThread = ThemeScreenshotThread(self)
self.themeScreenshotThread.start()
Receiver.send_message(u'cursor_normal')
self.application.set_normal_cursor()
def nextId(self):
"""
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 not self.webAccess:
if not self.web_access:
return FirstTimePage.NoInternet
else:
return FirstTimePage.Songs
@ -163,14 +168,13 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
elif self.currentId() == FirstTimePage.NoInternet:
return FirstTimePage.Progress
elif self.currentId() == FirstTimePage.Themes:
Receiver.send_message(u'cursor_busy')
Receiver.send_message(u'openlp_process_events')
self.application.set_busy_cursor()
while not self.themeScreenshotThread.isFinished():
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.
self._buildThemeScreenshots()
Receiver.send_message(u'cursor_normal')
self.application.set_normal_cursor()
return FirstTimePage.Defaults
else:
return self.currentId() + 1
@ -181,7 +185,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
"""
# Keep track of the page we are at. Triggering "Cancel" causes pageId
# to be a -1.
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
if pageId != -1:
self.lastId = pageId
if pageId == FirstTimePage.Plugins:
@ -198,7 +202,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self.themeComboBox.addItem(item.text())
if self.hasRunWizard:
# 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)
if index == -1:
self.themeComboBox.addItem(theme)
@ -213,16 +217,15 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
if self.hasRunWizard:
self.cancelButton.setVisible(False)
elif pageId == FirstTimePage.Progress:
Receiver.send_message(u'cursor_busy')
self.application.set_busy_cursor()
self.repaint()
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
# Try to give the wizard a chance to redraw itself
time.sleep(0.2)
self._preWizard()
self._performWizard()
self._postWizard()
Receiver.send_message(u'cursor_normal')
Receiver.send_message(u'openlp_process_events')
self.application.set_normal_cursor()
def updateScreenListCombo(self):
"""
@ -237,23 +240,21 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
"""
Process the triggering of the cancel button.
"""
if self.lastId == FirstTimePage.NoInternet or \
(self.lastId <= FirstTimePage.Plugins and not self.hasRunWizard):
if self.lastId == FirstTimePage.NoInternet or (self.lastId <= FirstTimePage.Plugins and not self.hasRunWizard):
QtCore.QCoreApplication.exit()
sys.exit()
self.downloadCancelled = True
self.was_download_cancelled = True
while self.themeScreenshotThread.isRunning():
time.sleep(0.1)
Receiver.send_message(u'cursor_normal')
self.application.set_normal_cursor()
def onNoInternetFinishButtonClicked(self):
"""
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()
Receiver.send_message(u'cursor_normal')
Receiver.send_message(u'openlp_process_events')
self.application.set_normal_cursor()
Settings().setValue(u'general/has run wizard', True)
self.close()
@ -267,7 +268,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
urlfile = urllib2.urlopen(url)
filename = open(fpath, "wb")
# Download until finished or canceled.
while not self.downloadCancelled:
while not self.was_download_cancelled:
data = urlfile.read(block_size)
if not data:
break
@ -276,7 +277,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self._downloadProgress(block_count, block_size)
filename.close()
# Delete file if cancelled, it may be a partial file.
if self.downloadCancelled:
if self.was_download_cancelled:
os.remove(fpath)
def _buildThemeScreenshots(self):
@ -297,11 +298,20 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
screenshot)))
def _getFileSize(self, url):
"""
Get the size of a file.
``url``
The URL of the file we want to download.
"""
site = urllib.urlopen(url)
meta = site.info()
return int(meta.getheaders("Content-Length")[0])
def _downloadProgress(self, count, block_size):
"""
Calculate and display the download progress.
"""
increment = (count * block_size) - self.previous_size
self._incrementProgressBar(None, increment)
self.previous_size = count * block_size
@ -320,7 +330,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self.progressLabel.setText(status_text)
if increment > 0:
self.progressBar.setValue(self.progressBar.value() + increment)
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
def _preWizard(self):
"""
@ -328,10 +338,10 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
"""
self.max_progress = 0
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
for i in xrange(self.songsListWidget.count()):
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
item = self.songsListWidget.item(i)
if item.checkState() == QtCore.Qt.Checked:
filename = item.data(QtCore.Qt.UserRole)
@ -340,7 +350,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
# Loop through the Bibles list and increase for each selected item
iterator = QtGui.QTreeWidgetItemIterator(self.biblesTreeWidget)
while iterator.value():
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
item = iterator.value()
if item.parent() and item.checkState(0) == QtCore.Qt.Checked:
filename = item.data(0, QtCore.Qt.UserRole)
@ -349,7 +359,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
iterator += 1
# Loop through the themes list and increase for each selected item
for i in xrange(self.themesListWidget.count()):
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
item = self.themesListWidget.item(i)
if item.checkState() == QtCore.Qt.Checked:
filename = item.data(QtCore.Qt.UserRole)
@ -357,7 +367,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self.max_progress += size
if self.max_progress:
# 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.setMinimum(0)
self.progressBar.setMaximum(self.max_progress)
@ -369,7 +379,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self.progressPage.setTitle(translate('OpenLP.FirstTimeWizard', 'Setting Up'))
self.progressPage.setSubTitle(u'Setup complete.')
self.repaint()
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
# Try to give the wizard a chance to repaint itself
time.sleep(0.1)
@ -396,7 +406,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self.finishButton.setEnabled(True)
self.cancelButton.setVisible(False)
self.nextButton.setVisible(False)
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
def _performWizard(self):
"""
@ -416,7 +426,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self._setPluginStatus(self.customCheckBox, u'custom/status')
self._setPluginStatus(self.songUsageCheckBox, u'songusage/status')
self._setPluginStatus(self.alertCheckBox, u'alerts/status')
if self.webAccess:
if self.web_access:
# Build directories for downloads
songs_destination = os.path.join(
unicode(gettempdir(), get_filesystem_encoding()), u'openlp')
@ -459,5 +469,28 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
Settings().setValue(u'themes/global theme', self.themeComboBox.currentText())
def _setPluginStatus(self, field, tag):
"""
Set the status of a plugin.
"""
status = PluginStatus.Active if field.checkState() == QtCore.Qt.Checked else PluginStatus.Inactive
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,14 +26,23 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The UI widgets of the language selection dialog.
"""
from PyQt4 import QtGui
from openlp.core.lib import translate
from openlp.core.lib.ui import create_button_box
class Ui_FirstTimeLanguageDialog(object):
"""
The UI widgets of the language selection dialog.
"""
def setupUi(self, languageDialog):
"""
Set up the UI.
"""
languageDialog.setObjectName(u'languageDialog')
languageDialog.resize(300, 50)
self.dialogLayout = QtGui.QVBoxLayout(languageDialog)
@ -59,6 +68,9 @@ class Ui_FirstTimeLanguageDialog(object):
self.setMaximumHeight(self.sizeHint().height())
def retranslateUi(self, languageDialog):
"""
Translate the UI on the fly.
"""
self.setWindowTitle(translate('OpenLP.FirstTimeLanguageForm', 'Select Translation'))
self.infoLabel.setText(
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 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The language selection dialog.
"""
from PyQt4 import QtGui
from openlp.core.lib.ui import create_action
from openlp.core.utils import LanguageManager
from firsttimelanguagedialog import Ui_FirstTimeLanguageDialog
class FirstTimeLanguageForm(QtGui.QDialog, Ui_FirstTimeLanguageDialog):
"""
The exception dialog
The language selection dialog.
"""
def __init__(self, parent=None):
"""
Constructor
"""
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
self.qmList = LanguageManager.get_qm_list()
@ -52,6 +58,9 @@ class FirstTimeLanguageForm(QtGui.QDialog, Ui_FirstTimeLanguageDialog):
return QtGui.QDialog.exec_(self)
def accept(self):
"""
Run when the dialog is OKed.
"""
# It's the first row so must be Automatic
if self.languageComboBox.currentIndex() == 0:
LanguageManager.auto_language = True
@ -63,6 +72,9 @@ class FirstTimeLanguageForm(QtGui.QDialog, Ui_FirstTimeLanguageDialog):
return QtGui.QDialog.accept(self)
def reject(self):
"""
Run when the dialog is canceled.
"""
LanguageManager.auto_language = True
LanguageManager.set_language(False, False)
return QtGui.QDialog.reject(self)

View File

@ -26,7 +26,9 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The UI widgets for the first time wizard.
"""
from PyQt4 import QtCore, QtGui
import sys
@ -34,7 +36,11 @@ import sys
from openlp.core.lib import translate
from openlp.core.lib.ui import add_welcome_page
class FirstTimePage(object):
"""
An enumeration class with each of the pages of the wizard.
"""
Welcome = 0
Plugins = 1
NoInternet = 2
@ -46,13 +52,19 @@ class FirstTimePage(object):
class Ui_FirstTimeWizard(object):
"""
The UI widgets for the first time wizard.
"""
def setupUi(self, FirstTimeWizard):
"""
Set up the UI.
"""
FirstTimeWizard.setObjectName(u'FirstTimeWizard')
FirstTimeWizard.resize(550, 386)
FirstTimeWizard.setModal(True)
FirstTimeWizard.setWizardStyle(QtGui.QWizard.ModernStyle)
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.noInternetFinishButton = self.button(QtGui.QWizard.CustomButton1)
self.cancelButton = self.button(QtGui.QWizard.CancelButton)
@ -193,17 +205,20 @@ class Ui_FirstTimeWizard(object):
self.retranslateUi(FirstTimeWizard)
def retranslateUi(self, FirstTimeWizard):
"""
Translate the UI on the fly
"""
FirstTimeWizard.setWindowTitle(translate(
'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'))
self.informationLabel.setText(translate('OpenLP.FirstTimeWizard',
'This wizard will help you to configure OpenLP for initial use.'
' Click the next button below to start.'))
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.customCheckBox.setText(translate('OpenLP.FirstTimeWizard','Custom Slides'))
self.customCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Custom Slides'))
self.bibleCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Bible'))
self.imageCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Images'))
# TODO Presentation plugin is not yet working on Mac OS X.

View File

@ -26,16 +26,23 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The UI widgets for the formatting tags window.
"""
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate, UiStrings
from openlp.core.lib import UiStrings, translate
from openlp.core.lib.ui import create_button_box
class Ui_FormattingTagDialog(object):
"""
The UI widgets for the formatting tags window.
"""
def setupUi(self, formattingTagDialog):
"""
Set up the UI
"""
formattingTagDialog.setObjectName(u'formattingTagDialog')
formattingTagDialog.resize(725, 548)
self.listdataGridLayout = QtGui.QGridLayout(formattingTagDialog)
@ -116,6 +123,9 @@ class Ui_FormattingTagDialog(object):
self.retranslateUi(formattingTagDialog)
def retranslateUi(self, formattingTagDialog):
"""
Translate the UI on the fly
"""
formattingTagDialog.setWindowTitle(translate('OpenLP.FormattingTagDialog', 'Configure Formatting Tags'))
self.editGroupBox.setTitle(translate('OpenLP.FormattingTagDialog', 'Edit Selection'))
self.savePushButton.setText(translate('OpenLP.FormattingTagDialog', 'Save'))

View File

@ -27,14 +27,13 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`formattingtagform` provides an Tag Edit facility. The Base set are
protected and included each time loaded. Custom tags can be defined and saved.
The Custom Tag arrays are saved in a pickle so QSettings works on them. Base
Tags cannot be changed.
The :mod:`formattingtagform` provides an Tag Edit facility. The Base set are protected and included each time loaded.
Custom tags can be defined and saved. The Custom Tag arrays are saved in a pickle so QSettings works on them. Base Tags
cannot be changed.
"""
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.ui.formattingtagdialog import Ui_FormattingTagDialog
@ -49,7 +48,7 @@ class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog):
"""
QtGui.QDialog.__init__(self, parent)
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.savePushButton, QtCore.SIGNAL(u'clicked()'), self.onSavedClicked)
QtCore.QObject.connect(self.deletePushButton, QtCore.SIGNAL(u'clicked()'), self.onDeleteClicked)

View File

@ -26,14 +26,18 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The general tab of the configuration dialog.
"""
import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, Settings, SettingsTab, translate, ScreenList, UiStrings
from openlp.core.lib import Receiver, Settings, SettingsTab, ScreenList, UiStrings, translate
log = logging.getLogger(__name__)
class GeneralTab(SettingsTab):
"""
GeneralTab is the general settings tab in the settings dialog.

View File

@ -27,19 +27,23 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`maindisplay` module provides the functionality to display screens
and play multimedia within OpenLP.
The :mod:`maindisplay` module provides the functionality to display screens 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 logging
import os
import sys
from PyQt4 import QtCore, QtGui, QtWebKit, QtOpenGL
from PyQt4.phonon import Phonon
from openlp.core.lib import Receiver, build_html, ServiceItem, image_to_byte, translate, expand_tags,\
Settings, ImageSource, Registry
from openlp.core.lib import Receiver, ServiceItem, Settings, ImageSource, Registry, build_html, expand_tags, \
image_to_byte, translate
from openlp.core.lib.theme import BackgroundType
from openlp.core.lib import ScreenList
@ -47,8 +51,6 @@ from openlp.core.ui import HideMode, AlertLocation
log = logging.getLogger(__name__)
#http://www.steveheffernan.com/html5-video-player/demo-video-player.html
#http://html5demos.com/two-videos
class Display(QtGui.QGraphicsView):
"""
@ -57,6 +59,9 @@ class Display(QtGui.QGraphicsView):
Preview display.
"""
def __init__(self, parent, live, controller):
"""
Constructor
"""
if live:
QtGui.QGraphicsView.__init__(self)
# Overwrite the parent() method.
@ -101,6 +106,9 @@ class Display(QtGui.QGraphicsView):
QtCore.Qt.ScrollBarAlwaysOff)
def resizeEvent(self, event):
"""
React to resizing of this display
"""
self.webView.setGeometry(0, 0, self.width(), self.height())
def isWebLoaded(self):
@ -116,6 +124,9 @@ class MainDisplay(Display):
This is the display screen as a specialized class from the Display class
"""
def __init__(self, parent, live, controller):
"""
Constructor
"""
Display.__init__(self, parent, live, controller)
self.screens = ScreenList()
self.rebuildCSS = False
@ -153,6 +164,9 @@ class MainDisplay(Display):
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_updated'), self.configChanged)
def setTransparency(self, enabled):
"""
Set the transparency of the window
"""
if enabled:
self.setAutoFillBackground(False)
else:
@ -229,7 +243,7 @@ class MainDisplay(Display):
log.debug(u'text to display')
# Wait for the webview to update before displaying text.
while not self.webLoaded:
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
self.setGeometry(self.screen[u'size'])
if animate:
self.frame.evaluateJavaScript(u'show_text("%s")' % slide.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'))
@ -278,7 +292,7 @@ class MainDisplay(Display):
"""
API for replacement backgrounds so Images are added directly to cache.
"""
self.image_manager.addImage(path, ImageSource.ImagePlugin, background)
self.image_manager.add_image(path, ImageSource.ImagePlugin, background)
if not hasattr(self, u'serviceItem'):
return False
self.override[u'image'] = path
@ -300,7 +314,7 @@ class MainDisplay(Display):
re-added to the image manager.
"""
log.debug(u'image to display')
image = self.image_manager.getImageBytes(path, ImageSource.ImagePlugin)
image = self.image_manager.get_image_bytes(path, ImageSource.ImagePlugin)
self.controller.media_controller.media_reset(self.controller)
self.displayImage(image)
@ -333,18 +347,18 @@ class MainDisplay(Display):
Generates a preview of the image displayed.
"""
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.
if self.isLive and hasattr(self, u'serviceItem'):
# Wait for the fade to finish before geting the preview.
# Important otherwise preview will have incorrect text if at all!
if self.serviceItem.themedata and self.serviceItem.themedata.display_slide_transition:
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.
# Important otherwise first preview will miss the background !
while not self.webLoaded:
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
# if was hidden keep it hidden
if self.isLive:
if self.hideMode:
@ -381,14 +395,16 @@ class MainDisplay(Display):
self.override = {}
else:
# replace the background
background = self.image_manager.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 ==
BackgroundType.to_string(BackgroundType.Transparent))
if self.serviceItem.themedata.background_filename:
self.serviceItem.bg_image_bytes = self.image_manager.getImageBytes(
self.serviceItem.themedata.background_filename,ImageSource.Theme)
self.serviceItem.bg_image_bytes = self.image_manager.get_image_bytes(
self.serviceItem.themedata.background_filename,
ImageSource.Theme
)
if image_path:
image_bytes = self.image_manager.getImageBytes(image_path, ImageSource.ImagePlugin)
image_bytes = self.image_manager.get_image_bytes(image_path, ImageSource.ImagePlugin)
else:
image_bytes = None
html = build_html(self.serviceItem, self.screen, self.isLive, background, image_bytes,
@ -487,6 +503,16 @@ class MainDisplay(Display):
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):
"""
@ -532,6 +558,9 @@ class AudioPlayer(QtCore.QObject):
self.mediaObject.enqueue(self.playlist[self.currentIndex])
def onFinished(self):
"""
When the audio track finishes.
"""
if self.repeat:
log.debug(u'Repeat is enabled... here we go again!')
self.mediaObject.clearQueue()
@ -540,6 +569,9 @@ class AudioPlayer(QtCore.QObject):
self.play()
def connectVolumeSlider(self, slider):
"""
Connect the volume slider to the output channel.
"""
slider.setAudioOutput(self.audioObject)
def reset(self):
@ -586,6 +618,9 @@ class AudioPlayer(QtCore.QObject):
self.playlist.extend(map(Phonon.MediaSource, filenames))
def next(self):
"""
Skip forward to the next track in the list
"""
if not self.repeat and self.currentIndex + 1 >= len(self.playlist):
return
isPlaying = self.mediaObject.state() == Phonon.PlayingState
@ -599,6 +634,9 @@ class AudioPlayer(QtCore.QObject):
self.mediaObject.play()
def goTo(self, index):
"""
Go to a particular track in the list
"""
isPlaying = self.mediaObject.state() == Phonon.PlayingState
self.mediaObject.clearQueue()
self.mediaObject.clear()
@ -609,5 +647,7 @@ class AudioPlayer(QtCore.QObject):
#@todo is this used?
def connectSlot(self, signal, slot):
"""
Connect a slot to a signal on the media object
"""
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 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
This is the main window, where all the action happens.
"""
import logging
import os
import sys
@ -39,13 +41,13 @@ from datetime import datetime
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Renderer, build_icon, OpenLPDockWidget, PluginManager, Receiver, translate, ImageManager, \
PluginStatus, Registry, Settings, ScreenList
from openlp.core.lib import Renderer, OpenLPDockWidget, PluginManager, Receiver, ImageManager, PluginStatus, Registry, \
Settings, ScreenList, build_icon, check_directory_exists, translate
from openlp.core.lib.ui import UiStrings, create_action
from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, ThemeManager, SlideController, PluginForm, \
MediaDockManager, ShortcutListForm, FormattingTagForm
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
from openlp.core.utils.actions import ActionList, CategoryOrder
from openlp.core.ui.firsttimeform import FirstTimeForm
@ -80,21 +82,24 @@ PROGRESSBAR_STYLE = """
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
"""
mainWindow.setObjectName(u'MainWindow')
mainWindow.setWindowIcon(build_icon(u':/icon/openlp-logo-64x64.png'))
mainWindow.setDockNestingEnabled(True)
main_window.setObjectName(u'MainWindow')
main_window.setWindowIcon(build_icon(u':/icon/openlp-logo-64x64.png'))
main_window.setDockNestingEnabled(True)
# 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.mainContentLayout = QtGui.QHBoxLayout(self.mainContent)
self.mainContentLayout.setSpacing(0)
self.mainContentLayout.setMargin(0)
self.mainContentLayout.setObjectName(u'mainContentLayout')
mainWindow.setCentralWidget(self.mainContent)
main_window.setCentralWidget(self.mainContent)
self.controlSplitter = QtGui.QSplitter(self.mainContent)
self.controlSplitter.setOrientation(QtCore.Qt.Horizontal)
self.controlSplitter.setObjectName(u'controlSplitter')
@ -108,7 +113,7 @@ class Ui_MainWindow(object):
panelLocked = Settings().value(u'user interface/lock panel')
self.liveController.panel.setVisible(liveVisible)
# Create menu
self.menuBar = QtGui.QMenuBar(mainWindow)
self.menuBar = QtGui.QMenuBar(main_window)
self.menuBar.setObjectName(u'menuBar')
self.fileMenu = QtGui.QMenu(self.menuBar)
self.fileMenu.setObjectName(u'fileMenu')
@ -134,10 +139,10 @@ class Ui_MainWindow(object):
# Help Menu
self.helpMenu = QtGui.QMenu(self.menuBar)
self.helpMenu.setObjectName(u'helpMenu')
mainWindow.setMenuBar(self.menuBar)
self.statusBar = QtGui.QStatusBar(mainWindow)
main_window.setMenuBar(self.menuBar)
self.statusBar = QtGui.QStatusBar(main_window)
self.statusBar.setObjectName(u'statusBar')
mainWindow.setStatusBar(self.statusBar)
main_window.setStatusBar(self.statusBar)
self.loadProgressBar = QtGui.QProgressBar(self.statusBar)
self.loadProgressBar.setObjectName(u'loadProgressBar')
self.statusBar.addPermanentWidget(self.loadProgressBar)
@ -148,142 +153,142 @@ class Ui_MainWindow(object):
self.defaultThemeLabel.setObjectName(u'defaultThemeLabel')
self.statusBar.addPermanentWidget(self.defaultThemeLabel)
# 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)
# Create the media toolbox
self.mediaToolBox = QtGui.QToolBox(self.mediaManagerDock)
self.mediaToolBox.setObjectName(u'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
self.serviceManagerDock = OpenLPDockWidget(mainWindow, u'serviceManagerDock',
self.serviceManagerDock = OpenLPDockWidget(main_window, u'serviceManagerDock',
u':/system/system_servicemanager.png')
self.serviceManagerContents = ServiceManager(self.serviceManagerDock)
self.serviceManagerDock.setWidget(self.serviceManagerContents)
mainWindow.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.serviceManagerDock)
main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.serviceManagerDock)
# 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(self.themeManagerDock)
self.themeManagerContents.setObjectName(u'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
action_list = ActionList.get_instance()
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',
shortcuts=[QtGui.QKeySequence(u'Ctrl+N')],
category=UiStrings().File,
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',
shortcuts=[QtGui.QKeySequence(u'Ctrl+O')],
category=UiStrings().File,
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',
shortcuts=[QtGui.QKeySequence(u'Ctrl+S')],
category=UiStrings().File,
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')],
category=UiStrings().File,
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')],
category=UiStrings().File,
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',
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
self.fileExitItem.setMenuRole(QtGui.QAction.QuitRole)
action_list.add_category(UiStrings().Import, CategoryOrder.standardMenu)
self.importThemeItem = create_action(mainWindow, u'importThemeItem', category=UiStrings().Import)
self.importLanguageItem = create_action(mainWindow, u'importLanguageItem')
self.importThemeItem = create_action(main_window, u'importThemeItem', category=UiStrings().Import)
self.importLanguageItem = create_action(main_window, u'importLanguageItem')
action_list.add_category(UiStrings().Export, CategoryOrder.standardMenu)
self.exportThemeItem = create_action(mainWindow, u'exportThemeItem', category=UiStrings().Export)
self.exportLanguageItem = create_action(mainWindow, u'exportLanguageItem')
self.exportThemeItem = create_action(main_window, u'exportThemeItem', category=UiStrings().Export)
self.exportLanguageItem = create_action(main_window, u'exportLanguageItem')
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')],
icon=u':/system/system_mediamanager.png',
checked=self.mediaManagerDock.isVisible(),
category=UiStrings().View, triggers=self.toggleMediaManager)
self.viewThemeManagerItem = create_action(mainWindow,
self.viewThemeManagerItem = create_action(main_window,
u'viewThemeManagerItem', shortcuts=[QtGui.QKeySequence(u'F10')],
icon=u':/system/system_thememanager.png',
checked=self.themeManagerDock.isVisible(),
category=UiStrings().View, triggers=self.toggleThemeManager)
self.viewServiceManagerItem = create_action(mainWindow,
self.viewServiceManagerItem = create_action(main_window,
u'viewServiceManagerItem', shortcuts=[QtGui.QKeySequence(u'F9')],
icon=u':/system/system_servicemanager.png',
checked=self.serviceManagerDock.isVisible(),
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,
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,
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)
action_list.add_category(UiStrings().ViewMode,
CategoryOrder.standardMenu)
self.modeDefaultItem = create_action(mainWindow, u'modeDefaultItem', checked=False,
self.modeDefaultItem = create_action(main_window, u'modeDefaultItem', checked=False,
category=UiStrings().ViewMode)
self.modeSetupItem = create_action(mainWindow, u'modeSetupItem', checked=False, category=UiStrings().ViewMode)
self.modeLiveItem = create_action(mainWindow, u'modeLiveItem', checked=True, category=UiStrings().ViewMode)
self.modeGroup = QtGui.QActionGroup(mainWindow)
self.modeSetupItem = create_action(main_window, u'modeSetupItem', checked=False, category=UiStrings().ViewMode)
self.modeLiveItem = create_action(main_window, u'modeLiveItem', checked=True, category=UiStrings().ViewMode)
self.modeGroup = QtGui.QActionGroup(main_window)
self.modeGroup.addAction(self.modeDefaultItem)
self.modeGroup.addAction(self.modeSetupItem)
self.modeGroup.addAction(self.modeLiveItem)
self.modeDefaultItem.setChecked(True)
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',
category=UiStrings().Tools)
self.toolsOpenDataFolder = create_action(mainWindow,
self.toolsOpenDataFolder = create_action(main_window,
u'toolsOpenDataFolder', icon=u':/general/general_open.png',
category=UiStrings().Tools)
self.toolsFirstTimeWizard = create_action(mainWindow,
self.toolsFirstTimeWizard = create_action(main_window,
u'toolsFirstTimeWizard', icon=u':/general/general_revert.png',
category=UiStrings().Tools)
self.updateThemeImages = create_action(mainWindow,
self.updateThemeImages = create_action(main_window,
u'updateThemeImages', category=UiStrings().Tools)
action_list.add_category(UiStrings().Settings,
CategoryOrder.standardMenu)
self.settingsPluginListItem = create_action(mainWindow,
self.settingsPluginListItem = create_action(main_window,
u'settingsPluginListItem',
icon=u':/system/settings_plugin_list.png',
shortcuts=[QtGui.QKeySequence(u'Alt+F7')],
category=UiStrings().Settings, triggers=self.onPluginItemClicked)
# i18n Language Items
self.autoLanguageItem = create_action(mainWindow, u'autoLanguageItem',
self.autoLanguageItem = create_action(main_window, u'autoLanguageItem',
checked=LanguageManager.auto_language)
self.languageGroup = QtGui.QActionGroup(mainWindow)
self.languageGroup = QtGui.QActionGroup(main_window)
self.languageGroup.setExclusive(True)
self.languageGroup.setObjectName(u'languageGroup')
add_actions(self.languageGroup, [self.autoLanguageItem])
qmList = LanguageManager.get_qm_list()
savedLanguage = LanguageManager.get_language()
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])
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)
# 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)
self.settingsConfigureItem = create_action(mainWindow, u'settingsConfigureItem',
self.settingsConfigureItem = create_action(main_window, u'settingsConfigureItem',
icon=u':/system/system_settings.png', category=UiStrings().Settings)
# Give QT Extra Hint that this is the Preferences Menu Item
self.settingsConfigureItem.setMenuRole(QtGui.QAction.PreferencesRole)
self.settingsImportItem = create_action(mainWindow, u'settingsImportItem', category=UiStrings().Settings)
self.settingsExportItem = create_action(mainWindow, u'settingsExportItem', category=UiStrings().Settings)
self.settingsImportItem = create_action(main_window, u'settingsImportItem', category=UiStrings().Settings)
self.settingsExportItem = create_action(main_window, u'settingsExportItem', category=UiStrings().Settings)
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')],
category=UiStrings().Help, triggers=self.onAboutItemClicked)
# Give QT Extra Hint that this is an About Menu Item
@ -291,15 +296,15 @@ class Ui_MainWindow(object):
if os.name == u'nt':
self.localHelpFile = os.path.join(
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',
shortcuts=[QtGui.QKeySequence(u'F1')],
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',
shortcuts=[QtGui.QKeySequence(u'Alt+F1')],
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.fileExportMenu, (self.settingsExportItem, None, self.exportThemeItem, self.exportLanguageItem))
add_actions(self.fileMenu, (self.fileNewItem, self.fileOpenItem,
@ -333,7 +338,7 @@ class Ui_MainWindow(object):
add_actions(self.menuBar, (self.fileMenu.menuAction(), self.viewMenu.menuAction(), self.toolsMenu.menuAction(),
self.settingsMenu.menuAction(), self.helpMenu.menuAction()))
# Initialise the translation
self.retranslateUi(mainWindow)
self.retranslateUi(main_window)
self.mediaToolBox.setCurrentIndex(0)
# Connect up some signals and slots
QtCore.QObject.connect(self.fileMenu, QtCore.SIGNAL(u'aboutToShow()'), self.updateRecentFilesMenu)
@ -406,7 +411,8 @@ class Ui_MainWindow(object):
'Toggle the visibility of the service manager.'))
self.viewPreviewPanel.setText(translate('OpenLP.MainWindow', '&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.setToolTip(translate('OpenLP.MainWindow', 'Toggle Live Panel'))
self.lockPanel.setText(translate('OpenLP.MainWindow', 'L&ock Panels'))
@ -449,14 +455,13 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
"""
log.info(u'MainWindow loaded')
def __init__(self, application):
def __init__(self):
"""
This constructor sets up the interface, the various managers, and the
plugins.
"""
QtGui.QMainWindow.__init__(self)
Registry().register(u'main_window', self)
self.application = application
self.clipboard = self.application.clipboard()
self.arguments = self.application.args
# Set up settings sections for the main application (not for use by plugins).
@ -481,7 +486,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.recentFiles = []
# Set up the path with plugins
plugin_path = AppLocation.get_directory(AppLocation.PluginsDir)
self.pluginManager = PluginManager(plugin_path)
self.plugin_manager = PluginManager(plugin_path)
self.imageManager = ImageManager()
# Set up the interface
self.setupUi(self)
@ -496,9 +501,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.copyData = False
# Set up signals and slots
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()'),
self.themeManagerContents.onExportTheme)
self.themeManagerContents.on_export_theme)
QtCore.QObject.connect(self.mediaManagerDock, QtCore.SIGNAL(u'visibilityChanged(bool)'),
self.viewMediaManagerItem.setChecked)
QtCore.QObject.connect(self.serviceManagerDock, QtCore.SIGNAL(u'visibilityChanged(bool)'),
@ -517,7 +522,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.onSettingsShortcutsItemClicked)
QtCore.QObject.connect(self.settingsImportItem, QtCore.SIGNAL(u'triggered()'),
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
self.languageGroup.triggered.connect(LanguageManager.set_language)
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'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'mainwindow_status_text'), self.showStatusMessage)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'mainwindow_status_text'),
self.showStatusMessage)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'cleanup'), self.clean_up)
# Media Manager
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
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'),
self.onInformationMessage)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'set_new_data_path'), self.setNewDataPath)
@ -546,25 +551,25 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
# Define the media Dock Manager
self.mediaDockManager = MediaDockManager(self.mediaToolBox)
log.info(u'Load Plugins')
self.pluginManager.find_plugins(plugin_path)
self.plugin_manager.find_plugins(plugin_path)
# hook methods have to happen after find_plugins. Find plugins needs
# the controllers hence the hooks have moved from setupUI() to here
# Find and insert settings tabs
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
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.
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.
self.pluginManager.hook_export_menu(self.fileExportMenu)
self.plugin_manager.hook_export_menu(self.fileExportMenu)
# 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.
log.info(u'initialise plugins')
self.pluginManager.initialise_plugins()
self.plugin_manager.initialise_plugins()
# Create the displays as all necessary components are loaded.
self.previewController.screenSizeChanged()
self.liveController.screenSizeChanged()
@ -576,18 +581,24 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.settingsForm.postSetUp()
# Once all components are initialised load the Themes
log.info(u'Load Themes')
self.themeManagerContents.loadThemes(True)
self.themeManagerContents.load_themes(True)
# Hide/show the theme combobox on the service manager
self.serviceManagerContents.themeChange()
self.serviceManagerContents.theme_change()
# Reset the cursor
Receiver.send_message(u'cursor_normal')
self.application.set_normal_cursor()
def setAutoLanguage(self, value):
"""
Set the language to automatic.
"""
self.languageGroup.setDisabled(value)
LanguageManager.auto_language = value
LanguageManager.set_language(self.languageGroup.checkedAction())
def onMediaToolBoxChanged(self, index):
"""
Focus a widget when the media toolbox changes.
"""
widget = self.mediaToolBox.widget(index)
if widget:
widget.onFocus()
@ -631,24 +642,26 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.setViewMode(False, True, False, False, True)
self.modeLiveItem.setChecked(True)
def appStartup(self):
def app_startup(self):
"""
Give all the plugins a chance to perform some tasks at startup
"""
Receiver.send_message(u'openlp_process_events')
for plugin in self.pluginManager.plugins:
self.application.process_events()
for plugin in self.plugin_manager.plugins:
if plugin.isActive():
plugin.appStartup()
Receiver.send_message(u'openlp_process_events')
plugin.app_startup()
self.application.process_events()
def firstTime(self):
# Import themes if first time
Receiver.send_message(u'openlp_process_events')
for plugin in self.pluginManager.plugins:
if hasattr(plugin, u'firstTime'):
Receiver.send_message(u'openlp_process_events')
plugin.firstTime()
Receiver.send_message(u'openlp_process_events')
def first_time(self):
"""
Import themes if first time
"""
self.application.process_events()
for plugin in self.plugin_manager.plugins:
if hasattr(plugin, u'first_time'):
self.application.process_events()
plugin.first_time()
self.application.process_events()
temp_dir = os.path.join(unicode(gettempdir()), u'openlp')
shutil.rmtree(temp_dir, True)
@ -669,29 +682,30 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
QtGui.QMessageBox.No)
if answer == QtGui.QMessageBox.No:
return
Receiver.send_message(u'cursor_busy')
screens = ScreenList()
firstTime = FirstTimeForm(screens, self)
firstTime.exec_()
if firstTime.downloadCancelled:
first_run_wizard = FirstTimeForm(screens, self)
first_run_wizard.exec_()
if first_run_wizard.was_download_cancelled:
return
self.firstTime()
for plugin in self.pluginManager.plugins:
self.application.set_busy_cursor()
self.first_time()
for plugin in self.plugin_manager.plugins:
self.activePlugin = plugin
oldStatus = self.activePlugin.status
self.activePlugin.setStatus()
if oldStatus != self.activePlugin.status:
if self.activePlugin.status == PluginStatus.Active:
self.activePlugin.toggleStatus(PluginStatus.Active)
self.activePlugin.appStartup()
self.activePlugin.app_startup()
else:
self.activePlugin.toggleStatus(PluginStatus.Inactive)
self.themeManagerContents.configUpdated()
self.themeManagerContents.loadThemes(True)
self.themeManagerContents.config_updated()
self.themeManagerContents.load_themes(True)
Receiver.send_message(u'theme_update_global', self.themeManagerContents.global_theme)
# Check if any Bibles downloaded. If there are, they will be
# processed.
Receiver.send_message(u'bibles_load_list', True)
self.application.set_normal_cursor()
def blankCheck(self):
"""
@ -705,15 +719,24 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
translate('OpenLP.MainWindow', 'The Main Display has been blanked out'))
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'])
def onWarningMessage(self, data):
Receiver.send_message(u'close_splash')
QtGui.QMessageBox.warning(self, data[u'title'], data[u'message'])
def warning_message(self, message):
"""
Display a warning message
"""
self.application.close_splash_screen()
QtGui.QMessageBox.warning(self, message[u'title'], message[u'message'])
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'])
def onHelpWebSiteClicked(self):
@ -760,7 +783,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
"""
Updates the new theme preview images.
"""
self.themeManagerContents.updatePreviewImages()
self.themeManagerContents.update_preview_images()
def onFormattingTagItemClicked(self):
"""
@ -800,8 +823,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
QtGui.QMessageBox.No)
if answer == QtGui.QMessageBox.No:
return
import_file_name = QtGui.QFileDialog.getOpenFileName(self,translate('OpenLP.MainWindow', 'Open File'), '',
translate('OpenLP.MainWindow', 'OpenLP Export Settings Files (*.conf)'))
import_file_name = QtGui.QFileDialog.getOpenFileName(self, translate('OpenLP.MainWindow', 'Open File'), '',
translate('OpenLP.MainWindow', 'OpenLP Export Settings Files (*.conf)'))
if not import_file_name:
return
setting_sections = []
@ -817,10 +840,17 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
setting_sections.extend([self.headerSection])
setting_sections.extend([u'crashreport'])
# Add plugin sections.
for plugin in self.pluginManager.plugins:
for plugin in self.plugin_manager.plugins:
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()
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
# 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
@ -880,7 +910,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
return
# Make sure it's a .conf file.
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(),
get_filesystem_encoding()), u'openlp', u'exportConf.tmp')
self.saveSettings()
@ -894,7 +924,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
setting_sections.extend([self.themesSettingsSection])
setting_sections.extend([self.displayTagsSection])
# Add plugin sections.
for plugin in self.pluginManager.plugins:
for plugin in self.plugin_manager.plugins:
setting_sections.extend([plugin.name])
# Delete old files if found.
if os.path.exists(temp_file):
@ -979,14 +1009,14 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
renderer.
"""
log.debug(u'screenChanged')
Receiver.send_message(u'cursor_busy')
self.imageManager.updateDisplay()
self.application.set_busy_cursor()
self.imageManager.update_display()
self.renderer.update_display()
self.previewController.screenSizeChanged()
self.liveController.screenSizeChanged()
self.setFocus()
self.activateWindow()
Receiver.send_message(u'cursor_normal')
self.application.set_normal_cursor()
def closeEvent(self, event):
"""
@ -994,7 +1024,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
"""
# The MainApplication did not even enter the event loop (this happens
# 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()
return
# If we just did a settings import, close without saving changes.
@ -1036,17 +1066,17 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
``save_settings``
Switch to prevent saving settings. Defaults to **True**.
"""
self.imageManager.stopManager = True
while self.imageManager.imageThread.isRunning():
self.imageManager.stop_manager = True
while self.imageManager.image_thread.isRunning():
time.sleep(0.1)
# Clean temporary files used by services
self.serviceManagerContents.cleanUp()
self.serviceManagerContents.clean_up()
if save_settings:
if Settings().value(u'advanced/save current plugin'):
Settings().setValue(u'advanced/current media plugin', self.mediaToolBox.currentIndex())
# Call the cleanup method to shutdown plugins.
log.info(u'cleanup plugins')
self.pluginManager.finalise_plugins()
self.plugin_manager.finalise_plugins()
if save_settings:
# Save settings
self.saveSettings()
@ -1100,18 +1130,33 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.setWindowTitle(title)
def showStatusMessage(self, message):
"""
Show a message in the status bar
"""
self.statusBar.showMessage(message)
def defaultThemeChanged(self, theme):
"""
Update the default theme indicator in the status bar
"""
self.defaultThemeLabel.setText(translate('OpenLP.MainWindow', 'Default Theme: %s') % theme)
def toggleMediaManager(self):
"""
Toggle the visibility of the media manager
"""
self.mediaManagerDock.setVisible(not self.mediaManagerDock.isVisible())
def toggleServiceManager(self):
"""
Toggle the visibility of the service manager
"""
self.serviceManagerDock.setVisible(not self.serviceManagerDock.isVisible())
def toggleThemeManager(self):
"""
Toggle the visibility of the theme manager
"""
self.themeManagerDock.setVisible(not self.themeManagerDock.isVisible())
def setPreviewPanelVisibility(self, visible):
@ -1184,7 +1229,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.restoreState(settings.value(u'main window state'))
self.liveController.splitter.restoreState(settings.value(u'live splitter geometry'))
self.previewController.splitter.restoreState(settings.value(u'preview splitter geometry'))
self.controlSplitter.restoreState(settings.value(u'mainwindow splitter geometry'))
self.controlSplitter.restoreState(settings.value(u'main window splitter geometry'))
settings.endGroup()
def saveSettings(self):
@ -1205,7 +1250,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
settings.setValue(u'main window geometry', self.saveGeometry())
settings.setValue(u'live splitter geometry', self.liveController.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()
def updateRecentFilesMenu(self):
@ -1270,14 +1315,14 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.loadProgressBar.show()
self.loadProgressBar.setMaximum(size)
self.loadProgressBar.setValue(0)
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
def incrementProgressBar(self):
"""
Increase the Progress Bar value by 1
"""
self.loadProgressBar.setValue(self.loadProgressBar.value() + 1)
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
def finishedProgressBar(self):
"""
@ -1292,35 +1337,43 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
if event.timerId() == self.timer_id:
self.timer_id = 0
self.loadProgressBar.hide()
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
def setNewDataPath(self, new_data_path):
"""
Set the new data path
"""
self.newDataPath = new_data_path
def setCopyData(self, copy_data):
"""
Set the flag to copy the data
"""
self.copyData = copy_data
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())
# Copy OpenLP data to new location if requested.
self.application.set_busy_cursor()
if self.copyData:
log.info(u'Copying data to new path')
try:
Receiver.send_message(u'openlp_process_events')
Receiver.send_message(u'cursor_busy')
self.showStatusMessage(
translate('OpenLP.MainWindow', 'Copying OpenLP data to new data directory location - %s '
'- Please wait for copy to finish').replace('%s', self.newDataPath))
dir_util.copy_tree(old_data_path, self.newDataPath)
log.info(u'Copy sucessful')
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))
QtGui.QMessageBox.critical(self, translate('OpenLP.MainWindow', 'New Data Directory Error'),
translate('OpenLP.MainWindow',
'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
else:
log.info(u'No data copy requested')
@ -1330,4 +1383,14 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
# Check if the new data path is our default.
if self.newDataPath == AppLocation.get_directory(AppLocation.DataDir):
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 #
# 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
from openlp.core.lib import Settings
@ -34,6 +37,7 @@ from PyQt4 import QtCore
log = logging.getLogger(__name__)
class MediaState(object):
"""
An enumeration for possible States of the Media Player
@ -70,6 +74,7 @@ class MediaInfo(object):
end_time = 0
media_type = MediaType()
def get_media_players():
"""
This method extracts the configured media players and overridden player
@ -85,7 +90,7 @@ def get_media_players():
overridden_player = u'auto'
else:
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
@ -108,3 +113,5 @@ def set_media_players(players_list, overridden_player=u'auto'):
from mediacontroller import MediaController
from playertab import PlayerTab
__all__ = [u'MediaController', u'PlayerTab']

View File

@ -26,13 +26,16 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# 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 os
import datetime
from PyQt4 import QtCore, QtGui
from openlp.core.lib import OpenLPToolbar, Receiver, translate, Settings, Registry, UiStrings
from openlp.core.lib import OpenLPToolbar, Receiver, Settings, Registry, UiStrings, translate
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players
from openlp.core.ui.media.mediaplayer import MediaPlayer
@ -41,11 +44,15 @@ from openlp.core.ui import DisplayControllerType
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
@ -55,7 +62,7 @@ class MediaSlider(QtGui.QSlider):
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)))
self.setToolTip(u'%s' % datetime.timedelta(seconds=int(timevalue / 1000)))
QtGui.QSlider.mouseMoveEvent(self, event)
def mousePressEvent(self, event):
@ -87,6 +94,9 @@ class MediaController(object):
"""
def __init__(self, parent):
"""
Constructor
"""
self.mainWindow = parent
Registry().register(u'media_controller', self)
self.mediaPlayers = {}
@ -96,7 +106,7 @@ class MediaController(object):
self.timer = QtCore.QTimer()
self.timer.setInterval(200)
# 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'playbackPause'), self.media_pause_msg)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'playbackStop'), self.media_stop_msg)
@ -298,7 +308,6 @@ class MediaController(object):
QtCore.QObject.connect(controller.seekSlider, 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):
"""
After a new display is configured, all media related widget will be
@ -428,7 +437,7 @@ class MediaController(object):
``serviceItem``
The ServiceItem containing the details to be played.
"""
controller = self.displayControllers[DisplayControllerType.Plugin]
controller = self.displayControllers[DisplayControllerType.Plugin]
log.debug(u'media_length')
# stop running videos
self.media_reset(controller)
@ -500,8 +509,7 @@ class MediaController(object):
First element is the controller which should be used
"""
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):
"""
@ -551,7 +559,7 @@ class MediaController(object):
First element is the controller which should be used
"""
log.debug(u'media_pause_msg')
self.media_pause( msg[0])
self.media_pause(msg[0])
def media_pause(self, controller):
"""
@ -716,6 +724,9 @@ class MediaController(object):
self.timer.start()
def finalise(self):
"""
Reset all the media controllers when OpenLP shuts down
"""
self.timer.stop()
for controller in self.displayControllers:
self.media_reset(self.displayControllers[controller])
@ -739,4 +750,4 @@ class MediaController(object):
self._service_manager = Registry().get(u'service_manager')
return self._service_manager
service_manager = property(_get_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 #
# 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
class MediaPlayer(object):
"""
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'):
"""
Constructor
"""
self.parent = parent
self.name = name
self.available = self.check_available()
@ -143,3 +150,13 @@ class MediaPlayer(object):
Returns Information about the player
"""
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,7 +26,9 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`~openlp.core.ui.media.phononplayer` contains the Phonon player component.
"""
import logging
import mimetypes
from datetime import datetime
@ -34,7 +36,7 @@ from datetime import datetime
from PyQt4 import QtGui
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.mediaplayer import MediaPlayer
@ -56,24 +58,25 @@ ADDITIONAL_EXT = {
u'video/x-matroska': [u'.mpv', u'.mkv'],
u'video/x-wmv': [u'.wmv'],
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']}
VIDEO_CSS = u"""
#videobackboard {
z-index:3;
background-color: %s;
background-color: %(bgcolor)s;
}
#video1 {
background-color: %s;
background-color: %(bgcolor)s;
z-index:4;
}
#video2 {
background-color: %s;
background-color: %(bgcolor)s;
z-index:4;
}
"""
class PhononPlayer(MediaPlayer):
"""
A specialised version of the MediaPlayer class, which provides a Phonon
@ -81,6 +84,9 @@ class PhononPlayer(MediaPlayer):
"""
def __init__(self, parent):
"""
Constructor
"""
MediaPlayer.__init__(self, parent, u'phonon')
self.original_name = u'Phonon'
self.display_name = u'&Phonon'
@ -94,13 +100,16 @@ class PhononPlayer(MediaPlayer):
elif mimetype.startswith(u'video/'):
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.
extensions = mimetypes.guess_all_extensions(unicode(mimetype))
for extension in extensions:
ext = u'*%s' % extension
if ext not in list:
list.append(ext)
if ext not in mimetype_list:
mimetype_list.append(ext)
log.info(u'MediaPlugin: %s extensions: %s' % (mimetype, u' '.join(extensions)))
# Add extensions for this mimetype from self.additional_extensions.
# This hack clears mimetypes' and operating system's shortcomings
@ -108,12 +117,15 @@ class PhononPlayer(MediaPlayer):
if mimetype in self.additional_extensions.keys():
for extension in self.additional_extensions[mimetype]:
ext = u'*%s' % extension
if ext not in list:
list.append(ext)
if ext not in mimetype_list:
mimetype_list.append(ext)
log.info(u'MediaPlugin: %s additional extensions: %s' %
(mimetype, u' '.join(self.additional_extensions[mimetype])))
def setup(self, display):
"""
Set up the player widgets
"""
display.phononWidget = Phonon.VideoWidget(display)
display.phononWidget.resize(display.size())
display.mediaObject = Phonon.MediaObject(display)
@ -126,9 +138,15 @@ class PhononPlayer(MediaPlayer):
self.hasOwnWidget = True
def check_available(self):
"""
Check if the player is available
"""
return True
def load(self, display):
"""
Load a video into the display
"""
log.debug(u'load vid in Phonon Controller')
controller = display.controller
volume = controller.media_info.volume
@ -150,15 +168,21 @@ class PhononPlayer(MediaPlayer):
current_state = display.mediaObject.state()
if current_state == Phonon.ErrorState:
return False
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
if (datetime.now() - start).seconds > 5:
return False
return True
def resize(self, display):
"""
Resize the display
"""
display.phononWidget.resize(display.size())
def play(self, display):
"""
Play the current media item
"""
controller = display.controller
start_time = 0
if display.mediaObject.state() != Phonon.PausedState and \
@ -177,25 +201,40 @@ class PhononPlayer(MediaPlayer):
return True
def pause(self, display):
"""
Pause the current media item
"""
display.mediaObject.pause()
if self.media_state_wait(display, Phonon.PausedState):
self.state = MediaState.Paused
def stop(self, display):
"""
Stop the current media item
"""
display.mediaObject.stop()
self.set_visible(display, False)
self.state = MediaState.Stopped
def volume(self, display, vol):
"""
Set the volume
"""
# 1.0 is the highest value
if display.hasAudio:
vol = float(vol) / float(100)
display.audio.setVolume(vol)
def seek(self, display, seekVal):
"""
Go to a particular point in the current media item
"""
display.mediaObject.seek(seekVal)
def reset(self, display):
"""
Reset the media player
"""
display.mediaObject.stop()
display.mediaObject.clearQueue()
self.set_visible(display, False)
@ -203,10 +242,16 @@ class PhononPlayer(MediaPlayer):
self.state = MediaState.Off
def set_visible(self, display, status):
"""
Set the visibility of the widget
"""
if self.hasOwnWidget:
display.phononWidget.setVisible(status)
def update_ui(self, display):
"""
Update the UI
"""
if display.mediaObject.state() == Phonon.PausedState and self.state != MediaState.Paused:
self.stop(display)
controller = display.controller
@ -224,9 +269,12 @@ class PhononPlayer(MediaPlayer):
Add css style sheets to htmlbuilder
"""
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):
"""
Return some info about this player
"""
return(translate('Media.player', 'Phonon is a media player which '
'interacts with the operating system to provide media capabilities.') +
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 #
# 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 openlp.core.lib import SettingsTab, translate, Receiver, Settings, UiStrings
from openlp.core.lib import SettingsTab, Receiver, Settings, UiStrings, translate
from openlp.core.lib.ui import create_button
from openlp.core.ui.media import get_media_players, set_media_players
class MediaQCheckBox(QtGui.QCheckBox):
"""
MediaQCheckBox adds an extra property, playerName to the QCheckBox class.
"""
def setPlayerName(self, name):
"""
Set the player name
"""
self.playerName = name
@ -45,16 +51,20 @@ class PlayerTab(SettingsTab):
"""
MediaTab is the Media settings tab in the settings dialog.
"""
def __init__(self, parent, mainWindow):
self.parent = parent
self.mainWindow = mainWindow
self.mediaPlayers = mainWindow.mediaController.mediaPlayers
def __init__(self, parent):
"""
Constructor
"""
self.mediaPlayers = self.media_controller.mediaPlayers
self.savedUsedPlayers = None
self.iconPath = u':/media/multimedia-player.png'
player_translated = translate('OpenLP.PlayerTab', 'Players')
SettingsTab.__init__(self, parent, u'Players', player_translated)
def setupUi(self):
"""
Set up the UI
"""
self.setObjectName(u'MediaTab')
SettingsTab.setupUi(self)
self.bgColorGroupBox = QtGui.QGroupBox(self.leftColumn)
@ -116,6 +126,9 @@ class PlayerTab(SettingsTab):
self.onbackgroundColorButtonClicked)
def retranslateUi(self):
"""
Translate the UI on the fly
"""
self.mediaPlayerGroupBox.setTitle(translate('OpenLP.PlayerTab', 'Available Media Players'))
self.playerOrderGroupBox.setTitle(translate('OpenLP.PlayerTab', 'Player Search Order'))
self.bgColorGroupBox.setTitle(UiStrings().BackgroundColor)
@ -125,12 +138,18 @@ class PlayerTab(SettingsTab):
self.retranslatePlayers()
def onbackgroundColorButtonClicked(self):
"""
Set the background color
"""
new_color = QtGui.QColorDialog.getColor(QtGui.QColor(self.bg_color), self)
if new_color.isValid():
self.bg_color = new_color.name()
self.backgroundColorButton.setStyleSheet(u'background-color: %s' % self.bg_color)
def onPlayerCheckBoxChanged(self, check_state):
"""
Add or remove players depending on their status
"""
player = self.sender().playerName
if check_state == QtCore.Qt.Checked:
if player not in self.usedPlayers:
@ -141,6 +160,9 @@ class PlayerTab(SettingsTab):
self.updatePlayerList()
def updatePlayerList(self):
"""
Update the list of media players
"""
self.playerOrderlistWidget.clear()
for player in self.usedPlayers:
if player in self.playerCheckBoxes.keys():
@ -152,6 +174,9 @@ class PlayerTab(SettingsTab):
self.playerOrderlistWidget.addItem(self.mediaPlayers[unicode(player)].original_name)
def onUpButtonClicked(self):
"""
Move a media player up in the order
"""
row = self.playerOrderlistWidget.currentRow()
if row <= 0:
return
@ -161,6 +186,9 @@ class PlayerTab(SettingsTab):
self.usedPlayers.insert(row - 1, self.usedPlayers.pop(row))
def onDownButtonClicked(self):
"""
Move a media player down in the order
"""
row = self.playerOrderlistWidget.currentRow()
if row == -1 or row > self.playerOrderlistWidget.count() - 1:
return
@ -170,6 +198,9 @@ class PlayerTab(SettingsTab):
self.usedPlayers.insert(row + 1, self.usedPlayers.pop(row))
def load(self):
"""
Load the settings
"""
if self.savedUsedPlayers:
self.usedPlayers = self.savedUsedPlayers
self.usedPlayers = get_media_players()[0]
@ -183,6 +214,9 @@ class PlayerTab(SettingsTab):
self.backgroundColorButton.setStyleSheet(u'background-color: %s' % self.bg_color)
def save(self):
"""
Save the settings
"""
player_string_changed = False
settings = Settings()
settings.beginGroup(self.settingsSection)
@ -194,7 +228,7 @@ class PlayerTab(SettingsTab):
set_media_players(self.usedPlayers, override_player)
player_string_changed = True
if player_string_changed:
self.parent.reset_supported_suffixes()
self.service_manager.reset_supported_suffixes()
Receiver.send_message(u'mediaitem_media_rebuild')
Receiver.send_message(u'config_screen_changed')
@ -211,7 +245,7 @@ class PlayerTab(SettingsTab):
checkbox.setToolTip(player.get_info())
checkbox.setPlayerName(player.name)
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)
if player.available and player.name in self.usedPlayers:
checkbox.setChecked(True)

View File

@ -26,7 +26,9 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# 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 distutils.version import LooseVersion
import logging
@ -35,7 +37,7 @@ import sys
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.mediaplayer import MediaPlayer
@ -80,8 +82,8 @@ VIDEO_EXT = [
u'*.nsc',
u'*.nsv',
u'*.nut',
u'*.ra', u'*.ram', u'*.rm', u'*.rv' ,u'*.rmbv',
u'*.a52', u'*.dts', u'*.aac', u'*.flac' ,u'*.dv', u'*.vid',
u'*.ra', u'*.ram', u'*.rm', u'*.rv', u'*.rmbv',
u'*.a52', u'*.dts', u'*.aac', u'*.flac', u'*.dv', u'*.vid',
u'*.tta', u'*.tac',
u'*.ty',
u'*.dts',
@ -99,6 +101,9 @@ class VlcPlayer(MediaPlayer):
"""
def __init__(self, parent):
"""
Constructor
"""
MediaPlayer.__init__(self, parent, u'vlc')
self.original_name = u'VLC'
self.display_name = u'&VLC'
@ -108,6 +113,9 @@ class VlcPlayer(MediaPlayer):
self.video_extensions_list = VIDEO_EXT
def setup(self, display):
"""
Set up the media player
"""
display.vlcWidget = QtGui.QFrame(display)
display.vlcWidget.setFrameStyle(QtGui.QFrame.NoFrame)
# creating a basic vlc instance
@ -141,9 +149,15 @@ class VlcPlayer(MediaPlayer):
self.hasOwnWidget = True
def check_available(self):
"""
Return the availability of VLC
"""
return VLC_AVAILABLE
def load(self, display):
"""
Load a video into VLC
"""
log.debug(u'load vid in Vlc Controller')
controller = display.controller
volume = controller.media_info.volume
@ -173,15 +187,21 @@ class VlcPlayer(MediaPlayer):
while not mediaState == display.vlcMedia.get_state():
if display.vlcMedia.get_state() == vlc.State.Error:
return False
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
if (datetime.now() - start).seconds > 60:
return False
return True
def resize(self, display):
"""
Resize the player
"""
display.vlcWidget.resize(display.size())
def play(self, display):
"""
Play the current item
"""
controller = display.controller
start_time = 0
if self.state != MediaState.Paused and controller.media_info.start_time > 0:
@ -199,6 +219,9 @@ class VlcPlayer(MediaPlayer):
return True
def pause(self, display):
"""
Pause the current item
"""
if display.vlcMedia.get_state() != vlc.State.Playing:
return
display.vlcMediaPlayer.pause()
@ -206,27 +229,45 @@ class VlcPlayer(MediaPlayer):
self.state = MediaState.Paused
def stop(self, display):
"""
Stop the current item
"""
display.vlcMediaPlayer.stop()
self.state = MediaState.Stopped
def volume(self, display, vol):
"""
Set the volume
"""
if display.hasAudio:
display.vlcMediaPlayer.audio_set_volume(vol)
def seek(self, display, seekVal):
"""
Go to a particular position
"""
if display.vlcMediaPlayer.is_seekable():
display.vlcMediaPlayer.set_time(seekVal)
def reset(self, display):
"""
Reset the player
"""
display.vlcMediaPlayer.stop()
display.vlcWidget.setVisible(False)
self.state = MediaState.Off
def set_visible(self, display, status):
"""
Set the visibility
"""
if self.hasOwnWidget:
display.vlcWidget.setVisible(status)
def update_ui(self, display):
"""
Update the UI
"""
# Stop video if playback is finished.
if display.vlcMedia.get_state() == vlc.State.Ended:
self.stop(display)
@ -241,6 +282,9 @@ class VlcPlayer(MediaPlayer):
controller.seekSlider.blockSignals(False)
def get_info(self):
"""
Return some information about this player
"""
return(translate('Media.player', 'VLC is an external player which '
'supports a number of different formats.') +
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 #
# 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
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.mediaplayer import MediaPlayer
@ -40,14 +42,14 @@ log = logging.getLogger(__name__)
VIDEO_CSS = u"""
#videobackboard {
z-index:3;
background-color: %s;
background-color: %(bgcolor)s;
}
#video1 {
background-color: %s;
background-color: %(bgcolor)s;
z-index:4;
}
#video2 {
background-color: %s;
background-color: %(bgcolor)s;
z-index:4;
}
"""
@ -234,33 +236,33 @@ FLASH_HTML = u"""
"""
VIDEO_EXT = [
u'*.3gp'
, u'*.3gpp'
, u'*.3g2'
, u'*.3gpp2'
, u'*.aac'
, u'*.flv'
, u'*.f4a'
, u'*.f4b'
, u'*.f4p'
, u'*.f4v'
, u'*.mov'
, u'*.m4a'
, u'*.m4b'
, u'*.m4p'
, u'*.m4v'
, u'*.mkv'
, u'*.mp4'
, u'*.ogv'
, u'*.webm'
, u'*.mpg', u'*.wmv', u'*.mpeg', u'*.avi'
, u'*.swf'
]
u'*.3gp',
u'*.3gpp',
u'*.3g2',
u'*.3gpp2',
u'*.aac',
u'*.flv',
u'*.f4a',
u'*.f4b',
u'*.f4p',
u'*.f4v',
u'*.mov',
u'*.m4a',
u'*.m4b',
u'*.m4p',
u'*.m4v',
u'*.mkv',
u'*.mp4',
u'*.ogv',
u'*.webm',
u'*.mpg', u'*.wmv', u'*.mpeg', u'*.avi',
u'*.swf'
]
AUDIO_EXT = [
u'*.mp3'
, u'*.ogg'
]
u'*.mp3',
u'*.ogg'
]
class WebkitPlayer(MediaPlayer):
@ -270,6 +272,9 @@ class WebkitPlayer(MediaPlayer):
"""
def __init__(self, parent):
"""
Constructor
"""
MediaPlayer.__init__(self, parent, u'webkit')
self.original_name = u'WebKit'
self.display_name = u'&WebKit'
@ -283,7 +288,7 @@ class WebkitPlayer(MediaPlayer):
Add css style sheets to htmlbuilder
"""
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
def get_media_display_javascript(self):
@ -299,14 +304,23 @@ class WebkitPlayer(MediaPlayer):
return VIDEO_HTML + FLASH_HTML
def setup(self, display):
"""
Set up the player
"""
display.webView.resize(display.size())
display.webView.raise_()
self.hasOwnWidget = False
def check_available(self):
"""
Check the availability of the media player
"""
return True
def load(self, display):
"""
Load a video
"""
log.debug(u'load vid in Webkit Controller')
controller = display.controller
if display.hasAudio and not controller.media_info.is_background:
@ -329,9 +343,15 @@ class WebkitPlayer(MediaPlayer):
return True
def resize(self, display):
"""
Resize the player
"""
display.webView.resize(display.size())
def play(self, display):
"""
Play a video
"""
controller = display.controller
display.webLoaded = True
length = 0
@ -352,6 +372,9 @@ class WebkitPlayer(MediaPlayer):
return True
def pause(self, display):
"""
Pause a video
"""
controller = display.controller
if controller.media_info.is_flash:
display.frame.evaluateJavaScript(u'show_flash("pause");')
@ -360,6 +383,9 @@ class WebkitPlayer(MediaPlayer):
self.state = MediaState.Paused
def stop(self, display):
"""
Stop a video
"""
controller = display.controller
if controller.media_info.is_flash:
display.frame.evaluateJavaScript(u'show_flash("stop");')
@ -368,6 +394,9 @@ class WebkitPlayer(MediaPlayer):
self.state = MediaState.Stopped
def volume(self, display, vol):
"""
Set the volume
"""
controller = display.controller
# 1.0 is the highest value
if display.hasAudio:
@ -376,6 +405,9 @@ class WebkitPlayer(MediaPlayer):
display.frame.evaluateJavaScript(u'show_video(null, null, %s);' % str(vol))
def seek(self, display, seekVal):
"""
Go to a position in the video
"""
controller = display.controller
if controller.media_info.is_flash:
seek = seekVal
@ -385,6 +417,9 @@ class WebkitPlayer(MediaPlayer):
display.frame.evaluateJavaScript(u'show_video("seek", null, null, null, "%f");' % (seek))
def reset(self, display):
"""
Reset the player
"""
controller = display.controller
if controller.media_info.is_flash:
display.frame.evaluateJavaScript(u'show_flash("close");')
@ -393,6 +428,9 @@ class WebkitPlayer(MediaPlayer):
self.state = MediaState.Off
def set_visible(self, display, status):
"""
Set the visibility
"""
controller = display.controller
if status:
is_visible = "visible"
@ -404,6 +442,9 @@ class WebkitPlayer(MediaPlayer):
display.frame.evaluateJavaScript(u'show_video("setVisible", null, null, null, "%s");' % (is_visible))
def update_ui(self, display):
"""
Update the UI
"""
controller = display.controller
if controller.media_info.is_flash:
currentTime = display.frame.evaluateJavaScript(u'show_flash("currentTime");')
@ -428,6 +469,9 @@ class WebkitPlayer(MediaPlayer):
controller.seekSlider.blockSignals(False)
def get_info(self):
"""
Return some information about this player
"""
return(translate('Media.player', 'Webkit is a media player which runs '
'inside a web browser. This player allows text over video to be '
'rendered.') +

View File

@ -26,13 +26,16 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The media manager dock.
"""
import logging
from openlp.core.lib import StringContent
log = logging.getLogger(__name__)
class MediaDockManager(object):
"""
Provide a repository for MediaManagerItems

View File

@ -26,15 +26,23 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The UI widgets of the plugin view dialog
#"""
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate, UiStrings
from openlp.core.lib import UiStrings, translate
from openlp.core.lib.ui import create_button_box
class Ui_PluginViewDialog(object):
"""
The UI of the plugin view dialog
"""
def setupUi(self, pluginViewDialog):
"""
Set up the UI
"""
pluginViewDialog.setObjectName(u'pluginViewDialog')
pluginViewDialog.setWindowModality(QtCore.Qt.ApplicationModal)
self.pluginLayout = QtGui.QVBoxLayout(pluginViewDialog)
@ -72,6 +80,9 @@ class Ui_PluginViewDialog(object):
self.retranslateUi(pluginViewDialog)
def retranslateUi(self, pluginViewDialog):
"""
Translate the UI on the fly
"""
pluginViewDialog.setWindowTitle(translate('OpenLP.PluginForm', 'Plugin List'))
self.pluginInfoGroupBox.setTitle(translate('OpenLP.PluginForm', 'Plugin Details'))
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 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The actual plugin view form
"""
import logging
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
log = logging.getLogger(__name__)
class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
"""
The plugin form provides user control over the plugins OpenLP uses.
"""
def __init__(self, parent=None):
"""
Constructor
"""
QtGui.QDialog.__init__(self, parent)
self.activePlugin = None
self.programaticChange = False
@ -62,7 +68,7 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
self._clearDetails()
self.programaticChange = True
pluginListWidth = 0
for plugin in self.parent().pluginManager.plugins:
for plugin in self.plugin_manager.plugins:
item = QtGui.QListWidgetItem(self.pluginListWidget)
# 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.
@ -85,12 +91,18 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
self.pluginListWidget.setFixedWidth(pluginListWidth + self.pluginListWidget.iconSize().width() + 48)
def _clearDetails(self):
"""
Clear the plugin details widgets
"""
self.statusComboBox.setCurrentIndex(-1)
self.versionNumberLabel.setText(u'')
self.aboutTextBrowser.setHtml(u'')
self.statusComboBox.setEnabled(False)
def _setDetails(self):
"""
Set the details of the currently selected plugin
"""
log.debug(u'PluginStatus: %s', str(self.activePlugin.status))
self.versionNumberLabel.setText(self.activePlugin.version)
self.aboutTextBrowser.setHtml(self.activePlugin.about())
@ -103,13 +115,15 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
self.programaticChange = False
def onPluginListWidgetSelectionChanged(self):
"""
If the selected plugin changes, update the form
"""
if self.pluginListWidget.currentItem() is None:
self._clearDetails()
return
plugin_name_singular = \
self.pluginListWidget.currentItem().text().split(u'(')[0][:-1]
plugin_name_singular = self.pluginListWidget.currentItem().text().split(u'(')[0][:-1]
self.activePlugin = None
for plugin in self.parent().pluginManager.plugins:
for plugin in self.plugin_manager.plugins:
if plugin.status != PluginStatus.Disabled:
if plugin.nameStrings[u'singular'] == plugin_name_singular:
self.activePlugin = plugin
@ -120,13 +134,16 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
self._clearDetails()
def onStatusComboBoxChanged(self, status):
"""
If the status of a plugin is altered, apply the change
"""
if self.programaticChange or status == PluginStatus.Disabled:
return
if status == PluginStatus.Inactive:
Receiver.send_message(u'cursor_busy')
self.application.set_busy_cursor()
self.activePlugin.toggleStatus(PluginStatus.Active)
Receiver.send_message(u'cursor_normal')
self.activePlugin.appStartup()
self.application.set_normal_cursor()
self.activePlugin.app_startup()
else:
self.activePlugin.toggleStatus(PluginStatus.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)')
self.pluginListWidget.currentItem().setText(
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,10 +26,13 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The UI widgets of the print service dialog.
"""
from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, translate, SpellTextEdit, UiStrings
from openlp.core.lib import SpellTextEdit, UiStrings, build_icon, translate
class ZoomSize(object):
"""
@ -44,7 +47,13 @@ class ZoomSize(object):
class Ui_PrintServiceDialog(object):
"""
The UI of the print service dialog
"""
def setupUi(self, printServiceDialog):
"""
Set up the UI
"""
printServiceDialog.setObjectName(u'printServiceDialog')
printServiceDialog.resize(664, 594)
self.mainLayout = QtGui.QVBoxLayout(printServiceDialog)
@ -121,9 +130,12 @@ class Ui_PrintServiceDialog(object):
self.optionsLayout.addWidget(self.optionsGroupBox)
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):
"""
Translate the UI on the fly
"""
printServiceDialog.setWindowTitle(UiStrings().PrintService)
self.zoomOutButton.setToolTip(translate('OpenLP.PrintServiceForm', 'Zoom Out'))
self.zoomOriginalButton.setToolTip(translate('OpenLP.PrintServiceForm', 'Zoom Original'))
@ -131,7 +143,7 @@ class Ui_PrintServiceDialog(object):
self.optionsButton.setText(translate('OpenLP.PrintServiceForm', 'Options'))
self.titleLabel.setText(translate('OpenLP.PrintServiceForm', 'Title:'))
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.pageBreakAfterText.setText(translate('OpenLP.PrintServiceForm', 'Add page break before each text item'))
self.notesCheckBox.setText(translate('OpenLP.PrintServiceForm', 'Include service item notes'))
@ -144,6 +156,5 @@ class Ui_PrintServiceDialog(object):
u'100%',
u'75%',
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 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The actual print service dialog
"""
import cgi
import datetime
import os
@ -33,7 +36,7 @@ import os
from PyQt4 import QtCore, QtGui
from lxml import html
from openlp.core.lib import translate, get_text_file_string, Receiver, Settings, UiStrings, Registry
from openlp.core.lib import Receiver, Settings, UiStrings, Registry, translate, get_text_file_string
from openlp.core.ui.printservicedialog import Ui_PrintServiceDialog, ZoomSize
from openlp.core.utils import AppLocation
@ -106,8 +109,11 @@ http://doc.trolltech.com/4.7/richtext-html-subset.html#css-properties
}
"""
class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
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
@ -143,6 +149,9 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
self.updatePreviewText()
def toggleOptions(self, checked):
"""
Toggle various options
"""
self.optionsWidget.setVisible(checked)
if checked:
left = self.optionsButton.pos().x()
@ -169,7 +178,7 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
self._addElement(u'body', parent=html_data)
self._addElement(u'h1', cgi.escape(self.titleLineEdit.text()),
html_data.body, classId=u'serviceTitle')
for index, item in enumerate(self.service_manager.serviceItems):
for index, item in enumerate(self.service_manager.service_items):
self._addPreviewItem(html_data.body, item[u'service_item'], index)
# Add the custom service notes:
if self.footerTextEdit.toPlainText():
@ -181,6 +190,9 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
self.previewWidget.updatePreview()
def _addPreviewItem(self, body, item, index):
"""
Add a preview item
"""
div = self._addElement(u'div', classId=u'item', parent=body)
# Add the title of the service item.
item_title = self._addElement(u'h2', parent=div, classId=u'itemTitle')
@ -388,6 +400,9 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
settings.endGroup()
def update_song_usage(self):
"""
Update the song usage
"""
# Only continue when we include the song's text.
if not self.slideTextCheckBox.isChecked():
return
@ -413,4 +428,4 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
self._main_window = Registry().get(u'main_window')
return self._main_window
main_window = property(_get_main_window)
main_window = property(_get_main_window)

View File

@ -26,14 +26,23 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The UI widgets for the service item edit dialog
"""
from PyQt4 import QtGui
from openlp.core.lib import translate
from openlp.core.lib.ui import create_button_box, create_button
class Ui_ServiceItemEditDialog(object):
"""
The UI widgets for the service item edit dialog
"""
def setupUi(self, serviceItemEditDialog):
"""
Set up the UI
"""
serviceItemEditDialog.setObjectName(u'serviceItemEditDialog')
self.dialog_layout = QtGui.QGridLayout(serviceItemEditDialog)
self.dialog_layout.setContentsMargins(8, 8, 8, 8)
@ -61,4 +70,7 @@ class Ui_ServiceItemEditDialog(object):
self.retranslateUi(serviceItemEditDialog)
def retranslateUi(self, serviceItemEditDialog):
"""
Translate the UI on the fly
"""
serviceItemEditDialog.setWindowTitle(translate('OpenLP.ServiceItemEditForm', 'Reorder Service Item'))

View File

@ -26,12 +26,15 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The service item edit dialog
"""
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Registry
from serviceitemeditdialog import Ui_ServiceItemEditDialog
class ServiceItemEditForm(QtGui.QDialog, Ui_ServiceItemEditDialog):
"""
This is the form that is used to edit the verses of the song.
@ -47,6 +50,9 @@ class ServiceItemEditForm(QtGui.QDialog, Ui_ServiceItemEditDialog):
self.on_current_row_changed)
def set_service_item(self, item):
"""
Set the service item to be edited.
"""
self.item = item
self.item_list = []
if self.item.is_image():
@ -57,6 +63,9 @@ class ServiceItemEditForm(QtGui.QDialog, Ui_ServiceItemEditDialog):
self.list_widget.setCurrentItem(self.list_widget.currentItem())
def get_service_item(self):
"""
Get the modified service item.
"""
if self.data:
self.item._raw_frames = []
if self.item.is_image():

View File

@ -26,6 +26,9 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The service manager sets up, loads, saves and manages services.
"""
import cgi
import cPickle
import logging
@ -39,8 +42,8 @@ log = logging.getLogger(__name__)
from PyQt4 import QtCore, QtGui
from openlp.core.lib import OpenLPToolbar, ServiceItem, Receiver, build_icon, ItemCapabilities, SettingsManager, \
translate, str_to_bool, check_directory_exists, Settings, PluginStatus, Registry, UiStrings
from openlp.core.lib import OpenLPToolbar, ServiceItem, Receiver, ItemCapabilities, Settings, PluginStatus, Registry, \
UiStrings, build_icon, translate, str_to_bool, check_directory_exists
from openlp.core.lib.theme import ThemeLevel
from openlp.core.lib.ui import critical_error_message_box, create_widget_action, find_and_set_in_combo_box
from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm, StartTimeForm
@ -48,11 +51,15 @@ from openlp.core.ui.printserviceform import PrintServiceForm
from openlp.core.utils import AppLocation, delete_file, split_filename, format_time
from openlp.core.utils.actions import ActionList, CategoryOrder
class ServiceManagerList(QtGui.QTreeWidget):
"""
Set up key bindings and mouse behaviour for the service list
"""
def __init__(self, serviceManager, parent=None):
"""
Constructor
"""
QtGui.QTreeWidget.__init__(self, parent)
self.serviceManager = serviceManager
@ -93,16 +100,22 @@ class ServiceManagerList(QtGui.QTreeWidget):
mime_data.setText(u'ServiceManager')
drag.start(QtCore.Qt.CopyAction)
class ServiceManagerDialog(object):
"""
UI part of the Service Manager
"""
def setup_ui(self,widget):
def setup_ui(self, widget):
"""
Define the UI
"""
# Create the top toolbar
self.toolbar = OpenLPToolbar(self)
self.toolbar.addToolbarAction(u'newService', text=UiStrings().NewService, icon=u':/general/general_new.png',
tooltip=UiStrings().CreateService, triggers=self.on_new_service_clicked)
self.toolbar.addToolbarAction(u'openService', text=UiStrings().OpenService, icon=u':/general/general_open.png',
tooltip=translate('OpenLP.ServiceManager', 'Load an existing service.'), triggers=self.on_load_service_clicked)
tooltip=translate('OpenLP.ServiceManager', 'Load an existing service.'),
triggers=self.on_load_service_clicked)
self.toolbar.addToolbarAction(u'saveService', text=UiStrings().SaveService, icon=u':/general/general_save.png',
tooltip=translate('OpenLP.ServiceManager', 'Save this service.'), triggers=self.decide_save_method)
self.toolbar.addSeparator()
@ -185,7 +198,8 @@ class ServiceManagerDialog(object):
self.service_manager_list.make_live = self.order_toolbar.addToolbarAction(u'make_live',
text=translate('OpenLP.ServiceManager', 'Go Live'), icon=u':/general/general_live.png',
tooltip=translate('OpenLP.ServiceManager', 'Send the selected item to Live.'),
shortcuts=[QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return], category=UiStrings().Service, triggers=self.make_live)
shortcuts=[QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return], category=UiStrings().Service,
triggers=self.make_live)
self.layout.addWidget(self.order_toolbar)
# Connect up our signals and slots
QtCore.QObject.connect(self.theme_combo_box, QtCore.SIGNAL(u'activated(int)'),
@ -197,17 +211,10 @@ class ServiceManagerDialog(object):
QtCore.QObject.connect(self.service_manager_list, QtCore.SIGNAL(u'itemExpanded(QTreeWidgetItem*)'),
self.expanded)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'theme_update_list'), self.update_theme_list)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'servicemanager_preview_live'),
self.preview_live)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'servicemanager_next_item'), self.next_item)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'servicemanager_previous_item'),
self.previous_item)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'servicemanager_set_item'), self.on_set_item)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_updated'), self.config_updated)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_screen_changed'),
self.regenerate_service_Items)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'theme_update_global'), self.themeChange)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'service_item_update'), self.serviceItemUpdate)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'theme_update_global'), self.theme_change)
# Last little bits of setting up
self.service_theme = Settings().value(self.main_window.serviceManagerSettingsSection + u'/service theme')
self.servicePath = AppLocation.get_section_data_path(u'servicemanager')
@ -402,10 +409,12 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
elif result == QtGui.QMessageBox.Save:
self.decide_save_method()
if not load_file:
file_name = QtGui.QFileDialog.getOpenfile_name(self.main_window,
file_name = QtGui.QFileDialog.getOpenFileName(
self.main_window,
translate('OpenLP.ServiceManager', 'Open File'),
SettingsManager.get_last_dir(self.main_window.serviceManagerSettingsSection),
translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz *.oszl)'))
Settings().value(self.main_window.serviceManagerSettingsSection + u'/last directory'),
translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz *.oszl)')
)
if not file_name:
return False
else:
@ -441,7 +450,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
self.service_id += 1
self.set_modified(False)
Settings().setValue(u'servicemanager/last file', u'')
Receiver.send_message(u'servicemanager_new_service')
self.plugin_manager.new_service_created()
def save_file(self):
"""
@ -469,7 +478,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
missing_list = []
audio_files = []
total_size = 0
Receiver.send_message(u'cursor_busy')
self.application.set_busy_cursor()
# Number of items + 1 to zip it
self.main_window.displayProgressBar(len(self.service_items) + 1)
# Get list of missing files, and list of files to write
@ -485,7 +494,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
else:
write_list.append(path_from)
if missing_list:
Receiver.send_message(u'cursor_normal')
self.application.set_normal_cursor()
title = translate('OpenLP.ServiceManager', 'Service File(s) Missing')
message = translate('OpenLP.ServiceManager',
'The following file(s) in the service are missing:\n\t%s\n\n'
@ -495,7 +504,6 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
if answer == QtGui.QMessageBox.Cancel:
self.main_window.finishedProgressBar()
return False
Receiver.send_message(u'cursor_busy')
# Check if item contains a missing file.
for item in list(self.service_items):
self.main_window.incrementProgressBar()
@ -556,11 +564,11 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
if zip_file:
zip_file.close()
self.main_window.finishedProgressBar()
Receiver.send_message(u'cursor_normal')
self.application.set_normal_cursor()
if success:
try:
shutil.copy(temp_file_name, path_file_name)
except:
except shutil.Error:
return self.save_file_as()
self.main_window.addRecentFile(path_file_name)
self.set_modified(False)
@ -585,7 +593,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
log.debug(u'ServiceManager.save_file - %s', path_file_name)
Settings().setValue(self.main_window.serviceManagerSettingsSection + u'/last directory', path)
service = []
Receiver.send_message(u'cursor_busy')
self.application.set_busy_cursor()
# Number of items + 1 to zip it
self.main_window.displayProgressBar(len(self.service_items) + 1)
for item in self.service_items:
@ -614,11 +622,11 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
if zip_file:
zip_file.close()
self.main_window.finishedProgressBar()
Receiver.send_message(u'cursor_normal')
self.application.set_normal_cursor()
if success:
try:
shutil.copy(temp_file_name, path_file_name)
except:
except shutil.Error:
return self.save_file_as()
self.main_window.addRecentFile(path_file_name)
self.set_modified(False)
@ -653,11 +661,11 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
# SaveAs from osz to oszl is not valid as the files will be deleted
# on exit which is not sensible or usable in the long term.
if self._file_name.endswith(u'oszl') or self.service_has_all_original_files:
file_name = QtGui.QFileDialog.getSavefile_name(self.main_window, UiStrings().SaveService, path,
file_name = QtGui.QFileDialog.getSaveFileName(self.main_window, UiStrings().SaveService, path,
translate('OpenLP.ServiceManager',
'OpenLP Service Files (*.osz);; OpenLP Service Files - lite (*.oszl)'))
else:
file_name = QtGui.QFileDialog.getSavefile_name(self.main_window, UiStrings().SaveService, path,
file_name = QtGui.QFileDialog.getSaveFileName(self.main_window, UiStrings().SaveService, path,
translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz);;'))
if not file_name:
return False
@ -691,13 +699,15 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
return False
zip_file = None
file_to = None
self.application.set_busy_cursor()
try:
zip_file = zipfile.ZipFile(file_name)
for zip_info in zip_file.infolist():
try:
ucsfile = zip_info.filename.decode(u'utf-8')
except UnicodeDecodeError:
log.exception(u'file_name "%s" is not valid UTF-8' % zip_info.file_name.decode(u'utf-8', u'replace'))
log.exception(u'file_name "%s" is not valid UTF-8' %
zip_info.file_name.decode(u'utf-8', u'replace'))
critical_error_message_box(message=translate('OpenLP.ServiceManager',
'File is not a valid service.\n The content encoding is not UTF-8.'))
continue
@ -710,7 +720,6 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
if osfile.endswith(u'osd'):
p_file = os.path.join(self.servicePath, osfile)
if 'p_file' in locals():
Receiver.send_message(u'cursor_busy')
file_to = open(p_file, u'r')
items = cPickle.load(file_to)
file_to.close()
@ -755,6 +764,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
QtGui.QMessageBox.information(self, translate('OpenLP.ServiceManager', 'Corrupt File'),
translate('OpenLP.ServiceManager',
'This file is either corrupt or it is not an OpenLP 2 service file.'))
self.application.set_normal_cursor()
return
finally:
if file_to:
@ -762,7 +772,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
if zip_file:
zip_file.close()
self.main_window.finishedProgressBar()
Receiver.send_message(u'cursor_normal')
self.application.set_normal_cursor()
self.repaint_service_list(-1, -1)
def load_Last_file(self):
@ -809,7 +819,8 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
delay_suffix = u' %s s' % unicode(service_item[u'service_item'].timed_slide_interval)
else:
delay_suffix = u' ...'
self.timed_slide_interval.setText(translate('OpenLP.ServiceManager', '&Delay between slides') + delay_suffix)
self.timed_slide_interval.setText(
translate('OpenLP.ServiceManager', '&Delay between slides') + delay_suffix)
# TODO for future: make group explains itself more visually
else:
self.auto_play_slides_group.menuAction().setVisible(False)
@ -818,7 +829,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
if service_item[u'service_item'].is_capable(ItemCapabilities.CanAutoStartForLive):
self.auto_start_action.setVisible(True)
self.auto_start_action.setIcon(self.inactive)
self.auto_start_action.setText(translate('OpenLP.ServiceManager','&Auto Start - inactive'))
self.auto_start_action.setText(translate('OpenLP.ServiceManager', '&Auto Start - inactive'))
if service_item[u'service_item'].will_auto_start:
self.auto_start_action.setText(translate('OpenLP.ServiceManager', '&Auto Start - active'))
self.auto_start_action.setIcon(self.active)
@ -876,7 +887,6 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
self.main_window.generalSettingsSection + u'/loop delay')
self.set_modified()
def toggle_auto_play_slides_loop(self):
"""
Toggle Auto play slide loop.
@ -892,7 +902,6 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
self.main_window.generalSettingsSection + u'/loop delay')
self.set_modified()
def on_timed_slide_interval(self):
"""
Shows input dialog for enter interval in seconds for delay
@ -935,12 +944,20 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
self.add_service_item(self.serviceItemEditForm.get_service_item(),
replace=True, expand=self.service_items[item][u'expanded'])
def preview_live(self, message):
def preview_live(self, unique_identifier, row):
"""
Called by the SlideController to request a preview item be made live
and allows the next preview to be updated if relevant.
``unique_identifier``
Reference to the service_item
``row``
individual row number
"""
unique_identifier, row = message.split(u':')
for sitem in self.service_items:
if sitem[u'service_item'].unique_identifier == unique_identifier:
item = self.service_manager_list.topLevelItem(sitem[u'order'] - 1)
@ -966,9 +983,13 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
lookFor = 1
serviceIterator += 1
def previous_item(self, message):
def previous_item(self, last_slide=False):
"""
Called by the SlideController to select the previous service item.
``last_slide``
Is this the last slide in the service_item
"""
if not self.service_manager_list.selectedItems():
return
@ -978,7 +999,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
serviceIterator = QtGui.QTreeWidgetItemIterator(self.service_manager_list)
while serviceIterator.value():
if serviceIterator.value() == selected:
if message == u'last slide' and prevItemLastSlide:
if last_slide and prevItemLastSlide:
pos = prevItem.data(0, QtCore.Qt.UserRole)
check_expanded = self.service_items[pos - 1][u'expanded']
self.service_manager_list.setCurrentItem(prevItemLastSlide)
@ -1201,13 +1222,13 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
self.service_manager_list.setCurrentItem(treewidgetitem)
treewidgetitem.setExpanded(item[u'expanded'])
def cleanUp(self):
def clean_up(self):
"""
Empties the servicePath of temporary files on system exit.
"""
log.debug(u'Cleaning up servicePath')
for file in os.listdir(self.servicePath):
file_path = os.path.join(self.servicePath, file)
for file_name in os.listdir(self.servicePath):
file_path = os.path.join(self.servicePath, file_name)
delete_file(file_path)
if os.path.exists(os.path.join(self.servicePath, u'audio')):
shutil.rmtree(os.path.join(self.servicePath, u'audio'), True)
@ -1222,12 +1243,12 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
Settings().setValue(self.main_window.serviceManagerSettingsSection + u'/service theme', self.service_theme)
self.regenerate_service_Items(True)
def themeChange(self):
def theme_change(self):
"""
The theme may have changed in the settings dialog so make
sure the theme combo box is in the correct state.
"""
log.debug(u'themeChange')
log.debug(u'theme_change')
visible = self.renderer.theme_level == ThemeLevel.Global
self.theme_label.setVisible(visible)
self.theme_combo_box.setVisible(visible)
@ -1237,7 +1258,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
Rebuild the service list as things have changed and a
repaint is the easiest way to do this.
"""
Receiver.send_message(u'cursor_busy')
self.application.set_busy_cursor()
log.debug(u'regenerate_service_Items')
# force reset of renderer as theme data has changed
self.service_has_all_original_files = True
@ -1269,14 +1290,14 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
self.set_modified()
# Repaint it once only at the end
self.repaint_service_list(-1, -1)
Receiver.send_message(u'cursor_normal')
self.application.set_normal_cursor()
def serviceItemUpdate(self, message):
def service_item_update(self, edit_id, unique_identifier, temporary=False):
"""
Triggered from plugins to update service items.
Save the values as they will be used as part of the service load
"""
edit_id, self.load_item_unique_identifier, temporary = message.split(u':')
self.load_item_unique_identifier = unique_identifier
self.load_item_edit_id = int(edit_id)
self.load_item_temporary = str_to_bool(temporary)
@ -1344,7 +1365,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
"""
Send the current item to the Preview slide controller
"""
Receiver.send_message(u'cursor_busy')
self.application.set_busy_cursor()
item, child = self.find_service_item()
if self.service_items[item][u'service_item'].is_valid:
self.preview_controller.addServiceManagerItem(self.service_items[item][u'service_item'], child)
@ -1352,7 +1373,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
critical_error_message_box(translate('OpenLP.ServiceManager', 'Missing Display Handler'),
translate('OpenLP.ServiceManager',
'Your item cannot be displayed as there is no handler to display it'))
Receiver.send_message(u'cursor_normal')
self.application.set_normal_cursor()
def get_service_item(self):
"""
@ -1385,7 +1406,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
return
if row != -1:
child = row
Receiver.send_message(u'cursor_busy')
self.application.set_busy_cursor()
if self.service_items[item][u'service_item'].is_valid:
self.live_controller.addServiceManagerItem(self.service_items[item][u'service_item'], child)
if Settings().value(self.main_window.generalSettingsSection + u'/auto preview'):
@ -1400,13 +1421,13 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
critical_error_message_box(translate('OpenLP.ServiceManager', 'Missing Display Handler'),
translate('OpenLP.ServiceManager',
'Your item cannot be displayed as the plugin required to display it is missing or inactive'))
Receiver.send_message(u'cursor_normal')
self.application.set_normal_cursor()
def remote_edit(self):
"""
Triggers a remote edit to a plugin to allow item to be edited.
"""
item, child = self.find_service_item()
item = self.find_service_item()[0]
if self.service_items[item][u'service_item'].is_capable(ItemCapabilities.CanEdit):
new_item = Registry().get(self.service_items[item][u'service_item'].name). \
onRemoteEdit(self.service_items[item][u'service_item'].edit_id)
@ -1612,4 +1633,14 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
self._main_window = Registry().get(u'main_window')
return self._main_window
main_window = property(_get_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,12 +26,15 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# 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 openlp.core.lib import translate, SpellTextEdit, Registry
from openlp.core.lib import SpellTextEdit, Registry, translate
from openlp.core.lib.ui import create_button_box
class ServiceNoteForm(QtGui.QDialog):
"""
This is the form that is used to edit the verses of the song.
@ -45,10 +48,16 @@ class ServiceNoteForm(QtGui.QDialog):
self.retranslateUi()
def exec_(self):
"""
Execute the form and return the result.
"""
self.text_edit.setFocus()
return QtGui.QDialog.exec_(self)
def setupUi(self):
"""
Set up the UI of the dialog
"""
self.setObjectName(u'serviceNoteEdit')
self.dialog_layout = QtGui.QVBoxLayout(self)
self.dialog_layout.setContentsMargins(8, 8, 8, 8)
@ -61,6 +70,9 @@ class ServiceNoteForm(QtGui.QDialog):
self.dialog_layout.addWidget(self.button_box)
def retranslateUi(self):
"""
Translate the UI on the fly
"""
self.setWindowTitle(translate('OpenLP.ServiceNoteForm', 'Service Item Notes'))
def _get_main_window(self):
@ -71,4 +83,4 @@ class ServiceNoteForm(QtGui.QDialog):
self._main_window = Registry().get(u'main_window')
return self._main_window
main_window = property(_get_main_window)
main_window = property(_get_main_window)

View File

@ -26,14 +26,23 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The UI widgets of the settings dialog.
"""
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate, build_icon
from openlp.core.lib.ui import create_button_box
class Ui_SettingsDialog(object):
"""
The UI widgets of the settings dialog.
"""
def setupUi(self, settingsDialog):
"""
Set up the UI
"""
settingsDialog.setObjectName(u'settingsDialog')
settingsDialog.resize(800, 500)
settingsDialog.setWindowIcon(build_icon(u':/system/system_settings.png'))
@ -55,4 +64,7 @@ class Ui_SettingsDialog(object):
QtCore.QObject.connect(self.settingListWidget, QtCore.SIGNAL(u'currentRowChanged(int)'), self.tabChanged)
def retranslateUi(self, settingsDialog):
"""
Translate the UI on the fly
"""
settingsDialog.setWindowTitle(translate('OpenLP.SettingsForm', 'Configure OpenLP'))

View File

@ -33,13 +33,14 @@ import logging
from PyQt4 import QtGui
from openlp.core.lib import Receiver, build_icon, PluginStatus, Registry
from openlp.core.lib import Receiver, PluginStatus, Registry, build_icon
from openlp.core.ui import AdvancedTab, GeneralTab, ThemesTab
from openlp.core.ui.media import PlayerTab
from settingsdialog import Ui_SettingsDialog
log = logging.getLogger(__name__)
class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
"""
Provide the form to manipulate the settings for OpenLP
@ -54,13 +55,16 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
# General tab
self.generalTab = GeneralTab(self)
# Themes tab
self.themesTab = ThemesTab(self, self.main_window)
self.themesTab = ThemesTab(self)
# Advanced tab
self.advancedTab = AdvancedTab(self)
# Advanced tab
self.playerTab = PlayerTab(self, self.main_window)
self.playerTab = PlayerTab(self)
def exec_(self):
"""
Execute the form
"""
# load all the settings
self.settingListWidget.clear()
while self.stackedLayout.count():
@ -161,4 +165,4 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
self._service_manager = Registry().get(u'service_manager')
return self._service_manager
service_manager = property(_get_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 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The list of shortcuts within a dialog.
"""
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate, build_icon
from openlp.core.lib.ui import create_button_box
class CaptureShortcutButton(QtGui.QPushButton):
"""
A class to encapsulate a ``QPushButton``.
"""
def __init__(self, *args):
"""
Constructor
"""
QtGui.QPushButton.__init__(self, *args)
self.setCheckable(True)
@ -51,7 +57,13 @@ class CaptureShortcutButton(QtGui.QPushButton):
class Ui_ShortcutListDialog(object):
"""
The UI widgets for the shortcut dialog.
"""
def setupUi(self, shortcutListDialog):
"""
Set up the UI
"""
shortcutListDialog.setObjectName(u'shortcutListDialog')
shortcutListDialog.resize(500, 438)
self.shortcutListLayout = QtGui.QVBoxLayout(shortcutListDialog)
@ -113,6 +125,9 @@ class Ui_ShortcutListDialog(object):
self.retranslateUi(shortcutListDialog)
def retranslateUi(self, shortcutListDialog):
"""
Translate the UI on the fly
"""
shortcutListDialog.setWindowTitle(translate('OpenLP.ShortcutListDialog', 'Configure Shortcuts'))
self.descriptionLabel.setText(
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 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`~openlp.core.ui.shortcutlistform` module contains the form class"""
import logging
import re
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.actions import ActionList
from shortcutlistdialog import Ui_ShortcutListDialog
@ -48,6 +49,9 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
"""
def __init__(self, parent=None):
"""
Constructor
"""
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
self.changedActions = {}
@ -72,6 +76,9 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
self.onCustomRadioButtonClicked)
def keyPressEvent(self, event):
"""
Respond to certain key presses
"""
if event.key() == QtCore.Qt.Key_Space:
self.keyReleaseEvent(event)
elif self.primaryPushButton.isChecked() or self.alternatePushButton.isChecked():
@ -81,6 +88,9 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
self.close()
def keyReleaseEvent(self, event):
"""
Respond to certain key presses
"""
if not self.primaryPushButton.isChecked() and not self.alternatePushButton.isChecked():
return
key = event.key()
@ -106,6 +116,9 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
False, text=key_sequence.toString())
def exec_(self):
"""
Execute the dialog
"""
self.changedActions = {}
self.reloadShortcutList()
self._adjustButton(self.primaryPushButton, False, False, u'')
@ -422,10 +435,10 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
if action.shortcutContext() in [QtCore.Qt.WindowShortcut,
QtCore.Qt.ApplicationShortcut]:
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
if not is_valid:
Receiver.send_message(u'openlp_warning_message', {
self.main_window.warning_message( {
u'title': translate('OpenLP.ShortcutListDialog', 'Duplicate Shortcut'),
u'message': translate('OpenLP.ShortcutListDialog',
'The shortcut "%s" is already assigned to another action, '
@ -465,3 +478,13 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
button.setChecked(checked)
if enabled is not None:
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 #
# 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 logging
import copy
@ -34,8 +36,8 @@ from collections import deque
from PyQt4 import QtCore, QtGui
from openlp.core.lib import OpenLPToolbar, Receiver, ItemCapabilities, translate, build_icon, build_html, \
ServiceItem, ImageSource, SlideLimits, ServiceItemAction, Settings, Registry, UiStrings, ScreenList
from openlp.core.lib import OpenLPToolbar, Receiver, ItemCapabilities, ServiceItem, ImageSource, SlideLimits, \
ServiceItemAction, Settings, Registry, UiStrings, ScreenList, build_icon, build_html, translate
from openlp.core.ui import HideMode, MainDisplay, Display, DisplayControllerType
from openlp.core.lib.ui import create_action
from openlp.core.utils.actions import ActionList, CategoryOrder
@ -92,6 +94,14 @@ class SlideController(DisplayController):
u'audioPauseItem',
u'audioTimeLabel'
]
self.wideMenu = [
u'blankScreenButton',
u'themeScreenButton',
u'desktopScreenButton'
]
self.hideMenuList = [
u'hideMenu'
]
self.timer_id = 0
self.songEdit = False
self.selectedRow = 0
@ -193,6 +203,19 @@ class SlideController(DisplayController):
self.hideMenu.menu().addAction(self.blankScreen)
self.hideMenu.menu().addAction(self.themeScreen)
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)
# Play Slides Menu
self.playSlidesMenu = QtGui.QToolButton(self.toolbar)
@ -207,7 +230,7 @@ class SlideController(DisplayController):
self.playSlidesOnce = create_action(self, u'playSlidesOnce', text=UiStrings().PlaySlidesToEnd,
icon=u':/media/media_time.png', checked=False, shortcuts=[],
category=self.category, triggers=self.onPlaySlidesOnce)
if Settings().value(self.parent().generalSettingsSection + u'/enable slide loop'):
if Settings().value(self.parent().advancedSettingsSection + u'/slide limits') == SlideLimits.Wrap:
self.playSlidesMenu.setDefaultAction(self.playSlidesLoop)
else:
self.playSlidesMenu.setDefaultAction(self.playSlidesOnce)
@ -257,7 +280,7 @@ class SlideController(DisplayController):
self.audioMenu.addAction(self.nextTrackItem)
self.trackMenu = self.audioMenu.addMenu(translate('OpenLP.SlideController', 'Tracks'))
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(
u'background-color: palette(background); '
u'border-top-color: palette(shadow); '
@ -288,7 +311,7 @@ class SlideController(DisplayController):
self.slideLayout.setObjectName(u'SlideLayout')
self.previewDisplay = Display(self, self.isLive, self)
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.slideLayout.insertWidget(0, self.previewDisplay)
self.previewDisplay.hide()
@ -344,6 +367,7 @@ class SlideController(DisplayController):
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'slidecontroller_toggle_display'), self.toggleDisplay)
self.toolbar.setWidgetVisible(self.loopList, False)
self.toolbar.setWidgetVisible(self.wideMenu, False)
else:
QtCore.QObject.connect(self.previewListWidget,
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onGoLiveClick)
@ -432,6 +456,9 @@ class SlideController(DisplayController):
self.current_shortcut = u''
def setLiveHotkeys(self, parent=None):
"""
Set the live hotkeys
"""
self.previousService = create_action(parent, u'previousService',
text=translate('OpenLP.SlideController', 'Previous Service'),
shortcuts=[QtCore.Qt.Key_Left], context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category,
@ -442,10 +469,13 @@ class SlideController(DisplayController):
triggers=self.serviceNext)
self.escapeItem = create_action(parent, 'escapeItem',
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)
def liveEscape(self):
"""
If you press ESC on the live screen it should close the display temporarily.
"""
self.display.setVisible(False)
self.media_controller.media_stop(self)
@ -488,12 +518,12 @@ class SlideController(DisplayController):
self.keypress_loop = True
keypressCommand = self.keypress_queue.popleft()
if keypressCommand == ServiceItemAction.Previous:
Receiver.send_message('servicemanager_previous_item')
self.service_manager.previous_item()
elif keypressCommand == ServiceItemAction.PreviousLastSlide:
# 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:
Receiver.send_message('servicemanager_next_item')
self.service_manager.next_item()
self.keypress_loop = False
def screenSizeChanged(self):
@ -520,11 +550,14 @@ class SlideController(DisplayController):
serviceItem = ServiceItem()
self.previewDisplay.webView.setHtml(build_html(serviceItem, self.previewDisplay.screen, None, self.isLive,
plugins=self.plugin_manager.plugins))
self.media_controller.setup_display(self.previewDisplay,True)
self.media_controller.setup_display(self.previewDisplay, True)
if self.serviceItem:
self.refreshServiceItem()
def __addActionsToWidget(self, widget):
"""
Add actions to the widget specified by `widget`
"""
widget.addActions([
self.previousItem, self.nextItem,
self.previousService, self.nextService,
@ -562,8 +595,24 @@ class SlideController(DisplayController):
width = self.parent().controlSplitter.sizes()[self.split]
for framenumber in range(len(self.serviceItem.get_frames())):
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):
"""
Some song handler
"""
request = self.sender().text()
slide_no = self.slideList[request]
self.__updatePreviewSelection(slide_no)
@ -690,7 +739,7 @@ class SlideController(DisplayController):
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:
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()
@ -770,9 +819,9 @@ class SlideController(DisplayController):
else:
# If current slide set background to image
if framenumber == slideno:
self.serviceItem.bg_image_bytes = self.image_manager.getImageBytes(frame[u'path'],
self.serviceItem.bg_image_bytes = self.image_manager.get_image_bytes(frame[u'path'],
ImageSource.ImagePlugin)
image = self.image_manager.getImage(frame[u'path'], ImageSource.ImagePlugin)
image = self.image_manager.get_image(frame[u'path'], ImageSource.ImagePlugin)
label.setPixmap(QtGui.QPixmap.fromImage(image))
self.previewListWidget.setCellWidget(framenumber, 0, label)
slideHeight = width * (1 / self.ratio)
@ -1088,6 +1137,9 @@ class SlideController(DisplayController):
self.slideSelected()
def __checkUpdateSelectedSlide(self, row):
"""
Check if this slide has been updated
"""
if row + 1 < self.previewListWidget.rowCount():
self.previewListWidget.scrollToItem(self.previewListWidget.item(row + 1, 0))
self.previewListWidget.selectRow(row)
@ -1160,9 +1212,15 @@ class SlideController(DisplayController):
self.onToggleLoop()
def setAudioItemsVisibility(self, visible):
"""
Set the visibility of the audio stuff
"""
self.toolbar.setWidgetVisible(self.audioList, visible)
def onAudioPauseClicked(self, checked):
"""
Pause the audio player
"""
if not self.audioPauseItem.isVisible():
return
if checked:
@ -1213,8 +1271,7 @@ class SlideController(DisplayController):
row = self.previewListWidget.currentRow()
if -1 < row < self.previewListWidget.rowCount():
if self.serviceItem.from_service:
Receiver.send_message('servicemanager_preview_live', u'%s:%s' %
(self.serviceItem.unique_identifier, row))
self.service_manager.preview_live(self.serviceItem.unique_identifier, row)
else:
self.live_controller.addServiceManagerItem(self.serviceItem, row)
@ -1268,15 +1325,24 @@ class SlideController(DisplayController):
return None
def onNextTrackClicked(self):
"""
Go to the next track when next is clicked
"""
self.display.audioPlayer.next()
def onAudioTimeRemaining(self, time):
"""
Update how much time is remaining
"""
seconds = self.display.audioPlayer.mediaObject.remainingTime() // 1000
minutes = seconds // 60
seconds %= 60
self.audioTimeLabel.setText(u' %02d:%02d ' % (minutes, seconds))
def onTrackTriggered(self):
"""
Start playing a track
"""
action = self.sender()
self.display.audioPlayer.goTo(action.data())
@ -1328,4 +1394,4 @@ class SlideController(DisplayController):
self._live_controller = Registry().get(u'live_controller')
return self._live_controller
live_controller = property(_get_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 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from openlp.core.lib import Receiver
"""
The splash screen
"""
from PyQt4 import QtCore, QtGui
class SplashScreen(QtGui.QSplashScreen):
"""
The splash screen
"""
def __init__(self):
"""
Constructor
"""
QtGui.QSplashScreen.__init__(self)
self.setupUi()
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'close_splash'), self.close)
def setupUi(self):
"""
Set up the UI
"""
self.setObjectName(u'splashScreen')
self.setContextMenuPolicy(QtCore.Qt.PreventContextMenu)
splash_image = QtGui.QPixmap(u':/graphics/openlp-splash-screen.png')

View File

@ -26,15 +26,23 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The UI widgets for the time dialog
"""
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate, UiStrings
from openlp.core.lib import UiStrings, translate
from openlp.core.lib.ui import create_button_box
class Ui_StartTimeDialog(object):
"""
The UI widgets for the time dialog
"""
def setupUi(self, StartTimeDialog):
"""
Set up the UI
"""
StartTimeDialog.setObjectName(u'StartTimeDialog')
StartTimeDialog.resize(350, 10)
self.dialogLayout = QtGui.QGridLayout(StartTimeDialog)
@ -108,6 +116,9 @@ class Ui_StartTimeDialog(object):
self.setMaximumHeight(self.sizeHint().height())
def retranslateUi(self, StartTimeDialog):
"""
Update the translations on the fly
"""
self.setWindowTitle(translate('OpenLP.StartTimeForm', 'Item Start and Finish Time'))
self.hourSpinBox.setSuffix(UiStrings().Hours)
self.minuteSpinBox.setSuffix(UiStrings().Minutes)

View File

@ -26,19 +26,25 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The actual start time form.
"""
from PyQt4 import QtGui
from starttimedialog import Ui_StartTimeDialog
from openlp.core.lib import translate, UiStrings, Registry
from openlp.core.lib import UiStrings, Registry, translate
from openlp.core.lib.ui import critical_error_message_box
class StartTimeForm(QtGui.QDialog, Ui_StartTimeDialog):
"""
The exception dialog
The start time dialog
"""
def __init__(self):
"""
Constructor
"""
QtGui.QDialog.__init__(self, self.main_window)
self.setupUi(self)
@ -60,6 +66,9 @@ class StartTimeForm(QtGui.QDialog, Ui_StartTimeDialog):
return QtGui.QDialog.exec_(self)
def accept(self):
"""
When the dialog succeeds, this is run
"""
start = self.hourSpinBox.value() * 3600 + \
self.minuteSpinBox.value() * 60 + \
self.secondSpinBox.value()
@ -79,6 +88,9 @@ class StartTimeForm(QtGui.QDialog, Ui_StartTimeDialog):
return QtGui.QDialog.accept(self)
def _time_split(self, seconds):
"""
Split time up into hours minutes and seconds from secongs
"""
hours = seconds / 3600
seconds -= 3600 * hours
minutes = seconds / 60
@ -93,4 +105,4 @@ class StartTimeForm(QtGui.QDialog, Ui_StartTimeDialog):
self._main_window = Registry().get(u'main_window')
return self._main_window
main_window = property(_get_main_window)
main_window = property(_get_main_window)

View File

@ -26,13 +26,15 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The Theme wizard
"""
import logging
import os
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, translate, UiStrings
from openlp.core.lib import Receiver, UiStrings, Registry, translate
from openlp.core.lib.theme import BackgroundType, BackgroundGradientType
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui import ThemeLayoutForm
@ -41,6 +43,7 @@ from themewizard import Ui_ThemeWizard
log = logging.getLogger(__name__)
class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
"""
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.
"""
QtGui.QWizard.__init__(self, parent)
self.thememanager = parent
self.setupUi(self)
self.registerFields()
self.updateThemeAllowed = True
@ -72,14 +74,14 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
self.onGradientStartButtonClicked)
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.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.shadowColorButton, QtCore.SIGNAL(u'clicked()'), self.onShadowColorButtonClicked)
QtCore.QObject.connect(self.outlineCheckBox, QtCore.SIGNAL(u'stateChanged(int)'),
self.onOutlineCheckCheckBoxStateChanged)
QtCore.QObject.connect(self.shadowCheckBox, QtCore.SIGNAL(u'stateChanged(int)'),
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.mainPositionCheckBox, QtCore.SIGNAL(u'stateChanged(int)'),
self.onMainPositionCheckBoxStateChanged)
@ -149,7 +151,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
# Do not trigger on start up
if self.currentPage != self.welcomePage:
self.updateTheme()
self.thememanager.generateImage(self.theme, True)
self.theme_manager.generate_image(self.theme, True)
def updateLinesText(self, lines):
"""
@ -178,6 +180,9 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
pixmapHeight + 2 * frameWidth)
def validateCurrentPage(self):
"""
Validate the current page
"""
background_image = BackgroundType.to_string(BackgroundType.Image)
if self.page(self.currentId()) == self.backgroundPage and \
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)
if self.page(pageId) == self.previewPage:
self.updateTheme()
frame = self.thememanager.generateImage(self.theme)
frame = self.theme_manager.generate_image(self.theme)
self.previewBoxLabel.setPixmap(frame)
self.displayAspectRatio = float(frame.width()) / frame.height()
self.resizeEvent()
@ -206,15 +211,15 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
Generate layout preview and display the form.
"""
self.updateTheme()
width = self.thememanager.mainwindow.renderer.width
height = self.thememanager.mainwindow.renderer.height
width = self.renderer.width
height = self.renderer.height
pixmap = QtGui.QPixmap(width, height)
pixmap.fill(QtCore.Qt.white)
paint = QtGui.QPainter(pixmap)
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.drawRect(self.thememanager.mainwindow.renderer.get_footer_rectangle(self.theme))
paint.drawRect(self.renderer.get_footer_rectangle(self.theme))
paint.end()
self.themeLayoutForm.exec_(pixmap)
@ -444,18 +449,30 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
self.setBackgroundPageValues()
def onMainColorButtonClicked(self):
"""
Set the main colour value
"""
self.theme.font_main_color = self._colorButton(self.theme.font_main_color)
self.setMainAreaPageValues()
def onOutlineColorButtonClicked(self):
"""
Set the outline colour value
"""
self.theme.font_main_outline_color = self._colorButton(self.theme.font_main_outline_color)
self.setMainAreaPageValues()
def onShadowColorButtonClicked(self):
"""
Set the shadow colour value
"""
self.theme.font_main_shadow_color = self._colorButton(self.theme.font_main_shadow_color)
self.setMainAreaPageValues()
def onFooterColorButtonClicked(self):
"""
Set the footer colour value
"""
self.theme.font_footer_color = self._colorButton(self.theme.font_footer_color)
self.setFooterAreaPageValues()
@ -514,9 +531,9 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
filename = os.path.split(unicode(self.theme.background_filename))[1]
saveTo = os.path.join(self.path, self.theme.theme_name, 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
self.thememanager.saveTheme(self.theme, saveFrom, saveTo)
self.theme_manager.save_theme(self.theme, saveFrom, saveTo)
return QtGui.QDialog.accept(self)
def _colorButton(self, field):
@ -527,3 +544,23 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
if new_color.isValid():
field = new_color.name()
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 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The layout of the theme
"""
from PyQt4 import QtGui
from openlp.core.lib import translate
@ -34,7 +36,13 @@ from openlp.core.lib.ui import create_button_box
class Ui_ThemeLayoutDialog(object):
"""
The layout of the theme
"""
def setupUi(self, themeLayoutDialog):
"""
Set up the UI
"""
themeLayoutDialog.setObjectName(u'themeLayoutDialogDialog')
#themeLayoutDialog.resize(300, 200)
self.previewLayout = QtGui.QVBoxLayout(themeLayoutDialog)
@ -63,7 +71,9 @@ class Ui_ThemeLayoutDialog(object):
self.retranslateUi(themeLayoutDialog)
def retranslateUi(self, themeLayoutDialog):
"""
Translate the UI on the fly
"""
themeLayoutDialog.setWindowTitle(translate('OpenLP.StartTimeForm', 'Theme Layout'))
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.'))

View File

@ -26,16 +26,22 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The form layout
"""
from PyQt4 import QtGui, QtCore
from themelayoutdialog import Ui_ThemeLayoutDialog
class ThemeLayoutForm(QtGui.QDialog, Ui_ThemeLayoutDialog):
"""
The exception dialog
"""
def __init__(self, parent):
"""
Constructor
"""
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
@ -44,11 +50,7 @@ class ThemeLayoutForm(QtGui.QDialog, Ui_ThemeLayoutDialog):
Run the Dialog with correct heading.
"""
pixmap = image.scaledToHeight(400, QtCore.Qt.SmoothTransformation)
self.themeDisplayLabel.setPixmap(image)
self.themeDisplayLabel.setPixmap(pixmap)
displayAspectRatio = float(image.width()) / image.height()
self.themeDisplayLabel.setFixedSize(400, 400 / displayAspectRatio )
self.themeDisplayLabel.setFixedSize(400, 400 / displayAspectRatio)
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 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The Theme Manager manages adding, deleteing and modifying of themes.
"""
import os
import zipfile
import shutil
@ -36,9 +38,9 @@ import re
from xml.etree.ElementTree import ElementTree, XML
from PyQt4 import QtCore, QtGui
from openlp.core.lib import OpenLPToolbar, get_text_file_string, build_icon, Receiver, SettingsManager, translate, \
check_item_selected, check_directory_exists, create_thumb, validate_thumb, ImageSource, Settings, Registry, \
UiStrings
from openlp.core.lib import ImageSource, OpenLPToolbar, Receiver, Registry, SettingsManager, Settings, UiStrings, \
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.ui import critical_error_message_box, create_widget_action
from openlp.core.theme import Theme
@ -47,11 +49,15 @@ from openlp.core.utils import AppLocation, delete_file, locale_compare, get_file
log = logging.getLogger(__name__)
class ThemeManager(QtGui.QWidget):
"""
Manages the orders of Theme.
"""
def __init__(self, parent=None):
"""
Constructor
"""
QtGui.QWidget.__init__(self, parent)
Registry().register(u'theme_manager', self)
self.settingsSection = u'themes'
@ -72,67 +78,67 @@ class ThemeManager(QtGui.QWidget):
text=translate('OpenLP.ThemeManager', 'Edit Theme'),
icon=u':/themes/theme_edit.png',
tooltip=translate('OpenLP.ThemeManager', 'Edit a theme.'),
triggers=self.onEditTheme)
self.deleteToolbarAction = self.toolbar.addToolbarAction(u'deleteTheme',
triggers=self.on_edit_theme)
self.deleteToolbarAction = self.toolbar.addToolbarAction(u'delete_theme',
text=translate('OpenLP.ThemeManager', 'Delete Theme'),
icon=u':/general/general_delete.png',
tooltip=translate('OpenLP.ThemeManager', 'Delete a theme.'),
triggers=self.onDeleteTheme)
triggers=self.on_delete_theme)
self.toolbar.addSeparator()
self.toolbar.addToolbarAction(u'importTheme',
text=translate('OpenLP.ThemeManager', 'Import Theme'),
icon=u':/general/general_import.png',
tooltip=translate('OpenLP.ThemeManager', 'Import a theme.'),
triggers=self.onImportTheme)
triggers=self.on_import_theme)
self.toolbar.addToolbarAction(u'exportTheme',
text=translate('OpenLP.ThemeManager', 'Export Theme'),
icon=u':/general/general_export.png',
tooltip=translate('OpenLP.ThemeManager', 'Export a theme.'),
triggers=self.onExportTheme)
triggers=self.on_export_theme)
self.layout.addWidget(self.toolbar)
self.themeWidget = QtGui.QWidgetAction(self.toolbar)
self.themeWidget.setObjectName(u'themeWidget')
self.theme_widget = QtGui.QWidgetAction(self.toolbar)
self.theme_widget.setObjectName(u'theme_widget')
# create theme manager list
self.themeListWidget = QtGui.QListWidget(self)
self.themeListWidget.setAlternatingRowColors(True)
self.themeListWidget.setIconSize(QtCore.QSize(88, 50))
self.themeListWidget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.themeListWidget.setObjectName(u'themeListWidget')
self.layout.addWidget(self.themeListWidget)
QtCore.QObject.connect(self.themeListWidget, QtCore.SIGNAL('customContextMenuRequested(QPoint)'),
self.contextMenu)
self.theme_list_widget = QtGui.QListWidget(self)
self.theme_list_widget.setAlternatingRowColors(True)
self.theme_list_widget.setIconSize(QtCore.QSize(88, 50))
self.theme_list_widget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.theme_list_widget.setObjectName(u'theme_list_widget')
self.layout.addWidget(self.theme_list_widget)
QtCore.QObject.connect(self.theme_list_widget, QtCore.SIGNAL('customContextMenuRequested(QPoint)'),
self.context_menu)
# build the context menu
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'),
icon=u':/themes/theme_edit.png', triggers=self.onEditTheme)
self.copyAction = create_widget_action(self.menu,
icon=u':/themes/theme_edit.png', triggers=self.on_edit_theme)
self.copy_action = create_widget_action(self.menu,
text=translate('OpenLP.ThemeManager', '&Copy Theme'),
icon=u':/themes/theme_edit.png', triggers=self.onCopyTheme)
self.renameAction = create_widget_action(self.menu,
icon=u':/themes/theme_edit.png', triggers=self.on_copy_theme)
self.rename_action = create_widget_action(self.menu,
text=translate('OpenLP.ThemeManager', '&Rename Theme'),
icon=u':/themes/theme_edit.png', triggers=self.onRenameTheme)
self.deleteAction = create_widget_action(self.menu,
icon=u':/themes/theme_edit.png', triggers=self.on_rename_theme)
self.delete_action = create_widget_action(self.menu,
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.globalAction = create_widget_action(self.menu,
self.global_action = create_widget_action(self.menu,
text=translate('OpenLP.ThemeManager', 'Set As &Global Default'),
icon=u':/general/general_export.png',
triggers=self.changeGlobalFromScreen)
self.exportAction = create_widget_action(self.menu,
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
QtCore.QObject.connect(self.themeListWidget,
QtCore.QObject.connect(self.theme_list_widget,
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.changeGlobalFromScreen)
QtCore.QObject.connect(self.themeListWidget,
QtCore.SIGNAL(u'currentItemChanged(QListWidgetItem *, QListWidgetItem *)'), self.checkListState)
QtCore.QObject.connect(self.theme_list_widget,
QtCore.SIGNAL(u'currentItemChanged(QListWidgetItem *, QListWidgetItem *)'), self.check_list_state)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'theme_update_global'), self.changeGlobalFromTab)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_updated'), self.configUpdated)
QtCore.SIGNAL(u'theme_update_global'), self.change_global_from_tab)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_updated'), self.config_updated)
# Variables
self.themeList = []
self.theme_list = []
self.path = AppLocation.get_section_data_path(self.settingsSection)
check_directory_exists(self.path)
self.thumbPath = os.path.join(self.path, u'thumbnails')
@ -141,27 +147,28 @@ class ThemeManager(QtGui.QWidget):
self.oldBackgroundImage = None
self.badV1NameChars = re.compile(r'[%+\[\]]')
# 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
"""
Receiver.send_message(u'cursor_busy')
self.application.set_busy_cursor()
files = SettingsManager.get_files(self.settingsSection, u'.otz')
for file in files:
file = os.path.join(self.path, file)
self.unzipTheme(file, self.path)
delete_file(file)
Receiver.send_message(u'cursor_normal')
for theme_file in files:
theme_file = os.path.join(self.path, theme_file)
self.unzip_theme(theme_file, self.path)
delete_file(theme_file)
self.application.set_normal_cursor()
def configUpdated(self):
def config_updated(self):
"""
Triggered when Config dialog is updated.
"""
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.
"""
@ -175,41 +182,41 @@ class ThemeManager(QtGui.QWidget):
else:
self.deleteToolbarAction.setVisible(False)
def contextMenu(self, point):
def context_menu(self, point):
"""
Build the Right Click Context menu and set state depending on
the type of theme.
"""
item = self.themeListWidget.itemAt(point)
item = self.theme_list_widget.itemAt(point)
if item is None:
return
real_theme_name = item.data(QtCore.Qt.UserRole)
theme_name = unicode(item.text())
visible = real_theme_name == theme_name
self.deleteAction.setVisible(visible)
self.renameAction.setVisible(visible)
self.globalAction.setVisible(visible)
self.menu.exec_(self.themeListWidget.mapToGlobal(point))
self.delete_action.setVisible(visible)
self.rename_action.setVisible(visible)
self.global_action.setVisible(visible)
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
tab
"""
log.debug(u'changeGlobalFromTab %s', theme_name)
for count in range (0, self.themeListWidget.count()):
log.debug(u'change_global_from_tab %s', theme_name)
for count in range(0, self.theme_list_widget.count()):
# reset the old name
item = self.themeListWidget.item(count)
item = self.theme_list_widget.item(count)
old_name = item.text()
new_name = item.data(QtCore.Qt.UserRole)
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
if theme_name == 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(
item not in self.themeListWidget.selectedItems())
item not in self.theme_list_widget.selectedItems())
def changeGlobalFromScreen(self, index=-1):
"""
@ -217,21 +224,21 @@ class ThemeManager(QtGui.QWidget):
Theme Manager list
"""
log.debug(u'changeGlobalFromScreen %s', index)
selected_row = self.themeListWidget.currentRow()
for count in range (0, self.themeListWidget.count()):
item = self.themeListWidget.item(count)
selected_row = self.theme_list_widget.currentRow()
for count in range(0, self.theme_list_widget.count()):
item = self.theme_list_widget.item(count)
old_name = item.text()
# reset the old name
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
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
self.themeListWidget.item(count).setText(name)
self.theme_list_widget.item(count).setText(name)
Settings().setValue(self.settingsSection + u'/global theme', self.global_theme)
Receiver.send_message(u'theme_update_global', self.global_theme)
self._pushThemes()
self._push_themes()
def onAddTheme(self):
"""
@ -242,44 +249,44 @@ class ThemeManager(QtGui.QWidget):
theme.set_default_header_footer()
self.themeForm.theme = theme
self.themeForm.exec_()
self.loadThemes()
self.load_themes()
def onRenameTheme(self):
def on_rename_theme(self):
"""
Renames an existing theme to a new name
"""
if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to rename.'),
translate('OpenLP.ThemeManager', 'Rename Confirmation'),
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)
self.fileRenameForm.fileNameEdit.setText(old_theme_name)
if self.fileRenameForm.exec_():
new_theme_name = self.fileRenameForm.fileNameEdit.text()
if old_theme_name == new_theme_name:
return
if self.checkIfThemeExists(new_theme_name):
old_theme_data = self.getThemeData(old_theme_name)
if self.check_if_theme_exists(new_theme_name):
old_theme_data = self.get_theme_data(old_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.plugin_manager.plugins:
if plugin.usesTheme(old_theme_name):
plugin.renameTheme(old_theme_name, new_theme_name)
self.renderer.update_theme(new_theme_name, old_theme_name)
self.loadThemes()
self.load_themes()
def onCopyTheme(self):
def on_copy_theme(self):
"""
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)
self.fileRenameForm.fileNameEdit.setText(translate('OpenLP.ThemeManager',
'Copy of %s', 'Copy of <theme name>') % old_theme_name)
if self.fileRenameForm.exec_(True):
new_theme_name = self.fileRenameForm.fileNameEdit.text()
if self.checkIfThemeExists(new_theme_name):
theme_data = self.getThemeData(old_theme_name)
if self.check_if_theme_exists(new_theme_name):
theme_data = self.get_theme_data(old_theme_name)
self.cloneThemeData(theme_data, new_theme_name)
def cloneThemeData(self, theme_data, new_theme_name):
@ -295,65 +302,65 @@ class ThemeManager(QtGui.QWidget):
save_from = theme_data.background_filename
theme_data.theme_name = new_theme_name
theme_data.extend_image_filename(self.path)
self.saveTheme(theme_data, save_from, save_to)
self.loadThemes()
self.save_theme(theme_data, save_from, save_to)
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
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.')):
item = self.themeListWidget.currentItem()
theme = self.getThemeData(item.data(QtCore.Qt.UserRole))
item = self.theme_list_widget.currentItem()
theme = self.get_theme_data(item.data(QtCore.Qt.UserRole))
if theme.background_type == u'image':
self.oldBackgroundImage = theme.background_filename
self.themeForm.theme = theme
self.themeForm.exec_(True)
self.oldBackgroundImage = None
self.renderer.update_theme(theme.theme_name)
self.loadThemes()
self.load_themes()
def onDeleteTheme(self):
def on_delete_theme(self):
"""
Delete a theme
"""
if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to delete.'),
translate('OpenLP.ThemeManager', 'Delete Confirmation'),
translate('OpenLP.ThemeManager', 'Delete %s theme?')):
item = self.themeListWidget.currentItem()
item = self.theme_list_widget.currentItem()
theme = item.text()
row = self.themeListWidget.row(item)
self.themeListWidget.takeItem(row)
self.deleteTheme(theme)
row = self.theme_list_widget.row(item)
self.theme_list_widget.takeItem(row)
self.delete_theme(theme)
self.renderer.update_theme(theme, only_delete=True)
# As we do not reload the themes, push out the change. Reload the
# 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.
``theme``
The theme to delete.
"""
self.themeList.remove(theme)
self.theme_list.remove(theme)
thumb = u'%s.png' % theme
delete_file(os.path.join(self.path, thumb))
delete_file(os.path.join(self.thumbPath, thumb))
try:
encoding = get_filesystem_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)
def onExportTheme(self):
def on_export_theme(self):
"""
Export the theme in a zip file
"""
item = self.themeListWidget.currentItem()
item = self.theme_list_widget.currentItem()
if item is None:
critical_error_message_box(message=translate('OpenLP.ThemeManager', 'You have not selected a theme.'))
return
@ -361,34 +368,34 @@ class ThemeManager(QtGui.QWidget):
path = QtGui.QFileDialog.getExistingDirectory(self,
translate('OpenLP.ThemeManager', 'Save Theme - (%s)') % theme,
Settings().value(self.settingsSection + u'/last directory export'))
Receiver.send_message(u'cursor_busy')
self.application.set_busy_cursor()
if path:
Settings().setValue(self.settingsSection + u'/last directory export', path)
theme_path = os.path.join(path, theme + u'.otz')
# FIXME: Do not overwrite build-in.
zip = None
theme_zip = None
try:
zip = zipfile.ZipFile(theme_path, u'w')
theme_zip = zipfile.ZipFile(theme_path, u'w')
source = os.path.join(self.path, theme)
for files in os.walk(source):
for name in files[2]:
zip.write(
theme_zip.write(
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,
translate('OpenLP.ThemeManager', 'Theme Exported'),
translate('OpenLP.ThemeManager', 'Your theme has been successfully exported.'))
except (IOError, OSError):
log.exception(u'Export Theme Failed')
critical_error_message_box(
translate('OpenLP.ThemeManager', 'Theme Export Failed'),
critical_error_message_box(translate('OpenLP.ThemeManager', 'Theme Export Failed'),
translate('OpenLP.ThemeManager', 'Your theme could not be exported due to an error.'))
finally:
if zip:
zip.close()
Receiver.send_message(u'cursor_normal')
if theme_zip:
theme_zip.close()
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
attempting to extract OpenLP themes from those files. This process
@ -401,37 +408,36 @@ class ThemeManager(QtGui.QWidget):
log.info(u'New Themes %s', unicode(files))
if not files:
return
Receiver.send_message(u'cursor_busy')
for file in files:
Settings().setValue(self.settingsSection + u'/last directory import', unicode(file))
self.unzipTheme(file, self.path)
self.loadThemes()
Receiver.send_message(u'cursor_normal')
self.application.set_busy_cursor()
for file_name in files:
Settings().setValue(self.settingsSection + u'/last directory import', unicode(file_name))
self.unzip_theme(file_name, self.path)
self.load_themes()
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
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.
"""
log.debug(u'Load themes from dir')
self.themeList = []
self.themeListWidget.clear()
self.theme_list = []
self.theme_list_widget.clear()
files = SettingsManager.get_files(self.settingsSection, u'.png')
if firstTime:
self.firstTime()
if first_time:
self.first_time()
files = SettingsManager.get_files(self.settingsSection, u'.png')
# No themes have been found so create one
if not files:
theme = ThemeXML()
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)
self.configUpdated()
self.config_updated()
files = SettingsManager.get_files(self.settingsSection, u'.png')
# Sort the themes by its name considering language specific
files.sort(key=lambda file_name: unicode(file_name),
cmp=locale_compare)
files.sort(key=lambda file_name: unicode(file_name), cmp=locale_compare)
# now process the file list of png files
for name in files:
# check to see file is in theme root directory
@ -450,23 +456,23 @@ class ThemeManager(QtGui.QWidget):
icon = create_thumb(theme, thumb)
item_name.setIcon(icon)
item_name.setData(QtCore.Qt.UserRole, text_name)
self.themeListWidget.addItem(item_name)
self.themeList.append(text_name)
self._pushThemes()
self.theme_list_widget.addItem(item_name)
self.theme_list.append(text_name)
self._push_themes()
def _pushThemes(self):
def _push_themes(self):
"""
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 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
@ -480,18 +486,20 @@ class ThemeManager(QtGui.QWidget):
log.debug(u'No theme data - using default theme')
return ThemeXML()
else:
return self._createThemeFromXml(xml, self.path)
return self._create_theme_fom_Xml(xml, self.path)
def overWriteMessageBox(self, theme_name):
ret = QtGui.QMessageBox.question(self,
translate('OpenLP.ThemeManager', 'Theme Already Exists'),
def over_write_message_box(self, theme_name):
"""
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',
'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.No)
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
Generate a new preview file. Check the XML theme version and upgrade if
@ -499,32 +507,31 @@ class ThemeManager(QtGui.QWidget):
"""
log.debug(u'Unzipping theme %s', file_name)
file_name = unicode(file_name)
zip = None
theme_zip = None
out_file = None
file_xml = None
abort_import = True
try:
zip = zipfile.ZipFile(file_name)
xml_file = filter(lambda name:
os.path.splitext(name)[1].lower() == u'.xml', zip.namelist())
theme_zip = zipfile.ZipFile(file_name)
xml_file = filter(lambda name: os.path.splitext(name)[1].lower() == u'.xml', theme_zip.namelist())
if len(xml_file) != 1:
log.exception(u'Theme contains "%s" XML files' % len(xml_file))
raise Exception(u'validation')
xml_tree = ElementTree(element=XML(zip.read(xml_file[0]))).getroot()
raise Exception('validation')
xml_tree = ElementTree(element=XML(theme_zip.read(xml_file[0]))).getroot()
v1_background = xml_tree.find(u'BackgroundType')
if v1_background is not None:
theme_name, file_xml, out_file, abort_import = self.unzipVersion122(
dir, zip, xml_file[0], xml_tree, v1_background, out_file)
theme_name, file_xml, out_file, abort_import = self.unzip_version_122(
directory, theme_zip, xml_file[0], xml_tree, v1_background, out_file)
else:
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)
if theme_exists and not self.overWriteMessageBox(theme_name):
if theme_exists and not self.over_write_message_box(theme_name):
abort_import = True
return
else:
abort_import = False
for name in zip.namelist():
for name in theme_zip.namelist():
try:
uname = unicode(name, u'utf-8')
except UnicodeDecodeError:
@ -536,15 +543,15 @@ class ThemeManager(QtGui.QWidget):
if split_name[-1] == u'' or len(split_name) == 1:
# is directory or preview file
continue
full_name = os.path.join(dir, uname)
full_name = os.path.join(directory, uname)
check_directory_exists(os.path.dirname(full_name))
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.write(file_xml.encode(u'utf-8'))
else:
out_file = open(full_name, u'wb')
out_file.write(zip.read(name))
out_file.write(theme_zip.read(name))
out_file.close()
except (IOError, zipfile.BadZipfile):
log.exception(u'Importing theme from zip failed %s' % file_name)
@ -557,39 +564,38 @@ class ThemeManager(QtGui.QWidget):
raise
finally:
# Close the files, to be able to continue creating the theme.
if zip:
zip.close()
if theme_zip:
theme_zip.close()
if out_file:
out_file.close()
if not abort_import:
# As all files are closed, we can create the Theme.
if file_xml:
theme = self._createThemeFromXml(file_xml, self.path)
self.generateAndSaveImage(dir, theme_name, theme)
theme = self._create_theme_fom_Xml(file_xml, self.path)
self.generate_and_save_image(directory, theme_name, theme)
# Only show the error message, when IOError was not raised (in
# this case the error message has already been shown).
elif zip is not None:
elif theme_zip is not None:
critical_error_message_box(
translate('OpenLP.ThemeManager', 'Validation Error'),
translate('OpenLP.ThemeManager', 'File is not a valid theme.'))
log.exception(u'Theme file does not contain XML data %s' % file_name)
def unzipVersion122(self, dir, zip, xml_file, xml_tree, background,
out_file):
def unzip_version_122(self, dir_name, zip_file, xml_file, xml_tree, background, out_file):
"""
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.
"""
theme_name = xml_tree.find(u'Name').text.strip()
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)
if theme_exists and not self.overWriteMessageBox(theme_name):
if theme_exists and not self.over_write_message_box(theme_name):
return '', '', '', True
themedir = os.path.join(dir, theme_name)
themedir = os.path.join(dir_name, theme_name)
check_directory_exists(themedir)
file_xml = unicode(zip.read(xml_file), u'utf-8')
file_xml = self._migrateVersion122(file_xml)
file_xml = unicode(zip_file.read(xml_file), u'utf-8')
file_xml = self._migrate_version_122(file_xml)
out_file = open(os.path.join(themedir, theme_name + u'.xml'), u'w')
out_file.write(file_xml.encode(u'utf-8'))
out_file.close()
@ -597,18 +603,17 @@ class ThemeManager(QtGui.QWidget):
image_name = xml_tree.find(u'BackgroundParameter1').text.strip()
# image file has same extension and is in subfolder
image_file = filter(lambda name: os.path.splitext(name)[1].lower()
== os.path.splitext(image_name)[1].lower() and name.find(r'/'),
zip.namelist())
== os.path.splitext(image_name)[1].lower() and name.find(r'/'), zip_file.namelist())
if len(image_file) >= 1:
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()
else:
log.exception(u'Theme file does not contain image file "%s"' % image_name.decode(u'utf-8', u'replace'))
raise Exception(u'validation')
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
@ -623,25 +628,25 @@ class ThemeManager(QtGui.QWidget):
return False
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
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):
self.image_manager.updateImageBorder(theme.background_filename,
self.image_manager.update_image_border(theme.background_filename,
ImageSource.Theme, QtGui.QColor(theme.background_border_color))
self.image_manager.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
necessary
"""
name = theme.theme_name
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)
check_directory_exists(theme_dir)
theme_file = os.path.join(theme_dir, name + u'.xml')
@ -660,13 +665,16 @@ class ThemeManager(QtGui.QWidget):
try:
encoding = get_filesystem_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')
self.generateAndSaveImage(self.path, name, theme)
self.generate_and_save_image(self.path, name, theme)
def generateAndSaveImage(self, dir, name, theme):
log.debug(u'generateAndSaveImage %s %s', dir, name)
frame = self.generateImage(theme)
def generate_and_save_image(self, directory, name, 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')
if os.path.exists(sample_path_name):
os.unlink(sample_path_name)
@ -675,18 +683,18 @@ class ThemeManager(QtGui.QWidget):
create_thumb(sample_path_name, thumb, False)
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.
"""
self.main_window.displayProgressBar(len(self.themeList))
for theme in self.themeList:
self.main_window.displayProgressBar(len(self.theme_list))
for theme in self.theme_list:
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.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
@ -696,21 +704,21 @@ class ThemeManager(QtGui.QWidget):
``forcePage``
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.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
``theme``
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')
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
@ -722,15 +730,14 @@ class ThemeManager(QtGui.QWidget):
theme.extend_image_filename(path)
return theme
def _validate_theme_action(self, select_text, confirm_title, confirm_text,
testPlugin=True, confirm=True):
def _validate_theme_action(self, select_text, confirm_title, confirm_text, testPlugin=True, confirm=True):
"""
Check to see if theme has been selected and the destructive action
is allowed.
"""
self.global_theme = Settings().value(self.settingsSection + u'/global theme')
if check_item_selected(self.themeListWidget, select_text):
item = self.themeListWidget.currentItem()
if check_item_selected(self.theme_list_widget, select_text):
item = self.theme_list_widget.currentItem()
theme = item.text()
# confirm deletion
if confirm:
@ -755,7 +762,7 @@ class ThemeManager(QtGui.QWidget):
return True
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.
@ -843,3 +850,13 @@ class ThemeManager(QtGui.QWidget):
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,10 +26,12 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The Themes configuration tab
"""
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, Settings, SettingsTab, translate, UiStrings
from openlp.core.lib import Receiver, Settings, SettingsTab, UiStrings, translate
from openlp.core.lib.theme import ThemeLevel
from openlp.core.lib.ui import find_and_set_in_combo_box
@ -38,13 +40,18 @@ class ThemesTab(SettingsTab):
"""
ThemesTab is the theme settings tab in the settings dialog.
"""
def __init__(self, parent, mainwindow):
self.mainwindow = mainwindow
def __init__(self, parent):
"""
Constructor
"""
generalTranslated = translate('OpenLP.ThemesTab', 'Themes')
SettingsTab.__init__(self, parent, u'Themes', generalTranslated)
self.iconPath = u':/themes/theme_new.png'
def setupUi(self):
"""
Set up the UI
"""
self.setObjectName(u'ThemesTab')
SettingsTab.setupUi(self)
self.GlobalGroupBox = QtGui.QGroupBox(self.leftColumn)
@ -100,6 +107,9 @@ class ThemesTab(SettingsTab):
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'theme_update_list'), self.updateThemeList)
def retranslateUi(self):
"""
Translate the UI on the fly
"""
self.tabTitleVisible = UiStrings().Themes
self.GlobalGroupBox.setTitle(translate('OpenLP.ThemesTab', 'Global Theme'))
self.LevelGroupBox.setTitle(translate('OpenLP.ThemesTab', 'Theme Level'))
@ -117,6 +127,9 @@ class ThemesTab(SettingsTab):
'any themes associated with either the service or the songs.'))
def load(self):
"""
Load the theme settings into the tab
"""
settings = Settings()
settings.beginGroup(self.settingsSection)
self.theme_level = settings.value(u'theme level')
@ -130,30 +143,48 @@ class ThemesTab(SettingsTab):
self.SongLevelRadioButton.setChecked(True)
def save(self):
"""
Save the settings
"""
settings = Settings()
settings.beginGroup(self.settingsSection)
settings.setValue(u'theme level', self.theme_level)
settings.setValue(u'global theme', self.global_theme)
settings.endGroup()
self.mainwindow.renderer.set_global_theme(self.global_theme)
self.mainwindow.renderer.set_theme_level(self.theme_level)
self.renderer.set_global_theme(self.global_theme)
self.renderer.set_theme_level(self.theme_level)
Receiver.send_message(u'theme_update_global', self.global_theme)
def postSetUp(self):
"""
After setting things up...
"""
Receiver.send_message(u'theme_update_global', self.global_theme)
def onSongLevelButtonClicked(self):
"""
Set the theme level
"""
self.theme_level = ThemeLevel.Song
def onServiceLevelButtonClicked(self):
"""
Set the theme level
"""
self.theme_level = ThemeLevel.Service
def onGlobalLevelButtonClicked(self):
"""
Set the theme level
"""
self.theme_level = ThemeLevel.Global
def onDefaultComboBoxChanged(self, value):
"""
Set the global default theme
"""
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()
def updateThemeList(self, theme_list):
@ -170,8 +201,8 @@ class ThemesTab(SettingsTab):
self.DefaultComboBox.clear()
self.DefaultComboBox.addItems(theme_list)
find_and_set_in_combo_box(self.DefaultComboBox, self.global_theme)
self.mainwindow.renderer.set_global_theme(self.global_theme)
self.mainwindow.renderer.set_theme_level(self.theme_level)
self.renderer.set_global_theme(self.global_theme)
self.renderer.set_theme_level(self.theme_level)
if self.global_theme is not u'':
self.__previewGlobalTheme()
@ -179,7 +210,7 @@ class ThemesTab(SettingsTab):
"""
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))
if not preview.isNull():
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 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The Create/Edit theme wizard
"""
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate, build_icon, UiStrings
from openlp.core.lib import UiStrings, build_icon, translate
from openlp.core.lib.theme import HorizontalType, BackgroundType, BackgroundGradientType
from openlp.core.lib.ui import add_welcome_page, create_valign_selection_widgets
class Ui_ThemeWizard(object):
"""
The Create/Edit theme wizard
"""
def setupUi(self, themeWizard):
"""
Set up the UI
"""
themeWizard.setObjectName(u'OpenLP.ThemeWizard')
themeWizard.setModal(True)
themeWizard.setWizardStyle(QtGui.QWizard.ModernStyle)
@ -372,7 +381,7 @@ class Ui_ThemeWizard(object):
QtCore.SLOT(u'setDisabled(bool)'))
QtCore.QObject.connect(self.mainPositionCheckBox, QtCore.SIGNAL(u'toggled(bool)'), self.mainHeightSpinBox,
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.QObject.connect(self.footerPositionCheckBox, QtCore.SIGNAL(u'toggled(bool)'), self.footerYSpinBox,
QtCore.SLOT(u'setDisabled(bool)'))
@ -382,8 +391,11 @@ class Ui_ThemeWizard(object):
QtCore.SLOT(u'setDisabled(bool)'))
def retranslateUi(self, themeWizard):
"""
Translate the UI on the fly
"""
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'))
self.informationLabel.setText(
translate('OpenLP.ThemeWizard', 'This wizard will help you to '

View File

@ -34,11 +34,12 @@ import os
from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, Receiver, Settings, translate, UiStrings
from openlp.core.lib import Receiver, Registry, Settings, UiStrings, build_icon, translate
from openlp.core.lib.ui import add_welcome_page
log = logging.getLogger(__name__)
class WizardStrings(object):
"""
Provide standard strings for wizards to use.
@ -96,6 +97,9 @@ class OpenLPWizard(QtGui.QWizard):
Whether to add a progress page with a progressbar at the end of the wizard.
"""
def __init__(self, parent, plugin, name, image, addProgressPage=True):
"""
Constructor
"""
QtGui.QWizard.__init__(self, parent)
self.plugin = plugin
self.withProgressPage = addProgressPage
@ -234,7 +238,7 @@ class OpenLPWizard(QtGui.QWizard):
self.progressLabel.setText(status_text)
if increment > 0:
self.progressBar.setValue(self.progressBar.value() + increment)
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
def preWizard(self):
"""
@ -252,7 +256,7 @@ class OpenLPWizard(QtGui.QWizard):
self.progressBar.setValue(self.progressBar.maximum())
self.finishButton.setVisible(True)
self.cancelButton.setVisible(False)
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
def getFileName(self, title, editbox, setting_name, filters=u''):
"""
@ -301,3 +305,13 @@ class OpenLPWizard(QtGui.QWizard):
if folder:
editbox.setText(folder)
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

@ -29,7 +29,7 @@
"""
The :mod:`openlp.core.utils` module provides the utility libraries for OpenLP.
"""
from datetime import datetime, timedelta
from datetime import datetime
from distutils.version import LooseVersion
import logging
import locale
@ -39,7 +39,7 @@ from subprocess import Popen, PIPE
import sys
import urllib2
from openlp.core.lib import Settings
from openlp.core.lib import Registry, Settings
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)
INVALID_FILE_CHARS = re.compile(r'[\\/:\*\?"<>\|\+\[\]%]', re.UNICODE)
class VersionThread(QtCore.QThread):
"""
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.
"""
def __init__(self, parent):
QtCore.QThread.__init__(self, parent)
def run(self):
"""
Run the thread.
@ -157,7 +155,8 @@ def _get_os_dir_path(dir_type):
return os.path.join(unicode(os.getenv(u'APPDATA'), encoding), u'openlp')
elif sys.platform == u'darwin':
if dir_type == AppLocation.DataDir:
return os.path.join(unicode(os.getenv(u'HOME'), encoding), u'Library', u'Application Support', u'openlp', u'Data')
return os.path.join(unicode(os.getenv(u'HOME'), encoding),
u'Library', u'Application Support', u'openlp', u'Data')
elif dir_type == AppLocation.LanguageDir:
return os.path.split(openlp.__file__)[0]
return os.path.join(unicode(os.getenv(u'HOME'), encoding), u'Library', u'Application Support', u'openlp')
@ -425,7 +424,7 @@ def get_web_page(url, header=None, update_openlp=False):
if not page:
return None
if update_openlp:
Receiver.send_message(u'openlp_process_events')
Registry().get(u'application').process_events()
log.debug(page)
return page
@ -472,6 +471,9 @@ def format_time(text, local_time):
The time to be used to add to the string. This is a time object
"""
def match_formatting(match):
"""
Format the match
"""
return local_time.strftime(match.group())
return re.sub('\%[a-zA-Z]', match_formatting, text)
@ -488,17 +490,14 @@ def locale_compare(string1, string2):
return locale.strcoll(string1.lower(), string2.lower())
# For performance reasons provide direct reference to compare function
# without wrapping it in another function making te string lowercase.
# This is needed for sorting songs.
# For performance reasons provide direct reference to compare function without wrapping it in another function making
# the string lowercase. This is needed for sorting songs.
locale_direct_compare = locale.strcoll
from languagemanager import LanguageManager
from actions import ActionList
__all__ = [u'AppLocation', u'get_application_version', u'check_latest_version',
u'add_actions', u'get_filesystem_encoding', u'LanguageManager',
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']
__all__ = [u'AppLocation', u'ActionList', u'LanguageManager', u'get_application_version', u'check_latest_version',
u'add_actions', u'get_filesystem_encoding', 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']

View File

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

View File

@ -27,8 +27,7 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`languagemanager` module provides all the translation settings and
language file loading for OpenLP.
The :mod:`languagemanager` module provides all the translation settings and language file loading for OpenLP.
"""
import logging
import re
@ -37,10 +36,11 @@ import sys
from PyQt4 import QtCore, QtGui
from openlp.core.utils import AppLocation
from openlp.core.lib import translate, Settings
from openlp.core.lib import Settings, translate
log = logging.getLogger(__name__)
class LanguageManager(object):
"""
Helper for Language selection

View File

@ -29,9 +29,9 @@
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, Settings, StringContent, build_icon, translate
from openlp.core.lib.db import Manager
from openlp.core.lib.ui import create_action, UiStrings
from openlp.core.lib.theme import VerticalType

View File

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

View File

@ -29,8 +29,7 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import SettingsTab, translate, Receiver, Settings, UiStrings
from openlp.core.ui import AlertLocation
from openlp.core.lib import SettingsTab, Receiver, Settings, UiStrings, translate
from openlp.core.lib.ui import create_valign_selection_widgets
class AlertsTab(SettingsTab):

View File

@ -31,8 +31,8 @@ import logging
from PyQt4 import QtGui
from openlp.core.lib import Plugin, StringContent, build_icon, translate, Settings
from openlp.core.lib.ui import create_action, UiStrings
from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.core.lib.ui import UiStrings, create_action
from openlp.core.utils.actions import ActionList
from openlp.plugins.bibles.lib import BibleManager, BiblesTab, BibleMediaItem, LayoutStyle, DisplayStyle, \
LanguageSelection
@ -102,11 +102,11 @@ class BiblePlugin(Plugin):
#action_list.remove_action(self.exportBibleItem, UiStrings().Export)
self.exportBibleItem.setVisible(False)
def appStartup(self):
def app_startup(self):
"""
Perform tasks on application startup
"""
Plugin.appStartup(self)
Plugin.app_startup(self)
if self.manager.old_bible_databases:
if QtGui.QMessageBox.information(self.main_window,
translate('OpenLP', 'Information'),

View File

@ -34,7 +34,7 @@ import os
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, translate, Settings, UiStrings
from openlp.core.lib import Settings, UiStrings, translate
from openlp.core.lib.db import delete_database
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
@ -578,7 +578,7 @@ class BibleImportForm(OpenLPWizard):
self.progressLabel.setText(translate('BiblesPlugin.ImportWizardForm', 'Registering Bible...'))
else:
self.progressLabel.setText(WizardStrings.StartingImport)
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
def performWizard(self):
"""

View File

@ -36,7 +36,7 @@ from tempfile import gettempdir
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, translate, check_directory_exists, Settings, UiStrings
from openlp.core.lib import Receiver, Settings, UiStrings, translate, check_directory_exists
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
from openlp.core.utils import AppLocation, delete_file, get_filesystem_encoding
@ -335,7 +335,7 @@ class BibleUpgradeForm(OpenLPWizard):
"""
OpenLPWizard.preWizard(self)
self.progressLabel.setText(translate('BiblesPlugin.UpgradeWizardForm', 'Starting upgrade...'))
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
def performWizard(self):
"""
@ -465,7 +465,7 @@ class BibleUpgradeForm(OpenLPWizard):
self.newbibles[number].create_verse(db_book.id,
int(verse[u'chapter']),
int(verse[u'verse']), unicode(verse[u'text']))
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
self.newbibles[number].session.commit()
else:
language_id = self.newbibles[number].get_object(BibleMeta, u'language_id')
@ -511,7 +511,7 @@ class BibleUpgradeForm(OpenLPWizard):
self.newbibles[number].create_verse(db_book.id,
int(verse[u'chapter']),
int(verse[u'verse']), unicode(verse[u'text']))
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
self.newbibles[number].session.commit()
if not self.success.get(number, True):
self.incrementProgressBar(translate('BiblesPlugin.UpgradeWizardForm',

View File

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

@ -33,7 +33,7 @@ plugin.
import logging
import re
from openlp.core.lib import translate, Settings
from openlp.core.lib import Settings, translate
log = logging.getLogger(__name__)

View File

@ -31,7 +31,7 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, SettingsTab, translate, Settings, UiStrings
from openlp.core.lib import Receiver, SettingsTab, Settings, UiStrings, translate
from openlp.core.lib.ui import find_and_set_in_combo_box
from openlp.plugins.bibles.lib import LayoutStyle, DisplayStyle, update_reference_separators, \
get_reference_separator, LanguageSelection

View File

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

View File

@ -34,11 +34,11 @@ import re
import sqlite3
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.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.ui import critical_error_message_box
from openlp.core.utils import AppLocation, clean_filename
@ -360,7 +360,7 @@ class BibleDB(QtCore.QObject, Manager):
``book``
The name of the book, according to the selected language.
``language_selection``
The language selection the user has chosen in the settings
section of the Bible.
@ -549,6 +549,16 @@ class BibleDB(QtCore.QObject, Manager):
verses = self.session.query(Verse).all()
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):
"""

View File

@ -38,7 +38,7 @@ from HTMLParser import HTMLParseError
from BeautifulSoup import BeautifulSoup, NavigableString, Tag
from openlp.core.lib import Receiver, translate
from openlp.core.lib import Registry, translate
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.utils import get_web_page
from openlp.plugins.bibles.lib import SearchResults
@ -164,7 +164,7 @@ class BGExtract(object):
if len(verse_parts) > 1:
verse = int(verse_parts[0])
except TypeError:
log.warn(u'Illegal verse number: %s', unicode(raw_verse_num))
log.warn(u'Illegal verse number: %s', unicode(verse))
verses.append((verse, text))
verse_list = {}
for verse, text in verses[::-1]:
@ -203,8 +203,7 @@ class BGExtract(object):
if clean_verse_num:
verse_text = raw_verse_num.next
part = raw_verse_num.next.next
while not (isinstance(part, Tag) and
part.get(u'class') == u'versenum'):
while not (isinstance(part, Tag) and part.get(u'class') == u'versenum'):
# While we are still in the same verse grab all the text.
if isinstance(part, NavigableString):
verse_text += part
@ -235,9 +234,10 @@ class BGExtract(object):
soup = get_soup_for_bible_ref(
u'http://www.biblegateway.com/passage/?%s' % url_params,
pre_parse_regex=r'<meta name.*?/>', pre_parse_substitute='', cleaner=cleaner)
self.application.process_events()
if not soup:
return None
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
div = soup.find('div', 'result-text-style-normal')
self._clean_soup(div)
span_list = div.findAll('span', 'text')
@ -281,7 +281,7 @@ class BGExtract(object):
if not soup:
send_error_message(u'parse')
return None
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
content = soup.find(u'table', u'infotable')
if content:
content = content.findAll(u'tr')
@ -319,17 +319,15 @@ class BSExtract(object):
``chapter``
Chapter number
"""
log.debug(u'BSExtract.get_bible_chapter("%s", "%s", "%s")', version,
book_name, chapter)
log.debug(u'BSExtract.get_bible_chapter("%s", "%s", "%s")', version, book_name, chapter)
url_version = urllib.quote(version.encode("utf-8"))
url_book_name = urllib.quote(book_name.encode("utf-8"))
chapter_url = u'http://m.bibleserver.com/text/%s/%s%d' % \
(url_version, url_book_name, chapter)
chapter_url = u'http://m.bibleserver.com/text/%s/%s%d' % (url_version, url_book_name, chapter)
header = (u'Accept-Language', u'en')
soup = get_soup_for_bible_ref(chapter_url, header)
if not soup:
return None
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
content = soup.find(u'div', u'content')
if not content:
log.error(u'No verses found in the Bibleserver response.')
@ -339,7 +337,7 @@ class BSExtract(object):
verse_number = re.compile(r'v(\d{1,2})(\d{3})(\d{3}) verse.*')
verses = {}
for verse in content:
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
versenumber = int(verse_number.sub(r'\3', verse[u'class']))
verses[versenumber] = verse.contents[1].rstrip(u'\n')
return SearchResults(book_name, chapter, verses)
@ -354,8 +352,7 @@ class BSExtract(object):
"""
log.debug(u'BSExtract.get_books_from_http("%s")', version)
urlversion = urllib.quote(version.encode("utf-8"))
chapter_url = u'http://m.bibleserver.com/overlay/selectBook?'\
'translation=%s' % (urlversion)
chapter_url = u'http://m.bibleserver.com/overlay/selectBook?translation=%s' % (urlversion)
soup = get_soup_for_bible_ref(chapter_url)
if not soup:
return None
@ -365,9 +362,7 @@ class BSExtract(object):
send_error_message(u'parse')
return None
content = content.findAll(u'li')
return [
book.contents[0].contents[0] for book in content
]
return [book.contents[0].contents[0] for book in content]
class CWExtract(object):
@ -392,17 +387,15 @@ class CWExtract(object):
``chapter``
Chapter number
"""
log.debug(u'CWExtract.get_bible_chapter("%s", "%s", "%s")', version,
book_name, chapter)
log.debug(u'CWExtract.get_bible_chapter("%s", "%s", "%s")', version, book_name, chapter)
url_book_name = book_name.replace(u' ', u'-')
url_book_name = url_book_name.lower()
url_book_name = urllib.quote(url_book_name.encode("utf-8"))
chapter_url = u'http://www.biblestudytools.com/%s/%s/%s.html' % \
(version, url_book_name, chapter)
chapter_url = u'http://www.biblestudytools.com/%s/%s/%s.html' % (version, url_book_name, chapter)
soup = get_soup_for_bible_ref(chapter_url)
if not soup:
return None
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
html_verses = soup.findAll(u'span', u'versetext')
if not html_verses:
log.error(u'No verses found in the CrossWalk response.')
@ -412,27 +405,25 @@ class CWExtract(object):
reduce_spaces = re.compile(r'[ ]{2,}')
fix_punctuation = re.compile(r'[ ]+([.,;])')
for verse in html_verses:
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
verse_number = int(verse.contents[0].contents[0])
verse_text = u''
for part in verse.contents:
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
if isinstance(part, NavigableString):
verse_text = verse_text + part
verse_text += part
elif part and part.attrMap and \
(part.attrMap[u'class'] == u'WordsOfChrist' or \
part.attrMap[u'class'] == u'strongs'):
(part.attrMap[u'class'] == u'WordsOfChrist' or part.attrMap[u'class'] == u'strongs'):
for subpart in part.contents:
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
if isinstance(subpart, NavigableString):
verse_text = verse_text + subpart
elif subpart and subpart.attrMap and \
subpart.attrMap[u'class'] == u'strongs':
verse_text += subpart
elif subpart and subpart.attrMap and subpart.attrMap[u'class'] == u'strongs':
for subsub in subpart.contents:
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
if isinstance(subsub, NavigableString):
verse_text = verse_text + subsub
Receiver.send_message(u'openlp_process_events')
verse_text += subsub
self.application.process_events()
# Fix up leading and trailing spaces, multiple spaces, and spaces
# between text and , and .
verse_text = verse_text.strip(u'\n\r\t ')
@ -449,8 +440,7 @@ class CWExtract(object):
The version of the bible like NIV for New International Version
"""
log.debug(u'CWExtract.get_books_from_http("%s")', version)
chapter_url = u'http://www.biblestudytools.com/%s/'\
% (version)
chapter_url = u'http://www.biblestudytools.com/%s/' % (version)
soup = get_soup_for_bible_ref(chapter_url)
if not soup:
return None
@ -504,9 +494,7 @@ class HTTPBible(BibleDB):
``True`` on success, ``False`` on failure.
"""
self.wizard.progressBar.setMaximum(68)
self.wizard.incrementProgressBar(translate(
'BiblesPlugin.HTTPBible',
'Registering Bible and loading books...'))
self.wizard.incrementProgressBar(translate('BiblesPlugin.HTTPBible', 'Registering Bible and loading books...'))
self.save_meta(u'download_source', self.download_source)
self.save_meta(u'download_name', self.download_name)
if self.proxy_server:
@ -528,19 +516,16 @@ class HTTPBible(BibleDB):
log.exception(u'Importing books from %s - download name: "%s" '\
'failed' % (self.download_source, self.download_name))
return False
self.wizard.progressBar.setMaximum(len(books)+2)
self.wizard.incrementProgressBar(translate(
'BiblesPlugin.HTTPBible', 'Registering Language...'))
bible = BiblesResourcesDB.get_webbible(self.download_name,
self.download_source.lower())
self.wizard.progressBar.setMaximum(len(books) + 2)
self.wizard.incrementProgressBar(translate( 'BiblesPlugin.HTTPBible', 'Registering Language...'))
bible = BiblesResourcesDB.get_webbible(self.download_name, self.download_source.lower())
if bible[u'language_id']:
language_id = bible[u'language_id']
self.save_meta(u'language_id', language_id)
else:
language_id = self.get_language(bible_name)
if not language_id:
log.exception(u'Importing books from %s " '\
'failed' % self.filename)
log.exception(u'Importing books from %s failed' % self.filename)
return False
for book in books:
if self.stop_import_flag:
@ -548,8 +533,7 @@ class HTTPBible(BibleDB):
self.wizard.incrementProgressBar(translate(
'BiblesPlugin.HTTPBible', 'Importing %s...',
'Importing <book name>...') % book)
book_ref_id = self.get_book_ref_id_by_name(book, len(books),
language_id)
book_ref_id = self.get_book_ref_id_by_name(book, len(books), language_id)
if not book_ref_id:
log.exception(u'Importing books from %s - download name: "%s" '\
'failed' % (self.download_source, self.download_name))
@ -598,7 +582,7 @@ class HTTPBible(BibleDB):
return []
book = db_book.name
if BibleDB.get_verse_count(self, book_id, reference[1]) == 0:
Receiver.send_message(u'cursor_busy')
self.application.set_busy_cursor()
search_results = self.get_chapter(book, reference[1])
if search_results and search_results.has_verselist():
## We have found a book of the bible lets check to see
@ -606,14 +590,13 @@ class HTTPBible(BibleDB):
## we get a correct book. For example it is possible
## to request ac and get Acts back.
book_name = search_results.book
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
# Check to see if book/chapter exists.
db_book = self.get_book(book_name)
self.create_chapter(db_book.id, search_results.chapter,
search_results.verselist)
Receiver.send_message(u'openlp_process_events')
Receiver.send_message(u'cursor_normal')
Receiver.send_message(u'openlp_process_events')
self.create_chapter(db_book.id, search_results.chapter, search_results.verselist)
self.application.process_events()
self.application.set_normal_cursor()
self.application.process_events()
return BibleDB.get_verses(self, reference_list, show_error)
def get_chapter(self, book, chapter):
@ -660,6 +643,16 @@ class HTTPBible(BibleDB):
log.debug(u'HTTPBible.get_verse_count("%s", %s)', book_id, chapter)
return BiblesResourcesDB.get_verse_count(book_id, chapter)
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)
def get_soup_for_bible_ref(reference_url, header=None, pre_parse_regex=None,
pre_parse_substitute=None, cleaner=None):
"""
@ -701,7 +694,7 @@ def get_soup_for_bible_ref(reference_url, header=None, pre_parse_regex=None,
if not soup:
send_error_message(u'parse')
return None
Receiver.send_message(u'openlp_process_events')
Registry().get(u'application').process_events()
return soup
def send_error_message(error_type):

View File

@ -30,7 +30,7 @@
import logging
import os
from openlp.core.lib import Receiver, SettingsManager, translate, Settings
from openlp.core.lib import Receiver, SettingsManager, Settings, translate
from openlp.core.utils import AppLocation, delete_file
from openlp.plugins.bibles.lib import parse_reference, get_reference_separator, LanguageSelection
from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta

View File

@ -31,8 +31,8 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, translate, create_separated_list, \
ServiceItemContext, Settings, UiStrings
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, ServiceItemContext, Settings, UiStrings, \
create_separated_list, translate
from openlp.core.lib.searchedit import SearchEdit
from openlp.core.lib.ui import set_case_insensitive_completer, create_horizontal_adjusting_combo_box, \
critical_error_message_box, find_and_set_in_combo_box, build_icon
@ -349,7 +349,7 @@ class BibleMediaItem(MediaManagerItem):
self.loadBibles()
# If called from first time wizard re-run, process any new bibles.
if process:
self.plugin.appStartup()
self.plugin.app_startup()
self.updateAutoCompleter()
def initialiseAdvancedBible(self, bible, last_book_id=None):
@ -614,7 +614,7 @@ class BibleMediaItem(MediaManagerItem):
"""
log.debug(u'Advanced Search Button clicked')
self.advancedSearchButton.setEnabled(False)
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
bible = self.advancedVersionComboBox.currentText()
second_bible = self.advancedSecondComboBox.currentText()
book = self.advancedBookComboBox.currentText()
@ -628,7 +628,7 @@ class BibleMediaItem(MediaManagerItem):
verse_range = chapter_from + verse_separator + verse_from + range_separator + chapter_to + \
verse_separator + verse_to
versetext = u'%s %s' % (book, verse_range)
Receiver.send_message(u'cursor_busy')
self.application.set_busy_cursor()
self.search_results = self.plugin.manager.get_verses(bible, versetext, book_ref_id)
if second_bible:
self.second_search_results = self.plugin.manager.get_verses(second_bible, versetext, book_ref_id)
@ -640,8 +640,7 @@ class BibleMediaItem(MediaManagerItem):
self.displayResults(bible, second_bible)
self.advancedSearchButton.setEnabled(True)
self.checkSearchResult()
Receiver.send_message(u'cursor_normal')
Receiver.send_message(u'openlp_process_events')
self.application.set_normal_cursor()
def onQuickSearchButton(self):
"""
@ -650,7 +649,7 @@ class BibleMediaItem(MediaManagerItem):
"""
log.debug(u'Quick Search Button clicked')
self.quickSearchButton.setEnabled(False)
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
bible = self.quickVersionComboBox.currentText()
second_bible = self.quickSecondComboBox.currentText()
text = self.quickSearchEdit.text()
@ -662,7 +661,7 @@ class BibleMediaItem(MediaManagerItem):
self.search_results[0].book.book_reference_id)
else:
# We are doing a 'Text Search'.
Receiver.send_message(u'cursor_busy')
self.application.set_busy_cursor()
bibles = self.plugin.manager.get_bibles()
self.search_results = self.plugin.manager.verse_search(bible, second_bible, text)
if second_bible and self.search_results:
@ -697,8 +696,7 @@ class BibleMediaItem(MediaManagerItem):
self.displayResults(bible, second_bible)
self.quickSearchButton.setEnabled(True)
self.checkSearchResult()
Receiver.send_message(u'cursor_normal')
Receiver.send_message(u'openlp_process_events')
self.application.set_normal_cursor()
def displayResults(self, bible, second_bible=u''):
"""

View File

@ -31,7 +31,6 @@ import logging
import sqlite
import sys
from openlp.core.lib import Receiver
from openlp.core.ui.wizard import WizardStrings
from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB
@ -108,7 +107,7 @@ class OpenLP1Bible(BibleDB):
verse_number = int(verse[1])
text = unicode(verse[2], u'cp1252')
self.create_verse(db_book.id, chapter, verse_number, text)
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
self.session.commit()
connection.close()
return True

View File

@ -30,7 +30,7 @@
import logging
from lxml import etree, objectify
from openlp.core.lib import Receiver, translate
from openlp.core.lib import translate
from openlp.core.lib.ui import critical_error_message_box
from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB
@ -129,7 +129,7 @@ class OpenSongBible(BibleDB):
self.wizard.incrementProgressBar(translate('BiblesPlugin.Opensong', 'Importing %s %s...',
'Importing <book name> <chapter>...')) % (db_book.name, chapter_number)
self.session.commit()
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
except etree.XMLSyntaxError as inst:
critical_error_message_box(message=translate('BiblesPlugin.OpenSongImport',
'Incorrect Bible file type supplied. OpenSong Bibles may be '

View File

@ -33,7 +33,7 @@ import chardet
import codecs
import re
from openlp.core.lib import Receiver, translate
from openlp.core.lib import translate
from openlp.core.utils import AppLocation
from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB
@ -182,7 +182,7 @@ class OSISBible(BibleDB):
.replace(u'</div>', u'').replace(u'</w>', u'')
verse_text = self.spaces_regex.sub(u' ', verse_text)
self.create_verse(db_book.id, chapter, verse, verse_text)
Receiver.send_message(u'openlp_process_events')
self.application.process_events()
self.session.commit()
if match_count == 0:
success = False

View File

@ -72,12 +72,12 @@ class VerseReferenceList(object):
prev = index - 1
if self.verse_list[prev][u'version'] != verse[u'version']:
result = u'%s (%s)' % (result, self.verse_list[prev][u'version'])
result = result + u', '
result += u', '
if self.verse_list[prev][u'book'] != verse[u'book']:
result = u'%s%s %s:' % (result, verse[u'book'], verse[u'chapter'])
elif self.verse_list[prev][u'chapter'] != verse[u'chapter']:
result = u'%s%s:' % (result, verse[u'chapter'])
result = result + str(verse[u'start'])
result += str(verse[u'start'])
if verse[u'start'] != verse[u'end']:
result = u'%s-%s' % (result, verse[u'end'])
if len(self.version_list) > 1:
@ -89,8 +89,8 @@ class VerseReferenceList(object):
for index, version in enumerate(self.version_list):
if index > 0:
if result[-1] not in [u';', u',', u'.']:
result = result + u';'
result = result + u' '
result += u';'
result += u' '
result = u'%s%s, %s' % (result, version[u'version'], version[u'copyright'])
if version[u'permission'].strip():
result = result + u', ' + version[u'permission']

View File

@ -29,7 +29,7 @@
from PyQt4 import QtGui
from openlp.core.lib import build_icon, translate, UiStrings
from openlp.core.lib import UiStrings, build_icon, translate
from openlp.core.lib.ui import create_button_box, create_button
class Ui_CustomEditDialog(object):

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