diff --git a/openlp/.version b/openlp/.version
index 2007f03af..8fdcf3869 100644
--- a/openlp/.version
+++ b/openlp/.version
@@ -1 +1 @@
-1.9.1-bzr821
+1.9.2
diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py
index 5408c611d..d6f805c98 100644
--- a/openlp/core/lib/__init__.py
+++ b/openlp/core/lib/__init__.py
@@ -22,7 +22,6 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
-
"""
The :mod:`lib` module contains most of the components and libraries that make
OpenLP work.
@@ -47,6 +46,10 @@ def translate(context, text, comment=None):
``text``
The text to put into the translation tables for translation.
+
+ ``comment``
+ An identifying string for when the same text is used in different roles
+ within the same context.
"""
return QtCore.QCoreApplication.translate(context, text, comment)
@@ -115,6 +118,18 @@ def build_icon(icon):
def context_menu_action(base, icon, text, slot):
"""
Utility method to help build context menus for plugins
+
+ ``base``
+ The parent menu to add this menu item to
+
+ ``icon``
+ An icon for this action
+
+ ``text``
+ The text to display for this action
+
+ ``slot``
+ The code to run when this action is triggered
"""
action = QtGui.QAction(text, base)
if icon:
@@ -125,6 +140,15 @@ def context_menu_action(base, icon, text, slot):
def context_menu(base, icon, text):
"""
Utility method to help build context menus for plugins
+
+ ``base``
+ The parent object to add this menu to
+
+ ``icon``
+ An icon for this menu
+
+ ``text``
+ The text to display for this menu
"""
action = QtGui.QMenu(text, base)
action.setIcon(build_icon(icon))
@@ -133,6 +157,9 @@ def context_menu(base, icon, text):
def context_menu_separator(base):
"""
Add a separator to a context menu
+
+ ``base``
+ The menu object to add the separator to
"""
action = QtGui.QAction(u'', base)
action.setSeparator(True)
@@ -200,5 +227,4 @@ from themexmlhandler import ThemeXML
from renderer import Renderer
from rendermanager import RenderManager
from mediamanageritem import MediaManagerItem
-from basemodel import BaseModel
from baselistwithdnd import BaseListWithDnD
diff --git a/openlp/core/lib/basemodel.py b/openlp/core/lib/basemodel.py
deleted file mode 100644
index f56336c7b..000000000
--- a/openlp/core/lib/basemodel.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2010 Raoul Snyman #
-# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
-# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin #
-# Thompson, Jon Tibble, Carsten Tinggaard #
-# --------------------------------------------------------------------------- #
-# 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 #
-###############################################################################
-
-class BaseModel(object):
- """
- BaseModel provides a base object with a set of generic functions
- """
-
- @classmethod
- def populate(cls, **kwargs):
- """
- Creates an instance of a class and populates it, returning the instance
- """
- me = cls()
- for key in kwargs:
- me.__setattr__(key, kwargs[key])
- return me
-
diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py
new file mode 100644
index 000000000..f20f3ab38
--- /dev/null
+++ b/openlp/core/lib/db.py
@@ -0,0 +1,253 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2010 Raoul Snyman #
+# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
+# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin #
+# Thompson, Jon Tibble, Carsten Tinggaard #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+The :mod:`db` module provides the core database functionality for OpenLP
+"""
+import logging
+import os
+
+from PyQt4 import QtCore
+from sqlalchemy import create_engine, MetaData
+from sqlalchemy.exceptions import InvalidRequestError
+from sqlalchemy.orm import scoped_session, sessionmaker
+
+from openlp.core.utils import AppLocation
+
+log = logging.getLogger(__name__)
+
+def init_db(url, auto_flush=True, auto_commit=False):
+ """
+ Initialise and return the session and metadata for a database
+
+ ``url``
+ The database to initialise connection with
+
+ ``auto_flush``
+ Sets the flushing behaviour of the session
+
+ ``auto_commit``
+ Sets the commit behaviour of the session
+ """
+ engine = create_engine(url)
+ metadata = MetaData(bind=engine)
+ session = scoped_session(sessionmaker(autoflush=auto_flush,
+ autocommit=auto_commit, bind=engine))
+ return session, metadata
+
+def delete_database(plugin_name, db_file_name=None):
+ """
+ Remove a database file from the system.
+
+ ``plugin_name``
+ The name of the plugin to remove the database for
+
+ ``db_file_name``
+ The database file name. Defaults to None resulting in the
+ plugin_name being used.
+ """
+ db_file_path = None
+ if db_file_name:
+ db_file_path = os.path.join(
+ AppLocation.get_section_data_path(plugin_name), db_file_name)
+ else:
+ db_file_path = os.path.join(
+ AppLocation.get_section_data_path(plugin_name), plugin_name)
+ try:
+ os.remove(db_file_path)
+ return True
+ except OSError:
+ return False
+
+class BaseModel(object):
+ """
+ BaseModel provides a base object with a set of generic functions
+ """
+ @classmethod
+ def populate(cls, **kwargs):
+ """
+ Creates an instance of a class and populates it, returning the instance
+ """
+ me = cls()
+ for key in kwargs:
+ me.__setattr__(key, kwargs[key])
+ return me
+
+class Manager(object):
+ """
+ Provide generic object persistence management
+ """
+ def __init__(self, plugin_name, init_schema, db_file_name=None):
+ """
+ Runs the initialisation process that includes creating the connection
+ to the database and the tables if they don't exist.
+
+ ``plugin_name``
+ The name to setup paths and settings section names
+
+ ``init_schema``
+ The init_schema function for this database
+
+ ``db_file_name``
+ The file name to use for this database. Defaults to None resulting
+ in the plugin_name being used.
+ """
+ settings = QtCore.QSettings()
+ settings.beginGroup(plugin_name)
+ self.db_url = u''
+ db_type = unicode(
+ settings.value(u'db type', QtCore.QVariant(u'sqlite')).toString())
+ if db_type == u'sqlite':
+ if db_file_name:
+ self.db_url = u'sqlite:///%s/%s' % (
+ AppLocation.get_section_data_path(plugin_name),
+ db_file_name)
+ else:
+ self.db_url = u'sqlite:///%s/%s.sqlite' % (
+ AppLocation.get_section_data_path(plugin_name), plugin_name)
+ else:
+ self.db_url = u'%s://%s:%s@%s/%s' % (db_type,
+ unicode(settings.value(u'db username').toString()),
+ unicode(settings.value(u'db password').toString()),
+ unicode(settings.value(u'db hostname').toString()),
+ unicode(settings.value(u'db database').toString()))
+ settings.endGroup()
+ self.session = init_schema(self.db_url)
+
+ def save_object(self, object_instance):
+ """
+ Save an object to the database
+
+ ``object_instance``
+ The object to save
+ """
+ try:
+ self.session.add(object_instance)
+ self.session.commit()
+ return True
+ except InvalidRequestError:
+ self.session.rollback()
+ log.exception(u'Object save failed')
+ return False
+
+ def get_object(self, object_class, key=None):
+ """
+ Return the details of an object
+
+ ``object_class``
+ The type of object to return
+
+ ``key``
+ The unique reference or primary key for the instance to return
+ """
+ if not key:
+ return object_class()
+ else:
+ return self.session.query(object_class).get(key)
+
+ def get_object_filtered(self, object_class, filter_clause):
+ """
+ Returns an object matching specified criteria
+
+ ``object_class``
+ The type of object to return
+
+ ``filter_clause``
+ The criteria to select the object by
+ """
+ return self.session.query(object_class).filter(filter_clause).first()
+
+ def get_all_objects(self, object_class, order_by_ref=None):
+ """
+ Returns all the objects from the database
+
+ ``object_class``
+ The type of objects to return
+
+ ``order_by_ref``
+ Any parameters to order the returned objects by. Defaults to None.
+ """
+ query = self.session.query(object_class)
+ if order_by_ref:
+ return query.order_by(order_by_ref).all()
+ return query.all()
+
+ def get_all_objects_filtered(self, object_class, filter_clause,
+ order_by_ref=None):
+ """
+ Returns a selection of objects from the database
+
+ ``object_class``
+ The type of objects to return
+
+ ``filter_clause``
+ The filter governing selection of objects to return
+
+ ``order_by_ref``
+ Any parameters to order the returned objects by. Defaults to None.
+ """
+ query = self.session.query(object_class).filter(filter_clause)
+ if order_by_ref:
+ return query.order_by(order_by_ref).all()
+ return query.all()
+
+ def delete_object(self, object_class, key):
+ """
+ Delete an object from the database
+
+ ``object_class``
+ The type of object to delete
+
+ ``key``
+ The unique reference or primary key for the instance to be deleted
+ """
+ if key != 0:
+ object_instance = self.get_object(object_class, key)
+ try:
+ self.session.delete(object_instance)
+ self.session.commit()
+ return True
+ except InvalidRequestError:
+ self.session.rollback()
+ log.exception(u'Failed to delete object')
+ return False
+ else:
+ return True
+
+ def delete_all_objects(self, object_class):
+ """
+ Delete all object records
+
+ ``object_class``
+ The type of object to delete
+ """
+ try:
+ self.session.query(object_class).delete(synchronize_session=False)
+ self.session.commit()
+ return True
+ except InvalidRequestError:
+ self.session.rollback()
+ log.exception(u'Failed to delete all %s records',
+ object_class.__name__)
+ return False
diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py
index 2983eaca2..322ce8cd0 100644
--- a/openlp/core/lib/mediamanageritem.py
+++ b/openlp/core/lib/mediamanageritem.py
@@ -525,8 +525,7 @@ class MediaManagerItem(QtGui.QWidget):
if self.ServiceItemIconName:
service_item.add_icon(self.ServiceItemIconName)
else:
- service_item.add_icon(
- u':/media/media_' + self.PluginNameShort.lower() + u'.png')
+ service_item.add_icon(self.parent.icon)
if self.generateSlideData(service_item, item):
return service_item
else:
diff --git a/openlp/core/lib/plugin.py b/openlp/core/lib/plugin.py
index a5d712dfb..1450ef1fe 100644
--- a/openlp/core/lib/plugin.py
+++ b/openlp/core/lib/plugin.py
@@ -242,19 +242,22 @@ class Plugin(QtCore.QObject):
"""
if self.media_item:
self.media_item.initialise()
+ self.insert_toolbox_item()
def finalise(self):
"""
Called by the plugin Manager to cleanup things.
"""
- pass
+ self.remove_toolbox_item()
def remove_toolbox_item(self):
"""
Called by the plugin to remove toolbar
"""
- self.mediadock.remove_dock(self.name)
- self.settings_form.removeTab(self.name)
+ if self.media_item:
+ self.mediadock.remove_dock(self.name)
+ if self.settings_tab:
+ self.settings_form.removeTab(self.name)
def insert_toolbox_item(self):
"""
diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py
index aa8c0a95a..c7f96528c 100644
--- a/openlp/core/lib/renderer.py
+++ b/openlp/core/lib/renderer.py
@@ -22,7 +22,10 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
-
+"""
+The :mod:`renderer` module enables OpenLP to take the input from plugins and
+format it for the output display.
+"""
import logging
from PyQt4 import QtGui, QtCore
diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py
index dfcad984a..c107a1872 100644
--- a/openlp/core/lib/serviceitem.py
+++ b/openlp/core/lib/serviceitem.py
@@ -35,6 +35,7 @@ import uuid
from PyQt4 import QtGui
from openlp.core.lib import build_icon, resize_image
+from openlp.core.utils import AppLocation
log = logging.getLogger(__name__)
@@ -92,6 +93,7 @@ class ServiceItem(object):
self.is_valid = True
self.cache = {}
self.icon = None
+ self.serviceItemPath = AppLocation.get_section_data_path(u'serviceItems')
def add_capability(self, capability):
"""
@@ -153,9 +155,12 @@ class ServiceItem(object):
del self.cache[len(self._display_frames)]
log.log(15, u'Formatting took %4s' % (time.time() - before))
elif self.service_item_type == ServiceItemType.Image:
- for slide in self._raw_frames:
+ for count, slide in enumerate(self._raw_frames):
slide[u'image'] = resize_image(slide[u'image'],
self.render_manager.width, self.render_manager.height)
+ path = os.path.join(self.serviceItemPath, self._uuid + unicode(count) + u'.png')
+ slide[u'image'].save(path)
+ slide[u'display'] = path
elif self.service_item_type == ServiceItemType.Command:
pass
else:
@@ -371,7 +376,8 @@ class ServiceItem(object):
if self.service_item_type == ServiceItemType.Text:
return self.render_individual(row)
else:
- return {u'main':self._raw_frames[row][u'image'], u'trans':None}
+ return {u'main':self._raw_frames[row][u'image'],
+ u'trans':None, u'display':self._raw_frames[row][u'display']}
def get_frame_title(self, row=0):
"""
diff --git a/openlp/core/theme/theme.py b/openlp/core/theme/theme.py
index 2ea13d01b..6cddbcb45 100644
--- a/openlp/core/theme/theme.py
+++ b/openlp/core/theme/theme.py
@@ -168,7 +168,7 @@ class Theme(object):
theme_strings.append(u'_%s_' % (getattr(self, key)))
return u''.join(theme_strings)
- def _set_from_XML(self, xml):
+ def _set_from_xml(self, xml):
"""
Set theme class attributes with data from XML
diff --git a/openlp/core/ui/amendthemedialog.py b/openlp/core/ui/amendthemedialog.py
index a75f5e686..2bb202964 100644
--- a/openlp/core/ui/amendthemedialog.py
+++ b/openlp/core/ui/amendthemedialog.py
@@ -178,13 +178,11 @@ class Ui_AmendThemeDialog(object):
self.MainFontLayout.setWidget(2, QtGui.QFormLayout.LabelRole,
self.FontMainSize)
self.FontMainSizeSpinBox = QtGui.QSpinBox(self.FontMainGroupBox)
- sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
+ defaultSizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
QtGui.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(
+ defaultSizePolicy.setHeightForWidth(
self.FontMainSizeSpinBox.sizePolicy().hasHeightForWidth())
- self.FontMainSizeSpinBox.setSizePolicy(sizePolicy)
+ self.FontMainSizeSpinBox.setSizePolicy(defaultSizePolicy)
self.FontMainSizeSpinBox.setMinimumSize(QtCore.QSize(70, 0))
self.FontMainSizeSpinBox.setProperty(u'value', QtCore.QVariant(16))
self.FontMainSizeSpinBox.setMaximum(999)
@@ -230,8 +228,7 @@ class Ui_AmendThemeDialog(object):
self.FontMainLineSpacingSpinBox)
self.FontMainLinesPageLabel = QtGui.QLabel(self.FontMainGroupBox)
self.FontMainLinesPageLabel.setObjectName(u'FontMainLinesPageLabel')
- self.MainFontLayout.setWidget(6, QtGui.QFormLayout.LabelRole,
- self.FontMainLinesPageLabel)
+ self.MainFontLayout.addRow(self.FontMainLinesPageLabel)
spacerItem1 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum,
QtGui.QSizePolicy.Expanding)
self.MainLeftLayout.addItem(spacerItem1)
@@ -275,13 +272,9 @@ class Ui_AmendThemeDialog(object):
self.MainLocationLayout.setWidget(4, QtGui.QFormLayout.LabelRole,
self.FontMainHeightLabel)
self.FontMainXSpinBox = QtGui.QSpinBox(self.MainLocationGroupBox)
- sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
- QtGui.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(
+ defaultSizePolicy.setHeightForWidth(
self.FontMainXSpinBox.sizePolicy().hasHeightForWidth())
- self.FontMainXSpinBox.setSizePolicy(sizePolicy)
+ self.FontMainXSpinBox.setSizePolicy(defaultSizePolicy)
self.FontMainXSpinBox.setMinimumSize(QtCore.QSize(78, 0))
self.FontMainXSpinBox.setProperty(u'value', QtCore.QVariant(0))
self.FontMainXSpinBox.setMaximum(9999)
@@ -289,39 +282,27 @@ class Ui_AmendThemeDialog(object):
self.MainLocationLayout.setWidget(1, QtGui.QFormLayout.FieldRole,
self.FontMainXSpinBox)
self.FontMainYSpinBox = QtGui.QSpinBox(self.MainLocationGroupBox)
- sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
- QtGui.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(
+ defaultSizePolicy.setHeightForWidth(
self.FontMainYSpinBox.sizePolicy().hasHeightForWidth())
- self.FontMainYSpinBox.setSizePolicy(sizePolicy)
+ self.FontMainYSpinBox.setSizePolicy(defaultSizePolicy)
self.FontMainYSpinBox.setMinimumSize(QtCore.QSize(78, 0))
self.FontMainYSpinBox.setMaximum(9999)
self.FontMainYSpinBox.setObjectName(u'FontMainYSpinBox')
self.MainLocationLayout.setWidget(2, QtGui.QFormLayout.FieldRole,
self.FontMainYSpinBox)
self.FontMainWidthSpinBox = QtGui.QSpinBox(self.MainLocationGroupBox)
- sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
- QtGui.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(
+ defaultSizePolicy.setHeightForWidth(
self.FontMainWidthSpinBox.sizePolicy().hasHeightForWidth())
- self.FontMainWidthSpinBox.setSizePolicy(sizePolicy)
+ self.FontMainWidthSpinBox.setSizePolicy(defaultSizePolicy)
self.FontMainWidthSpinBox.setMinimumSize(QtCore.QSize(78, 0))
self.FontMainWidthSpinBox.setMaximum(9999)
self.FontMainWidthSpinBox.setObjectName(u'FontMainWidthSpinBox')
self.MainLocationLayout.setWidget(3, QtGui.QFormLayout.FieldRole,
self.FontMainWidthSpinBox)
self.FontMainHeightSpinBox = QtGui.QSpinBox(self.MainLocationGroupBox)
- sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
- QtGui.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(
+ defaultSizePolicy.setHeightForWidth(
self.FontMainHeightSpinBox.sizePolicy().hasHeightForWidth())
- self.FontMainHeightSpinBox.setSizePolicy(sizePolicy)
+ self.FontMainHeightSpinBox.setSizePolicy(defaultSizePolicy)
self.FontMainHeightSpinBox.setMinimumSize(QtCore.QSize(78, 0))
self.FontMainHeightSpinBox.setMaximum(9999)
self.FontMainHeightSpinBox.setObjectName(u'FontMainHeightSpinBox')
@@ -378,13 +359,9 @@ class Ui_AmendThemeDialog(object):
self.FooterFontLayout.setWidget(2, QtGui.QFormLayout.LabelRole,
self.FontFooterSizeLabel)
self.FontFooterSizeSpinBox = QtGui.QSpinBox(self.FooterFontGroupBox)
- sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
- QtGui.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(
+ defaultSizePolicy.setHeightForWidth(
self.FontFooterSizeSpinBox.sizePolicy().hasHeightForWidth())
- self.FontFooterSizeSpinBox.setSizePolicy(sizePolicy)
+ self.FontFooterSizeSpinBox.setSizePolicy(defaultSizePolicy)
self.FontFooterSizeSpinBox.setMinimumSize(QtCore.QSize(70, 0))
self.FontFooterSizeSpinBox.setProperty(u'value', QtCore.QVariant(10))
self.FontFooterSizeSpinBox.setMaximum(999)
@@ -453,13 +430,9 @@ class Ui_AmendThemeDialog(object):
self.LocationFooterLayout.setWidget(4, QtGui.QFormLayout.LabelRole,
self.FontFooterHeightLabel)
self.FontFooterXSpinBox = QtGui.QSpinBox(self.LocationFooterGroupBox)
- sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
- QtGui.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(
+ defaultSizePolicy.setHeightForWidth(
self.FontFooterXSpinBox.sizePolicy().hasHeightForWidth())
- self.FontFooterXSpinBox.setSizePolicy(sizePolicy)
+ self.FontFooterXSpinBox.setSizePolicy(defaultSizePolicy)
self.FontFooterXSpinBox.setMinimumSize(QtCore.QSize(78, 0))
self.FontFooterXSpinBox.setProperty(u'value', QtCore.QVariant(0))
self.FontFooterXSpinBox.setMaximum(9999)
@@ -467,13 +440,9 @@ class Ui_AmendThemeDialog(object):
self.LocationFooterLayout.setWidget(1, QtGui.QFormLayout.FieldRole,
self.FontFooterXSpinBox)
self.FontFooterYSpinBox = QtGui.QSpinBox(self.LocationFooterGroupBox)
- sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
- QtGui.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(
- self.FontFooterYSpinBox.sizePolicy().hasHeightForWidth())
- self.FontFooterYSpinBox.setSizePolicy(sizePolicy)
+ defaultSizePolicy.setHeightForWidth(
+ self.FontFooterXSpinBox.sizePolicy().hasHeightForWidth())
+ self.FontFooterYSpinBox.setSizePolicy(defaultSizePolicy)
self.FontFooterYSpinBox.setMinimumSize(QtCore.QSize(78, 0))
self.FontFooterYSpinBox.setProperty(u'value', QtCore.QVariant(0))
self.FontFooterYSpinBox.setMaximum(9999)
@@ -901,4 +870,3 @@ class Ui_AmendThemeDialog(object):
self.ThemeTabWidget.indexOf(self.OtherOptionsTab),
translate('AmendThemeForm', '&Other Options'))
self.PreviewGroupBox.setTitle(translate('AmendThemeForm', 'Preview'))
-
diff --git a/openlp/core/ui/displaytab.py b/openlp/core/ui/displaytab.py
index 8a028bbc8..0fb16a9f7 100644
--- a/openlp/core/ui/displaytab.py
+++ b/openlp/core/ui/displaytab.py
@@ -242,4 +242,3 @@ class DisplayTab(SettingsTab):
if self.amend_display_start != self.amend_display:
self.amend_display_start = self.amend_display
Receiver.send_message(u'config_screen_changed')
-
diff --git a/openlp/core/ui/generaltab.py b/openlp/core/ui/generaltab.py
index 4c42bf90c..340753707 100644
--- a/openlp/core/ui/generaltab.py
+++ b/openlp/core/ui/generaltab.py
@@ -32,13 +32,16 @@ class GeneralTab(SettingsTab):
GeneralTab is the general settings tab in the settings dialog.
"""
def __init__(self, screens):
+ """
+ Initialise the general settings tab
+ """
self.screens = screens
+ self.MonitorNumber = 0
SettingsTab.__init__(self, u'General')
def preLoad(self):
"""
- Set up the display screen and set correct screen
- values.
+ Set up the display screen and set correct screen values.
If not set before default to last screen.
"""
settings = QtCore.QSettings()
@@ -47,12 +50,14 @@ class GeneralTab(SettingsTab):
QtCore.QVariant(self.screens.display_count - 1)).toInt()[0]
self.screens.set_current_display(self.MonitorNumber)
self.screens.monitor_number = self.MonitorNumber
- self.DisplayOnMonitor = settings.value(
+ self.screens.display = settings.value(
u'display on monitor', QtCore.QVariant(True)).toBool()
- self.screens.display = self.DisplayOnMonitor
settings.endGroup()
def setupUi(self):
+ """
+ Create the user interface for the general settings tab
+ """
self.setObjectName(u'GeneralTab')
self.tabTitleVisible = translate('GeneralTab', 'General')
self.GeneralLayout = QtGui.QHBoxLayout(self)
@@ -152,31 +157,11 @@ class GeneralTab(SettingsTab):
QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.GeneralRightLayout.addItem(self.GeneralRightSpacer)
self.GeneralLayout.addWidget(self.GeneralRightWidget)
- QtCore.QObject.connect(self.MonitorComboBox,
- QtCore.SIGNAL(u'activated(int)'), self.onMonitorComboBoxChanged)
- QtCore.QObject.connect(self.DisplayOnMonitorCheck,
- QtCore.SIGNAL(u'stateChanged(int)'),
- self.onDisplayOnMonitorCheckChanged)
- QtCore.QObject.connect(self.WarningCheckBox,
- QtCore.SIGNAL(u'stateChanged(int)'), self.onWarningCheckBoxChanged)
- QtCore.QObject.connect(self.AutoOpenCheckBox,
- QtCore.SIGNAL(u'stateChanged(int)'), self.onAutoOpenCheckBoxChanged)
- QtCore.QObject.connect(self.ShowSplashCheckBox,
- QtCore.SIGNAL(u'stateChanged(int)'),
- self.onShowSplashCheckBoxChanged)
- QtCore.QObject.connect(self.SaveCheckServiceCheckBox,
- QtCore.SIGNAL(u'stateChanged(int)'),
- self.onSaveCheckServiceCheckBox)
- QtCore.QObject.connect(self.AutoPreviewCheckBox,
- QtCore.SIGNAL(u'stateChanged(int)'), self.onAutoPreviewCheckBox)
- QtCore.QObject.connect(self.NumberEdit,
- QtCore.SIGNAL(u'editingFinished()'), self.onNumberEditLostFocus)
- QtCore.QObject.connect(self.UsernameEdit,
- QtCore.SIGNAL(u'editingFinished()'), self.onUsernameEditLostFocus)
- QtCore.QObject.connect(self.PasswordEdit,
- QtCore.SIGNAL(u'editingFinished()'), self.onPasswordEditLostFocus)
def retranslateUi(self):
+ """
+ Translate the general settings tab to the currently selected language
+ """
self.MonitorGroupBox.setTitle(translate('GeneralTab', 'Monitors'))
self.MonitorLabel.setText(
translate('GeneralTab', 'Select monitor for output display:'))
@@ -204,37 +189,10 @@ class GeneralTab(SettingsTab):
self.PasswordLabel.setText(
translate('GeneralTab', 'SongSelect Password:'))
- def onMonitorComboBoxChanged(self):
- self.MonitorNumber = self.MonitorComboBox.currentIndex()
-
- def onDisplayOnMonitorCheckChanged(self, value):
- self.DisplayOnMonitor = (value == QtCore.Qt.Checked)
-
- def onAutoOpenCheckBoxChanged(self, value):
- self.AutoOpen = (value == QtCore.Qt.Checked)
-
- def onShowSplashCheckBoxChanged(self, value):
- self.ShowSplash = (value == QtCore.Qt.Checked)
-
- def onWarningCheckBoxChanged(self, value):
- self.Warning = (value == QtCore.Qt.Checked)
-
- def onSaveCheckServiceCheckBox(self, value):
- self.PromptSaveService = (value == QtCore.Qt.Checked)
-
- def onAutoPreviewCheckBox(self, value):
- self.AutoPreview = (value == QtCore.Qt.Checked)
-
- def onNumberEditLostFocus(self):
- self.CCLINumber = self.NumberEdit.displayText()
-
- def onUsernameEditLostFocus(self):
- self.Username = self.UsernameEdit.displayText()
-
- def onPasswordEditLostFocus(self):
- self.Password = self.PasswordEdit.displayText()
-
def load(self):
+ """
+ Load the settings to populate the form
+ """
settings = QtCore.QSettings()
settings.beginGroup(self.settingsSection)
for screen in self.screens.screen_list:
@@ -244,55 +202,54 @@ class GeneralTab(SettingsTab):
screen_name = u'%s (%s)' % (screen_name,
translate('GeneralTab', 'primary'))
self.MonitorComboBox.addItem(screen_name)
- # Get the configs
- self.Warning = settings.value(
- u'blank warning', QtCore.QVariant(False)).toBool()
- self.AutoOpen = settings.value(
- u'auto open', QtCore.QVariant(False)).toBool()
- self.ShowSplash = settings.value(
- u'show splash', QtCore.QVariant(True)).toBool()
- self.PromptSaveService = settings.value(
- u'save prompt', QtCore.QVariant(False)).toBool()
- self.AutoPreview = settings.value(
- u'auto preview', QtCore.QVariant(False)).toBool()
- self.CCLINumber = unicode(settings.value(
- u'ccli number', QtCore.QVariant(u'')).toString())
- self.Username = unicode(settings.value(
- u'songselect username', QtCore.QVariant(u'')).toString())
- self.Password = unicode(settings.value(
- u'songselect password', QtCore.QVariant(u'')).toString())
- settings.endGroup()
- self.SaveCheckServiceCheckBox.setChecked(self.PromptSaveService)
- # Set a few things up
+ self.NumberEdit.setText(unicode(settings.value(
+ u'ccli number', QtCore.QVariant(u'')).toString()))
+ self.UsernameEdit.setText(unicode(settings.value(
+ u'songselect username', QtCore.QVariant(u'')).toString()))
+ self.PasswordEdit.setText(unicode(settings.value(
+ u'songselect password', QtCore.QVariant(u'')).toString()))
+ self.SaveCheckServiceCheckBox.setChecked(settings.value(u'save prompt',
+ QtCore.QVariant(False)).toBool())
self.MonitorComboBox.setCurrentIndex(self.MonitorNumber)
- self.DisplayOnMonitorCheck.setChecked(self.DisplayOnMonitor)
- self.WarningCheckBox.setChecked(self.Warning)
- self.AutoOpenCheckBox.setChecked(self.AutoOpen)
- self.ShowSplashCheckBox.setChecked(self.ShowSplash)
- self.AutoPreviewCheckBox.setChecked(self.AutoPreview)
- self.NumberEdit.setText(self.CCLINumber)
- self.UsernameEdit.setText(self.Username)
- self.PasswordEdit.setText(self.Password)
+ self.DisplayOnMonitorCheck.setChecked(self.screens.display)
+ self.WarningCheckBox.setChecked(settings.value(u'blank warning',
+ QtCore.QVariant(False)).toBool())
+ self.AutoOpenCheckBox.setChecked(settings.value(u'auto open',
+ QtCore.QVariant(False)).toBool())
+ self.ShowSplashCheckBox.setChecked(settings.value(u'show splash',
+ QtCore.QVariant(True)).toBool())
+ self.AutoPreviewCheckBox.setChecked(settings.value(u'auto preview',
+ QtCore.QVariant(False)).toBool())
+ settings.endGroup()
def save(self):
+ """
+ Save the settings from the form
+ """
+ self.MonitorNumber = self.MonitorComboBox.currentIndex()
settings = QtCore.QSettings()
settings.beginGroup(self.settingsSection)
settings.setValue(u'monitor', QtCore.QVariant(self.MonitorNumber))
settings.setValue(u'display on monitor',
- QtCore.QVariant(self.DisplayOnMonitor))
- settings.setValue(u'blank warning', QtCore.QVariant(self.Warning))
- settings.setValue(u'auto open', QtCore.QVariant(self.AutoOpen))
- settings.setValue(u'show splash', QtCore.QVariant(self.ShowSplash))
+ QtCore.QVariant(self.DisplayOnMonitorCheck.isChecked()))
+ settings.setValue(u'blank warning',
+ QtCore.QVariant(self.WarningCheckBox.isChecked()))
+ settings.setValue(u'auto open',
+ QtCore.QVariant(self.AutoOpenCheckBox.isChecked()))
+ settings.setValue(u'show splash',
+ QtCore.QVariant(self.ShowSplashCheckBox.isChecked()))
settings.setValue(u'save prompt',
- QtCore.QVariant(self.PromptSaveService))
- settings.setValue(u'auto preview', QtCore.QVariant(self.AutoPreview))
- settings.setValue(u'ccli number', QtCore.QVariant(self.CCLINumber))
+ QtCore.QVariant(self.SaveCheckServiceCheckBox.isChecked()))
+ settings.setValue(u'auto preview',
+ QtCore.QVariant(self.AutoPreviewCheckBox.isChecked()))
+ settings.setValue(u'ccli number',
+ QtCore.QVariant(self.NumberEdit.displayText()))
settings.setValue(u'songselect username',
- QtCore.QVariant(self.Username))
+ QtCore.QVariant(self.UsernameEdit.displayText()))
settings.setValue(u'songselect password',
- QtCore.QVariant(self.Password))
+ QtCore.QVariant(self.PasswordEdit.displayText()))
settings.endGroup()
- self.screens.display = self.DisplayOnMonitor
+ self.screens.display = self.DisplayOnMonitorCheck.isChecked()
#Monitor Number has changed.
if self.screens.monitor_number != self.MonitorNumber:
self.screens.monitor_number = self.MonitorNumber
diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py
index a3c444097..ae6d400fe 100644
--- a/openlp/core/ui/maindisplay.py
+++ b/openlp/core/ui/maindisplay.py
@@ -26,14 +26,38 @@
import logging
import os
-from PyQt4 import QtCore, QtGui
+from PyQt4 import QtCore, QtGui, QtWebKit
from PyQt4.phonon import Phonon
from openlp.core.lib import Receiver, resize_image
from openlp.core.ui import HideMode
+from openlp.core.utils import AppLocation
log = logging.getLogger(__name__)
+HTMLIMAGE = """
+
+
+
+ """
+
+#http://www.steveheffernan.com/html5-video-player/demo-video-player.html
+HTMLVIDEO = u"""
+
+ \"
+
+
+ """
+
class DisplayManager(QtGui.QWidget):
"""
Wrapper class to hold the display widgets.
@@ -45,18 +69,79 @@ class DisplayManager(QtGui.QWidget):
QtGui.QWidget.__init__(self)
self.screens = screens
self.videoDisplay = VideoDisplay(self, screens)
+ self.audioPlayer = AudioPlayer(self)
self.mainDisplay = MainDisplay(self, screens)
+ QtCore.QObject.connect(Receiver.get_receiver(),
+ QtCore.SIGNAL(u'maindisplay_hide'), self.hideDisplay)
+ QtCore.QObject.connect(Receiver.get_receiver(),
+ QtCore.SIGNAL(u'maindisplay_show'), self.showDisplay)
+ QtCore.QObject.connect(Receiver.get_receiver(),
+ QtCore.SIGNAL(u'videodisplay_start'), self.onStartVideo)
+ QtCore.QObject.connect(Receiver.get_receiver(),
+ QtCore.SIGNAL(u'videodisplay_stop'), self.onStopVideo)
def setup(self):
self.videoDisplay.setup()
self.mainDisplay.setup()
+ def hideDisplay(self, message):
+ """
+ Hide the output displays
+ """
+ self.videoDisplay.mediaHide(message)
+ self.mainDisplay.hideDisplay(message)
+
+ def showDisplay(self, message):
+ """
+ Hide the output displays
+ """
+ self.videoDisplay.mediaShow(message)
+ self.mainDisplay.showDisplay(message)
+
+ def addAlert(self, alertMessage, location):
+ """
+ Handles the addition of an Alert Message to the Displays
+ """
+ self.mainDisplay.addAlert(alertMessage, location)
+
+ def displayImage(self, path):
+ """
+ Handles the addition of a background Image to the displays
+ """
+ self.mainDisplay.displayImage(path)
+
+ def displayVideo(self, path):
+ """
+ Handles the addition of a background Video to the displays
+ """
+ self.mainDisplay.displayVideo(path)
+
+ def onStartVideo(self, item):
+ """
+ Handles the Starting of a Video and Display Management
+ """
+ self.videoDisplay.setVisible(True)
+ self.mainDisplay.setVisible(False)
+ self.videoDisplay.onMediaQueue(item)
+
+ def onStopVideo(self):
+ """
+ Handles the Stopping of a Video and Display Management
+ """
+ self.mainDisplay.setVisible(True)
+ self.videoDisplay.setVisible(False)
+ self.videoDisplay.onMediaStop()
+
def close(self):
+ """
+ Handles the closure of the displays
+ """
self.videoDisplay.close()
+ self.audioPlayer.close()
self.mainDisplay.close()
-class DisplayWidget(QtGui.QWidget):
+class DisplayWidget(QtGui.QGraphicsView):
"""
Customised version of QTableWidget which can respond to keyboard
events.
@@ -117,32 +202,26 @@ class MainDisplay(DisplayWidget):
log.debug(u'Initialisation started')
DisplayWidget.__init__(self, parent)
self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.FramelessWindowHint)
- self.setWindowState(QtCore.Qt.WindowFullScreen)
+ self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
+ self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.parent = parent
- self.setWindowTitle(u'OpenLP Display')
# WA_TranslucentBackground is not available in QT4.4
try:
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
except AttributeError:
pass
self.screens = screens
- self.display_image = QtGui.QLabel(self)
- self.display_image.setScaledContents(True)
- self.display_text = QtGui.QLabel(self)
- self.display_text.setScaledContents(True)
- self.display_alert = QtGui.QLabel(self)
- self.display_alert.setScaledContents(True)
+ self.setupScene()
+ self.setupImage()
+ self.setupText()
+ self.setupAlert()
+ self.setupBlank()
self.primary = True
self.blankFrame = None
self.frame = None
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'videodisplay_start'), self.hideDisplayForVideo)
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'maindisplay_hide'), self.hideDisplay)
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'maindisplay_show'), self.showDisplay)
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'videodisplay_background'), self.hideDisplayForVideo)
+ #Hide desktop for now until we know where to put it
+ #and what size it should be.
+ self.setVisible(False)
def setup(self):
"""
@@ -153,12 +232,9 @@ class MainDisplay(DisplayWidget):
self.setVisible(False)
self.screen = self.screens.current
#Sort out screen locations and sizes
- self.display_alert.setGeometry(self.screen[u'size'])
- self.display_image.resize(
- self.screen[u'size'].width(), self.screen[u'size'].height())
- self.display_text.resize(
- self.screen[u'size'].width(), self.screen[u'size'].height())
self.setGeometry(self.screen[u'size'])
+ self.scene.setSceneRect(0,0,self.size().width(), self.size().height())
+ self.webView.setGeometry(0, 0, self.size().width(), self.size().height())
#Build a custom splash screen
self.InitialFrame = QtGui.QImage(
self.screen[u'size'].width(),
@@ -172,7 +248,7 @@ class MainDisplay(DisplayWidget):
(self.screen[u'size'].width() - splash_image.width()) / 2,
(self.screen[u'size'].height() - splash_image.height()) / 2,
splash_image)
- self.display_image.setPixmap(QtGui.QPixmap.fromImage(self.InitialFrame))
+ #self.display_image.setPixmap(QtGui.QPixmap.fromImage(self.InitialFrame))
self.repaint()
#Build a Black screen
painter = QtGui.QPainter()
@@ -186,30 +262,65 @@ class MainDisplay(DisplayWidget):
self.transparent = QtGui.QPixmap(
self.screen[u'size'].width(), self.screen[u'size'].height())
self.transparent.fill(QtCore.Qt.transparent)
- self.display_alert.setPixmap(self.transparent)
- self.display_text.setPixmap(self.transparent)
- self.frameView(self.transparent)
+# self.display_text.setPixmap(self.transparent)
+ #self.frameView(self.transparent)
# To display or not to display?
if not self.screen[u'primary']:
- self.showFullScreen()
+ self.setVisible(True)
self.primary = False
else:
self.setVisible(False)
self.primary = True
+ def setupScene(self):
+ self.scene = QtGui.QGraphicsScene(self)
+ self.scene.setSceneRect(0,0,self.size().width(), self.size().height())
+ self.setScene(self.scene)
+
+ def setupImage(self):
+ self.webView = QtWebKit.QWebView()
+ self.page = self.webView.page()
+ self.imageDisplay = self.page.mainFrame()
+ self.imageDisplay.setScrollBarPolicy(QtCore.Qt.Vertical, QtCore.Qt.ScrollBarAlwaysOff)
+ self.imageDisplay.setScrollBarPolicy(QtCore.Qt.Horizontal, QtCore.Qt.ScrollBarAlwaysOff)
+ self.proxy = QtGui.QGraphicsProxyWidget()
+ self.proxy.setWidget(self.webView)
+ self.proxy.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.FramelessWindowHint)
+ self.proxy.setZValue(2)
+ self.scene.addItem(self.proxy)
+
+ def setupText(self):
+ #self.display_text = QtGui.QGraphicsTextItem()
+ self.display_text = QtGui.QGraphicsPixmapItem()
+ #self.display_text.setPos(0,0)
+ #self.display_text.setTextWidth(self.size().width())
+ self.display_text.setZValue(4)
+ self.scene.addItem(self.display_text)
+
+ def setupAlert(self):
+ self.alertText = QtGui.QGraphicsTextItem()
+ self.alertText.setTextWidth(self.size().width())
+ self.alertText.setZValue(8)
+ self.scene.addItem(self.alertText)
+
+ def setupBlank(self):
+ self.display_blank = QtGui.QGraphicsPixmapItem()
+ self.display_blank.setZValue(10)
+ self.scene.addItem(self.display_blank)
+
def resetDisplay(self):
log.debug(u'resetDisplay')
Receiver.send_message(u'slidecontroller_live_stop_loop')
if self.primary:
self.setVisible(False)
else:
- self.showFullScreen()
+ self.setVisible(True)
- def hideDisplayForVideo(self):
- """
- Hides the main display if for the video to be played
- """
- self.hideDisplay(HideMode.Screen)
+# def hideDisplayForVideo(self):
+# """
+# Hides the main display if for the video to be played
+# """
+# self.hideDisplay(HideMode.Screen)
def hideDisplay(self, mode=HideMode.Screen):
"""
@@ -217,45 +328,30 @@ class MainDisplay(DisplayWidget):
Store the images so they can be replaced when required
"""
log.debug(u'hideDisplay mode = %d', mode)
- self.storeImage = QtGui.QPixmap(self.display_image.pixmap())
- self.storeText = QtGui.QPixmap(self.display_text.pixmap())
- self.display_alert.setPixmap(self.transparent)
- self.display_text.setPixmap(self.transparent)
+ #self.display_text.setPixmap(self.transparent)
if mode == HideMode.Screen:
- self.display_image.setPixmap(self.transparent)
+ #self.display_image.setPixmap(self.transparent)
+ self.setVisible(False)
elif mode == HideMode.Blank:
- self.display_image.setPixmap(
+ self.display_blank.setPixmap(
QtGui.QPixmap.fromImage(self.blankFrame))
else:
if self.parent.renderManager.renderer.bg_frame:
- self.display_image.setPixmap(QtGui.QPixmap.fromImage(
+ self.display_blank.setPixmap(QtGui.QPixmap.fromImage(
self.parent.renderManager.renderer.bg_frame))
else:
- self.display_image.setPixmap(
+ self.display_blank.setPixmap(
QtGui.QPixmap.fromImage(self.blankFrame))
- self.moveToTop()
- def moveToTop(self):
- log.debug(u'moveToTop')
- self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint |
- QtCore.Qt.FramelessWindowHint | QtCore.Qt.Dialog)
- self.show()
-
- def showDisplay(self):
+ def showDisplay(self, message=u''):
"""
Show the stored layers so the screen reappears as it was
originally.
Make the stored images None to release memory.
"""
log.debug(u'showDisplay')
- if self.storeImage:
- self.display_image.setPixmap(self.storeImage)
- self.display_alert.setPixmap(self.transparent)
- if self.storeText:
- self.display_text.setPixmap(self.storeText)
- self.storeImage = None
- self.store = None
- self.moveToTop()
+ self.display_blank.setPixmap(self.transparent)
+ #Trigger actions when display is active again
Receiver.send_message(u'maindisplay_active')
def addImageWithText(self, frame):
@@ -263,57 +359,91 @@ class MainDisplay(DisplayWidget):
frame = resize_image(
frame, self.screen[u'size'].width(), self.screen[u'size'].height())
self.display_image.setPixmap(QtGui.QPixmap.fromImage(frame))
- self.moveToTop()
- def setAlertSize(self, top, height):
- log.debug(u'setAlertSize')
- self.display_alert.setGeometry(
- QtCore.QRect(0, top,
- self.screen[u'size'].width(), height))
-
- def addAlertImage(self, frame, blank=False):
+ def addAlert(self, message, location):
+ """
+ Places the Alert text on the display at the correct location
+ ``message``
+ Text to be displayed
+ ``location``
+ Where on the screen the text should be. From the AlertTab
+ Combo box.
+ """
log.debug(u'addAlertImage')
- if blank:
- self.display_alert.setPixmap(self.transparent)
+ if location == 0:
+ self.alertText.setPos(0, 0)
+ elif location == 1:
+ self.alertText.setPos(0,self.size().height()/2)
else:
- self.display_alert.setPixmap(frame)
- self.moveToTop()
+ self.alertText.setPos(0,self.size().height() - 76)
+ self.alertText.setHtml(message)
- def frameView(self, frame, transition=False, display=True):
+ def displayImage(self, path):
+ """
+ Places the Image passed on the display screen
+ ``path``
+ The path to the image to be displayed
+ """
+ log.debug(u'adddisplayImage')
+ self.imageDisplay.setHtml(HTMLIMAGE % path)
+
+ def displayVideo(self, path):
+ """
+ Places the Video passed on the display screen
+ ``path``
+ The path to the image to be displayed
+ """
+ log.debug(u'adddisplayVideo')
+ self.imageDisplay.setHtml(HTMLVIDEO %
+ (path, self.screen[u'size'].width(), self.screen[u'size'].height()))
+
+ def frameView(self, frame, transition=False):
"""
Called from a slide controller to display a frame
if the alert is in progress the alert is added on top
``frame``
Image frame to be rendered
+ ``transition``
+ Are transitions required.
"""
- log.debug(u'frameView %d' % (display))
- if display:
- if transition:
- if self.frame is not None:
- self.display_text.setPixmap(
- QtGui.QPixmap.fromImage(self.frame))
- self.repaint()
- self.frame = None
- if frame[u'trans'] is not None:
- self.display_text.setPixmap(
- QtGui.QPixmap.fromImage(frame[u'trans']))
- self.repaint()
- self.frame = frame[u'trans']
+ log.debug(u'frameView')
+ if transition:
+ if self.frame is not None:
self.display_text.setPixmap(
- QtGui.QPixmap.fromImage(frame[u'main']))
- self.display_frame = frame[u'main']
+ QtGui.QPixmap.fromImage(self.frame))
+ self.update()
+ self.frame = None
+ if frame[u'trans'] is not None:
+ self.display_text.setPixmap(
+ QtGui.QPixmap.fromImage(frame[u'trans']))
self.repaint()
- else:
- if isinstance(frame, QtGui.QPixmap):
- self.display_text.setPixmap(frame)
- else:
- self.display_text.setPixmap(QtGui.QPixmap.fromImage(frame))
- self.display_frame = frame
- if not self.isVisible() and self.screens.display:
- self.setVisible(True)
- self.showFullScreen()
+ self.frame = frame[u'trans']
+ self.display_text.setPixmap(
+ QtGui.QPixmap.fromImage(frame[u'main']))
+ self.display_frame = frame[u'main']
+ self.repaint()
else:
- self.storeText = QtGui.QPixmap.fromImage(frame[u'main'])
+ if isinstance(frame, QtGui.QPixmap):
+ self.display_text.setPixmap(frame)
+ else:
+ self.display_text.setPixmap(QtGui.QPixmap.fromImage(frame))
+ self.display_frame = frame
+ if not self.isVisible() and self.screens.display:
+ self.setVisible(True)
+
+ def closeEvent(self, event):
+ """
+ Shutting down cleans up background files
+ """
+ serviceItemPath = AppLocation.get_section_data_path(u'serviceItems')
+ for file in os.listdir(serviceItemPath):
+ file_path = os.path.join(serviceItemPath, file)
+ try:
+ if os.path.isfile(file_path):
+ os.remove(file_path)
+ except OSError:
+ log.exception(u'Failed to clean up servicePath')
+
class VideoDisplay(Phonon.VideoWidget):
"""
@@ -339,37 +469,29 @@ class VideoDisplay(Phonon.VideoWidget):
self.screens = screens
self.hidden = False
self.message = None
+ self.mediaActive = False
self.mediaObject = Phonon.MediaObject()
self.setAspectRatio(aspect)
self.audioObject = Phonon.AudioOutput(Phonon.VideoCategory)
Phonon.createPath(self.mediaObject, self)
Phonon.createPath(self.mediaObject, self.audioObject)
flags = QtCore.Qt.FramelessWindowHint | QtCore.Qt.Dialog
- # WindowsStaysOnBottomHint is not available in QT4.4
- try:
- flags = flags | QtCore.Qt.WindowStaysOnBottomHint
- except AttributeError:
- pass
+## # WindowsStaysOnBottomHint is not available in QT4.4
+# try:
+# flags = flags | QtCore.Qt.WindowStaysOnBottomHint
+# except AttributeError:
+# pass
self.setWindowFlags(flags)
-
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'maindisplay_hide'), self.mediaHide)
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'maindisplay_show'), self.mediaShow)
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'videodisplay_start'), self.onMediaQueue)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'videodisplay_play'), self.onMediaPlay)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'videodisplay_pause'), self.onMediaPause)
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'videodisplay_stop'), self.onMediaStop)
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'videodisplay_background'), self.onMediaBackground)
+# QtCore.QObject.connect(Receiver.get_receiver(),
+# QtCore.SIGNAL(u'videodisplay_background'), self.onMediaBackground)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'config_updated'), self.setup)
QtCore.QObject.connect(self.mediaObject,
- QtCore.SIGNAL(u'finished()'), self.onMediaBackground)
+ QtCore.SIGNAL(u'finished()'), self.onMediaStop)
self.setVisible(False)
def keyPressEvent(self, event):
@@ -392,38 +514,48 @@ class VideoDisplay(Phonon.VideoWidget):
#Sort out screen locations and sizes
self.setGeometry(self.screen[u'size'])
# To display or not to display?
- if not self.screen[u'primary'] and self.isVisible():
- self.showFullScreen()
+ if not self.screen[u'primary']: # and self.isVisible():
+ #self.showFullScreen()
+ self.setVisible(False)
self.primary = False
else:
self.setVisible(False)
self.primary = True
- def onMediaBackground(self, message=None):
+ def closeEvent(self, event):
"""
- Play a video triggered from the video plugin with the
- file name passed in on the event.
- Also triggered from the Finish event so the video will loop
- if it is triggered from the plugin
+ Shutting down so clean up connections
"""
- log.debug(u'VideoDisplay Queue new media message %s' % message)
- #If not file take the stored one
- if not message:
- message = self.message
- # still no file name then stop as it was a normal video stopping
- if message:
- self.mediaObject.setCurrentSource(Phonon.MediaSource(message))
- self.message = message
- self._play()
+ self.onMediaStop()
+ for pth in self.outputPaths():
+ disconnected = pth.disconnect()
+
+# def onMediaBackground(self, message=None):
+# """
+# Play a video triggered from the video plugin with the
+# file name passed in on the event.
+# Also triggered from the Finish event so the video will loop
+# if it is triggered from the plugin
+# """
+# log.debug(u'VideoDisplay Queue new media message %s' % message)
+# #If not file take the stored one
+# if not message:
+# message = self.message
+# # still no file name then stop as it was a normal video stopping
+# if message:
+# self.mediaObject.setCurrentSource(Phonon.MediaSource(message))
+# self.message = message
+# self._play()
def onMediaQueue(self, message):
"""
Set up a video to play from the serviceitem.
"""
log.debug(u'VideoDisplay Queue new media message %s' % message)
- file = os.path.join(message[0].get_frame_path(),
- message[0].get_frame_title())
+ file = os.path.join(message.get_frame_path(),
+ message.get_frame_title())
self.mediaObject.setCurrentSource(Phonon.MediaSource(file))
+ self.mediaActive = True
self._play()
def onMediaPlay(self):
@@ -442,7 +574,6 @@ class VideoDisplay(Phonon.VideoWidget):
log.debug(u'VideoDisplay _play called')
self.mediaObject.play()
self.setVisible(True)
- self.showFullScreen()
def onMediaPause(self):
"""
@@ -458,6 +589,7 @@ class VideoDisplay(Phonon.VideoWidget):
"""
log.debug(u'VideoDisplay Media stopped by user')
self.message = None
+ self.mediaActive = False
self.mediaObject.stop()
self.onMediaFinish()
@@ -469,7 +601,7 @@ class VideoDisplay(Phonon.VideoWidget):
self.mediaObject.clearQueue()
self.setVisible(False)
- def mediaHide(self):
+ def mediaHide(self, message=u''):
"""
Hide the video display
"""
@@ -477,10 +609,90 @@ class VideoDisplay(Phonon.VideoWidget):
self.hidden = True
self.setVisible(False)
- def mediaShow(self):
+ def mediaShow(self, message=''):
"""
Show the video disaply if it was already hidden
"""
if self.hidden:
self.hidden = False
- self._play()
+ if self.mediaActive:
+ self._play()
+
+class AudioPlayer(QtCore.QObject):
+ """
+ This Class will play audio only allowing components to work witn a
+ soundtrack which does not take over the user interface.
+ """
+ log.info(u'AudioPlayer Loaded')
+
+ def __init__(self, parent):
+ """
+ The constructor for the display form.
+
+ ``parent``
+ The parent widget.
+
+ ``screens``
+ The list of screens.
+ """
+ log.debug(u'AudioPlayer Initialisation started')
+ QtCore.QObject.__init__(self)
+ self.parent = parent
+ self.message = None
+ self.mediaObject = Phonon.MediaObject()
+ self.audioObject = Phonon.AudioOutput(Phonon.VideoCategory)
+ Phonon.createPath(self.mediaObject, self.audioObject)
+
+ def setup(self):
+ """
+ Sets up the Audio Player for use
+ """
+ log.debug(u'AudioPlayer Setup')
+
+ def close(self):
+ """
+ Shutting down so clean up connections
+ """
+ self.onMediaStop()
+ for pth in self.mediaObject.outputPaths():
+ disconnected = pth.disconnect()
+
+ def onMediaQueue(self, message):
+ """
+ Set up a video to play from the serviceitem.
+ """
+ log.debug(u'AudioPlayer Queue new media message %s' % message)
+ file = os.path.join(message[0].get_frame_path(),
+ message[0].get_frame_title())
+ self.mediaObject.setCurrentSource(Phonon.MediaSource(file))
+ self.onMediaPlay()
+
+ def onMediaPlay(self):
+ """
+ We want to play the play so start it
+ """
+ log.debug(u'AudioPlayer _play called')
+ self.mediaObject.play()
+
+ def onMediaPause(self):
+ """
+ Pause the Audio
+ """
+ log.debug(u'AudioPlayer Media paused by user')
+ self.mediaObject.pause()
+
+ def onMediaStop(self):
+ """
+ Stop the Audio and clean up
+ """
+ log.debug(u'AudioPlayer Media stopped by user')
+ self.message = None
+ self.mediaObject.stop()
+ self.onMediaFinish()
+
+ def onMediaFinish(self):
+ """
+ Clean up the Object queue
+ """
+ log.debug(u'AudioPlayer Reached end of media playlist')
+ self.mediaObject.clearQueue()
diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py
index 0f21b7307..f4d573d20 100644
--- a/openlp/core/ui/mainwindow.py
+++ b/openlp/core/ui/mainwindow.py
@@ -63,7 +63,7 @@ class VersionThread(QtCore.QThread):
self.parent = parent
self.app_version = app_version
self.version_splitter = re.compile(
- r'([0-9]+).([0-9]+).([0-9]+)(?:-bzr([0-9]+))')
+ r'([0-9]+).([0-9]+).([0-9]+)(?:-bzr([0-9]+))?')
def run(self):
"""
@@ -79,14 +79,14 @@ class VersionThread(QtCore.QThread):
remote_version[u'major'] = int(match.group(1))
remote_version[u'minor'] = int(match.group(2))
remote_version[u'release'] = int(match.group(3))
- if len(match.groups()) > 3:
+ if len(match.groups()) > 3 and match.group(4):
remote_version[u'revision'] = int(match.group(4))
match = self.version_splitter.match(self.app_version[u'full'])
if match:
local_version[u'major'] = int(match.group(1))
local_version[u'minor'] = int(match.group(2))
local_version[u'release'] = int(match.group(3))
- if len(match.groups()) > 3:
+ if len(match.groups()) > 3 and match.group(4):
local_version[u'revision'] = int(match.group(4))
if remote_version[u'major'] > local_version[u'major'] or \
remote_version[u'minor'] > local_version[u'minor'] or \
@@ -845,7 +845,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
recentFileCount = QtCore.QSettings().value(
self.generalSettingsSection + u'/max recent files',
QtCore.QVariant(4)).toInt()[0]
- if filename and filename not in self.recentFiles:
+ if filename:
+ position = self.recentFiles.indexOf(filename)
+ if position != -1:
+ self.recentFiles.removeAt(position)
self.recentFiles.insert(0, QtCore.QString(filename))
while self.recentFiles.count() > recentFileCount:
self.recentFiles.removeLast()
diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py
index 540be0ff4..837415921 100644
--- a/openlp/core/ui/servicemanager.py
+++ b/openlp/core/ui/servicemanager.py
@@ -33,7 +33,7 @@ log = logging.getLogger(__name__)
from PyQt4 import QtCore, QtGui
from openlp.core.lib import OpenLPToolbar, ServiceItem, context_menu_action, \
- Receiver, build_icon, ItemCapabilities, SettingsManager, translate
+ Receiver, build_icon, ItemCapabilities, SettingsManager, translate, ThemeLevel
from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm
from openlp.core.utils import AppLocation
@@ -134,15 +134,13 @@ class ServiceManager(QtGui.QWidget):
self.ThemeLabel = QtGui.QLabel(translate('ServiceManager', 'Theme:'),
self)
self.ThemeLabel.setMargin(3)
- self.Toolbar.addWidget(self.ThemeLabel)
+ self.Toolbar.addToolbarWidget(u'ThemeLabel', self.ThemeLabel)
self.ThemeComboBox = QtGui.QComboBox(self.Toolbar)
self.ThemeComboBox.setToolTip(translate('ServiceManager',
'Select a theme for the service'))
self.ThemeComboBox.setSizeAdjustPolicy(
QtGui.QComboBox.AdjustToContents)
- self.ThemeWidget = QtGui.QWidgetAction(self.Toolbar)
- self.ThemeWidget.setDefaultWidget(self.ThemeComboBox)
- self.Toolbar.addAction(self.ThemeWidget)
+ self.Toolbar.addToolbarWidget(u'ThemeWidget', self.ThemeComboBox)
self.Layout.addWidget(self.Toolbar)
# Create the service manager list
self.ServiceManagerList = ServiceManagerList(self)
@@ -214,6 +212,8 @@ class ServiceManager(QtGui.QWidget):
QtCore.SIGNAL(u'servicemanager_list_request'), self.listRequest)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'config_updated'), self.regenerateServiceItems)
+ QtCore.QObject.connect(Receiver.get_receiver(),
+ QtCore.SIGNAL(u'theme_update_global'), self.themeChange)
# Last little bits of setting up
self.service_theme = unicode(QtCore.QSettings().value(
self.parent.serviceSettingsSection + u'/service theme',
@@ -625,13 +625,13 @@ class ServiceManager(QtGui.QWidget):
def onLoadService(self, lastService=False):
if lastService:
- filename = SettingsManager.get_last_dir(
- self.parent.serviceSettingsSection)
+ filename = self.parent.recentFiles[0]
else:
filename = QtGui.QFileDialog.getOpenFileName(
self, translate('ServiceManager', 'Open Service'),
SettingsManager.get_last_dir(
self.parent.serviceSettingsSection), u'Services (*.osz)')
+ filename = QtCore.QDir.toNativeSeparators(filename)
self.loadService(filename)
def loadService(self, filename=None):
@@ -756,6 +756,18 @@ class ServiceManager(QtGui.QWidget):
QtCore.QVariant(self.service_theme))
self.regenerateServiceItems()
+ def themeChange(self):
+ """
+ The theme may have changed in the settings dialog so make
+ sure the theme combo box is in the correct state.
+ """
+ if self.parent.RenderManager.theme_level == ThemeLevel.Global:
+ self.Toolbar.actions[u'ThemeLabel'].setVisible(False)
+ self.Toolbar.actions[u'ThemeWidget'].setVisible(False)
+ else:
+ self.Toolbar.actions[u'ThemeLabel'].setVisible(True)
+ self.Toolbar.actions[u'ThemeWidget'].setVisible(True)
+
def regenerateServiceItems(self):
"""
Rebuild the service list as things have changed and a
diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py
index c2ec38069..5a34d09f8 100644
--- a/openlp/core/ui/slidecontroller.py
+++ b/openlp/core/ui/slidecontroller.py
@@ -105,9 +105,9 @@ class SlideController(QtGui.QWidget):
self.isLive = isLive
self.parent = parent
self.mainDisplay = self.parent.displayManager.mainDisplay
+ self.displayManager = self.parent.displayManager
self.loopList = [
u'Start Loop',
- u'Stop Loop',
u'Loop Separator',
u'Image SpinBox'
]
@@ -196,18 +196,25 @@ class SlideController(QtGui.QWidget):
self.onSlideSelectedLast)
if self.isLive:
self.Toolbar.addToolbarSeparator(u'Close Separator')
- self.blankButton = self.Toolbar.addToolbarButton(
- u'Blank Screen', u':/slides/slide_blank.png',
- translate('SlideController', 'Blank Screen'),
- self.onBlankDisplay, True)
- self.themeButton = self.Toolbar.addToolbarButton(
- u'Display Theme', u':/slides/slide_theme.png',
- translate('SlideController', 'Theme Screen'),
- self.onThemeDisplay, True)
- self.hideButton = self.Toolbar.addToolbarButton(
- u'Hide screen', u':/slides/slide_desktop.png',
- translate('SlideController', 'Hide Screen'),
- self.onHideDisplay, True)
+ self.HideMenu = QtGui.QToolButton(self.Toolbar)
+ self.HideMenu.setText(translate('SlideController', 'Hide'))
+ self.HideMenu.setPopupMode(QtGui.QToolButton.MenuButtonPopup)
+ self.Toolbar.addToolbarWidget(u'Hide Menu', self.HideMenu)
+ self.HideMenu.setMenu(QtGui.QMenu(
+ translate('SlideController', 'Hide'), self.Toolbar))
+ self.BlankScreen = QtGui.QAction(QtGui.QIcon( u':/slides/slide_blank.png'), u'Blank Screen', self.HideMenu)
+ self.BlankScreen.setCheckable(True)
+ QtCore.QObject.connect(self.BlankScreen, QtCore.SIGNAL("triggered(bool)"), self.onBlankDisplay)
+ self.ThemeScreen = QtGui.QAction(QtGui.QIcon(u':/slides/slide_theme.png'), u'Blank to Theme', self.HideMenu)
+ self.ThemeScreen.setCheckable(True)
+ QtCore.QObject.connect(self.ThemeScreen, QtCore.SIGNAL("triggered(bool)"), self.onThemeDisplay)
+ self.DesktopScreen = QtGui.QAction(QtGui.QIcon(u':/slides/slide_desktop.png'), u'Show Desktop', self.HideMenu)
+ self.DesktopScreen.setCheckable(True)
+ QtCore.QObject.connect(self.DesktopScreen, QtCore.SIGNAL("triggered(bool)"), self.onHideDisplay)
+ self.HideMenu.setDefaultAction(self.BlankScreen)
+ self.HideMenu.menu().addAction(self.BlankScreen)
+ self.HideMenu.menu().addAction(self.ThemeScreen)
+ self.HideMenu.menu().addAction(self.DesktopScreen)
if not self.isLive:
self.Toolbar.addToolbarSeparator(u'Close Separator')
self.Toolbar.addToolbarButton(
@@ -252,19 +259,6 @@ class SlideController(QtGui.QWidget):
u'Media Stop', u':/slides/media_playback_stop.png',
translate('SlideController', 'Start playing media'),
self.onMediaStop)
- if self.isLive:
- self.blankButton = self.Mediabar.addToolbarButton(
- u'Blank Screen', u':/slides/slide_blank.png',
- translate('SlideController', 'Blank Screen'),
- self.onBlankDisplay, True)
- self.themeButton = self.Mediabar.addToolbarButton(
- u'Display Theme', u':/slides/slide_theme.png',
- translate('SlideController', 'Theme Screen'),
- self.onThemeDisplay, True)
- self.hideButton = self.Mediabar.addToolbarButton(
- u'Hide screen', u':/slides/slide_desktop.png',
- translate('SlideController', 'Hide Screen'),
- self.onHideDisplay, True)
if not self.isLive:
self.seekSlider = Phonon.SeekSlider()
self.seekSlider.setGeometry(QtCore.QRect(90, 260, 221, 24))
@@ -340,6 +334,7 @@ class SlideController(QtGui.QWidget):
self.receiveSpinDelay)
if isLive:
self.Toolbar.makeWidgetsInvisible(self.loopList)
+ self.Toolbar.actions[u'Stop Loop'].setVisible(False)
else:
self.Toolbar.makeWidgetsInvisible(self.songEditList)
self.Mediabar.setVisible(False)
@@ -436,8 +431,8 @@ class SlideController(QtGui.QWidget):
self.Mediabar.setVisible(False)
self.Toolbar.makeWidgetsInvisible([u'Song Menu'])
self.Toolbar.makeWidgetsInvisible(self.loopList)
+ self.Toolbar.actions[u'Stop Loop'].setVisible(False)
if item.is_text():
- self.Toolbar.makeWidgetsInvisible(self.loopList)
if QtCore.QSettings().value(
self.parent.songsSettingsSection + u'/show songbar',
QtCore.QVariant(True)).toBool() and len(self.slideList) > 0:
@@ -519,21 +514,21 @@ class SlideController(QtGui.QWidget):
"""
log.debug(u'processManagerItem')
self.onStopLoop()
- #If old item was a command tell it to stop
+ #If old item was a command tell it to stop
if self.serviceItem:
if self.serviceItem.is_command():
- Receiver.send_message(u'%s_stop' %
+ Receiver.send_message(u'%s_stop' %
self.serviceItem.name.lower(), [serviceItem, self.isLive])
if self.serviceItem.is_media():
self.onMediaStop()
if serviceItem.is_media():
self.onMediaStart(serviceItem)
- if self.isLive:
- blanked = self.blankButton.isChecked()
- else:
- blanked = False
+# if self.isLive:
+# blanked = self.blankButton.isChecked()
+# else:
+# blanked = False
Receiver.send_message(u'%s_start' % serviceItem.name.lower(),
- [serviceItem, self.isLive, blanked, slideno])
+ [serviceItem, self.isLive, True, slideno])
self.slideList = {}
width = self.parent.ControlSplitter.sizes()[self.split]
#Set pointing cursor when we have somthing to point at
@@ -661,7 +656,7 @@ class SlideController(QtGui.QWidget):
"""
log.debug(u'mainDisplaySetBackground')
if not self.mainDisplay.primary:
- self.blankButton.setChecked(True)
+ self.onBlankDisplay(True)
def onSlideBlank(self):
"""
@@ -679,55 +674,55 @@ class SlideController(QtGui.QWidget):
"""
Handle the blank screen button actions
"""
- log.debug(u'onBlankDisplay %d' % checked)
- self.hideButton.setChecked(False)
- self.themeButton.setChecked(False)
- self.canDisplay = not checked
+ log.debug(u'onBlankDisplay %s' % checked)
+ self.HideMenu.setDefaultAction(self.BlankScreen)
+ self.BlankScreen.setChecked(checked)
+ self.ThemeScreen.setChecked(False)
+ self.DesktopScreen.setChecked(False)
QtCore.QSettings().setValue(
self.parent.generalSettingsSection + u'/screen blank',
QtCore.QVariant(checked))
if checked:
Receiver.send_message(u'maindisplay_hide', HideMode.Blank)
- self.blankPlugin(True)
else:
Receiver.send_message(u'maindisplay_show')
- self.blankPlugin(False)
+ self.blankPlugin(checked)
def onThemeDisplay(self, checked):
"""
Handle the Theme screen button
"""
- log.debug(u'onThemeDisplay %d' % checked)
- self.blankButton.setChecked(False)
- self.hideButton.setChecked(False)
- self.canDisplay = False
+ log.debug(u'onThemeDisplay %s' % checked)
+ self.HideMenu.setDefaultAction(self.ThemeScreen)
+ self.BlankScreen.setChecked(False)
+ self.ThemeScreen.setChecked(checked)
+ self.DesktopScreen.setChecked(False)
if checked:
Receiver.send_message(u'maindisplay_hide', HideMode.Theme)
- self.blankPlugin(True)
else:
Receiver.send_message(u'maindisplay_show')
- self.blankPlugin(False)
+ self.blankPlugin(checked)
def onHideDisplay(self, checked):
"""
Handle the Hide screen button
"""
- log.debug(u'onHideDisplay %d' % checked)
- self.blankButton.setChecked(False)
- self.themeButton.setChecked(False)
- self.canDisplay = False
+ log.debug(u'onHideDisplay %s' % checked)
+ self.HideMenu.setDefaultAction(self.DesktopScreen)
+ self.BlankScreen.setChecked(False)
+ self.ThemeScreen.setChecked(False)
+ self.DesktopScreen.setChecked(checked)
if checked:
Receiver.send_message(u'maindisplay_hide', HideMode.Screen)
- self.hidePlugin(True)
else:
Receiver.send_message(u'maindisplay_show')
- self.hidePlugin(False)
+ self.hidePlugin(checked)
def blankPlugin(self, blank):
"""
Blank the display screen within a plugin if required.
"""
- log.debug(u'blankPlugin %d ', blank)
+ log.debug(u'blankPlugin %s ', blank)
if self.serviceItem is not None:
if blank:
Receiver.send_message(u'%s_blank'
@@ -740,8 +735,9 @@ class SlideController(QtGui.QWidget):
def hidePlugin(self, hide):
"""
- Blank the display screen.
+ Tell the plugin to hide the display screen.
"""
+ log.debug(u'hidePlugin %s ', hide)
if self.serviceItem is not None:
if hide:
Receiver.send_message(u'%s_hide'
@@ -786,7 +782,10 @@ class SlideController(QtGui.QWidget):
log.log(
15, u'Slide Rendering took %4s' % (time.time() - before))
if self.isLive:
- self.mainDisplay.frameView(frame, True, self.canDisplay)
+ if self.serviceItem.is_text():
+ self.mainDisplay.frameView(frame, True)
+ else:
+ self.displayManager.displayImage(frame[u'display'])
self.selectedRow = row
Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix,
row)
@@ -889,6 +888,8 @@ class SlideController(QtGui.QWidget):
if self.PreviewListWidget.rowCount() > 1:
self.timer_id = self.startTimer(
int(self.DelaySpinBox.value()) * 1000)
+ self.Toolbar.actions[u'Stop Loop'].setVisible(True)
+ self.Toolbar.actions[u'Start Loop'].setVisible(False)
def onStopLoop(self):
"""
@@ -897,6 +898,8 @@ class SlideController(QtGui.QWidget):
if self.timer_id != 0:
self.killTimer(self.timer_id)
self.timer_id = 0
+ self.Toolbar.actions[u'Start Loop'].setVisible(True)
+ self.Toolbar.actions[u'Stop Loop'].setVisible(False)
def timerEvent(self, event):
"""
@@ -928,8 +931,7 @@ class SlideController(QtGui.QWidget):
"""
log.debug(u'SlideController onMediaStart')
if self.isLive:
- Receiver.send_message(u'videodisplay_start',
- [item, self.blankButton.isChecked()])
+ Receiver.send_message(u'videodisplay_start', item)
else:
self.mediaObject.stop()
self.mediaObject.clearQueue()
diff --git a/openlp/core/ui/themestab.py b/openlp/core/ui/themestab.py
index 73fbfeb88..007a51fd6 100644
--- a/openlp/core/ui/themestab.py
+++ b/openlp/core/ui/themestab.py
@@ -150,9 +150,9 @@ class ThemesTab(SettingsTab):
settings.setValue(u'global theme',
QtCore.QVariant(self.global_theme))
settings.endGroup()
- Receiver.send_message(u'theme_update_global', self.global_theme)
self.parent.RenderManager.set_global_theme(
self.global_theme, self.theme_level)
+ Receiver.send_message(u'theme_update_global', self.global_theme)
def postSetUp(self):
Receiver.send_message(u'theme_update_global', self.global_theme)
diff --git a/openlp/core/utils/languagemanager.py b/openlp/core/utils/languagemanager.py
index e556e7e7c..c0315559f 100644
--- a/openlp/core/utils/languagemanager.py
+++ b/openlp/core/utils/languagemanager.py
@@ -22,7 +22,10 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
-
+"""
+The :mod:`languagemanager` module provides all the translation settings and
+language file loading for OpenLP.
+"""
import logging
import os
@@ -42,50 +45,74 @@ class LanguageManager(object):
@staticmethod
def get_translator(language):
+ """
+ Set up a translator to use in this instance of OpenLP
+
+ ``language``
+ The language to load into the translator
+ """
if LanguageManager.AutoLanguage:
language = QtCore.QLocale.system().name()
lang_Path = AppLocation.get_directory(AppLocation.AppDir)
lang_Path = os.path.join(lang_Path, u'resources', u'i18n')
- appTranslator = QtCore.QTranslator()
- if appTranslator.load("openlp_" + language, lang_Path):
- return appTranslator
+ app_translator = QtCore.QTranslator()
+ if app_translator.load("openlp_" + language, lang_Path):
+ return app_translator
@staticmethod
def find_qm_files():
+ """
+ Find all available language files in this OpenLP install
+ """
trans_dir = AppLocation.get_directory(AppLocation.AppDir)
trans_dir = QtCore.QDir(os.path.join(trans_dir, u'resources', u'i18n'))
- fileNames = trans_dir.entryList(QtCore.QStringList("*.qm"),
+ file_names = trans_dir.entryList(QtCore.QStringList("*.qm"),
QtCore.QDir.Files, QtCore.QDir.Name)
- for name in fileNames:
- fileNames.replaceInStrings(name, trans_dir.filePath(name))
- return fileNames
+ for name in file_names:
+ file_names.replaceInStrings(name, trans_dir.filePath(name))
+ return file_names
@staticmethod
- def language_name(qmFile):
+ def language_name(qm_file):
+ """
+ Load the language name from a language file
+
+ ``qm_file``
+ The file to obtain the name from
+ """
translator = QtCore.QTranslator()
- translator.load(qmFile)
+ translator.load(qm_file)
return translator.translate('MainWindow', 'English')
@staticmethod
def get_language():
+ """
+ Retrieve a saved language to use from settings
+ """
settings = QtCore.QSettings(u'OpenLP', u'OpenLP')
language = unicode(settings.value(
u'general/language', QtCore.QVariant(u'[en]')).toString())
log.info(u'Language file: \'%s\' Loaded from conf file' % language)
- regEx = QtCore.QRegExp("^\[(.*)\]")
- if regEx.exactMatch(language):
+ reg_ex = QtCore.QRegExp("^\[(.*)\]")
+ if reg_ex.exactMatch(language):
LanguageManager.AutoLanguage = True
- language = regEx.cap(1)
+ language = reg_ex.cap(1)
return language
@staticmethod
def set_language(action):
- actionName = u'%s' % action.objectName()
- qmList = LanguageManager.get_qm_list()
+ """
+ Set the language to translate OpenLP into
+
+ ``action``
+ The language menu option
+ """
+ action_name = u'%s' % action.objectName()
+ qm_list = LanguageManager.get_qm_list()
if LanguageManager.AutoLanguage:
- language = u'[%s]' % qmList[actionName]
+ language = u'[%s]' % qm_list[action_name]
else:
- language = u'%s' % qmList[actionName]
+ language = u'%s' % qm_list[action_name]
QtCore.QSettings().setValue(
u'general/language', QtCore.QVariant(language))
log.info(u'Language file: \'%s\' written to conf file' % language)
@@ -96,17 +123,23 @@ class LanguageManager(object):
@staticmethod
def init_qm_list():
+ """
+ Initialise the list of available translations
+ """
LanguageManager.__qmList__ = {}
- qmFiles = LanguageManager.find_qm_files()
- for i, qmf in enumerate(qmFiles):
- regEx = QtCore.QRegExp("^.*openlp_(.*).qm")
- if regEx.exactMatch(qmf):
- langName = regEx.cap(1)
+ qm_files = LanguageManager.find_qm_files()
+ for i, qmf in enumerate(qm_files):
+ reg_ex = QtCore.QRegExp("^.*openlp_(.*).qm")
+ if reg_ex.exactMatch(qmf):
+ lang_name = reg_ex.cap(1)
LanguageManager.__qmList__[u'%#2i %s' % (i+1,
- LanguageManager.language_name(qmf))] = langName
+ LanguageManager.language_name(qmf))] = lang_name
@staticmethod
def get_qm_list():
+ """
+ Return the list of available translations
+ """
if LanguageManager.__qmList__ is None:
LanguageManager.init_qm_list()
return LanguageManager.__qmList__
diff --git a/openlp/plugins/alerts/__init__.py b/openlp/plugins/alerts/__init__.py
index cb376ec38..76ca202dd 100644
--- a/openlp/plugins/alerts/__init__.py
+++ b/openlp/plugins/alerts/__init__.py
@@ -24,5 +24,5 @@
###############################################################################
"""
The :mod:`alerts` module provides the Alerts plugin for producing impromptu
-on-screen announcements during a service
+on-screen announcements during a service.
"""
diff --git a/openlp/plugins/alerts/alertsplugin.py b/openlp/plugins/alerts/alertsplugin.py
index 4127afaac..57388c538 100644
--- a/openlp/plugins/alerts/alertsplugin.py
+++ b/openlp/plugins/alerts/alertsplugin.py
@@ -28,7 +28,9 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Plugin, build_icon, PluginStatus, translate
-from openlp.plugins.alerts.lib import AlertsManager, AlertsTab, DBManager
+from openlp.core.lib.db import Manager
+from openlp.plugins.alerts.lib import AlertsManager, AlertsTab
+from openlp.plugins.alerts.lib.db import init_schema
from openlp.plugins.alerts.forms import AlertForm
log = logging.getLogger(__name__)
@@ -39,13 +41,16 @@ class alertsPlugin(Plugin):
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Alerts', u'1.9.2', plugin_helpers)
self.weight = -3
- self.icon = build_icon(u':/media/media_image.png')
+ self.icon = build_icon(u':/plugins/plugin_alerts.png')
self.alertsmanager = AlertsManager(self)
- self.manager = DBManager()
+ self.manager = Manager(u'alerts', init_schema)
self.alertForm = AlertForm(self.manager, self)
self.status = PluginStatus.Active
def get_settings_tab(self):
+ """
+ Return the settings tab for the Alerts plugin
+ """
self.alertsTab = AlertsTab(self)
return self.alertsTab
@@ -60,7 +65,7 @@ class alertsPlugin(Plugin):
"""
log.info(u'add tools menu')
self.toolsAlertItem = QtGui.QAction(tools_menu)
- AlertIcon = build_icon(u':/tools/tools_alert.png')
+ AlertIcon = build_icon(u':/plugins/plugin_alerts.png')
self.toolsAlertItem.setIcon(AlertIcon)
self.toolsAlertItem.setObjectName(u'toolsAlertItem')
self.toolsAlertItem.setText(
@@ -80,8 +85,8 @@ class alertsPlugin(Plugin):
def finalise(self):
log.info(u'Plugin Finalise')
+ Plugin.finalise(self)
self.toolsAlertItem.setVisible(False)
- #stop any events being processed
def togglealertsState(self):
self.alertsActive = not self.alertsActive
@@ -97,4 +102,4 @@ class alertsPlugin(Plugin):
about_text = translate('AlertsPlugin',
'Alerts Plugin
This plugin '
'controls the displaying of alerts on the presentations screen')
- return about_text
\ No newline at end of file
+ return about_text
diff --git a/openlp/plugins/alerts/forms/alertform.py b/openlp/plugins/alerts/forms/alertform.py
index e783d718a..bf75f9ced 100644
--- a/openlp/plugins/alerts/forms/alertform.py
+++ b/openlp/plugins/alerts/forms/alertform.py
@@ -25,8 +25,8 @@
from PyQt4 import QtGui, QtCore
-from openlp.plugins.alerts.lib.models import AlertItem
from openlp.core.lib import translate
+from openlp.plugins.alerts.lib.db import AlertItem
from alertdialog import Ui_AlertDialog
@@ -62,7 +62,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
def loadList(self):
self.AlertListWidget.clear()
- alerts = self.manager.get_all_alerts()
+ alerts = self.manager.get_all_objects(AlertItem, AlertItem.text)
for alert in alerts:
item_name = QtGui.QListWidgetItem(alert.text)
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(alert.id))
@@ -82,7 +82,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
item = self.AlertListWidget.currentItem()
if item:
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
- self.parent.manager.delete_alert(item_id)
+ self.manager.delete_object(AlertItem, item_id)
row = self.AlertListWidget.row(item)
self.AlertListWidget.takeItem(row)
self.AlertTextEdit.setText(u'')
@@ -98,7 +98,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
else:
alert = AlertItem()
alert.text = unicode(self.AlertTextEdit.text())
- self.manager.save_alert(alert)
+ self.manager.save_object(alert)
self.AlertTextEdit.setText(u'')
self.loadList()
@@ -107,9 +107,9 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
Save an alert
"""
if self.item_id:
- alert = self.manager.get_alert(self.item_id)
+ alert = self.manager.get_object(AlertItem, self.item_id)
alert.text = unicode(self.AlertTextEdit.text())
- self.manager.save_alert(alert)
+ self.manager.save_object(alert)
self.item_id = None
self.loadList()
else:
diff --git a/openlp/plugins/alerts/lib/__init__.py b/openlp/plugins/alerts/lib/__init__.py
index 81a2641f6..2c22e5375 100644
--- a/openlp/plugins/alerts/lib/__init__.py
+++ b/openlp/plugins/alerts/lib/__init__.py
@@ -25,4 +25,3 @@
from alertsmanager import AlertsManager
from alertstab import AlertsTab
-from manager import DBManager
diff --git a/openlp/plugins/alerts/lib/alertsmanager.py b/openlp/plugins/alerts/lib/alertsmanager.py
index ecd41bbd1..aac3eccb9 100644
--- a/openlp/plugins/alerts/lib/alertsmanager.py
+++ b/openlp/plugins/alerts/lib/alertsmanager.py
@@ -25,12 +25,21 @@
import logging
-from PyQt4 import QtCore, QtGui
+from PyQt4 import QtCore
from openlp.core.lib import Receiver, translate
log = logging.getLogger(__name__)
+HTMLCODE = u"""
+
+ %s
+
+"""
+
class AlertsManager(QtCore.QObject):
"""
AlertsTab is the Alerts settings tab in the settings dialog.
@@ -47,28 +56,6 @@ class AlertsManager(QtCore.QObject):
QtCore.SIGNAL(u'maindisplay_active'), self.generateAlert)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'alerts_text'), self.onAlertText)
- QtCore.QObject.connect(Receiver.get_receiver(),
- QtCore.SIGNAL(u'config_screen_changed'), self.screenChanged)
-
- def screenChanged(self):
- log.debug(u'screen changed')
- self.alertTab = self.parent.alertsTab
- self.screen = self.parent.maindisplay.screens.current
- self.font = QtGui.QFont()
- self.font.setFamily(self.alertTab.font_face)
- self.font.setBold(True)
- self.font.setPointSize(self.alertTab.font_size)
- self.metrics = QtGui.QFontMetrics(self.font)
- self.alertHeight = self.metrics.height() + 4
- if self.alertTab.location == 0:
- self.alertScreenPosition = 0
- else:
- self.alertScreenPosition = self.screen[u'size'].height() \
- - self.alertHeight
- self.alertHeight = self.screen[u'size'].height() \
- - self.alertScreenPosition
- self.parent.maindisplay.setAlertSize(self.alertScreenPosition,
- self.alertHeight)
def onAlertText(self, message):
"""
@@ -88,8 +75,6 @@ class AlertsManager(QtCore.QObject):
display text
"""
log.debug(u'display alert called %s' % text)
- if not self.screen:
- self.screenChanged()
self.alertList.append(text)
if self.timer_id != 0:
Receiver.send_message(u'maindisplay_status_text',
@@ -100,37 +85,35 @@ class AlertsManager(QtCore.QObject):
self.generateAlert()
def generateAlert(self):
+ """
+ Format and request the Alert and start the timer
+ """
log.debug(u'Generate Alert called')
if len(self.alertList) == 0:
return
text = self.alertList.pop(0)
alertTab = self.parent.alertsTab
- alertframe = \
- QtGui.QPixmap(self.screen[u'size'].width(), self.alertHeight)
- alertframe.fill(QtCore.Qt.transparent)
- painter = QtGui.QPainter(alertframe)
- painter.fillRect(alertframe.rect(), QtCore.Qt.transparent)
- painter.setRenderHint(QtGui.QPainter.Antialiasing)
- painter.fillRect(
- QtCore.QRect(
- 0, 0, alertframe.rect().width(),
- alertframe.rect().height()),
- QtGui.QColor(self.alertTab.bg_color))
- painter.setFont(self.font)
- painter.setPen(QtGui.QColor(self.alertTab.font_color))
- x, y = (0, 2)
- painter.drawText(
- x, y + self.metrics.height() - self.metrics.descent() - 1, text)
- painter.end()
- self.parent.maindisplay.addAlertImage(alertframe)
+ text = HTMLCODE % (alertTab.font_color, alertTab.bg_color,
+ alertTab.font_face, alertTab.font_size, text)
+ self.parent.preview_controller.parent.displayManager.addAlert(text,
+ alertTab.location)
# check to see if we have a timer running
if self.timer_id == 0:
self.timer_id = self.startTimer(int(alertTab.timeout) * 1000)
def timerEvent(self, event):
+ """
+ Time has finished so if our time then request the next Alert
+ if there is one and reset the timer.
+ ``event``
+ the QT event that has been triggered.
+
+ """
log.debug(u'timer event')
+ alertTab = self.parent.alertsTab
if event.timerId() == self.timer_id:
- self.parent.maindisplay.addAlertImage(None, True)
+ self.parent.preview_controller.parent.displayManager.addAlert(u'',
+ alertTab.location)
self.killTimer(self.timer_id)
self.timer_id = 0
self.generateAlert()
diff --git a/openlp/plugins/alerts/lib/alertstab.py b/openlp/plugins/alerts/lib/alertstab.py
index 31a9f7a3e..e03bbfabe 100644
--- a/openlp/plugins/alerts/lib/alertstab.py
+++ b/openlp/plugins/alerts/lib/alertstab.py
@@ -128,6 +128,7 @@ class AlertsTab(SettingsTab):
self.LocationComboBox = QtGui.QComboBox(self.LocationWidget)
self.LocationComboBox.addItem(QtCore.QString())
self.LocationComboBox.addItem(QtCore.QString())
+ self.LocationComboBox.addItem(QtCore.QString())
self.LocationComboBox.setObjectName(u'LocationComboBox')
self.LocationLayout.addWidget(self.LocationComboBox)
self.LocationSpacer = QtGui.QSpacerItem(147, 20,
@@ -208,9 +209,11 @@ class AlertsTab(SettingsTab):
translate('AlertsPlugin.AlertsTab', 'Preview'))
self.FontPreview.setText(
translate('AlertsPlugin.AlertsTab', 'openlp.org'))
- self.LocationComboBox.setItemText(0,
+ self.LocationComboBox.setItemText(0,
translate('AlertsPlugin.AlertsTab', 'Top'))
- self.LocationComboBox.setItemText(1,
+ self.LocationComboBox.setItemText(1,
+ translate('AlertsPlugin.AlertsTab', 'Middle'))
+ self.LocationComboBox.setItemText(2,
translate('AlertsPlugin.AlertsTab', 'Bottom'))
def onBackgroundColorButtonClicked(self):
@@ -295,4 +298,4 @@ class AlertsTab(SettingsTab):
font.setPointSize(self.font_size)
self.FontPreview.setFont(font)
self.FontPreview.setStyleSheet(u'background-color: %s; color: %s' %
- (self.bg_color, self.font_color))
\ No newline at end of file
+ (self.bg_color, self.font_color))
diff --git a/openlp/plugins/alerts/lib/classes.py b/openlp/plugins/alerts/lib/classes.py
deleted file mode 100644
index e58f80829..000000000
--- a/openlp/plugins/alerts/lib/classes.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2010 Raoul Snyman #
-# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
-# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin #
-# Thompson, Jon Tibble, Carsten Tinggaard #
-# --------------------------------------------------------------------------- #
-# 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.core.lib import BaseModel
-
-class AlertItem(BaseModel):
- """
- Custom Slide model
- """
- pass
diff --git a/openlp/plugins/alerts/lib/models.py b/openlp/plugins/alerts/lib/db.py
similarity index 72%
rename from openlp/plugins/alerts/lib/models.py
rename to openlp/plugins/alerts/lib/db.py
index f222345f1..5e4b1a99a 100644
--- a/openlp/plugins/alerts/lib/models.py
+++ b/openlp/plugins/alerts/lib/db.py
@@ -22,18 +22,36 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
+"""
+The :mod:`db` module provides the database and schema that is the backend for
+the Alerts plugin
+"""
-from sqlalchemy import create_engine
-from sqlalchemy.orm import scoped_session, sessionmaker, mapper
+from sqlalchemy import Column, Table, types
+from sqlalchemy.orm import mapper
-from openlp.plugins.alerts.lib.meta import metadata
-from openlp.plugins.alerts.lib.tables import *
-from openlp.plugins.alerts.lib.classes import *
+from openlp.core.lib.db import BaseModel, init_db
+
+class AlertItem(BaseModel):
+ """
+ AlertItem model
+ """
+ pass
+
+def init_schema(url):
+ """
+ Setup the alerts database connection and initialise the database schema
+
+ ``url``
+ The database to setup
+ """
+ session, metadata = init_db(url)
+
+ alerts_table = Table(u'alerts', metadata,
+ Column(u'id', types.Integer(), primary_key=True),
+ Column(u'text', types.UnicodeText, nullable=False))
-def init_models(url):
- engine = create_engine(url)
- metadata.bind = engine
- session = scoped_session(sessionmaker(autoflush=True, autocommit=False,
- bind=engine))
mapper(AlertItem, alerts_table)
+
+ metadata.create_all(checkfirst=True)
return session
diff --git a/openlp/plugins/alerts/lib/manager.py b/openlp/plugins/alerts/lib/manager.py
deleted file mode 100644
index 088f0cbae..000000000
--- a/openlp/plugins/alerts/lib/manager.py
+++ /dev/null
@@ -1,114 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2010 Raoul Snyman #
-# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
-# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin #
-# Thompson, Jon Tibble, Carsten Tinggaard #
-# --------------------------------------------------------------------------- #
-# 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 #
-###############################################################################
-
-import logging
-
-from PyQt4 import QtCore
-from sqlalchemy.exceptions import InvalidRequestError
-
-from openlp.core.utils import AppLocation
-from openlp.plugins.alerts.lib.models import init_models, metadata, AlertItem
-
-log = logging.getLogger(__name__)
-
-class DBManager(object):
- """
- The Song Manager provides a central location for all database code. This
- class takes care of connecting to the database and running all the queries.
- """
- log.info(u'Alerts DB loaded')
-
- def __init__(self):
- """
- Creates the connection to the database, and creates the tables if they
- don't exist.
- """
- log.debug(u'Alerts Initialising')
- settings = QtCore.QSettings()
- settings.beginGroup(u'alerts')
- self.db_url = u''
- db_type = unicode(
- settings.value(u'db type', QtCore.QVariant(u'sqlite')).toString())
- if db_type == u'sqlite':
- self.db_url = u'sqlite:///%s/alerts.sqlite' % \
- AppLocation.get_section_data_path(u'alerts')
- else:
- self.db_url = u'%s://%s:%s@%s/%s' % (db_type,
- unicode(settings.value(u'db username').toString()),
- unicode(settings.value(u'db password').toString()),
- unicode(settings.value(u'db hostname').toString()),
- unicode(settings.value(u'db database').toString()))
- settings.endGroup()
- self.session = init_models(self.db_url)
- metadata.create_all(checkfirst=True)
- log.debug(u'Alerts Initialised')
-
- def get_all_alerts(self):
- """
- Returns the details of a Alert Show
- """
- return self.session.query(AlertItem).order_by(AlertItem.text).all()
-
- def save_alert(self, alert_item):
- """
- Saves a Alert show to the database
- """
- log.debug(u'Alert added')
- try:
- self.session.add(alert_item)
- self.session.commit()
- log.debug(u'Alert saved')
- return True
- except InvalidRequestError:
- self.session.rollback()
- log.exception(u'Alert save failed')
- return False
-
- def get_alert(self, id=None):
- """
- Returns the details of a Alert
- """
- if id is None:
- return AlertItem()
- else:
- return self.session.query(AlertItem).get(id)
-
- def delete_alert(self, id):
- """
- Delete a Alert show
- """
- if id != 0:
- alert_item = self.get_alert(id)
- try:
- self.session.delete(alert_item)
- self.session.commit()
- return True
- except InvalidRequestError:
- self.session.rollback()
- log.exception(u'Alert deleton failed')
- return False
- else:
- return True
-
diff --git a/openlp/plugins/alerts/lib/meta.py b/openlp/plugins/alerts/lib/meta.py
deleted file mode 100644
index affa31969..000000000
--- a/openlp/plugins/alerts/lib/meta.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2010 Raoul Snyman #
-# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
-# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin #
-# Thompson, Jon Tibble, Carsten Tinggaard #
-# --------------------------------------------------------------------------- #
-# 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 sqlalchemy import MetaData
-
-__all__ = ['session', 'metadata', 'engine']
-
-# SQLAlchemy database engine. Updated by model.init_model()
-engine = None
-
-# SQLAlchemy session manager. Updated by model.init_model()
-session = None
-
-# Global metadata. If you have multiple databases with overlapping table
-# names, you'll need a metadata for each database
-metadata = MetaData()
diff --git a/openlp/plugins/alerts/lib/tables.py b/openlp/plugins/alerts/lib/tables.py
deleted file mode 100644
index 0e707570d..000000000
--- a/openlp/plugins/alerts/lib/tables.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2010 Raoul Snyman #
-# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
-# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin #
-# Thompson, Jon Tibble, Carsten Tinggaard #
-# --------------------------------------------------------------------------- #
-# 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 sqlalchemy import Column, Table, types
-
-from openlp.plugins.alerts.lib.meta import metadata
-
-# Definition of the "alerts" table
-alerts_table = Table(u'alerts', metadata,
- Column(u'id', types.Integer(), primary_key=True),
- Column(u'text', types.UnicodeText, nullable=False))
diff --git a/openlp/plugins/bibles/__init__.py b/openlp/plugins/bibles/__init__.py
index ca5ff7508..2491c4142 100644
--- a/openlp/plugins/bibles/__init__.py
+++ b/openlp/plugins/bibles/__init__.py
@@ -23,6 +23,6 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
-The :mod:`bibles' modules provides the Bible plugin to enable OpenLP to display
-scripture
+The :mod:`bibles' module provides the Bible plugin to enable OpenLP to display
+scripture.
"""
diff --git a/openlp/plugins/bibles/bibleplugin.py b/openlp/plugins/bibles/bibleplugin.py
index 2398ead9c..9f4f034ab 100644
--- a/openlp/plugins/bibles/bibleplugin.py
+++ b/openlp/plugins/bibles/bibleplugin.py
@@ -38,7 +38,7 @@ class BiblePlugin(Plugin):
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Bibles', u'1.9.2', plugin_helpers)
self.weight = -9
- self.icon = build_icon(u':/media/media_bible.png')
+ self.icon = build_icon(u':/plugins/plugin_bibles.png')
#Register the bible Manager
self.status = PluginStatus.Active
self.manager = None
@@ -48,14 +48,12 @@ class BiblePlugin(Plugin):
if self.manager is None:
self.manager = BibleManager(self)
Plugin.initialise(self)
- self.insert_toolbox_item()
self.ImportBibleItem.setVisible(True)
self.ExportBibleItem.setVisible(True)
def finalise(self):
log.info(u'Plugin Finalise')
Plugin.finalise(self)
- self.remove_toolbox_item()
self.ImportBibleItem.setVisible(False)
self.ExportBibleItem.setVisible(False)
@@ -99,4 +97,4 @@ class BiblePlugin(Plugin):
def can_delete_theme(self, theme):
if self.settings_tab.bible_theme == theme:
return False
- return True
\ No newline at end of file
+ return True
diff --git a/openlp/plugins/bibles/forms/importwizardform.py b/openlp/plugins/bibles/forms/importwizardform.py
index 12b7bbaae..da225b782 100644
--- a/openlp/plugins/bibles/forms/importwizardform.py
+++ b/openlp/plugins/bibles/forms/importwizardform.py
@@ -32,6 +32,7 @@ from PyQt4 import QtCore, QtGui
from bibleimportwizard import Ui_BibleImportWizard
from openlp.core.lib import Receiver, SettingsManager, translate
+from openlp.core.lib.db import delete_database
from openlp.core.utils import AppLocation
from openlp.plugins.bibles.lib.manager import BibleFormat
@@ -224,7 +225,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
Show the file open dialog for the OSIS file.
"""
self.getFileName(
- translate('BiblesPlugin.ImportWizardForm', 'Open OSIS File'),
+ translate('BiblesPlugin.ImportWizardForm', 'Open OSIS File'),
self.OSISLocationEdit)
def onBooksFileButtonClicked(self):
@@ -239,10 +240,8 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
"""
Show the file open dialog for the verses CSV file.
"""
- self.getFileName(
- translate('BiblesPlugin.ImportWizardForm',
- 'Open Verses CSV File'),
- self.CsvVerseLocationEdit)
+ self.getFileName(translate('BiblesPlugin.ImportWizardForm',
+ 'Open Verses CSV File'), self.CsvVerseLocationEdit)
def onOpenSongBrowseButtonClicked(self):
"""
@@ -451,7 +450,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
self.ImportProgressLabel.setText(
translate('BiblesPlugin.ImportWizardForm',
'Your Bible import failed.'))
- importer.delete()
+ delete_database(self.bibleplugin.settingsSection, importer.file)
def postImport(self):
self.ImportProgressBar.setValue(self.ImportProgressBar.maximum())
diff --git a/openlp/plugins/bibles/lib/csvbible.py b/openlp/plugins/bibles/lib/csvbible.py
index 3cfe9dea5..9a504f48f 100644
--- a/openlp/plugins/bibles/lib/csvbible.py
+++ b/openlp/plugins/bibles/lib/csvbible.py
@@ -97,11 +97,11 @@ class CSVBible(BibleDB):
book_ptr = book.name
self.wizard.incrementProgressBar(
u'Importing %s %s' % (book.name, line[1]))
- self.commit()
+ self.session.commit()
self.create_verse(book.id, line[1], line[2],
unicode(line[3], details['encoding']))
Receiver.send_message(u'openlp_process_events')
- self.commit()
+ self.session.commit()
except IOError:
log.exception(u'Loading verses from file failed')
success = False
@@ -113,5 +113,3 @@ class CSVBible(BibleDB):
return False
else:
return success
-
-
diff --git a/openlp/plugins/bibles/lib/db.py b/openlp/plugins/bibles/lib/db.py
index 863f7f40a..a453d5bcc 100644
--- a/openlp/plugins/bibles/lib/db.py
+++ b/openlp/plugins/bibles/lib/db.py
@@ -23,20 +23,99 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
-import os
import logging
import chardet
import re
-from sqlalchemy import or_
from PyQt4 import QtCore, QtGui
+from sqlalchemy import Column, ForeignKey, or_, Table, types
+from sqlalchemy.orm import class_mapper, mapper, relation
+from sqlalchemy.orm.exc import UnmappedClassError
from openlp.core.lib import translate
-from openlp.plugins.bibles.lib.models import *
+from openlp.core.lib.db import BaseModel, init_db, Manager
log = logging.getLogger(__name__)
-class BibleDB(QtCore.QObject):
+class BibleMeta(BaseModel):
+ """
+ Bible Meta Data
+ """
+ pass
+
+class Testament(BaseModel):
+ """
+ Bible Testaments
+ """
+ pass
+
+class Book(BaseModel):
+ """
+ Song model
+ """
+ pass
+
+class Verse(BaseModel):
+ """
+ Topic model
+ """
+ pass
+
+def init_schema(url):
+ """
+ Setup a bible database connection and initialise the database schema
+
+ ``url``
+ The database to setup
+ """
+ session, metadata = init_db(url)
+
+ meta_table = Table(u'metadata', metadata,
+ Column(u'key', types.Unicode(255), primary_key=True, index=True),
+ Column(u'value', types.Unicode(255)),
+ )
+ testament_table = Table(u'testament', metadata,
+ Column(u'id', types.Integer, primary_key=True),
+ Column(u'name', types.Unicode(50)),
+ )
+ book_table = Table(u'book', metadata,
+ Column(u'id', types.Integer, primary_key=True),
+ Column(u'testament_id', types.Integer, ForeignKey(u'testament.id')),
+ Column(u'name', types.Unicode(50), index=True),
+ Column(u'abbreviation', types.Unicode(5), index=True),
+ )
+ verse_table = Table(u'verse', metadata,
+ Column(u'id', types.Integer, primary_key=True, index=True),
+ Column(u'book_id', types.Integer, ForeignKey(u'book.id'), index=True),
+ Column(u'chapter', types.Integer, index=True),
+ Column(u'verse', types.Integer, index=True),
+ Column(u'text', types.UnicodeText, index=True),
+ )
+
+ try:
+ class_mapper(BibleMeta)
+ except UnmappedClassError:
+ mapper(BibleMeta, meta_table)
+ try:
+ class_mapper(Testament)
+ except UnmappedClassError:
+ mapper(Testament, testament_table,
+ properties={'books': relation(Book, backref='testament')})
+ try:
+ class_mapper(Book)
+ except UnmappedClassError:
+ mapper(Book, book_table,
+ properties={'verses': relation(Verse, backref='book')})
+ try:
+ class_mapper(Verse)
+ except UnmappedClassError:
+ mapper(Verse, verse_table)
+
+ metadata.create_all(checkfirst=True)
+ return session
+
+
+class BibleDB(QtCore.QObject, Manager):
"""
This class represents a database-bound Bible. It is used as a base class
for all the custom importers, so that the can implement their own import
@@ -73,26 +152,10 @@ class BibleDB(QtCore.QObject):
self.file = self.clean_filename(self.name)
if u'file' in kwargs:
self.file = kwargs[u'file']
- self.db_file = os.path.join(kwargs[u'path'], self.file)
- log.debug(u'Load bible %s on path %s', self.file, self.db_file)
- settings = QtCore.QSettings()
- settings.beginGroup(u'bibles')
- db_type = unicode(
- settings.value(u'db type', QtCore.QVariant(u'sqlite')).toString())
- db_url = u''
- if db_type == u'sqlite':
- db_url = u'sqlite:///' + self.db_file
- else:
- db_url = u'%s://%s:%s@%s/%s' % (db_type,
- unicode(settings.value(u'db username').toString()),
- unicode(settings.value(u'db password').toString()),
- unicode(settings.value(u'db hostname').toString()),
- unicode(settings.value(u'db database').toString()))
- settings.endGroup()
- self.session = init_models(db_url)
- metadata.create_all(checkfirst=True)
+ Manager.__init__(self, u'bibles', init_schema, self.file)
if u'file' in kwargs:
self.get_name()
+ self.wizard = None
def stop_import(self):
"""
@@ -105,7 +168,7 @@ class BibleDB(QtCore.QObject):
"""
Returns the version name of the Bible.
"""
- version_name = self.get_meta(u'Version')
+ version_name = self.get_object(BibleMeta, u'Version')
if version_name:
self.name = version_name.value
else:
@@ -125,16 +188,6 @@ class BibleDB(QtCore.QObject):
old_filename = re.sub(r'[^\w]+', u'_', old_filename).strip(u'_')
return old_filename + u'.sqlite'
- def delete(self):
- """
- Remove the Bible database file. Used when a Bible import fails.
- """
- try:
- os.remove(self.db_file)
- return True
- except OSError:
- return False
-
def register(self, wizard):
"""
This method basically just initialialises the database. It is called
@@ -146,36 +199,11 @@ class BibleDB(QtCore.QObject):
The actual Qt wizard form.
"""
self.wizard = wizard
- self.create_tables()
- return self.name
-
- def commit(self):
- """
- Perform a database commit.
- """
- log.debug('Committing...')
- self.session.commit()
-
- def create_tables(self):
- """
- Create some initial metadata.
- """
- log.debug(u'createTables')
self.create_meta(u'dbversion', u'2')
- self.create_testament(u'Old Testament')
- self.create_testament(u'New Testament')
- self.create_testament(u'Apocrypha')
-
- def create_testament(self, testament):
- """
- Add a testament to the database.
-
- ``testament``
- The testament name.
- """
- log.debug(u'BibleDB.create_testament("%s")', testament)
- self.session.add(Testament.populate(name=testament))
- self.commit()
+ self.save_object(Testament.populate(name=u'Old Testament'))
+ self.save_object(Testament.populate(name=u'New Testament'))
+ self.save_object(Testament.populate(name=u'Apocrypha'))
+ return self.name
def create_book(self, name, abbrev, testament=1):
"""
@@ -193,8 +221,7 @@ class BibleDB(QtCore.QObject):
log.debug(u'create_book %s,%s', name, abbrev)
book = Book.populate(name=name, abbreviation=abbrev,
testament_id=testament)
- self.session.add(book)
- self.commit()
+ self.save_object(book)
return book
def create_chapter(self, book_id, chapter, textlist):
@@ -221,7 +248,7 @@ class BibleDB(QtCore.QObject):
text = verse_text
)
self.session.add(verse)
- self.commit()
+ self.session.commit()
def create_verse(self, book_id, chapter, verse, text):
"""
@@ -252,31 +279,31 @@ class BibleDB(QtCore.QObject):
return verse
def create_meta(self, key, value):
- log.debug(u'save_meta %s/%s', key, value)
- self.session.add(BibleMeta.populate(key=key, value=value))
- self.commit()
+ """
+ Utility method to save BibleMeta objects in a Bible database
- def get_books(self):
- log.debug(u'BibleDB.get_books()')
- return self.session.query(Book).order_by(Book.id).all()
+ ``key``
+ The key for this instance
+
+ ``value``
+ The value for this instance
+ """
+ log.debug(u'save_meta %s/%s', key, value)
+ self.save_object(BibleMeta.populate(key=key, value=value))
def get_book(self, book):
- log.debug(u'BibleDb.get_book("%s")', book)
- db_book = self.session.query(Book)\
- .filter(Book.name.like(book + u'%'))\
- .first()
- if db_book is None:
- db_book = self.session.query(Book)\
- .filter(Book.abbreviation.like(book + u'%'))\
- .first()
- return db_book
+ """
+ Return a book object from the database
- def get_chapter(self, id, chapter):
- log.debug(u'BibleDB.get_chapter("%s", %s)', id, chapter)
- return self.session.query(Verse)\
- .filter_by(chapter=chapter)\
- .filter_by(book_id=id)\
- .first()
+ ``book``
+ The name of the book to return
+ """
+ log.debug(u'BibleDb.get_book("%s")', book)
+ db_book = self.get_object_filtered(Book, Book.name.like(book + u'%'))
+ if db_book is None:
+ db_book = self.get_object_filtered(Book,
+ Book.abbreviation.like(book + u'%'))
+ return db_book
def get_verses(self, reference_list):
"""
@@ -351,6 +378,12 @@ class BibleDB(QtCore.QObject):
return verses
def get_chapter_count(self, book):
+ """
+ Return the number of chapters in a book
+
+ ``book``
+ The book to get the chapter count for
+ """
log.debug(u'BibleDB.get_chapter_count("%s")', book)
count = self.session.query(Verse.chapter).join(Book)\
.filter(Book.name==book)\
@@ -361,6 +394,15 @@ class BibleDB(QtCore.QObject):
return count
def get_verse_count(self, book, chapter):
+ """
+ Return the number of verses in a chapter
+
+ ``book``
+ The book containing the chapter
+
+ ``chapter``
+ The chapter to get the verse count for
+ """
log.debug(u'BibleDB.get_verse_count("%s", %s)', book, chapter)
count = self.session.query(Verse).join(Book)\
.filter(Book.name==book)\
@@ -371,20 +413,10 @@ class BibleDB(QtCore.QObject):
else:
return count
- def get_meta(self, key):
- log.debug(u'get meta %s', key)
- return self.session.query(BibleMeta).get(key)
-
- def delete_meta(self, metakey):
- biblemeta = self.get_meta(metakey)
- try:
- self.session.delete(biblemeta)
- self.commit()
- return True
- except:
- return False
-
def dump_bible(self):
+ """
+ Utility debugging method to dump the contents of a bible
+ """
log.debug(u'.........Dumping Bible Database')
log.debug('...............................Books ')
books = self.session.query(Book).all()
diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py
index 073b03118..8bf7ac63e 100644
--- a/openlp/plugins/bibles/lib/http.py
+++ b/openlp/plugins/bibles/lib/http.py
@@ -35,8 +35,7 @@ from openlp.core.lib import Receiver
from openlp.core.utils import AppLocation
from openlp.plugins.bibles.lib.common import BibleCommon, SearchResults, \
unescape
-from openlp.plugins.bibles.lib.db import BibleDB
-from openlp.plugins.bibles.lib.models import Book
+from openlp.plugins.bibles.lib.db import BibleDB, Book
log = logging.getLogger(__name__)
diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py
index 7ef18a604..39f3c255b 100644
--- a/openlp/plugins/bibles/lib/manager.py
+++ b/openlp/plugins/bibles/lib/manager.py
@@ -29,12 +29,12 @@ from PyQt4 import QtCore
from openlp.core.lib import SettingsManager
from openlp.core.utils import AppLocation
+from openlp.plugins.bibles.lib.db import BibleDB, Book, BibleMeta
from common import parse_reference
from opensong import OpenSongBible
from osis import OSISBible
from csvbible import CSVBible
-from db import BibleDB
from http import HTTPBible
log = logging.getLogger(__name__)
@@ -137,11 +137,13 @@ class BibleManager(object):
log.debug(u'Bible Name: "%s"', name)
self.db_cache[name] = bible
# look to see if lazy load bible exists and get create getter.
- source = self.db_cache[name].get_meta(u'download source')
+ source = self.db_cache[name].get_object(BibleMeta,
+ u'download source')
if source:
- download_name = \
- self.db_cache[name].get_meta(u'download name').value
- meta_proxy = self.db_cache[name].get_meta(u'proxy url')
+ download_name = self.db_cache[name].get_object(BibleMeta,
+ u'download name').value
+ meta_proxy = self.db_cache[name].get_object(BibleMeta,
+ u'proxy url')
web_bible = HTTPBible(self.parent, path=self.path,
file=filename, download_source=source.value,
download_name=download_name)
@@ -196,7 +198,7 @@ class BibleManager(object):
u'name': book.name,
u'chapters': self.db_cache[bible].get_chapter_count(book.name)
}
- for book in self.db_cache[bible].get_books()
+ for book in self.db_cache[bible].get_all_objects(Book, Book.id)
]
def get_chapter_count(self, bible, book):
@@ -249,7 +251,7 @@ class BibleManager(object):
Returns the meta data for a given key
"""
log.debug(u'get_meta %s,%s', bible, key)
- return self.db_cache[bible].get_meta(key)
+ return self.db_cache[bible].get_object(BibleMeta, key)
def exists(self, name):
"""
diff --git a/openlp/plugins/bibles/lib/models.py b/openlp/plugins/bibles/lib/models.py
deleted file mode 100644
index d970bce08..000000000
--- a/openlp/plugins/bibles/lib/models.py
+++ /dev/null
@@ -1,94 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2010 Raoul Snyman #
-# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
-# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin #
-# Thompson, Jon Tibble, Carsten Tinggaard #
-# --------------------------------------------------------------------------- #
-# 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 sqlalchemy import Column, Table, MetaData, ForeignKey, types, \
- create_engine
-from sqlalchemy.orm import mapper, relation, sessionmaker, scoped_session
-
-from openlp.core.lib import BaseModel
-
-
-class BibleMeta(BaseModel):
- """
- Bible Meta Data
- """
- pass
-
-
-class Testament(BaseModel):
- """
- Bible Testaments
- """
- pass
-
-
-class Book(BaseModel):
- """
- Song model
- """
- pass
-
-
-class Verse(BaseModel):
- """
- Topic model
- """
- pass
-
-def init_models(db_url):
- engine = create_engine(db_url)
- metadata.bind = engine
- session = scoped_session(sessionmaker(autoflush=True, autocommit=False,
- bind=engine))
- return session
-
-metadata = MetaData()
-meta_table = Table(u'metadata', metadata,
- Column(u'key', types.Unicode(255), primary_key=True, index=True),
- Column(u'value', types.Unicode(255)),
-)
-testament_table = Table(u'testament', metadata,
- Column(u'id', types.Integer, primary_key=True),
- Column(u'name', types.Unicode(50)),
-)
-book_table = Table(u'book', metadata,
- Column(u'id', types.Integer, primary_key=True),
- Column(u'testament_id', types.Integer, ForeignKey(u'testament.id')),
- Column(u'name', types.Unicode(50), index=True),
- Column(u'abbreviation', types.Unicode(5), index=True),
-)
-verse_table = Table(u'verse', metadata,
- Column(u'id', types.Integer, primary_key=True, index=True),
- Column(u'book_id', types.Integer, ForeignKey(u'book.id'), index=True),
- Column(u'chapter', types.Integer, index=True),
- Column(u'verse', types.Integer, index=True),
- Column(u'text', types.UnicodeText, index=True),
-)
-mapper(BibleMeta, meta_table)
-mapper(Testament, testament_table,
- properties={'books': relation(Book, backref='testament')})
-mapper(Book, book_table,
- properties={'verses': relation(Verse, backref='book')})
-mapper(Verse, verse_table)
diff --git a/openlp/plugins/bibles/lib/opensong.py b/openlp/plugins/bibles/lib/opensong.py
index d4458815f..7c7beb7f6 100644
--- a/openlp/plugins/bibles/lib/opensong.py
+++ b/openlp/plugins/bibles/lib/opensong.py
@@ -90,7 +90,7 @@ class OpenSongBible(BibleDB):
QtCore.QString('%s %s %s' % (
translate('BiblesPlugin.Opensong', 'Importing'), \
db_book.name, chapter.attrib[u'n'])))
- self.commit()
+ self.session.commit()
except IOError:
log.exception(u'Loading bible from OpenSong file failed')
success = False
diff --git a/openlp/plugins/bibles/lib/osis.py b/openlp/plugins/bibles/lib/osis.py
index 844d31052..8437fd843 100644
--- a/openlp/plugins/bibles/lib/osis.py
+++ b/openlp/plugins/bibles/lib/osis.py
@@ -140,7 +140,7 @@ class OSISBible(BibleDB):
self.wizard.ImportProgressBar.setMaximum(260)
if last_chapter != chapter:
if last_chapter != 0:
- self.commit()
+ self.session.commit()
self.wizard.incrementProgressBar(
u'Importing %s %s...' % \
(self.books[match.group(1)][0], chapter))
@@ -169,7 +169,7 @@ class OSISBible(BibleDB):
verse_text = self.spaces_regex.sub(u' ', verse_text)
self.create_verse(db_book.id, chapter, verse, verse_text)
Receiver.send_message(u'openlp_process_events')
- self.commit()
+ self.session.commit()
self.wizard.incrementProgressBar(u'Finishing import...')
if match_count == 0:
success = False
diff --git a/openlp/plugins/custom/__init__.py b/openlp/plugins/custom/__init__.py
index 1a348a0df..2b9a101f1 100644
--- a/openlp/plugins/custom/__init__.py
+++ b/openlp/plugins/custom/__init__.py
@@ -22,3 +22,8 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
+"""
+The :mod:`custom` module provides the Custom plugin which allows custom,
+themed, text based items to be displayed without having to misuse another item
+type.
+"""
diff --git a/openlp/plugins/custom/customplugin.py b/openlp/plugins/custom/customplugin.py
index d4f18058e..60a0b312c 100644
--- a/openlp/plugins/custom/customplugin.py
+++ b/openlp/plugins/custom/customplugin.py
@@ -26,8 +26,11 @@
import logging
from forms import EditCustomForm
+
from openlp.core.lib import Plugin, build_icon, PluginStatus, translate
-from openlp.plugins.custom.lib import CustomManager, CustomMediaItem, CustomTab
+from openlp.core.lib.db import Manager
+from openlp.plugins.custom.lib import CustomMediaItem, CustomTab
+from openlp.plugins.custom.lib.db import CustomSlide, init_schema
log = logging.getLogger(__name__)
@@ -45,9 +48,9 @@ class CustomPlugin(Plugin):
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Custom', u'1.9.2', plugin_helpers)
self.weight = -5
- self.custommanager = CustomManager()
+ self.custommanager = Manager(u'custom', init_schema)
self.edit_custom_form = EditCustomForm(self.custommanager)
- self.icon = build_icon(u':/media/media_custom.png')
+ self.icon = build_icon(u':/plugins/plugin_custom.png')
self.status = PluginStatus.Active
def get_settings_tab(self):
@@ -57,15 +60,6 @@ class CustomPlugin(Plugin):
# Create the CustomManagerItem object
return CustomMediaItem(self, self.icon, self.name)
- def initialise(self):
- log.info(u'Plugin Initialising')
- Plugin.initialise(self)
- self.insert_toolbox_item()
-
- def finalise(self):
- log.info(u'Plugin Finalise')
- self.remove_toolbox_item()
-
def about(self):
about_text = translate('CustomPlugin',
'Custom Plugin
This plugin '
@@ -75,6 +69,7 @@ class CustomPlugin(Plugin):
return about_text
def can_delete_theme(self, theme):
- if len(self.custommanager.get_customs_for_theme(theme)) == 0:
+ if not self.custommanager.get_all_objects_filtered(CustomSlide,
+ CustomSlide.theme_name == theme):
return True
- return False
\ No newline at end of file
+ return False
diff --git a/openlp/plugins/custom/forms/editcustomform.py b/openlp/plugins/custom/forms/editcustomform.py
index d387e7543..a266c44c5 100644
--- a/openlp/plugins/custom/forms/editcustomform.py
+++ b/openlp/plugins/custom/forms/editcustomform.py
@@ -29,7 +29,7 @@ from PyQt4 import QtCore, QtGui
from editcustomdialog import Ui_customEditDialog
from openlp.core.lib import SongXMLBuilder, SongXMLParser, Receiver, translate
-from openlp.plugins.custom.lib.models import CustomSlide
+from openlp.plugins.custom.lib.db import CustomSlide
log = logging.getLogger(__name__)
@@ -116,7 +116,7 @@ class EditCustomForm(QtGui.QDialog, Ui_customEditDialog):
self.customSlide = CustomSlide()
self.initialise()
if id != 0:
- self.customSlide = self.custommanager.get_custom(id)
+ self.customSlide = self.custommanager.get_object(CustomSlide, id)
self.TitleEdit.setText(self.customSlide.title)
self.CreditEdit.setText(self.customSlide.credits)
songXML = SongXMLParser(self.customSlide.text)
@@ -166,8 +166,7 @@ class EditCustomForm(QtGui.QDialog, Ui_customEditDialog):
u'utf-8')
self.customSlide.theme_name = unicode(self.ThemeComboBox.currentText(),
u'utf-8')
- self.custommanager.save_slide(self.customSlide)
- return True
+ return self.custommanager.save_object(self.customSlide)
def onUpButtonPressed(self):
selectedRow = self.VerseListView.currentRow()
diff --git a/openlp/plugins/custom/lib/__init__.py b/openlp/plugins/custom/lib/__init__.py
index e62669ad3..0d9de3173 100644
--- a/openlp/plugins/custom/lib/__init__.py
+++ b/openlp/plugins/custom/lib/__init__.py
@@ -23,6 +23,5 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
-from manager import CustomManager
from mediaitem import CustomMediaItem
from customtab import CustomTab
diff --git a/openlp/plugins/custom/lib/classes.py b/openlp/plugins/custom/lib/classes.py
deleted file mode 100644
index dc6c5c1b8..000000000
--- a/openlp/plugins/custom/lib/classes.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2010 Raoul Snyman #
-# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
-# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin #
-# Thompson, Jon Tibble, Carsten Tinggaard #
-# --------------------------------------------------------------------------- #
-# 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.core.lib import BaseModel
-
-class CustomSlide(BaseModel):
- """
- Custom Slide model
- """
- pass
diff --git a/openlp/plugins/custom/lib/models.py b/openlp/plugins/custom/lib/db.py
similarity index 67%
rename from openlp/plugins/custom/lib/models.py
rename to openlp/plugins/custom/lib/db.py
index 3bd2886bd..39d935d9a 100644
--- a/openlp/plugins/custom/lib/models.py
+++ b/openlp/plugins/custom/lib/db.py
@@ -22,18 +22,40 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
+"""
+The :mod:`db` module provides the database and schema that is the backend for
+the Custom plugin
+"""
-from sqlalchemy import create_engine
-from sqlalchemy.orm import scoped_session, sessionmaker, mapper
+from sqlalchemy import Column, Table, types
+from sqlalchemy.orm import mapper
-from openlp.plugins.custom.lib.meta import metadata
-from openlp.plugins.custom.lib.tables import *
-from openlp.plugins.custom.lib.classes import *
+from openlp.core.lib.db import BaseModel, init_db
+
+class CustomSlide(BaseModel):
+ """
+ CustomSlide model
+ """
+ pass
+
+def init_schema(url):
+ """
+ Setup the custom database connection and initialise the database schema
+
+ ``url``
+ The database to setup
+ """
+ session, metadata = init_db(url)
+
+ custom_slide_table = Table(u'custom_slide', metadata,
+ Column(u'id', types.Integer(), primary_key=True),
+ Column(u'title', types.Unicode(255), nullable=False),
+ Column(u'text', types.UnicodeText, nullable=False),
+ Column(u'credits', types.UnicodeText),
+ Column(u'theme_name', types.Unicode(128))
+ )
-def init_models(url):
- engine = create_engine(url)
- metadata.bind = engine
- session = scoped_session(sessionmaker(autoflush=True, autocommit=False,
- bind=engine))
mapper(CustomSlide, custom_slide_table)
+
+ metadata.create_all(checkfirst=True)
return session
diff --git a/openlp/plugins/custom/lib/manager.py b/openlp/plugins/custom/lib/manager.py
deleted file mode 100644
index 793cd8699..000000000
--- a/openlp/plugins/custom/lib/manager.py
+++ /dev/null
@@ -1,117 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2010 Raoul Snyman #
-# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
-# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin #
-# Thompson, Jon Tibble, Carsten Tinggaard #
-# --------------------------------------------------------------------------- #
-# 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 #
-###############################################################################
-
-import logging
-
-from PyQt4 import QtCore
-from sqlalchemy.exceptions import InvalidRequestError
-
-from openlp.core.utils import AppLocation
-from openlp.plugins.custom.lib.models import init_models, metadata, CustomSlide
-
-log = logging.getLogger(__name__)
-
-class CustomManager(object):
- """
- The Song Manager provides a central location for all database code. This
- class takes care of connecting to the database and running all the queries.
- """
- log.info(u'Custom manager loaded')
-
- def __init__(self):
- """
- Creates the connection to the database, and creates the tables if they
- don't exist.
- """
- log.debug(u'Custom Initialising')
- settings = QtCore.QSettings()
- settings.beginGroup(u'custom')
- self.db_url = u''
- db_type = unicode(
- settings.value(u'db type', QtCore.QVariant(u'sqlite')).toString())
- if db_type == u'sqlite':
- self.db_url = u'sqlite:///%s/custom.sqlite' % \
- AppLocation.get_section_data_path(u'custom')
- else:
- self.db_url = u'%s://%s:%s@%s/%s' % (db_type,
- unicode(settings.value(u'db username').toString()),
- unicode(settings.value(u'db password').toString()),
- unicode(settings.value(u'db hostname').toString()),
- unicode(settings.value(u'db database').toString()))
- self.session = init_models(self.db_url)
- metadata.create_all(checkfirst=True)
- settings.endGroup()
- log.debug(u'Custom Initialised')
-
- def get_all_slides(self):
- """
- Returns the details of a Custom Slide Show
- """
- return self.session.query(CustomSlide).order_by(CustomSlide.title).all()
-
- def save_slide(self, customslide):
- """
- Saves a Custom slide show to the database
- """
- log.debug(u'Custom Slide added')
- try:
- self.session.add(customslide)
- self.session.commit()
- log.debug(u'Custom Slide saved')
- return True
- except InvalidRequestError:
- self.session.rollback()
- log.exception(u'Custom Slide save failed')
- return False
-
- def get_custom(self, id=None):
- """
- Returns the details of a Custom Slide
- """
- if id is None:
- return CustomSlide()
- else:
- return self.session.query(CustomSlide).get(id)
-
- def delete_custom(self, id):
- """
- Delete a Custom slide show
- """
- if id != 0:
- customslide = self.get_custom(id)
- try:
- self.session.delete(customslide)
- self.session.commit()
- return True
- except InvalidRequestError:
- self.session.rollback()
- log.exception(u'Custom Slide deleton failed')
- return False
- else:
- return True
-
- def get_customs_for_theme(self, theme):
- return self.session.query(
- CustomSlide).filter(CustomSlide.theme_name == theme).all()
diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py
index a4fb54932..f2ac04c1b 100644
--- a/openlp/plugins/custom/lib/mediaitem.py
+++ b/openlp/plugins/custom/lib/mediaitem.py
@@ -29,6 +29,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, SongXMLParser, BaseListWithDnD, \
Receiver, ItemCapabilities, translate, check_item_selected
+from openlp.plugins.custom.lib.db import CustomSlide
log = logging.getLogger(__name__)
@@ -72,7 +73,8 @@ class CustomMediaItem(MediaManagerItem):
MediaManagerItem.requiredIcons(self)
def initialise(self):
- self.loadCustomListView(self.parent.custommanager.get_all_slides())
+ self.loadCustomListView(self.parent.custommanager.get_all_objects(
+ CustomSlide, CustomSlide.title))
#Called to redisplay the song list screen edith from a search
#or from the exit of the Song edit dialog. If remote editing is active
#Trigger it and clean up so it will not update again.
@@ -84,10 +86,10 @@ class CustomMediaItem(MediaManagerItem):
def loadCustomListView(self, list):
self.ListView.clear()
- for CustomSlide in list:
- custom_name = QtGui.QListWidgetItem(CustomSlide.title)
+ for customSlide in list:
+ custom_name = QtGui.QListWidgetItem(customSlide.title)
custom_name.setData(
- QtCore.Qt.UserRole, QtCore.QVariant(CustomSlide.id))
+ QtCore.Qt.UserRole, QtCore.QVariant(customSlide.id))
self.ListView.addItem(custom_name)
def onNewClick(self):
@@ -106,7 +108,7 @@ class CustomMediaItem(MediaManagerItem):
type of display is required.
"""
fields = customid.split(u':')
- valid = self.parent.custommanager.get_custom(fields[1])
+ valid = self.parent.custommanager.get_object(CustomSlide, fields[1])
if valid:
self.remoteCustom = fields[1]
self.remoteTriggered = fields[0]
@@ -134,11 +136,14 @@ class CustomMediaItem(MediaManagerItem):
if check_item_selected(self.ListView,
translate('CustomPlugin.MediaItem',
'You must select an item to delete.')):
- item = self.ListView.currentItem()
- item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
- self.parent.custommanager.delete_custom(item_id)
- row = self.ListView.row(item)
- self.ListView.takeItem(row)
+ row_list = [item.row() for item in self.ListView.selectedIndexes()]
+ row_list.sort(reverse=True)
+ id_list = [(item.data(QtCore.Qt.UserRole)).toInt()[0]
+ for item in self.ListView.selectedIndexes()]
+ for id in id_list:
+ self.parent.custommanager.delete_custom(id)
+ for row in row_list:
+ self.ListView.takeItem(row)
def generateSlideData(self, service_item, item=None):
raw_slides = []
@@ -158,7 +163,7 @@ class CustomMediaItem(MediaManagerItem):
service_item.add_capability(ItemCapabilities.AllowsEdit)
service_item.add_capability(ItemCapabilities.AllowsPreview)
service_item.add_capability(ItemCapabilities.AllowsLoop)
- customSlide = self.parent.custommanager.get_custom(item_id)
+ customSlide = self.parent.custommanager.get_object(CustomSlide, item_id)
title = customSlide.title
credit = customSlide.credits
service_item.editId = item_id
diff --git a/openlp/plugins/custom/lib/meta.py b/openlp/plugins/custom/lib/meta.py
deleted file mode 100644
index affa31969..000000000
--- a/openlp/plugins/custom/lib/meta.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2010 Raoul Snyman #
-# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
-# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin #
-# Thompson, Jon Tibble, Carsten Tinggaard #
-# --------------------------------------------------------------------------- #
-# 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 sqlalchemy import MetaData
-
-__all__ = ['session', 'metadata', 'engine']
-
-# SQLAlchemy database engine. Updated by model.init_model()
-engine = None
-
-# SQLAlchemy session manager. Updated by model.init_model()
-session = None
-
-# Global metadata. If you have multiple databases with overlapping table
-# names, you'll need a metadata for each database
-metadata = MetaData()
diff --git a/openlp/plugins/custom/lib/tables.py b/openlp/plugins/custom/lib/tables.py
deleted file mode 100644
index bb86d9d6d..000000000
--- a/openlp/plugins/custom/lib/tables.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2010 Raoul Snyman #
-# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
-# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin #
-# Thompson, Jon Tibble, Carsten Tinggaard #
-# --------------------------------------------------------------------------- #
-# 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 sqlalchemy import Column, Table, types
-
-from openlp.plugins.custom.lib.meta import metadata
-
-# Definition of the "custom slide" table
-custom_slide_table = Table(u'custom_slide', metadata,
- Column(u'id', types.Integer(), primary_key=True),
- Column(u'title', types.Unicode(255), nullable=False),
- Column(u'text', types.UnicodeText, nullable=False),
- Column(u'credits', types.UnicodeText),
- Column(u'theme_name', types.Unicode(128))
-)
diff --git a/openlp/plugins/images/__init__.py b/openlp/plugins/images/__init__.py
index 1a348a0df..58cfb69b5 100644
--- a/openlp/plugins/images/__init__.py
+++ b/openlp/plugins/images/__init__.py
@@ -22,3 +22,7 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
+"""
+The :mod:`images` module provides the Images plugin. The Images plugin
+provides the facility to display images from OpenLP.
+"""
diff --git a/openlp/plugins/images/imageplugin.py b/openlp/plugins/images/imageplugin.py
index 8e9f9e220..be3863bda 100644
--- a/openlp/plugins/images/imageplugin.py
+++ b/openlp/plugins/images/imageplugin.py
@@ -36,18 +36,9 @@ class ImagePlugin(Plugin):
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Images', u'1.9.2', plugin_helpers)
self.weight = -7
- self.icon = build_icon(u':/media/media_image.png')
+ self.icon = build_icon(u':/plugins/plugin_images.png')
self.status = PluginStatus.Active
- def initialise(self):
- log.info(u'Plugin Initialising')
- Plugin.initialise(self)
- self.insert_toolbox_item()
-
- def finalise(self):
- log.info(u'Plugin Finalise')
- self.remove_toolbox_item()
-
def get_settings_tab(self):
return ImageTab(self.name)
@@ -64,4 +55,4 @@ class ImagePlugin(Plugin):
'an image is selected any songs which are rendered will use the '
'selected image from the background instead of the one provied by '
'the theme.
')
- return about_text
\ No newline at end of file
+ return about_text
diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py
index 29985a9ed..ee7a22106 100644
--- a/openlp/plugins/images/lib/mediaitem.py
+++ b/openlp/plugins/images/lib/mediaitem.py
@@ -119,9 +119,10 @@ class ImageMediaItem(MediaManagerItem):
"""
if check_item_selected(self.ListView, translate('ImagePlugin.MediaItem',
'You must select an item to delete.')):
- items = self.ListView.selectedIndexes()
- for item in items:
- text = self.ListView.item(item.row())
+ row_list = [item.row() for item in self.ListView.selectedIndexes()]
+ row_list.sort(reverse=True)
+ for row in row_list:
+ text = self.ListView.item(row)
if text:
try:
os.remove(os.path.join(self.servicePath,
@@ -129,9 +130,9 @@ class ImageMediaItem(MediaManagerItem):
except OSError:
#if not present do not worry
pass
- self.ListView.takeItem(item.row())
- SettingsManager.set_list(self.settingsSection,
- self.settingsSection, self.getFileList())
+ self.ListView.takeItem(row)
+ SettingsManager.set_list(self.settingsSection,
+ self.settingsSection, self.getFileList())
def loadList(self, list):
for file in list:
@@ -169,17 +170,14 @@ class ImageMediaItem(MediaManagerItem):
return False
def onReplaceClick(self):
- if not self.ListView.selectedIndexes():
- QtGui.QMessageBox.information(self,
- translate('ImagePlugin.MediaItem', 'No item selected'),
- translate('ImagePlugin.MediaItem',
- 'You must select one item'))
- items = self.ListView.selectedIndexes()
- for item in items:
- bitem = self.ListView.item(item.row())
- filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())
- frame = QtGui.QImage(unicode(filename))
- self.parent.maindisplay.addImageWithText(frame)
+ if check_item_selected(self.ListView,
+ translate('ImagePlugin.MediaItem',
+ 'You must select an item to process.')):
+ item = self.buildServiceItem()
+ item.render()
+ self.parent.live_controller.displayManager. \
+ displayImage(item.get_rendered_frame(0)[u'display'])
+
def onPreviewClick(self):
MediaManagerItem.onPreviewClick(self)
diff --git a/openlp/plugins/media/__init__.py b/openlp/plugins/media/__init__.py
index 1a348a0df..28ea0e960 100644
--- a/openlp/plugins/media/__init__.py
+++ b/openlp/plugins/media/__init__.py
@@ -22,3 +22,9 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
+"""
+The :mod:`media` module provides the Media plugin which allows OpenLP to
+display videos. The media supported depends not only on the Python support
+but also extensively on the codecs installed on the underlying operating system
+being picked up and usable by Python.
+"""
diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py
index b6de22712..10c398912 100644
--- a/openlp/plugins/media/lib/mediaitem.py
+++ b/openlp/plugins/media/lib/mediaitem.py
@@ -29,7 +29,8 @@ import os
from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, BaseListWithDnD, build_icon, \
- ItemCapabilities, SettingsManager, translate, check_item_selected
+ ItemCapabilities, SettingsManager, translate, check_item_selected, \
+ context_menu_action
log = logging.getLogger(__name__)
@@ -73,13 +74,13 @@ class MediaMediaItem(MediaManagerItem):
self.hasNewIcon = False
self.hasEditIcon = False
-# def addListViewToToolBar(self):
-# MediaManagerItem.addListViewToToolBar(self)
-# self.ListView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
-# self.ListView.addAction(
-# context_menu_action(self.ListView, u':/slides/slide_blank.png',
-# translate('MediaPlugin.MediaItem', 'Replace Live Background'),
-# self.onReplaceClick))
+ def addListViewToToolBar(self):
+ MediaManagerItem.addListViewToToolBar(self)
+ self.ListView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
+ self.ListView.addAction(
+ context_menu_action(self.ListView, u':/slides/slide_blank.png',
+ translate('MediaPlugin.MediaItem', 'Replace Live Background'),
+ self.onReplaceClick))
def addEndHeaderBar(self):
self.ImageWidget = QtGui.QWidget(self)
@@ -92,24 +93,25 @@ class MediaMediaItem(MediaManagerItem):
self.ImageWidget.setSizePolicy(sizePolicy)
self.ImageWidget.setObjectName(u'ImageWidget')
#Replace backgrounds do not work at present so remove functionality.
-# self.blankButton = self.Toolbar.addToolbarButton(
-# u'Replace Background', u':/slides/slide_blank.png',
-# translate('MediaPlugin.MediaItem', 'Replace Live Background'),
-# self.onReplaceClick, False)
+ self.blankButton = self.Toolbar.addToolbarButton(
+ u'Replace Background', u':/slides/slide_blank.png',
+ translate('MediaPlugin.MediaItem', 'Replace Live Background'),
+ self.onReplaceClick, False)
# Add the song widget to the page layout
self.PageLayout.addWidget(self.ImageWidget)
-# def onReplaceClick(self):
+ def onReplaceClick(self):
# if self.background:
# self.background = False
# Receiver.send_message(u'videodisplay_stop')
# else:
# self.background = True
-# if not self.ListView.selectedIndexes():
-# QtGui.QMessageBox.information(self,
-# translate('MediaPlugin.MediaItem', 'No item selected'),
-# translate('MediaPlugin.MediaItem',
-# 'You must select one item'))
+ if check_item_selected(self.ListView,
+ translate('ImagePlugin.MediaItem',
+ 'You must select an item to process.')):
+ item = self.ListView.currentItem()
+ filename = unicode(item.data(QtCore.Qt.UserRole).toString())
+ self.parent.live_controller.displayManager.displayVideo(filename)
# items = self.ListView.selectedIndexes()
# for item in items:
# bitem = self.ListView.item(item.row())
@@ -143,9 +145,10 @@ class MediaMediaItem(MediaManagerItem):
"""
if check_item_selected(self.ListView, translate('MediaPlugin.MediaItem',
'You must select an item to delete.')):
- item = self.ListView.currentItem()
- row = self.ListView.row(item)
- self.ListView.takeItem(row)
+ row_list = [item.row() for item in self.ListView.selectedIndexes()]
+ row_list.sort(reverse=True)
+ for row in row_list:
+ self.ListView.takeItem(row)
SettingsManager.set_list(self.settingsSection,
self.settingsSection, self.getFileList())
diff --git a/openlp/plugins/media/mediaplugin.py b/openlp/plugins/media/mediaplugin.py
index f7c2c998f..24138a0f5 100644
--- a/openlp/plugins/media/mediaplugin.py
+++ b/openlp/plugins/media/mediaplugin.py
@@ -38,7 +38,7 @@ class MediaPlugin(Plugin):
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Media', u'1.9.2', plugin_helpers)
self.weight = -6
- self.icon = build_icon(u':/media/media_video.png')
+ self.icon = build_icon(u':/plugins/plugin_media.png')
# passed with drag and drop messages
self.dnd_id = u'Media'
self.status = PluginStatus.Active
@@ -67,15 +67,6 @@ class MediaPlugin(Plugin):
type = u''
return list, type
- def initialise(self):
- log.info(u'Plugin Initialising')
- Plugin.initialise(self)
- self.insert_toolbox_item()
-
- def finalise(self):
- log.info(u'Plugin Finalise')
- self.remove_toolbox_item()
-
def get_media_manager_item(self):
# Create the MediaManagerItem object
return MediaMediaItem(self, self.icon, self.name)
diff --git a/openlp/plugins/presentations/__init__.py b/openlp/plugins/presentations/__init__.py
index 1a348a0df..b7f26b39b 100644
--- a/openlp/plugins/presentations/__init__.py
+++ b/openlp/plugins/presentations/__init__.py
@@ -22,3 +22,7 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
+"""
+The :mod:`presentations` module provides the Presentations plugin which allows
+OpenLP to show presentations from most popular presentation packages.
+"""
diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py
index 52de42ca7..c4250f27a 100644
--- a/openlp/plugins/presentations/lib/impresscontroller.py
+++ b/openlp/plugins/presentations/lib/impresscontroller.py
@@ -41,10 +41,15 @@ from openlp.core.lib import resize_image
if os.name == u'nt':
from win32com.client import Dispatch
+ import pywintypes
else:
- import uno
- from com.sun.star.beans import PropertyValue
-
+ try:
+ import uno
+ from com.sun.star.beans import PropertyValue
+ uno_available = True
+ except ImportError:
+ uno_available = False
+
from PyQt4 import QtCore
from presentationcontroller import PresentationController, PresentationDocument
@@ -78,9 +83,7 @@ class ImpressController(PresentationController):
if os.name == u'nt':
return self.get_com_servicemanager() is not None
else:
- # If not windows, and we've got this far then probably
- # installed else the import uno would likely have failed
- return True
+ return uno_available
def start_process(self):
"""
@@ -322,7 +325,10 @@ class ImpressDocument(PresentationDocument):
Returns true if screen is blank
"""
log.debug(u'is blank OpenOffice')
- return self.control.isPaused()
+ if self.control:
+ return self.control.isPaused()
+ else:
+ return False
def stop_presentation(self):
log.debug(u'stop presentation OpenOffice')
diff --git a/openlp/plugins/presentations/lib/mediaitem.py b/openlp/plugins/presentations/lib/mediaitem.py
index 384d28c4a..ee50dd556 100644
--- a/openlp/plugins/presentations/lib/mediaitem.py
+++ b/openlp/plugins/presentations/lib/mediaitem.py
@@ -180,18 +180,22 @@ class PresentationMediaItem(MediaManagerItem):
if check_item_selected(self.ListView,
translate('PresentationPlugin.MediaItem',
'You must select an item to delete.')):
- item = self.ListView.currentItem()
- row = self.ListView.row(item)
- self.ListView.takeItem(row)
+ items = self.ListView.selectedIndexes()
+ row_list = [item.row() for item in items]
+ row_list.sort(reverse=True)
+ for item in items:
+ filepath = unicode(item.data(
+ QtCore.Qt.UserRole).toString())
+ #not sure of this has errors
+ #John please can you look at .
+ for cidx in self.controllers:
+ doc = self.controllers[cidx].add_doc(filepath)
+ doc.presentation_deleted()
+ doc.close_presentation()
+ for row in row_list:
+ self.ListView.takeItem(row)
SettingsManager.set_list(self.settingsSection,
self.settingsSection, self.getFileList())
- filepath = unicode(item.data(QtCore.Qt.UserRole).toString())
- #not sure of this has errors
- #John please can you look at .
- for cidx in self.controllers:
- doc = self.controllers[cidx].add_doc(filepath)
- doc.presentation_deleted()
- doc.close_presentation()
def generateSlideData(self, service_item, item=None):
items = self.ListView.selectedIndexes()
diff --git a/openlp/plugins/presentations/lib/pptviewcontroller.py b/openlp/plugins/presentations/lib/pptviewcontroller.py
index 10ab41fd0..e8f0d9390 100644
--- a/openlp/plugins/presentations/lib/pptviewcontroller.py
+++ b/openlp/plugins/presentations/lib/pptviewcontroller.py
@@ -27,7 +27,7 @@ import os
import logging
if os.name == u'nt':
- from ctypes import *
+ from ctypes import cdll
from ctypes.wintypes import RECT
from presentationcontroller import PresentationController, PresentationDocument
diff --git a/openlp/plugins/presentations/presentationplugin.py b/openlp/plugins/presentations/presentationplugin.py
index 9303d5921..22c7c554e 100644
--- a/openlp/plugins/presentations/presentationplugin.py
+++ b/openlp/plugins/presentations/presentationplugin.py
@@ -40,7 +40,7 @@ class PresentationPlugin(Plugin):
self.controllers = {}
Plugin.__init__(self, u'Presentations', u'1.9.2', plugin_helpers)
self.weight = -8
- self.icon = build_icon(u':/media/media_presentation.png')
+ self.icon = build_icon(u':/plugins/plugin_presentations.png')
self.status = PluginStatus.Active
def get_settings_tab(self):
@@ -64,7 +64,7 @@ class PresentationPlugin(Plugin):
controller = self.controllers[key]
if controller.enabled:
controller.kill()
- self.remove_toolbox_item()
+ Plugin.finalise(self)
def get_media_manager_item(self):
"""
diff --git a/openlp/plugins/remotes/__init__.py b/openlp/plugins/remotes/__init__.py
index 1a348a0df..59b771c0d 100644
--- a/openlp/plugins/remotes/__init__.py
+++ b/openlp/plugins/remotes/__init__.py
@@ -22,3 +22,7 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
+"""
+The :mod:`remotes` plugin allows OpenLP to be controlled from another machine
+over a network connection.
+"""
diff --git a/openlp/plugins/remotes/remoteplugin.py b/openlp/plugins/remotes/remoteplugin.py
index 7004207e4..808714fb3 100644
--- a/openlp/plugins/remotes/remoteplugin.py
+++ b/openlp/plugins/remotes/remoteplugin.py
@@ -25,7 +25,7 @@
import logging
-from openlp.core.lib import Plugin, translate
+from openlp.core.lib import Plugin, translate, build_icon
from openlp.plugins.remotes.lib import RemoteTab, HttpServer
log = logging.getLogger(__name__)
@@ -38,6 +38,7 @@ class RemotesPlugin(Plugin):
remotes constructor
"""
Plugin.__init__(self, u'Remotes', u'1.9.2', plugin_helpers)
+ self.icon = build_icon(u':/plugins/plugin_remote.png')
self.weight = -1
self.server = None
@@ -55,7 +56,7 @@ class RemotesPlugin(Plugin):
Tidy up and close down the http server
"""
log.debug(u'finalise')
- self.remove_toolbox_item()
+ Plugin.finalise(self)
if self.server:
self.server.close()
@@ -74,4 +75,4 @@ class RemotesPlugin(Plugin):
'provides the ability to send messages to a running version of '
'openlp on a different computer via a web browser or other app
'
'The Primary use for this would be to send alerts from a creche')
- return about_text
\ No newline at end of file
+ return about_text
diff --git a/openlp/plugins/songs/__init__.py b/openlp/plugins/songs/__init__.py
index 1a348a0df..4cd5537eb 100644
--- a/openlp/plugins/songs/__init__.py
+++ b/openlp/plugins/songs/__init__.py
@@ -22,3 +22,7 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
+"""
+The :mod:`songs` module provides the Songs plugin. The Songs plugin provides
+the main lyric projection function of OpenLP.
+"""
diff --git a/openlp/plugins/songs/forms/authorsdialog.py b/openlp/plugins/songs/forms/authorsdialog.py
index 972cab053..76e9dda55 100644
--- a/openlp/plugins/songs/forms/authorsdialog.py
+++ b/openlp/plugins/songs/forms/authorsdialog.py
@@ -24,6 +24,7 @@
###############################################################################
from PyQt4 import QtCore, QtGui
+
from openlp.core.lib import translate
class Ui_AuthorsDialog(object):
diff --git a/openlp/plugins/songs/forms/authorsform.py b/openlp/plugins/songs/forms/authorsform.py
index 5c5f019d9..c219b12ac 100644
--- a/openlp/plugins/songs/forms/authorsform.py
+++ b/openlp/plugins/songs/forms/authorsform.py
@@ -28,7 +28,6 @@ from PyQt4 import QtGui, QtCore
from openlp.core.lib import translate
from openlp.plugins.songs.forms.authorsdialog import Ui_AuthorsDialog
-
class AuthorsForm(QtGui.QDialog, Ui_AuthorsDialog):
"""
Class to control the Maintenance of Authors Dialog
diff --git a/openlp/plugins/songs/forms/editsongdialog.py b/openlp/plugins/songs/forms/editsongdialog.py
index 1d23a4df9..ce3291988 100644
--- a/openlp/plugins/songs/forms/editsongdialog.py
+++ b/openlp/plugins/songs/forms/editsongdialog.py
@@ -24,9 +24,8 @@
###############################################################################
from PyQt4 import QtCore, QtGui
-from openlp.core.lib import translate
-from openlp.core.lib import build_icon
+from openlp.core.lib import build_icon, translate
class Ui_EditSongDialog(object):
def setupUi(self, EditSongDialog):
diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py
index cbb79bff4..8c04bed0a 100644
--- a/openlp/plugins/songs/forms/editsongform.py
+++ b/openlp/plugins/songs/forms/editsongform.py
@@ -31,7 +31,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import SongXMLBuilder, SongXMLParser, Receiver, translate
from openlp.plugins.songs.forms import EditVerseForm
from openlp.plugins.songs.lib import VerseType
-from openlp.plugins.songs.lib.models import Song, Author, Topic, Book
+from openlp.plugins.songs.lib.db import Book, Song, Author, Topic
from editsongdialog import Ui_EditSongDialog
log = logging.getLogger(__name__)
@@ -118,7 +118,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.TopicRemoveButton.setEnabled(False)
def loadAuthors(self):
- authors = self.songmanager.get_authors()
+ authors = self.songmanager.get_all_objects(Author, Author.display_name)
self.AuthorsSelectionComboItem.clear()
self.AuthorsSelectionComboItem.addItem(u'')
for author in authors:
@@ -128,7 +128,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
row, QtCore.QVariant(author.id))
def loadTopics(self):
- topics = self.songmanager.get_topics()
+ topics = self.songmanager.get_all_objects(Topic, Topic.name)
self.SongTopicCombo.clear()
self.SongTopicCombo.addItem(u'')
for topic in topics:
@@ -137,7 +137,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.SongTopicCombo.setItemData(row, QtCore.QVariant(topic.id))
def loadBooks(self):
- books = self.songmanager.get_books()
+ books = self.songmanager.get_all_objects(Book, Book.name)
self.SongbookCombo.clear()
self.SongbookCombo.addItem(u'')
for book in books:
@@ -178,11 +178,12 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.loadAuthors()
self.loadTopics()
self.loadBooks()
- self.song = self.songmanager.get_song(id)
+ self.song = self.songmanager.get_object(Song, id)
self.TitleEditItem.setText(self.song.title)
title = self.song.search_title.split(u'@')
if self.song.song_book_id != 0:
- book_name = self.songmanager.get_book(self.song.song_book_id)
+ book_name = self.songmanager.get_object(Book,
+ self.song.song_book_id)
id = self.SongbookCombo.findText(
unicode(book_name.name), QtCore.Qt.MatchExactly)
if id == -1:
@@ -289,7 +290,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
QtGui.QMessageBox.Yes) == QtGui.QMessageBox.Yes:
author = Author.populate(first_name=text.rsplit(u' ', 1)[0],
last_name=text.rsplit(u' ', 1)[1], display_name=text)
- self.songmanager.save_author(author)
+ self.songmanager.save_object(author)
self.song.authors.append(author)
author_item = QtGui.QListWidgetItem(
unicode(author.display_name))
@@ -302,7 +303,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
return
elif item > 0:
item_id = (self.AuthorsSelectionComboItem.itemData(item)).toInt()[0]
- author = self.songmanager.get_author(item_id)
+ author = self.songmanager.get_object(Author, item_id)
self.song.authors.append(author)
author_item = QtGui.QListWidgetItem(unicode(author.display_name))
author_item.setData(QtCore.Qt.UserRole, QtCore.QVariant(author.id))
@@ -325,7 +326,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.AuthorRemoveButton.setEnabled(False)
item = self.AuthorsListView.currentItem()
author_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
- author = self.songmanager.get_author(author_id)
+ author = self.songmanager.get_object(Author, author_id)
self.song.authors.remove(author)
row = self.AuthorsListView.row(item)
self.AuthorsListView.takeItem(row)
@@ -341,7 +342,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
QtGui.QMessageBox.Yes) == QtGui.QMessageBox.Yes:
topic = Topic.populate(name=text)
- self.songmanager.save_topic(topic)
+ self.songmanager.save_object(topic)
self.song.topics.append(topic)
topic_item = QtGui.QListWidgetItem(unicode(topic.name))
topic_item.setData(QtCore.Qt.UserRole,
@@ -353,7 +354,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
return
elif item > 0:
item_id = (self.SongTopicCombo.itemData(item)).toInt()[0]
- topic = self.songmanager.get_topic(item_id)
+ topic = self.songmanager.get_object(Topic, item_id)
self.song.topics.append(topic)
topic_item = QtGui.QListWidgetItem(unicode(topic.name))
topic_item.setData(QtCore.Qt.UserRole, QtCore.QVariant(topic.id))
@@ -375,7 +376,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.TopicRemoveButton.setEnabled(False)
item = self.TopicsListView.currentItem()
topic_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
- topic = self.songmanager.get_topic(topic_id)
+ topic = self.songmanager.get_object(Topic, topic_id)
self.song.topics.remove(topic)
row = self.TopicsListView.row(item)
self.TopicsListView.takeItem(row)
@@ -391,12 +392,12 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
QtGui.QMessageBox.Yes) == QtGui.QMessageBox.Yes:
book = Book.populate(name=text)
- self.songmanager.save_book(book)
+ self.songmanager.save_object(book)
self.song.book = book
self.loadBooks()
else:
return
- elif item > 1:
+ elif item >= 1:
item = int(self.SongbookCombo.currentIndex())
self.song.song_book_id = \
(self.SongbookCombo.itemData(item)).toInt()[0]
@@ -630,7 +631,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
if self._validate_song():
self.processLyrics()
self.processTitle()
- self.songmanager.save_song(self.song)
+ self.songmanager.save_object(self.song)
return True
return False
diff --git a/openlp/plugins/songs/forms/songbookdialog.py b/openlp/plugins/songs/forms/songbookdialog.py
index eb791cd69..2ab223b34 100644
--- a/openlp/plugins/songs/forms/songbookdialog.py
+++ b/openlp/plugins/songs/forms/songbookdialog.py
@@ -24,6 +24,7 @@
###############################################################################
from PyQt4 import QtCore, QtGui
+
from openlp.core.lib import translate
class Ui_SongBookDialog(object):
diff --git a/openlp/plugins/songs/forms/songbookform.py b/openlp/plugins/songs/forms/songbookform.py
index fd447db22..6316a8002 100644
--- a/openlp/plugins/songs/forms/songbookform.py
+++ b/openlp/plugins/songs/forms/songbookform.py
@@ -28,7 +28,6 @@ from PyQt4 import QtGui
from openlp.core.lib import translate
from openlp.plugins.songs.forms.songbookdialog import Ui_SongBookDialog
-
class SongBookForm(QtGui.QDialog, Ui_SongBookDialog):
"""
Class documentation goes here.
diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py
index 8a830d720..09db3dcb8 100644
--- a/openlp/plugins/songs/forms/songimportform.py
+++ b/openlp/plugins/songs/forms/songimportform.py
@@ -30,7 +30,7 @@ from PyQt4 import QtCore, QtGui
from songimportwizard import Ui_SongImportWizard
from openlp.core.lib import Receiver, SettingsManager, translate
#from openlp.core.utils import AppLocation
-from openlp.plugins.songs.lib.manager import SongFormat
+from openlp.plugins.songs.lib import SongFormat
log = logging.getLogger(__name__)
diff --git a/openlp/plugins/songs/forms/songmaintenanceform.py b/openlp/plugins/songs/forms/songmaintenanceform.py
index 4a666c3c5..54a8d539f 100644
--- a/openlp/plugins/songs/forms/songmaintenanceform.py
+++ b/openlp/plugins/songs/forms/songmaintenanceform.py
@@ -25,12 +25,10 @@
from PyQt4 import QtGui, QtCore
-from openlp.plugins.songs.lib.classes import Author, Book, Topic
-from songmaintenancedialog import Ui_SongMaintenanceDialog
-from authorsform import AuthorsForm
-from topicsform import TopicsForm
-from songbookform import SongBookForm
from openlp.core.lib import translate
+from openlp.plugins.songs.forms import AuthorsForm, TopicsForm, SongBookForm
+from openlp.plugins.songs.lib.db import Author, Book, Topic
+from songmaintenancedialog import Ui_SongMaintenanceDialog
class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
"""
@@ -81,17 +79,17 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
else:
return -1
- def _deleteItem(self, list_widget, get_func, del_func, reset_func,
- dlg_title, del_text, err_text, sel_text):
+ def _deleteItem(self, item_class, list_widget, reset_func, dlg_title,
+ del_text, err_text, sel_text):
item_id = self._getCurrentItemId(list_widget)
if item_id != -1:
- item = get_func(item_id)
+ item = self.songmanager.get_object(item_class, item_id)
if item and len(item.songs) == 0:
if QtGui.QMessageBox.warning(self, dlg_title, del_text,
QtGui.QMessageBox.StandardButtons(
QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)
) == QtGui.QMessageBox.Yes:
- del_func(item.id)
+ self.songmanager.delete_object(item_class, item.id)
reset_func()
else:
QtGui.QMessageBox.critical(self, dlg_title, err_text)
@@ -100,7 +98,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def resetAuthors(self):
self.AuthorsListWidget.clear()
- authors = self.songmanager.get_authors()
+ authors = self.songmanager.get_all_objects(Author, Author.display_name)
for author in authors:
if author.display_name:
author_name = QtGui.QListWidgetItem(author.display_name)
@@ -112,7 +110,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def resetTopics(self):
self.TopicsListWidget.clear()
- topics = self.songmanager.get_topics()
+ topics = self.songmanager.get_all_objects(Topic, Topic.name)
for topic in topics:
topic_name = QtGui.QListWidgetItem(topic.name)
topic_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(topic.id))
@@ -120,7 +118,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def resetBooks(self):
self.BooksListWidget.clear()
- books = self.songmanager.get_books()
+ books = self.songmanager.get_all_objects(Book, Book.name)
for book in books:
book_name = QtGui.QListWidgetItem(book.name)
book_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(book.id))
@@ -133,7 +131,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
first_name=unicode(self.authorform.FirstNameEdit.text()),
last_name=unicode(self.authorform.LastNameEdit.text()),
display_name=unicode(self.authorform.DisplayEdit.text()))
- if self.songmanager.save_author(author):
+ if self.songmanager.save_object(author):
self.resetAuthors()
else:
QtGui.QMessageBox.critical(
@@ -145,7 +143,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def onTopicAddButtonClick(self):
if self.topicform.exec_():
topic = Topic.populate(name=unicode(self.topicform.NameEdit.text()))
- if self.songmanager.save_topic(topic):
+ if self.songmanager.save_object(topic):
self.resetTopics()
else:
QtGui.QMessageBox.critical(
@@ -159,7 +157,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
book = Book.populate(
name=unicode(self.bookform.NameEdit.text()),
publisher=unicode(self.bookform.PublisherEdit.text()))
- if self.songmanager.save_book(book):
+ if self.songmanager.save_object(book):
self.resetBooks()
else:
QtGui.QMessageBox.critical(
@@ -171,7 +169,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def onAuthorEditButtonClick(self):
author_id = self._getCurrentItemId(self.AuthorsListWidget)
if author_id != -1:
- author = self.songmanager.get_author(author_id)
+ author = self.songmanager.get_object(Author, author_id)
# Just make sure none of the fields is None
if author.first_name is None:
author.first_name = u''
@@ -189,7 +187,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
author.last_name = unicode(self.authorform.LastNameEdit.text())
author.display_name = unicode(
self.authorform.DisplayEdit.text())
- if self.songmanager.save_author(author):
+ if self.songmanager.save_object(author):
self.resetAuthors()
else:
QtGui.QMessageBox.critical(
@@ -201,11 +199,11 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def onTopicEditButtonClick(self):
topic_id = self._getCurrentItemId(self.TopicsListWidget)
if topic_id != -1:
- topic = self.songmanager.get_topic(topic_id)
+ topic = self.songmanager.get_object(Topic, topic_id)
self.topicform.NameEdit.setText(topic.name)
if self.topicform.exec_(False):
topic.name = unicode(self.topicform.NameEdit.text())
- if self.songmanager.save_topic(topic):
+ if self.songmanager.save_object(topic):
self.resetTopics()
else:
QtGui.QMessageBox.critical(
@@ -217,13 +215,13 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def onBookEditButtonClick(self):
book_id = self._getCurrentItemId(self.BooksListWidget)
if book_id != -1:
- book = self.songmanager.get_book(book_id)
+ book = self.songmanager.get_object(Book, book_id)
self.bookform.NameEdit.setText(book.name)
self.bookform.PublisherEdit.setText(book.publisher)
if self.bookform.exec_(False):
book.name = unicode(self.bookform.NameEdit.text())
book.publisher = unicode(self.bookform.PublisherEdit.text())
- if self.songmanager.save_book(book):
+ if self.songmanager.save_object(book):
self.resetBooks()
else:
QtGui.QMessageBox.critical(
@@ -236,11 +234,9 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
"""
Delete the author if the author is not attached to any songs
"""
- self._deleteItem(
- self.AuthorsListWidget, self.songmanager.get_author,
- self.songmanager.delete_author, self.resetAuthors,
+ self._deleteItem(Author, self.AuthorsListWidget, self.resetAuthors,
translate('SongsPlugin.SongMaintenanceForm', 'Delete Author'),
- translate('SongsPlugin.SongMaintenanceForm',
+ translate('SongsPlugin.SongMaintenanceForm',
'Are you sure you want to delete the selected author?'),
translate('SongsPlugin.SongMaintenanceForm',
'This author can\'t be deleted, they are currently '
@@ -252,13 +248,11 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
"""
Delete the Book is the Book is not attached to any songs
"""
- self._deleteItem(
- self.TopicsListWidget, self.songmanager.get_topic,
- self.songmanager.delete_topic, self.resetTopics,
+ self._deleteItem(Topic, self.TopicsListWidget, self.resetTopics,
translate('SongsPlugin.SongMaintenanceForm', 'Delete Topic'),
- translate('SongsPlugin.SongMaintenanceForm',
+ translate('SongsPlugin.SongMaintenanceForm',
'Are you sure you want to delete the selected topic?'),
- translate('SongsPlugin.SongMaintenanceForm',
+ translate('SongsPlugin.SongMaintenanceForm',
'This topic can\'t be deleted, it is currently '
'assigned to at least one song.'),
translate('SongsPlugin.SongMaintenanceForm',
@@ -268,13 +262,11 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
"""
Delete the Book is the Book is not attached to any songs
"""
- self._deleteItem(
- self.BooksListWidget, self.songmanager.get_book,
- self.songmanager.delete_book, self.resetBooks,
+ self._deleteItem(Book, self.BooksListWidget, self.resetBooks,
translate('SongsPlugin.SongMaintenanceForm', 'Delete Book'),
translate('SongsPlugin.SongMaintenanceForm',
'Are you sure you want to delete the selected book?'),
- translate('SongsPlugin.SongMaintenanceForm',
+ translate('SongsPlugin.SongMaintenanceForm',
'This book can\'t be deleted, it is currently '
'assigned to at least one song.'),
- translate('SongsPlugin.SongMaintenanceForm', 'No book selected!'))
+ translate('SongsPlugin.SongMaintenanceForm', u'No book selected!'))
diff --git a/openlp/plugins/songs/forms/topicsdialog.py b/openlp/plugins/songs/forms/topicsdialog.py
index 463367683..6ee06c9c0 100644
--- a/openlp/plugins/songs/forms/topicsdialog.py
+++ b/openlp/plugins/songs/forms/topicsdialog.py
@@ -24,6 +24,7 @@
###############################################################################
from PyQt4 import QtCore, QtGui
+
from openlp.core.lib import translate
class Ui_TopicsDialog(object):
diff --git a/openlp/plugins/songs/forms/topicsform.py b/openlp/plugins/songs/forms/topicsform.py
index cf93ff0f2..51d649ebe 100644
--- a/openlp/plugins/songs/forms/topicsform.py
+++ b/openlp/plugins/songs/forms/topicsform.py
@@ -28,7 +28,6 @@ from PyQt4 import QtGui
from openlp.core.lib import translate
from openlp.plugins.songs.forms.topicsdialog import Ui_TopicsDialog
-
class TopicsForm(QtGui.QDialog, Ui_TopicsDialog):
"""
Class documentation goes here.
diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py
index dddb23b4e..8c07c31c7 100644
--- a/openlp/plugins/songs/lib/__init__.py
+++ b/openlp/plugins/songs/lib/__init__.py
@@ -25,6 +25,52 @@
from openlp.core.lib import translate
+#from openlp.plugins.songs.lib import OpenLyricsSong, OpenSongSong, CCLISong, \
+# CSVSong
+
+class SongFormat(object):
+ """
+ This is a special enumeration class that holds the various types of songs,
+ plus a few helper functions to facilitate generic handling of song types
+ for importing.
+ """
+ Unknown = -1
+ OpenLyrics = 0
+ OpenSong = 1
+ CCLI = 2
+ CSV = 3
+
+ @staticmethod
+ def get_class(id):
+ """
+ Return the appropriate imeplementation class.
+
+ ``id``
+ The song format.
+ """
+# if id == SongFormat.OpenLyrics:
+# return OpenLyricsSong
+# elif id == SongFormat.OpenSong:
+# return OpenSongSong
+# elif id == SongFormat.CCLI:
+# return CCLISong
+# elif id == SongFormat.CSV:
+# return CSVSong
+# else:
+ return None
+
+ @staticmethod
+ def list():
+ """
+ Return a list of the supported song formats.
+ """
+ return [
+ SongFormat.OpenLyrics,
+ SongFormat.OpenSong,
+ SongFormat.CCLI,
+ SongFormat.CSV
+ ]
+
class VerseType(object):
"""
VerseType provides an enumeration for the tags that may be associated
@@ -91,7 +137,6 @@ class VerseType(object):
unicode(VerseType.to_string(VerseType.Other)).lower():
return VerseType.Other
-from manager import SongManager
from songstab import SongsTab
from mediaitem import SongMediaItem
from songimport import SongImport
diff --git a/openlp/plugins/songs/lib/classes.py b/openlp/plugins/songs/lib/classes.py
deleted file mode 100644
index c465588a4..000000000
--- a/openlp/plugins/songs/lib/classes.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2010 Raoul Snyman #
-# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
-# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin #
-# Thompson, Jon Tibble, Carsten Tinggaard #
-# --------------------------------------------------------------------------- #
-# 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.core.lib import BaseModel
-
-class Author(BaseModel):
- """
- Author model
- """
- pass
-
-class Book(BaseModel):
- """
- Book model
- """
- def __repr__(self):
- return u'' % (
- str(self.id), self.name, self.publisher)
-
-class Song(BaseModel):
- """
- Song model
- """
- pass
-
-class Topic(BaseModel):
- """
- Topic model
- """
- pass
diff --git a/openlp/plugins/songs/lib/db.py b/openlp/plugins/songs/lib/db.py
new file mode 100644
index 000000000..655043144
--- /dev/null
+++ b/openlp/plugins/songs/lib/db.py
@@ -0,0 +1,151 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2010 Raoul Snyman #
+# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
+# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin #
+# Thompson, Jon Tibble, Carsten Tinggaard #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+The :mod:`db` module provides the database and schema that is the backend for
+the Songs plugin
+"""
+
+from sqlalchemy import Column, ForeignKey, Index, Table, types
+from sqlalchemy.orm import mapper, relation
+
+from openlp.core.lib.db import BaseModel, init_db
+
+class Author(BaseModel):
+ """
+ Author model
+ """
+ pass
+
+class Book(BaseModel):
+ """
+ Book model
+ """
+ def __repr__(self):
+ return u'' % (
+ str(self.id), self.name, self.publisher)
+
+class Song(BaseModel):
+ """
+ Song model
+ """
+ pass
+
+class Topic(BaseModel):
+ """
+ Topic model
+ """
+ pass
+
+def init_schema(url):
+ """
+ Setup the songs database connection and initialise the database schema
+
+ ``url``
+ The database to setup
+ """
+ session, metadata = init_db(url, auto_flush=False)
+
+ # Definition of the "authors" table
+ authors_table = Table(u'authors', metadata,
+ Column(u'id', types.Integer, primary_key=True),
+ Column(u'first_name', types.Unicode(128)),
+ Column(u'last_name', types.Unicode(128)),
+ Column(u'display_name', types.Unicode(255), nullable=False)
+ )
+
+ # Definition of the "song_books" table
+ song_books_table = Table(u'song_books', metadata,
+ Column(u'id', types.Integer, primary_key=True),
+ Column(u'name', types.Unicode(128), nullable=False),
+ Column(u'publisher', types.Unicode(128))
+ )
+
+ # Definition of the "songs" table
+ songs_table = Table(u'songs', metadata,
+ Column(u'id', types.Integer, primary_key=True),
+ Column(u'song_book_id', types.Integer,
+ ForeignKey(u'song_books.id'), default=0),
+ Column(u'title', types.Unicode(255), nullable=False),
+ Column(u'lyrics', types.UnicodeText, nullable=False),
+ Column(u'verse_order', types.Unicode(128)),
+ Column(u'copyright', types.Unicode(255)),
+ Column(u'comments', types.UnicodeText),
+ Column(u'ccli_number', types.Unicode(64)),
+ Column(u'song_number', types.Unicode(64)),
+ Column(u'theme_name', types.Unicode(128)),
+ Column(u'search_title', types.Unicode(255), index=True, nullable=False),
+ Column(u'search_lyrics', types.UnicodeText, index=True, nullable=False)
+ )
+
+ # Definition of the "topics" table
+ topics_table = Table(u'topics', metadata,
+ Column(u'id', types.Integer, primary_key=True),
+ Column(u'name', types.Unicode(128), nullable=False)
+ )
+
+ # Definition of the "authors_songs" table
+ authors_songs_table = Table(u'authors_songs', metadata,
+ Column(u'author_id', types.Integer,
+ ForeignKey(u'authors.id'), primary_key=True),
+ Column(u'song_id', types.Integer,
+ ForeignKey(u'songs.id'), primary_key=True)
+ )
+
+ # Definition of the "songs_topics" table
+ songs_topics_table = Table(u'songs_topics', metadata,
+ Column(u'song_id', types.Integer,
+ ForeignKey(u'songs.id'), primary_key=True),
+ Column(u'topic_id', types.Integer,
+ ForeignKey(u'topics.id'), primary_key=True)
+ )
+
+ # Define table indexes
+ Index(u'authors_id', authors_table.c.id)
+ Index(u'authors_display_name_id', authors_table.c.display_name,
+ authors_table.c.id)
+ Index(u'song_books_id', song_books_table.c.id)
+ Index(u'songs_id', songs_table.c.id)
+ Index(u'topics_id', topics_table.c.id)
+ Index(u'authors_songs_author', authors_songs_table.c.author_id,
+ authors_songs_table.c.song_id)
+ Index(u'authors_songs_song', authors_songs_table.c.song_id,
+ authors_songs_table.c.author_id)
+ Index(u'topics_song_topic', songs_topics_table.c.topic_id,
+ songs_topics_table.c.song_id)
+ Index(u'topics_song_song', songs_topics_table.c.song_id,
+ songs_topics_table.c.topic_id)
+
+ mapper(Author, authors_table)
+ mapper(Book, song_books_table)
+ mapper(Song, songs_table,
+ properties={'authors': relation(Author, backref='songs',
+ secondary=authors_songs_table),
+ 'book': relation(Book, backref='songs'),
+ 'topics': relation(Topic, backref='songs',
+ secondary=songs_topics_table)})
+ mapper(Topic, topics_table)
+
+ metadata.create_all(checkfirst=True)
+ return session
diff --git a/openlp/plugins/songs/lib/manager.py b/openlp/plugins/songs/lib/manager.py
deleted file mode 100644
index 4276303d5..000000000
--- a/openlp/plugins/songs/lib/manager.py
+++ /dev/null
@@ -1,318 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2010 Raoul Snyman #
-# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
-# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin #
-# Thompson, Jon Tibble, Carsten Tinggaard #
-# --------------------------------------------------------------------------- #
-# 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 #
-###############################################################################
-
-import logging
-
-from PyQt4 import QtCore
-from sqlalchemy.exceptions import InvalidRequestError
-
-from openlp.core.utils import AppLocation
-from openlp.plugins.songs.lib.models import init_models, metadata, Song, \
- Author, Topic, Book
-#from openlp.plugins.songs.lib import OpenLyricsSong, OpenSongSong, CCLISong, \
-# CSVSong
-
-log = logging.getLogger(__name__)
-
-class SongFormat(object):
- """
- This is a special enumeration class that holds the various types of songs,
- plus a few helper functions to facilitate generic handling of song types
- for importing.
- """
- Unknown = -1
- OpenLyrics = 0
- OpenSong = 1
- CCLI = 2
- CSV = 3
-
- @staticmethod
- def get_class(id):
- """
- Return the appropriate imeplementation class.
-
- ``id``
- The song format.
- """
-# if id == SongFormat.OpenLyrics:
-# return OpenLyricsSong
-# elif id == SongFormat.OpenSong:
-# return OpenSongSong
-# elif id == SongFormat.CCLI:
-# return CCLISong
-# elif id == SongFormat.CSV:
-# return CSVSong
-# else:
- return None
-
- @staticmethod
- def list():
- """
- Return a list of the supported song formats.
- """
- return [
- SongFormat.OpenLyrics,
- SongFormat.OpenSong,
- SongFormat.CCLI,
- SongFormat.CSV
- ]
-
-
-class SongManager(object):
- """
- The Song Manager provides a central location for all database code. This
- class takes care of connecting to the database and running all the queries.
- """
- log.info(u'Song manager loaded')
-
- def __init__(self):
- """
- Creates the connection to the database, and creates the tables if they
- don't exist.
- """
- log.debug(u'Song Initialising')
- settings = QtCore.QSettings()
- settings.beginGroup(u'songs')
- self.db_url = u''
- db_type = unicode(settings.value(u'db type',
- QtCore.QVariant(u'sqlite')).toString())
- if db_type == u'sqlite':
- self.db_url = u'sqlite:///%s/songs.sqlite' % \
- AppLocation.get_section_data_path(u'songs')
- else:
- self.db_url = u'%s://%s:%s@%s/%s' % (db_type,
- unicode(settings.value(
- u'db username', QtCore.QVariant(u'')).toString()),
- unicode(settings.value(
- u'db password', QtCore.QVariant(u'')).toString()),
- unicode(settings.value(
- u'db hostname', QtCore.QVariant(u'')).toString()),
- unicode(settings.value(
- u'db database', QtCore.QVariant(u'')).toString()))
- self.session = init_models(self.db_url)
- metadata.create_all(checkfirst=True)
- settings.endGroup()
- log.debug(u'Song Initialised')
-
- def get_songs(self):
- """
- Returns the details of a song
- """
- return self.session.query(Song).order_by(Song.title).all()
-
- def search_song_title(self, keywords):
- """
- Searches the song title for keywords.
- """
- return self.session.query(Song).filter(
- Song.search_title.like(u'%' + keywords + u'%')).order_by(
- Song.search_title.asc()).all()
-
- def search_song_lyrics(self, keywords):
- """
- Searches the song lyrics for keywords.
- """
- return self.session.query(Song).filter(
- Song.search_lyrics.like(u'%' + keywords + u'%')).order_by(
- Song.search_lyrics.asc()).all()
-
- def get_song_from_author(self, keywords):
- """
- Searches the song authors for keywords.
- """
- return self.session.query(Author).filter(Author.display_name.like(
- u'%' + keywords + u'%')).order_by(Author.display_name.asc()).all()
-
- def get_song(self, id=None):
- """
- Returns the details of a song
- """
- if id is None:
- return Song()
- else:
- return self.session.query(Song).get(id)
-
- def save_song(self, song):
- """
- Saves a song to the database
- """
- try:
- self.session.add(song)
- self.session.commit()
- return True
- except InvalidRequestError:
- log.exception(u'Could not save song to song database')
- self.session.rollback()
- return False
-
- def delete_song(self, songid):
- song = self.get_song(songid)
- try:
- self.session.delete(song)
- self.session.commit()
- return True
- except InvalidRequestError:
- self.session.rollback()
- log.exception(u'Could not delete song from song database')
- return False
-
- def get_authors(self):
- """
- Returns a list of all the authors
- """
- return self.session.query(Author).order_by(Author.display_name).all()
-
- def get_author(self, id):
- """
- Details of the Author
- """
- return self.session.query(Author).get(id)
-
- def get_author_by_name(self, name):
- """
- Get author by display name
- """
- return self.session.query(Author).filter_by(display_name=name).first()
-
- def save_author(self, author):
- """
- Save the Author and refresh the cache
- """
- try:
- self.session.add(author)
- self.session.commit()
- return True
- except InvalidRequestError:
- self.session.rollback()
- log.exception(u'Could not save author to song database')
- return False
-
- def delete_author(self, authorid):
- """
- Delete the author
- """
- author = self.get_author(authorid)
- try:
- self.session.delete(author)
- self.session.commit()
- return True
- except InvalidRequestError:
- self.session.rollback()
- log.exception(u'Could not delete author from song database')
- return False
-
- def get_topics(self):
- """
- Returns a list of all the topics
- """
- return self.session.query(Topic).order_by(Topic.name).all()
-
- def get_topic(self, id):
- """
- Details of the Topic
- """
- return self.session.query(Topic).get(id)
-
- def get_topic_by_name(self, name):
- """
- Get topic by name
- """
- return self.session.query(Topic).filter_by(name=name).first()
-
- def save_topic(self, topic):
- """
- Save the Topic
- """
- try:
- self.session.add(topic)
- self.session.commit()
- return True
- except InvalidRequestError:
- self.session.rollback()
- log.exception(u'Could not save topic to song database')
- return False
-
- def delete_topic(self, topicid):
- """
- Delete the topic
- """
- topic = self.get_topic(topicid)
- try:
- self.session.delete(topic)
- self.session.commit()
- return True
- except InvalidRequestError:
- self.session.rollback()
- log.exception(u'Could not delete topic from song database')
- return False
-
- def get_books(self):
- """
- Returns a list of all the Books
- """
- return self.session.query(Book).order_by(Book.name).all()
-
- def get_book(self, id):
- """
- Details of the Books
- """
- return self.session.query(Book).get(id)
-
- def get_book_by_name(self, name):
- """
- Get book by name
- """
- return self.session.query(Book).filter_by(name=name).first()
-
- def save_book(self, book):
- """
- Save the Book
- """
- try:
- self.session.add(book)
- self.session.commit()
- return True
- except InvalidRequestError:
- self.session.rollback()
- log.exception(u'Could not save book to song database')
- return False
-
- def delete_book(self, bookid):
- """
- Delete the Book
- """
- book = self.get_book(bookid)
- try:
- self.session.delete(book)
- self.session.commit()
- return True
- except InvalidRequestError:
- self.session.rollback()
- log.exception(u'Could not delete book from song database')
- return False
-
- def get_songs_for_theme(self, theme):
- return self.session.query(Song).filter(Song.theme_name == theme).all()
-
diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py
index 385e391d3..4557f53fa 100644
--- a/openlp/plugins/songs/lib/mediaitem.py
+++ b/openlp/plugins/songs/lib/mediaitem.py
@@ -31,6 +31,7 @@ from openlp.core.lib import MediaManagerItem, SongXMLParser, \
BaseListWithDnD, Receiver, ItemCapabilities, translate, check_item_selected
from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
ImportWizardForm
+from openlp.plugins.songs.lib.db import Song
log = logging.getLogger(__name__)
@@ -164,18 +165,21 @@ class SongMediaItem(MediaManagerItem):
search_type = self.SearchTypeComboBox.currentIndex()
if search_type == 0:
log.debug(u'Titles Search')
- search_results = self.parent.manager.search_song_title(
- search_keywords)
+ search_results = self.parent.manager.get_all_objects_filtered(Song,
+ Song.search_title.like(u'%' + search_keywords + u'%'),
+ Song.search_title.asc())
self.displayResultsSong(search_results)
elif search_type == 1:
log.debug(u'Lyrics Search')
- search_results = self.parent.manager.search_song_lyrics(
- search_keywords)
+ search_results = self.parent.manager.get_all_objects_filtered(Song,
+ Song.search_lyrics.like(u'%' + search_keywords + u'%'),
+ Song.search_lyrics.asc())
self.displayResultsSong(search_results)
elif search_type == 2:
log.debug(u'Authors Search')
- search_results = self.parent.manager.get_song_from_author(
- search_keywords)
+ search_results = self.parent.manager.get_all_objects_filtered(
+ Author, Author.display_name.like(u'%' + search_keywords + u'%'),
+ Author.display_name.asc())
self.displayResultsAuthor(search_results)
#Called to redisplay the song list screen edith from a search
#or from the exit of the Song edit dialog. If remote editing is active
@@ -268,7 +272,7 @@ class SongMediaItem(MediaManagerItem):
type of display is required.
"""
fields = songid.split(u':')
- valid = self.parent.manager.get_song(fields[1])
+ valid = self.parent.manager.get_object(Song, fields[1])
if valid:
self.remoteSong = fields[1]
self.remoteTriggered = fields[0]
@@ -310,7 +314,7 @@ class SongMediaItem(MediaManagerItem):
return
for item in items:
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
- self.parent.manager.delete_song(item_id)
+ self.parent.manager.delete_object(Song, item_id)
self.onSearchTextButtonClick()
def generateSlideData(self, service_item, item=None):
@@ -331,7 +335,7 @@ class SongMediaItem(MediaManagerItem):
service_item.add_capability(ItemCapabilities.AllowsEdit)
service_item.add_capability(ItemCapabilities.AllowsPreview)
service_item.add_capability(ItemCapabilities.AllowsLoop)
- song = self.parent.manager.get_song(item_id)
+ song = self.parent.manager.get_object(Song, item_id)
service_item.theme = song.theme_name
service_item.editId = item_id
if song.lyrics.startswith(u'= start_date.toPyDate()) \
.filter(SongUsageItem.usagedate < end_date.toPyDate()) \
- .order_by(SongUsageItem.usagedate, SongUsageItem.usagetime ).all()
-
- def insert_songusage(self, songusageitem):
- """
- Saves an SongUsage to the database
- """
- log.debug(u'SongUsage added')
- try:
- self.session.add(songusageitem)
- self.session.commit()
- return True
- except InvalidRequestError:
- self.session.rollback()
- log.exception(u'SongUsage item failed to save')
- return False
-
- def get_songusage(self, id=None):
- """
- Returns the details of a SongUsage
- """
- if id is None:
- return SongUsageItem()
- else:
- return self.session.query(SongUsageItem).get(id)
-
- def delete_songusage(self, id):
- """
- Delete a SongUsage record
- """
- if id != 0:
- songusageitem = self.get_songusage(id)
- try:
- self.session.delete(songusageitem)
- self.session.commit()
- return True
- except InvalidRequestError:
- self.session.rollback()
- log.exception(u'SongUsage Item failed to delete')
- return False
- else:
- return True
-
- def delete_all(self):
- """
- Delete all Song Usage records
- """
- try:
- self.session.query(SongUsageItem).delete(synchronize_session=False)
- self.session.commit()
- return True
- except InvalidRequestError:
- self.session.rollback()
- log.exception(u'Failed to delete all Song Usage items')
- return False
+ .order_by(SongUsageItem.usagedate, SongUsageItem.usagetime).all()
def delete_to_date(self, date):
"""
Delete SongUsage records before given date
"""
try:
- self.session.query(SongUsageItem)\
- .filter(SongUsageItem.usagedate <= date)\
+ self.session.query(SongUsageItem) \
+ .filter(SongUsageItem.usagedate <= date) \
.delete(synchronize_session=False)
self.session.commit()
return True
@@ -146,4 +79,3 @@ class SongUsageManager(object):
self.session.rollback()
log.exception(u'Failed to delete all Song Usage items to %s' % date)
return False
-
diff --git a/openlp/plugins/songusage/lib/meta.py b/openlp/plugins/songusage/lib/meta.py
deleted file mode 100644
index affa31969..000000000
--- a/openlp/plugins/songusage/lib/meta.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2010 Raoul Snyman #
-# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
-# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin #
-# Thompson, Jon Tibble, Carsten Tinggaard #
-# --------------------------------------------------------------------------- #
-# 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 sqlalchemy import MetaData
-
-__all__ = ['session', 'metadata', 'engine']
-
-# SQLAlchemy database engine. Updated by model.init_model()
-engine = None
-
-# SQLAlchemy session manager. Updated by model.init_model()
-session = None
-
-# Global metadata. If you have multiple databases with overlapping table
-# names, you'll need a metadata for each database
-metadata = MetaData()
diff --git a/openlp/plugins/songusage/lib/tables.py b/openlp/plugins/songusage/lib/tables.py
deleted file mode 100644
index 008c722b1..000000000
--- a/openlp/plugins/songusage/lib/tables.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2010 Raoul Snyman #
-# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
-# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin #
-# Thompson, Jon Tibble, Carsten Tinggaard #
-# --------------------------------------------------------------------------- #
-# 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 sqlalchemy import Column, Table, types
-
-from openlp.plugins.songusage.lib.meta import metadata
-
-# Definition of the "songusage" table
-songusage_table = Table(u'songusage_data', metadata,
- Column(u'id', types.Integer(), primary_key=True),
- Column(u'usagedate', types.Date, index=True, nullable=False),
- Column(u'usagetime', types.Time, index=True, nullable=False),
- Column(u'title', types.Unicode(255), nullable=False),
- Column(u'authors', types.Unicode(255), nullable=False),
- Column(u'copyright', types.Unicode(255)),
- Column(u'ccl_number', types.Unicode(65))
-)
diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py
index 743a333d3..a9994902a 100644
--- a/openlp/plugins/songusage/songusageplugin.py
+++ b/openlp/plugins/songusage/songusageplugin.py
@@ -23,16 +23,16 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
-from datetime import datetime
import logging
+from datetime import datetime
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Plugin, Receiver, build_icon, translate
from openlp.plugins.songusage.lib import SongUsageManager
from openlp.plugins.songusage.forms import SongUsageDetailForm, \
SongUsageDeleteForm
-from openlp.plugins.songusage.lib.models import SongUsageItem
+from openlp.plugins.songusage.lib.db import SongUsageItem
log = logging.getLogger(__name__)
@@ -42,7 +42,7 @@ class SongUsagePlugin(Plugin):
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'SongUsage', u'1.9.2', plugin_helpers)
self.weight = -4
- self.icon = build_icon(u':/media/media_image.png')
+ self.icon = build_icon(u':/plugins/plugin_songusage.png')
self.songusagemanager = None
self.songusageActive = False
@@ -76,7 +76,7 @@ class SongUsagePlugin(Plugin):
translate('SongUsagePlugin', 'Generate report on Song Usage'))
self.SongUsageReport.setObjectName(u'SongUsageReport')
#SongUsage activation
- SongUsageIcon = build_icon(u':/tools/tools_alert.png')
+ SongUsageIcon = build_icon(u':/plugins/plugin_songusage.png')
self.SongUsageStatus = QtGui.QAction(tools_menu)
self.SongUsageStatus.setIcon(SongUsageIcon)
self.SongUsageStatus.setCheckable(True)
@@ -148,7 +148,7 @@ class SongUsagePlugin(Plugin):
song_usage_item.authors = u''
for author in audit[1]:
song_usage_item.authors += author + u' '
- self.songusagemanager.insert_songusage(song_usage_item)
+ self.songusagemanager.save_object(song_usage_item)
def onSongUsageDelete(self):
self.SongUsagedeleteform.exec_()
@@ -162,4 +162,4 @@ class SongUsagePlugin(Plugin):
'SongUsage Plugin
This plugin '
'records the use of songs and when they have been used during '
'a live service')
- return about_text
\ No newline at end of file
+ return about_text
diff --git a/resources/images/openlp-2.qrc b/resources/images/openlp-2.qrc
index 49309b8d5..118a30eae 100644
--- a/resources/images/openlp-2.qrc
+++ b/resources/images/openlp-2.qrc
@@ -1,5 +1,5 @@
-
+
topic_edit.png
author_add.png
author_delete.png
@@ -17,7 +17,18 @@
song_topic_edit.png
song_book_edit.png
-
+
+ plugin_alerts.png
+ plugin_bibles.png
+ plugin_custom.png
+ plugin_images.png
+ plugin_media.png
+ plugin_presentations.png
+ plugin_songs.png
+ plugin_remote.png
+ plugin_songusage.png
+
+
general_preview.png
general_live.png
general_add.png
@@ -29,7 +40,7 @@
general_open.png
general_save.png
-
+
slide_close.png
slide_first.png
slide_last.png
@@ -42,7 +53,7 @@
media_playback_stop.png
media_playback_pause.png
-
+
openlp-logo-16x16.png
openlp-logo-32x32.png
openlp-logo-48x48.png
@@ -50,27 +61,27 @@
openlp-logo-128x128.png
openlp-logo-256x256.png
-
+
openlp-about-logo.png
openlp-splash-screen.png
-
+
import_selectall.png
import_move_to_list.png
import_remove.png
import_load.png
-
+
export_selectall.png
export_remove.png
export_load.png
export_move_to_list.png
-
+
wizard_importsong.bmp
wizard_importbible.bmp
-
+
service_notes.png
service_item_notes.png
service_bottom.png
@@ -78,7 +89,7 @@
service_top.png
service_up.png
-
+
system_close.png
system_about.png
system_help_contents.png
@@ -89,27 +100,21 @@
system_exit.png
system_settings.png
-
- media_custom.png
- media_presentation.png
- media_image.png
- media_song.png
- media_bible.png
- media_video.png
+
media_time.png
media_stop.png
image_clapperboard.png
-
+
messagebox_critical.png
messagebox_info.png
messagebox_warning.png
-
+
tools_add.png
tools_alert.png
-
+
theme_delete.png
theme_new.png
theme_edit.png
diff --git a/resources/images/plugin_alerts.png b/resources/images/plugin_alerts.png
new file mode 100644
index 000000000..331aa2687
Binary files /dev/null and b/resources/images/plugin_alerts.png differ
diff --git a/resources/images/media_bible.png b/resources/images/plugin_bibles.png
similarity index 100%
rename from resources/images/media_bible.png
rename to resources/images/plugin_bibles.png
diff --git a/resources/images/media_custom.png b/resources/images/plugin_custom.png
similarity index 100%
rename from resources/images/media_custom.png
rename to resources/images/plugin_custom.png
diff --git a/resources/images/media_image.png b/resources/images/plugin_images.png
similarity index 100%
rename from resources/images/media_image.png
rename to resources/images/plugin_images.png
diff --git a/resources/images/media_video.png b/resources/images/plugin_media.png
similarity index 100%
rename from resources/images/media_video.png
rename to resources/images/plugin_media.png
diff --git a/resources/images/media_presentation.png b/resources/images/plugin_presentations.png
similarity index 100%
rename from resources/images/media_presentation.png
rename to resources/images/plugin_presentations.png
diff --git a/resources/images/plugin_remote.png b/resources/images/plugin_remote.png
new file mode 100644
index 000000000..d70f0f6de
Binary files /dev/null and b/resources/images/plugin_remote.png differ
diff --git a/resources/images/media_song.png b/resources/images/plugin_songs.png
similarity index 100%
rename from resources/images/media_song.png
rename to resources/images/plugin_songs.png
diff --git a/resources/images/plugin_songusage.png b/resources/images/plugin_songusage.png
new file mode 100644
index 000000000..bf110aa6d
Binary files /dev/null and b/resources/images/plugin_songusage.png differ
diff --git a/resources/images/song_maintenance.png b/resources/images/song_maintenance.png
index 860e1717e..992e1b638 100644
Binary files a/resources/images/song_maintenance.png and b/resources/images/song_maintenance.png differ
diff --git a/scripts/generate_resources.sh b/scripts/generate_resources.sh
old mode 100644
new mode 100755