This commit is contained in:
phill-ridout 2013-07-06 15:23:30 +01:00
commit b26793db1f
43 changed files with 910 additions and 825 deletions

View File

@ -38,6 +38,8 @@ from sqlalchemy import Table, MetaData, Column, types, create_engine
from sqlalchemy.exc import SQLAlchemyError, InvalidRequestError, DBAPIError, OperationalError from sqlalchemy.exc import SQLAlchemyError, InvalidRequestError, DBAPIError, OperationalError
from sqlalchemy.orm import scoped_session, sessionmaker, mapper from sqlalchemy.orm import scoped_session, sessionmaker, mapper
from sqlalchemy.pool import NullPool from sqlalchemy.pool import NullPool
from alembic.migration import MigrationContext
from alembic.operations import Operations
from openlp.core.lib import translate, Settings from openlp.core.lib import translate, Settings
from openlp.core.lib.ui import critical_error_message_box from openlp.core.lib.ui import critical_error_message_box
@ -65,6 +67,17 @@ def init_db(url, auto_flush=True, auto_commit=False):
return session, metadata return session, metadata
def get_upgrade_op(session):
"""
Create a migration context and an operations object for performing upgrades.
``session``
The SQLAlchemy session object.
"""
context = MigrationContext.configure(session.bind.connect())
return Operations(context)
def upgrade_db(url, upgrade): def upgrade_db(url, upgrade):
""" """
Upgrade a database. Upgrade a database.
@ -82,13 +95,7 @@ def upgrade_db(url, upgrade):
Provides a class for the metadata table. Provides a class for the metadata table.
""" """
pass pass
load_changes = False
tables = []
try:
tables = upgrade.upgrade_setup(metadata)
load_changes = True
except (SQLAlchemyError, DBAPIError):
pass
metadata_table = Table(u'metadata', metadata, metadata_table = Table(u'metadata', metadata,
Column(u'key', types.Unicode(64), primary_key=True), Column(u'key', types.Unicode(64), primary_key=True),
Column(u'value', types.UnicodeText(), default=None) Column(u'value', types.UnicodeText(), default=None)
@ -105,22 +112,22 @@ def upgrade_db(url, upgrade):
if version > upgrade.__version__: if version > upgrade.__version__:
return version, upgrade.__version__ return version, upgrade.__version__
version += 1 version += 1
if load_changes: try:
while hasattr(upgrade, u'upgrade_%d' % version): while hasattr(upgrade, u'upgrade_%d' % version):
log.debug(u'Running upgrade_%d', version) log.debug(u'Running upgrade_%d', version)
try: try:
upgrade_func = getattr(upgrade, u'upgrade_%d' % version) upgrade_func = getattr(upgrade, u'upgrade_%d' % version)
upgrade_func(session, metadata, tables) upgrade_func(session, metadata)
session.commit() session.commit()
# Update the version number AFTER a commit so that we are sure the previous transaction happened # Update the version number AFTER a commit so that we are sure the previous transaction happened
version_meta.value = unicode(version) version_meta.value = unicode(version)
session.commit() session.commit()
version += 1 version += 1
except (SQLAlchemyError, DBAPIError): except (SQLAlchemyError, DBAPIError):
log.exception(u'Could not run database upgrade script ' log.exception(u'Could not run database upgrade script "upgrade_%s", upgrade process has been halted.',
'"upgrade_%s", upgrade process has been halted.', version) version)
break break
else: except (SQLAlchemyError, DBAPIError):
version_meta = Metadata.populate(key=u'version', value=int(upgrade.__version__)) version_meta = Metadata.populate(key=u'version', value=int(upgrade.__version__))
session.commit() session.commit()
return int(version_meta.value), upgrade.__version__ return int(version_meta.value), upgrade.__version__

View File

@ -29,7 +29,7 @@
""" """
Provide HTML Tag management and Formatting Tag access class Provide HTML Tag management and Formatting Tag access class
""" """
import cPickle import json
from openlp.core.lib import Settings, translate from openlp.core.lib import Settings, translate
@ -66,7 +66,7 @@ class FormattingTags(object):
if isinstance(tag[element], unicode): if isinstance(tag[element], unicode):
tag[element] = tag[element].encode('utf8') tag[element] = tag[element].encode('utf8')
# Formatting Tags were also known as display tags. # Formatting Tags were also known as display tags.
Settings().setValue(u'displayTags/html_tags', cPickle.dumps(tags) if tags else u'') Settings().setValue(u'formattingTags/html_tags', json.dumps(tags) if tags else u'')
@staticmethod @staticmethod
def load_tags(): def load_tags():
@ -156,13 +156,10 @@ class FormattingTags(object):
u'end html': u'', u'protected': True, u'temporary': False}) u'end html': u'', u'protected': True, u'temporary': False})
FormattingTags.add_html_tags(base_tags) FormattingTags.add_html_tags(base_tags)
FormattingTags.add_html_tags(temporary_tags) FormattingTags.add_html_tags(temporary_tags)
# Formatting Tags were also known as display tags. # Formatting Tags were also known as display tags.
user_expands = Settings().value(u'displayTags/html_tags') user_expands_string = str(Settings().value(u'formattingTags/html_tags'))
# cPickle only accepts str not unicode strings
user_expands_string = str(user_expands)
if user_expands_string: if user_expands_string:
user_tags = cPickle.loads(user_expands_string) user_tags = json.loads(user_expands_string)
for tag in user_tags: for tag in user_tags:
for element in tag: for element in tag:
if isinstance(tag[element], str): if isinstance(tag[element], str):

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 # vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4

View File

@ -728,10 +728,14 @@ class MediaManagerItem(QtGui.QWidget):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -30,6 +30,7 @@
Provide the generic plugin functionality for OpenLP plugins. Provide the generic plugin functionality for OpenLP plugins.
""" """
import logging import logging
import os
from PyQt4 import QtCore from PyQt4 import QtCore
@ -424,8 +425,11 @@ class Plugin(QtCore.QObject):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -103,9 +103,6 @@ class Registry(object):
``key`` ``key``
The service to be deleted. The service to be deleted.
""" """
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)
if key in self.service_list: if key in self.service_list:
del self.service_list[key] del self.service_list[key]

View File

@ -485,6 +485,12 @@ class ServiceItem(object):
""" """
return self.unique_identifier != other.unique_identifier return self.unique_identifier != other.unique_identifier
def __hash__(self):
"""
Return the hash for the service item.
"""
return self.unique_identifier
def is_media(self): def is_media(self):
""" """
Confirms if the ServiceItem is media Confirms if the ServiceItem is media

View File

@ -115,7 +115,7 @@ class Settings(QtCore.QSettings):
u'advanced/single click preview': False, u'advanced/single click preview': False,
u'advanced/x11 bypass wm': X11_BYPASS_DEFAULT, u'advanced/x11 bypass wm': X11_BYPASS_DEFAULT,
u'crashreport/last directory': u'', u'crashreport/last directory': u'',
u'displayTags/html_tags': u'', u'formattingTags/html_tags': u'',
u'core/audio repeat list': False, u'core/audio repeat list': False,
u'core/auto open': False, u'core/auto open': False,
u'core/auto preview': False, u'core/auto preview': False,
@ -244,6 +244,7 @@ class Settings(QtCore.QSettings):
u'shortcuts/printServiceItem': [QtGui.QKeySequence(u'Ctrl+P')], u'shortcuts/printServiceItem': [QtGui.QKeySequence(u'Ctrl+P')],
u'shortcuts/songExportItem': [], u'shortcuts/songExportItem': [],
u'shortcuts/songUsageStatus': [QtGui.QKeySequence(QtCore.Qt.Key_F4)], u'shortcuts/songUsageStatus': [QtGui.QKeySequence(QtCore.Qt.Key_F4)],
u'shortcuts/searchShortcut': [QtGui.QKeySequence(u'Ctrl+F')],
u'shortcuts/settingsShortcutsItem': [], u'shortcuts/settingsShortcutsItem': [],
u'shortcuts/settingsImportItem': [], u'shortcuts/settingsImportItem': [],
u'shortcuts/settingsPluginListItem': [QtGui.QKeySequence(u'Alt+F7')], u'shortcuts/settingsPluginListItem': [QtGui.QKeySequence(u'Alt+F7')],

View File

@ -291,7 +291,7 @@ class Ui_AboutDialog(object):
'but WITHOUT ANY WARRANTY; without even the implied warranty of ' 'but WITHOUT ANY WARRANTY; without even the implied warranty of '
'MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See below ' 'MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See below '
'for more details.') 'for more details.')
gpltext = ('GNU GENERAL PUBLIC LICENSE\n' gpl_text = ('GNU GENERAL PUBLIC LICENSE\n'
'Version 2, June 1991\n' 'Version 2, June 1991\n'
'\n' '\n'
'Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 ' 'Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 '
@ -662,7 +662,7 @@ class Ui_AboutDialog(object):
'linking proprietary applications with the library. If this is ' 'linking proprietary applications with the library. If this is '
'what you want to do, use the GNU Lesser General Public License ' 'what you want to do, use the GNU Lesser General Public License '
'instead of this License.') 'instead of this License.')
self.license_text_edit.setPlainText(u'%s\n\n%s\n\n%s\n\n\n%s' % (copyright_note, licence, disclaimer, gpltext)) self.license_text_edit.setPlainText(u'%s\n\n%s\n\n%s\n\n\n%s' % (copyright_note, licence, disclaimer, gpl_text))
self.about_notebook.setTabText(self.about_notebook.indexOf(self.license_tab), self.about_notebook.setTabText(self.about_notebook.indexOf(self.license_tab),
translate('OpenLP.AboutForm', 'License')) translate('OpenLP.AboutForm', 'License'))
self.volunteer_button.setText(translate('OpenLP.AboutForm', 'Volunteer')) self.volunteer_button.setText(translate('OpenLP.AboutForm', 'Volunteer'))

View File

