← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~trb143/openlp/futures into lp:openlp

 

Tim Bentley has proposed merging lp:~trb143/openlp/futures into lp:openlp.

Requested reviews:
  OpenLP Core (openlp-core)


Cleaned up logging code
Added code to stop themes in use being deleted
Added Service Notes to service items
Fixed ServiceManager context menu so it works based on the item selected
Various minor bug fixes
-- 
https://code.launchpad.net/~trb143/openlp/futures/+merge/20731
Your team OpenLP Core is subscribed to branch lp:openlp.
=== modified file 'openlp.pyw'
--- openlp.pyw	2010-03-04 19:47:17 +0000
+++ openlp.pyw	2010-03-05 10:25:28 +0000
@@ -32,14 +32,14 @@
 from optparse import OptionParser
 from PyQt4 import QtCore, QtGui
 
+log = logging.getLogger()
+
 import openlp
 from openlp.core.lib import Receiver, str_to_bool
 from openlp.core.resources import qInitResources
 from openlp.core.ui import MainWindow, SplashScreen, ScreenList
 from openlp.core.utils import get_config_directory, ConfigHelper
 
-log = logging.getLogger()
-
 application_stylesheet = u"""
 QMainWindow::separator
 {
@@ -66,7 +66,6 @@
     The core application class. This class inherits from Qt's QApplication
     class in order to provide the core of the application.
     """
-    global log
     log.info(u'OpenLP Application Loaded')
 
     def notify(self, obj, evt):
@@ -165,7 +164,7 @@
     filename = os.path.join(log_path, u'openlp.log')
     logfile = FileHandler(filename, u'w')
     logfile.setFormatter(logging.Formatter(
-        u'%(asctime)s %(name)-15s %(levelname)-8s %(message)s'))
+        u'%(asctime)s %(name)-20s %(levelname)-8s %(message)s'))
     log.addHandler(logfile)
     logging.addLevelName(15, u'Timer')
     # Parse command line options and deal with them.

=== modified file 'openlp/core/lib/dockwidget.py'
--- openlp/core/lib/dockwidget.py	2009-12-31 12:52:01 +0000
+++ openlp/core/lib/dockwidget.py	2010-03-05 10:25:28 +0000
@@ -27,6 +27,8 @@
 
 from PyQt4 import QtGui
 
+log = logging.getLogger(__name__)
+
 class OpenLPDockWidget(QtGui.QDockWidget):
     """
     Custom DockWidget class to handle events
@@ -40,10 +42,9 @@
         if name:
             self.setObjectName(name)
         self.setFloating(False)
-        self.log = logging.getLogger(u'OpenLPDockWidget')
-        self.log.debug(u'Init done')
+        log.debug(u'Init done')
 
     def closeEvent(self, event):
         self.parent.settingsmanager.setUIItemVisibility(
             self.objectName(), False)
-        event.accept()
\ No newline at end of file
+        event.accept()

=== modified file 'openlp/core/lib/eventreceiver.py'
--- openlp/core/lib/eventreceiver.py	2010-02-06 13:39:14 +0000
+++ openlp/core/lib/eventreceiver.py	2010-03-05 10:25:28 +0000
@@ -27,6 +27,8 @@
 
 from PyQt4 import QtCore
 
+log = logging.getLogger(__name__)
+
 class EventReceiver(QtCore.QObject):
     """
     Class to allow events to be passed from different parts of the
@@ -108,9 +110,6 @@
         Informs all components of the presentation types supported.
 
     """
-    global log
-    log = logging.getLogger(u'EventReceiver')
-
     def __init__(self):
         """
         Initialise the event receiver, calling the parent constructor.

=== modified file 'openlp/core/lib/mediamanageritem.py'
--- openlp/core/lib/mediamanageritem.py	2010-01-29 20:20:30 +0000
+++ openlp/core/lib/mediamanageritem.py	2010-03-05 10:25:28 +0000
@@ -32,6 +32,8 @@
 from openlp.core.lib import contextMenuAction, contextMenuSeparator
 from serviceitem import ServiceItem
 
+log = logging.getLogger(__name__)
+
 class MediaManagerItem(QtGui.QWidget):
     """
     MediaManagerItem is a helper widget for plugins.
@@ -92,9 +94,6 @@
         method is not defined, a default will be used (treat the
         filename as an image).
     """
-
-    global log
-    log = logging.getLogger(u'MediaManagerItem')
     log.info(u'Media Item loaded')
 
     def __init__(self, parent=None, icon=None, title=None):

=== modified file 'openlp/core/lib/plugin.py'
--- openlp/core/lib/plugin.py	2010-02-12 18:42:09 +0000
+++ openlp/core/lib/plugin.py	2010-03-05 10:25:28 +0000
@@ -28,6 +28,8 @@
 
 from openlp.core.lib import PluginConfig, Receiver
 
+log = logging.getLogger(__name__)
+
 class PluginStatus(object):
     """
     Defines the status of the plugin
@@ -88,8 +90,6 @@
         Used in the plugin manager, when a person clicks on the 'About' button.
 
     """
-    global log
-    log = logging.getLogger(u'Plugin')
     log.info(u'loaded')
 
     def __init__(self, name, version=None, plugin_helpers=None):
@@ -254,3 +254,9 @@
             self.mediadock.insert_dock(self.media_item, self.icon, self.weight)
         if self.settings_tab:
             self.settings.insertTab(self.settings_tab, self.weight)
+
+    def can_delete_theme(self, theme):
+        """
+        Called to ask the plugin if a theme can be deleted
+        """
+        return True

=== modified file 'openlp/core/lib/pluginmanager.py'
--- openlp/core/lib/pluginmanager.py	2010-02-12 18:42:09 +0000
+++ openlp/core/lib/pluginmanager.py	2010-03-05 10:25:28 +0000
@@ -29,13 +29,13 @@
 
 from openlp.core.lib import Plugin, PluginStatus
 
+log = logging.getLogger(__name__)
+
 class PluginManager(object):
     """
     This is the Plugin manager, which loads all the plugins,
     and executes all the hooks, as and when necessary.
     """
-    global log
-    log = logging.getLogger(u'PluginMgr')
     log.info(u'Plugin manager loaded')
 
     def __init__(self, dir):

=== modified file 'openlp/core/lib/renderer.py'
--- openlp/core/lib/renderer.py	2010-01-22 17:54:08 +0000
+++ openlp/core/lib/renderer.py	2010-03-05 10:25:28 +0000
@@ -28,13 +28,13 @@
 from PyQt4 import QtGui, QtCore
 from openlp.core.lib import resize_image
 
+log = logging.getLogger(__name__)
+
 class Renderer(object):
     """
     Genarates a pixmap image of a array of text. The Text is formatted to
     make sure it fits on the screen and if not extra frames are generated.
     """
-    global log
-    log = logging.getLogger(u'Renderer')
     log.info(u'Renderer Loaded')
 
     def __init__(self):

=== modified file 'openlp/core/lib/rendermanager.py'
--- openlp/core/lib/rendermanager.py	2010-02-06 16:23:47 +0000
+++ openlp/core/lib/rendermanager.py	2010-03-05 10:25:28 +0000
@@ -30,6 +30,8 @@
 from renderer import Renderer
 from openlp.core.lib import ThemeLevel
 
+log = logging.getLogger(__name__)
+
 class RenderManager(object):
     """
     Class to pull all Renderer interactions into one place. The plugins will
@@ -45,8 +47,6 @@
     ``screen_number``
         Defaults to *0*. The index of the output/display screen.
     """
