← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~meths/openlp/testing into lp:openlp

 

Jon Tibble has proposed merging lp:~meths/openlp/testing into lp:openlp.

Requested reviews:
  OpenLP Core (openlp-core)


Database layer refactor
-- 
https://code.launchpad.net/~meths/openlp/testing/+merge/28638
Your team OpenLP Core is requested to review the proposed merge of lp:~meths/openlp/testing into lp:openlp.
=== modified file 'openlp/core/lib/__init__.py'
--- openlp/core/lib/__init__.py	2010-06-24 19:04:18 +0000
+++ openlp/core/lib/__init__.py	2010-06-28 13:37:16 +0000
@@ -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 @@
 
     ``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 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(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_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 renderer import Renderer
 from rendermanager import RenderManager
 from mediamanageritem import MediaManagerItem
-from basemodel import BaseModel
 from baselistwithdnd import BaseListWithDnD

=== renamed file 'openlp/core/lib/basemodel.py' => 'openlp/core/lib/db.py'
--- openlp/core/lib/basemodel.py	2010-05-29 20:57:56 +0000
+++ openlp/core/lib/db.py	2010-06-28 13:37:16 +0000
@@ -22,12 +22,68 @@
 # 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):
         """
@@ -38,3 +94,152 @@
             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_string):
+        """
+        Returns an object matching specified criteria
+
+        ``object_class``
+            The type of object to return
+
+        ``filter_string``
+            The criteria to select the object by
+        """
+        return self.session.query(object_class).filter(filter_string).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.
+        """
+        if order_by_ref:
+            return self.session.query(object_class).order_by(order_by_ref).all()
+        return self.session.query(object_class).all()
+
+    def get_all_objects_filtered(self, object_class, filter_string):
+        """
+        Returns a selection of objects from the database
+
+        ``object_class``
+            The type of objects to return
+
+        ``filter_string``
+            The filter governing selection of objects to return
+        """
+        return self.session.query(object_class).filter(filter_string).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

=== modified file 'openlp/plugins/alerts/alertsplugin.py'
--- openlp/plugins/alerts/alertsplugin.py	2010-06-23 17:37:01 +0000
+++ openlp/plugins/alerts/alertsplugin.py	2010-06-28 13:37:16 +0000
@@ -28,7 +28,9 @@
 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__)
@@ -41,11 +43,14 @@
         self.weight = -3
         self.icon = build_icon(u':/media/media_image.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
 

=== modified file 'openlp/plugins/alerts/forms/alertform.py'
--- openlp/plugins/alerts/forms/alertform.py	2010-06-21 16:43:59 +0000
+++ openlp/plugins/alerts/forms/alertform.py	2010-06-28 13:37:16 +0000
@@ -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 @@
 
     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 @@
         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 @@
         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 @@
         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:

=== modified file 'openlp/plugins/alerts/lib/__init__.py'
--- openlp/plugins/alerts/lib/__init__.py	2010-04-30 01:35:41 +0000
+++ openlp/plugins/alerts/lib/__init__.py	2010-06-28 13:37:16 +0000
@@ -25,4 +25,3 @@
 
 from alertsmanager import AlertsManager
 from alertstab import AlertsTab
-from manager import DBManager

=== removed file 'openlp/plugins/alerts/lib/classes.py'
--- openlp/plugins/alerts/lib/classes.py	2010-05-28 00:26:49 +0000
+++ openlp/plugins/alerts/lib/classes.py	1970-01-01 00:00:00 +0000
@@ -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

=== added file 'openlp/plugins/alerts/lib/db.py'
--- openlp/plugins/alerts/lib/db.py	1970-01-01 00:00:00 +0000
+++ openlp/plugins/alerts/lib/db.py	2010-06-28 13:37:16 +0000
@@ -0,0 +1,57 @@
+# -*- 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 Alerts plugin
+"""
+
+from sqlalchemy import Column, Table, types
+from sqlalchemy.orm import mapper
+
+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))
+
+    mapper(AlertItem, alerts_table)
+
+    metadata.create_all(checkfirst=True)
+    return session

=== removed file 'openlp/plugins/alerts/lib/manager.py'
--- openlp/plugins/alerts/lib/manager.py	2010-05-27 20:56:34 +0000
+++ openlp/plugins/alerts/lib/manager.py	1970-01-01 00:00:00 +0000
@@ -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
-

=== removed file 'openlp/plugins/alerts/lib/meta.py'
--- openlp/plugins/alerts/lib/meta.py	2010-03-21 23:58:01 +0000
+++ openlp/plugins/alerts/lib/meta.py	1970-01-01 00:00:00 +0000
@@ -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()

=== removed file 'openlp/plugins/alerts/lib/models.py'
--- openlp/plugins/alerts/lib/models.py	2010-06-01 17:13:54 +0000
+++ openlp/plugins/alerts/lib/models.py	1970-01-01 00:00:00 +0000
@@ -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 create_engine
-from sqlalchemy.orm import scoped_session, sessionmaker, mapper
-
-from openlp.plugins.alerts.lib.meta import metadata
-from openlp.plugins.alerts.lib.tables import *
-from openlp.plugins.alerts.lib.classes import *
-
-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)
-    return session

=== removed file 'openlp/plugins/alerts/lib/tables.py'
--- openlp/plugins/alerts/lib/tables.py	2010-03-21 23:58:01 +0000
+++ openlp/plugins/alerts/lib/tables.py	1970-01-01 00:00:00 +0000
@@ -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))

=== modified file 'openlp/plugins/bibles/forms/importwizardform.py'
--- openlp/plugins/bibles/forms/importwizardform.py	2010-06-21 18:28:36 +0000
+++ openlp/plugins/bibles/forms/importwizardform.py	2010-06-28 13:37:16 +0000
@@ -32,6 +32,7 @@
 
 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 @@
         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 @@
         """
         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 @@
             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())