@ -68,7 +68,7 @@ class ThemeScreenshotThread(QtCore.QThread):
screenshot = config.get(u'theme_%s' % theme, u'screenshot') screenshot = config.get(u'theme_%s' % theme, u'screenshot')
urllib.urlretrieve(u'%s%s' % (self.parent().web, screenshot), urllib.urlretrieve(u'%s%s' % (self.parent().web, screenshot),
os.path.join(unicode(gettempdir(), get_filesystem_encoding()), u'openlp', screenshot)) os.path.join(unicode(gettempdir(), get_filesystem_encoding()), u'openlp', screenshot))
item = QtGui.QListWidgetItem(title, self.parent().themesListWidget) item = QtGui.QListWidgetItem(title, self.parent().themes_list_widget)
item.setData(QtCore.Qt.UserRole, filename) item.setData(QtCore.Qt.UserRole, filename)
item.setCheckState(QtCore.Qt.Unchecked) item.setCheckState(QtCore.Qt.Unchecked)
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable) item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
@ -76,8 +76,7 @@ class ThemeScreenshotThread(QtCore.QThread):
class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard): class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
""" """
This is the Theme Import Wizard, which allows easy creation and editing of This is the Theme Import Wizard, which allows easy creation and editing of OpenLP themes.
OpenLP themes.
""" """
log.info(u'ThemeWizardForm loaded') log.info(u'ThemeWizardForm loaded')
@ -97,10 +96,11 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self.config.readfp(io.BytesIO(files)) self.config.readfp(io.BytesIO(files))
self.update_screen_list_combo() self.update_screen_list_combo()
self.was_download_cancelled = False self.was_download_cancelled = False
self.theme_screenshot_thread = None
self.downloading = translate('OpenLP.FirstTimeWizard', 'Downloading %s...') self.downloading = translate('OpenLP.FirstTimeWizard', 'Downloading %s...')
self.cancelButton.clicked.connect(self.onCancelButtonClicked) self.cancel_button.clicked.connect(self.on_cancel_button_clicked)
self.noInternetFinishButton.clicked.connect(self.onNoInternetFinishButtonClicked) self.no_internet_finish_button.clicked.connect(self.on_no_internet_finish_button_clicked)
self.currentIdChanged.connect(self.onCurrentIdChanged) self.currentIdChanged.connect(self.on_current_id_changed)
Registry().register_function(u'config_screen_changed', self.update_screen_list_combo) Registry().register_function(u'config_screen_changed', self.update_screen_list_combo)
def exec_(self): def exec_(self):
@ -116,9 +116,9 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
""" """
self.restart() 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) self.no_internet_finish_button.setVisible(False)
# Check if this is a re-run of the wizard. # Check if this is a re-run of the wizard.
self.hasRunWizard = Settings().value(u'core/has run wizard') self.has_run_wizard = Settings().value(u'core/has run wizard')
# Sort out internet access for downloads # Sort out internet access for downloads
if self.web_access: if self.web_access:
songs = self.config.get(u'songs', u'languages') songs = self.config.get(u'songs', u'languages')
@ -126,7 +126,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
for song in songs: for song in songs:
title = unicode(self.config.get(u'songs_%s' % song, u'title'), u'utf8') title = unicode(self.config.get(u'songs_%s' % song, u'title'), u'utf8')
filename = unicode(self.config.get(u'songs_%s' % song, u'filename'), u'utf8') filename = unicode(self.config.get(u'songs_%s' % song, u'filename'), u'utf8')
item = QtGui.QListWidgetItem(title, self.songsListWidget) item = QtGui.QListWidgetItem(title, self.songs_list_widget)
item.setData(QtCore.Qt.UserRole, filename) item.setData(QtCore.Qt.UserRole, filename)
item.setCheckState(QtCore.Qt.Unchecked) item.setCheckState(QtCore.Qt.Unchecked)
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable) item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
@ -134,7 +134,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
bible_languages = bible_languages.split(u',') bible_languages = bible_languages.split(u',')
for lang in bible_languages: for lang in bible_languages:
language = unicode(self.config.get(u'bibles_%s' % lang, u'title'), u'utf8') language = unicode(self.config.get(u'bibles_%s' % lang, u'title'), u'utf8')
langItem = QtGui.QTreeWidgetItem(self.biblesTreeWidget, [language]) langItem = QtGui.QTreeWidgetItem(self.bibles_tree_widget, [language])
bibles = self.config.get(u'bibles_%s' % lang, u'translations') bibles = self.config.get(u'bibles_%s' % lang, u'translations')
bibles = bibles.split(u',') bibles = bibles.split(u',')
for bible in bibles: for bible in bibles:
@ -144,10 +144,10 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
item.setData(0, QtCore.Qt.UserRole, filename) item.setData(0, QtCore.Qt.UserRole, filename)
item.setCheckState(0, QtCore.Qt.Unchecked) item.setCheckState(0, QtCore.Qt.Unchecked)
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable) item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
self.biblesTreeWidget.expandAll() self.bibles_tree_widget.expandAll()
# Download the theme screenshots. # Download the theme screenshots.
self.themeScreenshotThread = ThemeScreenshotThread(self) self.theme_screenshot_thread = ThemeScreenshotThread(self)
self.themeScreenshotThread.start() self.theme_screenshot_thread.start()
self.application.set_normal_cursor() self.application.set_normal_cursor()
def nextId(self): def nextId(self):
@ -166,61 +166,60 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
return FirstTimePage.Progress return FirstTimePage.Progress
elif self.currentId() == FirstTimePage.Themes: elif self.currentId() == FirstTimePage.Themes:
self.application.set_busy_cursor() self.application.set_busy_cursor()
while not self.themeScreenshotThread.isFinished(): while not self.theme_screenshot_thread.isFinished():
time.sleep(0.1) time.sleep(0.1)
self.application.process_events() self.application.process_events()
# Build the screenshot icons, as this can not be done in the thread. # Build the screenshot icons, as this can not be done in the thread.
self._buildThemeScreenshots() self._build_theme_screenshots()
self.application.set_normal_cursor() self.application.set_normal_cursor()
return FirstTimePage.Defaults return FirstTimePage.Defaults
else: else:
return self.currentId() + 1 return self.currentId() + 1
def onCurrentIdChanged(self, pageId): def on_current_id_changed(self, page_id):
""" """
Detects Page changes and updates as appropriate. Detects Page changes and updates as appropriate.
""" """
# Keep track of the page we are at. Triggering "Cancel" causes pageId # Keep track of the page we are at. Triggering "Cancel" causes page_id to be a -1.
# to be a -1.
self.application.process_events() self.application.process_events()
if pageId != -1: if page_id != -1:
self.lastId = pageId self.last_id = page_id
if pageId == FirstTimePage.Plugins: if page_id == FirstTimePage.Plugins:
# Set the no internet page text. # Set the no internet page text.
if self.hasRunWizard: if self.has_run_wizard:
self.noInternetLabel.setText(self.noInternetText) self.no_internet_label.setText(self.no_internet_text)
else: else:
self.noInternetLabel.setText(self.noInternetText + self.cancelWizardText) self.no_internet_label.setText(self.no_internet_text + self.cancelWizardText)
elif pageId == FirstTimePage.Defaults: elif page_id == FirstTimePage.Defaults:
self.themeComboBox.clear() self.theme_combo_box.clear()
for iter in xrange(self.themesListWidget.count()): for iter in xrange(self.themes_list_widget.count()):
item = self.themesListWidget.item(iter) item = self.themes_list_widget.item(iter)
if item.checkState() == QtCore.Qt.Checked: if item.checkState() == QtCore.Qt.Checked:
self.themeComboBox.addItem(item.text()) self.theme_combo_box.addItem(item.text())
if self.hasRunWizard: if self.has_run_wizard:
# Add any existing themes to list. # Add any existing themes to list.
for theme in self.theme_manager.get_themes(): for theme in self.theme_manager.get_themes():
index = self.themeComboBox.findText(theme) index = self.theme_combo_box.findText(theme)
if index == -1: if index == -1:
self.themeComboBox.addItem(theme) self.theme_combo_box.addItem(theme)
default_theme = Settings().value(u'themes/global theme') default_theme = Settings().value(u'themes/global theme')
# Pre-select the current default theme. # Pre-select the current default theme.
index = self.themeComboBox.findText(default_theme) index = self.theme_combo_box.findText(default_theme)
self.themeComboBox.setCurrentIndex(index) self.theme_combo_box.setCurrentIndex(index)
elif pageId == FirstTimePage.NoInternet: elif page_id == FirstTimePage.NoInternet:
self.backButton.setVisible(False) self.back_button.setVisible(False)
self.nextButton.setVisible(False) self.next_button.setVisible(False)
self.noInternetFinishButton.setVisible(True) self.no_internet_finish_button.setVisible(True)
if self.hasRunWizard: if self.has_run_wizard:
self.cancelButton.setVisible(False) self.cancel_button.setVisible(False)
elif pageId == FirstTimePage.Progress: elif page_id == FirstTimePage.Progress:
self.application.set_busy_cursor() self.application.set_busy_cursor()
self.repaint() self.repaint()
self.application.process_events() self.application.process_events()
# Try to give the wizard a chance to redraw itself # Try to give the wizard a chance to redraw itself
time.sleep(0.2) time.sleep(0.2)
self._preWizard() self._pre_wizard()
self._performWizard() self._perform_wizard()
self._post_wizard() self._post_wizard()
self.application.set_normal_cursor() self.application.set_normal_cursor()
@ -229,70 +228,72 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
The user changed screen resolution or enabled/disabled more screens, so The user changed screen resolution or enabled/disabled more screens, so
we need to update the combo box. we need to update the combo box.
""" """
self.displayComboBox.clear() self.display_combo_box.clear()
self.displayComboBox.addItems(self.screens.get_screen_list()) self.display_combo_box.addItems(self.screens.get_screen_list())
self.displayComboBox.setCurrentIndex(self.displayComboBox.count() - 1) self.display_combo_box.setCurrentIndex(self.display_combo_box.count() - 1)
def onCancelButtonClicked(self): def on_cancel_button_clicked(self):
""" """
Process the triggering of the cancel button. Process the triggering of the cancel button.
""" """
if self.lastId == FirstTimePage.NoInternet or (self.lastId <= FirstTimePage.Plugins and not self.hasRunWizard): if self.last_id == FirstTimePage.NoInternet or (self.last_id <= FirstTimePage.Plugins and not self.has_run_wizard):
QtCore.QCoreApplication.exit() QtCore.QCoreApplication.exit()
sys.exit() sys.exit()
self.was_download_cancelled = True self.was_download_cancelled = True
while self.themeScreenshotThread.isRunning(): # Was the thread created.
time.sleep(0.1) if self.theme_screenshot_thread:
while self.theme_screenshot_thread.isRunning():
time.sleep(0.1)
self.application.set_normal_cursor() self.application.set_normal_cursor()
def onNoInternetFinishButtonClicked(self): def on_no_internet_finish_button_clicked(self):
""" """
Process the triggering of the "Finish" button on the No Internet page. Process the triggering of the "Finish" button on the No Internet page.
""" """
self.application.set_busy_cursor() self.application.set_busy_cursor()
self._performWizard() self._perform_wizard()
self.application.set_normal_cursor() self.application.set_normal_cursor()
Settings().setValue(u'core/has run wizard', True) Settings().setValue(u'core/has run wizard', True)
self.close() self.close()
def urlGetFile(self, url, fpath): def url_get_file(self, url, f_path):
"""" """"
Download a file given a URL. The file is retrieved in chunks, giving Download a file given a URL. The file is retrieved in chunks, giving the ability to cancel the download at any
the ability to cancel the download at any point. point.
""" """
block_count = 0 block_count = 0
block_size = 4096 block_size = 4096
urlfile = urllib2.urlopen(url) url_file = urllib2.urlopen(url)
filename = open(fpath, "wb") filename = open(f_path, "wb")
# Download until finished or canceled. # Download until finished or canceled.
while not self.was_download_cancelled: while not self.was_download_cancelled:
data = urlfile.read(block_size) data = url_file.read(block_size)
if not data: if not data:
break break
filename.write(data) filename.write(data)
block_count += 1 block_count += 1
self._downloadProgress(block_count, block_size) self._download_progress(block_count, block_size)
filename.close() filename.close()
# Delete file if cancelled, it may be a partial file. # Delete file if cancelled, it may be a partial file.
if self.was_download_cancelled: if self.was_download_cancelled:
os.remove(fpath) os.remove(f_path)
def _buildThemeScreenshots(self): def _build_theme_screenshots(self):
""" """
This method builds the theme screenshots' icons for all items in the This method builds the theme screenshots' icons for all items in the
``self.themesListWidget``. ``self.themes_list_widget``.
""" """
themes = self.config.get(u'themes', u'files') themes = self.config.get(u'themes', u'files')
themes = themes.split(u',') themes = themes.split(u',')
for theme in themes: for theme in themes:
filename = self.config.get(u'theme_%s' % theme, u'filename') filename = self.config.get(u'theme_%s' % theme, u'filename')
screenshot = self.config.get(u'theme_%s' % theme, u'screenshot') screenshot = self.config.get(u'theme_%s' % theme, u'screenshot')
for index in xrange(self.themesListWidget.count()): for index in xrange(self.themes_list_widget.count()):
item = self.themesListWidget.item(index) item = self.themes_list_widget.item(index)
if item.data(QtCore.Qt.UserRole) == filename: if item.data(QtCore.Qt.UserRole) == filename:
break break
item.setIcon(build_icon(os.path.join(unicode(gettempdir(), item.setIcon(build_icon(os.path.join(unicode(gettempdir(),
get_filesystem_encoding()), u'openlp', screenshot))) get_filesystem_encoding()), u'openlp', screenshot)))
def _getFileSize(self, url): def _getFileSize(self, url):
""" """
@ -305,15 +306,15 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
meta = site.info() meta = site.info()
return int(meta.getheaders("Content-Length")[0]) return int(meta.getheaders("Content-Length")[0])
def _downloadProgress(self, count, block_size): def _download_progress(self, count, block_size):
""" """
Calculate and display the download progress. Calculate and display the download progress.
""" """
increment = (count * block_size) - self.previous_size increment = (count * block_size) - self.previous_size
self._incrementProgressBar(None, increment) self._increment_progress_bar(None, increment)
self.previous_size = count * block_size self.previous_size = count * block_size
def _incrementProgressBar(self, status_text, increment=1): def _increment_progress_bar(self, status_text, increment=1):
""" """
Update the wizard progress page. Update the wizard progress page.
@ -324,28 +325,28 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
The value to increment the progress bar by. The value to increment the progress bar by.
""" """
if status_text: if status_text:
self.progressLabel.setText(status_text) self.progress_label.setText(status_text)
if increment > 0: if increment > 0:
self.progressBar.setValue(self.progressBar.value() + increment) self.progress_bar.setValue(self.progress_bar.value() + increment)
self.application.process_events() self.application.process_events()
def _preWizard(self): def _pre_wizard(self):
""" """
Prepare the UI for the process. Prepare the UI for the process.
""" """
self.max_progress = 0 self.max_progress = 0
self.finishButton.setVisible(False) self.finish_button.setVisible(False)
self.application.process_events() self.application.process_events()
# Loop through the songs list and increase for each selected item # Loop through the songs list and increase for each selected item
for i in xrange(self.songsListWidget.count()): for i in xrange(self.songs_list_widget.count()):
self.application.process_events() self.application.process_events()
item = self.songsListWidget.item(i) item = self.songs_list_widget.item(i)
if item.checkState() == QtCore.Qt.Checked: if item.checkState() == QtCore.Qt.Checked:
filename = item.data(QtCore.Qt.UserRole) filename = item.data(QtCore.Qt.UserRole)
size = self._getFileSize(u'%s%s' % (self.web, filename)) size = self._getFileSize(u'%s%s' % (self.web, filename))
self.max_progress += size self.max_progress += size
# Loop through the Bibles list and increase for each selected item # Loop through the Bibles list and increase for each selected item
iterator = QtGui.QTreeWidgetItemIterator(self.biblesTreeWidget) iterator = QtGui.QTreeWidgetItemIterator(self.bibles_tree_widget)
while iterator.value(): while iterator.value():
self.application.process_events() self.application.process_events()
item = iterator.value() item = iterator.value()
@ -355,9 +356,9 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self.max_progress += size self.max_progress += size
iterator += 1 iterator += 1
# Loop through the themes list and increase for each selected item # Loop through the themes list and increase for each selected item
for i in xrange(self.themesListWidget.count()): for i in xrange(self.themes_list_widget.count()):
self.application.process_events() self.application.process_events()
item = self.themesListWidget.item(i) item = self.themes_list_widget.item(i)
if item.checkState() == QtCore.Qt.Checked: if item.checkState() == QtCore.Qt.Checked:
filename = item.data(QtCore.Qt.UserRole) filename = item.data(QtCore.Qt.UserRole)
size = self._getFileSize(u'%s%s' % (self.web, filename)) size = self._getFileSize(u'%s%s' % (self.web, filename))
@ -365,16 +366,16 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
if self.max_progress: if self.max_progress:
# Add on 2 for plugins status setting plus a "finished" point. # Add on 2 for plugins status setting plus a "finished" point.
self.max_progress += 2 self.max_progress += 2
self.progressBar.setValue(0) self.progress_bar.setValue(0)
self.progressBar.setMinimum(0) self.progress_bar.setMinimum(0)
self.progressBar.setMaximum(self.max_progress) self.progress_bar.setMaximum(self.max_progress)
self.progressPage.setTitle(translate('OpenLP.FirstTimeWizard', 'Setting Up And Downloading')) self.progress_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Setting Up And Downloading'))
self.progressPage.setSubTitle( self.progress_page.setSubTitle(
translate('OpenLP.FirstTimeWizard', 'Please wait while OpenLP is set up and your data is downloaded.')) translate('OpenLP.FirstTimeWizard', 'Please wait while OpenLP is set up and your data is downloaded.'))
else: else:
self.progressBar.setVisible(False) self.progress_bar.setVisible(False)
self.progressPage.setTitle(translate('OpenLP.FirstTimeWizard', 'Setting Up')) self.progress_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Setting Up'))
self.progressPage.setSubTitle(u'Setup complete.') self.progress_page.setSubTitle(u'Setup complete.')
self.repaint() self.repaint()
self.application.process_events() self.application.process_events()
# Try to give the wizard a chance to repaint itself # Try to give the wizard a chance to repaint itself
@ -385,44 +386,44 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
Clean up the UI after the process has finished. Clean up the UI after the process has finished.
""" """
if self.max_progress: if self.max_progress:
self.progressBar.setValue(self.progressBar.maximum()) self.progress_bar.setValue(self.progress_bar.maximum())
if self.hasRunWizard: if self.has_run_wizard:
self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', self.progress_label.setText(translate('OpenLP.FirstTimeWizard',
'Download complete. Click the finish button to return to OpenLP.')) 'Download complete. Click the finish button to return to OpenLP.'))
else: else:
self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', self.progress_label.setText(translate('OpenLP.FirstTimeWizard',
'Download complete. Click the finish button to start OpenLP.')) 'Download complete. Click the finish button to start OpenLP.'))
else: else:
if self.hasRunWizard: if self.has_run_wizard:
self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', self.progress_label.setText(translate('OpenLP.FirstTimeWizard',
'Click the finish button to return to OpenLP.')) 'Click the finish button to return to OpenLP.'))
else: else:
self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', self.progress_label.setText(translate('OpenLP.FirstTimeWizard',
'Click the finish button to start OpenLP.')) 'Click the finish button to start OpenLP.'))
self.finishButton.setVisible(True) self.finish_button.setVisible(True)
self.finishButton.setEnabled(True) self.finish_button.setEnabled(True)
self.cancelButton.setVisible(False) self.cancel_button.setVisible(False)
self.nextButton.setVisible(False) self.next_button.setVisible(False)
self.application.process_events() self.application.process_events()
def _performWizard(self): def _perform_wizard(self):
""" """
Run the tasks in the wizard. Run the tasks in the wizard.
""" """
# Set plugin states # Set plugin states
self._incrementProgressBar(translate('OpenLP.FirstTimeWizard', 'Enabling selected plugins...')) self._increment_progress_bar(translate('OpenLP.FirstTimeWizard', 'Enabling selected plugins...'))
self._setPluginStatus(self.songsCheckBox, u'songs/status') self._set_plugin_status(self.songs_check_box, u'songs/status')
self._setPluginStatus(self.bibleCheckBox, u'bibles/status') self._set_plugin_status(self.bible_check_box, u'bibles/status')
# TODO Presentation plugin is not yet working on Mac OS X. # TODO Presentation plugin is not yet working on Mac OS X.
# For now just ignore it. # For now just ignore it.
if sys.platform != 'darwin': if sys.platform != 'darwin':
self._setPluginStatus(self.presentationCheckBox, u'presentations/status') self._set_plugin_status(self.presentation_check_box, u'presentations/status')
self._setPluginStatus(self.imageCheckBox, u'images/status') self._set_plugin_status(self.image_check_box, u'images/status')
self._setPluginStatus(self.mediaCheckBox, u'media/status') self._set_plugin_status(self.media_check_box, u'media/status')
self._setPluginStatus(self.remoteCheckBox, u'remotes/status') self._set_plugin_status(self.remote_check_box, u'remotes/status')
self._setPluginStatus(self.customCheckBox, u'custom/status') self._set_plugin_status(self.custom_check_box, u'custom/status')
self._setPluginStatus(self.songUsageCheckBox, u'songusage/status') self._set_plugin_status(self.song_usage_check_box, u'songusage/status')
self._setPluginStatus(self.alertCheckBox, u'alerts/status') self._set_plugin_status(self.alert_check_box, u'alerts/status')
if self.web_access: if self.web_access:
# Build directories for downloads # Build directories for downloads
songs_destination = os.path.join( songs_destination = os.path.join(
@ -430,42 +431,42 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
bibles_destination = AppLocation.get_section_data_path(u'bibles') bibles_destination = AppLocation.get_section_data_path(u'bibles')
themes_destination = AppLocation.get_section_data_path(u'themes') themes_destination = AppLocation.get_section_data_path(u'themes')
# Download songs # Download songs
for i in xrange(self.songsListWidget.count()): for i in xrange(self.songs_list_widget.count()):
item = self.songsListWidget.item(i) item = self.songs_list_widget.item(i)
if item.checkState() == QtCore.Qt.Checked: if item.checkState() == QtCore.Qt.Checked:
filename = item.data(QtCore.Qt.UserRole) filename = item.data(QtCore.Qt.UserRole)
self._incrementProgressBar(self.downloading % filename, 0) self._increment_progress_bar(self.downloading % filename, 0)
self.previous_size = 0 self.previous_size = 0
destination = os.path.join(songs_destination, unicode(filename)) destination = os.path.join(songs_destination, unicode(filename))
self.urlGetFile(u'%s%s' % (self.web, filename), destination) self.url_get_file(u'%s%s' % (self.web, filename), destination)
# Download Bibles # Download Bibles
bibles_iterator = QtGui.QTreeWidgetItemIterator( bibles_iterator = QtGui.QTreeWidgetItemIterator(
self.biblesTreeWidget) self.bibles_tree_widget)
while bibles_iterator.value(): while bibles_iterator.value():
item = bibles_iterator.value() item = bibles_iterator.value()
if item.parent() and item.checkState(0) == QtCore.Qt.Checked: if item.parent() and item.checkState(0) == QtCore.Qt.Checked:
bible = item.data(0, QtCore.Qt.UserRole) bible = item.data(0, QtCore.Qt.UserRole)
self._incrementProgressBar(self.downloading % bible, 0) self._increment_progress_bar(self.downloading % bible, 0)
self.previous_size = 0 self.previous_size = 0
self.urlGetFile(u'%s%s' % (self.web, bible), os.path.join(bibles_destination, bible)) self.url_get_file(u'%s%s' % (self.web, bible), os.path.join(bibles_destination, bible))
bibles_iterator += 1 bibles_iterator += 1
# Download themes # Download themes
for i in xrange(self.themesListWidget.count()): for i in xrange(self.themes_list_widget.count()):
item = self.themesListWidget.item(i) item = self.themes_list_widget.item(i)
if item.checkState() == QtCore.Qt.Checked: if item.checkState() == QtCore.Qt.Checked:
theme = item.data(QtCore.Qt.UserRole) theme = item.data(QtCore.Qt.UserRole)
self._incrementProgressBar(self.downloading % theme, 0) self._increment_progress_bar(self.downloading % theme, 0)
self.previous_size = 0 self.previous_size = 0
self.urlGetFile(u'%s%s' % (self.web, theme), os.path.join(themes_destination, theme)) self.url_get_file(u'%s%s' % (self.web, theme), os.path.join(themes_destination, theme))
# Set Default Display # Set Default Display
if self.displayComboBox.currentIndex() != -1: if self.display_combo_box.currentIndex() != -1:
Settings().setValue(u'core/monitor', self.displayComboBox.currentIndex()) Settings().setValue(u'core/monitor', self.display_combo_box.currentIndex())
self.screens.set_current_display(self.displayComboBox.currentIndex()) self.screens.set_current_display(self.display_combo_box.currentIndex())
# Set Global Theme # Set Global Theme
if self.themeComboBox.currentIndex() != -1: if self.theme_combo_box.currentIndex() != -1:
Settings().setValue(u'themes/global theme', self.themeComboBox.currentText()) Settings().setValue(u'themes/global theme', self.theme_combo_box.currentText())
def _setPluginStatus(self, field, tag): def _set_plugin_status(self, field, tag):
""" """
Set the status of a plugin. Set the status of a plugin.
""" """
@ -484,10 +485,14 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -55,200 +55,199 @@ class Ui_FirstTimeWizard(object):
""" """
The UI widgets for the first time wizard. The UI widgets for the first time wizard.
""" """
def setupUi(self, FirstTimeWizard): def setupUi(self, first_time_wizard):
""" """
Set up the UI. Set up the UI.
""" """
FirstTimeWizard.setObjectName(u'FirstTimeWizard') first_time_wizard.setObjectName(u'first_time_wizard')
FirstTimeWizard.resize(550, 386) first_time_wizard.resize(550, 386)
FirstTimeWizard.setModal(True) first_time_wizard.setModal(True)
FirstTimeWizard.setWizardStyle(QtGui.QWizard.ModernStyle) first_time_wizard.setWizardStyle(QtGui.QWizard.ModernStyle)
FirstTimeWizard.setOptions(QtGui.QWizard.IndependentPages | QtGui.QWizard.NoBackButtonOnStartPage | first_time_wizard.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.finish_button = self.button(QtGui.QWizard.FinishButton)
self.noInternetFinishButton = self.button(QtGui.QWizard.CustomButton1) self.no_internet_finish_button = self.button(QtGui.QWizard.CustomButton1)
self.cancelButton = self.button(QtGui.QWizard.CancelButton) self.cancel_button = self.button(QtGui.QWizard.CancelButton)
self.nextButton = self.button(QtGui.QWizard.NextButton) self.next_button = self.button(QtGui.QWizard.NextButton)
self.backButton = self.button(QtGui.QWizard.BackButton) self.back_button = self.button(QtGui.QWizard.BackButton)
add_welcome_page(FirstTimeWizard, u':/wizards/wizard_firsttime.bmp') add_welcome_page(first_time_wizard, u':/wizards/wizard_firsttime.bmp')
# The plugins page # The plugins page
self.pluginPage = QtGui.QWizardPage() self.plugin_page = QtGui.QWizardPage()
self.pluginPage.setObjectName(u'pluginPage') self.plugin_page.setObjectName(u'plugin_page')
self.pluginLayout = QtGui.QVBoxLayout(self.pluginPage) self.plugin_layout = QtGui.QVBoxLayout(self.plugin_page)
self.pluginLayout.setContentsMargins(40, 15, 40, 0) self.plugin_layout.setContentsMargins(40, 15, 40, 0)
self.pluginLayout.setObjectName(u'pluginLayout') self.plugin_layout.setObjectName(u'plugin_layout')
self.songsCheckBox = QtGui.QCheckBox(self.pluginPage) self.songs_check_box = QtGui.QCheckBox(self.plugin_page)
self.songsCheckBox.setChecked(True) self.songs_check_box.setChecked(True)
self.songsCheckBox.setObjectName(u'songsCheckBox') self.songs_check_box.setObjectName(u'songs_check_box')
self.pluginLayout.addWidget(self.songsCheckBox) self.plugin_layout.addWidget(self.songs_check_box)
self.customCheckBox = QtGui.QCheckBox(self.pluginPage) self.custom_check_box = QtGui.QCheckBox(self.plugin_page)
self.customCheckBox.setChecked(True) self.custom_check_box.setChecked(True)
self.customCheckBox.setObjectName(u'customCheckBox') self.custom_check_box.setObjectName(u'custom_check_box')
self.pluginLayout.addWidget(self.customCheckBox) self.plugin_layout.addWidget(self.custom_check_box)
self.bibleCheckBox = QtGui.QCheckBox(self.pluginPage) self.bible_check_box = QtGui.QCheckBox(self.plugin_page)
self.bibleCheckBox.setChecked(True) self.bible_check_box.setChecked(True)
self.bibleCheckBox.setObjectName(u'bibleCheckBox') self.bible_check_box.setObjectName(u'bible_check_box')
self.pluginLayout.addWidget(self.bibleCheckBox) self.plugin_layout.addWidget(self.bible_check_box)
self.imageCheckBox = QtGui.QCheckBox(self.pluginPage) self.image_check_box = QtGui.QCheckBox(self.plugin_page)
self.imageCheckBox.setChecked(True) self.image_check_box.setChecked(True)
self.imageCheckBox.setObjectName(u'imageCheckBox') self.image_check_box.setObjectName(u'image_check_box')
self.pluginLayout.addWidget(self.imageCheckBox) self.plugin_layout.addWidget(self.image_check_box)
# TODO Presentation plugin is not yet working on Mac OS X. # TODO Presentation plugin is not yet working on Mac OS X.
# For now just ignore it. # For now just ignore it.
if sys.platform != 'darwin': if sys.platform != 'darwin':
self.presentationCheckBox = QtGui.QCheckBox(self.pluginPage) self.presentation_check_box = QtGui.QCheckBox(self.plugin_page)
self.presentationCheckBox.setChecked(True) self.presentation_check_box.setChecked(True)
self.presentationCheckBox.setObjectName(u'presentationCheckBox') self.presentation_check_box.setObjectName(u'presentation_check_box')
self.pluginLayout.addWidget(self.presentationCheckBox) self.plugin_layout.addWidget(self.presentation_check_box)
self.mediaCheckBox = QtGui.QCheckBox(self.pluginPage) self.media_check_box = QtGui.QCheckBox(self.plugin_page)
self.mediaCheckBox.setChecked(True) self.media_check_box.setChecked(True)
self.mediaCheckBox.setObjectName(u'mediaCheckBox') self.media_check_box.setObjectName(u'media_check_box')
self.pluginLayout.addWidget(self.mediaCheckBox) self.plugin_layout.addWidget(self.media_check_box)
self.remoteCheckBox = QtGui.QCheckBox(self.pluginPage) self.remote_check_box = QtGui.QCheckBox(self.plugin_page)
self.remoteCheckBox.setObjectName(u'remoteCheckBox') self.remote_check_box.setObjectName(u'remote_check_box')
self.pluginLayout.addWidget(self.remoteCheckBox) self.plugin_layout.addWidget(self.remote_check_box)
self.songUsageCheckBox = QtGui.QCheckBox(self.pluginPage) self.song_usage_check_box = QtGui.QCheckBox(self.plugin_page)
self.songUsageCheckBox.setChecked(True) self.song_usage_check_box.setChecked(True)
self.songUsageCheckBox.setObjectName(u'songUsageCheckBox') self.song_usage_check_box.setObjectName(u'song_usage_check_box')
self.pluginLayout.addWidget(self.songUsageCheckBox) self.plugin_layout.addWidget(self.song_usage_check_box)
self.alertCheckBox = QtGui.QCheckBox(self.pluginPage) self.alert_check_box = QtGui.QCheckBox(self.plugin_page)
self.alertCheckBox.setChecked(True) self.alert_check_box.setChecked(True)
self.alertCheckBox.setObjectName(u'alertCheckBox') self.alert_check_box.setObjectName(u'alert_check_box')
self.pluginLayout.addWidget(self.alertCheckBox) self.plugin_layout.addWidget(self.alert_check_box)
FirstTimeWizard.setPage(FirstTimePage.Plugins, self.pluginPage) first_time_wizard.setPage(FirstTimePage.Plugins, self.plugin_page)
# The "you don't have an internet connection" page. # The "you don't have an internet connection" page.
self.noInternetPage = QtGui.QWizardPage() self.no_internet_page = QtGui.QWizardPage()
self.noInternetPage.setObjectName(u'noInternetPage') self.no_internet_page.setObjectName(u'no_internet_page')
self.noInternetLayout = QtGui.QVBoxLayout(self.noInternetPage) self.no_internet_layout = QtGui.QVBoxLayout(self.no_internet_page)
self.noInternetLayout.setContentsMargins(50, 30, 50, 40) self.no_internet_layout.setContentsMargins(50, 30, 50, 40)
self.noInternetLayout.setObjectName(u'noInternetLayout') self.no_internet_layout.setObjectName(u'no_internet_layout')
self.noInternetLabel = QtGui.QLabel(self.noInternetPage) self.no_internet_label = QtGui.QLabel(self.no_internet_page)
self.noInternetLabel.setWordWrap(True) self.no_internet_label.setWordWrap(True)
self.noInternetLabel.setObjectName(u'noInternetLabel') self.no_internet_label.setObjectName(u'no_internet_label')
self.noInternetLayout.addWidget(self.noInternetLabel) self.no_internet_layout.addWidget(self.no_internet_label)
FirstTimeWizard.setPage(FirstTimePage.NoInternet, self.noInternetPage) first_time_wizard.setPage(FirstTimePage.NoInternet, self.no_internet_page)
# The song samples page # The song samples page
self.songsPage = QtGui.QWizardPage() self.songs_page = QtGui.QWizardPage()
self.songsPage.setObjectName(u'songsPage') self.songs_page.setObjectName(u'songs_page')
self.songsLayout = QtGui.QVBoxLayout(self.songsPage) self.songs_layout = QtGui.QVBoxLayout(self.songs_page)
self.songsLayout.setContentsMargins(50, 20, 50, 20) self.songs_layout.setContentsMargins(50, 20, 50, 20)
self.songsLayout.setObjectName(u'songsLayout') self.songs_layout.setObjectName(u'songs_layout')
self.songsListWidget = QtGui.QListWidget(self.songsPage) self.songs_list_widget = QtGui.QListWidget(self.songs_page)
self.songsListWidget.setAlternatingRowColors(True) self.songs_list_widget.setAlternatingRowColors(True)
self.songsListWidget.setObjectName(u'songsListWidget') self.songs_list_widget.setObjectName(u'songs_list_widget')
self.songsLayout.addWidget(self.songsListWidget) self.songs_layout.addWidget(self.songs_list_widget)
FirstTimeWizard.setPage(FirstTimePage.Songs, self.songsPage) first_time_wizard.setPage(FirstTimePage.Songs, self.songs_page)
# The Bible samples page # The Bible samples page
self.biblesPage = QtGui.QWizardPage() self.bibles_page = QtGui.QWizardPage()
self.biblesPage.setObjectName(u'biblesPage') self.bibles_page.setObjectName(u'bibles_page')
self.biblesLayout = QtGui.QVBoxLayout(self.biblesPage) self.bibles_layout = QtGui.QVBoxLayout(self.bibles_page)
self.biblesLayout.setContentsMargins(50, 20, 50, 20) self.bibles_layout.setContentsMargins(50, 20, 50, 20)
self.biblesLayout.setObjectName(u'biblesLayout') self.bibles_layout.setObjectName(u'bibles_layout')
self.biblesTreeWidget = QtGui.QTreeWidget(self.biblesPage) self.bibles_tree_widget = QtGui.QTreeWidget(self.bibles_page)
self.biblesTreeWidget.setAlternatingRowColors(True) self.bibles_tree_widget.setAlternatingRowColors(True)
self.biblesTreeWidget.header().setVisible(False) self.bibles_tree_widget.header().setVisible(False)
self.biblesTreeWidget.setObjectName(u'biblesTreeWidget') self.bibles_tree_widget.setObjectName(u'bibles_tree_widget')
self.biblesLayout.addWidget(self.biblesTreeWidget) self.bibles_layout.addWidget(self.bibles_tree_widget)
FirstTimeWizard.setPage(FirstTimePage.Bibles, self.biblesPage) first_time_wizard.setPage(FirstTimePage.Bibles, self.bibles_page)
# The theme samples page # The theme samples page
self.themesPage = QtGui.QWizardPage() self.themes_page = QtGui.QWizardPage()
self.themesPage.setObjectName(u'themesPage') self.themes_page.setObjectName(u'themes_page')
self.themesLayout = QtGui.QVBoxLayout(self.themesPage) self.themes_layout = QtGui.QVBoxLayout(self.themes_page)
self.themesLayout.setContentsMargins(20, 50, 20, 60) self.themes_layout.setContentsMargins(20, 50, 20, 60)
self.themesLayout.setObjectName(u'themesLayout') self.themes_layout.setObjectName(u'themes_layout')
self.themesListWidget = QtGui.QListWidget(self.themesPage) self.themes_list_widget = QtGui.QListWidget(self.themes_page)
self.themesListWidget.setViewMode(QtGui.QListView.IconMode) self.themes_list_widget.setViewMode(QtGui.QListView.IconMode)
self.themesListWidget.setMovement(QtGui.QListView.Static) self.themes_list_widget.setMovement(QtGui.QListView.Static)
self.themesListWidget.setFlow(QtGui.QListView.LeftToRight) self.themes_list_widget.setFlow(QtGui.QListView.LeftToRight)
self.themesListWidget.setSpacing(4) self.themes_list_widget.setSpacing(4)
self.themesListWidget.setUniformItemSizes(True) self.themes_list_widget.setUniformItemSizes(True)
self.themesListWidget.setIconSize(QtCore.QSize(133, 100)) self.themes_list_widget.setIconSize(QtCore.QSize(133, 100))
self.themesListWidget.setWrapping(False) self.themes_list_widget.setWrapping(False)
self.themesListWidget.setObjectName(u'themesListWidget') self.themes_list_widget.setObjectName(u'themes_list_widget')
self.themesLayout.addWidget(self.themesListWidget) self.themes_layout.addWidget(self.themes_list_widget)
FirstTimeWizard.setPage(FirstTimePage.Themes, self.themesPage) first_time_wizard.setPage(FirstTimePage.Themes, self.themes_page)
# the default settings page # the default settings page
self.defaultsPage = QtGui.QWizardPage() self.defaults_page = QtGui.QWizardPage()
self.defaultsPage.setObjectName(u'defaultsPage') self.defaults_page.setObjectName(u'defaults_page')
self.defaultsLayout = QtGui.QFormLayout(self.defaultsPage) self.defaults_layout = QtGui.QFormLayout(self.defaults_page)
self.defaultsLayout.setContentsMargins(50, 20, 50, 20) self.defaults_layout.setContentsMargins(50, 20, 50, 20)
self.defaultsLayout.setObjectName(u'defaultsLayout') self.defaults_layout.setObjectName(u'defaults_layout')
self.displayLabel = QtGui.QLabel(self.defaultsPage) self.display_label = QtGui.QLabel(self.defaults_page)
self.displayLabel.setObjectName(u'displayLabel') self.display_label.setObjectName(u'display_label')
self.displayComboBox = QtGui.QComboBox(self.defaultsPage) self.display_combo_box = QtGui.QComboBox(self.defaults_page)
self.displayComboBox.setEditable(False) self.display_combo_box.setEditable(False)
self.displayComboBox.setInsertPolicy(QtGui.QComboBox.NoInsert) self.display_combo_box.setInsertPolicy(QtGui.QComboBox.NoInsert)
self.displayComboBox.setObjectName(u'displayComboBox') self.display_combo_box.setObjectName(u'display_combo_box')
self.defaultsLayout.addRow(self.displayLabel, self.displayComboBox) self.defaults_layout.addRow(self.display_label, self.display_combo_box)
self.themeLabel = QtGui.QLabel(self.defaultsPage) self.theme_label = QtGui.QLabel(self.defaults_page)
self.themeLabel.setObjectName(u'themeLabel') self.theme_label.setObjectName(u'theme_label')
self.themeComboBox = QtGui.QComboBox(self.defaultsPage) self.theme_combo_box = QtGui.QComboBox(self.defaults_page)
self.themeComboBox.setEditable(False) self.theme_combo_box.setEditable(False)
self.themeComboBox.setInsertPolicy(QtGui.QComboBox.NoInsert) self.theme_combo_box.setInsertPolicy(QtGui.QComboBox.NoInsert)
self.themeComboBox.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents) self.theme_combo_box.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
self.themeComboBox.setObjectName(u'themeComboBox') self.theme_combo_box.setObjectName(u'theme_combo_box')
self.defaultsLayout.addRow(self.themeLabel, self.themeComboBox) self.defaults_layout.addRow(self.theme_label, self.theme_combo_box)
FirstTimeWizard.setPage(FirstTimePage.Defaults, self.defaultsPage) first_time_wizard.setPage(FirstTimePage.Defaults, self.defaults_page)
# Progress page # Progress page
self.progressPage = QtGui.QWizardPage() self.progress_page = QtGui.QWizardPage()
self.progressPage.setObjectName(u'progressPage') self.progress_page.setObjectName(u'progress_page')
self.progressLayout = QtGui.QVBoxLayout(self.progressPage) self.progress_layout = QtGui.QVBoxLayout(self.progress_page)
self.progressLayout.setMargin(48) self.progress_layout.setMargin(48)
self.progressLayout.setObjectName(u'progressLayout') self.progress_layout.setObjectName(u'progress_layout')
self.progressLabel = QtGui.QLabel(self.progressPage) self.progress_label = QtGui.QLabel(self.progress_page)
self.progressLabel.setObjectName(u'progressLabel') self.progress_label.setObjectName(u'progress_label')
self.progressLayout.addWidget(self.progressLabel) self.progress_layout.addWidget(self.progress_label)
self.progressBar = QtGui.QProgressBar(self.progressPage) self.progress_bar = QtGui.QProgressBar(self.progress_page)
self.progressBar.setObjectName(u'progressBar') self.progress_bar.setObjectName(u'progress_bar')
self.progressLayout.addWidget(self.progressBar) self.progress_layout.addWidget(self.progress_bar)
FirstTimeWizard.setPage(FirstTimePage.Progress, self.progressPage) first_time_wizard.setPage(FirstTimePage.Progress, self.progress_page)
self.retranslateUi(FirstTimeWizard) self.retranslateUi(first_time_wizard)
def retranslateUi(self, FirstTimeWizard): def retranslateUi(self, first_time_wizard):
""" """
Translate the UI on the fly Translate the UI on the fly
""" """
FirstTimeWizard.setWindowTitle(translate('OpenLP.FirstTimeWizard', 'First Time Wizard')) first_time_wizard.setWindowTitle(translate('OpenLP.FirstTimeWizard', 'First Time Wizard'))
self.title_label.setText(u'<span style="font-size:14pt; font-weight:600;">%s</span>' % self.title_label.setText(u'<span style="font-size:14pt; font-weight:600;">%s</span>' %
translate('OpenLP.FirstTimeWizard', 'Welcome to the First Time Wizard')) translate('OpenLP.FirstTimeWizard', 'Welcome to the First Time Wizard'))
self.information_label.setText(translate('OpenLP.FirstTimeWizard', self.information_label.setText(translate('OpenLP.FirstTimeWizard',
'This wizard will help you to configure OpenLP for initial use. Click the next button below to start.')) '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.plugin_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Activate required Plugins'))
self.pluginPage.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Select the Plugins you wish to use. ')) self.plugin_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Select the Plugins you wish to use. '))
self.songsCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Songs')) self.songs_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Songs'))
self.customCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Custom Slides')) self.custom_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Custom Slides'))
self.bibleCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Bible')) self.bible_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Bible'))
self.imageCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Images')) self.image_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Images'))
# TODO Presentation plugin is not yet working on Mac OS X. # TODO Presentation plugin is not yet working on Mac OS X.
# For now just ignore it. # For now just ignore it.
if sys.platform != 'darwin': if sys.platform != 'darwin':
self.presentationCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Presentations')) self.presentation_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Presentations'))
self.mediaCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Media (Audio and Video)')) self.media_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Media (Audio and Video)'))
self.remoteCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Allow remote access')) self.remote_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Allow remote access'))
self.songUsageCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Monitor Song Usage')) self.song_usage_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Monitor Song Usage'))
self.alertCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Allow Alerts')) self.alert_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Allow Alerts'))
self.noInternetPage.setTitle(translate('OpenLP.FirstTimeWizard', 'No Internet Connection')) self.no_internet_page.setTitle(translate('OpenLP.FirstTimeWizard', 'No Internet Connection'))
self.noInternetPage.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Unable to detect an Internet connection.')) self.no_internet_page.setSubTitle(
self.noInternetText = translate('OpenLP.FirstTimeWizard', translate('OpenLP.FirstTimeWizard', 'Unable to detect an Internet connection.'))
'No Internet connection was found. The First Time Wizard needs an ' self.no_internet_text = translate('OpenLP.FirstTimeWizard',
'Internet connection in order to be able to download sample ' 'No Internet connection was found. The First Time Wizard needs an Internet connection in order to be able '
'songs, Bibles and themes. Click the Finish button now to start ' 'to download sample songs, Bibles and themes. Click the Finish button now to start OpenLP with initial '
'OpenLP with initial settings and no sample data.\n\nTo re-run the ' 'settings and no sample data.\n\nTo re-run the First Time Wizard and import this sample data at a later '
'First Time Wizard and import this sample data at a later time, ' 'time, check your Internet connection and re-run this wizard by selecting "Tools/Re-run First Time Wizard" '
'check your Internet connection and re-run this wizard by ' 'from OpenLP.')
'selecting "Tools/Re-run First Time Wizard" from OpenLP.')
self.cancelWizardText = translate('OpenLP.FirstTimeWizard', self.cancelWizardText = translate('OpenLP.FirstTimeWizard',
'\n\nTo cancel the First Time Wizard completely (and not start OpenLP), click the Cancel button now.') '\n\nTo cancel the First Time Wizard completely (and not start OpenLP), click the Cancel button now.')
self.songsPage.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Songs')) self.songs_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Songs'))
self.songsPage.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Select and download public domain songs.')) self.songs_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Select and download public domain songs.'))
self.biblesPage.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Bibles')) self.bibles_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Bibles'))
self.biblesPage.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Select and download free Bibles.')) self.bibles_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Select and download free Bibles.'))
self.themesPage.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Themes')) self.themes_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Themes'))
self.themesPage.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Select and download sample themes.')) self.themes_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Select and download sample themes.'))
self.defaultsPage.setTitle(translate('OpenLP.FirstTimeWizard', 'Default Settings')) self.defaults_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Default Settings'))
self.defaultsPage.setSubTitle(translate('OpenLP.FirstTimeWizard', self.defaults_page.setSubTitle(translate('OpenLP.FirstTimeWizard',
'Set up default settings to be used by OpenLP.')) 'Set up default settings to be used by OpenLP.'))
self.displayLabel.setText(translate('OpenLP.FirstTimeWizard', 'Default output display:')) self.display_label.setText(translate('OpenLP.FirstTimeWizard', 'Default output display:'))
self.themeLabel.setText(translate('OpenLP.FirstTimeWizard', 'Select default theme:')) self.theme_label.setText(translate('OpenLP.FirstTimeWizard', 'Select default theme:'))
self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', 'Starting configuration process...')) self.progress_label.setText(translate('OpenLP.FirstTimeWizard', 'Starting configuration process...'))
FirstTimeWizard.setButtonText(QtGui.QWizard.CustomButton1, translate('OpenLP.FirstTimeWizard', 'Finish')) first_time_wizard.setButtonText(QtGui.QWizard.CustomButton1, translate('OpenLP.FirstTimeWizard', 'Finish'))