-    global log
-    log = logging.getLogger(u'RenderManager')
     log.info(u'RenderManager Loaded')
 
     def __init__(self, theme_manager, screens, screen_number=0):

=== modified file 'openlp/core/lib/serviceitem.py'
--- openlp/core/lib/serviceitem.py	2010-02-26 12:18:01 +0000
+++ openlp/core/lib/serviceitem.py	2010-03-05 10:25:28 +0000
@@ -32,6 +32,8 @@
 
 from openlp.core.lib import build_icon, Receiver, resize_image
 
+log = logging.getLogger(__name__)
+
 class ServiceItemType(object):
     """
     Defines the type of service item
@@ -46,8 +48,6 @@
     the service manager, the slide controller, and the projection screen
     compositor.
     """
-    global log
-    log = logging.getLogger(u'ServiceItem')
     log.info(u'Service Item created')
 
     def __init__(self, plugin=None):
@@ -73,6 +73,7 @@
         self._display_frames = []
         self._uuid = unicode(uuid.uuid1())
         self.autoPreviewAllowed = False
+        self.notes = u''
 
     def addIcon(self, icon):
         """
@@ -202,6 +203,7 @@
             u'footer':self.raw_footer,
             u'type':self.service_item_type,
             u'audit':self.audit,
+            u'notes':self.notes,
             u'preview':self.autoPreviewAllowed
         }
         service_data = []
@@ -237,6 +239,7 @@
         self.raw_footer = header[u'footer']
         self.audit = header[u'audit']
         self.autoPreviewAllowed = header[u'preview']
+        self.notes = header[u'notes']
         if self.service_item_type == ServiceItemType.Text:
             for slide in serviceitem[u'serviceitem'][u'data']:
                 self._raw_frames.append(slide)

=== modified file 'openlp/core/lib/songxmlhandler.py'
--- openlp/core/lib/songxmlhandler.py	2009-12-31 12:52:01 +0000
+++ openlp/core/lib/songxmlhandler.py	2010-03-05 10:25:28 +0000
@@ -27,6 +27,8 @@
 from xml.dom.minidom import Document
 from xml.etree.ElementTree import ElementTree, XML, dump
 
+log = logging.getLogger(__name__)
+
 class SongXMLBuilder(object):
     """
     This class builds the XML used to describe songs.
@@ -42,8 +44,6 @@
           </lyrics>
         </song>
     """
-    global log
-    log = logging.getLogger(u'SongXMLBuilder')
     log.info(u'SongXMLBuilder Loaded')
 
     def __init__(self):
@@ -123,8 +123,6 @@
           </lyrics>
         </song>
     """
-    global log
-    log = logging.getLogger(u'SongXMLParser')
     log.info(u'SongXMLParser Loaded')
 
     def __init__(self, xml):
@@ -158,4 +156,4 @@
         """
         Debugging aid to dump XML so that we can see what we have.
         """
-        return dump(self.song_xml)
\ No newline at end of file
+        return dump(self.song_xml)

=== modified file 'openlp/core/lib/toolbar.py'
--- openlp/core/lib/toolbar.py	2009-12-31 12:52:01 +0000
+++ openlp/core/lib/toolbar.py	2010-03-05 10:25:28 +0000
@@ -29,6 +29,8 @@
 
 from openlp.core.lib import build_icon
 
+log = logging.getLogger(__name__)
+
 class OpenLPToolbar(QtGui.QToolBar):
     """
     Lots of toolbars around the place, so it makes sense to have a common way
@@ -43,8 +45,7 @@
         self.icons = {}
         self.setIconSize(QtCore.QSize(20, 20))
         self.actions = {}
-        self.log = logging.getLogger(u'OpenLPToolbar')
-        self.log.debug(u'Init done')
+        log.debug(u'Init done')
 
     def addToolbarButton(self, title, icon, tooltip=None, slot=None,
         checkable=False):
@@ -119,7 +120,7 @@
         if self.icons[title]:
             return self.icons[title]
         else:
-            self.log.error(u'getIconFromTitle - no icon for %s' % title)
+            log.error(u'getIconFromTitle - no icon for %s' % title)
             return QtGui.QIcon()
 
     def makeWidgetsInvisible(self, widgets):
@@ -152,4 +153,4 @@
         push_button.setCheckable(True)
         push_button.setFlat(True)
         self.addWidget(push_button)
-        return push_button
\ No newline at end of file
+        return push_button

=== modified file 'openlp/core/ui/__init__.py'
--- openlp/core/ui/__init__.py	2010-02-17 19:05:39 +0000
+++ openlp/core/ui/__init__.py	2010-03-05 10:25:28 +0000
@@ -23,6 +23,7 @@
 # Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
 ###############################################################################
 
+from serviceitemform import ServiceItemNoteForm
 from screen import ScreenList
 from maindisplay import MainDisplay
 from amendthemeform import AmendThemeForm
@@ -40,4 +41,4 @@
 
 __all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainWindow',
     'MainDisplay', 'SlideController', 'ServiceManager', 'ThemeManager',
-    'AmendThemeForm', 'MediaDockManager']
+    'AmendThemeForm', 'MediaDockManager', 'ServiceItemNoteForm']

=== modified file 'openlp/core/ui/maindisplay.py'
--- openlp/core/ui/maindisplay.py	2010-02-21 13:20:39 +0000
+++ openlp/core/ui/maindisplay.py	2010-03-05 10:25:28 +0000
@@ -31,13 +31,13 @@
 
 from openlp.core.lib import Receiver, resize_image
 
+log = logging.getLogger(__name__)
+
 class DisplayWidget(QtGui.QWidget):
     """
     Customised version of QTableWidget which can respond to keyboard
     events.
     """
-    global log
-    log = logging.getLogger(u'MainDisplay')
     log.info(u'MainDisplay loaded')
 
     def __init__(self, parent=None, name=None):
@@ -78,8 +78,6 @@
     """
     This is the form that is used to display things on the projector.
     """
-    global log
-    log = logging.getLogger(u'MainDisplay')
     log.info(u'MainDisplay Loaded')
 
     def __init__(self, parent, screens):
@@ -188,6 +186,7 @@
         Receiver.send_message(u'screen_changed')
 
     def resetDisplay(self):
+        Receiver.send_message(u'stop_display_loop')
         if self.primary:
             self.setVisible(False)
         else:

=== modified file 'openlp/core/ui/mainwindow.py'
--- openlp/core/ui/mainwindow.py	2010-02-25 21:09:27 +0000
+++ openlp/core/ui/mainwindow.py	2010-03-05 10:25:28 +0000
@@ -36,6 +36,8 @@
     OpenLPDockWidget, SettingsManager, PluginManager, Receiver, str_to_bool
 from openlp.core.utils import check_latest_version
 
+log = logging.getLogger(__name__)
+
 media_manager_style = """
   QToolBox::tab {
     background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
@@ -420,8 +422,6 @@
     """
     The main window.
     """
-    global log
-    log = logging.getLogger(u'MainWindow')
     log.info(u'MainWindow loaded')
 
     def __init__(self, screens, applicationVersion):

=== modified file 'openlp/core/ui/mediadockmanager.py'
--- openlp/core/ui/mediadockmanager.py	2009-12-31 12:52:01 +0000
+++ openlp/core/ui/mediadockmanager.py	2010-03-05 10:25:28 +0000
@@ -25,7 +25,7 @@
 
 import logging
 
-log = logging.getLogger(u'MediaDockManager')
+log = logging.getLogger(__name__)
 
 class MediaDockManager(object):
 
@@ -58,4 +58,4 @@
             if self.media_dock.widget(dock_index):
                 if self.media_dock.widget(dock_index).ConfigSection == name:
                     self.media_dock.widget(dock_index).hide()
-                    self.media_dock.removeItem(dock_index)
\ No newline at end of file
+                    self.media_dock.removeItem(dock_index)

=== modified file 'openlp/core/ui/pluginform.py'
--- openlp/core/ui/pluginform.py	2009-12-31 12:52:01 +0000
+++ openlp/core/ui/pluginform.py	2010-03-05 10:25:28 +0000
@@ -30,9 +30,9 @@
 from openlp.core.lib.plugin import PluginStatus
 from plugindialog import Ui_PluginViewDialog
 
+log = logging.getLogger(__name__)
+
 class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
-    global log
-    log = logging.getLogger(u'PluginForm')
 
     def __init__(self, parent=None):
         QtGui.QDialog.__init__(self, parent)
@@ -126,4 +126,4 @@
         elif self.activePlugin.status == PluginStatus.Disabled:
             status_text = 'Disabled'
         self.PluginListWidget.currentItem().setText(
-            u'%s (%s)' % (self.activePlugin.name, status_text))
\ No newline at end of file
+            u'%s (%s)' % (self.activePlugin.name, status_text))

