← Back to team overview

openlp-core team mailing list archive

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

 

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

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

Add missing files so Remote and Presentations work
Add code to get Impress to start and stop with a presentations
Correct SlideManager and ServiceManager so Command style services work
Changes to layout formula for different screen sizes. (More work needed)
Other cleanups.
-- 
https://code.launchpad.net/~trb143/openlp/bugfixes/+merge/11269
Your team openlp.org Core is subscribed to branch lp:openlp.
=== modified file 'openlp/core/lib/eventreceiver.py'
--- openlp/core/lib/eventreceiver.py	2009-08-29 07:17:56 +0000
+++ openlp/core/lib/eventreceiver.py	2009-09-05 19:58:02 +0000
@@ -54,6 +54,25 @@
     ``request_spin_delay``
         Requests a spin delay
 
+    ``{plugin}_start``
+        Requests a plugin to start a external program
+        Path and file provided in message
+
+    ``{plugin}_first``
+        Requests a plugin to handle a first event
+
+    ``{plugin}_previous``
+        Requests a plugin to handle a previous event
+
+    ``{plugin}_next``
+        Requests a plugin to handle a next event
+
+    ``{plugin}_last``
+        Requests a plugin to handle a last event
+
+    ``{plugin}_stop``
+        Requests a plugin to handle a stop event
+
     """
     global log
     log = logging.getLogger(u'EventReceiver')

=== modified file 'openlp/core/lib/pluginmanager.py'
--- openlp/core/lib/pluginmanager.py	2009-08-26 05:00:19 +0000
+++ openlp/core/lib/pluginmanager.py	2009-09-05 08:52:01 +0000
@@ -135,6 +135,7 @@
         """
         Loop through all the plugins. If a plugin has a valid settings tab
         item, add it to the settings tab.
+        Tabs are set for all plugins not just Active ones
 
         ``settingsform``
             Defaults to *None*. The settings form to add tabs to.

=== modified file 'openlp/core/lib/serviceitem.py'
--- openlp/core/lib/serviceitem.py	2009-09-03 17:46:46 +0000
+++ openlp/core/lib/serviceitem.py	2009-09-05 13:30:09 +0000
@@ -51,6 +51,7 @@
         if hostplugin is not None:
             self.RenderManager = self.plugin.render_manager
             self.shortname = hostplugin.name
+            self.name = self.plugin.name
         self.title = u''
         self.items = []
         self.iconic_representation = None
@@ -158,6 +159,7 @@
         file to represent this item.
         """
         oos_header = {
+            u'name': self.name.lower(),
             u'plugin': self.shortname,
             u'theme':self.theme,
             u'title':self.title,
@@ -190,6 +192,7 @@
         """
         header = serviceitem[u'serviceitem'][u'header']
         self.title = header[u'title']
+        self.name = header[u'name']
         self.service_item_type = header[u'type']
         self.shortname = header[u'plugin']
         self.theme = header[u'theme']

=== modified file 'openlp/core/lib/settingsmanager.py'
--- openlp/core/lib/settingsmanager.py	2009-07-09 05:15:26 +0000
+++ openlp/core/lib/settingsmanager.py	2009-09-06 12:13:09 +0000
@@ -27,7 +27,9 @@
         self.screen = screen[0]
         self.width = self.screen[u'size'].width()
         self.height = self.screen[u'size'].height()
-        self.mainwindow_width = self.width * 0.8
         self.mainwindow_height = self.height * 0.8
-        self.mainwindow_docbars = self.width / 3
-        self.mainwindow_slidecontroller = self.width / 6
+        self.mainwindow_docbars = self.width / 5
+        if self.mainwindow_docbars > 300:
+            self.mainwindow_docbars = 300
+        self.mainwindow_slidecontroller = (self.width - (self.mainwindow_docbars * 3  ) / 2) / 2
+        print self.width,  self.mainwindow_docbars, self.mainwindow_slidecontroller