View File

@ -38,6 +38,7 @@ Some of the code for this form is based on the examples at:
from __future__ import division from __future__ import division
import cgi import cgi
import logging import logging
import os
import sys import sys
from PyQt4 import QtCore, QtGui, QtWebKit, QtOpenGL from PyQt4 import QtCore, QtGui, QtWebKit, QtOpenGL
@ -327,6 +328,9 @@ class MainDisplay(Display):
self.display_image(self.service_item.bg_image_bytes) self.display_image(self.service_item.bg_image_bytes)
else: else:
self.display_image(None) self.display_image(None)
# Update the preview frame.
if self.is_live:
self.live_controller.update_preview()
# clear the cache # clear the cache
self.override = {} self.override = {}
@ -494,11 +498,15 @@ class MainDisplay(Display):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -100,10 +100,10 @@ class Ui_MainWindow(object):
self.main_contentLayout.setMargin(0) self.main_contentLayout.setMargin(0)
self.main_contentLayout.setObjectName(u'main_contentLayout') self.main_contentLayout.setObjectName(u'main_contentLayout')
main_window.setCentralWidget(self.main_content) main_window.setCentralWidget(self.main_content)
self.controlSplitter = QtGui.QSplitter(self.main_content) self.control_splitter = QtGui.QSplitter(self.main_content)
self.controlSplitter.setOrientation(QtCore.Qt.Horizontal) self.control_splitter.setOrientation(QtCore.Qt.Horizontal)
self.controlSplitter.setObjectName(u'controlSplitter') self.control_splitter.setObjectName(u'control_splitter')
self.main_contentLayout.addWidget(self.controlSplitter) self.main_contentLayout.addWidget(self.control_splitter)
# Create slide controllers # Create slide controllers
self.preview_controller = SlideController(self) self.preview_controller = SlideController(self)
self.live_controller = SlideController(self, True) self.live_controller = SlideController(self, True)
@ -113,9 +113,9 @@ class Ui_MainWindow(object):
panel_locked = Settings().value(u'user interface/lock panel') panel_locked = Settings().value(u'user interface/lock panel')
self.live_controller.panel.setVisible(live_visible) self.live_controller.panel.setVisible(live_visible)
# Create menu # Create menu
self.menuBar = QtGui.QMenuBar(main_window) self.menu_bar = QtGui.QMenuBar(main_window)
self.menuBar.setObjectName(u'menuBar') self.menu_bar.setObjectName(u'menu_bar')
self.file_menu = QtGui.QMenu(self.menuBar) self.file_menu = QtGui.QMenu(self.menu_bar)
self.file_menu.setObjectName(u'fileMenu') self.file_menu.setObjectName(u'fileMenu')
self.recent_files_menu = QtGui.QMenu(self.file_menu) self.recent_files_menu = QtGui.QMenu(self.file_menu)
self.recent_files_menu.setObjectName(u'recentFilesMenu') self.recent_files_menu.setObjectName(u'recentFilesMenu')
@ -124,22 +124,22 @@ class Ui_MainWindow(object):
self.file_export_menu = QtGui.QMenu(self.file_menu) self.file_export_menu = QtGui.QMenu(self.file_menu)
self.file_export_menu.setObjectName(u'file_export_menu') self.file_export_menu.setObjectName(u'file_export_menu')
# View Menu # View Menu
self.view_menu = QtGui.QMenu(self.menuBar) self.view_menu = QtGui.QMenu(self.menu_bar)
self.view_menu.setObjectName(u'viewMenu') self.view_menu.setObjectName(u'viewMenu')
self.view_modeMenu = QtGui.QMenu(self.view_menu) self.view_modeMenu = QtGui.QMenu(self.view_menu)
self.view_modeMenu.setObjectName(u'viewModeMenu') self.view_modeMenu.setObjectName(u'viewModeMenu')
# Tools Menu # Tools Menu
self.tools_menu = QtGui.QMenu(self.menuBar) self.tools_menu = QtGui.QMenu(self.menu_bar)
self.tools_menu.setObjectName(u'tools_menu') self.tools_menu.setObjectName(u'tools_menu')
# Settings Menu # Settings Menu
self.settings_menu = QtGui.QMenu(self.menuBar) self.settings_menu = QtGui.QMenu(self.menu_bar)
self.settings_menu.setObjectName(u'settingsMenu') self.settings_menu.setObjectName(u'settingsMenu')
self.settings_language_menu = QtGui.QMenu(self.settings_menu) self.settings_language_menu = QtGui.QMenu(self.settings_menu)
self.settings_language_menu.setObjectName(u'settingsLanguageMenu') self.settings_language_menu.setObjectName(u'settingsLanguageMenu')
# Help Menu # Help Menu
self.help_menu = QtGui.QMenu(self.menuBar) self.help_menu = QtGui.QMenu(self.menu_bar)
self.help_menu.setObjectName(u'helpMenu') self.help_menu.setObjectName(u'helpMenu')
main_window.setMenuBar(self.menuBar) main_window.setMenuBar(self.menu_bar)
self.status_bar = QtGui.QStatusBar(main_window) self.status_bar = QtGui.QStatusBar(main_window)
self.status_bar.setObjectName(u'status_bar') self.status_bar.setObjectName(u'status_bar')
main_window.setStatusBar(self.status_bar) main_window.setStatusBar(self.status_bar)
@ -237,7 +237,7 @@ class Ui_MainWindow(object):
self.view_live_panel = create_action(main_window, u'viewLivePanel', self.view_live_panel = create_action(main_window, u'viewLivePanel',
can_shortcuts=True, checked=live_visible, can_shortcuts=True, checked=live_visible,
category=UiStrings().View, triggers=self.set_live_panel_visibility) category=UiStrings().View, triggers=self.set_live_panel_visibility)
self.lockPanel = create_action(main_window, u'lockPanel', self.lock_panel = create_action(main_window, u'lockPanel',
can_shortcuts=True, checked=panel_locked, can_shortcuts=True, checked=panel_locked,
category=UiStrings().View, category=UiStrings().View,
triggers=self.set_lock_panel) triggers=self.set_lock_panel)
@ -310,6 +310,10 @@ class Ui_MainWindow(object):
can_shortcuts=True, can_shortcuts=True,
category=UiStrings().Help, triggers=self.on_online_help_clicked) category=UiStrings().Help, triggers=self.on_online_help_clicked)
self.web_site_item = create_action(main_window, u'webSiteItem', can_shortcuts=True, category=UiStrings().Help) self.web_site_item = create_action(main_window, u'webSiteItem', can_shortcuts=True, category=UiStrings().Help)
# Shortcuts not connected to buttons or menu entires.
self.search_shortcut_action = create_action(main_window,
u'searchShortcut', can_shortcuts=True, category=translate('OpenLP.MainWindow', 'General'),
triggers=self.on_search_shortcut_triggered)
add_actions(self.file_import_menu, (self.settings_import_item, None, self.import_theme_item, add_actions(self.file_import_menu, (self.settings_import_item, None, self.import_theme_item,
self.import_language_item)) self.import_language_item))
add_actions(self.file_export_menu, (self.settings_export_item, None, self.export_theme_item, add_actions(self.file_export_menu, (self.settings_export_item, None, self.export_theme_item,
@ -321,7 +325,7 @@ class Ui_MainWindow(object):
add_actions(self.view_modeMenu, (self.mode_default_Item, self.mode_setup_item, self.mode_live_item)) add_actions(self.view_modeMenu, (self.mode_default_Item, self.mode_setup_item, self.mode_live_item))
add_actions(self.view_menu, (self.view_modeMenu.menuAction(), None, self.view_media_manager_item, add_actions(self.view_menu, (self.view_modeMenu.menuAction(), None, self.view_media_manager_item,
self.view_service_manager_item, self.view_theme_manager_item, None, self.view_preview_panel, self.view_service_manager_item, self.view_theme_manager_item, None, self.view_preview_panel,
self.view_live_panel, None, self.lockPanel)) self.view_live_panel, None, self.lock_panel))
# i18n add Language Actions # i18n add Language Actions
add_actions(self.settings_language_menu, (self.auto_language_item, None)) add_actions(self.settings_language_menu, (self.auto_language_item, None))
add_actions(self.settings_language_menu, self.language_group.actions()) add_actions(self.settings_language_menu, self.language_group.actions())
@ -342,8 +346,9 @@ class Ui_MainWindow(object):
self.about_item)) self.about_item))
else: else:
add_actions(self.help_menu, (self.on_line_help_item, None, self.web_site_item, self.about_item)) add_actions(self.help_menu, (self.on_line_help_item, None, self.web_site_item, self.about_item))
add_actions(self.menuBar, (self.file_menu.menuAction(), self.view_menu.menuAction(), add_actions(self.menu_bar, (self.file_menu.menuAction(), self.view_menu.menuAction(),
self.tools_menu.menuAction(), self.settings_menu.menuAction(), self.help_menu.menuAction())) self.tools_menu.menuAction(), self.settings_menu.menuAction(), self.help_menu.menuAction()))
add_actions(self, [self.search_shortcut_action])
# Initialise the translation # Initialise the translation
self.retranslateUi(main_window) self.retranslateUi(main_window)
self.media_tool_box.setCurrentIndex(0) self.media_tool_box.setCurrentIndex(0)
@ -356,12 +361,11 @@ class Ui_MainWindow(object):
self.set_lock_panel(panel_locked) self.set_lock_panel(panel_locked)
self.settingsImported = False self.settingsImported = False
def retranslateUi(self, mainWindow): def retranslateUi(self, main_window):
""" """
Set up the translation system Set up the translation system
""" """
mainWindow.mainTitle = UiStrings().OLPV2x main_window.setWindowTitle(UiStrings().OLPV2x)
mainWindow.setWindowTitle(mainWindow.mainTitle)
self.file_menu.setTitle(translate('OpenLP.MainWindow', '&File')) self.file_menu.setTitle(translate('OpenLP.MainWindow', '&File'))
self.file_import_menu.setTitle(translate('OpenLP.MainWindow', '&Import')) self.file_import_menu.setTitle(translate('OpenLP.MainWindow', '&Import'))
self.file_export_menu.setTitle(translate('OpenLP.MainWindow', '&Export')) self.file_export_menu.setTitle(translate('OpenLP.MainWindow', '&Export'))
@ -423,8 +427,8 @@ class Ui_MainWindow(object):
translate('OpenLP.MainWindow', 'Toggle the visibility of the preview panel.')) translate('OpenLP.MainWindow', 'Toggle the visibility of the preview panel.'))
self.view_live_panel.setText(translate('OpenLP.MainWindow', '&Live Panel')) self.view_live_panel.setText(translate('OpenLP.MainWindow', '&Live Panel'))
self.view_live_panel.setToolTip(translate('OpenLP.MainWindow', 'Toggle Live Panel')) self.view_live_panel.setToolTip(translate('OpenLP.MainWindow', 'Toggle Live Panel'))
self.lockPanel.setText(translate('OpenLP.MainWindow', 'L&ock Panels')) self.lock_panel.setText(translate('OpenLP.MainWindow', 'L&ock Panels'))
self.lockPanel.setStatusTip(translate('OpenLP.MainWindow', 'Prevent the panels being moved.')) self.lock_panel.setStatusTip(translate('OpenLP.MainWindow', 'Prevent the panels being moved.'))
self.view_live_panel.setStatusTip(translate('OpenLP.MainWindow', 'Toggle the visibility of the live panel.')) self.view_live_panel.setStatusTip(translate('OpenLP.MainWindow', 'Toggle the visibility of the live panel.'))
self.settingsPluginListItem.setText(translate('OpenLP.MainWindow', '&Plugin List')) self.settingsPluginListItem.setText(translate('OpenLP.MainWindow', '&Plugin List'))
self.settingsPluginListItem.setStatusTip(translate('OpenLP.MainWindow', 'List the Plugins')) self.settingsPluginListItem.setStatusTip(translate('OpenLP.MainWindow', 'List the Plugins'))
@ -433,6 +437,9 @@ class Ui_MainWindow(object):
if os.name == u'nt': if os.name == u'nt':
self.offlineHelpItem.setText(translate('OpenLP.MainWindow', '&User Guide')) self.offlineHelpItem.setText(translate('OpenLP.MainWindow', '&User Guide'))
self.on_line_help_item.setText(translate('OpenLP.MainWindow', '&Online Help')) self.on_line_help_item.setText(translate('OpenLP.MainWindow', '&Online Help'))
self.search_shortcut_action.setText(UiStrings().Search)
self.search_shortcut_action.setToolTip(
translate('OpenLP.MainWindow', 'Jump to the search box of the current active plugin.'))
self.web_site_item.setText(translate('OpenLP.MainWindow', '&Web Site')) self.web_site_item.setText(translate('OpenLP.MainWindow', '&Web Site'))
for item in self.language_group.actions(): for item in self.language_group.actions():
item.setText(item.objectName()) item.setText(item.objectName())
@ -467,8 +474,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self): def __init__(self):
""" """
This constructor sets up the interface, the various managers, and the This constructor sets up the interface, the various managers, and the plugins.
plugins.
""" """
QtGui.QMainWindow.__init__(self) QtGui.QMainWindow.__init__(self)
Registry().register(u'main_window', self) Registry().register(u'main_window', self)
@ -491,7 +497,6 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.new_data_path = None self.new_data_path = None
self.copy_data = False self.copy_data = False
Settings().set_up_default_values() Settings().set_up_default_values()
self.service_not_saved = False
self.about_form = AboutForm(self) self.about_form = AboutForm(self)
self.media_controller = MediaController() self.media_controller = MediaController()
self.settings_form = SettingsForm(self) self.settings_form = SettingsForm(self)
@ -536,22 +541,31 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
Registry().register_function(u'theme_update_global', self.default_theme_changed) Registry().register_function(u'theme_update_global', self.default_theme_changed)
Registry().register_function(u'openlp_version_check', self.version_notice) Registry().register_function(u'openlp_version_check', self.version_notice)
Registry().register_function(u'config_screen_changed', self.screen_changed) Registry().register_function(u'config_screen_changed', self.screen_changed)
Registry().register_function(u'bootstrap_post_set_up', self.restore_current_media_manager_item)
self.renderer = Renderer() self.renderer = Renderer()
log.info(u'Load data from Settings')
if Settings().value(u'advanced/save current plugin'):
savedPlugin = Settings().value(u'advanced/current media plugin')
if savedPlugin != -1:
self.media_tool_box.setCurrentIndex(savedPlugin)
# Reset the cursor # Reset the cursor
self.application.set_normal_cursor() self.application.set_normal_cursor()
def setAutoLanguage(self, value): def restore_current_media_manager_item(self):
""" """
Set the language to automatic. Called on start up to restore the last active media plugin.
""" """
self.language_group.setDisabled(value) log.info(u'Load data from Settings')
LanguageManager.auto_language = value if Settings().value(u'advanced/save current plugin'):
LanguageManager.set_language(self.language_group.checkedAction()) saved_plugin_id = Settings().value(u'advanced/current media plugin')
if saved_plugin_id != -1:
self.media_tool_box.setCurrentIndex(saved_plugin_id)
def on_search_shortcut_triggered(self):
"""
Called when the search shotcut has been pressed.
"""
# Make sure the media_dock is visible.
if not self.media_manager_dock.isVisible():
self.media_manager_dock.setVisible(True)
widget = self.media_tool_box.currentWidget()
if widget:
widget.on_focus()
def on_media_tool_box_changed(self, index): def on_media_tool_box_changed(self, index):
""" """
@ -966,8 +980,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
""" """
self.setViewMode(False, True, False, False, True, u'live') self.setViewMode(False, True, False, False, True, u'live')
def setViewMode(self, media=True, service=True, theme=True, preview=True, def setViewMode(self, media=True, service=True, theme=True, preview=True, live=True, mode=u''):
live=True, mode=u''):
""" """
Set OpenLP to a different view mode. Set OpenLP to a different view mode.
""" """
@ -982,8 +995,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
def screen_changed(self): def screen_changed(self):
""" """
The screen has changed so we have to update components such as the The screen has changed so we have to update components such as the renderer.
renderer.
""" """
log.debug(u'screen_changed') log.debug(u'screen_changed')
self.application.set_busy_cursor() self.application.set_busy_cursor()
@ -1064,44 +1076,24 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
if self.live_controller.display: if self.live_controller.display:
self.live_controller.display.close() self.live_controller.display.close()
self.live_controller.display = None self.live_controller.display = None
if os.name == u'nt':
# Needed for Windows to stop crashes on exit
Registry().remove(u'application')
def service_changed(self, reset=False, serviceName=None): def set_service_modified(self, modified, file_name):
""" """
Hook to change the main window title when the service changes This method is called from the ServiceManager to set the title of the main window.
``reset``
Shows if the service has been cleared or saved
``serviceName``
The name of the service (if it has one)
"""
if not serviceName:
service_name = u'(unsaved service)'
else:
service_name = serviceName
if reset:
self.service_not_saved = False
title = u'%s - %s' % (self.mainTitle, service_name)
else:
self.service_not_saved = True
title = u'%s - %s*' % (self.mainTitle, service_name)
self.setWindowTitle(title)
def set_service_modified(self, modified, fileName):
"""
This method is called from the ServiceManager to set the title of the
main window.
``modified`` ``modified``
Whether or not this service has been modified. Whether or not this service has been modified.
``fileName`` ``file_name``
The file name of the service file. The file name of the service file.
""" """
if modified: if modified:
title = u'%s - %s*' % (self.mainTitle, fileName) title = u'%s - %s*' % (UiStrings().OLPV2x, file_name)
else: else:
title = u'%s - %s' % (self.mainTitle, fileName) title = u'%s - %s' % (UiStrings().OLPV2x, file_name)
self.setWindowTitle(title) self.setWindowTitle(title)
def show_status_message(self, message): def show_status_message(self, message):
@ -1137,8 +1129,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
def set_preview_panel_visibility(self, visible): def set_preview_panel_visibility(self, visible):
""" """
Sets the visibility of the preview panel including saving the setting Sets the visibility of the preview panel including saving the setting and updating the menu.
and updating the menu.
``visible`` ``visible``
A bool giving the state to set the panel to A bool giving the state to set the panel to
@ -1175,8 +1166,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
def set_live_panel_visibility(self, visible): def set_live_panel_visibility(self, visible):
""" """
Sets the visibility of the live panel including saving the setting and Sets the visibility of the live panel including saving the setting and updating the menu.
updating the menu.
``visible`` ``visible``
A bool giving the state to set the panel to A bool giving the state to set the panel to
@ -1205,7 +1195,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.restoreState(settings.value(u'main window state')) self.restoreState(settings.value(u'main window state'))
self.live_controller.splitter.restoreState(settings.value(u'live splitter geometry')) self.live_controller.splitter.restoreState(settings.value(u'live splitter geometry'))
self.preview_controller.splitter.restoreState(settings.value(u'preview splitter geometry')) self.preview_controller.splitter.restoreState(settings.value(u'preview splitter geometry'))
self.controlSplitter.restoreState(settings.value(u'main window splitter geometry')) self.control_splitter.restoreState(settings.value(u'main window splitter geometry'))
settings.endGroup() settings.endGroup()
def save_settings(self): def save_settings(self):
@ -1226,13 +1216,12 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
settings.setValue(u'main window geometry', self.saveGeometry()) settings.setValue(u'main window geometry', self.saveGeometry())
settings.setValue(u'live splitter geometry', self.live_controller.splitter.saveState()) settings.setValue(u'live splitter geometry', self.live_controller.splitter.saveState())
settings.setValue(u'preview splitter geometry', self.preview_controller.splitter.saveState()) settings.setValue(u'preview splitter geometry', self.preview_controller.splitter.saveState())
settings.setValue(u'main window splitter geometry', self.controlSplitter.saveState()) settings.setValue(u'main window splitter geometry', self.control_splitter.saveState())
settings.endGroup() settings.endGroup()
def update_recent_files_menu(self): def update_recent_files_menu(self):
""" """
Updates the recent file menu with the latest list of service files Updates the recent file menu with the latest list of service files accessed.
accessed.
""" """
recent_file_count = Settings().value(u'advanced/recent file count') recent_file_count = Settings().value(u'advanced/recent file count')
existing_recent_files = [recentFile for recentFile in self.recent_files existing_recent_files = [recentFile for recentFile in self.recent_files
@ -1374,10 +1363,14 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -29,6 +29,8 @@
""" """
The :mod:`~openlp.core.ui.media.mediaplayer` module contains the MediaPlayer class. The :mod:`~openlp.core.ui.media.mediaplayer` module contains the MediaPlayer class.
""" """
import os
from openlp.core.lib import Registry from openlp.core.lib import Registry
from openlp.core.ui.media import MediaState from openlp.core.ui.media import MediaState
@ -153,10 +155,14 @@ class MediaPlayer(object):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -44,113 +44,57 @@ VIDEO_CSS = u"""
z-index:3; z-index:3;
background-color: %(bgcolor)s; background-color: %(bgcolor)s;
} }
#video1 { #video {
background-color: %(bgcolor)s;
z-index:4;
}
#video2 {
background-color: %(bgcolor)s; background-color: %(bgcolor)s;
z-index:4; z-index:4;
} }
""" """
VIDEO_JS = u""" VIDEO_JS = u"""
var video_timer = null; function show_video(state, path, volume, loop, variable_value){
var current_video = '1'; // Sometimes video.currentTime stops slightly short of video.duration and video.ended is intermittent!
function show_video(state, path, volume, loop, varVal){ var video = document.getElementById('video');
// Note, the preferred method for looping would be to use the
// video tag loop attribute.
// But QtWebKit doesn't support this. Neither does it support the
// onended event, hence the setInterval()
// In addition, setting the currentTime attribute to zero to restart
// the video raises an INDEX_SIZE_ERROR: DOM Exception 1
// To complicate it further, sometimes vid.currentTime stops
// slightly short of vid.duration and vid.ended is intermittent!
//
// Note, currently the background may go black between loops. Not
// desirable. Need to investigate using two <video>'s, and hiding/
// preloading one, and toggle between the two when looping.
if(current_video=='1'){
var vid = document.getElementById('video1');
var vid2 = document.getElementById('video2');
} else {
var vid = document.getElementById('video2');
var vid2 = document.getElementById('video1');
}
if(volume != null){ if(volume != null){
vid.volume = volume; video.volume = volume;
vid2.volume = volume;
} }
switch(state){ switch(state){
case 'init':
vid.src = 'file:///' + path;
vid2.src = 'file:///' + path;
if(loop == null) loop = false;
vid.looping = loop;
vid2.looping = loop;
vid.load();
break;
case 'load': case 'load':
vid2.style.visibility = 'hidden'; video.src = 'file:///' + path;
vid2.load(); if(loop == true) {
video.loop = true;
}
video.load();
break; break;
case 'play': case 'play':
vid.play(); video.play();
if(vid.looping){
video_timer = setInterval(
function() {
show_video('poll');
}, 200);
}
break; break;
case 'pause': case 'pause':
if(video_timer!=null){ video.pause();
clearInterval(video_timer);
video_timer = null;
}
vid.pause();
break; break;
case 'stop': case 'stop':
show_video('pause'); show_video('pause');
vid.currentTime = 0; video.currentTime = 0;
break;
case 'poll':
if(vid.ended||vid.currentTime+0.2>vid.duration)
show_video('swap');
break;
case 'swap':
show_video('pause');
if(current_video=='1')
current_video = '2';
else
current_video = '1';
show_video('load');
show_video('play');
show_video('setVisible',null,null,null,'visible');
break; break;
case 'close': case 'close':
show_video('stop'); show_video('stop');
vid.src = ''; video.src = '';
vid2.src = '';
break; break;
case 'length': case 'length':
return vid.duration; return video.duration;
case 'currentTime': case 'current_time':
return vid.currentTime; return video.currentTime;
case 'seek': case 'seek':
// doesnt work currently video.currentTime = variable_value;
vid.currentTime = varVal;
break; break;
case 'isEnded': case 'isEnded':
return vid.ended; return video.ended;
case 'setVisible': case 'setVisible':
vid.style.visibility = varVal; video.style.visibility = variable_value;
break; break;
case 'setBackBoard': case 'setBackBoard':
var back = document.getElementById('videobackboard'); var back = document.getElementById('videobackboard');
back.style.visibility = varVal; back.style.visibility = variable_value;
break; break;
} }
} }
@ -158,10 +102,7 @@ VIDEO_JS = u"""
VIDEO_HTML = u""" VIDEO_HTML = u"""
<div id="videobackboard" class="size" style="visibility:hidden"></div> <div id="videobackboard" class="size" style="visibility:hidden"></div>
<video id="video1" class="size" style="visibility:hidden" autobuffer preload> <video id="video" class="size" style="visibility:hidden" autobuffer preload></video>
</video>
<video id="video2" class="size" style="visibility:hidden" autobuffer preload>
</video>
""" """
FLASH_CSS = u""" FLASH_CSS = u"""
@ -173,25 +114,21 @@ FLASH_CSS = u"""
FLASH_JS = u""" FLASH_JS = u"""
function getFlashMovieObject(movieName) function getFlashMovieObject(movieName)
{ {
if (window.document[movieName]) if (window.document[movieName]){
{
return window.document[movieName]; return window.document[movieName];
} }
if (document.embeds && document.embeds[movieName]) if (document.embeds && document.embeds[movieName]){
return document.embeds[movieName]; return document.embeds[movieName];
}
} }
function show_flash(state, path, volume, varVal){ function show_flash(state, path, volume, variable_value){
var text = document.getElementById('flash'); var text = document.getElementById('flash');
var flashMovie = getFlashMovieObject("OpenLPFlashMovie"); var flashMovie = getFlashMovieObject("OpenLPFlashMovie");
var src = "src = 'file:///" + path + "'"; var src = "src = 'file:///" + path + "'";
var view_parm = " wmode='opaque'" + var view_parm = " wmode='opaque'" + " width='100%%'" + " height='100%%'";
" width='100%%'" + var swf_parm = " name='OpenLPFlashMovie'" + " autostart='true' loop='false' play='true'" +
" height='100%%'"; " hidden='false' swliveconnect='true' allowscriptaccess='always'" + " volume='" + volume + "'";
var swf_parm = " name='OpenLPFlashMovie'" +
" autostart='true' loop='false' play='true'" +
" hidden='false' swliveconnect='true' allowscriptaccess='always'" +
" volume='" + volume + "'";
switch(state){ switch(state){
case 'load': case 'load':
@ -217,15 +154,16 @@ FLASH_JS = u"""
break; break;
case 'length': case 'length':
return flashMovie.TotalFrames(); return flashMovie.TotalFrames();
case 'currentTime': case 'current_time':
return flashMovie.CurrentFrame(); return flashMovie.CurrentFrame();
case 'seek': case 'seek':
// flashMovie.GotoFrame(varVal); // flashMovie.GotoFrame(variable_value);
break; break;
case 'isEnded': case 'isEnded':
return false;//TODO check flash end //TODO check flash end
return false;
case 'setVisible': case 'setVisible':
text.style.visibility = varVal; text.style.visibility = variable_value;
break; break;
} }
} }
@ -338,7 +276,7 @@ class WebkitPlayer(MediaPlayer):
controller.media_info.is_flash = True controller.media_info.is_flash = True
js = u'show_flash("load","%s");' % (path.replace(u'\\', u'\\\\')) js = u'show_flash("load","%s");' % (path.replace(u'\\', u'\\\\'))
else: else:
js = u'show_video("init", "%s", %s, %s);' % (path.replace(u'\\', u'\\\\'), str(vol), loop) js = u'show_video("load", "%s", %s, %s);' % (path.replace(u'\\', u'\\\\'), str(vol), loop)
display.frame.evaluateJavaScript(js) display.frame.evaluateJavaScript(js)
return True return True
@ -447,25 +385,25 @@ class WebkitPlayer(MediaPlayer):
""" """
controller = display.controller controller = display.controller
if controller.media_info.is_flash: if controller.media_info.is_flash:
currentTime = display.frame.evaluateJavaScript(u'show_flash("currentTime");') current_time = display.frame.evaluateJavaScript(u'show_flash("current_time");')
length = display.frame.evaluateJavaScript(u'show_flash("length");') length = display.frame.evaluateJavaScript(u'show_flash("length");')
else: else:
if display.frame.evaluateJavaScript(u'show_video("isEnded");'): if display.frame.evaluateJavaScript(u'show_video("isEnded");'):
self.stop(display) self.stop(display)
currentTime = display.frame.evaluateJavaScript(u'show_video("currentTime");') current_time = display.frame.evaluateJavaScript(u'show_video("current_time");')
# check if conversion was ok and value is not 'NaN' # check if conversion was ok and value is not 'NaN'
if currentTime and currentTime != float('inf'): if current_time and current_time != float('inf'):
currentTime = int(currentTime * 1000) current_time = int(current_time * 1000)
length = display.frame.evaluateJavaScript(u'show_video("length");') length = display.frame.evaluateJavaScript(u'show_video("length");')
# check if conversion was ok and value is not 'NaN' # check if conversion was ok and value is not 'NaN'
if length and length != float('inf'): if length and length != float('inf'):
length = int(length * 1000) length = int(length * 1000)
if currentTime > 0: if current_time:
controller.media_info.length = length controller.media_info.length = length
controller.seek_slider.setMaximum(length) controller.seek_slider.setMaximum(length)
if not controller.seek_slider.isSliderDown(): if not controller.seek_slider.isSliderDown():
controller.seek_slider.blockSignals(True) controller.seek_slider.blockSignals(True)
controller.seek_slider.setSliderPosition(currentTime) controller.seek_slider.setSliderPosition(current_time)
controller.seek_slider.blockSignals(False) controller.seek_slider.blockSignals(False)
def get_info(self): def get_info(self):