=== modified file 'openlp/core/ui/screen.py'
--- openlp/core/ui/screen.py	2010-01-22 18:59:36 +0000
+++ openlp/core/ui/screen.py	2010-03-05 10:25:28 +0000
@@ -24,12 +24,12 @@
 ###############################################################################
 import logging
 
+log = logging.getLogger(__name__)
+
 class ScreenList(object):
     """
     Wrapper to handle the parameters of the display screen
     """
-    global log
-    log = logging.getLogger(u'Screen')
     log.info(u'Screen loaded')
 
     def __init__(self):

=== added file 'openlp/core/ui/serviceitemdialog.py'
--- openlp/core/ui/serviceitemdialog.py	1970-01-01 00:00:00 +0000
+++ openlp/core/ui/serviceitemdialog.py	2010-03-05 10:25:28 +0000
@@ -0,0 +1,49 @@
+# -*- 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, 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 PyQt4 import QtCore, QtGui
+
+class Ui_ServiceNoteEdit(object):
+    def setupUi(self, ServiceNoteEdit):
+        ServiceNoteEdit.setObjectName(u'ServiceNoteEdit')
+        ServiceNoteEdit.resize(400, 243)
+        self.widget = QtGui.QWidget(ServiceNoteEdit)
+        self.widget.setGeometry(QtCore.QRect(20, 10, 361, 223))
+        self.widget.setObjectName(u'widget')
+        self.verticalLayout = QtGui.QVBoxLayout(self.widget)
+        self.verticalLayout.setObjectName(u'verticalLayout')
+        self.textEdit = QtGui.QTextEdit(self.widget)
+        self.textEdit.setObjectName(u'textEdit')
+        self.verticalLayout.addWidget(self.textEdit)
+        self.buttonBox = QtGui.QDialogButtonBox(self.widget)
+        self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Save)
+        self.buttonBox.setObjectName(u'buttonBox')
+        self.verticalLayout.addWidget(self.buttonBox)
+
+        self.retranslateUi(ServiceNoteEdit)
+        QtCore.QMetaObject.connectSlotsByName(ServiceNoteEdit)
+
+    def retranslateUi(self, ServiceNoteEdit):
+        ServiceNoteEdit.setWindowTitle(self.trUtf8('Service Item Notes'))

=== added file 'openlp/core/ui/serviceitemform.py'
--- openlp/core/ui/serviceitemform.py	1970-01-01 00:00:00 +0000
+++ openlp/core/ui/serviceitemform.py	2010-03-05 10:25:28 +0000
@@ -0,0 +1,44 @@
+# -*- 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, 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 PyQt4 import QtCore, QtGui
+from serviceitemdialog import Ui_ServiceNoteEdit
+
+class ServiceItemNoteForm(QtGui.QDialog, Ui_ServiceNoteEdit):
+    """
+    This is the form that is used to edit the verses of the song.
+    """
+    def __init__(self, parent=None):
+        """
+        Constructor
+        """
+        QtGui.QDialog.__init__(self, parent)
+        self.setupUi(self)
+        QtCore.QObject.connect(self.buttonBox,
+                               QtCore.SIGNAL(u'accepted()'),
+                               self.accept)
+        QtCore.QObject.connect(self.buttonBox,
+                               QtCore.SIGNAL(u'rejected()'),
+                               self.reject)

=== modified file 'openlp/core/ui/servicemanager.py'
--- openlp/core/ui/servicemanager.py	2010-03-02 07:01:56 +0000
+++ openlp/core/ui/servicemanager.py	2010-03-05 10:25:28 +0000
@@ -28,33 +28,21 @@
 import cPickle
 import zipfile
 
+log = logging.getLogger(__name__)
+
 from PyQt4 import QtCore, QtGui
+
 from openlp.core.lib import PluginConfig, OpenLPToolbar, ServiceItem, \
     contextMenuAction, contextMenuSeparator, contextMenu, Receiver, \
-    contextMenu, str_to_bool
+    contextMenu, str_to_bool, build_icon
+from openlp.core.ui import ServiceItemNoteForm
 
 class ServiceManagerList(QtGui.QTreeWidget):
 
     def __init__(self, parent=None, name=None):
         QtGui.QTreeWidget.__init__(self,parent)
         self.parent = parent
-
-#    def mousePressEvent(self, event):
-#        if event.button() == QtCore.Qt.RightButton:
-#            item = self.itemAt(event.pos())
-#            parentitem = item.parent()
-#            if parentitem is None:
-#                pos = item.data(0, QtCore.Qt.UserRole).toInt()[0]
-#            else:
-#                pos = parentitem.data(0, QtCore.Qt.UserRole).toInt()[0]
-#            serviceItem = self.parent.serviceItems[pos - 1]
-#            if serviceItem[u'data'].edit_enabled:
-#                self.parent.editAction.setVisible(True)
-#            else:
-#                self.parent.editAction.setVisible(False)
-#            event.accept()
-#        else:
-#            event.ignore()
+        self.setExpandsOnDoubleClick(False)
 
     def keyPressEvent(self, event):
         if type(event) == QtGui.QKeyEvent:
@@ -91,6 +79,7 @@
         just tell it what plugin to call
         """
         if event.buttons() != QtCore.Qt.LeftButton:
+            event.ignore()
             return
         drag = QtGui.QDrag(self)
         mimeData = QtCore.QMimeData()
@@ -105,9 +94,6 @@
     the resources used into one OSZ file for use on any OpenLP v2 installation.
     Also handles the UI tasks of moving things up and down etc.
     """