=== modified file 'openlp/core/ui/mainwindow.py'
--- openlp/core/ui/mainwindow.py	2009-09-01 19:39:49 +0000
+++ openlp/core/ui/mainwindow.py	2009-09-05 06:29:23 +0000
@@ -106,7 +106,7 @@
         self.MediaManagerDock.setWindowIcon(icon)
         self.MediaManagerDock.setFloating(False)
         self.MediaManagerDock.setObjectName(u'MediaManagerDock')
-        self.MediaManagerDock.setMinimumWidth(300)
+        self.MediaManagerDock.setMinimumWidth(self.settingsmanager.mainwindow_docbars)
         self.MediaManagerContents = QtGui.QWidget()
         self.MediaManagerContents.setObjectName(u'MediaManagerContents')
         self.MediaManagerLayout = QtGui.QHBoxLayout(self.MediaManagerContents)
@@ -128,7 +128,7 @@
         self.ServiceManagerDock.setFeatures(
             QtGui.QDockWidget.AllDockWidgetFeatures)
         self.ServiceManagerDock.setObjectName(u'ServiceManagerDock')
-        self.ServiceManagerDock.setMinimumWidth(300)
+        self.ServiceManagerDock.setMinimumWidth(self.settingsmanager.mainwindow_docbars)
         self.ServiceManagerContents = ServiceManager(self)
         self.ServiceManagerDock.setWidget(self.ServiceManagerContents)
         MainWindow.addDockWidget(

=== modified file 'openlp/core/ui/servicemanager.py'
--- openlp/core/ui/servicemanager.py	2009-09-02 01:44:09 +0000
+++ openlp/core/ui/servicemanager.py	2009-09-05 13:30:09 +0000
@@ -18,6 +18,7 @@
 Place, Suite 330, Boston, MA 02111-1307 USA
 """
 import os
+import sys
 import logging
 import cPickle
 import zipfile
@@ -137,21 +138,28 @@
         self.ServiceManagerList.addAction(contextMenuSeparator(self.ServiceManagerList))
         self.ServiceManagerList.addAction(contextMenuAction(
             self.ServiceManagerList, ':/services/service_delete',
-            translate(u'ServiceManager',u'&Remove from Service'), self.onDeleteFromService))
+            translate(u'ServiceManager',u'&Remove from Service'),
+            self.onDeleteFromService))
         self.Layout.addWidget(self.ServiceManagerList)
         # Add the bottom toolbar
         self.OrderToolbar = OpenLPToolbar(self)
-        self.OrderToolbar.addToolbarButton(u'Move to top', u':/services/service_top.png',
+        self.OrderToolbar.addToolbarButton(u'Move to top',
+            u':/services/service_top.png',
             translate(u'ServiceManager', u'Move to top'), self.onServiceTop)
-        self.OrderToolbar.addToolbarButton(u'Move up', u':/services/service_up.png',
+        self.OrderToolbar.addToolbarButton(u'Move up',
+            u':/services/service_up.png',
             translate(u'ServiceManager', u'Move up order'), self.onServiceUp)
-        self.OrderToolbar.addToolbarButton(u'Move down', u':/services/service_down.png',
+        self.OrderToolbar.addToolbarButton(u'Move down',
+            u':/services/service_down.png',
             translate(u'ServiceManager', u'Move down order'), self.onServiceDown)
-        self.OrderToolbar.addToolbarButton(u'Move to bottom', u':/services/service_bottom.png',
+        self.OrderToolbar.addToolbarButton(u'Move to bottom',
+            u':/services/service_bottom.png',
             translate(u'ServiceManager', u'Move to end'), self.onServiceEnd)
         self.OrderToolbar.addSeparator()
-        self.OrderToolbar.addToolbarButton(u'Delete From Service', u':/services/service_delete.png',
-            translate(u'ServiceManager', u'Delete From Service'), self.onDeleteFromService)
+        self.OrderToolbar.addToolbarButton(u'Delete From Service',
+            u':/services/service_delete.png',
+            translate(u'ServiceManager', u'Delete From Service'),
+            self.onDeleteFromService)
         self.Layout.addWidget(self.OrderToolbar)
         # Connect up our signals and slots
         QtCore.QObject.connect(self.ThemeComboBox,
@@ -402,6 +410,7 @@
                     #if not present do not worry
                     pass
             except:
+                log.error(u'Problem processing oos load %s', sys.exc_info()[0])
                 pass
         self.serviceName = name[len(name) - 1]
         self.parent.OosChanged(True, self.serviceName)

=== modified file 'openlp/core/ui/slidecontroller.py'
--- openlp/core/ui/slidecontroller.py	2009-09-03 04:41:30 +0000
+++ openlp/core/ui/slidecontroller.py	2009-09-05 19:58:02 +0000
@@ -68,6 +68,7 @@
         self.parent = parent
         self.image_list = [u'Start Loop', u'Stop Loop', u'Loop Spearator', u'Image SpinBox']
         self.timer_id = 0
+        self.item = None
         self.Panel = QtGui.QWidget(parent.ControlSplitter)
         self.Splitter = QtGui.QSplitter(self.Panel)
         self.Splitter.setOrientation(QtCore.Qt.Vertical)
@@ -229,9 +230,17 @@
         Called by plugins
         """
         log.debug(u'addServiceItem')
+        #If old item was a command tell it to stop
+        if self.item is not None and self.item.service_item_type == ServiceType.Command:
+            Receiver().send_message(u'%s_stop'%item.name.lower())
+        self.item = item
         item.render()
         self.enableToolBar(item)
-        self.displayServiceManagerItems(item, 0)
+        if item.service_item_type == ServiceType.Command:
+            Receiver().send_message(u'%s_start'%item.name.lower(), \
+                u'%s:%s:%s' % (item.shortname, item.service_item_path, item.service_frames[0][u'title']))
+        else:
+            self.displayServiceManagerItems(item, 0)
 
     def addServiceManagerItem(self, item, slideno):
         """
@@ -240,8 +249,16 @@
         Called by ServiceManager
         """
         log.debug(u'addServiceItem')
+        #If old item was a command tell it to stop
+        if self.item.service_item_type == ServiceType.Command:
+            Receiver().send_message(u'%s_stop'%item.name.lower())
+        self.item = item
         self.enableToolBar(item)
-        self.displayServiceManagerItems(item, slideno)
+        if item.service_item_type == ServiceType.Command:
+            Receiver().send_message(u'%s_start'%item.name.lower(), \
+                u'%s:%s:%s' % (item.shortname, item.service_item_path, item.service_frames[0][u'title']))
+        else:
+            self.displayServiceManagerItems(item, slideno)
 
     def displayServiceManagerItems(self, serviceitem, slideno):
         """
@@ -310,11 +327,14 @@
         """
         Go to the next slide.
         """
-        row = self.PreviewListWidget.currentRow() + 1
-        if row == self.PreviewListWidget.rowCount():
-            row = 0
-        self.PreviewListWidget.selectRow(row)
-        self.onSlideSelected()
+        if self.item.service_item_type == ServiceType.Command:
+            Receiver().send_message(u'%s_next'% self.item.name.lower())
+        else:
+            row = self.PreviewListWidget.currentRow() + 1
+            if row == self.PreviewListWidget.rowCount():
+                row = 0
+            self.PreviewListWidget.selectRow(row)
+            self.onSlideSelected()
 
     def onSlideSelectedPrevious(self):
         """

=== modified file 'openlp/plugins/presentations/lib/__init__.py'
--- openlp/plugins/presentations/lib/__init__.py	2009-08-14 17:41:29 +0000
+++ openlp/plugins/presentations/lib/__init__.py	2009-09-05 13:30:09 +0000
@@ -17,8 +17,11 @@
 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 Place, Suite 330, Boston, MA 02111-1307 USA
 """
+from impresscontroller import ImpressController
+from messagelistener import MessageListener
 from mediaitem import PresentationMediaItem
 from presentationtab import PresentationTab
-from impresscontroller import impressController
-
-__all__ = ['PresentationMediaItem', 'PresentationTab', 'impressController']
+
+
+__all__ = ['PresentationMediaItem', 'PresentationTab',
+    'ImpressController', 'MessageListener']

=== modified file 'openlp/plugins/presentations/lib/impresscom.py'
--- openlp/plugins/presentations/lib/impresscom.py	2009-09-02 01:44:09 +0000
+++ openlp/plugins/presentations/lib/impresscom.py	2009-09-05 06:29:23 +0000
@@ -182,7 +182,7 @@
 if __name__ == '__main__':
     ooo = Openoffice()
     ooo.createResolver()
-    #show = ImpressCOMPres(ooo, u'/home/timali/test1.odp')
-    #show.go()
+    show = ImpressCOMPres(ooo, u'/home/timali/test1.odp')
+    show.go()
     #show.resume()
     #show.nextStep()

=== added file 'openlp/plugins/presentations/lib/impresscontroller.py'
--- openlp/plugins/presentations/lib/impresscontroller.py	1970-01-01 00:00:00 +0000
+++ openlp/plugins/presentations/lib/impresscontroller.py	2009-09-06 08:11:32 +0000
@@ -0,0 +1,122 @@
+# -*- 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
+"""
+# OOo API documentation:
+# http://api.openoffice.org/docs/common/ref/com/sun/star/presentation/XSlideShowController.html
+# http://docs.go-oo.org/sd/html/classsd_1_1SlideShow.html
+# http://www.oooforum.org/forum/viewtopic.phtml?t=5252
+# http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/Working_with_Presentations
+# http://mail.python.org/pipermail/python-win32/2008-January/006676.html
+#http://www.linuxjournal.com/content/starting-stopping-and-connecting-openoffice-python
+#http://nxsy.org/comparing-documents-with-openoffice-and-python
+
+import logging
+import os ,  subprocess
+import time
+import uno
+import sys
+
+from PyQt4 import QtCore
+
+class ImpressController(object):
+    global log
+    log = logging.getLogger(u'ImpressController')
+
+    def __init__(self):
+        log.debug(u'Initialising')
+        self.process = None
+        self.document = None
+        self.presentation = None
+        self.startOpenoffice()
+
+    def startOpenoffice(self):
+        log.debug(u'start Openoffice')
+        cmd = u'openoffice.org -nologo -norestore -minimized -headless ' + u'"' + u'-accept=socket,host=localhost,port=2002;urp;'+ u'"'
+        self.process = QtCore.QProcess()
+        self.process.startDetached(cmd)
+        self.process.waitForStarted()
+
+    def kill(self):
+        log.debug(u'Kill')
+        self.closePresentation()
+
+    def loadPresentation(self, presentation):
+        log.debug(u'create Resolver')
+        try:
+            context = uno.getComponentContext()
+            resolver = context.ServiceManager.createInstanceWithContext(u'com.sun.star.bridge.UnoUrlResolver', context)
+            ctx = resolver.resolve(u'uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext')
+            smgr = ctx.ServiceManager
+            desktop = smgr.createInstanceWithContext( "com.sun.star.frame.Desktop", ctx )
+            url = uno.systemPathToFileUrl(presentation)
+            properties = []
+            properties = tuple(properties)
+            self.document = desktop.loadComponentFromURL(url, "_blank", 0, properties)
+            self.presentation = self.document.getPresentation()
+            self.presentation.start()
+        except:
+            log.error(u'Failed reason %s' % sys.exc_info())
+
+    def closePresentation(self):
+        """
+        Close presentation and clean up objects
+        Triggerent by new object being added to SlideController orOpenLP
+        being shut down
+        """
+        if self.document is not None:
+            if self.presentation is not None:
+                self.presentation.end()
+                self.presentation = None
+            self.document.dispose()
+            self.document = None
+
+    def isActive(self):
+        return self.presentation.isRunning() and self.presentation.isActive()
+
+    def resume(self):
+        return self.presentation.resume()
+
+    def pause(self):
+        return self.presentation.pause()
+
+    def blankScreen(self):
+        self.presentation.blankScreen(0)
+
+    def stop(self):
+        self.presentation.deactivate()
+        # self.presdoc.end()
+
+    def go(self):
+        self.presentation.activate()
+        # self.presdoc.start()
+
+    def getSlideNumber(self):
+        return self.presentation.getCurrentSlideIndex
+
+    def setSlideNumber(self, slideno):
+        self.presentation.gotoSlideIndex(slideno)
+
+    slideNumber = property(getSlideNumber, setSlideNumber)
+
+    def nextStep(self):
+        self.presentation.gotoNextSlide()
+
+    def prevStep(self):
+        self.presentation.gotoPreviousSlide()
+

=== modified file 'openlp/plugins/presentations/lib/mediaitem.py'
--- openlp/plugins/presentations/lib/mediaitem.py	2009-08-31 21:53:35 +0000
+++ openlp/plugins/presentations/lib/mediaitem.py	2009-09-05 13:30:09 +0000
@@ -22,6 +22,7 @@
 
 from PyQt4 import QtCore, QtGui
 from openlp.core.lib import MediaManagerItem, ServiceItem, translate, BaseListWithDnD
+from openlp.plugins.presentations.lib import MessageListener
 
 # We have to explicitly create separate classes for each plugin
 # in order for DnD to the Service manager to work correctly.
@@ -54,6 +55,7 @@
         # be instanced by the base MediaManagerItem
         self.ListViewWithDnD_class = PresentationListView
         MediaManagerItem.__init__(self, parent, icon, title)
+        self.message_listener = MessageListener(controllers)
 
     def addHeaderBar(self):
         self.PresentationWidget = QtGui.QWidget(self)

=== added file 'openlp/plugins/presentations/lib/messagelistener.py'
--- openlp/plugins/presentations/lib/messagelistener.py	1970-01-01 00:00:00 +0000
+++ openlp/plugins/presentations/lib/messagelistener.py	2009-09-05 19:58:02 +0000
@@ -0,0 +1,67 @@
+# -*- 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
+import os
+
+from PyQt4 import QtCore
+from openlp.core.lib import Receiver
+from openlp.plugins.presentations.lib import ImpressController
+
+class MessageListener(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'MessageListener')
+    log.info(u'Message Listener loaded')
+
+    def __init__(self, controllers):
+        self.controllers = controllers
+        self.handler = None
+
+        QtCore.QObject.connect(Receiver.get_receiver(),
+            QtCore.SIGNAL(u'presentations_start'), self.startup)
+        QtCore.QObject.connect(Receiver.get_receiver(),
+            QtCore.SIGNAL(u'presentations_stop'), self.next)
+        QtCore.QObject.connect(Receiver.get_receiver(),
+            QtCore.SIGNAL(u'presentations_first'), self.next)
+        QtCore.QObject.connect(Receiver.get_receiver(),
+            QtCore.SIGNAL(u'presentations_previous'), self.next)
+        QtCore.QObject.connect(Receiver.get_receiver(),
+            QtCore.SIGNAL(u'presentations_next'), self.next)
+        QtCore.QObject.connect(Receiver.get_receiver(),
+            QtCore.SIGNAL(u'presentations_last'), self.next)
+
+    def startup(self, message):
+        """
+        Start of new presentation
+        Save the handler as any new presentations start here
+        """
+        self.handler, file =  self.decodeMessage(message)
+        self.controllers[self.handler].loadPresentation(file)
+
+    def next(self, message):
+        self.controllers[self.handler].nextStep()
+
+    def decodeMessage(self, message):
+        bits = message.split(u':')
+        file = os.path.join(bits[1], bits[2])
+        return bits[0], file

=== modified file 'openlp/plugins/presentations/presentationplugin.py'
--- openlp/plugins/presentations/presentationplugin.py	2009-08-24 20:05:46 +0000
+++ openlp/plugins/presentations/presentationplugin.py	2009-09-06 08:11:32 +0000
@@ -19,12 +19,13 @@
 """
 
 import os
+import sys
 import logging
 
 from PyQt4 import QtCore, QtGui
 
 from openlp.core.lib import Plugin,  MediaManagerItem
-from openlp.plugins.presentations.lib import PresentationMediaItem, PresentationTab,  impressController
+from openlp.plugins.presentations.lib import PresentationMediaItem, PresentationTab,  ImpressController
 
 class PresentationPlugin(Plugin):
 
@@ -65,16 +66,16 @@
         If Not do not install the plugin.
         """
         log.debug('check_pre_conditions')
-
+        #Lets see if Impress is required (Default is Not wanted)
         if int(self.config.get_config(u'Impress', 0)) == 2:
             try:
                 #Check to see if we have uno installed
                 import uno
-                openoffice = impressController()
+                openoffice = ImpressController()
                 self.registerControllers(u'Impress', openoffice)
             except:
-                pass
-        #If we have no controllers disable plugin
+                log.error(u'Reason : %s', sys.exc_info())#[0])
+        #If we have no available controllers disable plugin
         if len(self.controllers) > 0:
             return True
         else:
@@ -82,7 +83,7 @@
 
     def finalise(self):
         log.debug(u'Finalise')
-        print self.controllers
+        #Ask each controller to tidy up
         for controller in self.controllers:
             print controller
             self.controllers[controller].kill()

=== added file 'openlp/plugins/remotes/lib/remotetab.py'
--- openlp/plugins/remotes/lib/remotetab.py	1970-01-01 00:00:00 +0000
+++ openlp/plugins/remotes/lib/remotetab.py	2009-09-05 08:58:29 +0000
@@ -0,0 +1,59 @@
+# -*- 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
+"""
+
+from PyQt4 import QtCore, QtGui
+
+from openlp.core.lib import SettingsTab,  str_to_bool,  translate
+
+class RemoteTab(SettingsTab):
+    """
+    RemoteTab is the Remotes settings tab in the settings dialog.
+    """
+    def __init__(self):
+        SettingsTab.__init__(self, translate(u'RemoteTab', u'Remotes'), u'Remotes')
+
+    def setupUi(self):
+        self.setObjectName(u'RemoteTab')
+        self.RemoteLayout = QtGui.QFormLayout(self)
+        self.RemoteLayout.setObjectName(u'RemoteLayout')
+        self.RemoteModeGroupBox = QtGui.QGroupBox(self)
+        self.RemoteModeGroupBox.setObjectName(u'RemoteModeGroupBox')
+        self.RemoteModeLayout = QtGui.QVBoxLayout(self.RemoteModeGroupBox)
+        self.RemoteModeLayout.setSpacing(8)
+        self.RemoteModeLayout.setMargin(8)
+        self.RemoteModeLayout.setObjectName(u'RemoteModeLayout')
+        self.RemotePortSpinBox = QtGui.QSpinBox(self.RemoteModeGroupBox)
+        self.RemotePortSpinBox.setObjectName(u'RemotePortSpinBox')
+        self.RemotePortSpinBox.setMaximum(32767)
+        self.RemoteModeLayout.addWidget(self.RemotePortSpinBox)
+        self.WarningLabel = QtGui.QLabel(self.RemoteModeGroupBox)
+        self.WarningLabel.setObjectName(u'WarningLabel')
+        self.RemoteModeLayout.addWidget(self.WarningLabel)
+        self.RemoteLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.RemoteModeGroupBox)
+
+    def retranslateUi(self):
+        self.RemoteModeGroupBox.setTitle(translate(u'RemoteTab', u'Remotes Receiver Port'))
+        self.WarningLabel.setText(translate(u'RemoteTab', u'A restart is needed for this change to become effective'))
+
+    def load(self):
+        self.RemotePortSpinBox.setValue(int(self.config.get_config(u'remote port', 4316)))
+
+    def save(self):
+        self.config.set_config(u'remote port', unicode(self.RemotePortSpinBox.value()))

=== modified file 'openlp/plugins/songs/forms/editsongform.py'
--- openlp/plugins/songs/forms/editsongform.py	2009-09-04 17:19:54 +0000
+++ openlp/plugins/songs/forms/editsongform.py	2009-09-05 08:58:29 +0000
@@ -285,7 +285,6 @@
             self.verse_form.setVerse(item.text())
             self.verse_form.exec_()
             item.setText(self.verse_form.getVerse())
-        self.VerseListWidget.repaint()
         self.VerseEditButton.setEnabled(False)
         self.VerseDeleteButton.setEnabled(False)
 


Follow ups