=== modified file 'openlp/plugins/bibles/lib/csvbible.py'
--- openlp/plugins/bibles/lib/csvbible.py	2010-06-10 13:28:41 +0000
+++ openlp/plugins/bibles/lib/csvbible.py	2010-06-28 13:37:16 +0000
@@ -97,11 +97,11 @@
                     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 @@
             return False
         else:
             return success
-
-

=== modified file 'openlp/plugins/bibles/lib/db.py'
--- openlp/plugins/bibles/lib/db.py	2010-06-21 18:28:36 +0000
+++ openlp/plugins/bibles/lib/db.py	2010-06-28 13:37:16 +0000
@@ -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 @@
             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 @@
         """
         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 @@
         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 @@
             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 @@
         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 @@
                 text = verse_text
             )
             self.session.add(verse)
-        self.commit()
+        self.session.commit()
 
     def create_verse(self, book_id, chapter, verse, text):
         """
@@ -252,32 +279,33 @@
         return verse
 
     def create_meta(self, key, value):
+        """
+        Utility method to save BibleMeta objects in a Bible database
+
+        ``key``
+            The key for this instance
+
+        ``value``
+            The value for this instance
+        """
         log.debug(u'save_meta %s/%s', key, value)
-        self.session.add(BibleMeta.populate(key=key, value=value))
-        self.commit()
-
-    def get_books(self):
-        log.debug(u'BibleDB.get_books()')
-        return self.session.query(Book).order_by(Book.id).all()
+        self.save_object(BibleMeta.populate(key=key, value=value))
 
     def get_book(self, book):
+        """
+        Return a book object from the database
+
+        ``book``
+            The name of the book to return
+        """
         log.debug(u'BibleDb.get_book("%s")', book)
-        db_book = self.session.query(Book)\
-            .filter(Book.name.like(book + u'%'))\
-            .first()
+        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()
+            db_book = self.session.query(Book).filter(
+                Book.abbreviation.like(book + u'%')).first()
         return db_book
 