-    global log
-    log = logging.getLogger(u'ServiceManager')
-
     def __init__(self, parent):
         """
         Sets up the service manager, toolbars, list view, et al.
@@ -121,6 +107,7 @@
         #Indicates if remoteTriggering is active.  If it is the next addServiceItem call
         #will replace the currently selected one.
         self.remoteEditTriggered = False
+        self.serviceItemNoteForm = ServiceItemNoteForm()
         #start with the layout
         self.Layout = QtGui.QVBoxLayout(self)
         self.Layout.setSpacing(0)
@@ -161,37 +148,13 @@
         self.ServiceManagerList.setAlternatingRowColors(True)
         self.ServiceManagerList.setHeaderHidden(True)
         self.ServiceManagerList.setExpandsOnDoubleClick(False)
+        self.ServiceManagerList.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
+        self.ServiceManagerList.customContextMenuRequested.connect(self.contextMenu)
         self.ServiceManagerList.setObjectName(u'ServiceManagerList')
         # enable drop
         self.ServiceManagerList.__class__.dragEnterEvent = self.dragEnterEvent
         self.ServiceManagerList.__class__.dragMoveEvent = self.dragEnterEvent
         self.ServiceManagerList.__class__.dropEvent = self.dropEvent
-        # Add a context menu to the service manager list
-        self.ServiceManagerList.setContextMenuPolicy(
-            QtCore.Qt.ActionsContextMenu)
-        self.editAction = contextMenuAction(
-            self.ServiceManagerList, ':/services/service_edit.png',
-            self.trUtf8('&Edit Item'), self.remoteEdit)
-        self.ServiceManagerList.addAction(self.editAction)
-        self.ServiceManagerList.addAction(contextMenuSeparator(
-            self.ServiceManagerList))
-        self.ServiceManagerList.addAction(contextMenuAction(
-            self.ServiceManagerList, ':/system/system_preview.png',
-            self.trUtf8('&Preview Verse'), self.makePreview))
-        self.ServiceManagerList.addAction(contextMenuAction(
-            self.ServiceManagerList, ':/system/system_live.png',
-            self.trUtf8('&Show Live'), self.makeLive))
-        self.ServiceManagerList.addAction(contextMenuSeparator(
-            self.ServiceManagerList))
-        self.ServiceManagerList.addAction(contextMenuAction(
-            self.ServiceManagerList, ':/services/service_delete',
-            self.trUtf8('&Remove from Service'), self.onDeleteFromService))
-        self.ServiceManagerList.addAction(contextMenuSeparator(
-            self.ServiceManagerList))
-        self.ThemeMenu = contextMenu(
-            self.ServiceManagerList, '',
-            self.trUtf8('&Change Item Theme'))
-        self.ServiceManagerList.addAction(self.ThemeMenu.menuAction())
         self.Layout.addWidget(self.ServiceManagerList)
         # Add the bottom toolbar
         self.OrderToolbar = OpenLPToolbar(self)
@@ -216,7 +179,7 @@
         QtCore.QObject.connect(self.ThemeComboBox,
             QtCore.SIGNAL(u'activated(int)'), self.onThemeComboBoxSelected)
         QtCore.QObject.connect(self.ServiceManagerList,
-           QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.makeLive)
+            QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.makeLive)
         QtCore.QObject.connect(self.ServiceManagerList,
            QtCore.SIGNAL(u'itemCollapsed(QTreeWidgetItem*)'), self.collapsed)
         QtCore.QObject.connect(self.ServiceManagerList,
@@ -234,10 +197,60 @@
         self.servicePath = self.config.get_data_path()
         self.service_theme = unicode(
             self.config.get_config(u'service theme', u''))
+        #build the context menu
+        self.menu = QtGui.QMenu()
+        self.editAction = self.menu.addAction(self.trUtf8('&Edit Item'))
+        self.editAction.setIcon(build_icon(':/services/service_edit.png'))
+        self.notesAction = self.menu.addAction(self.trUtf8('&Notes'))
+        self.notesAction.setIcon(build_icon(':/services/service_notes.png'))
+        self.sep1 = self.menu.addAction(u'')
+        self.sep1.setSeparator(True)
+        self.previewAction = self.menu.addAction(self.trUtf8('&Preview Verse'))
+        self.previewAction.setIcon(build_icon(':/system/system_preview.png'))
+        self.liveAction = self.menu.addAction(self.trUtf8('&Live Verse'))
+        self.liveAction.setIcon(build_icon(':/system/system_live.png'))
+        self.sep2 = self.menu.addAction(u'')
+        self.sep2.setSeparator(True)
+        self.themeMenu = QtGui.QMenu(self.trUtf8('&Change Item Theme'))
+        self.menu.addMenu(self.themeMenu)
+
+    def contextMenu(self, point):
+        item = self.ServiceManagerList.itemAt(point)
+        if item.parent() is None:
+            pos = item.data(0, QtCore.Qt.UserRole).toInt()[0]
+        else:
+            pos = item.parent().data(0, QtCore.Qt.UserRole).toInt()[0]
+        serviceItem = self.serviceItems[pos - 1]
+        self.editAction.setVisible(False)
+        self.notesAction.setVisible(False)
+        if serviceItem[u'service_item'].edit_enabled:
+            self.editAction.setVisible(True)
+        if item.parent() is None:
+            self.notesAction.setVisible(True)
+        self.themeMenu.menuAction().setVisible(False)
+        if serviceItem[u'service_item'].is_text():
+            self.themeMenu.menuAction().setVisible(True)
+        action = self.menu.exec_(self.ServiceManagerList.mapToGlobal(point))
+        if action == self.editAction:
+            self.remoteEdit()
+        if action == self.notesAction:
+            self.onServiceItemNoteForm()
+        if action == self.previewAction:
+            self.makePreview()
+        if action == self.liveAction:
+            self.makeLive()
 
     def onPresentationTypes(self, presentation_types):
         self.presentation_types = presentation_types
 
+    def onServiceItemNoteForm(self):
+        item, count = self.findServiceItem()
+        self.serviceItemNoteForm.textEdit.setPlainText(
+            self.serviceItems[item][u'service_item'].notes)
+        if self.serviceItemNoteForm.exec_():
+            self.serviceItems[item][u'service_item'].notes = \
+                self.serviceItemNoteForm.textEdit.toPlainText()
+
     def nextItem(self):
         """
         Called by the SlideController to select the
@@ -722,7 +735,7 @@
             A list of current themes to be displayed
         """
         self.ThemeComboBox.clear()
-        self.ThemeMenu.clear()
+        self.themeMenu.clear()
         self.ThemeComboBox.addItem(u'')
         for theme in theme_list:
             self.ThemeComboBox.addItem(theme)
@@ -730,7 +743,7 @@
                 self.ServiceManagerList,
                 None,
                 theme , self.onThemeChangeAction)
-            self.ThemeMenu.addAction(action)
+            self.themeMenu.addAction(action)
         id = self.ThemeComboBox.findText(self.service_theme,
             QtCore.Qt.MatchExactly)
         # Not Found

=== modified file 'openlp/core/ui/settingsform.py'
--- openlp/core/ui/settingsform.py	2010-02-11 18:39:28 +0000
+++ openlp/core/ui/settingsform.py	2010-03-05 10:25:28 +0000
@@ -31,7 +31,7 @@
 from openlp.core.lib import Receiver
 from settingsdialog import Ui_SettingsDialog
 
-log = logging.getLogger(u'SettingsForm')
+log = logging.getLogger(__name__)
 
 class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
 

=== modified file 'openlp/core/ui/slidecontroller.py'
--- openlp/core/ui/slidecontroller.py	2010-02-27 07:39:47 +0000
+++ openlp/core/ui/slidecontroller.py	2010-03-05 10:25:28 +0000
@@ -33,6 +33,8 @@
 from openlp.core.lib import OpenLPToolbar, Receiver, str_to_bool, \
 PluginConfig, resize_image
 
+log = logging.getLogger(__name__)
+
 class SlideList(QtGui.QTableWidget):
     """
     Customised version of QTableWidget which can respond to keyboard