View File

@ -30,6 +30,7 @@
The actual plugin view form The actual plugin view form
""" """
import logging import logging
import os
from PyQt4 import QtGui from PyQt4 import QtGui
@ -166,10 +167,14 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -1588,10 +1588,14 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -129,11 +129,18 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
continue continue
item = QtGui.QTreeWidgetItem([category.name]) item = QtGui.QTreeWidgetItem([category.name])
for action in category.actions: for action in category.actions:
actionText = REMOVE_AMPERSAND.sub('', action.text()) action_text = REMOVE_AMPERSAND.sub('', action.text())
actionItem = QtGui.QTreeWidgetItem([actionText]) action_item = QtGui.QTreeWidgetItem([action_text])
actionItem.setIcon(0, action.icon()) action_item.setIcon(0, action.icon())
actionItem.setData(0, QtCore.Qt.UserRole, action) action_item.setData(0, QtCore.Qt.UserRole, action)
item.addChild(actionItem) tool_tip_text = action.toolTip()
# Only display tool tips if they are helpful.
if tool_tip_text != action_text:
# Display the tool tip in all three colums.
action_item.setToolTip(0, tool_tip_text)
action_item.setToolTip(1, tool_tip_text)
action_item.setToolTip(2, tool_tip_text)
item.addChild(action_item)
self.treeWidget.addTopLevelItem(item) self.treeWidget.addTopLevelItem(item)
item.setExpanded(True) item.setExpanded(True)
self.refreshShortcutList() self.refreshShortcutList()

