New features and fixes

bzr-revno: 522
This commit is contained in:
Tim Bentley 2009-09-06 18:34:13 +01:00
commit 1a7cd15be3
15 changed files with 337 additions and 30 deletions

View File

@ -54,6 +54,25 @@ class EventReceiver(QtCore.QObject):
``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')

View File

@ -135,6 +135,7 @@ class PluginManager(object):
"""
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.

View File

@ -51,6 +51,7 @@ class ServiceItem(object):
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 @@ class ServiceItem(object):
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 @@ class ServiceItem(object):
"""
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']

View File

@ -27,7 +27,9 @@ class SettingsManager(object):
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

View File

@ -106,7 +106,7 @@ class Ui_MainWindow(object):
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 @@ class Ui_MainWindow(object):
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(

View File

@ -18,6 +18,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 sys
import logging
import cPickle
import zipfile
@ -137,21 +138,28 @@ class ServiceManager(QtGui.QWidget):
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 @@ class ServiceManager(QtGui.QWidget):
#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)

View File

@ -68,6 +68,7 @@ class SlideController(QtGui.QWidget):
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 @@ class SlideController(QtGui.QWidget):
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 @@ class SlideController(QtGui.QWidget):
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 @@ class SlideController(QtGui.QWidget):
"""
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):
"""

View File

@ -17,8 +17,11 @@ 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 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']

View File

@ -182,7 +182,7 @@ class ImpressCOMSlide(object):
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()

View File

@ -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()

View File

@ -22,6 +22,7 @@ import os
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 @@ class PresentationMediaItem(MediaManagerItem):
# 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)

View File

@ -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

View File

@ -19,12 +19,13 @@ Place, Suite 330, Boston, MA 02111-1307 USA
"""
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 @@ class PresentationPlugin(Plugin):
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 @@ class PresentationPlugin(Plugin):
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()

View File

@ -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()))

View File

@ -285,7 +285,6 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
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)