@@ -74,9 +76,6 @@
     SlideController is the slide controller widget. This widget is what the
     user uses to control the displaying of verses/slides/etc on the screen.
     """
-    global log
-    log = logging.getLogger(u'SlideController')
-
     def __init__(self, parent, settingsmanager, isLive=False):
         """
         Set up the Slide Controller.
@@ -183,7 +182,7 @@
                 self.trUtf8('Move to live'), self.onGoLive)
             self.Toolbar.addToolbarSeparator(u'Close Separator')
             self.Toolbar.addToolbarButton(
-                u'Edit Song', u':/songs/song_edit.png',
+                u'Edit Song', u':/services/service_edit.png',
                 self.trUtf8('Edit and re-preview Song'), self.onEditSong)
         if isLive:
             self.Toolbar.addToolbarSeparator(u'Loop Separator')
@@ -194,6 +193,8 @@
                 u'Stop Loop', u':/media/media_stop.png',
                 self.trUtf8('Stop continuous loop'), self.onStopLoop)
             self.DelaySpinBox = QtGui.QSpinBox()
+            self.DelaySpinBox.setMinimum(1)
+            self.DelaySpinBox.setMaximum(180)
             self.Toolbar.addToolbarWidget(
                 u'Image SpinBox', self.DelaySpinBox)
             self.DelaySpinBox.setSuffix(self.trUtf8('s'))
@@ -281,6 +282,8 @@
             self.Toolbar.makeWidgetsInvisible(self.song_edit_list)
         self.Mediabar.setVisible(False)
         QtCore.QObject.connect(Receiver.get_receiver(),
+            QtCore.SIGNAL(u'stop_display_loop'), self.onStopLoop)
+        QtCore.QObject.connect(Receiver.get_receiver(),
             QtCore.SIGNAL(u'%s_first' % prefix), self.onSlideSelectedFirst)
         QtCore.QObject.connect(Receiver.get_receiver(),
             QtCore.SIGNAL(u'%s_next' % prefix), self.onSlideSelectedNext)

=== modified file 'openlp/core/ui/thememanager.py'
--- openlp/core/ui/thememanager.py	2010-02-22 16:57:08 +0000
+++ openlp/core/ui/thememanager.py	2010-03-05 10:25:28 +0000
@@ -38,13 +38,12 @@
     contextMenuSeparator
 from openlp.core.utils import ConfigHelper
 
+log = logging.getLogger(__name__)
+
 class ThemeManager(QtGui.QWidget):
     """
     Manages the orders of Theme.
     """
-    global log
-    log = logging.getLogger(u'ThemeManager')
-
     def __init__(self, parent):
         QtGui.QWidget.__init__(self, parent)
         self.parent = parent
@@ -181,6 +180,19 @@
                     self.trUtf8('You are unable to delete the default theme!'),
                     QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
             else:
+                for plugin in self.parent.plugin_manager.plugins:
+                    if not plugin.can_delete_theme(theme):
+                        QtGui.QMessageBox.critical(
+                            self, self.trUtf8('Error'),
+                            self.trUtf8('theme %s is use in %s plugin' % (theme, plugin.name)),
+                            QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
+                        return
+                if unicode(self.parent.ServiceManagerContents.ThemeComboBox.currentText()) == theme:
+                    QtGui.QMessageBox.critical(
+                        self, self.trUtf8('Error'),
+                        self.trUtf8('theme %s is use Service Manager' % theme),
+                        QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok))
+                    return
                 self.themelist.remove(theme)
                 th = theme + u'.png'
                 row = self.ThemeListWidget.row(item)

=== modified file 'openlp/migration/display.py'
--- openlp/migration/display.py	2009-12-31 12:52:01 +0000
+++ openlp/migration/display.py	2010-03-05 10:25:28 +0000
@@ -25,9 +25,9 @@
 
 import logging
 
+log = logging.getLogger(__name__)
+
 class Display():
-    global log
-    log = logging.getLogger(u'Display Logger')
     log.info(u'Display Class loaded')
 
     @staticmethod
@@ -39,4 +39,4 @@
     def sub_output(string):
         if not string is None:
             log.debug(u'   '+string);
-            print (u'   '+string)
\ No newline at end of file
+            print (u'   '+string)

=== modified file 'openlp/plugins/alerts/alertsplugin.py'
--- openlp/plugins/alerts/alertsplugin.py	2010-02-17 19:13:04 +0000
+++ openlp/plugins/alerts/alertsplugin.py	2010-03-05 10:25:28 +0000
@@ -31,9 +31,9 @@
 from openlp.plugins.alerts.lib import AlertsManager, DBManager
 from openlp.plugins.alerts.forms import AlertsTab, AlertForm, AlertEditForm
 
+log = logging.getLogger(__name__)
+
 class alertsPlugin(Plugin):
-    global log
-    log = logging.getLogger(u'AlertsPlugin')
     log.info(u'Alerts Plugin loaded')
 
     def __init__(self, plugin_helpers):

=== modified file 'openlp/plugins/alerts/lib/alertsmanager.py'
--- openlp/plugins/alerts/lib/alertsmanager.py	2010-02-21 13:20:39 +0000
+++ openlp/plugins/alerts/lib/alertsmanager.py	2010-03-05 10:25:28 +0000
@@ -29,12 +29,12 @@
 
 from openlp.core.lib import Receiver
 
+log = logging.getLogger(__name__)
+
 class AlertsManager(QtCore.QObject):
     """
-    BiblesTab is the Bibles settings tab in the settings dialog.
+    AlertsTab is the Alerts settings tab in the settings dialog.
     """
-    global log
-    log = logging.getLogger(u'AlertManager')
     log.info(u'Alert Manager loaded')
 
     def __init__(self, parent):

=== modified file 'openlp/plugins/alerts/lib/manager.py'
--- openlp/plugins/alerts/lib/manager.py	2010-02-14 20:19:57 +0000
+++ openlp/plugins/alerts/lib/manager.py	2010-03-05 10:25:28 +0000
@@ -27,14 +27,13 @@
 
 from openlp.plugins.alerts.lib.models import init_models, metadata, AlertItem
 
+log = logging.getLogger(__name__)
+
 class DBManager():
     """
     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.
     """
-
-    global log
-    log = logging.getLogger(u'AlertsDBManager')
     log.info(u'Alerts DB loaded')
 
     def __init__(self, config):

=== modified file 'openlp/plugins/bibles/bibleplugin.py'
--- openlp/plugins/bibles/bibleplugin.py	2010-02-06 15:02:46 +0000
+++ openlp/plugins/bibles/bibleplugin.py	2010-03-05 10:25:28 +0000
@@ -30,9 +30,9 @@
 from openlp.core.lib import Plugin, build_icon, PluginStatus
 from openlp.plugins.bibles.lib import BibleManager, BiblesTab, BibleMediaItem
 
+log = logging.getLogger(__name__)
+
 class BiblePlugin(Plugin):
-    global log
-    log = logging.getLogger(u'BiblePlugin')
     log.info(u'Bible Plugin loaded')
 
     def __init__(self, plugin_helpers):
@@ -92,3 +92,9 @@
             'plugin allows bible verses from different sources to be '
             'displayed on the screen during the service.')
         return about_text
+
+
+    def can_delete_theme(self, theme):
+        if self.settings_tab.bible_theme == theme:
+            return False
+        return True

=== modified file 'openlp/plugins/bibles/forms/importwizardform.py'
--- openlp/plugins/bibles/forms/importwizardform.py	2010-02-06 16:23:47 +0000
+++ openlp/plugins/bibles/forms/importwizardform.py	2010-03-05 10:25:28 +0000
@@ -34,6 +34,8 @@
 from openlp.core.lib import Receiver
 from openlp.plugins.bibles.lib.manager import BibleFormat
 