View File

@ -121,7 +121,7 @@ class SlideController(DisplayController):
self.service_item = None self.service_item = None
self.slide_limits = None self.slide_limits = None
self.update_slide_limits() self.update_slide_limits()
self.panel = QtGui.QWidget(parent.controlSplitter) self.panel = QtGui.QWidget(parent.control_splitter)
self.slideList = {} self.slideList = {}
self.slide_count = 0 self.slide_count = 0
self.slide_image = None self.slide_image = None
@ -566,8 +566,7 @@ class SlideController(DisplayController):
max_width = self.preview_frame.width() - self.grid.margin() * 2 max_width = self.preview_frame.width() - self.grid.margin() * 2
self.slide_preview.setFixedSize(QtCore.QSize(max_width, max_width / self.ratio)) self.slide_preview.setFixedSize(QtCore.QSize(max_width, max_width / self.ratio))
self.preview_display.setFixedSize(QtCore.QSize(max_width, max_width / self.ratio)) self.preview_display.setFixedSize(QtCore.QSize(max_width, max_width / self.ratio))
self.preview_display.screen = { self.preview_display.screen = {u'size': self.preview_display.geometry()}
u'size': self.preview_display.geometry()}
self.on_controller_size_changed(self.controller.width()) self.on_controller_size_changed(self.controller.width())
def on_controller_size_changed(self, width): def on_controller_size_changed(self, width):
@ -592,7 +591,7 @@ class SlideController(DisplayController):
""" """
request = self.sender().text() request = self.sender().text()
slide_no = self.slideList[request] slide_no = self.slideList[request]
width = self.main_window.controlSplitter.sizes()[self.split] width = self.main_window.control_splitter.sizes()[self.split]
self.preview_widget.replace_service_item(self.service_item, width, slide_no) self.preview_widget.replace_service_item(self.service_item, width, slide_no)
self.slide_selected() self.slide_selected()
@ -697,9 +696,8 @@ class SlideController(DisplayController):
def add_service_manager_item(self, item, slide_no): def add_service_manager_item(self, item, slide_no):
""" """
Method to install the service item into the controller and Method to install the service item into the controller and request the correct toolbar for the plugin. Called by
request the correct toolbar for the plugin. :class:`~openlp.core.ui.ServiceManager`
Called by ServiceManager
""" """
log.debug(u'add_service_manager_item live = %s' % self.is_live) log.debug(u'add_service_manager_item live = %s' % self.is_live)
# If no valid slide number is specified we take the first one, but we remember the initial value to see if we # If no valid slide number is specified we take the first one, but we remember the initial value to see if we
@ -724,8 +722,7 @@ class SlideController(DisplayController):
def _process_item(self, service_item, slideno): def _process_item(self, service_item, slideno):
""" """
Loads a ServiceItem into the system from ServiceManager Loads a ServiceItem into the system from ServiceManager. Display the slide number passed.
Display the slide number passed
""" """
log.debug(u'processManagerItem live = %s' % self.is_live) log.debug(u'processManagerItem live = %s' % self.is_live)
self.on_stop_loop() self.on_stop_loop()
@ -734,7 +731,8 @@ class SlideController(DisplayController):
self.service_item = copy.copy(service_item) self.service_item = copy.copy(service_item)
if old_item and self.is_live and old_item.is_capable(ItemCapabilities.ProvidesOwnDisplay): if old_item and self.is_live and old_item.is_capable(ItemCapabilities.ProvidesOwnDisplay):
self._reset_blank() self._reset_blank()
Registry().execute(u'%s_start' % service_item.name.lower(), [service_item, self.is_live, self.hide_mode(), slideno]) Registry().execute(
u'%s_start' % service_item.name.lower(), [service_item, self.is_live, self.hide_mode(), slideno])
self.slideList = {} self.slideList = {}
if self.is_live: if self.is_live:
self.song_menu.menu().clear() self.song_menu.menu().clear()
@ -759,7 +757,7 @@ class SlideController(DisplayController):
self.display.audio_player.play() self.display.audio_player.play()
self.set_audio_items_visibility(True) self.set_audio_items_visibility(True)
row = 0 row = 0
width = self.main_window.controlSplitter.sizes()[self.split] width = self.main_window.control_splitter.sizes()[self.split]
for framenumber, frame in enumerate(self.service_item.get_frames()): for framenumber, frame in enumerate(self.service_item.get_frames()):
if self.service_item.is_text(): if self.service_item.is_text():
if frame[u'verseTag']: if frame[u'verseTag']:

View File

@ -836,10 +836,14 @@ class ThemeManager(QtGui.QWidget):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -320,10 +320,14 @@ class OpenLPWizard(QtGui.QWizard):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -28,6 +28,7 @@
############################################################################### ###############################################################################
import logging import logging
import os
import re import re
from PyQt4 import QtGui from PyQt4 import QtGui
@ -191,10 +192,14 @@ class EditBibleForm(QtGui.QDialog, Ui_EditBibleDialog):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -544,11 +544,15 @@ class BibleDB(QtCore.QObject, Manager):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -29,6 +29,7 @@
""" """
The :mod:`http` module enables OpenLP to retrieve scripture from bible websites. The :mod:`http` module enables OpenLP to retrieve scripture from bible websites.
""" """
import os
import logging import logging
import re import re
import socket import socket
@ -301,11 +302,15 @@ class BGExtract(object):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)
@ -362,8 +367,8 @@ class BSExtract(object):
The version of the Bible like NIV for New International Version The version of the Bible like NIV for New International Version
""" """
log.debug(u'BSExtract.get_books_from_http("%s")', version) log.debug(u'BSExtract.get_books_from_http("%s")', version)
urlversion = urllib.quote(version.encode("utf-8")) url_version = 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' % (url_version)
soup = get_soup_for_bible_ref(chapter_url) soup = get_soup_for_bible_ref(chapter_url)
if not soup: if not soup:
return None return None
@ -377,11 +382,15 @@ class BSExtract(object):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)
@ -477,11 +486,15 @@ class CWExtract(object):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)
@ -598,9 +611,8 @@ class HTTPBible(BibleDB):
if show_error: if show_error:
critical_error_message_box( critical_error_message_box(
translate('BiblesPlugin', 'No Book Found'), translate('BiblesPlugin', 'No Book Found'),
translate('BiblesPlugin', 'No matching ' translate('BiblesPlugin', 'No matching book could be found in this Bible. Check that you have '
'book could be found in this Bible. Check that you ' 'spelled the name of the book correctly.'))
'have spelled the name of the book correctly.'))
return [] return []
book = db_book.name book = db_book.name
if BibleDB.get_verse_count(self, book_id, reference[1]) == 0: if BibleDB.get_verse_count(self, book_id, reference[1]) == 0:
@ -667,14 +679,19 @@ class HTTPBible(BibleDB):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)
def get_soup_for_bible_ref(reference_url, header=None, pre_parse_regex=None, pre_parse_substitute=None): def get_soup_for_bible_ref(reference_url, header=None, pre_parse_regex=None, pre_parse_substitute=None):
""" """
Gets a webpage and returns a parsed and optionally cleaned soup or None. Gets a webpage and returns a parsed and optionally cleaned soup or None.
@ -724,13 +741,10 @@ def send_error_message(error_type):
if error_type == u'download': if error_type == u'download':
critical_error_message_box( critical_error_message_box(
translate('BiblesPlugin.HTTPBible', 'Download Error'), translate('BiblesPlugin.HTTPBible', 'Download Error'),
translate('BiblesPlugin.HTTPBible', 'There was a ' translate('BiblesPlugin.HTTPBible', 'There was a problem downloading your verse selection. Please check '
'problem downloading your verse selection. Please check your ' 'your Internet connection, and if this error continues to occur please consider reporting a bug.'))
'Internet connection, and if this error continues to occur '
'please consider reporting a bug.'))
elif error_type == u'parse': elif error_type == u'parse':
critical_error_message_box( critical_error_message_box(
translate('BiblesPlugin.HTTPBible', 'Parse Error'), translate('BiblesPlugin.HTTPBible', 'Parse Error'),
translate('BiblesPlugin.HTTPBible', 'There was a ' translate('BiblesPlugin.HTTPBible', 'There was a problem extracting your verse selection. If this error '
'problem extracting your verse selection. If this error continues ' 'continues to occur please consider reporting a bug.'))
'to occur please consider reporting a bug.'))