-    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()
-
     def get_verses(self, reference_list):
         """
         This is probably the most used function. It retrieves the list of
@@ -351,6 +379,12 @@
         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 +395,15 @@
             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 +414,10 @@
         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()

=== modified file 'openlp/plugins/bibles/lib/http.py'
--- openlp/plugins/bibles/lib/http.py	2010-06-17 21:01:30 +0000
+++ openlp/plugins/bibles/lib/http.py	2010-06-28 13:37:16 +0000
@@ -35,8 +35,7 @@
 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__)
 

=== modified file 'openlp/plugins/bibles/lib/manager.py'
--- openlp/plugins/bibles/lib/manager.py	2010-05-31 23:23:08 +0000
+++ openlp/plugins/bibles/lib/manager.py	2010-06-28 13:37:16 +0000
@@ -29,12 +29,12 @@
 
 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 @@
             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 @@
                 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 @@
         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):
         """

=== removed file 'openlp/plugins/bibles/lib/models.py'
--- openlp/plugins/bibles/lib/models.py	2010-05-30 15:26:45 +0000
+++ openlp/plugins/bibles/lib/models.py	1970-01-01 00:00:00 +0000
@@ -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)

=== modified file 'openlp/plugins/bibles/lib/opensong.py'
--- openlp/plugins/bibles/lib/opensong.py	2010-06-21 16:43:59 +0000
+++ openlp/plugins/bibles/lib/opensong.py	2010-06-28 13:37:16 +0000
@@ -90,7 +90,7 @@
                         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

=== modified file 'openlp/plugins/bibles/lib/osis.py'
--- openlp/plugins/bibles/lib/osis.py	2010-06-25 19:01:03 +0000
+++ openlp/plugins/bibles/lib/osis.py	2010-06-28 13:37:16 +0000
@@ -140,7 +140,7 @@
                             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 @@
                     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

=== modified file 'openlp/plugins/custom/customplugin.py'
--- openlp/plugins/custom/customplugin.py	2010-06-23 17:37:01 +0000
+++ openlp/plugins/custom/customplugin.py	2010-06-28 13:37:16 +0000
@@ -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,7 +48,7 @@
     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.status = PluginStatus.Active
@@ -75,6 +78,8 @@
         return about_text
 
     def can_delete_theme(self, theme):
-        if len(self.custommanager.get_customs_for_theme(theme)) == 0:
+        filter_string = u'theme_name=%s' % theme
+        if not self.custommanager.get_all_objects_filtered(CustomSlide,
+            filter_string):
             return True
         return False
\ No newline at end of file

=== modified file 'openlp/plugins/custom/forms/editcustomform.py'
--- openlp/plugins/custom/forms/editcustomform.py	2010-06-21 23:38:54 +0000
+++ openlp/plugins/custom/forms/editcustomform.py	2010-06-28 13:37:16 +0000
@@ -29,7 +29,7 @@
 
 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 @@
         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 @@
             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()

=== modified file 'openlp/plugins/custom/lib/__init__.py'
--- openlp/plugins/custom/lib/__init__.py	2010-03-21 23:58:01 +0000
+++ openlp/plugins/custom/lib/__init__.py	2010-06-28 13:37:16 +0000
@@ -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

=== removed file 'openlp/plugins/custom/lib/classes.py'
--- openlp/plugins/custom/lib/classes.py	2010-05-28 00:26:49 +0000
+++ openlp/plugins/custom/lib/classes.py	1970-01-01 00:00:00 +0000
@@ -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