+log = logging.getLogger(__name__)
+
 class DownloadLocation(object):
     Unknown = -1
     Crosswalk = 0
@@ -54,9 +56,6 @@
     This is the Bible Import Wizard, which allows easy importing of Bibles
     into OpenLP from other formats like OSIS, CSV and OpenSong.
     """
-
-    global log
-    log = logging.getLogger(u'BibleImportForm')
     log.info(u'BibleImportForm loaded')
 
     def __init__(self, parent, config, manager, bibleplugin):
@@ -371,4 +370,4 @@
         self.ImportProgressBar.setValue(self.ImportProgressBar.maximum())
         self.finishButton.setVisible(True)
         self.cancelButton.setVisible(False)
-        Receiver.send_message(u'process_events')
\ No newline at end of file
+        Receiver.send_message(u'process_events')

=== modified file 'openlp/plugins/bibles/lib/biblestab.py'
--- openlp/plugins/bibles/lib/biblestab.py	2010-02-14 13:27:32 +0000
+++ openlp/plugins/bibles/lib/biblestab.py	2010-03-05 10:25:28 +0000
@@ -29,12 +29,12 @@
 
 from openlp.core.lib import str_to_bool, Receiver, SettingsTab
 
+log = logging.getLogger(__name__)
+
 class BiblesTab(SettingsTab):
     """
     BiblesTab is the Bibles settings tab in the settings dialog.
     """
-    global log
-    log = logging.getLogger(u'BibleTab')
     log.info(u'Bible Tab loaded')
 
     def __init__(self, title, section=None):

=== modified file 'openlp/plugins/bibles/lib/manager.py'
--- openlp/plugins/bibles/lib/manager.py	2010-02-06 16:23:47 +0000
+++ openlp/plugins/bibles/lib/manager.py	2010-03-05 10:25:28 +0000
@@ -33,6 +33,8 @@
 from db import BibleDB
 from http import HTTPBible
 
+log = logging.getLogger(__name__)
+
 class BibleMode(object):
     """
     This is basically an enumeration class which specifies the mode of a Bible.
@@ -85,8 +87,6 @@
     """
     The Bible manager which holds and manages all the Bibles.
     """
-    global log
-    log = logging.getLogger(u'BibleManager')
     log.info(u'Bible manager loaded')
 
     def __init__(self, parent, config):

=== modified file 'openlp/plugins/bibles/lib/mediaitem.py'
--- openlp/plugins/bibles/lib/mediaitem.py	2010-02-27 09:18:26 +0000
+++ openlp/plugins/bibles/lib/mediaitem.py	2010-03-05 10:25:28 +0000
@@ -32,6 +32,8 @@
     BaseListWithDnD
 from openlp.plugins.bibles.forms import ImportWizardForm
 
+log = logging.getLogger(__name__)
+
 class BibleListView(BaseListWithDnD):
     """
     Drag and drop capable list for Bibles.
@@ -47,8 +49,6 @@
     """
     This is the custom media manager item for Bibles.
     """
-    global log
-    log = logging.getLogger(u'BibleMediaItem')
     log.info(u'Bible Media Item loaded')
 
     def __init__(self, parent, icon, title):

=== modified file 'openlp/plugins/bibles/lib/osis.py'
--- openlp/plugins/bibles/lib/osis.py	2010-02-28 20:50:14 +0000
+++ openlp/plugins/bibles/lib/osis.py	2010-03-05 10:25:28 +0000
@@ -35,12 +35,12 @@
 from openlp.core.lib import Receiver
 from db import BibleDB
 
+log = logging.getLogger(__name__)
+
 class OSISBible(BibleDB):
     """
     OSIS Bible format importer class.
     """
-    global log
-    log = logging.getLogger(u'BibleOSISImpl')
     log.info(u'BibleOSISImpl loaded')
 
     def __init__(self, parent, **kwargs):

=== modified file 'openlp/plugins/custom/customplugin.py'
--- openlp/plugins/custom/customplugin.py	2010-02-06 10:33:33 +0000
+++ openlp/plugins/custom/customplugin.py	2010-03-05 10:25:28 +0000
@@ -29,6 +29,7 @@
 from openlp.core.lib import Plugin, build_icon, PluginStatus
 from openlp.plugins.custom.lib import CustomManager, CustomMediaItem, CustomTab
 
+log = logging.getLogger(__name__)
 
 class CustomPlugin(Plugin):
     """
@@ -39,9 +40,6 @@
     the songs plugin has become restrictive. Examples could be
     Welcome slides, Bible Reading information, Orders of service.
     """
-
-    global log
-    log = logging.getLogger(u'CustomPlugin')
     log.info(u'Custom Plugin loaded')
 
     def __init__(self, plugin_helpers):
@@ -74,3 +72,8 @@
             'songs are.  This plugin provides greater freedom over the '
             'songs plugin.<br>')
         return about_text
+
+    def can_delete_theme(self, theme):
+        if len(self.custommanager.get_customs_for_theme(theme)) == 0:
+            return True
+        return False

=== modified file 'openlp/plugins/custom/forms/editcustomform.py'
--- openlp/plugins/custom/forms/editcustomform.py	2010-01-31 19:49:01 +0000
+++ openlp/plugins/custom/forms/editcustomform.py	2010-03-05 10:25:28 +0000
@@ -30,12 +30,12 @@
 from openlp.core.lib import SongXMLBuilder, SongXMLParser, Receiver
 from openlp.plugins.custom.lib.models import CustomSlide
 
+log = logging.getLogger(__name__)
+
 class EditCustomForm(QtGui.QDialog, Ui_customEditDialog):
     """
     Class documentation goes here.
     """
-    global log
-    log = logging.getLogger(u'EditCustomForm')
     log.info(u'Custom Editor loaded')
     def __init__(self, custommanager, parent = None):
         """

=== modified file 'openlp/plugins/custom/lib/manager.py'
--- openlp/plugins/custom/lib/manager.py	2010-02-16 18:47:26 +0000
+++ openlp/plugins/custom/lib/manager.py	2010-03-05 10:25:28 +0000
@@ -27,14 +27,13 @@
 
 from openlp.plugins.custom.lib.models import init_models, metadata, CustomSlide
 
+log = logging.getLogger(__name__)
+
 class CustomManager():
     """
     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.
     """
-
-    global log
-    log = logging.getLogger(u'CustomManager')
     log.info(u'Custom manager loaded')
 
     def __init__(self, config):
@@ -106,3 +105,6 @@
                 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-02-27 09:18:26 +0000
+++ openlp/plugins/custom/lib/mediaitem.py	2010-03-05 10:25:28 +0000
@@ -30,6 +30,8 @@
 from openlp.core.lib import MediaManagerItem, SongXMLParser, BaseListWithDnD,\
 Receiver, str_to_bool
 
+log = logging.getLogger(__name__)
+
 class CustomListView(BaseListWithDnD):
     def __init__(self, parent=None):
         self.PluginName = u'Custom'
@@ -39,8 +41,6 @@
     """
     This is the custom media manager item for Custom Slides.
     """
-    global log
-    log = logging.getLogger(u'CustomMediaItem')
     log.info(u'Custom Media Item loaded')
 
     def __init__(self, parent, icon, title):

