← Back to team overview

openlp-core team mailing list archive

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

 

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

Requested reviews:
    openlp.org Core (openlp-core)

Tested with new Config code and still works.
Songs now have Authors / Topics and SongBook tabs working and attached (issue with deleting last row though)
Bible bug fixes and cleanups following initial testing.
Songs now talk to ServiceManager so can be rendered.
Songs plugin much more standard than before but much more to do.
-- 
https://code.launchpad.net/~trb143/openlp/servicing/+merge/7089
Your team openlp.org Core is subscribed to branch lp:openlp.
=== modified file 'openlp/core/lib/eventreceiver.py'
--- openlp/core/lib/eventreceiver.py	2009-05-20 20:17:20 +0000
+++ openlp/core/lib/eventreceiver.py	2009-06-04 16:14:10 +0000
@@ -28,7 +28,7 @@
         QtCore.QObject.__init__(self)
 
     def send_message(self, event, msg=None):
-        self.emit(SIGNAL(event), msg)
+        self.emit(QtCore.SIGNAL(event), msg)
 
     def received(self, msg=None):
         print msg

=== modified file 'openlp/core/lib/renderer.py'
--- openlp/core/lib/renderer.py	2009-06-02 16:25:36 +0000
+++ openlp/core/lib/renderer.py	2009-06-03 15:38:14 +0000
@@ -109,7 +109,7 @@
         """
         External API to sort out the text to pe placed on the frame
         """
-        #print "########## Format Slide ##################"
+        print "########## Format Slide ##################"
         log.debug(u'format_slide %s', words)
         verses = []
         words = words.replace("\r\n", "\n")
@@ -121,8 +121,8 @@
                 text.append(line)
 
         split_text = self._split_set_of_lines(text, False)
-        #print "split text ", split_text
-        #print "text ", text
+        print "split text ", split_text
+        print "text ", text
         return split_text
 
 #    def render_screen(self, screennum):

=== modified file 'openlp/core/lib/serviceitem.py'
--- openlp/core/lib/serviceitem.py	2009-06-02 16:25:36 +0000
+++ openlp/core/lib/serviceitem.py	2009-06-04 16:14:10 +0000
@@ -65,7 +65,6 @@
         if len(self.frames) == 0 and len(self.raw_slides) > 0 :
             for slide in self.raw_slides:
                 formated = self.plugin.render_manager.format_slide(slide)
-                #print formated
                 for format in formated:
                     frame = self.plugin.render_manager.generate_slide(format, self.raw_footer)
                     self.frames.append({u'title': format, u'image': frame})

=== modified file 'openlp/core/ui/servicemanager.py'
--- openlp/core/ui/servicemanager.py	2009-06-01 17:50:37 +0000
+++ openlp/core/ui/servicemanager.py	2009-06-04 16:14:10 +0000
@@ -132,7 +132,7 @@
     def addServiceItem(self, item):
         self.serviceItems.append({u'data': item, u'order': len(self.serviceItems)+1})
         treewidgetitem = QtGui.QTreeWidgetItem(self.ServiceManagerList)
-        treewidgetitem.setText(0,item.title + u':' + item.shortname)
+        treewidgetitem.setText(0,item.title) # + u':' + item.shortname)
         treewidgetitem.setIcon(0,item.iconic_representation)
         treewidgetitem.setData(0, QtCore.Qt.UserRole, QtCore.QVariant(len(self.serviceItems)))
         treewidgetitem.setExpanded(True)

=== modified file 'openlp/core/ui/slidecontroller.py'
--- openlp/core/ui/slidecontroller.py	2009-06-02 19:02:12 +0000
+++ openlp/core/ui/slidecontroller.py	2009-06-04 19:00:41 +0000
@@ -53,7 +53,7 @@
         self.beginInsertRows(QtCore.QModelIndex(), row, row)
         log.info(u'insert row %d' % row)
         # create a preview image