=== added file 'openlp/plugins/custom/lib/db.py'
--- openlp/plugins/custom/lib/db.py	1970-01-01 00:00:00 +0000
+++ openlp/plugins/custom/lib/db.py	2010-06-28 13:37:16 +0000
@@ -0,0 +1,61 @@
+# -*- 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 Custom plugin
+"""
+
+from sqlalchemy import Column, Table, types
+from sqlalchemy.orm import mapper
+
+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))
+    )
+
+    mapper(CustomSlide, custom_slide_table)
+
+    metadata.create_all(checkfirst=True)
+    return session

=== removed file 'openlp/plugins/custom/lib/manager.py'
--- openlp/plugins/custom/lib/manager.py	2010-05-29 19:50:50 +0000
+++ openlp/plugins/custom/lib/manager.py	1970-01-01 00:00:00 +0000
@@ -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()

=== modified file 'openlp/plugins/custom/lib/mediaitem.py'
--- openlp/plugins/custom/lib/mediaitem.py	2010-06-24 15:50:40 +0000
+++ openlp/plugins/custom/lib/mediaitem.py	2010-06-28 13:37:16 +0000
@@ -29,6 +29,7 @@
 
 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 @@
         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 @@
 
     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 @@
         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]
@@ -136,7 +138,7 @@
             '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)
+            self.parent.custommanager.delete_object(CustomSlide, item_id)
             row = self.ListView.row(item)
             self.ListView.takeItem(row)
 
@@ -158,7 +160,7 @@
         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

=== removed file 'openlp/plugins/custom/lib/meta.py'
--- openlp/plugins/custom/lib/meta.py	2010-03-21 23:58:01 +0000
+++ openlp/plugins/custom/lib/meta.py	1970-01-01 00:00:00 +0000
@@ -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()

=== removed file 'openlp/plugins/custom/lib/models.py'
--- openlp/plugins/custom/lib/models.py	2010-06-01 17:13:54 +0000
+++ openlp/plugins/custom/lib/models.py	1970-01-01 00:00:00 +0000
@@ -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 create_engine
-from sqlalchemy.orm import scoped_session, sessionmaker, mapper
-
-from openlp.plugins.custom.lib.meta import metadata
-from openlp.plugins.custom.lib.tables import *
-from openlp.plugins.custom.lib.classes import *
-
-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)
-    return session

=== removed file 'openlp/plugins/custom/lib/tables.py'
--- openlp/plugins/custom/lib/tables.py	2010-03-21 23:58:01 +0000
+++ openlp/plugins/custom/lib/tables.py	1970-01-01 00:00:00 +0000
@@ -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))
-)

=== modified file 'openlp/plugins/songs/forms/authorsdialog.py'
--- openlp/plugins/songs/forms/authorsdialog.py	2010-06-21 16:43:59 +0000
+++ openlp/plugins/songs/forms/authorsdialog.py	2010-06-28 13:37:16 +0000
@@ -24,6 +24,7 @@
 ###############################################################################
 
 from PyQt4 import QtCore, QtGui
+
 from openlp.core.lib import translate
 
 class Ui_AuthorsDialog(object):

=== modified file 'openlp/plugins/songs/forms/authorsform.py'
--- openlp/plugins/songs/forms/authorsform.py	2010-06-21 16:43:59 +0000
+++ openlp/plugins/songs/forms/authorsform.py	2010-06-28 13:37:16 +0000
@@ -28,7 +28,6 @@
 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

=== modified file 'openlp/plugins/songs/forms/editsongdialog.py'
--- openlp/plugins/songs/forms/editsongdialog.py	2010-06-25 08:07:51 +0000
+++ openlp/plugins/songs/forms/editsongdialog.py	2010-06-28 13:37:16 +0000
@@ -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):

=== modified file 'openlp/plugins/songs/forms/editsongform.py'
--- openlp/plugins/songs/forms/editsongform.py	2010-06-25 08:07:51 +0000
+++ openlp/plugins/songs/forms/editsongform.py	2010-06-28 13:37:16 +0000
@@ -31,7 +31,7 @@
 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 @@
         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 @@
                 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 @@
             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 @@
         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 @@
                 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 @@
                 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 @@
         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 @@
                 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 @@
                 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 @@
         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,7 +392,7 @@
                 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:
@@ -630,7 +631,7 @@
         if self._validate_song():
             self.processLyrics()
             self.processTitle()
-            self.songmanager.save_song(self.song)
+            self.songmanager.save_object(self.song)
             return True
         return False
 

=== modified file 'openlp/plugins/songs/forms/songbookdialog.py'
--- openlp/plugins/songs/forms/songbookdialog.py	2010-06-21 16:43:59 +0000
+++ openlp/plugins/songs/forms/songbookdialog.py	2010-06-28 13:37:16 +0000
@@ -24,6 +24,7 @@
 ###############################################################################
 
 from PyQt4 import QtCore, QtGui
+
 from openlp.core.lib import translate
 
 class Ui_SongBookDialog(object):

=== modified file 'openlp/plugins/songs/forms/songbookform.py'
--- openlp/plugins/songs/forms/songbookform.py	2010-06-21 16:43:59 +0000
+++ openlp/plugins/songs/forms/songbookform.py	2010-06-28 13:37:16 +0000
@@ -28,7 +28,6 @@
 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.

=== modified file 'openlp/plugins/songs/forms/songmaintenanceform.py'
--- openlp/plugins/songs/forms/songmaintenanceform.py	2010-06-21 18:28:36 +0000
+++ openlp/plugins/songs/forms/songmaintenanceform.py	2010-06-28 13:37:16 +0000
@@ -25,12 +25,10 @@
 
 from PyQt4 import QtGui, QtCore
 
-from openlp.plugins.songs.lib.classes import Author, Book, Topic
+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
-from authorsform import AuthorsForm
-from topicsform import TopicsForm
-from songbookform import SongBookForm
-from openlp.core.lib import translate
 
 class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
     """