View File

@ -37,28 +37,13 @@ __version__ = 1
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def upgrade_setup(metadata): def upgrade_1(session, metadata):
"""
Set up the latest revision all tables, with reflection, needed for the
upgrade process. If you want to drop a table, you need to remove it from
here, and add it to your upgrade function.
"""
# Don't define the "metadata" table, as the upgrade mechanism already
# defines it.
tables = {
u'book': Table(u'book', metadata, autoload=True),
u'verse': Table(u'verse', metadata, autoload=True)
}
return tables
def upgrade_1(session, metadata, tables):
""" """
Version 1 upgrade. Version 1 upgrade.
This upgrade renames a number of keys to a single naming convention. This upgrade renames a number of keys to a single naming convention.
""" """
metadata_table = metadata.tables[u'metadata'] metadata_table = Table(u'metadata', metadata, autoload=True)
# Copy "Version" to "name" ("version" used by upgrade system) # Copy "Version" to "name" ("version" used by upgrade system)
# TODO: Clean up in a subsequent release of OpenLP (like 2.0 final) # TODO: Clean up in a subsequent release of OpenLP (like 2.0 final)
session.execute(insert(metadata_table).values( session.execute(insert(metadata_table).values(

View File

@ -100,8 +100,7 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
self.credit_edit.setText(self.custom_slide.credits) self.credit_edit.setText(self.custom_slide.credits)
custom_XML = CustomXMLParser(self.custom_slide.text) custom_XML = CustomXMLParser(self.custom_slide.text)
slide_list = custom_XML.get_verses() slide_list = custom_XML.get_verses()
for slide in slide_list: self.slide_list_view.addItems([slide[1] for slide in slide_list])
self.slide_list_view.addItem(slide[1])
theme = self.custom_slide.theme_name theme = self.custom_slide.theme_name
find_and_set_in_combo_box(self.theme_combo_box, theme) find_and_set_in_combo_box(self.theme_combo_box, theme)
self.title_edit.setFocus() self.title_edit.setFocus()

View File

@ -41,14 +41,19 @@ class CustomSlide(BaseModel):
""" """
CustomSlide model CustomSlide model
""" """
# By default sort the customs by its title considering language specific # By default sort the customs by its title considering language specific characters.
# characters.
def __lt__(self, other): def __lt__(self, other):
return get_locale_key(self.title) < get_locale_key(other.title) return get_locale_key(self.title) < get_locale_key(other.title)
def __eq__(self, other): def __eq__(self, other):
return get_locale_key(self.title) == get_locale_key(other.title) return get_locale_key(self.title) == get_locale_key(other.title)
def __hash__(self):
"""
Return the hash for a custom slide.
"""
return self.id
def init_schema(url): def init_schema(url):
""" """

View File

@ -174,13 +174,13 @@ class PPTViewer(QtGui.QWidget):
int(self.widthEdit.text()), int(self.heightEdit.text())) int(self.widthEdit.text()), int(self.heightEdit.text()))
filename = str(self.pptEdit.text().replace(u'/', u'\\')) filename = str(self.pptEdit.text().replace(u'/', u'\\'))
folder = str(self.folderEdit.text().replace(u'/', u'\\')) folder = str(self.folderEdit.text().replace(u'/', u'\\'))
print filename, folder print(filename, folder)
self.pptid = self.pptdll.OpenPPT(filename, None, rect, folder) self.pptid = self.pptdll.OpenPPT(filename, None, rect, folder)
print u'id: ' + unicode(self.pptid) print(u'id: ' + unicode(self.pptid))
if oldid >= 0: if oldid >= 0:
self.pptdll.ClosePPT(oldid); self.pptdll.ClosePPT(oldid);
slides = self.pptdll.GetSlideCount(self.pptid) slides = self.pptdll.GetSlideCount(self.pptid)
print u'slidecount: ' + unicode(slides) print(u'slidecount: ' + unicode(slides))
self.total.setNum(self.pptdll.GetSlideCount(self.pptid)) self.total.setNum(self.pptdll.GetSlideCount(self.pptid))
self.updateCurrSlide() self.updateCurrSlide()
@ -188,14 +188,14 @@ class PPTViewer(QtGui.QWidget):
if self.pptid < 0: if self.pptid < 0:
return return
slide = unicode(self.pptdll.GetCurrentSlide(self.pptid)) slide = unicode(self.pptdll.GetCurrentSlide(self.pptid))
print u'currslide: ' + slide print(u'currslide: ' + slide)
self.slideEdit.setText(slide) self.slideEdit.setText(slide)
app.processEvents() app.processEvents()
def gotoClick(self): def gotoClick(self):
if self.pptid < 0: if self.pptid < 0:
return return
print self.slideEdit.text() print(self.slideEdit.text())
self.pptdll.GotoSlide(self.pptid, int(self.slideEdit.text())) self.pptdll.GotoSlide(self.pptid, int(self.slideEdit.text()))
self.updateCurrSlide() self.updateCurrSlide()
app.processEvents() app.processEvents()
@ -207,7 +207,7 @@ class PPTViewer(QtGui.QWidget):
if __name__ == '__main__': if __name__ == '__main__':
pptdll = cdll.LoadLibrary(r'pptviewlib.dll') pptdll = cdll.LoadLibrary(r'pptviewlib.dll')
pptdll.SetDebug(1) pptdll.SetDebug(1)
print u'Begin...' print(u'Begin...')
app = QtGui.QApplication(sys.argv) app = QtGui.QApplication(sys.argv)
window = PPTViewer() window = PPTViewer()
window.pptdll = pptdll window.pptdll = pptdll

View File

@ -349,10 +349,14 @@ class DuplicateSongRemovalForm(OpenLPWizard):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -275,7 +275,6 @@ class Ui_EditSongDialog(object):
self.bottom_layout.setObjectName(u'bottom_layout') self.bottom_layout.setObjectName(u'bottom_layout')
self.warning_label = QtGui.QLabel(edit_song_dialog) self.warning_label = QtGui.QLabel(edit_song_dialog)
self.warning_label.setObjectName(u'warning_label') self.warning_label.setObjectName(u'warning_label')
self.warning_label.setVisible(False)
self.bottom_layout.addWidget(self.warning_label) self.bottom_layout.addWidget(self.warning_label)
self.button_box = create_button_box(edit_song_dialog, u'button_box', [u'cancel', u'save']) self.button_box = create_button_box(edit_song_dialog, u'button_box', [u'cancel', u'save'])
self.bottom_layout.addWidget(self.button_box) self.bottom_layout.addWidget(self.button_box)
@ -323,8 +322,10 @@ class Ui_EditSongDialog(object):
self.from_media_button.setText(translate('SongsPlugin.EditSongForm', 'Add &Media')) self.from_media_button.setText(translate('SongsPlugin.EditSongForm', 'Add &Media'))
self.audio_remove_button.setText(translate('SongsPlugin.EditSongForm', '&Remove')) self.audio_remove_button.setText(translate('SongsPlugin.EditSongForm', '&Remove'))
self.audio_remove_all_button.setText(translate('SongsPlugin.EditSongForm', 'Remove &All')) self.audio_remove_all_button.setText(translate('SongsPlugin.EditSongForm', 'Remove &All'))
self.warning_label.setText( self.not_all_verses_used_warning = \
translate('SongsPlugin.EditSongForm', '<strong>Warning:</strong> Not all of the verses are in use.')) translate('SongsPlugin.EditSongForm', '<strong>Warning:</strong> Not all of the verses are in use.')
self.no_verse_order_entered_warning = \
translate('SongsPlugin.EditSongForm', '<strong>Warning:</strong> You have not entered a verse order.')
def create_combo_box(parent, name): def create_combo_box(parent, name):

View File

@ -456,6 +456,8 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.title_edit.setFocus() self.title_edit.setFocus()
# Hide or show the preview button. # Hide or show the preview button.
self.preview_button.setVisible(preview) self.preview_button.setVisible(preview)
# Check if all verse tags are used.
self.on_verse_order_text_changed(self.verse_order_edit.text())
def tag_rows(self): def tag_rows(self):
""" """
@ -683,21 +685,33 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.verse_edit_button.setEnabled(False) self.verse_edit_button.setEnabled(False)
self.verse_delete_button.setEnabled(False) self.verse_delete_button.setEnabled(False)
def on_verse_order_text_changed(self, text): def on_verse_order_text_changed(self, text):
verses = [] """
verse_names = [] Checks if the verse order is complete or missing. Shows a error message according to the state of the verse
order = self._extract_verse_order(text) order.
``text``
The text of the verse order edit (ignored).
"""
# Extract all verses which were used in the order.
verses_in_order = self._extract_verse_order(self.verse_order_edit.text())
# Find the verses which were not used in the order.
verses_not_used = []
for index in range(self.verse_list_widget.rowCount()): for index in range(self.verse_list_widget.rowCount()):
verse = self.verse_list_widget.item(index, 0) verse = self.verse_list_widget.item(index, 0)
verse = verse.data(QtCore.Qt.UserRole) verse = verse.data(QtCore.Qt.UserRole)
if verse not in verse_names: if verse not in verses_in_order:
verses.append(verse)
verse_names.append(u'%s%s' % (VerseType.translated_tag(verse[0]), verse[1:]))
verses_not_used = []
for verse in verses:
if not verse in order:
verses_not_used.append(verse) verses_not_used.append(verse)
self.warning_label.setVisible(len(verses_not_used) > 0) # Set the label text.
label_text = u''
# No verse order was entered.
if not verses_in_order:
label_text = self.no_verse_order_entered_warning
# The verse order does not contain all verses.
elif verses_not_used:
label_text = self.not_all_verses_used_warning
self.warning_label.setText(label_text)
def on_copyright_insert_button_triggered(self): def on_copyright_insert_button_triggered(self):
text = self.copyright_edit.text() text = self.copyright_edit.text()

View File

@ -27,6 +27,7 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
import logging import logging
import os
from PyQt4 import QtGui, QtCore from PyQt4 import QtGui, QtCore
from sqlalchemy.sql import and_ from sqlalchemy.sql import and_
@ -525,10 +526,14 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def _get_application(self): def _get_application(self):
""" """
Adds the application to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -84,10 +84,14 @@ class OpenLyricsExport(object):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -1,131 +0,0 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2013 Raoul Snyman #
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from openlp.plugins.songs.lib.opensongimport import OpenSongImport
from openlp.core.lib.db import Manager
from openlp.plugins.songs.lib.db import init_schema
import logging
LOG_FILENAME = 'test.log'
logging.basicConfig(filename=LOG_FILENAME,level=logging.INFO)
# Stubs to replace the UI functions for raw testing
class wizard_stub:
def __init__(self):
self.progressBar=progbar_stub()
def incrementProgressBar(self, str):
pass
class progbar_stub:
def __init__(self):
pass
def setMaximum(self, arg):
pass
def test():
manager = Manager(u'songs', init_schema)
o = OpenSongImport(manager, filenames=[u'test.opensong'])
o.import_wizard = wizard_stub()
o.commit = False
o.do_import()
o.print_song()
assert o.copyright == u'2010 Martin Thompson'
assert o.authors == [u'MartiÑ Thómpson', u'Martin2 Thómpson']
assert o.title == u'Martins Test'
assert o.alternate_title == u''
assert o.song_number == u'1'
assert [u'C1', u'Chorus 1'] in o.verses
assert [u'C2', u'Chorus 2'] in o.verses
assert not [u'C3', u'Chorus 3'] in o.verses
assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.verses
assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.verses
assert [u'V2', u'v2 Line 1\nV2 Line 2'] in o.verses
assert [u'V3A', u'V3 Line 1\nV3 Line 2'] in o.verses
assert [u'RAP1', u'Rap 1 Line 1\nRap 1 Line 2'] in o.verses
assert [u'RAP2', u'Rap 2 Line 1\nRap 2 Line 2'] in o.verses
assert [u'RAP3', u'Rap 3 Line 1\nRap 3 Line 2'] in o.verses
assert [u'X1', u'Unreferenced verse line 1'] in o.verses
assert o.verse_order_list == [u'V1', u'C1', u'V2', u'C2', u'V3A', u'B1', u'V1', u'T1', u'RAP1', u'RAP2', u'RAP3']
assert o.ccli_number == u'Blah'
assert o.topics == [u'TestTheme', u'TestAltTheme']
o.filenames = [u'test.opensong.zip']
o.set_defaults()
o.do_import()
o.print_song()
assert o.copyright == u'2010 Martin Thompson'
assert o.authors == [u'MartiÑ Thómpson']
assert o.title == u'Martins Test'
assert o.alternate_title == u''
assert o.song_number == u'1'
assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.verses
assert [u'C1', u'Chorus 1'] in o.verses
assert [u'C2', u'Chorus 2'] in o.verses
assert not [u'C3', u'Chorus 3'] in o.verses
assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.verses
assert [u'V2', u'v2 Line 1\nV2 Line 2'] in o.verses
print o.verse_order_list
assert o.verse_order_list == [u'V1', u'C1', u'V2', u'C2', u'V3', u'B1', u'V1']
o.filenames = [u'test2.opensong']
o.set_defaults()
o.do_import()
o.print_song()
assert o.copyright == u'2010 Martin Thompson'
assert o.authors == [u'Martin Thompson']
assert o.title == u'Martins 2nd Test'
assert o.alternate_title == u''
assert o.song_number == u'2'
print o.verses
assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.verses
assert [u'C1', u'Chorus 1'] in o.verses
assert [u'C2', u'Chorus 2'] in o.verses
assert not [u'C3', u'Chorus 3'] in o.verses
assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.verses
assert [u'V2', u'v2 Line 1\nV2 Line 2'] in o.verses
print o.verse_order_list
assert o.verse_order_list == [u'V1', u'V2', u'B1', u'C1', u'C2']
o.filenames = [u'test3.opensong']
o.set_defaults()
o.do_import()
o.print_song()
assert o.copyright == u'2010'
assert o.authors == [u'Martin Thompson']
assert o.title == u'Test single verse'
assert o.alternate_title == u''
assert o.ccli_number == u'123456'
assert o.verse_order_list == [u'V1']
assert o.topics == [u'Worship: Declaration']
print o.verses[0]
assert [u'V1', u'Line 1\nLine 2'] in o.verses
print "Tests passed"
if __name__ == "__main__":
test()

View File

@ -31,31 +31,15 @@ The :mod:`upgrade` module provides a way for the database and schema that is the
backend for the Songs plugin backend for the Songs plugin
""" """
from sqlalchemy import Column, Table, types from sqlalchemy import Column, types
from sqlalchemy.sql.expression import func from sqlalchemy.sql.expression import func, false, null, text
from migrate.changeset.constraint import ForeignKeyConstraint
from openlp.core.lib.db import get_upgrade_op
__version__ = 3 __version__ = 3
def upgrade_setup(metadata):
"""
Set up the latest revision all tables, with reflection, needed for the
upgrade process. If you want to drop a table, you need to remove it from
here, and add it to your upgrade function.
"""
tables = {
u'authors': Table(u'authors', metadata, autoload=True),
u'media_files': Table(u'media_files', metadata, autoload=True),
u'song_books': Table(u'song_books', metadata, autoload=True),
u'songs': Table(u'songs', metadata, autoload=True),
u'topics': Table(u'topics', metadata, autoload=True),
u'authors_songs': Table(u'authors_songs', metadata, autoload=True),
u'songs_topics': Table(u'songs_topics', metadata, autoload=True)
}
return tables
def upgrade_1(session, metadata):
def upgrade_1(session, metadata, tables):
""" """
Version 1 upgrade. Version 1 upgrade.
@ -67,30 +51,35 @@ def upgrade_1(session, metadata, tables):
added to the media_files table, and a weight column so that the media added to the media_files table, and a weight column so that the media
files can be ordered. files can be ordered.
""" """
Table(u'media_files_songs', metadata, autoload=True).drop(checkfirst=True) op = get_upgrade_op(session)
Column(u'song_id', types.Integer(), default=None).create(table=tables[u'media_files']) op.drop_table(u'media_files_songs')
Column(u'weight', types.Integer(), default=0).create(table=tables[u'media_files']) op.add_column(u'media_files', Column(u'song_id', types.Integer(), server_default=null()))
op.add_column(u'media_files', Column(u'weight', types.Integer(), server_default=text(u'0')))
if metadata.bind.url.get_dialect().name != 'sqlite': if metadata.bind.url.get_dialect().name != 'sqlite':
# SQLite doesn't support ALTER TABLE ADD CONSTRAINT # SQLite doesn't support ALTER TABLE ADD CONSTRAINT
ForeignKeyConstraint([u'song_id'], [u'songs.id'], op.create_foreign_key(u'fk_media_files_song_id', u'media_files', u'songs', [u'song_id', u'id'])
table=tables[u'media_files']).create()
def upgrade_2(session, metadata, tables): def upgrade_2(session, metadata):
""" """
Version 2 upgrade. Version 2 upgrade.
This upgrade adds a create_date and last_modified date to the songs table This upgrade adds a create_date and last_modified date to the songs table
""" """
Column(u'create_date', types.DateTime(), default=func.now()).create(table=tables[u'songs']) op = get_upgrade_op(session)
Column(u'last_modified', types.DateTime(), default=func.now()).create(table=tables[u'songs']) op.add_column(u'songs', Column(u'create_date', types.DateTime(), default=func.now()))
op.add_column(u'songs', Column(u'last_modified', types.DateTime(), default=func.now()))
def upgrade_3(session, metadata, tables): def upgrade_3(session, metadata):
""" """
Version 3 upgrade. Version 3 upgrade.
This upgrade adds a temporary song flag to the songs table This upgrade adds a temporary song flag to the songs table
""" """
Column(u'temporary', types.Boolean(), default=False).create(table=tables[u'songs']) op = get_upgrade_op(session)
if metadata.bind.url.get_dialect().name == 'sqlite':
op.add_column(u'songs', Column(u'temporary', types.Boolean(create_constraint=False), server_default=false()))
else:
op.add_column(u'songs', Column(u'temporary', types.Boolean(), server_default=false()))

View File

@ -30,30 +30,19 @@
The :mod:`upgrade` module provides a way for the database and schema that is the The :mod:`upgrade` module provides a way for the database and schema that is the
backend for the SongsUsage plugin backend for the SongsUsage plugin
""" """
from openlp.core.lib.db import get_upgrade_op
from sqlalchemy import Column, Table, types from sqlalchemy import Column, types
__version__ = 1 __version__ = 1
def upgrade_setup(metadata):
"""
Set up the latest revision all tables, with reflection, needed for the
upgrade process. If you want to drop a table, you need to remove it from
here, and add it to your upgrade function.
"""
tables = {
u'songusage_data': Table(u'songusage_data', metadata, autoload=True)
}
return tables
def upgrade_1(session, metadata):
def upgrade_1(session, metadata, tables):
""" """
Version 1 upgrade. Version 1 upgrade.
This upgrade adds two new fields to the songusage database This upgrade adds two new fields to the songusage database
""" """
Column(u'plugin_name', types.Unicode(20), default=u'') \ op = get_upgrade_op(session)
.create(table=tables[u'songusage_data'], populate_default=True) op.add_column(u'songusage_data', Column(u'plugin_name', types.Unicode(20), server_default=u''))
Column(u'source', types.Unicode(10), default=u'') \ op.add_column(u'songusage_data', Column(u'source', types.Unicode(10), server_default=u''))
.create(table=tables[u'songusage_data'], populate_default=True)

View File

@ -175,6 +175,8 @@ OpenLP (previously openlp.org) is free church presentation software, or lyrics p
zip_safe=False, zip_safe=False,
install_requires=[ install_requires=[
# -*- Extra requirements: -*- # -*- Extra requirements: -*-
'sqlalchemy',
'alembic'
], ],
entry_points=""" entry_points="""
# -*- Entry points: -*- # -*- Entry points: -*-

View File

@ -0,0 +1,84 @@
"""
Package to test the openlp.core.lib package.
"""
from unittest import TestCase
from mock import MagicMock, patch
from sqlalchemy.pool import NullPool
from sqlalchemy.orm.scoping import ScopedSession
from sqlalchemy import MetaData
from openlp.core.lib.db import init_db, get_upgrade_op
class TestDB(TestCase):
"""
A test case for all the tests for the :mod:`~openlp.core.lib.db` module.
"""
def init_db_calls_correct_functions_test(self):
"""
Test that the init_db function makes the correct function calls
"""
# GIVEN: Mocked out SQLAlchemy calls and return objects, and an in-memory SQLite database URL
with patch(u'openlp.core.lib.db.create_engine') as mocked_create_engine, \
patch(u'openlp.core.lib.db.MetaData') as MockedMetaData, \
patch(u'openlp.core.lib.db.sessionmaker') as mocked_sessionmaker, \
patch(u'openlp.core.lib.db.scoped_session') as mocked_scoped_session:
mocked_engine = MagicMock()
mocked_metadata = MagicMock()
mocked_sessionmaker_object = MagicMock()
mocked_scoped_session_object = MagicMock()
mocked_create_engine.return_value = mocked_engine
MockedMetaData.return_value = mocked_metadata
mocked_sessionmaker.return_value = mocked_sessionmaker_object
mocked_scoped_session.return_value = mocked_scoped_session_object
db_url = u'sqlite://'
# WHEN: We try to initialise the db
session, metadata = init_db(db_url)
# THEN: We should see the correct function calls
mocked_create_engine.assert_called_with(db_url, poolclass=NullPool)
MockedMetaData.assert_called_with(bind=mocked_engine)
mocked_sessionmaker.assert_called_with(autoflush=True, autocommit=False, bind=mocked_engine)
mocked_scoped_session.assert_called_with(mocked_sessionmaker_object)
self.assertIs(session, mocked_scoped_session_object, u'The ``session`` object should be the mock')
self.assertIs(metadata, mocked_metadata, u'The ``metadata`` object should be the mock')
def init_db_defaults_test(self):
"""
Test that initialising an in-memory SQLite database via ``init_db`` uses the defaults
"""
# GIVEN: An in-memory SQLite URL
db_url = u'sqlite://'
# WHEN: The database is initialised through init_db
session, metadata = init_db(db_url)
# THEN: Valid session and metadata objects should be returned
self.assertIsInstance(session, ScopedSession, u'The ``session`` object should be a ``ScopedSession`` instance')
self.assertIsInstance(metadata, MetaData, u'The ``metadata`` object should be a ``MetaData`` instance')
def get_upgrade_op_test(self):
"""
Test that the ``get_upgrade_op`` function creates a MigrationContext and an Operations object
"""
# GIVEN: Mocked out alembic classes and a mocked out SQLAlchemy session object
with patch(u'openlp.core.lib.db.MigrationContext') as MockedMigrationContext, \
patch(u'openlp.core.lib.db.Operations') as MockedOperations:
mocked_context = MagicMock()
mocked_op = MagicMock()
mocked_connection = MagicMock()
MockedMigrationContext.configure.return_value = mocked_context
MockedOperations.return_value = mocked_op
mocked_session = MagicMock()
mocked_session.bind.connect.return_value = mocked_connection
# WHEN: get_upgrade_op is executed with the mocked session object
op = get_upgrade_op(mocked_session)
# THEN: The op object should be mocked_op, and the correction function calls should have been made
self.assertIs(op, mocked_op, u'The return value should be the mocked object')
mocked_session.bind.connect.assert_called_with()
MockedMigrationContext.configure.assert_called_with(mocked_connection)
MockedOperations.assert_called_with(mocked_context)

View File

@ -33,11 +33,11 @@ class TestFormattingTags(TestCase):
""" """
with patch(u'openlp.core.lib.translate') as mocked_translate, \ with patch(u'openlp.core.lib.translate') as mocked_translate, \
patch(u'openlp.core.lib.settings') as mocked_settings, \ patch(u'openlp.core.lib.settings') as mocked_settings, \
patch(u'openlp.core.lib.formattingtags.cPickle') as mocked_cPickle: patch(u'openlp.core.lib.formattingtags.json') as mocked_json:
# GIVEN: Our mocked modules and functions. # GIVEN: Our mocked modules and functions.
mocked_translate.side_effect = lambda module, string_to_translate, comment: string_to_translate mocked_translate.side_effect = lambda module, string_to_translate, comment: string_to_translate
mocked_settings.value.return_value = u'' mocked_settings.value.return_value = u''
mocked_cPickle.load.return_value = [] mocked_json.load.return_value = []
# WHEN: Get the display tags. # WHEN: Get the display tags.
FormattingTags.load_tags() FormattingTags.load_tags()
@ -54,11 +54,11 @@ class TestFormattingTags(TestCase):
""" """
with patch(u'openlp.core.lib.translate') as mocked_translate, \ with patch(u'openlp.core.lib.translate') as mocked_translate, \
patch(u'openlp.core.lib.settings') as mocked_settings, \ patch(u'openlp.core.lib.settings') as mocked_settings, \
patch(u'openlp.core.lib.formattingtags.cPickle') as mocked_cPickle: patch(u'openlp.core.lib.formattingtags.json') as mocked_json:
# GIVEN: Our mocked modules and functions. # GIVEN: Our mocked modules and functions.
mocked_translate.side_effect = lambda module, string_to_translate: string_to_translate mocked_translate.side_effect = lambda module, string_to_translate: string_to_translate
mocked_settings.value.return_value = u'' mocked_settings.value.return_value = u''
mocked_cPickle.loads.side_effect = [[], [TAG]] mocked_json.loads.side_effect = [[], [TAG]]
# WHEN: Get the display tags. # WHEN: Get the display tags.
FormattingTags.load_tags() FormattingTags.load_tags()

View File

@ -16,6 +16,7 @@ from openlp.core.lib import str_to_bool, create_thumb, translate, check_director
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), u'..', u'..', u'resources')) TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), u'..', u'..', u'resources'))
class TestLib(TestCase): class TestLib(TestCase):
def str_to_bool_with_bool_test(self): def str_to_bool_with_bool_test(self):