=== modified file 'openlp/plugins/images/imageplugin.py'
--- openlp/plugins/images/imageplugin.py	2010-02-06 10:33:33 +0000
+++ openlp/plugins/images/imageplugin.py	2010-03-05 10:25:28 +0000
@@ -28,9 +28,9 @@
 from openlp.core.lib import Plugin, build_icon, PluginStatus
 from openlp.plugins.images.lib import ImageMediaItem, ImageTab
 
+log = logging.getLogger(__name__)
+
 class ImagePlugin(Plugin):
-    global log
-    log = logging.getLogger(u'ImagePlugin')
     log.info(u'Image Plugin loaded')
 
     def __init__(self, plugin_helpers):

=== modified file 'openlp/plugins/images/lib/imagetab.py'
--- openlp/plugins/images/lib/imagetab.py	2009-12-31 12:52:01 +0000
+++ openlp/plugins/images/lib/imagetab.py	2010-03-05 10:25:28 +0000
@@ -49,6 +49,7 @@
         self.TimeoutLabel.setObjectName(u'TimeoutLabel')
         self.TimeoutLayout.addWidget(self.TimeoutLabel)
         self.TimeoutSpinBox = QtGui.QSpinBox(self.ImageSettingsGroupBox)
+        self.TimeoutSpinBox.setMinimum(1)
         self.TimeoutSpinBox.setMaximum(180)
         self.TimeoutSpinBox.setObjectName(u'TimeoutSpinBox')
         self.TimeoutLayout.addWidget(self.TimeoutSpinBox)
@@ -78,4 +79,4 @@
         Receiver.send_message(u'update_spin_delay', self.loop_delay)
 
     def postSetUp(self):
-        Receiver.send_message(u'update_spin_delay', self.loop_delay)
\ No newline at end of file
+        Receiver.send_message(u'update_spin_delay', self.loop_delay)

=== modified file 'openlp/plugins/images/lib/mediaitem.py'
--- openlp/plugins/images/lib/mediaitem.py	2010-02-27 09:18:26 +0000
+++ openlp/plugins/images/lib/mediaitem.py	2010-03-05 10:25:28 +0000
@@ -29,6 +29,8 @@
 from PyQt4 import QtCore, QtGui
 from openlp.core.lib import MediaManagerItem, BaseListWithDnD, build_icon
 
+log = logging.getLogger(__name__)
+
 # We have to explicitly create separate classes for each plugin
 # in order for DnD to the Service manager to work correctly.
 class ImageListView(BaseListWithDnD):
@@ -40,8 +42,6 @@
     """
     This is the custom media manager item for images.
     """
-    global log
-    log = logging.getLogger(u'ImageMediaItem')
     log.info(u'Image Media Item loaded')
 
     def __init__(self, parent, icon, title):

=== modified file 'openlp/plugins/presentations/lib/impresscontroller.py'
--- openlp/plugins/presentations/lib/impresscontroller.py	2010-03-02 23:15:13 +0000
+++ openlp/plugins/presentations/lib/impresscontroller.py	2010-03-05 10:25:28 +0000
@@ -46,15 +46,15 @@
 
 from presentationcontroller import PresentationController,  PresentationDocument
 
+log = logging.getLogger(__name__)
+
 class ImpressController(PresentationController):
     """
     Class to control interactions with Impress presentations.
     It creates the runtime environment, loads and closes the presentation as
     well as triggering the correct activities based on the users input
     """
-    global log
-    log = logging.getLogger(u'ImpressController')
-    log.info(u'loaded')
+    log.info(u'ImpressController loaded')
 
     def __init__(self, plugin):
         """

=== modified file 'openlp/plugins/presentations/lib/mediaitem.py'
--- openlp/plugins/presentations/lib/mediaitem.py	2010-03-02 21:01:23 +0000
+++ openlp/plugins/presentations/lib/mediaitem.py	2010-03-05 10:25:28 +0000
@@ -31,6 +31,8 @@
 from openlp.core.lib import MediaManagerItem, BaseListWithDnD
 from openlp.plugins.presentations.lib import MessageListener
 
+log = logging.getLogger(__name__)
+
 # We have to explicitly create separate classes for each plugin
 # in order for DnD to the Service manager to work correctly.
 class PresentationListView(BaseListWithDnD):
@@ -43,8 +45,6 @@
     This is the Presentation media manager item for Presentation Items.
     It can present files using Openoffice
     """
-    global log
-    log = logging.getLogger(u'PresentationsMediaItem')
     log.info(u'Presentations Media Item loaded')
 
     def __init__(self, parent, icon, title, controllers):

=== modified file 'openlp/plugins/presentations/lib/messagelistener.py'
--- openlp/plugins/presentations/lib/messagelistener.py	2010-03-02 23:15:13 +0000
+++ openlp/plugins/presentations/lib/messagelistener.py	2010-03-05 10:25:28 +0000
@@ -30,13 +30,13 @@
 
 from openlp.core.lib import Receiver
 
+log = logging.getLogger(__name__)
+
 class Controller(object):
     """
     This is the Presentation listener who acts on events from the slide
     controller and passes the messages on the the correct presentation handlers
     """
-    global log
-    log = logging.getLogger(u'Controller')
     log.info(u'Controller loaded')
 
     def __init__(self, live):
@@ -152,8 +152,6 @@
     This is the Presentation listener who acts on events from the slide
     controller and passes the messages on the the correct presentation handlers
     """
-    global log
-    log = logging.getLogger(u'MessageListener')
     log.info(u'Message Listener loaded')
 
     def __init__(self, controllers):

=== modified file 'openlp/plugins/presentations/lib/powerpointcontroller.py'
--- openlp/plugins/presentations/lib/powerpointcontroller.py	2010-03-02 23:15:13 +0000
+++ openlp/plugins/presentations/lib/powerpointcontroller.py	2010-03-05 10:25:28 +0000
@@ -33,6 +33,8 @@
 
 from presentationcontroller import PresentationController,  PresentationDocument
 
+log = logging.getLogger(__name__)
+
 # PPT API documentation:
 # http://msdn.microsoft.com/en-us/library/aa269321(office.10).aspx
 
@@ -42,9 +44,7 @@
     It creates the runtime Environment , Loads the and Closes the Presentation
     As well as triggering the correct activities based on the users input
     """
-    global log
-    log = logging.getLogger(u'PowerpointController')
-    log.info(u'loaded')
+    log.info(u'PowerpointController loaded')
 
     def __init__(self, plugin):
         """

=== modified file 'openlp/plugins/presentations/lib/pptviewcontroller.py'
--- openlp/plugins/presentations/lib/pptviewcontroller.py	2010-03-02 23:15:13 +0000
+++ openlp/plugins/presentations/lib/pptviewcontroller.py	2010-03-05 10:25:28 +0000
@@ -32,15 +32,15 @@
 
 from presentationcontroller import PresentationController,  PresentationDocument
 
+log = logging.getLogger(__name__)
+
 class PptviewController(PresentationController):
     """
     Class to control interactions with PowerPOint Viewer Presentations
     It creates the runtime Environment , Loads the and Closes the Presentation
     As well as triggering the correct activities based on the users input
     """
-    global log
-    log = logging.getLogger(u'PptviewController')
-    log.info(u'loaded')
+    log.info(u'PPTViewController loaded')
 
     def __init__(self, plugin):
         """

=== modified file 'openlp/plugins/presentations/lib/presentationcontroller.py'
--- openlp/plugins/presentations/lib/presentationcontroller.py	2010-03-02 21:01:23 +0000
+++ openlp/plugins/presentations/lib/presentationcontroller.py	2010-03-05 10:25:28 +0000
@@ -31,6 +31,8 @@
 
 from openlp.core.lib import Receiver
 