-        frame1 = frame.scaled(QtCore.QSize(300, 225), QtCore.Qt.KeepAspectRatio,
+        frame1 = frame.scaled(QtCore.QSize(280, 210), QtCore.Qt.KeepAspectRatio,
             QtCore.Qt.SmoothTransformation)
         self.items.insert(row, (frame1, framenumber))
         log.info(u'Items: %s' % self.items)
@@ -196,7 +196,7 @@
         sizePolicy.setHeightForWidth(
             self.SlidePreview.sizePolicy().hasHeightForWidth())
         self.SlidePreview.setSizePolicy(sizePolicy)
-        self.SlidePreview.setMinimumSize(QtCore.QSize(250, 190))
+        self.SlidePreview.setMinimumSize(QtCore.QSize(280, 210))
         self.SlidePreview.setFrameShape(QtGui.QFrame.Box)
         self.SlidePreview.setFrameShadow(QtGui.QFrame.Plain)
         self.SlidePreview.setLineWidth(1)

=== modified file 'openlp/plugins/bibles/forms/bibleimportform.py'
--- openlp/plugins/bibles/forms/bibleimportform.py	2009-03-19 17:31:33 +0000
+++ openlp/plugins/bibles/forms/bibleimportform.py	2009-06-05 05:00:26 +0000
@@ -23,19 +23,16 @@
 import time
 import logging
 
-from openlp.core.resources import *
-
 from PyQt4 import QtCore, QtGui
-from PyQt4.QtGui import QDialog
 
 from bibleimportdialog import Ui_BibleImportDialog
-from openlp.core.lib import Receiver
-
-
-class BibleImportForm(QDialog, Ui_BibleImportDialog):
+from openlp.core.lib import Receiver,  translate
+
+
+class BibleImportForm(QtGui.QDialog, Ui_BibleImportDialog):
     global log
     log=logging.getLogger("BibleImportForm")
-    log.info("BibleImportForm loaded")    
+    log.info("BibleImportForm loaded")
     """
     Class documentation goes here.
     """
@@ -43,7 +40,7 @@
         """
         Constructor
         """
-        QDialog.__init__(self, parent)
+        QtGui.QDialog.__init__(self, parent)
         self.setupUi(self)
         self.biblemanager = biblemanager
         self.config = config
@@ -53,9 +50,9 @@
         self.AddressEdit.setText(self.config.get_config("proxy_address", ""))
         self.UsernameEdit.setText(self.config.get_config("proxy_username", ""))
         self.PasswordEdit.setText(self.config.get_config("proxy_password",""))
-        
+
         filepath = os.path.split(os.path.abspath(__file__))[0]
-        filepath = os.path.abspath(os.path.join(filepath, '..', 'resources','crosswalkbooks.csv')) 
+        filepath = os.path.abspath(os.path.join(filepath, '..', 'resources','crosswalkbooks.csv'))
         fbibles=open(filepath, 'r')
         self.bible_versions = {}
         self.BibleComboBox.clear()
@@ -64,125 +61,136 @@
             p = line.split(",")
             self.bible_versions[p[0]] = p[1].replace('\n', '')
             self.BibleComboBox.addItem(str(p[0]))
-   
+
         #Combo Boxes
         QtCore.QObject.connect(self.LocationComboBox, QtCore.SIGNAL("activated(int)"), self.onLocationComboBoxSelected)
         QtCore.QObject.connect(self.BibleComboBox, QtCore.SIGNAL("activated(int)"), self.onBibleComboBoxSelected)
 
-        #Buttons 
-        QtCore.QObject.connect(self.ImportButton, QtCore.SIGNAL("pressed()"), self.onImportButtonClicked)        
+        #Buttons
+        QtCore.QObject.connect(self.ImportButton, QtCore.SIGNAL("pressed()"), self.onImportButtonClicked)
         QtCore.QObject.connect(self.CancelButton, QtCore.SIGNAL("pressed()"), self.onCancelButtonClicked)
         QtCore.QObject.connect(self.VersesFileButton, QtCore.SIGNAL("pressed()"), self.onVersesFileButtonClicked)
         QtCore.QObject.connect(self.BooksFileButton, QtCore.SIGNAL("pressed()"), self.onBooksFileButtonClicked)
-        QtCore.QObject.connect(self.OsisFileButton, QtCore.SIGNAL("pressed()"), self.onOsisFileButtonClicked)        
-        
+        QtCore.QObject.connect(self.OsisFileButton, QtCore.SIGNAL("pressed()"), self.onOsisFileButtonClicked)
+
         #Lost Focus
         QtCore.QObject.connect(self.OSISLocationEdit, QtCore.SIGNAL("lostFocus()"), self.onOSISLocationEditLostFocus)
         QtCore.QObject.connect(self.BooksLocationEdit, QtCore.SIGNAL("lostFocus()"),self.onBooksLocationEditLostFocus)
         QtCore.QObject.connect(self.VerseLocationEdit, QtCore.SIGNAL("lostFocus()"), self.onVerseLocationEditLostFocus)
         QtCore.QObject.connect(self.AddressEdit, QtCore.SIGNAL("lostFocus()"), self.onProxyAddressEditLostFocus)
         QtCore.QObject.connect(self.UsernameEdit, QtCore.SIGNAL("lostFocus()"), self.onProxyUsernameEditLostFocus)
-        QtCore.QObject.connect(self.PasswordEdit, QtCore.SIGNAL("lostFocus()"), self.onProxyPasswordEditLostFocus)        
+        QtCore.QObject.connect(self.PasswordEdit, QtCore.SIGNAL("lostFocus()"), self.onProxyPasswordEditLostFocus)
 
 
     def onVersesFileButtonClicked(self):
         filename = QtGui.QFileDialog.getOpenFileName(self, 'Open file',self.config.get_last_dir(1))
         if filename != "":
-            self.VerseLocationEdit.setText(filename)            
+            self.VerseLocationEdit.setText(filename)
             self.config.set_last_dir(filename, 1)
-            self.setCsv()        
-        
+            self.setCsv()
+
     def onBooksFileButtonClicked(self):
         filename = QtGui.QFileDialog.getOpenFileName(self, 'Open file',self.config.get_last_dir(2))
-        if filename != "": 
-            self.BooksLocationEdit.setText(filename)            
+        if filename != "":
+            self.BooksLocationEdit.setText(filename)
             self.config.set_last_dir(filename, 2)
-            self.setCsv()                
-    
+            self.setCsv()
+
     def onOsisFileButtonClicked(self):
         filename = QtGui.QFileDialog.getOpenFileName(self, 'Open file',self.config.get_last_dir(3))
-        if filename != "":        
+        if filename != "":
             self.OSISLocationEdit.setText(filename)
             self.config.set_last_dir(filename, 3)
             self.setOsis()
- 
+
     def onOSISLocationEditLostFocus(self):
         if len(self.OSISLocationEdit.displayText() ) > 0:
             self.setOsis()
         else:
-            if self.bible_type == "OSIS": # Was OSIS and is not any more stops lostFocus running mad
-                self.bible_type = None        
+            # Was OSIS and is not any more stops lostFocus running mad
+            if self.bible_type == "OSIS":
+                self.bible_type = None
                 self.freeAll()
-            
+
     def onBooksLocationEditLostFocus(self):
         self.checkOsis()
-        
+
     def onVerseLocationEditLostFocus(self):
         self.checkOsis()
-        
+
     def onProxyAddressEditLostFocus(self):
         self.config.set_config("proxy_address", str(self.AddressEdit.displayText()))
 
     def onProxyUsernameEditLostFocus(self):
         self.config.set_config("proxy_username", str(self.UsernameEdit.displayText()))
-    
+
     def onProxyPasswordEditLostFocus(self):
         self.config.set_config("proxy_password", str(self.PasswordEdit.displayText()))
-        
+
     def onLocationComboBoxSelected(self):
-        self.checkHttp()        
-        
+        self.checkHttp()
+
     def onBibleComboBoxSelected(self):
         self.checkHttp()
         self.BibleNameEdit.setText(str(self.BibleComboBox.currentText()))
-        
+
     def onCancelButtonClicked(self):
         # tell import to stop
-        Receiver().send_message("openlpstopimport") 
+        Receiver().send_message("openlpstopimport")
         # tell bibleplugin to reload the bibles
         Receiver().send_message("openlpreloadbibles")
-        self.close() 
-        
+        self.close()
+
     def onImportButtonClicked(self):
         if self.biblemanager != None:
             if not self.bible_type == None and len(self.BibleNameEdit.displayText()) > 0:
                 self.MessageLabel.setText("Import Started")
-                self.ProgressBar.setMinimum(0) 
+                self.ProgressBar.setMinimum(0)
                 self.setMax(65)
                 self.ProgressBar.setValue(0)
                 self.biblemanager.process_dialog(self)
                 self.importBible()
                 self.MessageLabel.setText("Import Complete")
-                self.ProgressBar.setValue(self.barmax) 
+                self.ProgressBar.setValue(self.barmax)
                 # tell bibleplugin to reload the bibles
-                Receiver().send_message("openlpreloadbibles") 
+                Receiver().send_message("openlpreloadbibles")
+                message = u'Bible import completered'
+                reply = QtGui.QMessageBox.information(self,
+                    translate(u'BibleMediaItem', u'Information'),
+                    translate(u'BibleMediaItem', message))
 
     def setMax(self, max):
-        log.debug("set Max %s", max)        
+        log.debug("set Max %s", max)
         self.barmax = max
-        self.ProgressBar.setMaximum(max)        
+        self.ProgressBar.setMaximum(max)
 
     def incrementProgressBar(self, text ):
         log.debug("IncrementBar %s", text)
         self.MessageLabel.setText("Import processing " + text)
         self.ProgressBar.setValue(self.ProgressBar.value()+1)
-                
+
     def importBible(self):
         log.debug("Import Bible ")
         if self.bible_type == "OSIS":
-            self.biblemanager.register_osis_file_bible(str(self.BibleNameEdit.displayText()), self.OSISLocationEdit.displayText())
+            loaded = self.biblemanager.register_osis_file_bible(str(self.BibleNameEdit.displayText()),
+                self.OSISLocationEdit.displayText())
         elif self.bible_type == "CSV":
-            self.biblemanager.register_csv_file_bible(str(self.BibleNameEdit.displayText()), self.BooksLocationEdit.displayText(), self.VerseLocationEdit.displayText())
+            loaded = self.biblemanager.register_csv_file_bible(str(self.BibleNameEdit.displayText()),
+                self.BooksLocationEdit.displayText(), self.VerseLocationEdit.displayText())
         else:
             self.setMax(1) # set a value as it will not be needed
             bible = self.bible_versions[str(self.BibleComboBox.currentText())]
-            self.biblemanager.register_http_bible(str(self.BibleComboBox.currentText()), \
+            loaded = self.biblemanager.register_http_bible(str(self.BibleComboBox.currentText()), \
                                                                                      str(self.LocationComboBox.currentText()),  \
                                                                                      str(bible), \
                                                                                      str(self.AddressEdit.displayText()),  \
                                                                                      str(self.UsernameEdit .displayText()),  \
-                                                                                     str(self.PasswordEdit.displayText())) 
-        self.biblemanager.save_meta_data(str(self.BibleNameEdit.displayText()), str(self.VersionNameEdit.displayText()), str(self.CopyrightEdit.displayText()), str(self.PermisionEdit.displayText()))
+                                                                                     str(self.PasswordEdit.displayText()))
+        if loaded:
+            self.biblemanager.save_meta_data(str(self.BibleNameEdit.displayText()),
+                str(self.VersionNameEdit.displayText()),
+                str(self.CopyrightEdit.displayText()),
+                str(self.PermisionEdit.displayText()))
         self.bible_type = None
         self.freeAll() # free the screen state restrictions
         self.resetAll() # reset all the screen fields
@@ -191,16 +199,18 @@
         if len(self.BooksLocationEdit.displayText()) > 0 or len(self.VerseLocationEdit.displayText()) > 0:
             self.setCsv()
         else:
-            if self.bible_type == "CSV": # Was CSV and is not any more stops lostFocus running mad
-                self.bible_type = None        
+            # Was CSV and is not any more stops lostFocus running mad
+            if self.bible_type == "CSV":
+                self.bible_type = None
                 self.freeAll()
-        
+
     def checkHttp(self):
         if self.BibleComboBox.currentIndex() != 0 :  # First slot is blank so no bible
             self.setHttp()
         else:
-            if self.bible_type == "HTTP": # Was HTTP and is not any more stops lostFocus running mad
-                self.bible_type = None        
+            # Was HTTP and is not any more stops lostFocus running mad
+            if self.bible_type == "HTTP":
+                self.bible_type = None
                 self.freeAll()
 
     def blockCsv(self):
@@ -208,48 +218,48 @@
         self.VerseLocationEdit.setReadOnly(True)
         self.BooksFileButton.setEnabled(False)
         self.VersesFileButton.setEnabled(False)
-        
+
     def setCsv(self):
-        self.bible_type = "CSV" 
+        self.bible_type = "CSV"
         self.BooksLocationEdit.setReadOnly(False)
-        self.VerseLocationEdit.setReadOnly(False) 
+        self.VerseLocationEdit.setReadOnly(False)
         self.BooksFileButton.setEnabled(True)
         self.VersesFileButton.setEnabled(True)
         self.blockOsis()
-        self.blockHttp()        
-        
+        self.blockHttp()
+
     def setOsis(self):
-        self.bible_type = "OSIS"         
+        self.bible_type = "OSIS"
         self.OSISLocationEdit.setReadOnly(False)
-        self.OsisFileButton.setEnabled(True)        
+        self.OsisFileButton.setEnabled(True)
         self.blockCsv()
-        self.blockHttp()        
- 
+        self.blockHttp()
+
     def blockOsis(self):
         self.OSISLocationEdit.setReadOnly(True)
         self.OsisFileButton.setEnabled(False)
-        
+
     def setHttp(self):
-        self.bible_type = "HTTP"         
+        self.bible_type = "HTTP"
         self.LocationComboBox.setEnabled(True)
-        self.BibleComboBox.setEnabled(True)        
+        self.BibleComboBox.setEnabled(True)
         self.blockCsv()
-        self.blockOsis()        
- 
+        self.blockOsis()
+
     def blockHttp(self):
-        self.LocationComboBox.setEnabled(False)        
-        self.BibleComboBox.setEnabled(False)                
-        
+        self.LocationComboBox.setEnabled(False)
+        self.BibleComboBox.setEnabled(False)
+
     def freeAll(self):
-        if self.bible_type == None:  # only reset if no bible type set.  
+        if self.bible_type == None:  # only reset if no bible type set.
             self.BooksLocationEdit.setReadOnly(False)
-            self.VerseLocationEdit.setReadOnly(False) 
+            self.VerseLocationEdit.setReadOnly(False)
             self.BooksFileButton.setEnabled(True)
             self.VersesFileButton.setEnabled(True)
             self.OSISLocationEdit.setReadOnly(False)
-            self.OsisFileButton.setEnabled(True) 
+            self.OsisFileButton.setEnabled(True)
             self.LocationComboBox.setEnabled(True)
-            self.BibleComboBox.setEnabled(True)        
+            self.BibleComboBox.setEnabled(True)
 
     def resetAll(self):
         self.BooksLocationEdit.setText("")

=== modified file 'openlp/plugins/bibles/lib/bibleDBimpl.py'
--- openlp/plugins/bibles/lib/bibleDBimpl.py	2009-05-01 22:26:43 +0000
+++ openlp/plugins/bibles/lib/bibleDBimpl.py	2009-06-05 05:00:26 +0000
@@ -38,7 +38,7 @@
         self.config = config
         self.biblefile = os.path.join(biblepath, biblename+u'.sqlite')
         log.debug( "Load bible %s on path %s", biblename, self.biblefile)
-        db_type = self.config.get_config(u'db type')
+        db_type = self.config.get_config(u'db type', u'sqlite')
         if db_type  == u'sqlite':
             self.db = create_engine("sqlite:///" + self.biblefile)
         else:
@@ -101,6 +101,7 @@
         return book
 
     def save_meta(self, key, value):
+        log.debug( "save_meta %s/%s", key, value)
         metadata.bind.echo = False
         session = self.session()
         bmeta= BibleMeta()

=== modified file 'openlp/plugins/bibles/lib/bibleOSISimpl.py'
--- openlp/plugins/bibles/lib/bibleOSISimpl.py	2009-03-16 17:33:51 +0000
+++ openlp/plugins/bibles/lib/bibleOSISimpl.py	2009-06-04 20:06:32 +0000
@@ -15,7 +15,7 @@
 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 Place, Suite 330, Boston, MA 02111-1307 USA
 """
-import os 
+import os
 import os.path
 import logging
 from openlp.plugins.bibles.lib.bibleDBimpl import BibleDBImpl
@@ -23,28 +23,28 @@
 from PyQt4 import QtCore
 
 class BibleOSISImpl():
-    global log     
+    global log
     log=logging.getLogger(u'BibleOSISImpl')
     log.info(u'BibleOSISImpl loaded')
-    
+
     def __init__(self, biblepath, bibledb):
         self.bibledb = bibledb
         self.booksOfBible = {} # books of the bible linked to bibleid  {osis , name}
         self.abbrevOfBible = {} # books of the bible linked to bibleid  {osis ,Abbrev }
-        
+
         filepath = os.path.split(os.path.abspath(__file__))[0]
-        filepath = os.path.abspath(os.path.join(filepath, '..', 'resources','osisbooks.csv')) 
+        filepath = os.path.abspath(os.path.join(filepath, '..', 'resources','osisbooks.csv'))
         fbibles=open(filepath, 'r')
         for line in fbibles:
             p = line.split(",")
             self.booksOfBible[p[0]] = p[1].replace('\n', '')
-            self.abbrevOfBible[p[0]] = p[2].replace('\n', '') 
+            self.abbrevOfBible[p[0]] = p[2].replace('\n', '')
         self.loadbible = True
         QtCore.QObject.connect(Receiver().get_receiver(),QtCore.SIGNAL("openlpstopimport"),self.stop_import)
-                
+
     def stop_import(self):
         self.loadbible= False
-        
+
     def load_data(self, osisfile, dialogobject=None):
         osis=open(osisfile, 'r')
 
@@ -61,27 +61,27 @@
             pos = file.find(verseText)
             if pos > -1: # we have a verse
                 epos= file.find(">", pos)
-                ref =  file[pos+15:epos-1]  # Book Reference 
-                
+                ref =  file[pos+15:epos-1]  # Book Reference
+
                 #lets find the bible text only
                 pos = epos + 1 # find start of text
                 epos = file.find("</verse>", pos) # end  of text
-                text = file[pos : epos] 
+                text = unicode(file[pos : epos], u'utf8')
                 #print pos, e, f[pos:e] # Found Basic Text
 
                 #remove tags of extra information
                 text = self.remove_block(u'<title',u'</title>', text)
-                text = self.remove_block(u'<note',u'</note>', text)                
-                text = self.remove_block(u'<divineName',u'</divineName>', text)                
-                        
-                text = self.remove_tag(u'<lb',  text) 
-                text = self.remove_tag(u'<q',  text)  
-                text = self.remove_tag(u'<l',  text)                          
-                text = self.remove_tag(u'<lg',  text)  
+                text = self.remove_block(u'<note',u'</note>', text)
+                text = self.remove_block(u'<divineName',u'</divineName>', text)
+
+                text = self.remove_tag(u'<lb',  text)
+                text = self.remove_tag(u'<q',  text)
+                text = self.remove_tag(u'<l',  text)
+                text = self.remove_tag(u'<lg',  text)
 
                 # Strange tags where the end is not the same as the start
                 # The must be in this order as at least one bible has them
-                # crossing and the removal does not work. 
+                # crossing and the removal does not work.
                 pos = text.find(u'<FI>')
                 while pos > -1:
                     epos = text.find(u'<Fi>', pos)
@@ -90,7 +90,7 @@
                         pos = -1
                     else:
                         text =  text[:pos] + text[epos + 4: ]
-                        pos = text.find(u'<FI>') 
+                        pos = text.find(u'<FI>')
 
                 pos = text.find(u'<RF>')
                 while pos > -1:
@@ -98,9 +98,9 @@
                     text =  text[:pos] + text[epos + 4: ]
                     #print "X", pos, epos, text
                     pos = text.find(u'<RF>')
-  
+
                 p = ref.split(u'.', 3)  # split up the reference
-                #print p, ">>>", text  
+                #print p, ">>>", text
 
                 if book_ptr != p[0]:
                     if book_ptr == None:  # first time through
@@ -113,14 +113,14 @@
                     book_ptr = p[0]
                     book = self.bibledb.create_book(self.booksOfBible[p[0]] , self.abbrevOfBible[p[0]], testament)
                     dialogobject.incrementProgressBar(self.booksOfBible[p[0]] )
-                    Receiver().send_message("openlpprocessevents")                                        
+                    Receiver().send_message("openlpprocessevents")
                     count = 0
                 self.bibledb.add_verse(book.id, p[1], p[2], text)
                 count += 1
                 if count % 3 == 0:   #Every 3 verses repaint the screen
-                    Receiver().send_message("openlpprocessevents")                    
+                    Receiver().send_message("openlpprocessevents")
                     count = 0
-                    
+
     def remove_block(self, start_tag, end_tag,  text):
         """
         removes a block of text between two tags
@@ -134,9 +134,9 @@
                 pos = -1
             else:
                 text =  text[:pos] + text[epos + len(end_tag): ]
-                pos = text.find(start_tag) 
+                pos = text.find(start_tag)
         return text
-        
+
     def remove_tag(self, start_tag,  text):
         """
         removes a single tag
@@ -146,5 +146,5 @@
         while pos > -1:
             epos = text.find(u'/>', pos)
             text =  text[:pos] + text[epos + 2: ]
-            pos = text.find(start_tag)         
+            pos = text.find(start_tag)
         return text

=== modified file 'openlp/plugins/bibles/lib/manager.py'
--- openlp/plugins/bibles/lib/manager.py	2009-04-25 06:09:47 +0000
+++ openlp/plugins/bibles/lib/manager.py	2009-06-05 05:00:26 +0000
@@ -128,7 +128,10 @@
                 nbible.save_meta("proxyid", proxyid) # store the proxy userid
             if proxypass != None and proxypass != "":
                 nbible.save_meta("proxypass", proxypass) # store the proxy password
-
+            return True
+        else:
+            log.debug( "register_http_file_bible %s not created already exists", biblename)
+            return False
 
     def register_csv_file_bible(self, biblename, booksfile, versefile):
         """
@@ -143,6 +146,10 @@
             self.bible_db_cache[biblename] = nbible # cache the database for use later
             bcsv = BibleCSVImpl(nbible) # create the loader and pass in the database
             bcsv.load_data(booksfile, versefile, self.dialogobject)
+            return True
+        else:
+            log.debug( "register_csv_file_bible %s not created already exists", biblename)
+            return False
 
     def register_osis_file_bible(self, biblename, osisfile):
         """
@@ -157,6 +164,10 @@
             self.bible_db_cache[biblename] = nbible # cache the database for use later
             bcsv = BibleOSISImpl(self.biblePath, nbible) # create the loader and pass in the database
             bcsv.load_data(osisfile, self.dialogobject)
+            return True
+        else:
+            log.debug( "register_OSIS_file_bible %s , %s not created already exists", biblename, osisfile)
+            return False
 
     def get_bibles(self, mode="full"):
         log.debug("get_bibles")

=== modified file 'openlp/plugins/bibles/lib/mediaitem.py'
--- openlp/plugins/bibles/lib/mediaitem.py	2009-06-01 17:50:37 +0000
+++ openlp/plugins/bibles/lib/mediaitem.py	2009-06-05 05:00:26 +0000
@@ -283,7 +283,7 @@
                 self.initialiseBible(bible) # use the first bible as the trigger
 
     def onAdvancedVersionComboBox(self):
-        self.initialiseBible(str(self.AdvancedVersionComboBox.currentText())) # restet the bible info
+        self.initialiseBible(str(self.AdvancedVersionComboBox.currentText())) # reset the bible info
 
     def onAdvancedBookComboBox(self):
         self.initialiseBible(str(self.AdvancedVersionComboBox.currentText())) # reset the bible info
@@ -291,7 +291,7 @@
     def onBibleNewClick(self):
         self.bibleimportform = BibleImportForm(self.parent.config, self.parent.biblemanager, self)
         self.bibleimportform.exec_()
-        pass
+        self.reloadBibles()
 
     def onAdvancedFromVerse(self):
         frm = self.AdvancedFromVerse.currentText()
@@ -417,22 +417,14 @@
 
     def initialiseBible(self, bible):
         log.debug(u"initialiseBible %s", bible)
-        current_book = str(self.AdvancedBookComboBox.currentText())
-        chapter_count = self.parent.biblemanager.get_book_chapter_count(bible,
-            current_book)[0]
-        log.debug(u'Book change bible %s book %s ChapterCount %s', bible,
-            current_book, chapter_count)
-        if chapter_count == None:
-            # Only change the search details if the book is missing from the new bible
-            books = self.parent.biblemanager.get_bible_books(str(
-                self.AdvancedVersionComboBox.currentText()))
-            self.AdvancedBookComboBox.clear()
-            first = True
-            for book in books:
-                self.AdvancedBookComboBox.addItem(book.name)
-                if first:
-                    first = False
-                    self.initialiseChapterVerse(bible, book.name)
+        books = self.parent.biblemanager.get_bible_books(str(bible))
+        self.AdvancedBookComboBox.clear()
+        first = True
+        for book in books:
+            self.AdvancedBookComboBox.addItem(book.name)
+            if first:
+                first = False
+                self.initialiseChapterVerse(bible, book.name)
 
     def initialiseChapterVerse(self, bible, book):
         log.debug(u"initialiseChapterVerse %s , %s", bible, book)

=== modified file 'openlp/plugins/custom/lib/__init__.py'
--- openlp/plugins/custom/lib/__init__.py	2009-03-17 05:05:04 +0000
+++ openlp/plugins/custom/lib/__init__.py	2009-06-03 15:38:14 +0000
@@ -3,7 +3,7 @@
 """
 OpenLP - Open Source Lyrics Projection
 Copyright (c) 2008 Raoul Snyman
-Portions copyright (c) 2008 Martin Thompson, Tim Bentley
+Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley
 
 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
@@ -23,6 +23,3 @@
 from manager import CustomManager
 from customtab import CustomTab
 from mediaitem import CustomMediaItem
-
-__all__ = ['CustomManager', 'CustomTab', 'CustomMediaItem', 'CustomServiceItem','TextListData']
-

=== modified file 'openlp/plugins/custom/lib/mediaitem.py'
--- openlp/plugins/custom/lib/mediaitem.py	2009-06-01 17:50:37 +0000
+++ openlp/plugins/custom/lib/mediaitem.py	2009-06-03 15:38:14 +0000
@@ -228,11 +228,11 @@
         self.parent.service_manager.addServiceItem(service_item)
 
     def generateSlideData(self, service_item):
-        indexes = self.CustomListView.selectedIndexes()
         raw_slides =[]
         raw_footer = []
         slide = None
         theme = None
+        indexes = self.CustomListView.selectedIndexes()
         for index in indexes:
             id = self.CustomListData.getId(index)
             customSlide = self.parent.custommanager.get_custom(id)

=== modified file 'openlp/plugins/custom/lib/textlistdata.py'
--- openlp/plugins/custom/lib/textlistdata.py	2009-05-21 16:07:01 +0000
+++ openlp/plugins/custom/lib/textlistdata.py	2009-06-03 15:38:14 +0000
@@ -1,3 +1,22 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+"""
+OpenLP - Open Source Lyrics Projection
+Copyright (c) 2008 Raoul Snyman
+Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley
+
+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, QtGui
@@ -7,16 +26,16 @@
     An abstract list of strings
     """
     global log
-    log=logging.getLogger(u'TextListData')
+    log = logging.getLogger(u'TextListData')
     log.info(u'started')
 
     def __init__(self):
         QtCore.QAbstractListModel.__init__(self)
-        self.items=[] # will be a list of (database id , title) tuples
+        self.items = [] # will be a list of (database id , title) tuples
 
     def resetStore(self):
         #reset list so can be reloaded
-        self.items=[]
+        self.items = []
 
     def rowCount(self, parent):
         return len(self.items)
@@ -36,7 +55,7 @@
         self.insertRow(len(self.items), id, title)
 
     def data(self, index, role):
-        row=index.row()
+        row = index.row()
         if row > len(self.items): # if the last row is selected and deleted, we then get called with an empty row!
             return QtCore.QVariant()
         if role == QtCore.Qt.DisplayRole:

=== modified file 'openlp/plugins/presentations/lib/mediaitem.py'
--- openlp/plugins/presentations/lib/mediaitem.py	2009-05-22 18:30:25 +0000
+++ openlp/plugins/presentations/lib/mediaitem.py	2009-06-04 16:14:10 +0000
@@ -119,7 +119,7 @@
     def onPresentationNewClick(self):
         files = QtGui.QFileDialog.getOpenFileNames(None,
             translate('PresentationsMediaItem', u'Select presentations(s)'),
-            self.parent.config.get_last_dir(), u'Presentations (*.ppt *.pps *.odi)')
+            self.parent.config.get_last_dir(), u'Presentations (*.ppt *.pps *.odp)')
         if len(files) > 0:
             self.loadPresentationList(files)
             dir, filename = os.path.split(str(files[0]))