@@ -81,17 +79,17 @@
         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 @@
 
     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 @@
 
     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 @@
 
     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 @@
                 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 @@
     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 @@
             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 @@
     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 @@
                 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 @@
     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 @@
     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 @@
         """
         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 @@
         """
         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 @@
         """
         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!'))

=== modified file 'openlp/plugins/songs/forms/topicsdialog.py'
--- openlp/plugins/songs/forms/topicsdialog.py	2010-06-21 16:43:59 +0000
+++ openlp/plugins/songs/forms/topicsdialog.py	2010-06-28 13:37:16 +0000
@@ -24,6 +24,7 @@
 ###############################################################################
 
 from PyQt4 import QtCore, QtGui
+
 from openlp.core.lib import translate
 
 class Ui_TopicsDialog(object):

=== modified file 'openlp/plugins/songs/forms/topicsform.py'
--- openlp/plugins/songs/forms/topicsform.py	2010-06-21 18:28:36 +0000
+++ openlp/plugins/songs/forms/topicsform.py	2010-06-28 13:37:16 +0000
@@ -28,7 +28,6 @@
 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.

=== removed file 'openlp/plugins/songs/lib/classes.py'
--- openlp/plugins/songs/lib/classes.py	2010-05-28 00:26:49 +0000
+++ openlp/plugins/songs/lib/classes.py	1970-01-01 00:00:00 +0000
@@ -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'<Book id="%s" name="%s" publisher="%s" />' % (
-            str(self.id), self.name, self.publisher)
-
-class Song(BaseModel):
-    """
-    Song model
-    """
-    pass
-
-class Topic(BaseModel):
-    """
-    Topic model
-    """
-    pass

=== added file 'openlp/plugins/songs/lib/db.py'
--- openlp/plugins/songs/lib/db.py	1970-01-01 00:00:00 +0000
+++ openlp/plugins/songs/lib/db.py	2010-06-28 13:37:16 +0000
@@ -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'<Book id="%s" name="%s" publisher="%s" />' % (
+            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

=== modified file 'openlp/plugins/songs/lib/manager.py'
--- openlp/plugins/songs/lib/manager.py	2010-06-12 20:06:01 +0000
+++ openlp/plugins/songs/lib/manager.py	2010-06-28 13:37:16 +0000
@@ -25,12 +25,8 @@
 
 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.core.lib.db import Manager
+from openlp.plugins.songs.lib.db import init_schema, Song, Author
 #from openlp.plugins.songs.lib import OpenLyricsSong, OpenSongSong, CCLISong, \
 #    CSVSong
 
@@ -80,7 +76,7 @@
         ]
 
 
-class SongManager(object):
+class SongManager(Manager):
     """
     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.
@@ -93,35 +89,9 @@
         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()
+        Manager.__init__(self, u'songs', init_schema)
         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.