View File

@ -272,13 +272,13 @@ class TestServiceItem(TestCase):
service_item.add_icon = MagicMock() service_item.add_icon = MagicMock()
# WHEN: adding an media from a saved Service and mocked exists # WHEN: adding an media from a saved Service and mocked exists
line = self.convert_file_service_item(u'migrate_video_20_22.osd') line = read_service_from_file(u'migrate_video_20_22.osd')
with patch('os.path.exists'): with patch('os.path.exists'):
service_item.set_from_service(line, TEST_PATH) service_item.set_from_service(line[0], TEST_RESOURCES_PATH)
# THEN: We should get back a converted service item # THEN: We should get back a converted service item
assert service_item.is_valid is True, u'The new service item should be valid' assert service_item.is_valid is True, u'The new service item should be valid'
assert service_item.processor is None, u'The Processor should have been set' assert service_item.processor == u'VLC', u'The Processor should have been set'
assert service_item.title is None, u'The title should be set to a value' assert service_item.title is not None, u'The title should be set to a value'
assert service_item.is_capable(ItemCapabilities.HasDetailedTitleDisplay) is False, \ assert service_item.is_capable(ItemCapabilities.HasDetailedTitleDisplay) is False, \
u'The Capability should have been removed' u'The Capability should have been removed'

View File

@ -0,0 +1,60 @@
"""
Package to test the openlp.core.ui.mainwindow package.
"""
from unittest import TestCase
from mock import MagicMock, patch
from PyQt4 import QtGui
from openlp.core.lib import Registry
from openlp.core.ui.mainwindow import MainWindow
class TestMainWindow(TestCase):
def setUp(self):
"""
Create the UI
"""
Registry.create()
self.registry = Registry()
self.app = QtGui.QApplication([])
# Mock cursor busy/normal methods.
self.app.set_busy_cursor = MagicMock()
self.app.set_normal_cursor = MagicMock()
self.app.args =[]
Registry().register(u'application', self.app)
# Mock classes and methods used by mainwindow.
with patch(u'openlp.core.ui.mainwindow.SettingsForm') as mocked_settings_form, \
patch(u'openlp.core.ui.mainwindow.ImageManager') as mocked_image_manager, \
patch(u'openlp.core.ui.mainwindow.SlideController') as mocked_slide_controller, \
patch(u'openlp.core.ui.mainwindow.OpenLPDockWidget') as mocked_dock_widget, \
patch(u'openlp.core.ui.mainwindow.QtGui.QToolBox') as mocked_q_tool_box_class, \
patch(u'openlp.core.ui.mainwindow.QtGui.QMainWindow.addDockWidget') as mocked_add_dock_method, \
patch(u'openlp.core.ui.mainwindow.ServiceManager') as mocked_service_manager, \
patch(u'openlp.core.ui.mainwindow.ThemeManager') as mocked_theme_manager, \
patch(u'openlp.core.ui.mainwindow.Renderer') as mocked_renderer:
self.main_window = MainWindow()
def tearDown(self):
"""
Delete all the C++ objects at the end so that we don't have a segfault
"""
del self.main_window
del self.app
def restore_current_media_manager_item_test(self):
"""
Regression test for bug #1152509.
"""
# GIVEN: Mocked Settings().value method.
with patch(u'openlp.core.ui.mainwindow.Settings.value') as mocked_value:
# save current plugin: True; current media plugin: 2
mocked_value.side_effect = [True, 2]
# WHEN: Call the restore method.
Registry().execute(u'bootstrap_post_set_up')
# THEN: The current widget should have been set.
self.main_window.media_tool_box.setCurrentIndex.assert_called_with(2)

View File

@ -44,4 +44,67 @@ class TestEditSongForm(TestCase):
self.assertFalse(self.form.topic_remove_button.isEnabled(), u'The topic remove button should not be enabled') self.assertFalse(self.form.topic_remove_button.isEnabled(), u'The topic remove button should not be enabled')
def is_verse_edit_form_executed_test(self): def is_verse_edit_form_executed_test(self):
pass pass
def verse_order_no_warning_test(self):
"""
Test if the verse order warning is not shown
"""
# GIVEN: Mocked methods.
given_verse_order = u'V1 V2'
self.form.verse_list_widget.rowCount = MagicMock(return_value=2)
# Mock out the verse.
first_verse = MagicMock()
first_verse.data = MagicMock(return_value=u'V1')
second_verse = MagicMock()
second_verse.data = MagicMock(return_value= u'V2')
self.form.verse_list_widget.item = MagicMock(side_effect=[first_verse, second_verse])
self.form._extract_verse_order = MagicMock(return_value=given_verse_order.split())
# WHEN: Call the method.
self.form.on_verse_order_text_changed(given_verse_order)
# THEN: No text should be shown.
assert self.form.warning_label.text() == u'', u'There should be no warning.'
def verse_order_incomplete_warning_test(self):
"""
Test if the verse-order-incomple warning is shown
"""
# GIVEN: Mocked methods.
given_verse_order = u'V1'
self.form.verse_list_widget.rowCount = MagicMock(return_value=2)
# Mock out the verse.
first_verse = MagicMock()
first_verse.data = MagicMock(return_value=u'V1')
second_verse = MagicMock()
second_verse.data = MagicMock(return_value= u'V2')
self.form.verse_list_widget.item = MagicMock(side_effect=[first_verse, second_verse])
self.form._extract_verse_order = MagicMock(return_value=[given_verse_order])
# WHEN: Call the method.
self.form.on_verse_order_text_changed(given_verse_order)
# THEN: The verse-order-incomplete text should be shown.
assert self.form.warning_label.text() == self.form.not_all_verses_used_warning, \
u'The verse-order-incomplete warning should be shown.'
def bug_1170435_test(self):
"""
Regression test for bug 1170435 (test if "no verse order" message is shown)
"""
# GIVEN: Mocked methods.
given_verse_order = u''
self.form.verse_list_widget.rowCount = MagicMock(return_value=1)
# Mock out the verse. (We want a verse type to be returned).
mocked_verse = MagicMock()
mocked_verse.data = MagicMock(return_value=u'V1')
self.form.verse_list_widget.item = MagicMock(return_value=mocked_verse)
self.form._extract_verse_order = MagicMock(return_value=[])
self.form.verse_order_edit.text = MagicMock(return_value=given_verse_order)
# WHEN: Call the method.
self.form.on_verse_order_text_changed(given_verse_order)
# THEN: The no-verse-order message should be shown.
assert self.form.warning_label.text() == self.form.no_verse_order_entered_warning, \
u'The no-verse-order message should be shown.'