=== modified file 'openlp/plugins/songs/forms/__init__.py'
--- openlp/plugins/songs/forms/__init__.py	2009-03-09 12:49:55 +0000
+++ openlp/plugins/songs/forms/__init__.py	2009-06-03 17:32:53 +0000
@@ -3,7 +3,7 @@
 """
 OpenLP - Open Source Lyrics Projection
 Copyright (c) 2008 Raoul Snyman
-Portions copyright (c) 2008 Martin Thompson, Tim Bentley,
+Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley,
 
 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

=== modified file 'openlp/plugins/songs/forms/authorsdialog.py'
--- openlp/plugins/songs/forms/authorsdialog.py	2009-03-09 18:47:37 +0000
+++ openlp/plugins/songs/forms/authorsdialog.py	2009-06-04 19:00:41 +0000
@@ -8,6 +8,7 @@
 # WARNING! All changes made in this file will be lost!
 
 from PyQt4 import QtCore, QtGui
+from openlp.plugins.songs.lib import TextListData
 
 class Ui_AuthorsDialog(object):
     def setupUi(self, AuthorsDialog):
@@ -17,14 +18,13 @@
         self.DialogLayout.setSpacing(8)
         self.DialogLayout.setMargin(8)
         self.DialogLayout.setObjectName("DialogLayout")
-        self.AuthorListView = QtGui.QTableWidget(AuthorsDialog)
-        self.AuthorListView.setDragEnabled(True)
+
+        self.AuthorListView = QtGui.QListView()
         self.AuthorListView.setAlternatingRowColors(True)
-        self.AuthorListView.setColumnCount(0)
-        self.AuthorListView.setObjectName("AuthorListView")
-        self.AuthorListView.setColumnCount(0)
-        self.AuthorListView.setRowCount(0)
+        self.AuthorListData = TextListData()
+        self.AuthorListView.setModel(self.AuthorListData)
         self.DialogLayout.addWidget(self.AuthorListView)
+
         self.AuthorDetails = QtGui.QGroupBox(AuthorsDialog)
         self.AuthorDetails.setMinimumSize(QtCore.QSize(0, 0))
         self.AuthorDetails.setObjectName("AuthorDetails")
@@ -107,7 +107,7 @@
         self.FirstNameLabel.setText(QtGui.QApplication.translate("AuthorsDialog", "First Name:", None, QtGui.QApplication.UnicodeUTF8))
         self.LastNameLabel.setText(QtGui.QApplication.translate("AuthorsDialog", "Last Name:", None, QtGui.QApplication.UnicodeUTF8))
         self.ClearButton.setToolTip(QtGui.QApplication.translate("AuthorsDialog", "Clear Selection", None, QtGui.QApplication.UnicodeUTF8))
-        self.ClearButton.setText(QtGui.QApplication.translate("AuthorsDialog", "New", None, QtGui.QApplication.UnicodeUTF8))
+        self.ClearButton.setText(QtGui.QApplication.translate("AuthorsDialog", "Clear", None, QtGui.QApplication.UnicodeUTF8))
         self.AddUpdateButton.setToolTip(QtGui.QApplication.translate("AuthorsDialog", "Add Update Author", None, QtGui.QApplication.UnicodeUTF8))
         self.AddUpdateButton.setText(QtGui.QApplication.translate("AuthorsDialog", "Save", None, QtGui.QApplication.UnicodeUTF8))
         self.DeleteButton.setToolTip(QtGui.QApplication.translate("AuthorsDialog", "Delete Author", None, QtGui.QApplication.UnicodeUTF8))

=== modified file 'openlp/plugins/songs/forms/authorsform.py'
--- openlp/plugins/songs/forms/authorsform.py	2009-03-09 12:49:55 +0000
+++ openlp/plugins/songs/forms/authorsform.py	2009-06-05 05:00:26 +0000
@@ -2,7 +2,7 @@
 """
 OpenLP - Open Source Lyrics Projection
 Copyright (c) 2008 Raoul Snyman