@@ -144,175 +114,3 @@
         """
         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()
-

=== modified file 'openlp/plugins/songs/lib/mediaitem.py'
--- openlp/plugins/songs/lib/mediaitem.py	2010-06-24 15:50:40 +0000
+++ openlp/plugins/songs/lib/mediaitem.py	2010-06-28 13:37:16 +0000
@@ -31,6 +31,7 @@
     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__)
 
@@ -268,7 +269,7 @@
         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 +311,7 @@
                 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 +332,7 @@
         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'<?xml version='):

=== removed file 'openlp/plugins/songs/lib/meta.py'
--- openlp/plugins/songs/lib/meta.py	2010-03-21 23:58:01 +0000
+++ openlp/plugins/songs/lib/meta.py	1970-01-01 00:00:00 +0000
@@ -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()

=== removed file 'openlp/plugins/songs/lib/models.py'
--- openlp/plugins/songs/lib/models.py	2010-06-01 17:13:54 +0000
+++ openlp/plugins/songs/lib/models.py	1970-01-01 00:00:00 +0000
@@ -1,48 +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 create_engine
-from sqlalchemy.orm import scoped_session, sessionmaker, mapper, relation
-
-from openlp.plugins.songs.lib.meta import metadata
-from openlp.plugins.songs.lib.tables import *
-from openlp.plugins.songs.lib.classes import *
-
-def init_models(url):
-    engine = create_engine(url)
-    metadata.bind = engine
-    session = scoped_session(sessionmaker(autoflush=False, autocommit=False,
-        bind=engine))
-    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)
-    return session
-

=== modified file 'openlp/plugins/songs/lib/songimport.py'
--- openlp/plugins/songs/lib/songimport.py	2010-06-25 19:01:03 +0000
+++ openlp/plugins/songs/lib/songimport.py	2010-06-28 13:37:16 +0000
@@ -27,7 +27,7 @@
 
 from openlp.core.lib import SongXMLBuilder, translate
 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 Song, Author, Topic, Book
 
 class SongImport(object):
     """
@@ -264,7 +264,6 @@
         if len(self.authors) == 0:
             self.authors.append(u'Author unknown')
         self.commit_song()
-        #self.print_song()
 
     def commit_song(self):
         """
@@ -303,30 +302,33 @@
         song.theme_name = self.theme_name
         song.ccli_number = self.ccli_number
         for authortext in self.authors:
-            author = self.manager.get_author_by_name(authortext)
+            filter_string = u'display_name=%s' % authortext
+            author = self.manager.get_object_filtered(Author, filter_string)
             if author is None:
                 author = Author()
                 author.display_name = authortext
                 author.last_name = authortext.split(u' ')[-1]
                 author.first_name = u' '.join(authortext.split(u' ')[:-1])
-                self.manager.save_author(author)
+                self.manager.save_object(author)
             song.authors.append(author)
         if self.song_book_name:
-            song_book = self.manager.get_book_by_name(self.song_book_name)
+            filter_string = u'name=%s' % self.song_book_name
+            song_book = self.manager.get_object_filtered(Book, filter_string)
             if song_book is None:
                 song_book = Book()
                 song_book.name = self.song_book_name
                 song_book.publisher = self.song_book_pub
-                self.manager.save_book(song_book)
+                self.manager.save_object(song_book)
             song.song_book_id = song_book.id
         for topictext in self.topics:
-            topic = self.manager.get_topic_by_name(topictext)
+            filter_string = u'name=%s' % topictext
+            topic = self.manager.get_object_filtered(Topic, filter_string)
             if topic is None:
                 topic = Topic()
                 topic.name = topictext
-                self.manager.save_topic(topic)
+                self.manager.save_object(topic)
             song.topics.append(topictext)
-        self.manager.save_song(song)
+        self.manager.save_object(song)
 
     def print_song(self):
         """
@@ -357,5 +359,3 @@
             print u'THEME: ' + self.theme_name
         if self.ccli_number:
             print u'CCLI: ' + self.ccli_number
-
-

=== removed file 'openlp/plugins/songs/lib/tables.py'
--- openlp/plugins/songs/lib/tables.py	2010-03-21 23:58:01 +0000
+++ openlp/plugins/songs/lib/tables.py	1970-01-01 00:00:00 +0000
@@ -1,99 +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  *
-from sqlalchemy import Column, Table, ForeignKey, types
-
-from openlp.plugins.songs.lib.meta import metadata
-
-# 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)

=== modified file 'openlp/plugins/songs/songsplugin.py'
--- openlp/plugins/songs/songsplugin.py	2010-06-24 19:40:41 +0000
+++ openlp/plugins/songs/songsplugin.py	2010-06-28 13:37:16 +0000
@@ -30,6 +30,7 @@
 from openlp.core.lib import Plugin, build_icon, PluginStatus, Receiver, \
     translate
 from openlp.plugins.songs.lib import SongManager, SongMediaItem, SongsTab