+log = logging.getLogger(__name__)
+
 class PresentationController(object):
     """
     Base class for presentation controllers to inherit from
@@ -72,8 +74,6 @@
         Deletes presentation specific files, e.g. thumbnails
 
     """
-    global log
-    log = logging.getLogger(u'PresentationController')
     log.info(u'PresentationController loaded')
 
     def __init__(self, plugin=None, name=u'PresentationController'):

=== modified file 'openlp/plugins/presentations/presentationplugin.py'
--- openlp/plugins/presentations/presentationplugin.py	2010-02-06 10:33:33 +0000
+++ openlp/plugins/presentations/presentationplugin.py	2010-03-05 10:25:28 +0000
@@ -29,9 +29,9 @@
 from openlp.core.lib import Plugin, build_icon, Receiver, PluginStatus
 from openlp.plugins.presentations.lib import *
 
+log = logging.getLogger(__name__)
+
 class PresentationPlugin(Plugin):
-
-    global log
     log = logging.getLogger(u'PresentationPlugin')
 
     def __init__(self, plugin_helpers):

=== modified file 'openlp/plugins/remotes/remoteplugin.py'
--- openlp/plugins/remotes/remoteplugin.py	2010-02-06 10:33:33 +0000
+++ openlp/plugins/remotes/remoteplugin.py	2010-03-05 10:25:28 +0000
@@ -30,10 +30,9 @@
 from openlp.core.lib import Plugin, Receiver
 from openlp.plugins.remotes.lib import RemoteTab
 
+log = logging.getLogger(__name__)
+
 class RemotesPlugin(Plugin):
-
-    global log
-    log = logging.getLogger(u'RemotesPlugin')
     log.info(u'Remote Plugin loaded')
 
     def __init__(self, plugin_helpers):

=== modified file 'openlp/plugins/songs/lib/manager.py'
--- openlp/plugins/songs/lib/manager.py	2009-12-31 12:52:01 +0000
+++ openlp/plugins/songs/lib/manager.py	2010-03-05 10:25:28 +0000
@@ -28,14 +28,13 @@
 from openlp.plugins.songs.lib.models import init_models, metadata, Song, \
     Author, Topic, Book
 
+log = logging.getLogger(__name__)
+
 class SongManager():
     """
     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.
     """
-
-    global log
-    log = logging.getLogger(u'SongManager')
     log.info(u'Song manager loaded')
 
     def __init__(self, config):
@@ -238,3 +237,6 @@
             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-02-26 12:18:01 +0000
+++ openlp/plugins/songs/lib/mediaitem.py	2010-03-05 10:25:28 +0000
@@ -31,6 +31,8 @@
     BaseListWithDnD, Receiver,  str_to_bool
 from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm
 
+log = logging.getLogger(__name__)
+
 class SongListView(BaseListWithDnD):
     def __init__(self, parent=None):
         self.PluginName = u'Songs'
@@ -40,8 +42,6 @@
     """
     This is the custom media manager item for Songs.
     """
-    global log
-    log = logging.getLogger(u'SongMediaItem')
     log.info(u'Song Media Item loaded')
 
     def __init__(self, parent, icon, title):

=== modified file 'openlp/plugins/songs/songsplugin.py'
--- openlp/plugins/songs/songsplugin.py	2010-02-06 10:33:33 +0000
+++ openlp/plugins/songs/songsplugin.py	2010-03-05 10:25:28 +0000
@@ -32,6 +32,8 @@
 from openlp.plugins.songs.forms import OpenLPImportForm, OpenSongExportForm, \
     OpenSongImportForm, OpenLPExportForm
 
+log = logging.getLogger(__name__)
+
 class SongsPlugin(Plugin):
     """
     This is the number 1 plugin, if importance were placed on any
@@ -40,9 +42,6 @@
     specified. Authors, topics and song books can be assigned to songs
     as well.
     """
-
-    global log
-    log = logging.getLogger(u'SongsPlugin')
     log.info(u'Song Plugin loaded')
 
     def __init__(self, plugin_helpers):
@@ -180,3 +179,8 @@
         about_text = self.trUtf8('<b>Song Plugin</b> <br>This plugin allows '
             'Songs to be managed and displayed.<br>')
         return about_text
+
+    def can_delete_theme(self, theme):
+        if len(self.songmanager.get_songs_for_theme(theme)) == 0:
+            return True
+        return False

=== modified file 'openlp/plugins/songusage/forms/songusagedetailform.py'
--- openlp/plugins/songusage/forms/songusagedetailform.py	2010-02-11 18:39:28 +0000
+++ openlp/plugins/songusage/forms/songusagedetailform.py	2010-03-05 10:25:28 +0000
@@ -29,9 +29,9 @@
 
 from songusagedetaildialog import Ui_SongUsageDetailDialog
 
+log = logging.getLogger(__name__)
+
 class SongUsageDetailForm(QtGui.QDialog, Ui_SongUsageDetailDialog):
-    global log
-    log = logging.getLogger(u'SongUsageDetailForm')
     log.info(u'SongUsage Detail Form loaded')
     """
     Class documentation goes here.

=== modified file 'openlp/plugins/songusage/lib/manager.py'
--- openlp/plugins/songusage/lib/manager.py	2010-02-14 20:19:57 +0000
+++ openlp/plugins/songusage/lib/manager.py	2010-03-05 10:25:28 +0000
@@ -27,14 +27,13 @@
 
 from openlp.plugins.songusage.lib.models import init_models, metadata, SongUsageItem
 
+log = logging.getLogger(__name__)
+
 class SongUsageManager():
     """
     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.
     """
-
-    global log
-    log = logging.getLogger(u'SongUsageManager')
     log.info(u'SongUsage manager loaded')
 
     def __init__(self, config):

=== modified file 'openlp/plugins/songusage/songusageplugin.py'
--- openlp/plugins/songusage/songusageplugin.py	2010-02-06 10:33:33 +0000
+++ openlp/plugins/songusage/songusageplugin.py	2010-03-05 10:25:28 +0000
@@ -33,9 +33,9 @@
 from openlp.plugins.songusage.forms import SongUsageDetailForm, SongUsageDeleteForm
 from openlp.plugins.songusage.lib.models import SongUsageItem
 
+log = logging.getLogger(__name__)
+
 class SongUsagePlugin(Plugin):
-    global log
-    log = logging.getLogger(u'SongUsagePlugin')
     log.info(u'SongUsage Plugin loaded')
 
     def __init__(self, plugin_helpers):

=== added file 'resources/forms/serviceitemdialog.ui'
--- resources/forms/serviceitemdialog.ui	1970-01-01 00:00:00 +0000
+++ resources/forms/serviceitemdialog.ui	2010-03-05 10:25:28 +0000
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ServiceNoteEdit</class>
+ <widget class="QWidget" name="ServiceNoteEdit">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>243</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Service Item Notes</string>
+  </property>
+  <widget class="QWidget" name="">
+   <property name="geometry">
+    <rect>
+     <x>20</x>
+     <y>10</y>
+     <width>361</width>
+     <height>223</height>
+    </rect>
+   </property>
+   <layout class="QVBoxLayout" name="verticalLayout">
+    <item>
+     <widget class="QTextEdit" name="textEdit"/>
+    </item>
+    <item>
+     <widget class="QDialogButtonBox" name="buttonBox">
+      <property name="standardButtons">
+       <set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>


Follow ups