-Portions copyright (c) 2008 Martin Thompson, Tim Bentley, Carsten Tinggaard
+Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley, 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
@@ -17,12 +17,9 @@
 Place, Suite 330, Boston, MA 02111-1307 USA
 """
 from PyQt4 import QtGui, QtCore
-from PyQt4.QtCore import pyqtSignature
-
-from openlp.core.resources import *
-from openlp.plugins.songs.lib.classes import *
 
 from openlp.plugins.songs.forms.authorsdialog import Ui_AuthorsDialog
+from openlp.plugins.songs.lib import TextListData
 
 class AuthorsForm(QtGui.QDialog, Ui_AuthorsDialog):
     """
@@ -35,57 +32,51 @@
         QtGui.QDialog.__init__(self, parent)
         self.setupUi(self)
         self.songmanager = songmanager
-        self.AuthorListView.setColumnCount(2)
-        self.AuthorListView.setColumnHidden(0, True)
-        self.AuthorListView.setColumnWidth(1, 300)
-        #self.AuthorListView.setHorizontalHeaderLabels(QtCore.QStringList([" ","Author"]))
-        self.AuthorListView.horizontalHeader().setVisible(False)
-        self.AuthorListView.verticalHeader().setVisible(False)
-        self.currentrow = 0
+        self.currentRow = 0
         self.author = None
 
+        QtCore.QObject.connect(self.DeleteButton,
+            QtCore.SIGNAL('pressed()'), self.onDeleteButtonClick)
+        QtCore.QObject.connect(self.ClearButton,
+            QtCore.SIGNAL('pressed()'), self.onClearButtonClick)
+        QtCore.QObject.connect(self.AddUpdateButton,
+            QtCore.SIGNAL('pressed()'), self.onAddUpdateButtonClick)
+        QtCore.QObject.connect(self.DisplayEdit,
+            QtCore.SIGNAL('lostFocus()'), self.onDisplayEditLostFocus)
+        QtCore.QObject.connect(self.AuthorListView,
+            QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onAuthorListViewItemClicked)
+
     def load_form(self):
         """
         Refresh the screen and rest fields
         """
-        self.on_ClearButton_clicked() # tidy up screen
+        self.AuthorListData.resetStore()
+        self.onClearButtonClick() # tidy up screen
         authors = self.songmanager.get_authors()
-        self.AuthorListView.clear() # clear the results
-        #self.AuthorListView.setHorizontalHeaderLabels(QtCore.QStringList([" ","Author"]))
-        self.AuthorListView.horizontalHeader().setVisible(False)
-        self.AuthorListView.verticalHeader().setVisible(False)
-        self.AuthorListView.setRowCount(0)
         for author in authors:
-            row_count = self.AuthorListView.rowCount()
-            self.AuthorListView.setRowCount(row_count + 1)
-            author_id = QtGui.QTableWidgetItem(str(author.id))
-            self.AuthorListView.setItem(row_count, 0, author_id)
-            display_name = QtGui.QTableWidgetItem(author.display_name)
-            display_name.setFlags(QtCore.Qt.ItemIsSelectable)
-            self.AuthorListView.setItem(row_count, 1, display_name)
-            self.AuthorListView.setRowHeight(row_count, 20)
-        row_count = self.AuthorListView.rowCount()
-        if self.currentrow > row_count:
+            self.AuthorListData.addRow(author.id,author.display_name)
+        #rowCount is number of rows BUT test should be Zero based
+        row_count = self.AuthorListData.rowCount(None) - 1
+        if self.currentRow > row_count:
             # in case we have delete the last row of the table
-            self.currentrow = row_count
-        self.AuthorListView.selectRow(self.currentrow) # set selected row to previous selected row
+            self.currentRow = row_count
+        row = self.AuthorListData.createIndex(self.currentRow, 0)
+        if row.isValid():
+            self.AuthorListView.selectionModel().setCurrentIndex(row,
+                QtGui.QItemSelectionModel.SelectCurrent)
         self._validate_form()
 
-    @pyqtSignature("")
-    def on_DeleteButton_clicked(self):
+    def onDeleteButtonClick(self):
         """
         Delete the author is the Author is not attached to any songs
         """
         self.songmanager.delete_author(self.author.id)
-        self.on_ClearButton_clicked()
         self.load_form()
 
-    @pyqtSignature("")
-    def on_DisplayEdit_lostFocus(self):
+    def onDisplayEditLostFocus(self):
         self._validate_form()
 
-    @pyqtSignature("")
-    def on_AddUpdateButton_clicked(self):
+    def onAddUpdateButtonClick(self):
         """
         Sent New or update details to the database
         """