+from openlp.plugins.songs.lib.db import Song
 
 try:
     from openlp.plugins.songs.lib import SofImport, OooImport
@@ -39,7 +40,6 @@
 
 log = logging.getLogger(__name__)
 
-
 class SongsPlugin(Plugin):
     """
     This is the number 1 plugin, if importance were placed on any
@@ -69,7 +69,8 @@
         #    self.songmanager = SongManager()
         Plugin.initialise(self)
         self.insert_toolbox_item()
-        self.media_item.displayResultsSong(self.manager.get_songs())
+        self.media_item.displayResultsSong(
+            self.manager.get_all_objects(Song, Song.title))
 
     def finalise(self):
         log.info(u'Plugin Finalise')
@@ -198,6 +199,7 @@
         return about_text
 
     def can_delete_theme(self, theme):
-        if len(self.manager.get_songs_for_theme(theme)) == 0:
+        filter_string = u'theme_name=%s' % theme
+        if not self.manager.get_all_objects_filtered(Song, filter_string):
             return True
         return False

=== modified file 'openlp/plugins/songusage/forms/songusagedetailform.py'
--- openlp/plugins/songusage/forms/songusagedetailform.py	2010-06-21 18:28:36 +0000
+++ openlp/plugins/songusage/forms/songusagedetailform.py	2010-06-28 13:37:16 +0000
@@ -74,16 +74,16 @@
         filename = u'usage_detail_%s_%s.txt' % (
             self.FromDate.selectedDate().toString(u'ddMMyyyy'),
             self.ToDate.selectedDate().toString(u'ddMMyyyy'))
-        usage = self.parent.songusagemanager.get_all_songusage(
+        usage = self.parent.songusagemanager.get_songusage_for_period(
             self.FromDate.selectedDate(), self.ToDate.selectedDate())
         outname = os.path.join(unicode(self.FileLineEdit.text()), filename)
         file = None
         try:
             file = open(outname, u'w')
             for instance in usage:
-                record = u'\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"\n' % \
-                    (instance.usagedate,instance.usagetime, instance.title,
-                    instance.copyright, instance.ccl_number , instance.authors)
+                record = u'\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"\n' % (
+                    instance.usagedate, instance.usagetime, instance.title,
+                    instance.copyright, instance.ccl_number, instance.authors)
                 file.write(record)
         except IOError:
             log.exception(u'Failed to write out song usage records')

=== modified file 'openlp/plugins/songusage/lib/__init__.py'
--- openlp/plugins/songusage/lib/__init__.py	2010-03-21 23:58:01 +0000
+++ openlp/plugins/songusage/lib/__init__.py	2010-06-28 13:37:16 +0000
@@ -22,5 +22,7 @@
 # with this program; if not, write to the Free Software Foundation, Inc., 59  #
 # Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
 ###############################################################################
-
-from manager import SongUsageManager
+"""
+The :mod:`lib` module contains the library functions for the songusage plugin.
+"""
+from openlp.plugins.songusage.lib.manager import SongUsageManager

=== removed file 'openlp/plugins/songusage/lib/classes.py'
--- openlp/plugins/songusage/lib/classes.py	2010-05-28 00:26:49 +0000
+++ openlp/plugins/songusage/lib/classes.py	1970-01-01 00:00:00 +0000
@@ -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 SongUsageItem(BaseModel):
-    """
-    Audit model
-    """
-    pass

=== added file 'openlp/plugins/songusage/lib/db.py'
--- openlp/plugins/songusage/lib/db.py	1970-01-01 00:00:00 +0000
+++ openlp/plugins/songusage/lib/db.py	2010-06-28 13:37:16 +0000
@@ -0,0 +1,63 @@
+# -*- 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 SongUsage plugin
+"""
+
+from sqlalchemy import Column, Table, types
+from sqlalchemy.orm import mapper
+
+from openlp.core.lib.db import BaseModel, init_db
+
+class SongUsageItem(BaseModel):
+    """
+    SongUsageItem model
+    """
+    pass
+
+def init_schema(url):
+    """
+    Setup the songusage database connection and initialise the database schema
+
+    ``url``
+        The database to setup
+    """
+    session, metadata = init_db(url)
+
+    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))
+    )
+
+    mapper(SongUsageItem, songusage_table)
+
+    metadata.create_all(checkfirst=True)
+    return session

