diff --git a/documentation/pyqt-sql-py2exe.txt b/documentation/pyqt-sql-py2exe.txt deleted file mode 100644 index 33de23b6e..000000000 --- a/documentation/pyqt-sql-py2exe.txt +++ /dev/null @@ -1,58 +0,0 @@ -This content can be found at this URL: -http://netsuperbrain.com/Postmodern%20PostgreSQL%20Application%20Development.pdf - -Page 11-15: QtDesigner -Page 18-20: SQLAlchemy -Page 21-23: PyQt - widget -Page 24 : main -Page 28 : py2exe and release - - -============================== -This is the destilled content. -============================== - ----------------- -** sqlalchemy ** ----------------- -from sqlalchemy import create_engine, MetaData, Table -from sqlalchemy.orm import sessionmaker, mapper -engine = create_engine( 'postgres://postgres@localhost/customers' ) -metadata = MetaData( bind=engine, reflect=True) -Session = sessionmaker(bind=engine, autoflush=True, - transactional=True) - -class Customer(object): pass -mapper( Customer, Table('customers', metadata ) ) - -session = Session() -customer = Customer( businessName=“Jamb Safety”, - website=“www.jamb.com” ) -session.save( customer ) -for customer in Session.query(Customer).filter( - Customer.businessName.like(“Jamb%”)): - print customer.businessName -session.commit() - ------------------------- -** release and py2exe ** ------------------------- - -from distutils.core import setup -import py2exe -import glob -setup( - name="Customers", - author="Sankel Software", - author_email="david@sankelsoftware.com", - url="http://sankelsoftware.com", - license=“GPL", - version=“1.0.0", - windows=[ { "script":"main.py“,}], - options={"py2exe":{"includes":["sip”]}}, - data_files=[ - ("forms",glob.glob("forms/*.ui")), - ] ) - -release: -python setup.py py2exe --quiet --dist-dir=dist diff --git a/openlp.pyw b/openlp.pyw index f1b627940..e0c110a1c 100755 --- a/openlp.pyw +++ b/openlp.pyw @@ -78,9 +78,7 @@ class OpenLP(QtGui.QApplication): Run the OpenLP application. """ #Load and store current Application Version - filepath = AppLocation.get_directory(AppLocation.AppDir) - if not hasattr(sys, u'frozen'): - filepath = os.path.join(filepath, u'openlp') + filepath = AppLocation.get_directory(AppLocation.VersionDir) filepath = os.path.join(filepath, u'.version') fversion = None try: @@ -119,7 +117,7 @@ class OpenLP(QtGui.QApplication): pass #provide a listener for widgets to reqest a screen update. QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'process_events'), self.processEvents) + QtCore.SIGNAL(u'openlp_process_events'), self.processEvents) self.setApplicationName(u'OpenLP') self.setApplicationVersion(app_version[u'version']) if os.name == u'nt': @@ -201,4 +199,4 @@ if __name__ == u'__main__': """ Instantiate and run the application. """ - main() + main() \ No newline at end of file diff --git a/openlp/core/lib/eventreceiver.py b/openlp/core/lib/eventreceiver.py index 5b79fc40a..a839a8139 100644 --- a/openlp/core/lib/eventreceiver.py +++ b/openlp/core/lib/eventreceiver.py @@ -47,10 +47,10 @@ class EventReceiver(QtCore.QObject): ``{plugin}_add_service_item`` ask the plugin to push the selected items to the service item - ``update_themes`` + ``theme_update_list`` send out message with new themes - ``update_global_theme`` + ``theme_update_global`` Tell the components we have a new global theme ``load_song_list`` @@ -169,5 +169,4 @@ class Receiver(): """ Get the global ``eventreceiver`` instance. """ - return Receiver.eventreceiver - + return Receiver.eventreceiver \ No newline at end of file diff --git a/openlp/core/lib/pluginconfig.py b/openlp/core/lib/pluginconfig.py index 936a2f3a0..e27b86669 100644 --- a/openlp/core/lib/pluginconfig.py +++ b/openlp/core/lib/pluginconfig.py @@ -139,8 +139,9 @@ class PluginConfig(object): list = [] if list_count > 0: for counter in range(0, list_count): - item = unicode(self.get_config(u'%s %d' % (name, counter))) - list.append(item) + item = self.get_config(u'%s %d' % (name, counter)) + if item: + list.append(item) return list def set_list(self, name, list): diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index 7bb58af2b..3f3eedf5d 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -47,6 +47,7 @@ class ItemCapabilities(object): AllowsEdit = 2 AllowsMaintain = 3 RequiresMedia = 4 + AllowsLoop = 5 class ServiceItem(object): @@ -335,6 +336,3 @@ class ServiceItem(object): """ return self._raw_frames[row][u'path'] - def request_audit(self): - if self.audit: - Receiver.send_message(u'songusage_live', self.audit) diff --git a/openlp/core/ui/__init__.py b/openlp/core/ui/__init__.py index 21f41ae7c..0ba8f8da8 100644 --- a/openlp/core/ui/__init__.py +++ b/openlp/core/ui/__init__.py @@ -28,6 +28,7 @@ from servicenoteform import ServiceNoteForm from serviceitemeditform import ServiceItemEditForm from screen import ScreenList from maindisplay import MainDisplay +from maindisplay import VideoDisplay from amendthemeform import AmendThemeForm from slidecontroller import SlideController from splashscreen import SplashScreen diff --git a/openlp/core/ui/generaltab.py b/openlp/core/ui/generaltab.py index ec20650cf..f7e87e879 100644 --- a/openlp/core/ui/generaltab.py +++ b/openlp/core/ui/generaltab.py @@ -258,4 +258,5 @@ class GeneralTab(SettingsTab): if self.screens.monitor_number != self.MonitorNumber: self.screens.monitor_number = self.MonitorNumber self.screens.set_current_display(self.MonitorNumber) - Receiver.send_message(u'screen_changed') + Receiver.send_message(u'config_screen_changed') + Receiver.send_message(u'config_updated') diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index 5c2394ab2..92312429f 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -44,26 +44,27 @@ class DisplayWidget(QtGui.QWidget): def __init__(self, parent=None, name=None): QtGui.QWidget.__init__(self, parent) self.parent = parent - self.hotkey_map = {QtCore.Qt.Key_Return: 'servicemanager_next_item', - QtCore.Qt.Key_Space: 'live_slidecontroller_next_noloop', - QtCore.Qt.Key_Enter: 'live_slidecontroller_next_noloop', - QtCore.Qt.Key_0: 'servicemanager_next_item', - QtCore.Qt.Key_Backspace: 'live_slidecontroller_previous_noloop'} + self.hotkey_map = { + QtCore.Qt.Key_Return: 'servicemanager_next_item', + QtCore.Qt.Key_Space: 'slidecontroller_live_next_noloop', + QtCore.Qt.Key_Enter: 'slidecontroller_live_next_noloop', + QtCore.Qt.Key_0: 'servicemanager_next_item', + QtCore.Qt.Key_Backspace: 'slidecontroller_live_previous_noloop'} def keyPressEvent(self, event): if type(event) == QtGui.QKeyEvent: #here accept the event and do something if event.key() == QtCore.Qt.Key_Up: - Receiver.send_message(u'live_slidecontroller_previous') + Receiver.send_message(u'slidecontroller_live_previous') event.accept() elif event.key() == QtCore.Qt.Key_Down: - Receiver.send_message(u'live_slidecontroller_next') + Receiver.send_message(u'slidecontroller_live_next') event.accept() elif event.key() == QtCore.Qt.Key_PageUp: - Receiver.send_message(u'live_slidecontroller_first') + Receiver.send_message(u'slidecontroller_live_first') event.accept() elif event.key() == QtCore.Qt.Key_PageDown: - Receiver.send_message(u'live_slidecontroller_last') + Receiver.send_message(u'slidecontroller_live_last') event.accept() elif event.key() in self.hotkey_map: Receiver.send_message(self.hotkey_map[event.key()]) @@ -91,17 +92,13 @@ class MainDisplay(DisplayWidget): ``screens`` The list of screens. """ - log.debug(u'Initilisation started') + log.debug(u'Initialisation started') DisplayWidget.__init__(self, None) self.parent = parent self.setWindowTitle(u'OpenLP Display') + self.setAttribute(QtCore.Qt.WA_TranslucentBackground) + self.setWindowFlags(QtCore.Qt.FramelessWindowHint) self.screens = screens - self.mediaObject = Phonon.MediaObject(self) - self.video = Phonon.VideoWidget() - self.video.setVisible(False) - self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self.mediaObject) - Phonon.createPath(self.mediaObject, self.video) - Phonon.createPath(self.mediaObject, self.audio) self.display_image = QtGui.QLabel(self) self.display_image.setScaledContents(True) self.display_text = QtGui.QLabel(self) @@ -113,25 +110,14 @@ class MainDisplay(DisplayWidget): self.blankFrame = None self.frame = None self.firstTime = True - self.mediaLoaded = False self.hasTransition = False self.mediaBackground = False QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'live_slide_hide'), self.hideDisplay) + QtCore.SIGNAL(u'slide_live_hide'), self.hideDisplay) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'live_slide_show'), self.showDisplay) - QtCore.QObject.connect(self.mediaObject, - QtCore.SIGNAL(u'finished()'), self.onMediaFinish) + QtCore.SIGNAL(u'slide_live_show'), self.showDisplay) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'media_start'), self.onMediaQueue) - QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'media_play'), self.onMediaPlay) - QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'media_pause'), self.onMediaPause) - QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'media_stop'), self.onMediaStop) - QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'update_config'), self.setup) + QtCore.SIGNAL(u'slidecontroller_live_mediastart'), self.onMediaQueue) def setup(self): """ @@ -144,7 +130,6 @@ class MainDisplay(DisplayWidget): #Sort out screen locations and sizes self.setGeometry(self.screen[u'size']) self.display_alert.setGeometry(self.screen[u'size']) - self.video.setGeometry(self.screen[u'size']) self.display_image.resize(self.screen[u'size'].width(), self.screen[u'size'].height()) self.display_text.resize(self.screen[u'size'].width(), @@ -177,6 +162,7 @@ class MainDisplay(DisplayWidget): self.screen[u'size'].height()) self.transparent.fill(QtCore.Qt.transparent) self.display_alert.setPixmap(self.transparent) + self.display_text.setPixmap(self.transparent) self.frameView(self.transparent) # To display or not to display? if not self.screen[u'primary']: @@ -187,35 +173,41 @@ class MainDisplay(DisplayWidget): self.primary = True def resetDisplay(self): - Receiver.send_message(u'stop_display_loop') + log.debug(u'resetDisplay') + Receiver.send_message(u'maindisplay_stop_loop') if self.primary: self.setVisible(False) else: self.showFullScreen() def hideDisplay(self): - self.mediaLoaded = True - self.setVisible(False) + log.debug(u'hideDisplay') + self.display_image.setPixmap(self.transparent) + self.display_alert.setPixmap(self.transparent) + self.display_text.setPixmap(self.transparent) def showDisplay(self): - self.mediaLoaded = False + log.debug(u'showDisplay') if not self.primary: self.setVisible(True) self.showFullScreen() - Receiver.send_message(u'flush_alert') + Receiver.send_message(u'slide_live_active') def addImageWithText(self, frame): + log.debug(u'addImageWithText') frame = resize_image(frame, self.screen[u'size'].width(), self.screen[u'size'].height() ) self.display_image.setPixmap(QtGui.QPixmap.fromImage(frame)) def setAlertSize(self, top, height): + log.debug(u'setAlertSize') self.display_alert.setGeometry( QtCore.QRect(0, top, self.screen[u'size'].width(), height)) def addAlertImage(self, frame, blank=False): + log.debug(u'addAlertImage') if blank: self.display_alert.setPixmap(self.transparent) else: @@ -277,48 +269,146 @@ class MainDisplay(DisplayWidget): def onMediaQueue(self, message): log.debug(u'Queue new media message %s' % message) - self.display_image.close() - self.display_text.close() - self.display_alert.close() - file = os.path.join(message[1], message[2]) + self.hideDisplay() + self.activateWindow() + +class VideoWidget(QtGui.QWidget): + """ + Customised version of QTableWidget which can respond to keyboard + events. + """ + log.info(u'MainDisplay loaded') + + def __init__(self, parent=None, name=None): + QtGui.QWidget.__init__(self, None) + self.parent = parent + self.hotkey_map = { + QtCore.Qt.Key_Return: 'servicemanager_next_item', + QtCore.Qt.Key_Space: 'slidecontroller_live_next_noloop', + QtCore.Qt.Key_Enter: 'slidecontroller_live_next_noloop', + QtCore.Qt.Key_0: 'servicemanager_next_item', + QtCore.Qt.Key_Backspace: 'slidecontroller_live_previous_noloop'} + + def keyPressEvent(self, event): + if type(event) == QtGui.QKeyEvent: + #here accept the event and do something + if event.key() == QtCore.Qt.Key_Up: + Receiver.send_message(u'slidecontroller_live_previous') + event.accept() + elif event.key() == QtCore.Qt.Key_Down: + Receiver.send_message(u'slidecontroller_live_next') + event.accept() + elif event.key() == QtCore.Qt.Key_PageUp: + Receiver.send_message(u'slidecontroller_live_first') + event.accept() + elif event.key() == QtCore.Qt.Key_PageDown: + Receiver.send_message(u'slidecontroller_live_last') + event.accept() + elif event.key() in self.hotkey_map: + Receiver.send_message(self.hotkey_map[event.key()]) + event.accept() + elif event.key() == QtCore.Qt.Key_Escape: + self.resetDisplay() + event.accept() + event.ignore() + else: + event.ignore() + +class VideoDisplay(VideoWidget): + """ + This is the form that is used to display videos on the projector. + """ + log.info(u'VideoDisplay Loaded') + + def __init__(self, parent, screens): + """ + The constructor for the display form. + + ``parent`` + The parent widget. + + ``screens`` + The list of screens. + """ + log.debug(u'VideoDisplay Initialisation started') + VideoWidget.__init__(self, parent) + self.setWindowTitle(u'OpenLP Video Display') + self.parent = parent + self.screens = screens + self.setAttribute(QtCore.Qt.WA_TranslucentBackground) + self.setWindowFlags(QtCore.Qt.FramelessWindowHint) + self.mediaObject = Phonon.MediaObject(self) + self.video = Phonon.VideoWidget() + self.video.setVisible(False) + self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self.mediaObject) + Phonon.createPath(self.mediaObject, self.video) + Phonon.createPath(self.mediaObject, self.audio) + self.firstTime = True + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'slidecontroller_media_start'), self.onMediaQueue) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'slidecontroller_media_play'), self.onMediaPlay) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'slidecontroller_media_pause'), self.onMediaPause) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'slidecontroller_media_stop'), self.onMediaStop) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'config_updated'), self.setup) + + def setup(self): + """ + Sets up the screen on a particular screen. + """ + log.debug(u'VideoDisplay Setup %s for %s ' %(self.screens, + self.screens.monitor_number)) + self.setVisible(False) + self.screen = self.screens.current + #Sort out screen locations and sizes + self.setGeometry(self.screen[u'size']) + self.video.setGeometry(self.screen[u'size']) + + def onMediaQueue(self, message): + if not message[1]: + return + log.debug(u'VideoDisplay Queue new media message %s' % message) + file = os.path.join(message[0].get_frame_path(), + message[0].get_frame_title()) if self.firstTime: - self.mediaObject.setCurrentSource(Phonon.MediaSource(file)) + source = self.mediaObject.setCurrentSource(Phonon.MediaSource(file)) self.firstTime = False else: self.mediaObject.enqueue(Phonon.MediaSource(file)) self.onMediaPlay() def onMediaPlay(self): - log.debug(u'Play the new media, Live ') - if not self.mediaLoaded and not self.displayBlank: - self.blankDisplay() - self.display_frame = self.blankFrame + if not message[1]: + return + log.debug(u'VideoDisplay Play the new media, Live ') self.firstTime = True - self.mediaLoaded = True - self.display_image.hide() - self.display_text.hide() - self.display_alert.hide() + self.setWindowState(QtCore.Qt.WindowMinimized) self.video.setFullScreen(True) - self.video.setVisible(True) self.mediaObject.play() self.setVisible(True) - self.hide() + self.lower() def onMediaPause(self): - log.debug(u'Media paused by user') + if not message[1]: + return + log.debug(u'VideoDisplay Media paused by user') self.mediaObject.pause() def onMediaStop(self): - log.debug(u'Media stopped by user') + if not message[1]: + return + log.debug(u'VideoDisplay Media stopped by user') self.mediaObject.stop() self.onMediaFinish() def onMediaFinish(self): - log.debug(u'Reached end of media playlist') + if not message[1]: + return + log.debug(u'VideoDisplay Reached end of media playlist') self.mediaObject.stop() self.mediaObject.clearQueue() - self.mediaLoaded = False self.video.setVisible(False) - self.display_text.show() - self.display_image.show() - self.blankDisplay(False, False) + self.setVisible(False) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 23dbccabe..bb319ccb1 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -30,7 +30,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.ui import AboutForm, SettingsForm, \ ServiceManager, ThemeManager, MainDisplay, SlideController, \ - PluginForm, MediaDockManager + PluginForm, MediaDockManager, VideoDisplay from openlp.core.lib import RenderManager, PluginConfig, build_icon, \ OpenLPDockWidget, SettingsManager, PluginManager, Receiver, str_to_bool from openlp.core.utils import check_latest_version, AppLocation @@ -68,11 +68,11 @@ class VersionThread(QtCore.QThread): Run the thread. """ time.sleep(1) - Receiver.send_message(u'blank_check') + Receiver.send_message(u'maindisplay_blank_check') version = check_latest_version(self.generalConfig, self.app_version) #new version has arrived if version != self.app_version[u'full']: - Receiver.send_message(u'version_check', u'%s' % version) + Receiver.send_message(u'openlp_version_check', u'%s' % version) class Ui_MainWindow(object): @@ -443,6 +443,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): self.serviceNotSaved = False self.settingsmanager = SettingsManager(screens) self.generalConfig = PluginConfig(u'General') + self.videoDisplay = VideoDisplay(self, screens) self.mainDisplay = MainDisplay(self, screens) self.aboutForm = AboutForm(self, applicationVersion) self.settingsForm = SettingsForm(self.screens, self, self) @@ -491,13 +492,13 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtCore.QObject.connect(self.OptionsSettingsItem, QtCore.SIGNAL(u'triggered()'), self.onOptionsSettingsItemClicked) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'update_global_theme'), self.defaultThemeChanged) + QtCore.SIGNAL(u'theme_update_global'), self.defaultThemeChanged) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'version_check'), self.versionCheck) + QtCore.SIGNAL(u'openlp_version_check'), self.versionCheck) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'blank_check'), self.blankCheck) + QtCore.SIGNAL(u'maindisplay_blank_check'), self.blankCheck) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'screen_changed'), self.screenChanged) + QtCore.SIGNAL(u'config_screen_changed'), self.screenChanged) QtCore.QObject.connect(self.FileNewItem, QtCore.SIGNAL(u'triggered()'), self.ServiceManagerContents.onNewService) @@ -572,11 +573,14 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): self.showMaximized() #screen_number = self.getMonitorNumber() self.mainDisplay.setup() + self.videoDisplay.setup() if self.mainDisplay.isVisible(): self.mainDisplay.setFocus() self.activateWindow() if str_to_bool(self.generalConfig.get_config(u'auto open', False)): self.ServiceManagerContents.onLoadService(True) + self.videoDisplay.lower() + self.mainDisplay.raise_() def blankCheck(self): if str_to_bool(self.generalConfig.get_config(u'screen blank', False)) \ @@ -633,16 +637,19 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): if ret == QtGui.QMessageBox.Save: self.ServiceManagerContents.onSaveService() self.mainDisplay.close() + self.videoDisplay.close() self.cleanUp() event.accept() elif ret == QtGui.QMessageBox.Discard: self.mainDisplay.close() + self.videoDisplay.close() self.cleanUp() event.accept() else: event.ignore() else: self.mainDisplay.close() + self.videoDisplay.close() self.cleanUp() event.accept() diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 27ca95d0e..11ba067b0 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -186,11 +186,9 @@ class ServiceManager(QtGui.QWidget): QtCore.QObject.connect(self.ServiceManagerList, QtCore.SIGNAL(u'itemExpanded(QTreeWidgetItem*)'), self.expanded) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'update_themes'), self.updateThemeList) + QtCore.SIGNAL(u'theme_update_list'), self.updateThemeList) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'remote_edit_clear'), self.onRemoteEditClear) - QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'presentation types'), self.onPresentationTypes) + QtCore.SIGNAL(u'servicemanager_edit_clear'), self.onRemoteEditClear) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'servicemanager_next_item'), self.nextItem) QtCore.QObject.connect(Receiver.get_receiver(), @@ -257,9 +255,6 @@ class ServiceManager(QtGui.QWidget): if action == self.liveAction: self.makeLive() - def onPresentationTypes(self, presentation_types): - self.presentation_types = presentation_types - def onServiceItemNoteForm(self): item, count = self.findServiceItem() self.serviceNoteForm.textEdit.setPlainText( diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 35f520c9e..1d36bbdb7 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -54,11 +54,12 @@ class SlideList(QtGui.QTableWidget): def __init__(self, parent=None, name=None): QtGui.QTableWidget.__init__(self, parent.Controller) self.parent = parent - self.hotkey_map = {QtCore.Qt.Key_Return: 'servicemanager_next_item', - QtCore.Qt.Key_Space: 'live_slidecontroller_next_noloop', - QtCore.Qt.Key_Enter: 'live_slidecontroller_next_noloop', - QtCore.Qt.Key_0: 'servicemanager_next_item', - QtCore.Qt.Key_Backspace: 'live_slidecontroller_previous_noloop'} + self.hotkey_map = { + QtCore.Qt.Key_Return: 'servicemanager_next_item', + QtCore.Qt.Key_Space: 'slidecontroller_live_next_noloop', + QtCore.Qt.Key_Enter: 'slidecontroller_live_next_noloop', + QtCore.Qt.Key_0: 'servicemanager_next_item', + QtCore.Qt.Key_Backspace: 'slidecontroller_live_previous_noloop'} def keyPressEvent(self, event): if type(event) == QtGui.QKeyEvent: @@ -96,7 +97,7 @@ class SlideController(QtGui.QWidget): self.isLive = isLive self.parent = parent self.songsconfig = PluginConfig(u'Songs') - self.image_list = [ + self.loop_list = [ u'Start Loop', u'Stop Loop', u'Loop Separator', @@ -124,11 +125,11 @@ class SlideController(QtGui.QWidget): if self.isLive: self.TypeLabel.setText(self.trUtf8('Live')) self.split = 1 - prefix = u'live_slidecontroller' + self.type_prefix = u'live' else: self.TypeLabel.setText(self.trUtf8('Preview')) self.split = 0 - prefix = u'preview_slidecontroller' + self.type_prefix = u'preview' self.TypeLabel.setStyleSheet(u'font-weight: bold; font-size: 12pt;') self.TypeLabel.setAlignment(QtCore.Qt.AlignCenter) self.PanelLayout.addWidget(self.TypeLabel) @@ -196,7 +197,7 @@ class SlideController(QtGui.QWidget): u'Hide screen', u':/slides/slide_desktop.png', self.trUtf8('Hide Screen'), self.onHideDisplay, True) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'live_slide_blank'), self.blankScreen) + QtCore.SIGNAL(u'slide_live_blank'), self.blankScreen) if not self.isLive: self.Toolbar.addToolbarSeparator(u'Close Separator') self.Toolbar.addToolbarButton( @@ -233,6 +234,12 @@ class SlideController(QtGui.QWidget): self.Mediabar.addToolbarButton( u'Media Stop', u':/slides/media_playback_stop.png', self.trUtf8('Start playing media'), self.onMediaStop) + if not self.isLive: + self.seekSlider = Phonon.SeekSlider() + self.seekSlider.setGeometry(QtCore.QRect(90, 260, 221, 24)) + self.seekSlider.setObjectName(u'seekSlider') + self.Mediabar.addToolbarWidget( + u'Seek Slider', self.seekSlider) self.volumeSlider = Phonon.VolumeSlider() self.volumeSlider.setGeometry(QtCore.QRect(90, 260, 221, 24)) self.volumeSlider.setObjectName(u'volumeSlider') @@ -245,13 +252,15 @@ class SlideController(QtGui.QWidget): self.SongMenu.setText(self.trUtf8('Go to Verse')) self.SongMenu.setPopupMode(QtGui.QToolButton.InstantPopup) self.Toolbar.addToolbarWidget(u'Song Menu', self.SongMenu) - self.SongMenu.setMenu(QtGui.QMenu(self.trUtf8('Go to Verse'), self.Toolbar)) + self.SongMenu.setMenu(QtGui.QMenu(self.trUtf8('Go to Verse'), + self.Toolbar)) self.Toolbar.makeWidgetsInvisible([u'Song Menu']) # Screen preview area self.PreviewFrame = QtGui.QFrame(self.Splitter) self.PreviewFrame.setGeometry(QtCore.QRect(0, 0, 300, 225)) self.PreviewFrame.setSizePolicy(QtGui.QSizePolicy( - QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Label)) + QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Minimum, + QtGui.QSizePolicy.Label)) self.PreviewFrame.setFrameShape(QtGui.QFrame.StyledPanel) self.PreviewFrame.setFrameShadow(QtGui.QFrame.Sunken) self.PreviewFrame.setObjectName(u'PreviewFrame') @@ -296,30 +305,37 @@ class SlideController(QtGui.QWidget): QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSlideSelected) if isLive: QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'update_spin_delay'), self.receiveSpinDelay) - Receiver.send_message(u'request_spin_delay') + QtCore.SIGNAL(u'slidecontroller_live_spin_delay'), + self.receiveSpinDelay) if isLive: - self.Toolbar.makeWidgetsInvisible(self.image_list) + self.Toolbar.makeWidgetsInvisible(self.loop_list) else: self.Toolbar.makeWidgetsInvisible(self.song_edit_list) self.Mediabar.setVisible(False) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'stop_display_loop'), self.onStopLoop) + QtCore.SIGNAL(u'maindisplay_stop_loop'), self.onStopLoop) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'%s_first' % prefix), self.onSlideSelectedFirst) + QtCore.SIGNAL(u'slidecontroller_%s_go_first' % self.type_prefix), + self.onSlideSelectedFirst) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'%s_next' % prefix), self.onSlideSelectedNext) + QtCore.SIGNAL(u'%slidecontroller_s_go_next' % self.type_prefix), + self.onSlideSelectedNext) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'%s_previous' % prefix), self.onSlideSelectedPrevious) + QtCore.SIGNAL(u'slidecontroller_%s_go_previous' % self.type_prefix), + self.onSlideSelectedPrevious) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'%s_next_noloop' % prefix), self.onSlideSelectedNextNoloop) + QtCore.SIGNAL(u'slidecontroller_%s_go_next_noloop' % self.type_prefix), + self.onSlideSelectedNextNoloop) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'%s_previous_noloop' % prefix), + QtCore.SIGNAL(u'slidecontroller_%s_go_previous_noloop' % + self.type_prefix), self.onSlideSelectedPreviousNoloop) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'%s_last' % prefix), self.onSlideSelectedLast) + QtCore.SIGNAL(u'slidecontroller_%s_go_last' % self.type_prefix), + self.onSlideSelectedLast) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'%s_change' % prefix), self.onSlideChange) + QtCore.SIGNAL(u'slidecontroller_%s_change' % self.type_prefix), + self.onSlideChange) QtCore.QObject.connect(self.Splitter, QtCore.SIGNAL(u'splitterMoved(int, int)'), self.trackSplitter) QtCore.QObject.connect(Receiver.get_receiver(), @@ -374,20 +390,19 @@ class SlideController(QtGui.QWidget): self.Toolbar.setVisible(True) self.Mediabar.setVisible(False) self.Toolbar.makeWidgetsInvisible([u'Song Menu']) - self.Toolbar.makeWidgetsInvisible(self.image_list) + self.Toolbar.makeWidgetsInvisible(self.loop_list) if item.is_text(): - self.Toolbar.makeWidgetsInvisible(self.image_list) + self.Toolbar.makeWidgetsInvisible(self.loop_list) if str_to_bool(self.songsconfig.get_config(u'show songbar', True)) \ and len(self.slideList) > 0: self.Toolbar.makeWidgetsVisible([u'Song Menu']) - elif item.is_image(): - #Not sensible to allow loops with 1 frame - if len(item.get_frames()) > 1: - self.Toolbar.makeWidgetsVisible(self.image_list) - elif item.is_media(): + if item.is_capable(ItemCapabilities.AllowsLoop) and \ + len(item.get_frames()) > 1: + self.Toolbar.makeWidgetsVisible(self.loop_list) + if item.is_media(): self.Toolbar.setVisible(False) self.Mediabar.setVisible(True) - self.volumeSlider.setAudioOutput(self.parent.mainDisplay.audio) + #self.volumeSlider.setAudioOutput(self.parent.mainDisplay.videoDisplay.audio) def enablePreviewToolBar(self, item): """ @@ -455,20 +470,18 @@ class SlideController(QtGui.QWidget): Loads a ServiceItem into the system from ServiceManager Display the slide number passed """ - log.debug(u'processsManagerItem') + log.debug(u'processManagerItem') #If old item was a command tell it to stop if self.serviceItem and self.serviceItem.is_command(): self.onMediaStop() if serviceItem.is_media(): self.onMediaStart(serviceItem) - elif serviceItem.is_command(): - if self.isLive: - blanked = self.blankButton.isChecked() - else: - blanked = False - Receiver.send_message(u'%s_start' % serviceItem.name.lower(), \ - [serviceItem.title, serviceItem.get_frame_path(), - serviceItem.get_frame_title(), slideno, self.isLive, blanked]) + if self.isLive: + blanked = self.blankButton.isChecked() + else: + blanked = False + Receiver.send_message(u'slidecontroller_start', + [serviceItem, self.isLive, blanked, slideno]) self.slideList = {} width = self.parent.ControlSplitter.sizes()[self.split] #Set pointing cursor when we have somthing to point at @@ -532,7 +545,7 @@ class SlideController(QtGui.QWidget): self.PreviewListWidget.resizeRowsToContents() self.PreviewListWidget.setColumnWidth(0, self.labelWidth) self.PreviewListWidget.setColumnWidth(1, - self.PreviewListWidget.viewport().size().width() - self.labelWidth ) + self.PreviewListWidget.viewport().size().width() - self.labelWidth) if slideno > self.PreviewListWidget.rowCount(): self.PreviewListWidget.selectRow(self.PreviewListWidget.rowCount()) else: @@ -541,8 +554,6 @@ class SlideController(QtGui.QWidget): self.onSlideSelected() self.PreviewListWidget.setFocus() log.log(15, u'Display Rendering took %4s' % (time.time() - before)) - if self.isLive: - self.serviceItem.request_audit() #Screen event methods def onSlideSelectedFirst(self): @@ -552,7 +563,8 @@ class SlideController(QtGui.QWidget): if not self.serviceItem: return if self.serviceItem.is_command(): - Receiver.send_message(u'%s_first'% \ + Receiver.send_message(u'slidecontroller_%s_first' % + self.type_prefix, self.serviceItem.name.lower(), self.isLive) self.updatePreview() else: @@ -568,7 +580,7 @@ class SlideController(QtGui.QWidget): self.blankButton.setChecked(True) self.blankScreen(HideMode.Blank, self.blankButton.isChecked()) self.parent.generalConfig.set_config(u'screen blank', - self.blankButton.isChecked()) + self.blankButton.isChecked()) def onThemeDisplay(self, force=False): """ @@ -585,7 +597,7 @@ class SlideController(QtGui.QWidget): """ log.debug(u'onHideDisplay %d' % force) if force: - self.themeButton.setChecked(True) + self.hideButton.setChecked(True) if self.hideButton.isChecked(): self.parent.mainDisplay.hideDisplay() else: @@ -596,13 +608,13 @@ class SlideController(QtGui.QWidget): Blank the display screen. """ if self.serviceItem is not None: - if self.serviceItem.is_command(): - if blanked: - Receiver.send_message(u'%s_blank'% self.serviceItem.name.lower()) - else: - Receiver.send_message(u'%s_unblank'% self.serviceItem.name.lower()) + if blanked: + Receiver.send_message(u'slidecontroller_blank' % + [self.serviceItem, self.isLive]) else: - self.parent.mainDisplay.blankDisplay(blankType, blanked) + Receiver.send_message(u'slidecontroller_unblank' % + [self.serviceItem, self.isLive]) + self.parent.mainDisplay.blankDisplay(blankType, blanked) else: self.parent.mainDisplay.blankDisplay(blankType, blanked) @@ -614,9 +626,9 @@ class SlideController(QtGui.QWidget): row = self.PreviewListWidget.currentRow() self.selectedRow = 0 if row > -1 and row < self.PreviewListWidget.rowCount(): + Receiver.send_message(u'slidecontroller_slide', + [self.serviceItem, self.isLive, row]) if self.serviceItem.is_command() and self.isLive: - Receiver.send_message(u'%s_slide'% \ - self.serviceItem.name.lower(), u'%s:%s' % (row, self.isLive)) self.updatePreview() else: before = time.time() @@ -668,9 +680,9 @@ class SlideController(QtGui.QWidget): """ if not self.serviceItem: return + Receiver.send_message(u'slidecontroller_next', + [self.serviceItem, self.isLive]) if self.serviceItem.is_command(): - Receiver.send_message(u'%s_next' % \ - self.serviceItem.name.lower(), self.isLive) self.updatePreview() else: row = self.PreviewListWidget.currentRow() + 1 @@ -692,9 +704,9 @@ class SlideController(QtGui.QWidget): """ if not self.serviceItem: return + Receiver.send_message(u'slidecontroller_%s_previous' % + self.type_prefix, [self.serviceItem]) if self.serviceItem.is_command(): - Receiver.send_message( - u'%s_previous'% self.serviceItem.name.lower(), self.isLive) self.updatePreview() else: row = self.PreviewListWidget.currentRow() - 1 @@ -712,9 +724,9 @@ class SlideController(QtGui.QWidget): """ if not self.serviceItem: return + Receiver.send_message(u'slidecontroller_last', + [self.serviceItem, self.isLive]) if self.serviceItem.is_command(): - Receiver.send_message(u'%s_last' % \ - self.serviceItem.name.lower(), self.isLive) self.updatePreview() else: self.PreviewListWidget.selectRow( @@ -744,8 +756,8 @@ class SlideController(QtGui.QWidget): def onEditSong(self): self.songEdit = True - Receiver.send_message(u'%s_edit' % self.serviceItem.name, u'P:%s' % - self.serviceItem.editId ) + Receiver.send_message(u'slidecontroller_edit', + [self.serviceItem]) def onGoLive(self): """ @@ -758,34 +770,38 @@ class SlideController(QtGui.QWidget): def onMediaStart(self, item): if self.isLive: - Receiver.send_message(u'%s_start' % item.name.lower(), \ - [item.title, item.get_frame_path(), - item.get_frame_title(), self.isLive, self.blankButton.isChecked()]) + blanked = self.blankButton.isChecked() else: + blanked = False + Receiver.send_message(u'slidecontroller_media_start', + [item, self.isLive, blanked]) + if not self.isLive: self.mediaObject.stop() self.mediaObject.clearQueue() file = os.path.join(item.get_frame_path(), item.get_frame_title()) self.mediaObject.setCurrentSource(Phonon.MediaSource(file)) + self.seekSlider.setMediaObject(self.mediaObject) + self.seekSlider.show() self.onMediaPlay() def onMediaPause(self): - if self.isLive: - Receiver.send_message(u'%s_pause'% self.serviceItem.name.lower()) - else: + Receiver.send_message(u'slidecontroller_media_pause', + [item, self.isLive]) + if not self.isLive: self.mediaObject.pause() def onMediaPlay(self): - if self.isLive: - Receiver.send_message(u'%s_play'% self.serviceItem.name.lower(), self.isLive) - else: + Receiver.send_message(u'slidecontroller_media_play', + [item, self.isLive]) + if not self.isLive: self.SlidePreview.hide() self.video.show() self.mediaObject.play() def onMediaStop(self): - if self.isLive: - Receiver.send_message(u'%s_stop'% self.serviceItem.name.lower(), self.isLive) - else: + Receiver.send_message(u'slidecontroller_media_stop', + [item, self.isLive]) + if not self.isLive: self.mediaObject.stop() self.video.hide() self.SlidePreview.clear() diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index e35afa9a7..2867ed84b 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -102,7 +102,7 @@ class ThemeManager(QtGui.QWidget): QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.changeGlobalFromScreen) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'update_global_theme'), self.changeGlobalFromTab) + QtCore.SIGNAL(u'theme_update_global'), self.changeGlobalFromTab) #Variables self.themelist = [] self.path = os.path.join(ConfigHelper.get_data_path(), u'themes') @@ -148,7 +148,7 @@ class ThemeManager(QtGui.QWidget): self.ThemeListWidget.item(count).setText(name) self.config.set_config(u'global theme', self.global_theme) Receiver.send_message( - u'update_global_theme', self.global_theme) + u'theme_update_global', self.global_theme) self.pushThemes() def onAddTheme(self): @@ -291,7 +291,7 @@ class ThemeManager(QtGui.QWidget): self.pushThemes() def pushThemes(self): - Receiver.send_message(u'update_themes', self.getThemes() ) + Receiver.send_message(u'theme_update_list', self.getThemes() ) def getThemes(self): return self.themelist @@ -564,4 +564,4 @@ class ThemeManager(QtGui.QWidget): theme.font_main_y = int(theme.font_main_y.strip()) #theme.theme_mode theme.theme_name = theme.theme_name.strip() - #theme.theme_version + #theme.theme_version \ No newline at end of file diff --git a/openlp/core/ui/themestab.py b/openlp/core/ui/themestab.py index 0deca94e9..7bca99bf0 100644 --- a/openlp/core/ui/themestab.py +++ b/openlp/core/ui/themestab.py @@ -103,7 +103,7 @@ class ThemesTab(SettingsTab): QtCore.QObject.connect(self.DefaultComboBox, QtCore.SIGNAL(u'activated(int)'), self.onDefaultComboBoxChanged) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'update_themes'), self.updateThemeList) + QtCore.SIGNAL(u'theme_update_list'), self.updateThemeList) def retranslateUi(self): self.GlobalGroupBox.setTitle(self.trUtf8('Global theme')) @@ -136,12 +136,12 @@ class ThemesTab(SettingsTab): def save(self): self.config.set_config(u'theme level', self.theme_level) self.config.set_config(u'global theme',self.global_theme) - Receiver.send_message(u'update_global_theme', self.global_theme) + Receiver.send_message(u'theme_update_global', self.global_theme) self.parent.RenderManager.set_global_theme( self.global_theme, self.theme_level) def postSetUp(self): - Receiver.send_message(u'update_global_theme', self.global_theme) + Receiver.send_message(u'theme_update_global', self.global_theme) def onSongLevelButtonPressed(self): self.theme_level = ThemeLevel.Song @@ -188,4 +188,4 @@ class ThemesTab(SettingsTab): if not preview.isNull(): preview = preview.scaled(300, 255, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation) - self.DefaultListView.setPixmap(preview) + self.DefaultListView.setPixmap(preview) \ No newline at end of file diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index 4b053d877..12fc4a293 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -43,9 +43,10 @@ class AppLocation(object): ConfigDir = 2 DataDir = 3 PluginsDir = 4 + VersionDir = 5 @staticmethod - def get_directory(dir_type): + def get_directory(dir_type=1): """ Return the appropriate directory according to the directory type. @@ -83,17 +84,18 @@ class AppLocation(object): elif dir_type == AppLocation.PluginsDir: plugin_path = None app_path = os.path.abspath(os.path.split(sys.argv[0])[0]) - if sys.platform == u'win32': - if hasattr(sys, u'frozen') and sys.frozen == 1: - plugin_path = os.path.join(app_path, u'plugins') - else: - plugin_path = os.path.join(app_path, u'openlp', u'plugins') - elif sys.platform == u'darwin': + if hasattr(sys, u'frozen') and sys.frozen == 1: plugin_path = os.path.join(app_path, u'plugins') else: plugin_path = os.path.join( os.path.split(openlp.__file__)[0], u'plugins') return plugin_path + elif dir_type == AppLocation.VersionDir: + if hasattr(sys, u'frozen') and sys.frozen == 1: + plugin_path = os.path.abspath(os.path.split(sys.argv[0])[0]) + else: + plugin_path = os.path.split(openlp.__file__)[0] + return plugin_path def check_latest_version(config, current_version): diff --git a/openlp/core/utils/registry.py b/openlp/core/utils/registry.py index ba7c72a89..3d7137dfd 100644 --- a/openlp/core/utils/registry.py +++ b/openlp/core/utils/registry.py @@ -41,15 +41,17 @@ class Registry(object): """ Check if a value exists. """ - return self.config.has_option(section, key) + return self.config.has_option(section.encode('utf-8'), + key.encode('utf-8')) def get_value(self, section, key, default=None): """ Get a single value from the registry. """ try: - if self.config.get(section, key): - return self.config.get(section, key) + if self.config.get(section.encode('utf-8'), key.encode('utf-8')): + return self.config.get(section.encode('utf-8'), + key.encode('utf-8')).decode('utf-8') else: return default except: @@ -60,7 +62,8 @@ class Registry(object): Set a single value in the registry. """ try : - self.config.set(section, key, unicode(value)) + self.config.set(section.encode('utf-8'), key.encode('utf-8'), + unicode(value).encode('utf-8')) return self._save() except: return False @@ -70,7 +73,8 @@ class Registry(object): Delete a single value from the registry. """ try: - self.config.remove_option(section, key) + self.config.remove_option(section.encode('utf-8'), + key.encode('utf-8')) return self._save() except: return False @@ -79,14 +83,14 @@ class Registry(object): """ Check if a section exists. """ - return self.config.has_section(section) + return self.config.has_section(section.encode('utf-8')) def create_section(self, section): """ Create a new section in the registry. """ try: - self.config.add_section(section) + self.config.add_section(section.encode('utf-8')) return self._save() except: return False @@ -96,7 +100,7 @@ class Registry(object): Delete a section (including all values). """ try: - self.config.remove_section(section) + self.config.remove_section(section.encode('utf-8')) return self._save() except: return False diff --git a/openlp/plugins/alerts/forms/alertstab.py b/openlp/plugins/alerts/forms/alertstab.py index 9c45393af..33c574de5 100644 --- a/openlp/plugins/alerts/forms/alertstab.py +++ b/openlp/plugins/alerts/forms/alertstab.py @@ -35,6 +35,7 @@ class AlertsTab(SettingsTab): def __init__(self, parent, section=None): self.parent = parent self.manager = parent.manager + self.alertsmanager = parent.alertsmanager SettingsTab.__init__(self, parent.name, section) def setupUi(self): diff --git a/openlp/plugins/alerts/lib/alertsmanager.py b/openlp/plugins/alerts/lib/alertsmanager.py index 3b61125f4..7f3d7a654 100644 --- a/openlp/plugins/alerts/lib/alertsmanager.py +++ b/openlp/plugins/alerts/lib/alertsmanager.py @@ -40,21 +40,20 @@ class AlertsManager(QtCore.QObject): def __init__(self, parent): QtCore.QObject.__init__(self) self.parent = parent + self.screen = None self.timer_id = 0 self.alertList = [] QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'flush_alert'), self.generateAlert) + QtCore.SIGNAL(u'slide_live_active'), self.generateAlert) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'alert_text'), self.displayAlert) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'screen_changed'), self.screenChanged) - QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'config_updated'), self.screenChanged) + QtCore.SIGNAL(u'config_screen_changed'), self.screenChanged) def screenChanged(self): log.debug(u'screen changed') - self.screen = self.parent.maindisplay.screen self.alertTab = self.parent.alertsTab + self.screen = self.parent.maindisplay.screens.current self.font = QtGui.QFont() self.font.setFamily(self.alertTab.font_face) self.font.setBold(True) @@ -76,9 +75,11 @@ class AlertsManager(QtCore.QObject): display text """ log.debug(u'display alert called %s' % text) + if not self.screen: + self.screenChanged() self.parent.maindisplay.parent.StatusBar.showMessage(u'') self.alertList.append(text) - if self.timer_id != 0 or self.parent.maindisplay.mediaLoaded: + if self.timer_id != 0: self.parent.maindisplay.parent.StatusBar.showMessage(\ self.trUtf8(u'Alert message created and delayed')) return diff --git a/openlp/plugins/bibles/forms/importwizardform.py b/openlp/plugins/bibles/forms/importwizardform.py index a717a4f44..46bff5bb9 100644 --- a/openlp/plugins/bibles/forms/importwizardform.py +++ b/openlp/plugins/bibles/forms/importwizardform.py @@ -240,7 +240,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard): """ log.debug('Cancel button pressed!') if self.currentId() == 3: - Receiver.send_message(u'openlpstopimport') + Receiver.send_message(u'bibles_stop_import') def onCurrentIdChanged(self, id): if id == 3: @@ -354,7 +354,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard): log.debug(u'IncrementBar %s', status_text) self.ImportProgressLabel.setText(status_text) self.ImportProgressBar.setValue(self.ImportProgressBar.value() + 1) - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') def preImport(self): self.finishButton.setVisible(False) @@ -362,7 +362,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard): self.ImportProgressBar.setMaximum(1188) self.ImportProgressBar.setValue(0) self.ImportProgressLabel.setText(self.trUtf8('Starting import...')) - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') def performImport(self): bible_type = self.field(u'source_format').toInt()[0] @@ -424,4 +424,4 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard): self.ImportProgressBar.setValue(self.ImportProgressBar.maximum()) self.finishButton.setVisible(True) self.cancelButton.setVisible(False) - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') diff --git a/openlp/plugins/bibles/lib/biblestab.py b/openlp/plugins/bibles/lib/biblestab.py index 4c205b920..103187615 100644 --- a/openlp/plugins/bibles/lib/biblestab.py +++ b/openlp/plugins/bibles/lib/biblestab.py @@ -146,7 +146,7 @@ class BiblesTab(SettingsTab): self.BibleDualCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), self.onBibleDualCheckBox) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'update_themes'), self.updateThemeList) + QtCore.SIGNAL(u'theme_update_list'), self.updateThemeList) def retranslateUi(self): self.VerseDisplayGroupBox.setTitle(self.trUtf8('Verse Display')) @@ -225,4 +225,4 @@ class BiblesTab(SettingsTab): # Not Found id = 0 self.bible_theme = u'' - self.BibleThemeComboBox.setCurrentIndex(id) + self.BibleThemeComboBox.setCurrentIndex(id) \ No newline at end of file diff --git a/openlp/plugins/bibles/lib/csvbible.py b/openlp/plugins/bibles/lib/csvbible.py index 2f40e4b96..5b49852e5 100644 --- a/openlp/plugins/bibles/lib/csvbible.py +++ b/openlp/plugins/bibles/lib/csvbible.py @@ -52,7 +52,7 @@ class CSVBible(BibleDB): raise KeyError(u'You have to supply a file to import verses from.') self.versesfile = kwargs[u'versesfile'] QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'openlpstopimport'), self.stop_import) + QtCore.SIGNAL(u'bibles_stop_import'), self.stop_import) def stop_import(self): """ @@ -77,7 +77,7 @@ class CSVBible(BibleDB): details = chardet.detect(line[1]) self.create_book(unicode(line[1], details['encoding']), line[2], int(line[0])) - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') except: log.exception(u'Loading books from file failed') success = False @@ -105,7 +105,7 @@ class CSVBible(BibleDB): self.commit() self.create_verse(book.id, line[1], line[2], unicode(line[3], details['encoding'])) - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') self.commit() except: log.exception(u'Loading verses from file failed') @@ -118,4 +118,3 @@ class CSVBible(BibleDB): return False else: return success - diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py index b14f9b3a2..37d42f833 100644 --- a/openlp/plugins/bibles/lib/http.py +++ b/openlp/plugins/bibles/lib/http.py @@ -203,9 +203,9 @@ class BGExtract(BibleCommon): # Let's get the page, and then open it in BeautifulSoup, so as to # attempt to make "easy" work of bad HTML. page = urllib2.urlopen(urlstring) - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') soup = BeautifulSoup(page) - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') verses = soup.find(u'div', u'result-text-style-normal') verse_number = 0 verse_list = {0: u''} @@ -213,7 +213,7 @@ class BGExtract(BibleCommon): # This is a PERFECT example of opening the Cthulu tag! # O Bible Gateway, why doth ye such horrific HTML produce? for verse in verses: - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') if isinstance(verse, Tag) and verse.name == u'div' and filter(lambda a: a[0] == u'class', verse.attrs)[0][1] == u'footnotes': break if isinstance(verse, Tag) and verse.name == u'sup' and filter(lambda a: a[0] == u'class', verse.attrs)[0][1] != u'versenum': @@ -222,7 +222,7 @@ class BGExtract(BibleCommon): continue if isinstance(verse, Tag) and (verse.name == u'p' or verse.name == u'font') and verse.contents: for item in verse.contents: - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') if isinstance(item, Tag) and (item.name == u'h4' or item.name == u'h5'): continue if isinstance(item, Tag) and item.name == u'sup' and filter(lambda a: a[0] == u'class', item.attrs)[0][1] != u'versenum': @@ -235,7 +235,7 @@ class BGExtract(BibleCommon): continue if isinstance(item, Tag) and item.name == u'font': for subitem in item.contents: - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') if isinstance(subitem, Tag) and subitem.name == u'sup' and filter(lambda a: a[0] == u'class', subitem.attrs)[0][1] != u'versenum': continue if isinstance(subitem, Tag) and subitem.name == u'p' and not subitem.contents: @@ -294,37 +294,37 @@ class CWExtract(BibleCommon): (version, urlbookname.lower(), chapter) log.debug(u'URL: %s', chapter_url) page = urllib2.urlopen(chapter_url) - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') if not page: return None soup = BeautifulSoup(page) - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') htmlverses = soup.findAll(u'span', u'versetext') verses = {} reduce_spaces = re.compile(r'[ ]{2,}') fix_punctuation = re.compile(r'[ ]+([.,;])') for verse in htmlverses: - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') versenumber = int(verse.contents[0].contents[0]) versetext = u'' for part in verse.contents: - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') if isinstance(part, NavigableString): versetext = versetext + part elif part and part.attrMap and \ (part.attrMap[u'class'] == u'WordsOfChrist' or \ part.attrMap[u'class'] == u'strongs'): for subpart in part.contents: - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') if isinstance(subpart, NavigableString): versetext = versetext + subpart elif subpart and subpart.attrMap and \ subpart.attrMap[u'class'] == u'strongs': for subsub in subpart.contents: - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') if isinstance(subsub, NavigableString): versetext = versetext + subsub - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') # Fix up leading and trailing spaces, multiple spaces, and spaces # between text and , and . versetext = versetext.strip(u'\n\r\t ') @@ -415,14 +415,14 @@ class HTTPBible(BibleDB): if not db_book: book_details = self.lookup_book(book) if not book_details: - Receiver.send_message(u'bible_nobook') + Receiver.send_message(u'bibles_nobook') return [] db_book = self.create_book(book_details[u'name'], book_details[u'abbreviation'], book_details[u'testament_id']) book = db_book.name if BibleDB.get_verse_count(self, book, reference[1]) == 0: - Receiver.send_message(u'bible_showprogress') - Receiver.send_message(u'process_events') + Receiver.send_message(u'bibles_showprogress') + Receiver.send_message(u'openlp_process_events') search_results = self.get_chapter(self.name, book, reference[1]) if search_results and search_results.has_verselist(): ## We have found a book of the bible lets check to see @@ -430,14 +430,14 @@ class HTTPBible(BibleDB): ## we get a correct book. For example it is possible ## to request ac and get Acts back. bookname = search_results.get_book() - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') # check to see if book/chapter exists db_book = self.get_book(bookname) self.create_chapter(db_book.id, search_results.get_chapter(), search_results.get_verselist()) - Receiver.send_message(u'process_events') - Receiver.send_message(u'bible_hideprogress') - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') + Receiver.send_message(u'bibles_hideprogress') + Receiver.send_message(u'openlp_process_events') return BibleDB.get_verses(self, reference_list) def get_chapter(self, version, book, chapter): @@ -496,4 +496,3 @@ class HTTPBible(BibleDB): The hostname or IP address of the proxy server. """ self.proxy_server = server - diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index 80c81f3e7..66d27e4d3 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -63,7 +63,7 @@ class BibleMediaItem(MediaManagerItem): # place to store the search results self.search_results = {} QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'openlpreloadbibles'), self.reloadBibles) + QtCore.SIGNAL(u'bibles_load_list'), self.reloadBibles) def _decodeQtObject(self, listobj, key): obj = listobj[QtCore.QString(key)] @@ -257,11 +257,11 @@ class BibleMediaItem(MediaManagerItem): QtCore.QObject.connect(self.QuickSearchEdit, QtCore.SIGNAL(u'returnPressed()'), self.onQuickSearchButton) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'bible_showprogress'), self.onSearchProgressShow) + QtCore.SIGNAL(u'bibles_showprogress'), self.onSearchProgressShow) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'bible_hideprogress'), self.onSearchProgressHide) + QtCore.SIGNAL(u'bibles_hideprogress'), self.onSearchProgressHide) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'bible_nobook'), self.onNoBookFound) + QtCore.SIGNAL(u'bibles_nobook'), self.onNoBookFound) def addListViewToToolBar(self): MediaManagerItem.addListViewToToolBar(self) @@ -322,7 +322,7 @@ class BibleMediaItem(MediaManagerItem): def setQuickMessage(self, text): self.QuickMessage.setText(text) self.AdvancedMessage.setText(text) - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') #minor delay to get the events processed time.sleep(0.1) @@ -353,7 +353,7 @@ class BibleMediaItem(MediaManagerItem): def onSearchProgressShow(self): self.SearchProgress.setVisible(True) - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') #self.SearchProgress.setMinimum(0) #self.SearchProgress.setMaximum(2) #self.SearchProgress.setValue(1) @@ -449,6 +449,7 @@ class BibleMediaItem(MediaManagerItem): raw_footer = [] bible_text = u'' service_item.add_capability(ItemCapabilities.AllowsPreview) + service_item.add_capability(ItemCapabilities.AllowsLoop) #If we want to use a 2nd translation / version bible2 = u'' if self.SearchTabWidget.currentIndex() == 0: diff --git a/openlp/plugins/bibles/lib/opensong.py b/openlp/plugins/bibles/lib/opensong.py index 2f7e3e451..ea8bd3538 100644 --- a/openlp/plugins/bibles/lib/opensong.py +++ b/openlp/plugins/bibles/lib/opensong.py @@ -49,7 +49,7 @@ class OpenSongBible(BibleDB): raise KeyError(u'You have to supply a file name to import from.') self.filename = kwargs['filename'] QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'openlpstopimport'), self.stop_import) + QtCore.SIGNAL(u'bibles_stop_import'), self.stop_import) def stop_import(self): """ @@ -92,7 +92,7 @@ class OpenSongBible(BibleDB): int(verse.attrib[u'n']), unicode(verse.text) ) - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') self.wizard.incrementProgressBar( QtCore.QString('%s %s %s' % (self.trUtf8('Importing'),\ db_book.name, chapter.attrib[u'n']))) diff --git a/openlp/plugins/bibles/lib/osis.py b/openlp/plugins/bibles/lib/osis.py index 4416bb2c6..7c532e313 100644 --- a/openlp/plugins/bibles/lib/osis.py +++ b/openlp/plugins/bibles/lib/osis.py @@ -84,7 +84,7 @@ class OSISBible(BibleDB): if fbibles: fbibles.close() QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'openlpstopimport'), self.stop_import) + QtCore.SIGNAL(u'bibles_stop_import'), self.stop_import) def stop_import(self): """ @@ -167,7 +167,7 @@ class OSISBible(BibleDB): .replace(u'', u'').replace(u'', u'') verse_text = self.spaces_regex.sub(u' ', verse_text) self.create_verse(db_book.id, chapter, verse, verse_text) - Receiver.send_message(u'process_events') + Receiver.send_message(u'openlp_process_events') self.commit() self.wizard.incrementProgressBar(u'Finishing import...') if match_count == 0: diff --git a/openlp/plugins/custom/forms/editcustomdialog.py b/openlp/plugins/custom/forms/editcustomdialog.py index 35af9ce8d..5f3fe7614 100644 --- a/openlp/plugins/custom/forms/editcustomdialog.py +++ b/openlp/plugins/custom/forms/editcustomdialog.py @@ -24,13 +24,14 @@ ############################################################################### from PyQt4 import QtCore, QtGui -from openlp.core.lib import build_icon class Ui_customEditDialog(object): def setupUi(self, customEditDialog): customEditDialog.setObjectName(u'customEditDialog') customEditDialog.resize(590, 541) - icon = build_icon(u':/icon/openlp.org-icon-32.bmp') + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(u':/icon/openlp.org-icon-32.bmp'), + QtGui.QIcon.Normal, QtGui.QIcon.Off) customEditDialog.setWindowIcon(icon) self.gridLayout = QtGui.QGridLayout(customEditDialog) self.gridLayout.setObjectName(u'gridLayout') @@ -52,15 +53,19 @@ class Ui_customEditDialog(object): self.verticalLayout = QtGui.QVBoxLayout() self.verticalLayout.setObjectName(u'verticalLayout') self.UpButton = QtGui.QPushButton(customEditDialog) - icon1 = build_icon(u':/services/service_up.png') + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap(u':/services/service_up.png'), + QtGui.QIcon.Normal, QtGui.QIcon.Off) self.UpButton.setIcon(icon1) self.UpButton.setObjectName(u'UpButton') self.verticalLayout.addWidget(self.UpButton) - spacerItem = QtGui.QSpacerItem(20, 128, - QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) + spacerItem = QtGui.QSpacerItem(20, 128, QtGui.QSizePolicy.Minimum, + QtGui.QSizePolicy.Expanding) self.verticalLayout.addItem(spacerItem) self.DownButton = QtGui.QPushButton(customEditDialog) - icon2 = build_icon(u':/services/service_down.png') + icon2 = QtGui.QIcon() + icon2.addPixmap(QtGui.QPixmap(u':/services/service_down.png'), + QtGui.QIcon.Normal, QtGui.QIcon.Off) self.DownButton.setIcon(icon2) self.DownButton.setObjectName(u'DownButton') self.verticalLayout.addWidget(self.DownButton) @@ -97,6 +102,9 @@ class Ui_customEditDialog(object): self.ClearButton = QtGui.QPushButton(self.ButtonWidge) self.ClearButton.setObjectName(u'ClearButton') self.verticalLayout_2.addWidget(self.ClearButton) + self.SplitButton = QtGui.QPushButton(self.ButtonWidge) + self.SplitButton.setObjectName(u'SplitButton') + self.verticalLayout_2.addWidget(self.SplitButton) spacerItem1 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) self.verticalLayout_2.addItem(spacerItem1) @@ -121,16 +129,15 @@ class Ui_customEditDialog(object): self.horizontalLayout_2.addWidget(self.CreditEdit) self.gridLayout.addLayout(self.horizontalLayout_2, 4, 0, 1, 1) self.buttonBox = QtGui.QDialogButtonBox(customEditDialog) - self.buttonBox.setStandardButtons( - QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Save) + self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Save) self.buttonBox.setObjectName(u'buttonBox') self.gridLayout.addWidget(self.buttonBox, 5, 0, 1, 1) self.retranslateUi(customEditDialog) - QtCore.QObject.connect(self.buttonBox, - QtCore.SIGNAL(u'rejected()'), customEditDialog.closePressed) - QtCore.QObject.connect(self.buttonBox, - QtCore.SIGNAL(u'accepted()'), customEditDialog.accept) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(u'accepted()'), + customEditDialog.accept) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(u'rejected()'), + customEditDialog.closePressed) QtCore.QMetaObject.connectSlotsByName(customEditDialog) customEditDialog.setTabOrder(self.TitleEdit, self.VerseTextEdit) customEditDialog.setTabOrder(self.VerseTextEdit, self.AddButton) @@ -143,12 +150,11 @@ class Ui_customEditDialog(object): customEditDialog.setTabOrder(self.CreditEdit, self.UpButton) customEditDialog.setTabOrder(self.UpButton, self.DownButton) customEditDialog.setTabOrder(self.DownButton, self.ThemeComboBox) - customEditDialog.setTabOrder(self.ThemeComboBox, self.buttonBox) def retranslateUi(self, customEditDialog): + customEditDialog.setWindowTitle(self.trUtf8('Edit Custom Slides')) self.UpButton.setToolTip(self.trUtf8('Move slide Up 1')) self.DownButton.setToolTip(self.trUtf8('Move slide down 1')) - customEditDialog.setWindowTitle(self.trUtf8('Edit Custom Slides')) self.TitleLabel.setText(self.trUtf8('Title:')) self.AddButton.setText(self.trUtf8('Add New')) self.AddButton.setToolTip(self.trUtf8('Add new slide at bottom')) @@ -162,6 +168,7 @@ class Ui_customEditDialog(object): self.DeleteButton.setToolTip(self.trUtf8('Delete selected slide')) self.ClearButton.setText(self.trUtf8('Clear')) self.ClearButton.setToolTip(self.trUtf8('Clear edit area')) + self.SplitButton.setText(self.trUtf8('Split Slide')) + self.SplitButton.setToolTip(self.trUtf8('Add slide split')) self.ThemeLabel.setText(self.trUtf8('Theme:')) - self.ThemeComboBox.setToolTip(self.trUtf8('Set Theme for Slides')) self.CreditLabel.setText(self.trUtf8('Credits:')) diff --git a/openlp/plugins/custom/forms/editcustomform.py b/openlp/plugins/custom/forms/editcustomform.py index 410bd6fed..ff757d638 100644 --- a/openlp/plugins/custom/forms/editcustomform.py +++ b/openlp/plugins/custom/forms/editcustomform.py @@ -68,6 +68,8 @@ class EditCustomForm(QtGui.QDialog, Ui_customEditDialog): QtCore.SIGNAL(u'pressed()'), self.onUpButtonPressed) QtCore.QObject.connect(self.DownButton, QtCore.SIGNAL(u'pressed()'), self.onDownButtonPressed) + QtCore.QObject.connect(self.SplitButton, + QtCore.SIGNAL(u'pressed()'), self.onSplitButtonPressed) QtCore.QObject.connect(self.VerseListView, QtCore.SIGNAL(u'itemDoubleClicked(QListWidgetItem*)'), self.onVerseListViewSelected) @@ -75,7 +77,7 @@ class EditCustomForm(QtGui.QDialog, Ui_customEditDialog): QtCore.SIGNAL(u'itemClicked(QListWidgetItem*)'), self.onVerseListViewPressed) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'update_themes'), self.loadThemes) + QtCore.SIGNAL(u'theme_update_list'), self.loadThemes) # Create other objects and forms self.custommanager = custommanager self.initialise() @@ -84,7 +86,7 @@ class EditCustomForm(QtGui.QDialog, Ui_customEditDialog): log.debug(u'onPreview') if button.text() == unicode(self.trUtf8('Save && Preview')) \ and self.saveCustom(): - Receiver.send_message(u'preview_custom') + Receiver.send_message(u'custom_preview') def initialise(self): self.editAll = False @@ -94,6 +96,7 @@ class EditCustomForm(QtGui.QDialog, Ui_customEditDialog): self.EditAllButton.setEnabled(True) self.SaveButton.setEnabled(False) self.ClearButton.setEnabled(False) + self.SplitButton.setEnabled(False) self.TitleEdit.setText(u'') self.CreditEdit.setText(u'') self.VerseTextEdit.clear() @@ -132,13 +135,13 @@ class EditCustomForm(QtGui.QDialog, Ui_customEditDialog): self.previewButton.setVisible(True) def closePressed(self): - Receiver.send_message(u'remote_edit_clear') + Receiver.send_message(u'servicemanager_edit_clear') self.close() def accept(self): log.debug(u'accept') if self.saveCustom(): - Receiver.send_message(u'load_custom_list') + Receiver.send_message(u'custom_load_list') self.close() def saveCustom(self): @@ -202,12 +205,14 @@ class EditCustomForm(QtGui.QDialog, Ui_customEditDialog): def onEditAllButtonPressed(self): self.editAll = True self.AddButton.setEnabled(False) + self.SplitButton.setEnabled(True) if self.VerseListView.count() > 0: verse_list = u'' for row in range(0, self.VerseListView.count()): item = self.VerseListView.item(row) verse_list += item.text() - verse_list += u'\n---\n' + if row != self.VerseListView.count() - 1: + verse_list += u'\n[---]\n' self.editText(verse_list) def editText(self, text): @@ -222,7 +227,7 @@ class EditCustomForm(QtGui.QDialog, Ui_customEditDialog): def onSaveButtonPressed(self): if self.editAll: self.VerseListView.clear() - for row in unicode(self.VerseTextEdit.toPlainText()).split(u'\n---\n'): + for row in unicode(self.VerseTextEdit.toPlainText()).split(u'\n[---]\n'): self.VerseListView.addItem(row) else: self.VerseListView.currentItem().setText( @@ -241,8 +246,15 @@ class EditCustomForm(QtGui.QDialog, Ui_customEditDialog): self.SaveButton.setEnabled(False) self.EditButton.setEnabled(False) self.EditAllButton.setEnabled(True) + self.SplitButton.setEnabled(False) self.VerseTextEdit.clear() + def onSplitButtonPressed(self): + if self.VerseTextEdit.textCursor().columnNumber() != 0: + self.VerseTextEdit.insertPlainText(u'\n') + self.VerseTextEdit.insertPlainText(u'[---]\n' ) + self.VerseTextEdit.setFocus() + def onDeleteButtonPressed(self): self.VerseListView.takeItem(self.VerseListView.currentRow()) self.EditButton.setEnabled(False) @@ -258,5 +270,5 @@ class EditCustomForm(QtGui.QDialog, Ui_customEditDialog): return False, self.trUtf8('You need to enter a slide') if self.VerseTextEdit.toPlainText(): self.VerseTextEdit.setFocus() - return False, self.trUtf8('You have unsaved data') + return False, self.trUtf8('You have unsaved data, please save or clear') return True, u'' diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index 3c68b6d3d..a22c211e6 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -58,13 +58,13 @@ class CustomMediaItem(MediaManagerItem): def addEndHeaderBar(self): QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'%s_edit' % self.parent.name), self.onRemoteEdit) + QtCore.SIGNAL(u'custom_edit'), self.onRemoteEdit) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'remote_edit_clear' ), self.onRemoteEditClear) + QtCore.SIGNAL(u'servicemanager_edit_clear' ), self.onRemoteEditClear) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'load_custom_list'), self.initialise) + QtCore.SIGNAL(u'custom_load_list'), self.initialise) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'preview_custom'), self.onPreviewClick) + QtCore.SIGNAL(u'custom_preview'), self.onPreviewClick) def initPluginNameVisible(self): self.PluginNameVisible = self.trUtf8('Custom') @@ -149,6 +149,7 @@ class CustomMediaItem(MediaManagerItem): item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0] service_item.add_capability(ItemCapabilities.AllowsEdit) service_item.add_capability(ItemCapabilities.AllowsPreview) + service_item.add_capability(ItemCapabilities.AllowsLoop) customSlide = self.parent.custommanager.get_custom(item_id) title = customSlide.title credit = customSlide.credits @@ -169,4 +170,4 @@ class CustomMediaItem(MediaManagerItem): else: raw_footer.append(u'') service_item.raw_footer = raw_footer - return True \ No newline at end of file + return True diff --git a/openlp/plugins/images/lib/imagetab.py b/openlp/plugins/images/lib/imagetab.py index 203b36842..9283dbdf3 100644 --- a/openlp/plugins/images/lib/imagetab.py +++ b/openlp/plugins/images/lib/imagetab.py @@ -76,7 +76,9 @@ class ImageTab(SettingsTab): def save(self): self.config.set_config(u'loop delay', self.loop_delay) - Receiver.send_message(u'update_spin_delay', self.loop_delay) + Receiver.send_message(u'slidecontroller_live_spin_delay', + self.loop_delay) def postSetUp(self): - Receiver.send_message(u'update_spin_delay', self.loop_delay) + Receiver.send_message(u'slidecontroller_live_spin_delay', + self.loop_delay) diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index 4d56a7d32..6fbf66022 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -139,6 +139,7 @@ class ImageMediaItem(MediaManagerItem): service_item.title = self.trUtf8('Image(s)') service_item.add_capability(ItemCapabilities.AllowsMaintain) service_item.add_capability(ItemCapabilities.AllowsPreview) + service_item.add_capability(ItemCapabilities.AllowsLoop) for item in items: bitem = self.ListView.item(item.row()) filename = unicode((bitem.data(QtCore.Qt.UserRole)).toString()) @@ -162,4 +163,4 @@ class ImageMediaItem(MediaManagerItem): self.parent.maindisplay.addImageWithText(frame) def onPreviewClick(self): - MediaManagerItem.onPreviewClick(self) \ No newline at end of file + MediaManagerItem.onPreviewClick(self) diff --git a/openlp/plugins/presentations/lib/messagelistener.py b/openlp/plugins/presentations/lib/messagelistener.py index 39717d42d..beede4019 100644 --- a/openlp/plugins/presentations/lib/messagelistener.py +++ b/openlp/plugins/presentations/lib/messagelistener.py @@ -186,23 +186,23 @@ class MessageListener(object): self.liveHandler = Controller(True) # messages are sent from core.ui.slidecontroller QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'presentations_start'), self.startup) + QtCore.SIGNAL(u'slidecontroller_start'), self.startup) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'presentations_stop'), self.shutdown) + QtCore.SIGNAL(u'slidecontroller_stop'), self.shutdown) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'presentations_first'), self.first) + QtCore.SIGNAL(u'slidecontroller_first'), self.first) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'presentations_previous'), self.previous) + QtCore.SIGNAL(u'slidecontroller_previous'), self.previous) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'presentations_next'), self.next) + QtCore.SIGNAL(u'slidecontroller_next'), self.next) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'presentations_last'), self.last) + QtCore.SIGNAL(u'slidecontroller_last'), self.last) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'presentations_slide'), self.slide) + QtCore.SIGNAL(u'slidecontroller_slide'), self.slide) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'presentations_blank'), self.blank) + QtCore.SIGNAL(u'slidecontroller_blank'), self.blank) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'presentations_unblank'), self.unblank) + QtCore.SIGNAL(u'slidecontroller_unblank'), self.unblank) self.timer = QtCore.QTimer() self.timer.setInterval(500) QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.timeout) @@ -212,84 +212,96 @@ class MessageListener(object): Start of new presentation Save the handler as any new presentations start here """ + name, isLive, item = self.decode_message(message) + if name != u'presentation': + return log.debug(u'Startup called with message %s' % message) - self.handler, file, isLive, isBlank = self.decodeMessage(message) + isBlank = message[2] + file = os.path.join(item.get_frame_path(), + item.get_frame_title()) + self.handler = item.title if self.handler == self.mediaitem.Automatic: self.handler = self.mediaitem.findControllerByType(file) if not self.handler: return - if isLive: controller = self.liveHandler else: controller = self.previewHandler controller.addHandler(self.controllers[self.handler], file, isBlank) + def decode_message(self, message): + return message[0].name.lower(), message[1], message[0] + def slide(self, message): - slide, live = self.splitMessage(message) - if live: + name, isLive, item = self.decode_message(message) + if name != u'presentation': + return + if isLive: self.liveHandler.slide(slide, live) else: self.previewHandler.slide(slide, live) - def first(self, isLive): + def first(self, message): + name, isLive, item = self.decode_message(message) + if name != u'presentation': + return if isLive: self.liveHandler.first() else: self.previewHandler.first() - def last(self, isLive): + def last(self, message): + name, isLive, item = self.decode_message(message) + if name != u'presentation': + return if isLive: self.liveHandler.last() else: self.previewHandler.last() - def next(self, isLive): + def next(self, message): + name, isLive, item = self.decode_message(message) + if name != u'presentation': + return if isLive: self.liveHandler.next() else: self.previewHandler.next() - def previous(self, isLive): + def previous(self, message): + name, isLive, item = self.decode_message(message) + if name != u'presentation': + return if isLive: self.liveHandler.previous() else: self.previewHandler.previous() - def shutdown(self, isLive): + def shutdown(self, message): + name, isLive, item = self.decode_message(message) + if name != u'presentation': + return if isLive: + Receiver.send_message(u'slide_live_show') self.liveHandler.shutdown() - Receiver.send_message(u'live_slide_show') else: self.previewHandler.shutdown() - def blank(self): - self.liveHandler.blank() - - def unblank(self): - self.liveHandler.unblank() - - def splitMessage(self, message): - """ - Splits the selection messages - into it's component parts - - ``message`` - Message containing Presentaion handler name and file to be presented. - """ - bits = message.split(u':') - return bits[0], bits[1] - - def decodeMessage(self, message): - """ - Splits the initial message from the SlideController - into it's component parts - - ``message`` - Message containing Presentaion handler name and file to be presented. - """ - file = os.path.join(message[1], message[2]) - return message[0], file, message[4], message[5] + def blank(self, message): + name, isLive, item = self.decode_message(message) + if name != u'presentation': + return + if isLive: + self.liveHandler.blank() + def unblank(self, message): + name, isLive, item = self.decode_message(message) + if name != u'presentation': + return + if isLive: + self.liveHandler.unblank() + def timeout(self): self.liveHandler.poll() + diff --git a/openlp/plugins/presentations/lib/presentationcontroller.py b/openlp/plugins/presentations/lib/presentationcontroller.py index 389744b0b..760e861f8 100644 --- a/openlp/plugins/presentations/lib/presentationcontroller.py +++ b/openlp/plugins/presentations/lib/presentationcontroller.py @@ -361,7 +361,7 @@ class PresentationDocument(object): prefix = u'live' else: prefix = u'preview' - Receiver.send_message(u'%s_slidecontroller_change' % prefix, + Receiver.send_message(u'slidecontroller_%s_change' % prefix, self.slidenumber - 1) def get_slide_text(self, slide_no): diff --git a/openlp/plugins/presentations/presentationplugin.py b/openlp/plugins/presentations/presentationplugin.py index 00a83fe4b..ddf096b07 100644 --- a/openlp/plugins/presentations/presentationplugin.py +++ b/openlp/plugins/presentations/presentationplugin.py @@ -53,15 +53,10 @@ class PresentationPlugin(Plugin): log.info(u'Presentations Initialising') Plugin.initialise(self) self.insert_toolbox_item() - presentation_types = [] for controller in self.controllers: if self.controllers[controller].enabled: - presentation_types.append({u'%s' % controller : self.controllers[controller].supports}) self.controllers[controller].start_process() - Receiver.send_message( - u'presentation types', presentation_types) - def finalise(self): log.info(u'Plugin Finalise') #Ask each controller to tidy up diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index b2b1b14c4..176e3c2f6 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -93,7 +93,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): QtCore.QObject.connect(self.CCLNumberEdit, QtCore.SIGNAL(u'lostFocus()'), self.onCCLNumberEditLostFocus) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'update_themes'), self.loadThemes) + QtCore.SIGNAL(u'theme_update_list'), self.loadThemes) QtCore.QObject.connect(self.CommentsEdit, QtCore.SIGNAL(u'lostFocus()'), self.onCommentsEditLostFocus) QtCore.QObject.connect(self.VerseOrderEdit, @@ -464,16 +464,16 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): log.debug(u'onPreview') if button.text() == unicode(self.trUtf8('Save && Preview')) \ and self.saveSong(): - Receiver.send_message(u'preview_song') + Receiver.send_message(u'songs_preview') def closePressed(self): - Receiver.send_message(u'remote_edit_clear') + Receiver.send_message(u'servicemanager_edit_clear') self.close() def accept(self): log.debug(u'accept') if self.saveSong(): - Receiver.send_message(u'load_song_list') + Receiver.send_message(u'songs_load_list') self.close() def saveSong(self): diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 4ed56d06b..3825a4abf 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -27,4 +27,5 @@ from manager import SongManager from songstab import SongsTab from mediaitem import SongMediaItem from sofimport import SofImport +from oooimport import OooImport from songimport import SongImport diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index ad63cd783..fabf1cc64 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -122,15 +122,15 @@ class SongMediaItem(MediaManagerItem): QtCore.SIGNAL(u'textChanged(const QString&)'), self.onSearchTextEditChanged) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'load_song_list'), self.onSearchTextButtonClick) + QtCore.SIGNAL(u'songs_load_list'), self.onSearchTextButtonClick) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_updated'), self.configUpdated) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'preview_song'), self.onPreviewClick) + QtCore.SIGNAL(u'songs_preview'), self.onPreviewClick) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'%s_edit' % self.parent.name), self.onRemoteEdit) + QtCore.SIGNAL(u'songs_edit'), self.onRemoteEdit) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'remote_edit_clear'), self.onRemoteEditClear) + QtCore.SIGNAL(u'servicemanager_edit_clear'), self.onRemoteEditClear) def configUpdated(self): self.searchAsYouType = str_to_bool( @@ -306,6 +306,7 @@ class SongMediaItem(MediaManagerItem): item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0] service_item.add_capability(ItemCapabilities.AllowsEdit) service_item.add_capability(ItemCapabilities.AllowsPreview) + service_item.add_capability(ItemCapabilities.AllowsLoop) song = self.parent.songmanager.get_song(item_id) service_item.theme = song.theme_name service_item.editId = item_id @@ -361,4 +362,4 @@ class SongMediaItem(MediaManagerItem): service_item.audit = [ song.title, author_audit, song.copyright, song.ccli_number ] - return True \ No newline at end of file + return True diff --git a/openlp/plugins/songs/lib/oooimport.py b/openlp/plugins/songs/lib/oooimport.py new file mode 100644 index 000000000..403738973 --- /dev/null +++ b/openlp/plugins/songs/lib/oooimport.py @@ -0,0 +1,197 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2010 Raoul Snyman # +# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael # +# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin # +# Thompson, Jon Tibble, Carsten Tinggaard # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### + +import os +from PyQt4 import QtCore +from songimport import SongImport + +if os.name == u'nt': + from win32com.client import Dispatch + PAGE_BEFORE = 4 + PAGE_AFTER = 5 + PAGE_BOTH = 6 +else: + try: + import uno + from com.sun.star.style.BreakType import PAGE_BEFORE, PAGE_AFTER, PAGE_BOTH + except: + pass +class OooImport(object): + """ + Import songs from Impress/Powerpoint docs using Impress + """ + def __init__(self, songmanager): + """ + Initialise the class. Requires a songmanager class which is passed + to SongImport for writing song to disk + """ + self.song = None + self.manager = songmanager + self.document = None + self.process_started = False + + def import_docs(self, filenames): + self.start_ooo() + for filename in filenames: + filename = unicode(filename) + if os.path.isfile(filename): + self.open_ooo_file(filename) + if self.document: + if self.document.supportsService( + "com.sun.star.presentation.PresentationDocument"): + self.process_pres() + if self.document.supportsService( + "com.sun.star.text.TextDocument"): + self.process_doc() + self.close_ooo_file() + self.close_ooo() + + def start_ooo(self): + """ + Start OpenOffice.org process + TODO: The presentation/Impress plugin may already have it running + """ + if os.name == u'nt': + self.start_ooo_process() + self.desktop = self.manager.createInstance(u'com.sun.star.frame.Desktop') + else: + context = uno.getComponentContext() + resolver = context.ServiceManager.createInstanceWithContext( + u'com.sun.star.bridge.UnoUrlResolver', context) + ctx = None + loop = 0 + while ctx is None and loop < 5: + try: + ctx = resolver.resolve(u'uno:socket,host=localhost,' \ + + 'port=2002;urp;StarOffice.ComponentContext') + except: + pass + self.start_ooo_process() + loop += 1 + manager = ctx.ServiceManager + self.desktop = manager.createInstanceWithContext( + "com.sun.star.frame.Desktop", ctx ) + + def start_ooo_process(self): + try: + if os.name == u'nt': + self.manager = Dispatch(u'com.sun.star.ServiceManager') + self.manager._FlagAsMethod(u'Bridge_GetStruct') + self.manager._FlagAsMethod(u'Bridge_GetValueObject') + else: + cmd = u'openoffice.org -nologo -norestore -minimized -invisible ' \ + + u'-nofirststartwizard ' \ + + '-accept="socket,host=localhost,port=2002;urp;"' + process = QtCore.QProcess() + process.startDetached(cmd) + process.waitForStarted() + self.process_started = True + except: + pass + + def open_ooo_file(self, filepath): + """ + Open the passed file in OpenOffice.org Impress + """ + if os.name == u'nt': + url = u'file:///' + filepath.replace(u'\\', u'/') + url = url.replace(u':', u'|').replace(u' ', u'%20') + else: + url = uno.systemPathToFileUrl(filepath) + properties = [] + properties = tuple(properties) + try: + self.document = self.desktop.loadComponentFromURL(url, u'_blank', + 0, properties) + if not self.document.supportsService( + "com.sun.star.presentation.PresentationDocument") \ + and not self.document.supportsService( + "com.sun.star.text.TextDocument"): + self.close_ooo_file() + except: + pass + return + + def close_ooo_file(self): + """ + Close file. + """ + self.document.close(True) + self.document = None + + def close_ooo(self): + """ + Close OOo. But only if we started it and not on windows + """ + if self.process_started: + self.desktop.terminate() + + def process_pres(self): + """ + Process the file + """ + doc = self.document + slides = doc.getDrawPages() + text = u'' + for slide_no in range(slides.getCount()): + slide = slides.getByIndex(slide_no) + slidetext = u'' + for idx in range(slide.getCount()): + shape = slide.getByIndex(idx) + if shape.supportsService("com.sun.star.drawing.Text"): + if shape.getString().strip() != u'': + slidetext += shape.getString().strip() + u'\n\n' + if slidetext.strip() == u'': + slidetext = u'\f' + text += slidetext + song = SongImport(self.manager) + songs = SongImport.process_songs_text(self.manager, text) + for song in songs: + song.finish() + return + + def process_doc(self): + """ + Process the doc file, a paragraph at a time + """ + text = u'' + paragraphs = self.document.getText().createEnumeration() + while paragraphs.hasMoreElements(): + paratext = u'' + paragraph = paragraphs.nextElement() + if paragraph.supportsService("com.sun.star.text.Paragraph"): + textportions = paragraph.createEnumeration() + while textportions.hasMoreElements(): + textportion = textportions.nextElement() + if textportion.BreakType in (PAGE_BEFORE, PAGE_BOTH): + paratext += u'\f' + paratext += textportion.getString() + if textportion.BreakType in (PAGE_AFTER, PAGE_BOTH): + paratext += u'\f' + text += paratext + u'\n' + songs = SongImport.process_songs_text(self.manager, text) + for song in songs: + song.finish() + diff --git a/openlp/plugins/songs/lib/sofimport.py b/openlp/plugins/songs/lib/sofimport.py index ed5bb095d..48139931b 100644 --- a/openlp/plugins/songs/lib/sofimport.py +++ b/openlp/plugins/songs/lib/sofimport.py @@ -24,23 +24,24 @@ ############################################################################### # OOo API documentation: -# http://wiki.services.openoffice.org/wiki/Documentation/BASIC_Guide/Structure_of_Text_Documents +# http://wiki.services.openoffice.org/wiki/Documentation/BASIC_Guide/Structure_of_Text_Documents # http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/Text/Iterating_over_Text # http://www.oooforum.org/forum/viewtopic.phtml?t=14409 # http://wiki.services.openoffice.org/wiki/Python import re import os -import time +import time from PyQt4 import QtCore -from songimport import SongImport - +from songimport import SongImport +from oooimport import OooImport + if os.name == u'nt': from win32com.client import Dispatch BOLD = 150.0 - ITALIC = 2 - PAGE_BEFORE = 4 - PAGE_AFTER = 5 + ITALIC = 2 + PAGE_BEFORE = 4 + PAGE_AFTER = 5 PAGE_BOTH = 6 else: import uno @@ -48,7 +49,7 @@ else: from com.sun.star.awt.FontSlant import ITALIC from com.sun.star.style.BreakType import PAGE_BEFORE, PAGE_AFTER, PAGE_BOTH -class SofImport(object): +class SofImport(OooImport): """ Import songs provided on disks with the Songs of Fellowship music books VOLS1_2.RTF, sof3words.rtf and sof4words.rtf @@ -69,95 +70,28 @@ class SofImport(object): Initialise the class. Requires a songmanager class which is passed to SongImport for writing song to disk """ - self.song = None - self.manager = songmanager - self.process_started = False + OooImport.__init__(self,songmanager) def import_sof(self, filename): self.start_ooo() self.open_ooo_file(filename) - self.process_doc() + self.process_sof_file() + self.close_ooo_file() self.close_ooo() - def start_ooo(self): - """ - Start OpenOffice.org process - TODO: The presentation/Impress plugin may already have it running - """ - if os.name == u'nt': - self.start_ooo_process() - self.desktop = self.manager.createInstance(u'com.sun.star.frame.Desktop') - else: - context = uno.getComponentContext() - resolver = context.ServiceManager.createInstanceWithContext( - u'com.sun.star.bridge.UnoUrlResolver', context) - ctx = None - loop = 0 - while ctx is None and loop < 5: - try: - ctx = resolver.resolve(u'uno:socket,host=localhost,' \ - + 'port=2002;urp;StarOffice.ComponentContext') - except: - pass - self.start_ooo_process() - loop += 1 - manager = ctx.ServiceManager - self.desktop = manager.createInstanceWithContext( - "com.sun.star.frame.Desktop", ctx ) - - def start_ooo_process(self): - try: - if os.name == u'nt': - self.manager = Dispatch(u'com.sun.star.ServiceManager') - self.manager._FlagAsMethod(u'Bridge_GetStruct') - self.manager._FlagAsMethod(u'Bridge_GetValueObject') - else: - cmd = u'openoffice.org -nologo -norestore -minimized -invisible ' \ - + u'-nofirststartwizard ' \ - + '-accept="socket,host=localhost,port=2002;urp;"' - process = QtCore.QProcess() - process.startDetached(cmd) - process.waitForStarted() - self.process_started = True - except: - pass - - def open_ooo_file(self, filepath): - """ - Open the passed file in OpenOffice.org Writer - """ - if os.name == u'nt': - url = u'file:///' + filepath.replace(u'\\', u'/') - url = url.replace(u':', u'|').replace(u' ', u'%20') - else: - url = uno.systemPathToFileUrl(filepath) - properties = [] - properties = tuple(properties) - self.document = self.desktop.loadComponentFromURL(url, u'_blank', - 0, properties) - - def close_ooo(self): - """ - Close RTF file. Note, on Windows we'll leave OOo running - Leave running on Windows - """ - self.document.close(True) - if self.process_started: - self.desktop.terminate() - - def process_doc(self): + def process_sof_file(self): """ Process the RTF file, a paragraph at a time - """ + """ self.blanklines = 0 - self.new_song() + self.new_song() paragraphs = self.document.getText().createEnumeration() while paragraphs.hasMoreElements(): paragraph = paragraphs.nextElement() if paragraph.supportsService("com.sun.star.text.Paragraph"): - self.process_paragraph(paragraph) - if self.song: - self.song.finish() + self.process_paragraph(paragraph) + if self.song: + self.song.finish() self.song = None def process_paragraph(self, paragraph): @@ -171,71 +105,71 @@ class SofImport(object): In later books, there may not be line breaks, so check for 3 or more newlines """ - text = u'' - textportions = paragraph.createEnumeration() - while textportions.hasMoreElements(): - textportion = textportions.nextElement() - if textportion.BreakType in (PAGE_BEFORE, PAGE_BOTH): - self.process_paragraph_text(text) - self.new_song() - text = u'' + text = u'' + textportions = paragraph.createEnumeration() + while textportions.hasMoreElements(): + textportion = textportions.nextElement() + if textportion.BreakType in (PAGE_BEFORE, PAGE_BOTH): + self.process_paragraph_text(text) + self.new_song() + text = u'' text += self.process_textportion(textportion) - if textportion.BreakType in (PAGE_AFTER, PAGE_BOTH): - self.process_paragraph_text(text) - self.new_song() - text = u'' - self.process_paragraph_text(text) - + if textportion.BreakType in (PAGE_AFTER, PAGE_BOTH): + self.process_paragraph_text(text) + self.new_song() + text = u'' + self.process_paragraph_text(text) + def process_paragraph_text(self, text): """ Split the paragraph text into multiple lines and process - """ - for line in text.split(u'\n'): - self.process_paragraph_line(line) - if self.blanklines > 2: - self.new_song() - + """ + for line in text.split(u'\n'): + self.process_paragraph_line(line) + if self.blanklines > 2: + self.new_song() + def process_paragraph_line(self, text): """ Process a single line. Throw away that text which isn't relevant, i.e. stuff that appears at the end of the song. Anything that is OK, append to the current verse - """ - text = text.strip() - if text == u'': - self.blanklines += 1 - if self.blanklines > 1: - return - if self.song.get_title() != u'': - self.finish_verse() - return - self.blanklines = 0 - if self.skip_to_close_bracket: - if text.endswith(u')'): - self.skip_to_close_bracket = False - return + """ + text = text.strip() + if text == u'': + self.blanklines += 1 + if self.blanklines > 1: + return + if self.song.get_title() != u'': + self.finish_verse() + return + self.blanklines = 0 + if self.skip_to_close_bracket: + if text.endswith(u')'): + self.skip_to_close_bracket = False + return if text.startswith(u'CCL Licence'): - self.italics = False - return - if text == u'A Songs of Fellowship Worship Resource': - return + self.italics = False + return + if text == u'A Songs of Fellowship Worship Resource': + return if text.startswith(u'(NB.') or text.startswith(u'(Regrettably') \ - or text.startswith(u'(From'): - self.skip_to_close_bracket = True - return - if text.startswith(u'Copyright'): - self.song.add_copyright(text) - return - if text == u'(Repeat)': - self.finish_verse() - self.song.repeat_verse() - return + or text.startswith(u'(From'): + self.skip_to_close_bracket = True + return + if text.startswith(u'Copyright'): + self.song.add_copyright(text) + return + if text == u'(Repeat)': + self.finish_verse() + self.song.repeat_verse() + return if self.song.get_title() == u'': - if self.song.get_copyright() == u'': - self.add_author(text) - else: - self.song.add_copyright(text) - return + if self.song.get_copyright() == u'': + self.add_author(text) + else: + self.song.add_copyright(text) + return self.add_verse_line(text) def process_textportion(self, textportion): @@ -244,157 +178,132 @@ class SofImport(object): it's bold or italics. If it's bold then its a song number or song title. Song titles are in all capitals, so we must bring the capitalization into line - """ + """ text = textportion.getString() - text = self.tidy_text(text) + text = SongImport.tidy_text(text) if text.strip() == u'': - return text - if textportion.CharWeight == BOLD: - boldtext = text.strip() - if boldtext.isdigit() and self.song.get_song_number() == '': - self.add_songnumber(boldtext) - return u'' + return text + if textportion.CharWeight == BOLD: + boldtext = text.strip() + if boldtext.isdigit() and self.song.get_song_number() == '': + self.add_songnumber(boldtext) + return u'' if self.song.get_title() == u'': - text = self.uncap_text(text) - self.add_title(text) + text = self.uncap_text(text) + self.add_title(text) return text if text.strip().startswith(u'('): - return text - self.italics = (textportion.CharPosture == ITALIC) - return text - + return text + self.italics = (textportion.CharPosture == ITALIC) + return text + def new_song(self): """ A change of song. Store the old, create a new ... but only if the last song was complete. If not, stick with it - """ - if self.song: - self.finish_verse() + """ + if self.song: + self.finish_verse() if not self.song.check_complete(): - return - self.song.finish() + return + self.song.finish() self.song = SongImport(self.manager) self.skip_to_close_bracket = False - self.is_chorus = False + self.is_chorus = False self.italics = False self.currentverse = u'' - + def add_songnumber(self, song_no): """ Add a song number, store as alternate title. Also use the song number to work out which songbook we're in - """ + """ self.song.set_song_number(song_no) - self.song.set_alternate_title(song_no + u'.') - if int(song_no) <= 640: - self.song.set_song_book(u'Songs of Fellowship 1', - u'Kingsway Publications') - elif int(song_no) <= 1150: - self.song.set_song_book(u'Songs of Fellowship 2', - u'Kingsway Publications') - elif int(song_no) <= 1690: - self.song.set_song_book(u'Songs of Fellowship 3', - u'Kingsway Publications') - else: - self.song.set_song_book(u'Songs of Fellowship 4', - u'Kingsway Publications') + self.song.set_alternate_title(song_no + u'.') + if int(song_no) <= 640: + self.song.set_song_book(u'Songs of Fellowship 1', + u'Kingsway Publications') + elif int(song_no) <= 1150: + self.song.set_song_book(u'Songs of Fellowship 2', + u'Kingsway Publications') + elif int(song_no) <= 1690: + self.song.set_song_book(u'Songs of Fellowship 3', + u'Kingsway Publications') + else: + self.song.set_song_book(u'Songs of Fellowship 4', + u'Kingsway Publications') def add_title(self, text): """ Add the title to the song. Strip some leading/trailing punctuation that we don't want in a title - """ - title = text.strip() - if title.startswith(u'\''): - title = title[1:] - if title.endswith(u','): - title = title[:-1] - self.song.set_title(title) - + """ + title = text.strip() + if title.startswith(u'\''): + title = title[1:] + if title.endswith(u','): + title = title[:-1] + self.song.set_title(title) + def add_author(self, text): """ Add the author. OpenLP stores them individually so split by 'and', '&' and comma. However need to check for "Mr and Mrs Smith" and turn it to "Mr Smith" and "Mrs Smith". - """ - text = text.replace(u' and ', u' & ') - for author in text.split(u','): - authors = author.split(u'&') - for i in range(len(authors)): - author2 = authors[i].strip() - if author2.find(u' ') == -1 and i < len(authors) - 1: - author2 = author2 + u' ' \ - + authors[i + 1].strip().split(u' ')[-1] - if author2.endswith(u'.'): - author2 = author2[:-1] - if author2: - self.song.add_author(author2) - + """ + text = text.replace(u' and ', u' & ') + self.song.parse_author(text) + def add_verse_line(self, text): """ Add a line to the current verse. If the formatting has changed and we're beyond the second line of first verse, then this indicates a change of verse. Italics are a chorus - """ - if self.italics != self.is_chorus and ((len(self.song.verses) > 0) or - (self.currentverse.count(u'\n') > 1)): - self.finish_verse() - if self.italics: - self.is_chorus = True - self.currentverse += text + u'\n' - + """ + if self.italics != self.is_chorus and ((len(self.song.verses) > 0) or + (self.currentverse.count(u'\n') > 1)): + self.finish_verse() + if self.italics: + self.is_chorus = True + self.currentverse += text + u'\n' + def finish_verse(self): """ Verse is finished, store it. Note in book 1+2, some songs are formatted incorrectly. Here we try and split songs with missing line breaks into the correct number of verses. - """ - if self.currentverse.strip() == u'': - return - if self.is_chorus: - versetag = u'C' - splitat = None - else: - versetag = u'V' - splitat = self.verse_splits(self.song.get_song_number()) - if splitat: - ln = 0 - verse = u'' - for line in self.currentverse.split(u'\n'): - ln += 1 - if line == u'' or ln > splitat: - self.song.add_verse(verse, versetag) - ln = 0 - if line: - verse = line + u'\n' - else: - verse = u'' - else: - verse += line + u'\n' - if verse: - self.song.add_verse(verse, versetag) - else: - self.song.add_verse(self.currentverse, versetag) - self.currentverse = u'' - self.is_chorus = False - - def tidy_text(self, text): """ - Get rid of some dodgy unicode and formatting characters we're not - interested in. Some can be converted to ascii. - """ - text = text.replace(u'\t', u' ') - text = text.replace(u'\r', u'\n') - text = text.replace(u'\u2018', u'\'') - text = text.replace(u'\u2019', u'\'') - text = text.replace(u'\u201c', u'"') - text = text.replace(u'\u201d', u'"') - text = text.replace(u'\u2026', u'...') - text = text.replace(u'\u2013', u'-') - text = text.replace(u'\u2014', u'-') - return text - + if self.currentverse.strip() == u'': + return + if self.is_chorus: + versetag = u'C' + splitat = None + else: + versetag = u'V' + splitat = self.verse_splits(self.song.get_song_number()) + if splitat: + ln = 0 + verse = u'' + for line in self.currentverse.split(u'\n'): + ln += 1 + if line == u'' or ln > splitat: + self.song.add_verse(verse, versetag) + ln = 0 + if line: + verse = line + u'\n' + else: + verse = u'' + else: + verse += line + u'\n' + if verse: + self.song.add_verse(verse, versetag) + else: + self.song.add_verse(self.currentverse, versetag) + self.currentverse = u'' + self.is_chorus = False + + def uncap_text(self, text): """ Words in the title are in all capitals, so we lowercase them. @@ -403,128 +312,128 @@ class SofImport(object): There is a complicated word "One", which is sometimes lower and sometimes upper depending on context. Never mind, keep it lower. - """ - textarr = re.split(u'(\W+)', text) - textarr[0] = textarr[0].capitalize() - for i in range(1, len(textarr)): - # Do not translate these. Fixed strings in SOF song file - if textarr[i] in (u'JESUS', u'CHRIST', u'KING', u'ALMIGHTY', - u'REDEEMER', u'SHEPHERD', u'SON', u'GOD', u'LORD', u'FATHER', - u'HOLY', u'SPIRIT', u'LAMB', u'YOU', u'YOUR', u'I', u'I\'VE', - u'I\'M', u'I\'LL', u'SAVIOUR', u'O', u'YOU\'RE', u'HE', u'HIS', - u'HIM', u'ZION', u'EMMANUEL', u'MAJESTY', u'JESUS\'', u'JIREH', - u'JUDAH', u'LION', u'LORD\'S', u'ABRAHAM', u'GOD\'S', - u'FATHER\'S', u'ELIJAH'): - textarr[i] = textarr[i].capitalize() - else: - textarr[i] = textarr[i].lower() - text = u''.join(textarr) - return text - - def verse_splits(self, song_number): - """ - Because someone at Kingsway forgot to check the 1+2 RTF file, - some verses were not formatted correctly. - """ - if song_number == 11: return 8 - if song_number == 18: return 5 - if song_number == 21: return 6 - if song_number == 23: return 4 - if song_number == 24: return 7 - if song_number == 27: return 4 - if song_number == 31: return 6 - if song_number == 49: return 4 - if song_number == 50: return 8 - if song_number == 70: return 4 - if song_number == 75: return 8 - if song_number == 79: return 6 - if song_number == 97: return 7 - if song_number == 107: return 4 - if song_number == 109: return 4 - if song_number == 133: return 4 - if song_number == 155: return 10 - if song_number == 156: return 8 - if song_number == 171: return 4 - if song_number == 188: return 7 - if song_number == 192: return 4 - if song_number == 208: return 8 - if song_number == 215: return 8 - if song_number == 220: return 4 - if song_number == 247: return 6 - if song_number == 248: return 6 - if song_number == 251: return 8 - if song_number == 295: return 8 - if song_number == 307: return 5 - if song_number == 314: return 6 - if song_number == 325: return 8 - if song_number == 386: return 6 - if song_number == 415: return 4 - if song_number == 426: return 4 - if song_number == 434: return 5 - if song_number == 437: return 4 - if song_number == 438: return 6 - if song_number == 456: return 8 - if song_number == 461: return 4 - if song_number == 469: return 4 - if song_number == 470: return 5 - if song_number == 476: return 6 - if song_number == 477: return 7 - if song_number == 480: return 8 - if song_number == 482: return 4 - if song_number == 512: return 4 - if song_number == 513: return 8 - if song_number == 518: return 5 - if song_number == 520: return 4 - if song_number == 523: return 6 - if song_number == 526: return 8 - if song_number == 527: return 4 - if song_number == 529: return 4 - if song_number == 537: return 4 - if song_number == 555: return 6 - if song_number == 581: return 4 - if song_number == 589: return 6 - if song_number == 590: return 4 - if song_number == 593: return 8 - if song_number == 596: return 4 - if song_number == 610: return 6 - if song_number == 611: return 6 - if song_number == 619: return 8 - if song_number == 645: return 5 - if song_number == 653: return 6 - if song_number == 683: return 7 - if song_number == 686: return 4 - if song_number == 697: return 8 - if song_number == 698: return 4 - if song_number == 704: return 6 - if song_number == 716: return 4 - if song_number == 717: return 6 - if song_number == 730: return 4 - if song_number == 731: return 8 - if song_number == 732: return 8 - if song_number == 738: return 4 - if song_number == 756: return 9 - if song_number == 815: return 6 - if song_number == 830: return 8 - if song_number == 831: return 4 - if song_number == 876: return 6 - if song_number == 877: return 6 - if song_number == 892: return 4 - if song_number == 894: return 6 - if song_number == 902: return 8 - if song_number == 905: return 8 - if song_number == 921: return 6 - if song_number == 940: return 7 - if song_number == 955: return 9 - if song_number == 968: return 8 - if song_number == 972: return 7 - if song_number == 974: return 4 - if song_number == 988: return 6 - if song_number == 991: return 5 - if song_number == 1002: return 8 - if song_number == 1024: return 8 - if song_number == 1044: return 9 - if song_number == 1088: return 6 - if song_number == 1117: return 6 - if song_number == 1119: return 7 - return None + """ + textarr = re.split(u'(\W+)', text) + textarr[0] = textarr[0].capitalize() + for i in range(1, len(textarr)): + # Do not translate these. Fixed strings in SOF song file + if textarr[i] in (u'JESUS', u'CHRIST', u'KING', u'ALMIGHTY', + u'REDEEMER', u'SHEPHERD', u'SON', u'GOD', u'LORD', u'FATHER', + u'HOLY', u'SPIRIT', u'LAMB', u'YOU', u'YOUR', u'I', u'I\'VE', + u'I\'M', u'I\'LL', u'SAVIOUR', u'O', u'YOU\'RE', u'HE', u'HIS', + u'HIM', u'ZION', u'EMMANUEL', u'MAJESTY', u'JESUS\'', u'JIREH', + u'JUDAH', u'LION', u'LORD\'S', u'ABRAHAM', u'GOD\'S', + u'FATHER\'S', u'ELIJAH'): + textarr[i] = textarr[i].capitalize() + else: + textarr[i] = textarr[i].lower() + text = u''.join(textarr) + return text + + def verse_splits(self, song_number): + """ + Because someone at Kingsway forgot to check the 1+2 RTF file, + some verses were not formatted correctly. + """ + if song_number == 11: return 8 + if song_number == 18: return 5 + if song_number == 21: return 6 + if song_number == 23: return 4 + if song_number == 24: return 7 + if song_number == 27: return 4 + if song_number == 31: return 6 + if song_number == 49: return 4 + if song_number == 50: return 8 + if song_number == 70: return 4 + if song_number == 75: return 8 + if song_number == 79: return 6 + if song_number == 97: return 7 + if song_number == 107: return 4 + if song_number == 109: return 4 + if song_number == 133: return 4 + if song_number == 155: return 10 + if song_number == 156: return 8 + if song_number == 171: return 4 + if song_number == 188: return 7 + if song_number == 192: return 4 + if song_number == 208: return 8 + if song_number == 215: return 8 + if song_number == 220: return 4 + if song_number == 247: return 6 + if song_number == 248: return 6 + if song_number == 251: return 8 + if song_number == 295: return 8 + if song_number == 307: return 5 + if song_number == 314: return 6 + if song_number == 325: return 8 + if song_number == 386: return 6 + if song_number == 415: return 4 + if song_number == 426: return 4 + if song_number == 434: return 5 + if song_number == 437: return 4 + if song_number == 438: return 6 + if song_number == 456: return 8 + if song_number == 461: return 4 + if song_number == 469: return 4 + if song_number == 470: return 5 + if song_number == 476: return 6 + if song_number == 477: return 7 + if song_number == 480: return 8 + if song_number == 482: return 4 + if song_number == 512: return 4 + if song_number == 513: return 8 + if song_number == 518: return 5 + if song_number == 520: return 4 + if song_number == 523: return 6 + if song_number == 526: return 8 + if song_number == 527: return 4 + if song_number == 529: return 4 + if song_number == 537: return 4 + if song_number == 555: return 6 + if song_number == 581: return 4 + if song_number == 589: return 6 + if song_number == 590: return 4 + if song_number == 593: return 8 + if song_number == 596: return 4 + if song_number == 610: return 6 + if song_number == 611: return 6 + if song_number == 619: return 8 + if song_number == 645: return 5 + if song_number == 653: return 6 + if song_number == 683: return 7 + if song_number == 686: return 4 + if song_number == 697: return 8 + if song_number == 698: return 4 + if song_number == 704: return 6 + if song_number == 716: return 4 + if song_number == 717: return 6 + if song_number == 730: return 4 + if song_number == 731: return 8 + if song_number == 732: return 8 + if song_number == 738: return 4 + if song_number == 756: return 9 + if song_number == 815: return 6 + if song_number == 830: return 8 + if song_number == 831: return 4 + if song_number == 876: return 6 + if song_number == 877: return 6 + if song_number == 892: return 4 + if song_number == 894: return 6 + if song_number == 902: return 8 + if song_number == 905: return 8 + if song_number == 921: return 6 + if song_number == 940: return 7 + if song_number == 955: return 9 + if song_number == 968: return 8 + if song_number == 972: return 7 + if song_number == 974: return 4 + if song_number == 988: return 6 + if song_number == 991: return 5 + if song_number == 1002: return 8 + if song_number == 1024: return 8 + if song_number == 1044: return 9 + if song_number == 1088: return 6 + if song_number == 1117: return 6 + if song_number == 1119: return 7 + return None diff --git a/openlp/plugins/songs/lib/songimport.py b/openlp/plugins/songs/lib/songimport.py index 6adfcad7f..cb780f987 100644 --- a/openlp/plugins/songs/lib/songimport.py +++ b/openlp/plugins/songs/lib/songimport.py @@ -24,9 +24,10 @@ ############################################################################### import string -from openlp.core.lib import SongXMLBuilder +from PyQt4 import QtGui, QtCore +from openlp.core.lib import SongXMLBuilder from openlp.plugins.songs.lib.models import Song, Author, Topic, Book - + class SongImport(object): """ Helper class for import a song from a third party source into OpenLP @@ -42,232 +43,328 @@ class SongImport(object): song_manager is an instance of a SongManager, through which all database access is performed - """ + """ self.manager = song_manager - self.title = u'' + self.title = u'' self.song_number = u'' self.alternate_title = u'' - self.copyright = u'' - self.comment = u'' - self.theme_name = u'' - self.ccli_number = u'' - self.authors = [] - self.topics = [] - self.song_book_name = u'' - self.song_book_pub = u'' - self.verse_order_list = [] - self.verses = [] - self.versecount = 0 - self.choruscount = 0 - + self.copyright = u'' + self.comment = u'' + self.theme_name = u'' + self.ccli_number = u'' + self.authors = [] + self.topics = [] + self.song_book_name = u'' + self.song_book_pub = u'' + self.verse_order_list = [] + self.verses = [] + self.versecount = 0 + self.choruscount = 0 + self.copyright_string = unicode(QtGui.QApplication.translate( \ + u'SongImport', u'copyright')) + self.copyright_symbol = unicode(QtGui.QApplication.translate( \ + u'SongImport', u'©')) + + @staticmethod + def process_songs_text(manager, text): + songs = [] + songtexts = SongImport.tidy_text(text).split(u'\f') + song = SongImport(manager) + for songtext in songtexts: + if songtext.strip(): + song.process_song_text(songtext.strip()) + if song.check_complete(): + songs.append(song) + song = SongImport(manager) + if song.check_complete(): + songs.append(song) + return songs + + @staticmethod + def tidy_text(text): + """ + Get rid of some dodgy unicode and formatting characters we're not + interested in. Some can be converted to ascii. + """ + text = text.replace(u'\t', u' ') + text = text.replace(u'\r\n', u'\n') + text = text.replace(u'\r', u'\n') + text = text.replace(u'\u2018', u'\'') + text = text.replace(u'\u2019', u'\'') + text = text.replace(u'\u201c', u'"') + text = text.replace(u'\u201d', u'"') + text = text.replace(u'\u2026', u'...') + text = text.replace(u'\u2013', u'-') + text = text.replace(u'\u2014', u'-') + # Remove surplus blank lines, spaces, trailing/leading spaces + while text.find(u' ') >= 0: + text = text.replace(u' ', u' ') + text = text.replace(u'\n ', u'\n') + text = text.replace(u' \n', u'\n') + text = text.replace(u'\n\n\n\n\n', u'\f') + text = text.replace(u'\f ', u'\f') + text = text.replace(u' \f', u'\f') + while text.find(u'\f\f') >= 0: + text = text.replace(u'\f\f', u'\f') + return text + + def process_song_text(self, text): + versetexts = text.split(u'\n\n') + for versetext in versetexts: + if versetext.strip() != u'': + self.process_verse_text(versetext.strip()) + + def process_verse_text(self, text): + lines = text.split(u'\n') + if text.lower().find(self.copyright_string) >= 0 \ + or text.lower().find(self.copyright_symbol) >= 0: + copyright_found = False + for line in lines: + if copyright_found or line.lower().find(self.copyright_string) >= 0\ + or line.lower().find(self.copyright_symbol) >= 0: + copyright_found = True + self.add_copyright(line) + else: + self.parse_author(line) + return + if len(lines) == 1: + self.parse_author(lines[0]) + return + if not self.get_title(): + self.set_title(lines[0]) + self.add_verse(text) + def get_title(self): """ Return the title - """ - return self.title - + """ + return self.title + def get_copyright(self): """ Return the copyright - """ - return self.copyright - + """ + return self.copyright + def get_song_number(self): """ Return the song number - """ - return self.song_number - + """ + return self.song_number + def set_title(self, title): """ Set the title - """ - self.title = title + """ + self.title = title def set_alternate_title(self, title): """ Set the alternate title - """ - self.alternate_title = title - + """ + self.alternate_title = title + def set_song_number(self, song_number): """ Set the song number - """ - self.song_number = song_number - + """ + self.song_number = song_number + def set_song_book(self, song_book, publisher): """ Set the song book name and publisher - """ - self.song_book_name = song_book - self.song_book_pub = publisher - + """ + self.song_book_name = song_book + self.song_book_pub = publisher + def add_copyright(self, copyright): """ Build the copyright field - """ - if self.copyright != u'': - self.copyright += ' ' - self.copyright += copyright - - def add_author(self, text): + """ + if self.copyright.find(copyright) >= 0: + return + if self.copyright != u'': + self.copyright += ' ' + self.copyright += copyright + + def parse_author(self, text): + """ + Add the author. OpenLP stores them individually so split by 'and', '&' + and comma. + However need to check for "Mr and Mrs Smith" and turn it to + "Mr Smith" and "Mrs Smith". + """ + for author in text.split(u','): + authors = author.split(u'&') + for i in range(len(authors)): + author2 = authors[i].strip() + if author2.find(u' ') == -1 and i < len(authors) - 1: + author2 = author2 + u' ' \ + + authors[i + 1].strip().split(u' ')[-1] + if author2.endswith(u'.'): + author2 = author2[:-1] + if author2: + self.add_author(author2) + + def add_author(self, author): """ Add an author to the list - """ - self.authors.append(text) - - def add_verse(self, verse, versetag): + """ + if author in self.authors: + return + self.authors.append(author) + + def add_verse(self, verse, versetag=None): """ Add a verse. This is the whole verse, lines split by \n Verse tag can be V1/C1/B etc, or 'V' and 'C' (will count the verses/ choruses itself) or None, where it will assume verse It will also attempt to detect duplicates. In this case it will just add to the verse order - """ - for (oldversetag, oldverse) in self.verses: - if oldverse.strip() == verse.strip(): - self.verse_order_list.append(oldversetag) + """ + for (oldversetag, oldverse) in self.verses: + if oldverse.strip() == verse.strip(): + self.verse_order_list.append(oldversetag) return - if versetag.startswith(u'C'): - self.choruscount += 1 - if versetag == u'C': - versetag += unicode(self.choruscount) - if versetag == u'V' or not versetag: - self.versecount += 1 - versetag = u'V' + unicode(self.versecount) - self.verses.append([versetag, verse.rstrip()]) - self.verse_order_list.append(versetag) - if versetag.startswith(u'V') and self.contains_verse(u'C1'): - self.verse_order_list.append(u'C1') - + if versetag == u'V' or not versetag: + self.versecount += 1 + versetag = u'V' + unicode(self.versecount) + if versetag.startswith(u'C'): + self.choruscount += 1 + if versetag == u'C': + versetag += unicode(self.choruscount) + self.verses.append([versetag, verse.rstrip()]) + self.verse_order_list.append(versetag) + if versetag.startswith(u'V') and self.contains_verse(u'C1'): + self.verse_order_list.append(u'C1') + def repeat_verse(self): """ Repeat the previous verse in the verse order - """ - self.verse_order_list.append(self.verse_order_list[-1]) + """ + self.verse_order_list.append(self.verse_order_list[-1]) def contains_verse(self, versetag): return versetag in self.verse_order_list - + def check_complete(self): """ Check the mandatory fields are entered (i.e. title and a verse) Author not checked here, if no author then "Author unknown" is automatically added - """ - if self.title == u'' or len(self.verses) == 0: - return False - else: - return True - + """ + if self.title == u'' or len(self.verses) == 0: + return False + else: + return True + def remove_punctuation(self, text): """ Remove punctuation from the string for searchable fields """ - for c in string.punctuation: + for c in string.punctuation: text = text.replace(c, u'') - return text - + return text + def finish(self): """ All fields have been set to this song. Write it away - """ - if len(self.authors) == 0: - self.authors.append(u'Author unknown') - self.commit_song() + """ + if len(self.authors) == 0: + self.authors.append(u'Author unknown') + self.commit_song() #self.print_song() - + def commit_song(self): """ Write the song and it's fields to disk - """ - song = Song() - song.title = self.title + """ + song = Song() + song.title = self.title song.search_title = self.remove_punctuation(self.title) \ - + '@' + self.alternate_title - song.song_number = self.song_number - song.search_lyrics = u'' - sxml = SongXMLBuilder() - sxml.new_document() - sxml.add_lyrics_to_song() - for (versetag, versetext) in self.verses: - if versetag[0] == u'C': - versetype = u'Chorus' - elif versetag[0] == u'V': - versetype = u'Verse' - elif versetag[0] == u'B': - versetype = u'Bridge' - elif versetag[0] == u'I': - versetype = u'Intro' - elif versetag[0] == u'P': - versetype = u'Prechorus' - elif versetag[0] == u'E': - versetype = u'Ending' - else: - versetype = u'Other' - sxml.add_verse_to_lyrics(versetype, versetag[1:], versetext) - song.search_lyrics += u' ' + self.remove_punctuation(versetext) - song.lyrics = unicode(sxml.extract_xml(), u'utf-8') - song.verse_order = u' '.join(self.verse_order_list) - song.copyright = self.copyright - song.comment = self.comment - song.theme_name = self.theme_name - song.ccli_number = self.ccli_number - for authortext in self.authors: - author = self.manager.get_author_by_name(authortext) - if author is None: - author = Author() - author.display_name = authortext - author.last_name = authortext.split(u' ')[-1] - author.first_name = u' '.join(authortext.split(u' ')[:-1]) - self.manager.save_author(author) - song.authors.append(author) - if self.song_book_name: - song_book = self.manager.get_book_by_name(self.song_book_name) - if song_book is None: - song_book = Book() - song_book.name = self.song_book_name - song_book.publisher = self.song_book_pub - self.manager.save_book(song_book) - song.song_book_id = song_book.id - for topictext in self.topics: - topic = self.manager.get_topic_by_name(topictext) - if topic is None: - topic = Topic() + + '@' + self.alternate_title + song.song_number = self.song_number + song.search_lyrics = u'' + sxml = SongXMLBuilder() + sxml.new_document() + sxml.add_lyrics_to_song() + for (versetag, versetext) in self.verses: + if versetag[0] == u'C': + versetype = u'Chorus' + elif versetag[0] == u'V': + versetype = u'Verse' + elif versetag[0] == u'B': + versetype = u'Bridge' + elif versetag[0] == u'I': + versetype = u'Intro' + elif versetag[0] == u'P': + versetype = u'Prechorus' + elif versetag[0] == u'E': + versetype = u'Ending' + else: + versetype = u'Other' + sxml.add_verse_to_lyrics(versetype, versetag[1:], versetext) + song.search_lyrics += u' ' + self.remove_punctuation(versetext) + song.lyrics = unicode(sxml.extract_xml(), u'utf-8') + song.verse_order = u' '.join(self.verse_order_list) + song.copyright = self.copyright + song.comment = self.comment + song.theme_name = self.theme_name + song.ccli_number = self.ccli_number + for authortext in self.authors: + author = self.manager.get_author_by_name(authortext) + if author is None: + author = Author() + author.display_name = authortext + author.last_name = authortext.split(u' ')[-1] + author.first_name = u' '.join(authortext.split(u' ')[:-1]) + self.manager.save_author(author) + song.authors.append(author) + if self.song_book_name: + song_book = self.manager.get_book_by_name(self.song_book_name) + if song_book is None: + song_book = Book() + song_book.name = self.song_book_name + song_book.publisher = self.song_book_pub + self.manager.save_book(song_book) + song.song_book_id = song_book.id + for topictext in self.topics: + topic = self.manager.get_topic_by_name(topictext) + if topic is None: + topic = Topic() topic.name = topictext - self.manager.save_topic(topic) + self.manager.save_topic(topic) song.topics.append(topictext) - self.manager.save_song(song) - - def print_song(self): - """ - For debugging - """ - print u'========================================' \ - + u'========================================' - print u'TITLE: ' + self.title - print u'ALT TITLE: ' + self.alternate_title - for (versetag, versetext) in self.verses: - print u'VERSE ' + versetag + u': ' + versetext - print u'ORDER: ' + u' '.join(self.verse_order_list) - for author in self.authors: - print u'AUTHOR: ' + author - if self.copyright: - print u'COPYRIGHT: ' + self.copyright - if self.song_book_name: - print u'BOOK: ' + self.song_book_name - if self.song_book_pub: - print u'BOOK PUBLISHER: ' + self.song_book_pub - if self.song_number: - print u'NUMBER: ' + self.song_number - for topictext in self.topics: - print u'TOPIC: ' + topictext - if self.comment: - print u'COMMENT: ' + self.comment - if self.theme_name: - print u'THEME: ' + self.theme_name - if self.ccli_number: - print u'CCLI: ' + self.ccli_number - + self.manager.save_song(song) + + def print_song(self): + """ + For debugging + """ + print u'========================================' \ + + u'========================================' + print u'TITLE: ' + self.title + print u'ALT TITLE: ' + self.alternate_title + for (versetag, versetext) in self.verses: + print u'VERSE ' + versetag + u': ' + versetext + print u'ORDER: ' + u' '.join(self.verse_order_list) + for author in self.authors: + print u'AUTHOR: ' + author + if self.copyright: + print u'COPYRIGHT: ' + self.copyright + if self.song_book_name: + print u'BOOK: ' + self.song_book_name + if self.song_book_pub: + print u'BOOK PUBLISHER: ' + self.song_book_pub + if self.song_number: + print u'NUMBER: ' + self.song_number + for topictext in self.topics: + print u'TOPIC: ' + topictext + if self.comment: + print u'COMMENT: ' + self.comment + if self.theme_name: + print u'THEME: ' + self.theme_name + if self.ccli_number: + print u'CCLI: ' + self.ccli_number + diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index 2155e3c16..54ea6a352 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -29,7 +29,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import Plugin, build_icon, PluginStatus, Receiver from openlp.plugins.songs.lib import SongManager, SongMediaItem, SongsTab, \ - SofImport + SofImport, OooImport from openlp.plugins.songs.forms import OpenLPImportForm, OpenSongExportForm, \ OpenSongImportForm, OpenLPExportForm @@ -105,11 +105,14 @@ class SongsPlugin(Plugin): self.ImportOpenlp2Item.setObjectName(u'ImportOpenlp2Item') self.ImportSofItem = QtGui.QAction(import_menu) self.ImportSofItem.setObjectName(u'ImportSofItem') + self.ImportOooItem = QtGui.QAction(import_menu) + self.ImportOooItem.setObjectName(u'ImportOooItem') # Add to menus self.ImportSongMenu.addAction(self.ImportOpenlp1Item) self.ImportSongMenu.addAction(self.ImportOpenlp2Item) self.ImportSongMenu.addAction(self.ImportOpenSongItem) self.ImportSongMenu.addAction(self.ImportSofItem) + self.ImportSongMenu.addAction(self.ImportOooItem) import_menu.addAction(self.ImportSongMenu.menuAction()) # Translations... self.ImportSongMenu.setTitle(import_menu.trUtf8('&Song')) @@ -132,6 +135,12 @@ class SongsPlugin(Plugin): self.ImportSofItem.setStatusTip( import_menu.trUtf8('Import songs from the VOLS1_2.RTF, sof3words' \ + '.rtf and sof4words.rtf supplied with the music books')) + self.ImportOooItem.setText( + import_menu.trUtf8('Generic Document/Presentation Import')) + self.ImportOooItem.setToolTip( + import_menu.trUtf8('Import songs from Word/Writer/Powerpoint/Impress')) + self.ImportOooItem.setStatusTip( + import_menu.trUtf8('Import songs from Word/Writer/Powerpoint/Impress')) # Signals and slots QtCore.QObject.connect(self.ImportOpenlp1Item, QtCore.SIGNAL(u'triggered()'), self.onImportOpenlp1ItemClick) @@ -141,6 +150,8 @@ class SongsPlugin(Plugin): QtCore.SIGNAL(u'triggered()'), self.onImportOpenSongItemClick) QtCore.QObject.connect(self.ImportSofItem, QtCore.SIGNAL(u'triggered()'), self.onImportSofItemClick) + QtCore.QObject.connect(self.ImportOooItem, + QtCore.SIGNAL(u'triggered()'), self.onImportOooItemClick) self.ImportSongMenu.menuAction().setVisible(False) def add_export_menu_item(self, export_menu): @@ -184,12 +195,13 @@ class SongsPlugin(Plugin): self.opensong_import_form.show() def onImportSofItemClick(self): - filename = QtGui.QFileDialog.getOpenFileName( + filenames = QtGui.QFileDialog.getOpenFileNames( None, self.trUtf8('Open Songs of Fellowship file'), u'', u'Songs of Fellowship file (*.rtf *.RTF)') try: - sofimport = SofImport(self.songmanager) - sofimport.import_sof(unicode(filename)) + for filename in filenames: + sofimport = SofImport(self.songmanager) + sofimport.import_sof(unicode(filename)) except: log.exception('Could not import SoF file') QtGui.QMessageBox.critical(None, @@ -200,7 +212,15 @@ class SongsPlugin(Plugin): + ' included with the Songs of Fellowship Music Editions'), QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok), QtGui.QMessageBox.Ok) - Receiver.send_message(u'load_song_list') + Receiver.send_message(u'songs_load_list') + + def onImportOooItemClick(self): + filenames = QtGui.QFileDialog.getOpenFileNames( + None, self.trUtf8('Open documents or presentations'), + u'', u'All Files(*.*)') + oooimport = OooImport(self.songmanager) + oooimport.import_docs(filenames) + Receiver.send_message(u'songs_load_list') def onExportOpenlp1ItemClicked(self): self.openlp_export_form.show() diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index 0763e0675..c4a255d06 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -107,7 +107,7 @@ class SongUsagePlugin(Plugin): log.info(u'SongUsage Initialising') Plugin.initialise(self) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'songusage_live'), self.onReceiveSongUsage) + QtCore.SIGNAL(u'slidecontroller_start'), self.onReceiveSongUsage) self.SongUsageActive = str_to_bool( self.config.get_config(u'active', False)) self.SongUsageStatus.setChecked(self.SongUsageActive) @@ -127,21 +127,23 @@ class SongUsagePlugin(Plugin): self.SongUsageActive = not self.SongUsageActive self.config.set_config(u'active', self.SongUsageActive) - def onReceiveSongUsage(self, SongUsageData): + def onReceiveSongUsage(self, items): """ SongUsage a live song from SlideController """ - if self.SongUsageActive: - SongUsageitem = SongUsageItem() - SongUsageitem.usagedate = datetime.today() - SongUsageitem.usagetime = datetime.now().time() - SongUsageitem.title = SongUsageData[0] - SongUsageitem.copyright = SongUsageData[2] - SongUsageitem.ccl_number = SongUsageData[3] - SongUsageitem.authors = u'' - for author in SongUsageData[1]: - SongUsageitem.authors += author + u' ' - self.songusagemanager.insert_songusage(SongUsageitem) + audit = items[0].audit + live = items[1] + if self.SongUsageActive and audit and live: + song_usage_item = SongUsageItem() + song_usage_item.usagedate = datetime.today() + song_usage_item.usagetime = datetime.now().time() + song_usage_item.title = audit[0] + song_usage_item.copyright = audit[2] + song_usage_item.ccl_number = audit[3] + song_usage_item.authors = u'' + for author in audit[1]: + song_usage_item.authors += author + u' ' + self.songusagemanager.insert_songusage(song_usage_item) def onSongUsageDelete(self): self.SongUsagedeleteform.exec_() diff --git a/resources/forms/editcustomdialog.ui b/resources/forms/editcustomdialog.ui index 98bc1abb0..44ce46ca7 100644 --- a/resources/forms/editcustomdialog.ui +++ b/resources/forms/editcustomdialog.ui @@ -46,7 +46,7 @@ - + @@ -73,7 +73,7 @@ - + @@ -106,7 +106,7 @@ - + Add New @@ -136,7 +136,7 @@ - + Save @@ -163,6 +163,16 @@ + + + + + + + Split Slide + + + @@ -216,8 +226,11 @@ + + + - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + QDialogButtonBox::Cancel|QDialogButtonBox::Save @@ -236,12 +249,44 @@ UpButton DownButton ThemeComboBox - buttonBox - + + + buttonBox + accepted() + customEditDialog + accept() + + + 294 + 524 + + + 294 + 270 + + + + + buttonBox + rejected() + customEditDialog + close() + + + 294 + 524 + + + 294 + 270 + + + + accept() rejected() diff --git a/scripts/openlp-1to2-converter.py b/scripts/openlp-1to2-converter.py index 3b805a1bd..8645fc2a4 100755 --- a/scripts/openlp-1to2-converter.py +++ b/scripts/openlp-1to2-converter.py @@ -58,6 +58,7 @@ create_statements = [ id INTEGER NOT NULL, song_book_id INTEGER, title VARCHAR(255) NOT NULL, + alternate_title VARCHAR(255), lyrics TEXT NOT NULL, verse_order VARCHAR(128), copyright VARCHAR(255), @@ -183,16 +184,18 @@ def import_songs(): xml_verse_template = u'' for row in rows: clean_title = unicode(row[1], u'cp1252') - clean_lyrics = unicode(row[2], u'cp1252') + clean_lyrics = unicode(row[2], u'cp1252').replace(u'\r\n', u'\n') clean_copyright = unicode(row[3], u'cp1252') verse_order = u'' text_lyrics = clean_lyrics.split(u'\n\n') xml_verse = u'' + verses = [] for line, verse in enumerate(text_lyrics): if not verse: continue xml_verse += (xml_verse_template % (line + 1, verse)) - verse_order += '%d ' % (line + 1) + verses.append(u'V%d' % (line + 1)) + verse_order = u' '.join(verses) xml_lyrics = xml_lyrics_template % xml_verse search_title = prepare_string(clean_title) search_lyrics = prepare_string(clean_lyrics) diff --git a/openlp/plugins/remotes/remoteclient.py b/scripts/openlp-remoteclient.py similarity index 98% rename from openlp/plugins/remotes/remoteclient.py rename to scripts/openlp-remoteclient.py index 5939b9f26..de3099920 100755 --- a/openlp/plugins/remotes/remoteclient.py +++ b/scripts/openlp-remoteclient.py @@ -38,7 +38,7 @@ def sendData(options, message): print u'Errow thrown ', sys.exc_info()[1] def format_message(options): - return u'%s:%s' % (options.event, options.message) + return u'%s:%s' % (u'alert', options.message) def main(): usage = "usage: %prog [options] arg1 arg2" diff --git a/setup.py b/setup.py index 436c5a987..f2e6911fa 100755 --- a/setup.py +++ b/setup.py @@ -68,7 +68,8 @@ OpenLP (previously openlp.org) is free church presentation software, or lyrics p url='http://openlp.org/', license='GNU General Public License', packages=find_packages(exclude=['ez_setup', 'examples', 'tests']), - scripts=['openlp.pyw', 'scripts/openlp-1to2-converter.py', 'scripts/bible-1to2-converter.py'], + scripts=['openlp.pyw', 'scripts/openlp-1to2-converter.py', + 'scripts/bible-1to2-converter.py','scripts/openlp-remoteclient.py'], include_package_data=True, zip_safe=False, install_requires=[