@@ -95,38 +86,33 @@
         self.author.first_name = unicode(self.FirstNameEdit.displayText())
         self.author.last_name = unicode(self.LastNameEdit.displayText())
         self.songmanager.save_author(self.author)
-        self.on_ClearButton_clicked()
+        self.onClearButtonClick()
         self.load_form()
-        self._validate_form()
-
-
-    @pyqtSignature("")
-    def on_ClearButton_clicked(self):
+
+    def onClearButtonClick(self):
         """
         Tidy up screen if clear button pressed
         """
-        self.DisplayEdit.setText("")
-        self.FirstNameEdit.setText("")
-        self.LastNameEdit.setText("")
-        self.MessageLabel.setText("")
+        self.DisplayEdit.setText(u'')
+        self.FirstNameEdit.setText(u'')
+        self.LastNameEdit.setText(u'')
+        self.MessageLabel.setText(u'')
         self.DeleteButton.setEnabled(False)
         self.author = None
         self._validate_form()
 
-    @pyqtSignature("QTableWidgetItem*")
-    def on_AuthorListView_itemClicked(self, item):
+    def onAuthorListViewItemClicked(self, index):
         """
         An Author has been selected display it
         If the author is attached to a Song prevent delete
         """
-        self.currentrow = self.AuthorListView.currentRow()
-        id = int(self.AuthorListView.item(self.currentrow, 0).text())
+        self.currentRow = index.row()
+        id = int(self.AuthorListData.getId(index))
         self.author = self.songmanager.get_author(id)
 
         self.DisplayEdit.setText(self.author.display_name)
         self.FirstNameEdit.setText(self.author.first_name)
         self.LastNameEdit.setText(self.author.last_name)
-        #songs = self.songmanager.get_song_authors_for_author(id)
         if len(self.author.songs) > 0:
             self.MessageLabel.setText("Author in use 'Delete' is disabled")
             self.DeleteButton.setEnabled(False)
@@ -136,7 +122,8 @@
         self._validate_form()
 
     def _validate_form(self):
-        if len(self.DisplayEdit.displayText()) == 0: # We need at lease a display name
+        # We need at lease a display name
+        if len(self.DisplayEdit.displayText()) == 0:
             self.AddUpdateButton.setEnabled(False)
         else:
             self.AddUpdateButton.setEnabled(True)

=== modified file 'openlp/plugins/songs/forms/editsongdialog.py'
--- openlp/plugins/songs/forms/editsongdialog.py	2009-05-01 22:26:43 +0000
+++ openlp/plugins/songs/forms/editsongdialog.py	2009-06-04 19:00:41 +0000
@@ -61,6 +61,7 @@
         self.VerseEditLayout.setObjectName("VerseEditLayout")
         self.VerseListWidget = QtGui.QListWidget(self.VerseEditWidget)
         self.VerseListWidget.setObjectName("VerseListWidget")
+        self.VerseListWidget.setAlternatingRowColors(True)
         self.VerseEditLayout.addWidget(self.VerseListWidget)
         self.VerseButtonWidget = QtGui.QWidget(self.VerseEditWidget)
         self.VerseButtonWidget.setObjectName("VerseButtonWidget")
@@ -108,10 +109,10 @@
         self.ThemeSelectionComboItem = QtGui.QComboBox(self.ThemeGroupBox)
         self.ThemeSelectionComboItem.setObjectName("ThemeSelectionComboItem")
         self.ThemeLayout.addWidget(self.ThemeSelectionComboItem)
-        self.ThemeAddItem = QtGui.QPushButton(self.ThemeGroupBox)
-        self.ThemeAddItem.setMaximumSize(QtCore.QSize(110, 16777215))
-        self.ThemeAddItem.setObjectName("ThemeAddItem")
-        self.ThemeLayout.addWidget(self.ThemeAddItem)
+#        self.ThemeAddItem = QtGui.QPushButton(self.ThemeGroupBox)
+#        self.ThemeAddItem.setMaximumSize(QtCore.QSize(110, 16777215))
+#        self.ThemeAddItem.setObjectName("ThemeAddItem")
+#        self.ThemeLayout.addWidget(self.ThemeAddItem)
         self.DetailsLayout.addWidget(self.ThemeGroupBox)
         self.TopLayout.addWidget(self.TextWidget)
         self.AdditionalWidget = QtGui.QWidget(self.TopWidget)
@@ -234,12 +235,12 @@
         self.AddTopicsToSongButton.setObjectName("AddTopicsToSongButton")
         self.TopicAddLayout.addWidget(self.AddTopicsToSongButton)
         self.TopicLayout.addWidget(self.TopicAddWidget)
-        self.ToticsListView = QtGui.QTableWidget(self.TopicGroupBox)
-        self.ToticsListView.setAlternatingRowColors(True)
-        self.ToticsListView.setObjectName("ToticsListView")
-        self.ToticsListView.setColumnCount(0)
-        self.ToticsListView.setRowCount(0)
-        self.TopicLayout.addWidget(self.ToticsListView)
+        self.TopicsListView = QtGui.QTableWidget(self.TopicGroupBox)
+        self.TopicsListView.setAlternatingRowColors(True)
+        self.TopicsListView.setObjectName("TopicsListView")
+        self.TopicsListView.setColumnCount(0)
+        self.TopicsListView.setRowCount(0)
+        self.TopicLayout.addWidget(self.TopicsListView)
         self.TopicRemoveWidget = QtGui.QWidget(self.TopicGroupBox)
         self.TopicRemoveWidget.setObjectName("TopicRemoveWidget")
         self.TopicRemoveLayout = QtGui.QHBoxLayout(self.TopicRemoveWidget)
@@ -305,15 +306,14 @@
         EditSongDialog.setTabOrder(self.AlternativeEdit, self.VerseOrderEdit)
         EditSongDialog.setTabOrder(self.VerseOrderEdit, self.CommentsEdit)
         EditSongDialog.setTabOrder(self.CommentsEdit, self.ThemeSelectionComboItem)
-        EditSongDialog.setTabOrder(self.ThemeSelectionComboItem, self.ThemeAddItem)
-        EditSongDialog.setTabOrder(self.ThemeAddItem, self.AuthorAddtoSongItem)
+        EditSongDialog.setTabOrder(self.ThemeSelectionComboItem, self.AuthorAddtoSongItem)
         EditSongDialog.setTabOrder(self.AuthorAddtoSongItem, self.AuthorsListView)
         EditSongDialog.setTabOrder(self.AuthorsListView, self.AuthorRemoveItem)
         EditSongDialog.setTabOrder(self.AuthorRemoveItem, self.SongbookCombo)
         EditSongDialog.setTabOrder(self.SongbookCombo, self.AddSongBookButton)
         EditSongDialog.setTabOrder(self.AddSongBookButton, self.SongTopicCombo)
-        EditSongDialog.setTabOrder(self.SongTopicCombo, self.ToticsListView)
-        EditSongDialog.setTabOrder(self.ToticsListView, self.pushButton)
+        EditSongDialog.setTabOrder(self.SongTopicCombo, self.TopicsListView)
+        EditSongDialog.setTabOrder(self.TopicsListView, self.pushButton)
         EditSongDialog.setTabOrder(self.pushButton, self.CopyrightEditItem)
         EditSongDialog.setTabOrder(self.CopyrightEditItem, self.CopyrightInsertItem)
         EditSongDialog.setTabOrder(self.CopyrightInsertItem, self.CCLNumberEdit)
@@ -330,7 +330,6 @@
         self.VerseOrderLabel.setText(QtGui.QApplication.translate("EditSongDialog", "Verse Order:", None, QtGui.QApplication.UnicodeUTF8))
         self.CommentsLabel.setText(QtGui.QApplication.translate("EditSongDialog", "Comments:", None, QtGui.QApplication.UnicodeUTF8))
         self.ThemeGroupBox.setTitle(QtGui.QApplication.translate("EditSongDialog", "Theme", None, QtGui.QApplication.UnicodeUTF8))
-        self.ThemeAddItem.setText(QtGui.QApplication.translate("EditSongDialog", "Add a Theme", None, QtGui.QApplication.UnicodeUTF8))
         self.AuthorsGroupBox.setTitle(QtGui.QApplication.translate("EditSongDialog", "Authors", None, QtGui.QApplication.UnicodeUTF8))
         self.AuthorAddtoSongItem.setText(QtGui.QApplication.translate("EditSongDialog", "Add to Song", None, QtGui.QApplication.UnicodeUTF8))
         self.AuthorRemoveItem.setText(QtGui.QApplication.translate("EditSongDialog", "Remove", None, QtGui.QApplication.UnicodeUTF8))

=== modified file 'openlp/plugins/songs/forms/editsongform.py'
--- openlp/plugins/songs/forms/editsongform.py	2009-03-09 18:47:37 +0000
+++ openlp/plugins/songs/forms/editsongform.py	2009-06-04 20:06:32 +0000
@@ -3,7 +3,7 @@
 """
 OpenLP - Open Source Lyrics Projection
 Copyright (c) 2008 Raoul Snyman
-Portions copyright (c) 2008 Martin Thompson, Tim Bentley,
+Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley,
 
 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
@@ -69,6 +69,8 @@
 
     def initialise(self):
         self.loadAuthors()
+        self.loadTopics()
+        self.loadBooks()
 
     def loadAuthors(self):
         authors = self.songmanager.get_authors()
@@ -76,6 +78,18 @@
         for author in authors:
             self.AuthorsSelectionComboItem.addItem(author.display_name)
 
+    def loadTopics(self):
+        topics = self.songmanager.get_topics()
+        self.SongTopicCombo.clear()
+        for topic in topics:
+            self.SongTopicCombo.addItem(topic.name)
+
+    def loadBooks(self):
+        books = self.songmanager.get_books()
+        self.SongbookCombo.clear()
+        for book in books:
+            self.SongbookCombo.addItem(book.name)
+
     def loadSong(self, id):
         self.song = self.songmanager.get_song(id)
         self.TitleEditItem.setText(self.song.title)
@@ -111,6 +125,7 @@
         """
         self.topics_form.load_form()
         self.topics_form.exec_()
+        self.loadTopics()
 
     def onAddSongBookButtonClicked(self):
         """
@@ -118,6 +133,7 @@
         """
         self.song_book_form.load_form()
         self.song_book_form.exec_()
+        self.loadBooks()
 
     def onAddVerseButtonClicked(self):
         self.verse_form.setVerse('')