=== modified file 'openlp/plugins/songusage/lib/manager.py'
--- openlp/plugins/songusage/lib/manager.py	2010-06-19 20:21:36 +0000
+++ openlp/plugins/songusage/lib/manager.py	2010-06-28 13:37:16 +0000
@@ -25,16 +25,14 @@
 
 import logging
 
-from PyQt4 import QtCore
 from sqlalchemy.exceptions import InvalidRequestError
 
-from openlp.core.utils import AppLocation
-from openlp.plugins.songusage.lib.models import init_models, metadata, \
-    SongUsageItem
+from openlp.core.lib.db import Manager
+from openlp.plugins.songusage.lib.db import init_schema, SongUsageItem
 
 log = logging.getLogger(__name__)
 
-class SongUsageManager(object):
+class SongUsageManager(Manager):
     """
     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.
@@ -47,98 +45,31 @@
         don't exist.
         """
         log.debug(u'SongUsage Initialising')
-        settings = QtCore.QSettings()
-        settings.beginGroup(u'songusage')
-        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/songusage.sqlite' % \
-                AppLocation.get_section_data_path(u'songusage')
-        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()
+        Manager.__init__(self, u'songusage', init_schema)
         log.debug(u'SongUsage Initialised')
 
-    def get_all_songusage(self, start_date, end_date):
+    def get_songusage_for_period(self, start_date, end_date):
         """
-        Returns the details of SongUsage
+        Returns the details of SongUsage for a designated time period
+
+        ``start_date``
+            The start of the period to return
+
+        ``end_date``
+            The end of the period to return
         """
         return self.session.query(SongUsageItem) \
             .filter(SongUsageItem.usagedate >= 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 +77,3 @@
             self.session.rollback()
             log.exception(u'Failed to delete all Song Usage items to %s' % date)
             return False
-

=== removed file 'openlp/plugins/songusage/lib/meta.py'
--- openlp/plugins/songusage/lib/meta.py	2010-03-21 23:58:01 +0000
+++ openlp/plugins/songusage/lib/meta.py	1970-01-01 00:00:00 +0000
@@ -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()

=== removed file 'openlp/plugins/songusage/lib/models.py'
--- openlp/plugins/songusage/lib/models.py	2010-06-01 17:13:54 +0000
+++ openlp/plugins/songusage/lib/models.py	1970-01-01 00:00:00 +0000
@@ -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 create_engine
-from sqlalchemy.orm import scoped_session, sessionmaker, mapper
-
-from openlp.plugins.songusage.lib.meta import metadata
-from openlp.plugins.songusage.lib.tables import *
-from openlp.plugins.songusage.lib.classes import *
-
-def init_models(url):
-    engine = create_engine(url)
-    metadata.bind = engine
-    session = scoped_session(sessionmaker(autoflush=True, autocommit=False,
-        bind=engine))
-    mapper(SongUsageItem, songusage_table)
-    return session

=== removed file 'openlp/plugins/songusage/lib/tables.py'
--- openlp/plugins/songusage/lib/tables.py	2010-03-21 23:58:01 +0000
+++ openlp/plugins/songusage/lib/tables.py	1970-01-01 00:00:00 +0000
@@ -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))
-)

=== modified file 'openlp/plugins/songusage/songusageplugin.py'
--- openlp/plugins/songusage/songusageplugin.py	2010-06-23 17:37:01 +0000
+++ openlp/plugins/songusage/songusageplugin.py	2010-06-28 13:37:16 +0000
@@ -23,16 +23,16 @@
 # Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
 ###############################################################################
 
+import logging
+
 from datetime import datetime
-import logging
-
 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__)
 
@@ -148,7 +148,7 @@
             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 @@
             '<b>SongUsage Plugin</b><br>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


Follow ups