=== modified file 'openlp/plugins/songs/forms/songbookdialog.py'
--- openlp/plugins/songs/forms/songbookdialog.py	2009-03-09 18:47:37 +0000
+++ openlp/plugins/songs/forms/songbookdialog.py	2009-06-04 20:06:32 +0000
@@ -8,6 +8,7 @@
 # WARNING! All changes made in this file will be lost!
 
 from PyQt4 import QtCore, QtGui
+from openlp.plugins.songs.lib import TextListData
 
 class Ui_SongBookDialog(object):
     def setupUi(self, SongBookDialog):
@@ -17,10 +18,13 @@
         self.DialogLayout.setSpacing(8)
         self.DialogLayout.setMargin(8)
         self.DialogLayout.setObjectName("DialogLayout")
-        self.BookSongListView = QtGui.QTableWidget(SongBookDialog)
-        self.BookSongListView.setObjectName("BookSongListView")
-        self.BookSongListView.setColumnCount(0)
-        self.BookSongListView.setRowCount(0)
+
+        self.BookSongListView = QtGui.QListView()
+        self.BookSongListView.setAlternatingRowColors(True)
+        self.BookSongListData = TextListData()
+        self.BookSongListView.setModel(self.BookSongListData)
+        self.DialogLayout.addWidget(self.BookSongListView)
+
         self.DialogLayout.addWidget(self.BookSongListView)
         self.SongBookGroup = QtGui.QGroupBox(SongBookDialog)
         self.SongBookGroup.setMinimumSize(QtCore.QSize(0, 200))

=== modified file 'openlp/plugins/songs/forms/songbookform.py'
--- openlp/plugins/songs/forms/songbookform.py	2009-01-02 20:20:33 +0000
+++ openlp/plugins/songs/forms/songbookform.py	2009-06-05 05:00:26 +0000
@@ -2,7 +2,7 @@
 """
 OpenLP - Open Source Lyrics Projection
 Copyright (c) 2008 Raoul Snyman
-Portions copyright (c) 2008 Martin Thompson, Tim Bentley, Carsten Tinggaard
+Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley, 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
@@ -17,45 +17,110 @@
 Place, Suite 330, Boston, MA 02111-1307 USA
 """
 
-from openlp.core.resources import *
-
 from PyQt4 import QtGui, QtCore
-from PyQt4.QtGui import QDialog
-from PyQt4.QtCore import pyqtSignature
 from songbookdialog import Ui_SongBookDialog
+from openlp.plugins.songs.lib.classes import Book
 
-class SongBookForm(QDialog, Ui_SongBookDialog):
+class SongBookForm(QtGui.QDialog, Ui_SongBookDialog):
     """
     Class documentation goes here.
     """
-    def __init__(self,songmanager,  parent = None):
+    def __init__(self, songmanager, parent = None):
         """
         Constructor
         """
-        QDialog.__init__(self, parent)
+        QtGui.QDialog.__init__(self, parent)
         self.setupUi(self)
         self.songmanager = songmanager
-        
+        self.currentRow = 0
+        self.songbook = None
+
+        QtCore.QObject.connect(self.DeleteButton,
+            QtCore.SIGNAL('pressed()'), self.onDeleteButtonClick)
+        QtCore.QObject.connect(self.ClearButton,
+            QtCore.SIGNAL('pressed()'), self.onClearButtonClick)
+        QtCore.QObject.connect(self.AddUpdateButton,
+            QtCore.SIGNAL('pressed()'), self.onAddUpdateButtonClick)
+        QtCore.QObject.connect(self.NameEdit,
+            QtCore.SIGNAL('lostFocus()'), self.onBookNameEditLostFocus)
+        QtCore.QObject.connect(self.BookSongListView,
+            QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onBooksListViewItemClicked)
+
     def load_form(self):
-        A = 1   
-
-    @pyqtSignature("QTableWidgetItem*")
-    def on_BookSongListView_itemClicked(self, item):
-        """
-        Slot documentation goes here.
-        """
-        print "bslv ic " + str(item)
-    
-    @pyqtSignature("")
-    def on_DeleteButton_clicked(self):
-        """
-        Slot documentation goes here.
-        """
-        print "db c "
-    
-    @pyqtSignature("")
-    def on_AddUpdateButton_clicked(self):
-        """
-        Slot documentation goes here.
-        """
-        print "au c "
+        """
+        Refresh the screen and rest fields
+        """
+        self.BookSongListData.resetStore()
+        self.onClearButtonClick() # tidy up screen
+        Books = self.songmanager.get_books()
+        for Book in Books:
+            self.BookSongListData.addRow(Book.id,Book.name)
+        #rowCount is number of rows BUT test should be Zero based
+        row_count = self.BookSongListData.rowCount(None) - 1
+        if self.currentRow > row_count:
+            # in case we have delete the last row of the table
+            self.currentRow = row_count
+        row = self.BookSongListData.createIndex(self.currentRow, 0)
+        if row.isValid():
+            self.BookSongListView.selectionModel().setCurrentIndex(row,
+                QtGui.QItemSelectionModel.SelectCurrent)
+        self._validate_form()
+
+    def onDeleteButtonClick(self):
+        """
+        Delete the Book is the Book is not attached to any songs
+        """
+        self.songmanager.delete_book(self.Book.id)
+        self.load_form()
+
+    def onBookNameEditLostFocus(self):
+        self._validate_form()
+
+    def onAddUpdateButtonClick(self):
+        """
+        Sent New or update details to the database
+        """
+        if self.Book == None:
+            self.Book = Book()
+        self.Book.name = unicode(self.NameEdit.displayText())
+        self.Book.publisher = unicode(self.PublisherEdit.displayText())
+        self.songmanager.save_book(self.Book)
+        self.onClearButtonClick()
+        self.load_form()
+
+    def onClearButtonClick(self):
+        """
+        Tidy up screen if clear button pressed
+        """
+        self.NameEdit.setText(u'')
+        self.PublisherEdit.setText(u'')
+        self.MessageLabel.setText(u'')
+        self.DeleteButton.setEnabled(False)
+        self.AddUpdateButton.setEnabled(True)
+        self.Book = None
+        self._validate_form()
+
+    def onBooksListViewItemClicked(self, index):
+        """
+        An Book has been selected display it
+        If the Book is attached to a Song prevent delete
+        """
+        self.currentRow = index.row()
+        id = int(self.BookSongListData.getId(index))
+        self.Book = self.songmanager.get_book(id)
+
+        self.NameEdit.setText(self.Book.name)
+        self.PublisherEdit.setText(self.Book.publisher)
+        if len(self.Book.songs) > 0:
+            self.MessageLabel.setText("Book in use 'Delete' is disabled")
+            self.DeleteButton.setEnabled(False)
+        else:
+            self.MessageLabel.setText("Book is not used")
+            self.DeleteButton.setEnabled(True)
+        self._validate_form()
+
+    def _validate_form(self):
+        if len(self.NameEdit.displayText()) == 0: # We need at lease a display name
+            self.AddUpdateButton.setEnabled(False)
+        else:
+            self.AddUpdateButton.setEnabled(True)

=== modified file 'openlp/plugins/songs/forms/topicsdialog.py'
--- openlp/plugins/songs/forms/topicsdialog.py	2009-01-06 18:59:47 +0000
+++ openlp/plugins/songs/forms/topicsdialog.py	2009-06-04 19:00:41 +0000
@@ -8,6 +8,7 @@
 # WARNING! All changes made in this file will be lost!
 
 from PyQt4 import QtCore, QtGui
+from openlp.plugins.songs.lib import TextListData
 
 class Ui_TopicsDialog(object):
     def setupUi(self, TopicsDialog):
@@ -35,13 +36,13 @@
         self.gridLayout.addWidget(self.DeleteButton, 1, 3, 1, 1)
         self.AddUpdateButton = QtGui.QPushButton(self.TopicGroupBox)
         icon1 = QtGui.QIcon()
-        icon1.addPixmap(QtGui.QPixmap(":/system/system_settings.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+        icon1.addPixmap(QtGui.QPixmap(":/services/service_save.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
         self.AddUpdateButton.setIcon(icon1)
         self.AddUpdateButton.setObjectName("AddUpdateButton")
         self.gridLayout.addWidget(self.AddUpdateButton, 1, 4, 1, 1)
         self.ClearButton = QtGui.QPushButton(self.TopicGroupBox)
         icon2 = QtGui.QIcon()
-        icon2.addPixmap(QtGui.QPixmap(":/songs/song_edit.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+        icon2.addPixmap(QtGui.QPixmap(":/services/service_new.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
         self.ClearButton.setIcon(icon2)
         self.ClearButton.setObjectName("ClearButton")
         self.gridLayout.addWidget(self.ClearButton, 1, 2, 1, 1)
@@ -49,11 +50,13 @@
         self.MessageLabel = QtGui.QLabel(TopicsDialog)
         self.MessageLabel.setObjectName("MessageLabel")
         self.gridLayout_2.addWidget(self.MessageLabel, 3, 0, 1, 1)
-        self.TopicsListView = QtGui.QTableWidget(TopicsDialog)
-        self.TopicsListView.setObjectName("TopicsListView")
-        self.TopicsListView.setColumnCount(0)
-        self.TopicsListView.setRowCount(0)
+
+        self.TopicsListView = QtGui.QListView()
+        self.TopicsListView.setAlternatingRowColors(True)
+        self.TopicsListData = TextListData()
+        self.TopicsListView.setModel(self.TopicsListData)
         self.gridLayout_2.addWidget(self.TopicsListView, 0, 0, 1, 1)
+
         self.ButtonBox = QtGui.QDialogButtonBox(TopicsDialog)
         self.ButtonBox.setOrientation(QtCore.Qt.Horizontal)
         self.ButtonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok)
@@ -69,8 +72,11 @@
         TopicsDialog.setWindowTitle(QtGui.QApplication.translate("TopicsDialog", "Topic Maintenance", None, QtGui.QApplication.UnicodeUTF8))
         self.TopicGroupBox.setTitle(QtGui.QApplication.translate("TopicsDialog", "Topic", None, QtGui.QApplication.UnicodeUTF8))
         self.TopicNameLabel.setText(QtGui.QApplication.translate("TopicsDialog", "Topic Name:", None, QtGui.QApplication.UnicodeUTF8))
+
         self.DeleteButton.setToolTip(QtGui.QApplication.translate("TopicsDialog", "Delete Author", None, QtGui.QApplication.UnicodeUTF8))
+        self.DeleteButton.setText(QtGui.QApplication.translate("AuthorsDialog", "Delete", None, QtGui.QApplication.UnicodeUTF8))
         self.AddUpdateButton.setToolTip(QtGui.QApplication.translate("TopicsDialog", "Add Update Author", None, QtGui.QApplication.UnicodeUTF8))
+        self.AddUpdateButton.setText(QtGui.QApplication.translate("AuthorsDialog", "Save", None, QtGui.QApplication.UnicodeUTF8))
         self.ClearButton.setToolTip(QtGui.QApplication.translate("TopicsDialog", "Clear Selection", None, QtGui.QApplication.UnicodeUTF8))
-
+        self.ClearButton.setText(QtGui.QApplication.translate("TopicsDialog", "Clear", None, QtGui.QApplication.UnicodeUTF8))
 

=== modified file 'openlp/plugins/songs/forms/topicsform.py'
--- openlp/plugins/songs/forms/topicsform.py	2009-02-19 22:25:58 +0000
+++ openlp/plugins/songs/forms/topicsform.py	2009-06-05 05:00:26 +0000
@@ -2,7 +2,7 @@
 """
 OpenLP - Open Source Lyrics Projection
 Copyright (c) 2008 Raoul Snyman
-Portions copyright (c) 2008 Martin Thompson, Tim Bentley, Carsten Tinggaard
+Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley, 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
@@ -16,15 +16,14 @@
 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 Place, Suite 330, Boston, MA 02111-1307 USA
 """
-from openlp.core.resources import *
 
 from PyQt4 import QtGui, QtCore
-from PyQt4.QtGui import QDialog
-from PyQt4.QtCore import pyqtSignature
-
-from topicsdialog import Ui_TopicsDialog
-
-class TopicsForm(QDialog, Ui_TopicsDialog):
+from openlp.plugins.songs.lib import TextListData
+
+from openlp.plugins.songs.forms.topicsdialog import Ui_TopicsDialog
+from openlp.plugins.songs.lib.classes import Topic
+
+class TopicsForm(QtGui.QDialog, Ui_TopicsDialog):
     """
     Class documentation goes here.
     """
@@ -32,24 +31,95 @@
         """
         Constructor
         """
-        QDialog.__init__(self, parent)
+        QtGui.QDialog.__init__(self, parent)
         self.setupUi(self)
         self.songmanager = songmanager
-        #self.connect()
+        self.currentRow = 0
+        self.topic = None
+
+        QtCore.QObject.connect(self.DeleteButton,
+            QtCore.SIGNAL('pressed()'), self.onDeleteButtonClick)
+        QtCore.QObject.connect(self.ClearButton,
+            QtCore.SIGNAL('pressed()'), self.onClearButtonClick)
+        QtCore.QObject.connect(self.AddUpdateButton,
+            QtCore.SIGNAL('pressed()'), self.onAddUpdateButtonClick)
+        QtCore.QObject.connect(self.TopicNameEdit,
+            QtCore.SIGNAL('lostFocus()'), self.onTopicNameEditLostFocus)
+        QtCore.QObject.connect(self.TopicsListView,
+            QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onTopicsListViewItemClicked)
 
     def load_form(self):
-        A = 1
-
-    #@pyqtSignature("")
-    def onDeleteButtonClicked(self):
-        """
-        Slot documentation goes here.
-        """
-        print "db clicked"
-
-    #@pyqtSignature("")
-    def onAddUpdateButtonClicked(self):
-        """
-        Slot documentation goes here.
-        """
-        print "au clicked"
+        """
+        Refresh the screen and rest fields
+        """
+        self.TopicsListData.resetStore()
+        self.onClearButtonClick() # tidy up screen
+        topics = self.songmanager.get_topics()
+        for topic in topics:
+            self.TopicsListData.addRow(topic.id,topic.name)
+        #rowCount is number of rows BUT test should be Zero based
+        row_count = self.TopicsListData.rowCount(None) - 1
+        if self.currentRow > row_count:
+            # in case we have delete the last row of the table
+            self.currentRow = row_count
+        row = self.TopicsListData.createIndex(self.currentRow, 0)
+        if row.isValid():
+            self.TopicsListView.selectionModel().setCurrentIndex(row,
+                QtGui.QItemSelectionModel.SelectCurrent)
+        self._validate_form()
+
+    def onDeleteButtonClick(self):
+        """
+        Delete the Topic is the Topic is not attached to any songs
+        """
+        self.songmanager.delete_topic(self.topic.id)
+        self.load_form()
+
+    def onTopicNameEditLostFocus(self):
+        self._validate_form()
+
+    def onAddUpdateButtonClick(self):
+        """
+        Sent New or update details to the database
+        """
+        if self.topic == None:
+            self.topic = Topic()
+        self.topic.name = unicode(self.TopicNameEdit.displayText())
+        self.songmanager.save_topic(self.topic)
+        self.onClearButtonClick()
+        self.load_form()
+
+    def onClearButtonClick(self):
+        """
+        Tidy up screen if clear button pressed
+        """
+        self.TopicNameEdit.setText(u'')
+        self.MessageLabel.setText(u'')
+        self.DeleteButton.setEnabled(False)
+        self.AddUpdateButton.setEnabled(True)
+        self.topic = None
+        self._validate_form()
+
+    def onTopicsListViewItemClicked(self, index):
+        """
+        An Topic has been selected display it
+        If the Topic is attached to a Song prevent delete
+        """
+        self.currentRow = index.row()
+        id = int(self.TopicsListData.getId(index))
+        self.topic = self.songmanager.get_topic(id)
+
+        self.TopicNameEdit.setText(self.topic.name)
+        if len(self.topic.songs) > 0:
+            self.MessageLabel.setText("Topic in use 'Delete' is disabled")
+            self.DeleteButton.setEnabled(False)
+        else:
+            self.MessageLabel.setText("Topic is not used")
+            self.DeleteButton.setEnabled(True)
+        self._validate_form()
+
+    def _validate_form(self):
+        if len(self.TopicNameEdit.displayText()) == 0: # We need at lease a display name
+            self.AddUpdateButton.setEnabled(False)
+        else:
+            self.AddUpdateButton.setEnabled(True)

=== modified file 'openlp/plugins/songs/lib/__init__.py'
--- openlp/plugins/songs/lib/__init__.py	2009-03-09 12:49:55 +0000
+++ openlp/plugins/songs/lib/__init__.py	2009-06-03 15:38:14 +0000
@@ -3,7 +3,7 @@
 """
 OpenLP - Open Source Lyrics Projection
 Copyright (c) 2008 Raoul Snyman
-Portions copyright (c) 2008 Martin Thompson, Tim Bentley
+Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley
 
 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
@@ -17,10 +17,7 @@
 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 Place, Suite 330, Boston, MA 02111-1307 USA
 """
-
+from textlistdata import TextListData
 from manager import SongManager
 from songstab import SongsTab
 from mediaitem import SongMediaItem
-#from xml import SongOpenXml
-
-#__all__ = ['SongManager', 'SongsTab', 'SongMediaItem']

=== modified file 'openlp/plugins/songs/lib/manager.py'
--- openlp/plugins/songs/lib/manager.py	2009-02-19 22:25:58 +0000
+++ openlp/plugins/songs/lib/manager.py	2009-06-04 20:06:32 +0000
@@ -3,7 +3,7 @@
 """
 OpenLP - Open Source Lyrics Projection
 Copyright (c) 2008 Raoul Snyman
-Portions copyright (c) 2008 Martin Thompson, Tim Bentley
+Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley
 
 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
@@ -23,7 +23,7 @@
 
 from sqlalchemy import asc, desc
 from openlp.plugins.songs.lib.models import init_models, metadata, session, \
-    engine, songs_table, Song, Author, Topic
+    engine, songs_table, Song, Author, Topic,  Book
 
 import logging
 
@@ -34,7 +34,7 @@
     """
 
     global log
-    log=logging.getLogger('SongManager')
+    log = logging.getLogger('SongManager')
     log.info('Song manager loaded')
 
     def __init__(self, config):
@@ -45,7 +45,7 @@
         self.config = config
         log.debug('Song Initialising')
         self.db_url = u''
-        db_type = self.config.get_config(u'db type')
+        db_type = self.config.get_config(u'db type', u'sqlite')
         if db_type == u'sqlite':
             self.db_url = u'sqlite:///' + self.config.get_data_path() + \
                 u'/songs.sqlite'
@@ -134,11 +134,85 @@
 
     def delete_author(self, authorid):
         """
-        Delete the author and refresh the author cache
+        Delete the author
         """
+        author = self.get_author(authorid)
         try:
             self.session.delete(author)
             self.session.commit()
             return True
         except:
+            log.error("Errow thrown %s", sys.exc_info()[1])
+            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 save_topic(self, topic):
+        """
+        Save the Topic
+        """
+        try:
+            self.session.add(topic)
+            self.session.commit()
+            return True
+        except:
+            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:
+            log.error("Errow thrown %s", sys.exc_info()[1])
+            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 save_book(self, book):
+        """
+        Save the Book
+        """
+        try:
+            self.session.add(book)
+            self.session.commit()
+            return True
+        except:
+            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:
+            log.error("Errow thrown %s", sys.exc_info()[1])
             return False

=== modified file 'openlp/plugins/songs/lib/mediaitem.py'
--- openlp/plugins/songs/lib/mediaitem.py	2009-05-22 18:30:25 +0000
+++ openlp/plugins/songs/lib/mediaitem.py	2009-06-03 16:14:56 +0000
@@ -3,7 +3,7 @@
 """
 OpenLP - Open Source Lyrics Projection
 Copyright (c) 2008 Raoul Snyman
-Portions copyright (c) 2008 Martin Thompson, Tim Bentley
+Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley
 
 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
@@ -21,9 +21,33 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.lib import MediaManagerItem,  translate
+from openlp.core.lib import MediaManagerItem,  translate,  ServiceItem
 
 from openlp.plugins.songs.forms import EditSongForm
+from openlp.plugins.songs.lib import TextListData
+
+class SongList(QtGui.QListView):
+
+    def __init__(self,parent=None,name=None):
+        QtGui.QListView.__init__(self,parent)
+
+    def mouseMoveEvent(self, event):
+        """
+        Drag and drop event does not care what data is selected
+        as the recepient will use events to request the data move
+        just tell it what plugin to call
+        """
+        if event.buttons() != QtCore.Qt.LeftButton:
+            return
+        drag = QtGui.QDrag(self)
+        mimeData = QtCore.QMimeData()
+        drag.setMimeData(mimeData)
+        mimeData.setText(u'Song')
+
+        dropAction = drag.start(QtCore.Qt.CopyAction)
+
+        if dropAction == QtCore.Qt.CopyAction:
+            self.close()
 
 class SongMediaItem(MediaManagerItem):
     """
@@ -98,19 +122,29 @@
         self.SearchLayout.addWidget(self.SearchTextButton, 3, 2, 1, 1)
         # Add the song widget to the page layout
         self.PageLayout.addWidget(self.SongWidget)
-        self.SongListView = QtGui.QTableWidget()
-        self.SongListView.setColumnCount(2)
-        self.SongListView.setColumnHidden(0, True)
-        self.SongListView.setColumnWidth(1, 240)
-        self.SongListView.setShowGrid(False)
-        self.SongListView.setSortingEnabled(False)
+
+        self.SongListView = SongList()
         self.SongListView.setAlternatingRowColors(True)
-        self.SongListView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
-        self.SongListView.horizontalHeader().setVisible(False)
-        self.SongListView.verticalHeader().setVisible(False)
-        self.SongListView.setGeometry(QtCore.QRect(10, 100, 256, 591))
+        self.SongListData = TextListData()
+        self.SongListView.setModel(self.SongListData)
+        self.SongListView.setDragEnabled(True)
+
+#        self.SongListView = QtGui.QTableWidget()
+#        self.SongListView.setColumnCount(2)
+#        self.SongListView.setColumnHidden(0, True)
+#        self.SongListView.setColumnWidth(1, 240)
+#        self.SongListView.setShowGrid(False)
+#        self.SongListView.setSortingEnabled(False)
+#        self.SongListView.setAlternatingRowColors(True)
+#        self.SongListView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
+#        self.SongListView.horizontalHeader().setVisible(False)
+#        self.SongListView.verticalHeader().setVisible(False)
+#        self.SongListView.setGeometry(QtCore.QRect(10, 100, 256, 591))
         self.SongListView.setObjectName('SongListView')
+
         self.PageLayout.addWidget(self.SongListView)
+        self.SongListView.setDragEnabled(True)
+
         # Signals and slots
         QtCore.QObject.connect(self.SearchTextButton,
             QtCore.SIGNAL('pressed()'), self.onSearchTextButtonClick)
@@ -118,8 +152,8 @@
             QtCore.SIGNAL('pressed()'), self.onClearTextButtonClick)
         QtCore.QObject.connect(self.SearchTextEdit,
             QtCore.SIGNAL('textChanged(const QString&)'), self.onSearchTextEditChanged)
-        QtCore.QObject.connect(self.SongListView,
-            QtCore.SIGNAL('itemPressed(QTableWidgetItem * item)'), self.onSongSelected)
+#        QtCore.QObject.connect(self.SongListView,
+#            QtCore.SIGNAL('itemPressed(QTableWidgetItem * item)'), self.onSongSelected)
         #define and add the context menu
         self.SongListView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
         self.SongListView.addAction(self.contextMenuAction(self.SongListView,
@@ -148,26 +182,18 @@
         self.SearchTypeComboBox.addItem(translate('SongMediaItem', u'Authors'))
 
     def displayResults(self, searchresults):
-        log.debug("_search results")
-        self.SongListView.clear() # clear the results
-        self.SongListView.horizontalHeader().setVisible(False)
-        self.SongListView.verticalHeader().setVisible(False)
-        self.SongListView.setRowCount(0)
+        log.debug("display results")
+        self.SongListData.resetStore()
         #log.debug("Records returned from search %s", len(searchresults))
         for song in searchresults:
-            row_count = self.SongListView.rowCount()
-            self.SongListView.setRowCount(row_count + 1)
-            song_index = QtGui.QTableWidgetItem(str(song.id))
-            self.SongListView.setItem(row_count, 0, song_index)
             author_list = u''
             for author in song.authors:
                 if author_list != u'':
                     author_list = author_list + u', '
                 author_list = author_list + author.display_name
-            song_detail = QtGui.QTableWidgetItem(
-                u'%s (%s)' % (str(song.title), str(author_list)))
-            self.SongListView.setItem(row_count, 1, song_detail)
-            self.SongListView.setRowHeight(row_count, 20)
+            song_detail = str(u'%s (%s)' % (str(song.title), str(author_list)))
+
+            self.SongListData.addRow(song.id,song_detail)
 
     def onClearTextButtonClick(self):
         """
@@ -197,26 +223,57 @@
             #searchresults = self.songmanager.get_song_from_author(searchtext)
         self.displayResults(search_results)
 
-    def onSongSelected(self, item):
-        print item
-
     def onSongNewClick(self):
         self.edit_song_form.exec_()
 
     def onSongEditClick(self):
-        current_row = self.SongListView.currentRow()
-        id = int(self.SongListView.item(current_row, 0).text())
-        self.edit_song_form.loadSong(id)
-        self.edit_song_form.exec_()
+        indexes = self.SongListView.selectedIndexes()
+        for index in indexes:
+            id = self.SongListData.getId(index)
+            self.edit_song_form.loadSong(id)
+            self.edit_song_form.exec_()
 
     def onSongDeleteClick(self):
-        pass
+        indexes = self.SongListView.selectedIndexes()
+        for index in indexes:
+            id = self.SongListData.getId(index)
+            self.parent.songmanager.delete_song(id)
+            self.SongListData.deleteRow(index)
 
     def onSongPreviewClick(self):
-        pass
+        service_item = ServiceItem(self.parent)
+        service_item.addIcon( ":/media/media_song.png")
+        self.generateSlideData(service_item)
+        self.parent.preview_controller.addServiceItem(service_item)
+
+    def generateSlideData(self, service_item):
+        raw_slides =[]
+        raw_footer = []
+        indexes = self.SongListView.selectedIndexes()
+        for index in indexes:
+            id = self.SongListData.getId(index)
+            song = self.parent.songmanager.get_song(id)
+            if  song.theme_name == None or len(song.theme_name)  == 0:
+                service_item.theme = None
+            else:
+                service_item.theme = song.theme_name
+            verses = song.lyrics.split(u'\n\n')
+            for verse in verses:
+                raw_slides.append(verse)
+            service_item.raw_slides = raw_slides
+            service_item.title = song.title
+        raw_footer.append(str(u'%s \n%s \n' % (song.title, song.copyright )))
+        raw_footer.append(song.copyright)
+        service_item.raw_footer = raw_footer
 
     def onSongLiveClick(self):
-        pass
+        service_item = ServiceItem(self.parent)
+        service_item.addIcon( ":/media/media_song.png")
+        self.generateSlideData(service_item)
+        self.parent.live_controller.addServiceItem(service_item)
 
     def onSongAddClick(self):
-        pass
+        service_item = ServiceItem(self.parent)
+        service_item.addIcon( ":/media/media_song.png")
+        self.generateSlideData(service_item)
+        self.parent.service_manager.addServiceItem(service_item)

=== added file 'openlp/plugins/songs/lib/textlistdata.py'
--- openlp/plugins/songs/lib/textlistdata.py	1970-01-01 00:00:00 +0000
+++ openlp/plugins/songs/lib/textlistdata.py	2009-06-03 15:38:14 +0000
@@ -0,0 +1,80 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+"""
+OpenLP - Open Source Lyrics Projection
+Copyright (c) 2008 Raoul Snyman
+Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley
+
+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, QtGui
+
+class TextListData(QtCore.QAbstractListModel):
+    """
+    An abstract list of strings
+    """
+    global log
+    log = logging.getLogger(u'TextListData')
+    log.info(u'started')
+
+    def __init__(self):
+        QtCore.QAbstractListModel.__init__(self)
+        self.items = [] # will be a list of (database id , title) tuples
+
+    def resetStore(self):
+        #reset list so can be reloaded
+        self.items = []
+
+    def rowCount(self, parent):
+        return len(self.items)
+
+    def insertRow(self, row, id, title):
+        self.beginInsertRows(QtCore.QModelIndex(),row,row)
+        log.debug("insert row %d:%s for id %d" % (row,title, id))
+        self.items.insert(row, (id, title))
+        self.endInsertRows()
+
+    def removeRow(self, row):
+        self.beginRemoveRows(QtCore.QModelIndex(), row,row)
+        self.items.pop(row)
+        self.endRemoveRows()
+
+    def addRow(self, id, title):
+        self.insertRow(len(self.items), id, title)
+
+    def data(self, index, role):
+        row = index.row()
+        if row > len(self.items): # if the last row is selected and deleted, we then get called with an empty row!
+            return QtCore.QVariant()
+        if role == QtCore.Qt.DisplayRole:
+            retval = self.items[row][1]
+        else:
+            retval = QtCore.QVariant()
+        if type(retval) is not type(QtCore.QVariant):
+            return QtCore.QVariant(retval)
+        else:
+            return retval
+
+    def getIdList(self):
+        filelist = [item[0] for item in self.items];
+        return filelist
+
+    def getId(self, index):
+        row = index.row()
+        return self.items[row][0]
+
+    def deleteRow(self, index):
+        row = index.row()
+        self.removeRow(row)

=== modified file 'openlp/plugins/songs/songsplugin.py'
--- openlp/plugins/songs/songsplugin.py	2009-05-22 18:30:25 +0000
+++ openlp/plugins/songs/songsplugin.py	2009-06-03 15:38:14 +0000
@@ -49,8 +49,8 @@
 
     def get_media_manager_item(self):
         # Create the MediaManagerItem object
-        self.MediaManagerItem = SongMediaItem(self, self.icon, 'Songs')
-        return self.MediaManagerItem
+        self.media_item = SongMediaItem(self, self.icon, 'Songs')
+        return self.media_item
 
     def add_import_menu_item(self, import_menu):
         self.ImportSongMenu = QtGui.QMenu(import_menu)
@@ -127,3 +127,12 @@
         if event.event_type == EventType.ThemeListChanged:
             log.debug(u'New Theme request received')
             #self.edit_custom_form.loadThemes(self.theme_manager.getThemes())
+        if event.event_type == EventType.LoadServiceItem and event.payload == 'Song':
+            log.debug(u'Load Service Item received')
+            self.media_item.onSongAddClick()
+        if event.event_type == EventType.PreviewShow and event.payload == 'Song':
+            log.debug(u'Load Preview Item received ')
+            self.media_item.onSongPreviewClick()
+        if event.event_type == EventType.LiveShow and event.payload == 'Song':
+            log.debug(u'Load Live Show Item received')
+            self.media_item.onSongLiveClick()


Follow ups