diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 560450741..52ebe99c8 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -313,7 +313,7 @@ def expand_tags(text): from spelltextedit import SpellTextEdit from eventreceiver import Receiver from settingsmanager import SettingsManager -from plugin import PluginStatus, Plugin +from plugin import PluginStatus, StringContent, Plugin from pluginmanager import PluginManager from settingstab import SettingsTab from serviceitem import ServiceItem diff --git a/openlp/core/lib/eventreceiver.py b/openlp/core/lib/eventreceiver.py index a4f683e81..1080cd2f5 100644 --- a/openlp/core/lib/eventreceiver.py +++ b/openlp/core/lib/eventreceiver.py @@ -75,7 +75,7 @@ class EventReceiver(QtCore.QObject): Broadcasts that an item has been made live/previewed ``slidecontroller_{live|preview}_change`` - Informs the slidecontroller that a slide change has occurred and to + Informs the slidecontroller that a slide change has occurred and to update itself ``slidecontroller_{live|preview}_changed`` @@ -83,7 +83,7 @@ class EventReceiver(QtCore.QObject): ``slidecontroller_{live|preview}_text_request`` Request the text for the current item in the controller - Returns a slidecontroller_{live|preview}_text_response with an + Returns a slidecontroller_{live|preview}_text_response with an array of dictionaries with the tag and verse text ``slidecontroller_{live|preview}_blank`` @@ -106,23 +106,23 @@ class EventReceiver(QtCore.QObject): ``servicemanager_set_item`` Go live on a specific item, by index - + ``servicemanager_list_request`` Request the service list. Responds with servicemanager_list_response containing a array of dictionaries ``maindisplay_blank`` - Blank the maindisplay window + Blank the maindisplay window ``maindisplay_hide`` - Hide the maindisplay window + Hide the maindisplay window ``maindisplay_show`` - Return the maindisplay window + Return the maindisplay window ``maindisplay_active`` The maindisplay has been made active - + ``maindisplay_status_text`` Changes the bottom status bar text on the maindisplay window @@ -193,9 +193,17 @@ class EventReceiver(QtCore.QObject): ``{plugin}_add_service_item`` Ask the plugin to push the selected items to the service item + ``{plugin}_service_load`` + Ask the plugin to process an individual service item after it has been + loaded + + ``service_item_update`` + Passes back to the service manager the service item after it has been + processed by the plugin + ``alerts_text`` Displays an alert message - + ``bibles_nobook`` Attempt to find book resulted in no match diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index 625a74842..3752ffc4d 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -32,7 +32,8 @@ import os from PyQt4 import QtCore, QtGui from openlp.core.lib import context_menu_action, context_menu_separator, \ - SettingsManager, OpenLPToolbar, ServiceItem, build_icon, translate + SettingsManager, OpenLPToolbar, ServiceItem, StringContent, build_icon, \ + translate, Receiver log = logging.getLogger(__name__) @@ -51,26 +52,19 @@ class MediaManagerItem(QtGui.QWidget): The parent widget. Usually this will be the *Media Manager* itself. This needs to be a class descended from ``QWidget``. + ``plugin`` + The plugin widget. Usually this will be the *Plugin* + itself. This needs to be a class descended from ``Plugin``. + ``icon`` Either a ``QIcon``, a resource path, or a file name. This is the icon which is displayed in the *Media Manager*. - ``title`` - The title visible on the item in the *Media Manager*. - **Member Variables** When creating a descendant class from this class for your plugin, the following member variables should be set. - ``self.PluginNameShort`` - The shortened (usually singular) name for the plugin e.g. *'Song'* - for the Songs plugin. - - ``self.pluginNameVisible`` - The user visible name for a plugin which should use a suitable - translation function. - ``self.OnNewPrompt`` Defaults to *'Select Image(s)'*. @@ -93,13 +87,17 @@ class MediaManagerItem(QtGui.QWidget): """ log.info(u'Media Item loaded') - def __init__(self, parent=None, icon=None, title=None): + def __init__(self, parent=None, plugin=None, icon=None): """ Constructor to create the media manager item. """ QtGui.QWidget.__init__(self) self.parent = parent - self.settingsSection = title.lower() + #TODO: plugin should not be the parent in future + self.plugin = parent # plugin + visible_title = self.plugin.getString(StringContent.VisibleName) + self.title = unicode(visible_title[u'title']) + self.settingsSection = self.plugin.name.lower() if isinstance(icon, QtGui.QIcon): self.icon = icon elif isinstance(icon, basestring): @@ -107,8 +105,6 @@ class MediaManagerItem(QtGui.QWidget): QtGui.QIcon.Normal, QtGui.QIcon.Off) else: self.icon = None - if title: - self.title = title self.toolbar = None self.remoteTriggered = None self.serviceItemIconName = None @@ -119,6 +115,9 @@ class MediaManagerItem(QtGui.QWidget): self.requiredIcons() self.setupUi() self.retranslateUi() + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'%s_service_load' % self.parent.name.lower()), + self.serviceLoad) def requiredIcons(self): """ @@ -208,64 +207,58 @@ class MediaManagerItem(QtGui.QWidget): """ ## Import Button ## if self.hasImportIcon: + import_string = self.plugin.getString(StringContent.Import) self.addToolbarButton( - unicode(translate('OpenLP.MediaManagerItem', 'Import %s')) % - self.PluginNameShort, - unicode(translate('OpenLP.MediaManagerItem', 'Import a %s')) % - self.pluginNameVisible, + import_string[u'title'], + import_string[u'tooltip'], u':/general/general_import.png', self.onImportClick) - ## File Button ## + ## Load Button ## if self.hasFileIcon: + load_string = self.plugin.getString(StringContent.Load) self.addToolbarButton( - unicode(translate('OpenLP.MediaManagerItem', 'Load %s')) % - self.PluginNameShort, - unicode(translate('OpenLP.MediaManagerItem', 'Load a new %s')) % - self.pluginNameVisible, + load_string[u'title'], + load_string[u'tooltip'], u':/general/general_open.png', self.onFileClick) ## New Button ## if self.hasNewIcon: + new_string = self.plugin.getString(StringContent.New) self.addToolbarButton( - unicode(translate('OpenLP.MediaManagerItem', 'New %s')) % - self.PluginNameShort, - unicode(translate('OpenLP.MediaManagerItem', 'Add a new %s')) % - self.pluginNameVisible, + new_string[u'title'], + new_string[u'tooltip'], u':/general/general_new.png', self.onNewClick) ## Edit Button ## if self.hasEditIcon: + edit_string = self.plugin.getString(StringContent.Edit) self.addToolbarButton( - unicode(translate('OpenLP.MediaManagerItem', 'Edit %s')) % - self.PluginNameShort, - unicode(translate( - 'OpenLP.MediaManagerItem', 'Edit the selected %s')) % - self.pluginNameVisible, + edit_string[u'title'], + edit_string[u'tooltip'], u':/general/general_edit.png', self.onEditClick) ## Delete Button ## if self.hasDeleteIcon: + delete_string = self.plugin.getString(StringContent.Delete) self.addToolbarButton( - unicode(translate('OpenLP.MediaManagerItem', 'Delete %s')) % - self.PluginNameShort, - translate('OpenLP.MediaManagerItem', - 'Delete the selected item'), + delete_string[u'title'], + delete_string[u'tooltip'], u':/general/general_delete.png', self.onDeleteClick) ## Separator Line ## self.addToolbarSeparator() ## Preview ## + preview_string = self.plugin.getString(StringContent.Preview) self.addToolbarButton( - unicode(translate('OpenLP.MediaManagerItem', 'Preview %s')) % - self.PluginNameShort, - translate('OpenLP.MediaManagerItem', 'Preview the selected item'), + preview_string[u'title'], + preview_string[u'tooltip'], u':/general/general_preview.png', self.onPreviewClick) ## Live Button ## + live_string = self.plugin.getString(StringContent.Live) self.addToolbarButton( - u'Go Live', - translate('OpenLP.MediaManagerItem', 'Send the selected item live'), + live_string[u'title'], + live_string[u'tooltip'], u':/general/general_live.png', self.onLiveClick) ## Add to service Button ## + service_string = self.plugin.getString(StringContent.Service) self.addToolbarButton( - unicode(translate('OpenLP.MediaManagerItem', 'Add %s to Service')) % - self.PluginNameShort, - translate('OpenLP.MediaManagerItem', - 'Add the selected item(s) to the service'), + service_string[u'title'], + service_string[u'tooltip'], u':/general/general_add.png', self.onAddClick) def addListViewToToolBar(self): @@ -281,17 +274,18 @@ class MediaManagerItem(QtGui.QWidget): QtGui.QAbstractItemView.ExtendedSelection) self.listView.setAlternatingRowColors(True) self.listView.setDragEnabled(True) - self.listView.setObjectName(u'%sListView' % self.PluginNameShort) + self.listView.setObjectName(u'%sListView' % self.plugin.name) #Add to pageLayout self.pageLayout.addWidget(self.listView) #define and add the context menu self.listView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) + name_string = self.plugin.getString(StringContent.Name) if self.hasEditIcon: self.listView.addAction( context_menu_action( self.listView, u':/general/general_edit.png', unicode(translate('OpenLP.MediaManagerItem', '&Edit %s')) % - self.pluginNameVisible, + name_string[u'singular'], self.onEditClick)) self.listView.addAction(context_menu_separator(self.listView)) if self.hasDeleteIcon: @@ -300,14 +294,14 @@ class MediaManagerItem(QtGui.QWidget): self.listView, u':/general/general_delete.png', unicode(translate('OpenLP.MediaManagerItem', '&Delete %s')) % - self.pluginNameVisible, + name_string[u'singular'], self.onDeleteClick)) self.listView.addAction(context_menu_separator(self.listView)) self.listView.addAction( context_menu_action( self.listView, u':/general/general_preview.png', unicode(translate('OpenLP.MediaManagerItem', '&Preview %s')) % - self.pluginNameVisible, + name_string[u'singular'], self.onPreviewClick)) self.listView.addAction( context_menu_action( @@ -447,7 +441,7 @@ class MediaManagerItem(QtGui.QWidget): translate('OpenLP.MediaManagerItem', 'You must select one or more items to preview.')) else: - log.debug(self.PluginNameShort + u' Preview requested') + log.debug(self.plugin.name + u' Preview requested') service_item = self.buildServiceItem() if service_item: service_item.from_plugin = True @@ -464,7 +458,7 @@ class MediaManagerItem(QtGui.QWidget): translate('OpenLP.MediaManagerItem', 'You must select one or more items to send live.')) else: - log.debug(self.PluginNameShort + u' Live requested') + log.debug(self.plugin.name + u' Live requested') service_item = self.buildServiceItem() if service_item: service_item.from_plugin = True @@ -480,10 +474,10 @@ class MediaManagerItem(QtGui.QWidget): translate('OpenLP.MediaManagerItem', 'You must select one or more items.')) else: - #Is it posssible to process multiple list items to generate multiple - #service items? + # Is it posssible to process multiple list items to generate multiple + # service items? if self.singleServiceItem or self.remoteTriggered: - log.debug(self.PluginNameShort + u' Add requested') + log.debug(self.plugin.name + u' Add requested') service_item = self.buildServiceItem() if service_item: service_item.from_plugin = False @@ -507,10 +501,10 @@ class MediaManagerItem(QtGui.QWidget): translate('OpenLP.MediaManagerItem', 'You must select one or more items')) else: - log.debug(self.PluginNameShort + u' Add requested') + log.debug(self.plugin.name + u' Add requested') service_item = self.parent.serviceManager.getServiceItem() if not service_item: - QtGui.QMessageBox.information(self, + QtGui.QMessageBox.information(self, translate('OpenLP.MediaManagerItem', 'No Service Item Selected'), translate('OpenLP.MediaManagerItem', @@ -540,3 +534,11 @@ class MediaManagerItem(QtGui.QWidget): return service_item else: return None + + def serviceLoad(self, message): + """ + Method to add processing when a service has been loaded and + individual service items need to be processed by the plugins + """ + pass + diff --git a/openlp/core/lib/plugin.py b/openlp/core/lib/plugin.py index 45fbcb6b0..37ac3d74a 100644 --- a/openlp/core/lib/plugin.py +++ b/openlp/core/lib/plugin.py @@ -42,6 +42,18 @@ class PluginStatus(object): Inactive = 0 Disabled = -1 +class StringContent(object): + Name = u'name' + Import = u'import' + Load = u'load' + New = u'new' + Edit = u'edit' + Delete = u'delete' + Preview = u'preview' + Live = u'live' + Service = u'service' + VisibleName = u'visible_name' + class Plugin(QtCore.QObject): """ Base class for openlp plugins to inherit from. @@ -117,6 +129,8 @@ class Plugin(QtCore.QObject): """ QtCore.QObject.__init__(self) self.name = name + self.textStrings = {} + self.setPluginTextStrings() if version: self.version = version self.settingsSection = self.name.lower() @@ -257,9 +271,9 @@ class Plugin(QtCore.QObject): Called by the plugin to remove toolbar """ if self.mediaItem: - self.mediadock.remove_dock(self.name) + self.mediadock.remove_dock(self.mediaItem) if self.settings_tab: - self.settingsForm.removeTab(self.name) + self.settingsForm.removeTab(self.settings_tab) def insertToolboxItem(self): """ @@ -289,3 +303,15 @@ class Plugin(QtCore.QObject): The new name the plugin should now use. """ pass + + def getString(self, name): + """ + encapsulate access of plugins translated text strings + """ + return self.textStrings[name] + + def setPluginTextStrings(self): + """ + Called to define all translatable texts of the plugin + """ + pass diff --git a/openlp/core/lib/pluginmanager.py b/openlp/core/lib/pluginmanager.py index d4570bec5..ff136de54 100644 --- a/openlp/core/lib/pluginmanager.py +++ b/openlp/core/lib/pluginmanager.py @@ -30,7 +30,7 @@ import os import sys import logging -from openlp.core.lib import Plugin, PluginStatus +from openlp.core.lib import Plugin, StringContent, PluginStatus log = logging.getLogger(__name__) @@ -152,12 +152,13 @@ class PluginManager(object): for plugin in self.plugins: if plugin.status is not PluginStatus.Disabled: plugin.settings_tab = plugin.getSettingsTab() + visible_title = plugin.getString(StringContent.VisibleName) if plugin.settings_tab: log.debug(u'Inserting settings tab item from %s' % - plugin.name) - settingsform.addTab(plugin.name, plugin.settings_tab) + visible_title[u'title']) + settingsform.addTab(visible_title[u'title'], plugin.settings_tab) else: - log.debug(u'No tab settings in %s' % plugin.name) + log.debug(u'No tab settings in %s' % visible_title[u'title']) def hook_import_menu(self, import_menu): """ diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index f97575c5e..d5bcab457 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -161,8 +161,9 @@ class Renderer(object): html_text = u'' styled_text = u'' for line in text: - styled_line = expand_tags(line) + line_end - styled_text += styled_line + styled_line = expand_tags(line) + if styled_text: + styled_text += line_end + styled_line html = self.page_shell + styled_text + u'' self.web.setHtml(html) # Text too long so go to next page @@ -171,6 +172,8 @@ class Renderer(object): html_text = u'' styled_text = styled_line html_text += line + line_end + if line_break: + html_text = html_text[:len(html_text)-4] formatted.append(html_text) log.debug(u'format_slide - End') return formatted diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index e7ec9c2af..663328d95 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -58,6 +58,9 @@ class ItemCapabilities(object): AllowsLoop = 5 AllowsAdditions = 6 NoLineBreaks = 7 + OnLoadUpdate = 8 + AddIfNewItem = 9 + class ServiceItem(object): """ @@ -98,6 +101,9 @@ class ServiceItem(object): self.main = None self.footer = None self.bg_image_bytes = None + self.search_string = u'' + self.data_string = u'' + self._new_item() def _new_item(self): """ @@ -255,7 +261,9 @@ class ServiceItem(object): u'audit':self.audit, u'notes':self.notes, u'from_plugin':self.from_plugin, - u'capabilities':self.capabilities + u'capabilities':self.capabilities, + u'search':self.search_string, + u'data':self.data_string } service_data = [] if self.service_item_type == ServiceItemType.Text: @@ -293,6 +301,10 @@ class ServiceItem(object): self.notes = header[u'notes'] self.from_plugin = header[u'from_plugin'] self.capabilities = header[u'capabilities'] + # Added later so may not be present in older services. + if u'search' in header: + self.search_string = header[u'search'] + self.data_string = header[u'data'] if self.service_item_type == ServiceItemType.Text: for slide in serviceitem[u'serviceitem'][u'data']: self._raw_frames.append(slide) @@ -306,6 +318,7 @@ class ServiceItem(object): filename = os.path.join(path, text_image[u'title']) self.add_from_command( path, text_image[u'title'], text_image[u'image'] ) + self._new_item() def merge(self, other): """ diff --git a/openlp/core/lib/settingstab.py b/openlp/core/lib/settingstab.py index 99389d4c4..8de42e7a0 100644 --- a/openlp/core/lib/settingstab.py +++ b/openlp/core/lib/settingstab.py @@ -31,16 +31,19 @@ class SettingsTab(QtGui.QWidget): SettingsTab is a helper widget for plugins to define Tabs for the settings dialog. """ - def __init__(self, title): + def __init__(self, title, visible_title=None): """ Constructor to create the Settings tab item. ``title`` + The title of the tab, which is used internally for the tab handling. + + ``visible_title`` The title of the tab, which is usually displayed on the tab. """ QtGui.QWidget.__init__(self) self.tabTitle = title - self.tabTitleVisible = None + self.tabTitleVisible = visible_title self.settingsSection = self.tabTitle.lower() self.setupUi() self.retranslateUi() diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 10f1ee92e..81487e4f8 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -175,19 +175,13 @@ class Ui_MainWindow(object): QtCore.Qt.DockWidgetArea(2), self.ThemeManagerDock) # Create the menu items self.FileNewItem = QtGui.QAction(MainWindow) - self.FileNewItem.setIcon( - self.ServiceManagerContents.toolbar.getIconFromTitle( - u'New Service')) + self.FileNewItem.setIcon(build_icon(u':/general/general_new.png')) self.FileNewItem.setObjectName(u'FileNewItem') self.FileOpenItem = QtGui.QAction(MainWindow) - self.FileOpenItem.setIcon( - self.ServiceManagerContents.toolbar.getIconFromTitle( - u'Open Service')) + self.FileOpenItem.setIcon(build_icon(u':/general/general_open.png')) self.FileOpenItem.setObjectName(u'FileOpenItem') self.FileSaveItem = QtGui.QAction(MainWindow) - self.FileSaveItem.setIcon( - self.ServiceManagerContents.toolbar.getIconFromTitle( - u'Save Service')) + self.FileSaveItem.setIcon(build_icon(u':/general/general_save.png')) self.FileSaveItem.setObjectName(u'FileSaveItem') self.FileSaveAsItem = QtGui.QAction(MainWindow) self.FileSaveAsItem.setObjectName(u'FileSaveAsItem') @@ -343,7 +337,6 @@ class Ui_MainWindow(object): Set up the translation system """ MainWindow.mainTitle = translate('OpenLP.MainWindow', 'OpenLP 2.0') -# MainWindow.language = translate('OpenLP.MainWindow', 'English') MainWindow.setWindowTitle(MainWindow.mainTitle) self.FileMenu.setTitle(translate('OpenLP.MainWindow', '&File')) self.FileImportMenu.setTitle(translate('OpenLP.MainWindow', '&Import')) diff --git a/openlp/core/ui/mediadockmanager.py b/openlp/core/ui/mediadockmanager.py index afe316a8a..c49d7fab3 100644 --- a/openlp/core/ui/mediadockmanager.py +++ b/openlp/core/ui/mediadockmanager.py @@ -26,6 +26,8 @@ import logging +from openlp.core.lib import StringContent + log = logging.getLogger(__name__) class MediaDockManager(object): @@ -48,8 +50,9 @@ class MediaDockManager(object): ``icon`` An icon for this dock item """ - log.info(u'Adding %s dock' % media_item.title) - self.media_dock.addItem(media_item, icon, media_item.title) + visible_title = media_item.plugin.getString(StringContent.VisibleName) + log.info(u'Adding %s dock' % visible_title) + self.media_dock.addItem(media_item, icon, visible_title[u'title']) def insert_dock(self, media_item, icon, weight): """ @@ -57,27 +60,29 @@ class MediaDockManager(object): This does not work as it gives a Segmentation error. For now add at end of stack if not present """ - log.debug(u'Inserting %s dock' % media_item.title) + visible_title = media_item.plugin.getString(StringContent.VisibleName) + log.debug(u'Inserting %s dock' % visible_title[u'title']) match = False for dock_index in range(0, self.media_dock.count()): if self.media_dock.widget(dock_index).settingsSection == \ - media_item.title.lower(): + media_item.plugin.name.lower(): match = True break if not match: - self.media_dock.addItem(media_item, icon, media_item.title) + self.media_dock.addItem(media_item, icon, visible_title[u'title']) - def remove_dock(self, name): + def remove_dock(self, media_item): """ Removes a MediaManagerItem from the dock - ``name`` - The item to remove + ``media_item`` + The item to add to the dock """ - log.debug(u'remove %s dock' % name) + visible_title = media_item.plugin.getString(StringContent.VisibleName) + log.debug(u'remove %s dock' % visible_title[u'title']) for dock_index in range(0, self.media_dock.count()): if self.media_dock.widget(dock_index): if self.media_dock.widget(dock_index).settingsSection == \ - name.lower(): + media_item.plugin.name.lower(): self.media_dock.widget(dock_index).hide() self.media_dock.removeItem(dock_index) diff --git a/openlp/core/ui/pluginform.py b/openlp/core/ui/pluginform.py index a8e93bb86..cbde28ae7 100644 --- a/openlp/core/ui/pluginform.py +++ b/openlp/core/ui/pluginform.py @@ -28,7 +28,7 @@ import logging from PyQt4 import QtCore, QtGui -from openlp.core.lib import PluginStatus, translate +from openlp.core.lib import PluginStatus, StringContent, translate from plugindialog import Ui_PluginViewDialog log = logging.getLogger(__name__) @@ -78,7 +78,8 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog): elif plugin.status == PluginStatus.Disabled: status_text = unicode( translate('OpenLP.PluginForm', '%s (Disabled)')) - item.setText(status_text % plugin.name) + name_string = plugin.getString(StringContent.Name) + item.setText(status_text % name_string[u'plural']) # If the plugin has an icon, set it! if plugin.icon: item.setIcon(plugin.icon) @@ -106,10 +107,11 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog): if self.pluginListWidget.currentItem() is None: self._clearDetails() return - plugin_name = self.pluginListWidget.currentItem().text().split(u' ')[0] + plugin_name_plural = self.pluginListWidget.currentItem().text().split(u' ')[0] self.activePlugin = None for plugin in self.parent.plugin_manager.plugins: - if plugin.name == plugin_name: + name_string = plugin.getString(StringContent.Name) + if name_string[u'plural'] == plugin_name_plural: self.activePlugin = plugin break if self.activePlugin: @@ -137,5 +139,6 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog): elif self.activePlugin.status == PluginStatus.Disabled: status_text = unicode( translate('OpenLP.PluginForm', '%s (Disabled)')) + name_string = self.activePlugin.getString(StringContent.Name) self.pluginListWidget.currentItem().setText( - status_text % self.activePlugin.name) + status_text % name_string[u'plural']) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 319725790..1fb276a25 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -223,6 +223,8 @@ class ServiceManager(QtGui.QWidget): QtCore.SIGNAL(u'config_updated'), self.regenerateServiceItems) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'theme_update_global'), self.themeChange) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'service_item_update'), self.serviceItemUpdate) # Last little bits of setting up self.service_theme = unicode(QtCore.QSettings().value( self.parent.serviceSettingsSection + u'/service theme', @@ -600,6 +602,7 @@ class ServiceManager(QtGui.QWidget): zip = None file = None try: + write_list = [] zip = zipfile.ZipFile(unicode(filename), 'w') for item in self.serviceItems: service.append({u'serviceitem':item[u'service_item'] @@ -609,7 +612,10 @@ class ServiceManager(QtGui.QWidget): path_from = unicode(os.path.join( frame[u'path'], frame[u'title'])) - zip.write(path_from.encode(u'utf-8')) + # On write a file once + if not path_from in write_list: + write_list.append(path_from) + zip.write(path_from.encode(u'utf-8')) file = open(servicefile, u'wb') cPickle.dump(service, file) file.close() @@ -711,6 +717,9 @@ class ServiceManager(QtGui.QWidget): serviceitem.set_from_service(item, self.servicePath) self.validateItem(serviceitem) self.addServiceItem(serviceitem) + if serviceitem.is_capable(ItemCapabilities.OnLoadUpdate): + Receiver.send_message(u'%s_service_load' % + serviceitem.name.lower(), serviceitem) try: if os.path.isfile(p_file): os.remove(p_file) @@ -801,7 +810,31 @@ class ServiceManager(QtGui.QWidget): # does not impact the saved song so True may also be valid self.parent.serviceChanged(False, self.serviceName) - def addServiceItem(self, item, rebuild=False, expand=True, replace=False): + def serviceItemUpdate(self, message): + """ + Triggered from plugins to update service items. + """ + editId, uuid = message.split(u':') + for item in self.serviceItems: + if item[u'service_item']._uuid == uuid: + item[u'service_item'].editId = editId + + def replaceServiceItem(self, newItem): + """ + Using the service item passed replace the one with the same edit id + if found. + """ + newItem.render() + for itemcount, item in enumerate(self.serviceItems): + if item[u'service_item'].editId == newItem.editId and \ + item[u'service_item'].name == newItem.name: + newItem.merge(item[u'service_item']) + item[u'service_item'] = newItem + self.repaintServiceList(itemcount + 1, 0) + self.parent.LiveController.replaceServiceManagerItem(newItem) + self.parent.serviceChanged(False, self.serviceName) + + def addServiceItem(self, item, rebuild=False, expand=False, replace=False): """ Add a Service item to the list @@ -817,7 +850,7 @@ class ServiceManager(QtGui.QWidget): self.repaintServiceList(sitem + 1, 0) self.parent.LiveController.replaceServiceManagerItem(item) else: - #nothing selected for dnd + # nothing selected for dnd if self.droppos == 0: if isinstance(item, list): for inditem in item: @@ -834,7 +867,7 @@ class ServiceManager(QtGui.QWidget): u'order': self.droppos, u'expanded':expand}) self.repaintServiceList(self.droppos, 0) - #if rebuilding list make sure live is fixed. + # if rebuilding list make sure live is fixed. if rebuild: self.parent.LiveController.replaceServiceManagerItem(item) self.droppos = 0 @@ -914,7 +947,7 @@ class ServiceManager(QtGui.QWidget): else: pos = parentitem.data(0, QtCore.Qt.UserRole).toInt()[0] count = item.data(0, QtCore.Qt.UserRole).toInt()[0] - #adjust for zero based arrays + # adjust for zero based arrays pos = pos - 1 return pos, count @@ -940,7 +973,7 @@ class ServiceManager(QtGui.QWidget): if link.hasText(): plugin = event.mimeData().text() item = self.serviceManagerList.itemAt(event.pos()) - #ServiceManager started the drag and drop + # ServiceManager started the drag and drop if plugin == u'ServiceManager': startpos, startCount = self.findServiceItem() if item is None: @@ -952,22 +985,22 @@ class ServiceManager(QtGui.QWidget): self.serviceItems.insert(endpos, serviceItem) self.repaintServiceList(endpos, startCount) else: - #we are not over anything so drop + # we are not over anything so drop replace = False if item is None: self.droppos = len(self.serviceItems) else: - #we are over somthing so lets investigate + # we are over somthing so lets investigate pos = self._getParentItemData(item) - 1 serviceItem = self.serviceItems[pos] if (plugin == serviceItem[u'service_item'].name and serviceItem[u'service_item'].is_capable( ItemCapabilities.AllowsAdditions)): action = self.dndMenu.exec_(QtGui.QCursor.pos()) - #New action required + # New action required if action == self.newAction: self.droppos = self._getParentItemData(item) - #Append to existing action + # Append to existing action if action == self.addToAction: self.droppos = self._getParentItemData(item) item.setSelected(True) diff --git a/openlp/core/ui/settingsform.py b/openlp/core/ui/settingsform.py index 37fe1f329..d1cf19622 100644 --- a/openlp/core/ui/settingsform.py +++ b/openlp/core/ui/settingsform.py @@ -72,14 +72,15 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog): self.settingsTabWidget.insertTab( location + 14, tab, tab.tabTitleVisible) - def removeTab(self, name): + def removeTab(self, tab): """ Remove a tab from the form """ - log.debug(u'remove %s tab' % name) + log.debug(u'remove %s tab' % tab.tabTitleVisible) for tabIndex in range(0, self.settingsTabWidget.count()): if self.settingsTabWidget.widget(tabIndex): - if self.settingsTabWidget.widget(tabIndex).tabTitle == name: + if self.settingsTabWidget.widget(tabIndex).tabTitleVisible == \ + tab.tabTitleVisible: self.settingsTabWidget.removeTab(tabIndex) def accept(self): diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 0a3e0c91b..31bf0e321 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -179,19 +179,24 @@ class SlideController(QtGui.QWidget): self.HideMenu.setMenu(QtGui.QMenu( translate('OpenLP.SlideController', 'Hide'), self.Toolbar)) self.BlankScreen = QtGui.QAction(QtGui.QIcon( - u':/slides/slide_blank.png'), u'Blank Screen', self.HideMenu) + u':/slides/slide_blank.png'), + translate('OpenLP.SlideController', + 'Blank Screen'), self.HideMenu) self.BlankScreen.setCheckable(True) QtCore.QObject.connect(self.BlankScreen, QtCore.SIGNAL("triggered(bool)"), self.onBlankDisplay) self.ThemeScreen = QtGui.QAction(QtGui.QIcon( - u':/slides/slide_theme.png'), u'Blank to Theme', self.HideMenu) + u':/slides/slide_theme.png'), + translate('OpenLP.SlideController', + 'Blank to Theme'), self.HideMenu) self.ThemeScreen.setCheckable(True) QtCore.QObject.connect(self.ThemeScreen, QtCore.SIGNAL("triggered(bool)"), self.onThemeDisplay) if self.screens.display_count > 1: self.DesktopScreen = QtGui.QAction(QtGui.QIcon( - u':/slides/slide_desktop.png'), u'Show Desktop', - self.HideMenu) + u':/slides/slide_desktop.png'), + translate('OpenLP.SlideController', + 'Show Desktop'), self.HideMenu) self.DesktopScreen.setCheckable(True) QtCore.QObject.connect(self.DesktopScreen, QtCore.SIGNAL("triggered(bool)"), self.onHideDisplay) diff --git a/openlp/plugins/alerts/alertsplugin.py b/openlp/plugins/alerts/alertsplugin.py index b8a829b37..878185808 100644 --- a/openlp/plugins/alerts/alertsplugin.py +++ b/openlp/plugins/alerts/alertsplugin.py @@ -28,7 +28,7 @@ import logging from PyQt4 import QtCore, QtGui -from openlp.core.lib import Plugin, build_icon, translate +from openlp.core.lib import Plugin, StringContent, build_icon, translate from openlp.core.lib.db import Manager from openlp.plugins.alerts.lib import AlertsManager, AlertsTab from openlp.plugins.alerts.lib.db import init_schema @@ -101,3 +101,18 @@ class AlertsPlugin(Plugin): '
The alert plugin controls the displaying of nursery alerts ' 'on the display screen') return about_text + + def setPluginTextStrings(self): + """ + Called to define all translatable texts of the plugin + """ + ## Name PluginList ## + self.textStrings[StringContent.Name] = { + u'singular': translate('AlertsPlugin', 'Alert'), + u'plural': translate('AlertsPlugin', 'Alerts') + } + ## Name for MediaDockManager, SettingsManager ## + self.textStrings[StringContent.VisibleName] = { + u'title': translate('AlertsPlugin', 'Alerts') + } + \ No newline at end of file diff --git a/openlp/plugins/alerts/forms/alertform.py b/openlp/plugins/alerts/forms/alertform.py index e2ff6e2e2..7859417f7 100644 --- a/openlp/plugins/alerts/forms/alertform.py +++ b/openlp/plugins/alerts/forms/alertform.py @@ -35,7 +35,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog): """ Provide UI for the alert system """ - def __init__(self, plugin): + def __init__(self, title, visible_title): """ Initialise the alert form """ diff --git a/openlp/plugins/alerts/lib/alertstab.py b/openlp/plugins/alerts/lib/alertstab.py index 77b6e7fb6..625287603 100644 --- a/openlp/plugins/alerts/lib/alertstab.py +++ b/openlp/plugins/alerts/lib/alertstab.py @@ -32,14 +32,13 @@ class AlertsTab(SettingsTab): """ AlertsTab is the alerts settings tab in the settings dialog. """ - def __init__(self, parent): + def __init__(self, parent, visible_title): self.parent = parent self.manager = parent.manager - SettingsTab.__init__(self, parent.name) + SettingsTab.__init__(self, parent.name, visible_title) def setupUi(self): self.setObjectName(u'AlertsTab') - self.tabTitleVisible = translate('AlertsPlugin.AlertsTab', 'Alerts') self.AlertsLayout = QtGui.QHBoxLayout(self) self.AlertsLayout.setSpacing(8) self.AlertsLayout.setMargin(8) @@ -296,4 +295,3 @@ class AlertsTab(SettingsTab): self.FontPreview.setFont(font) self.FontPreview.setStyleSheet(u'background-color: %s; color: %s' % (self.bg_color, self.font_color)) - diff --git a/openlp/plugins/bibles/bibleplugin.py b/openlp/plugins/bibles/bibleplugin.py index 292342c8b..5dec63200 100644 --- a/openlp/plugins/bibles/bibleplugin.py +++ b/openlp/plugins/bibles/bibleplugin.py @@ -28,7 +28,7 @@ import logging from PyQt4 import QtCore, QtGui -from openlp.core.lib import Plugin, build_icon, translate +from openlp.core.lib import Plugin, StringContent, build_icon, translate from openlp.plugins.bibles.lib import BibleManager, BiblesTab, BibleMediaItem log = logging.getLogger(__name__) @@ -58,11 +58,12 @@ class BiblePlugin(Plugin): self.exportBibleItem.setVisible(False) def getSettingsTab(self): - return BiblesTab(self.name) + visible_name = self.getString(StringContent.VisibleName) + return BiblesTab(self.name, visible_name[u'title']) def getMediaManagerItem(self): # Create the BibleManagerItem object. - return BibleMediaItem(self, self.icon, self.name) + return BibleMediaItem(self, self, self.icon) def addImportMenuItem(self, import_menu): self.importBibleItem = QtGui.QAction(import_menu) @@ -114,3 +115,60 @@ class BiblePlugin(Plugin): The new name the plugin should now use. """ self.settings_tab.bible_theme = newTheme + + def setPluginTextStrings(self): + """ + Called to define all translatable texts of the plugin + """ + ## Name PluginList ## + self.textStrings[StringContent.Name] = { + u'singular': translate('BiblesPlugin', 'Bible'), + u'plural': translate('BiblesPlugin', 'Bibles') + } + ## Name for MediaDockManager, SettingsManager ## + self.textStrings[StringContent.VisibleName] = { + u'title': translate('BiblesPlugin', 'Bibles') + } + # Middle Header Bar + ## Import Button ## + self.textStrings[StringContent.Import] = { + u'title': translate('BiblesPlugin', 'Import'), + u'tooltip': translate('BiblesPlugin', + 'Import a Bible') + } + ## New Button ## + self.textStrings[StringContent.New] = { + u'title': translate('BiblesPlugin', 'Add'), + u'tooltip': translate('BiblesPlugin', + 'Add a new Bible') + } + ## Edit Button ## + self.textStrings[StringContent.Edit] = { + u'title': translate('BiblesPlugin', 'Edit'), + u'tooltip': translate('BiblesPlugin', + 'Edit the selected Bible') + } + ## Delete Button ## + self.textStrings[StringContent.Delete] = { + u'title': translate('BiblesPlugin', 'Delete'), + u'tooltip': translate('BiblesPlugin', + 'Delete the selected Bible') + } + ## Preview ## + self.textStrings[StringContent.Preview] = { + u'title': translate('BiblesPlugin', 'Preview'), + u'tooltip': translate('BiblesPlugin', + 'Preview the selected Bible') + } + ## Live Button ## + self.textStrings[StringContent.Live] = { + u'title': translate('BiblesPlugin', 'Live'), + u'tooltip': translate('BiblesPlugin', + 'Send the selected Bible live') + } + ## Add to service Button ## + self.textStrings[StringContent.Service] = { + u'title': translate('BiblesPlugin', 'Service'), + u'tooltip': translate('BiblesPlugin', + 'Add the selected Bible to the service') + } \ No newline at end of file diff --git a/openlp/plugins/bibles/lib/biblestab.py b/openlp/plugins/bibles/lib/biblestab.py index 0903c9625..b7d1b9bde 100644 --- a/openlp/plugins/bibles/lib/biblestab.py +++ b/openlp/plugins/bibles/lib/biblestab.py @@ -38,15 +38,14 @@ class BiblesTab(SettingsTab): """ log.info(u'Bible Tab loaded') - def __init__(self, title): + def __init__(self, title, visible_title): self.paragraph_style = True self.show_new_chapters = False self.display_style = 0 - SettingsTab.__init__(self, title) + SettingsTab.__init__(self, title, visible_title) def setupUi(self): self.setObjectName(u'BiblesTab') - self.tabTitleVisible = translate('BiblesPlugin.BiblesTab', 'Bibles') self.BibleLayout = QtGui.QHBoxLayout(self) self.BibleLayout.setSpacing(8) self.BibleLayout.setMargin(8) diff --git a/openlp/plugins/custom/customplugin.py b/openlp/plugins/custom/customplugin.py index 523ccb061..7e4b81b16 100644 --- a/openlp/plugins/custom/customplugin.py +++ b/openlp/plugins/custom/customplugin.py @@ -28,7 +28,7 @@ import logging from forms import EditCustomForm -from openlp.core.lib import Plugin, build_icon, translate +from openlp.core.lib import Plugin, StringContent, build_icon, translate from openlp.core.lib.db import Manager from openlp.plugins.custom.lib import CustomMediaItem, CustomTab from openlp.plugins.custom.lib.db import CustomSlide, init_schema @@ -55,11 +55,12 @@ class CustomPlugin(Plugin): self.icon = build_icon(self.icon_path) def getSettingsTab(self): - return CustomTab(self.name) + visible_name = self.getString(StringContent.VisibleName) + return CustomTab(self.name, visible_name[u'title']) def getMediaManagerItem(self): # Create the CustomManagerItem object - return CustomMediaItem(self, self.icon, self.name) + return CustomMediaItem(self, self, self.icon) def about(self): about_text = translate('CustomPlugin', 'Custom Plugin' @@ -96,3 +97,66 @@ class CustomPlugin(Plugin): for custom in customsUsingTheme: custom.theme_name = newTheme self.custommanager.save_object(custom) + + def setPluginTextStrings(self): + """ + Called to define all translatable texts of the plugin + """ + ## Name PluginList ## + self.textStrings[StringContent.Name] = { + u'singular': translate('CustomsPlugin', 'Custom'), + u'plural': translate('CustomsPlugin', 'Customs') + } + ## Name for MediaDockManager, SettingsManager ## + self.textStrings[StringContent.VisibleName] = { + u'title': translate('CustomsPlugin', 'Customs') + } + # Middle Header Bar + ## Import Button ## + self.textStrings[StringContent.Import] = { + u'title': translate('CustomsPlugin', 'Import'), + u'tooltip': translate('CustomsPlugin', + 'Import a Custom') + } + ## Load Button ## + self.textStrings[StringContent.Load] = { + u'title': translate('CustomsPlugin', 'Load'), + u'tooltip': translate('CustomsPlugin', + 'Load a new Custom') + } + ## New Button ## + self.textStrings[StringContent.New] = { + u'title': translate('CustomsPlugin', 'Add'), + u'tooltip': translate('CustomsPlugin', + 'Add a new Custom') + } + ## Edit Button ## + self.textStrings[StringContent.Edit] = { + u'title': translate('CustomsPlugin', 'Edit'), + u'tooltip': translate('CustomsPlugin', + 'Edit the selected Custom') + } + ## Delete Button ## + self.textStrings[StringContent.Delete] = { + u'title': translate('CustomsPlugin', 'Delete'), + u'tooltip': translate('CustomsPlugin', + 'Delete the selected Custom') + } + ## Preview ## + self.textStrings[StringContent.Preview] = { + u'title': translate('CustomsPlugin', 'Preview'), + u'tooltip': translate('CustomsPlugin', + 'Preview the selected Custom') + } + ## Live Button ## + self.textStrings[StringContent.Live] = { + u'title': translate('CustomsPlugin', 'Live'), + u'tooltip': translate('CustomsPlugin', + 'Send the selected Custom live') + } + ## Add to service Button ## + self.textStrings[StringContent.Service] = { + u'title': translate('CustomsPlugin', 'Service'), + u'tooltip': translate('CustomsPlugin', + 'Add the selected Custom to the service') + } \ No newline at end of file diff --git a/openlp/plugins/custom/lib/customtab.py b/openlp/plugins/custom/lib/customtab.py index 77ef0f3f6..461d6af59 100644 --- a/openlp/plugins/custom/lib/customtab.py +++ b/openlp/plugins/custom/lib/customtab.py @@ -32,12 +32,11 @@ class CustomTab(SettingsTab): """ CustomTab is the Custom settings tab in the settings dialog. """ - def __init__(self, title): - SettingsTab.__init__(self, title) + def __init__(self, title, visible_title): + SettingsTab.__init__(self, title, visible_title) def setupUi(self): self.setObjectName(u'CustomTab') - self.tabTitleVisible = translate('CustomPlugin.CustomTab', 'Custom') self.customLayout = QtGui.QFormLayout(self) self.customLayout.setSpacing(8) self.customLayout.setMargin(8) diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index 671a3679a..dd26883e8 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -46,14 +46,12 @@ class CustomMediaItem(MediaManagerItem): """ log.info(u'Custom Media Item loaded') - def __init__(self, parent, icon, title): - self.PluginNameShort = u'Custom' - self.pluginNameVisible = translate('CustomPlugin.MediaItem', 'Custom') + def __init__(self, parent, plugin, icon): self.IconPath = u'custom/custom' # this next is a class, not an instance of a class - it will # be instanced by the base MediaManagerItem self.ListViewWithDnD_class = CustomListView - MediaManagerItem.__init__(self, parent, icon, title) + MediaManagerItem.__init__(self, parent, self, icon) self.singleServiceItem = False # Holds information about whether the edit is remotly triggered and # which Custom is required. diff --git a/openlp/plugins/images/imageplugin.py b/openlp/plugins/images/imageplugin.py index 711000191..5bcf75af0 100644 --- a/openlp/plugins/images/imageplugin.py +++ b/openlp/plugins/images/imageplugin.py @@ -26,7 +26,7 @@ import logging -from openlp.core.lib import Plugin, build_icon, translate +from openlp.core.lib import Plugin, StringContent, build_icon, translate from openlp.plugins.images.lib import ImageMediaItem log = logging.getLogger(__name__) @@ -42,7 +42,7 @@ class ImagePlugin(Plugin): def getMediaManagerItem(self): # Create the MediaManagerItem object - return ImageMediaItem(self, self.icon, self.name) + return ImageMediaItem(self, self, self.icon) def about(self): about_text = translate('ImagePlugin', 'Image Plugin' @@ -57,3 +57,60 @@ class ImagePlugin(Plugin): 'selected image as a background instead of the background ' 'provided by the theme.') return about_text + + def setPluginTextStrings(self): + """ + Called to define all translatable texts of the plugin + """ + ## Name PluginList ## + self.textStrings[StringContent.Name] = { + u'singular': translate('ImagePlugin', 'Image'), + u'plural': translate('ImagePlugin', 'Images') + } + ## Name for MediaDockManager, SettingsManager ## + self.textStrings[StringContent.VisibleName] = { + u'title': translate('ImagePlugin', 'Images') + } + # Middle Header Bar + ## Load Button ## + self.textStrings[StringContent.Load] = { + u'title': translate('ImagePlugin', 'Load'), + u'tooltip': translate('ImagePlugin', + 'Load a new Image') + } + ## New Button ## + self.textStrings[StringContent.New] = { + u'title': translate('ImagePlugin', 'Add'), + u'tooltip': translate('ImagePlugin', + 'Add a new Image') + } + ## Edit Button ## + self.textStrings[StringContent.Edit] = { + u'title': translate('ImagePlugin', 'Edit'), + u'tooltip': translate('ImagePlugin', + 'Edit the selected Image') + } + ## Delete Button ## + self.textStrings[StringContent.Delete] = { + u'title': translate('ImagePlugin', 'Delete'), + u'tooltip': translate('ImagePlugin', + 'Delete the selected Image') + } + ## Preview ## + self.textStrings[StringContent.Preview] = { + u'title': translate('ImagePlugin', 'Preview'), + u'tooltip': translate('ImagePlugin', + 'Preview the selected Image') + } + ## Live Button ## + self.textStrings[StringContent.Live] = { + u'title': translate('ImagePlugin', 'Live'), + u'tooltip': translate('ImagePlugin', + 'Send the selected Image live') + } + ## Add to service Button ## + self.textStrings[StringContent.Service] = { + u'title': translate('ImagePlugin', 'Service'), + u'tooltip': translate('ImagePlugin', + 'Add the selected Image to the service') + } \ No newline at end of file diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index 4caf5bfc2..5a3918dd9 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -49,14 +49,12 @@ class ImageMediaItem(MediaManagerItem): """ log.info(u'Image Media Item loaded') - def __init__(self, parent, icon, title): - self.PluginNameShort = u'Image' - self.pluginNameVisible = translate('ImagePlugin.MediaItem', 'Image') + def __init__(self, parent, plugin, icon): self.IconPath = u'images/image' # this next is a class, not an instance of a class - it will # be instanced by the base MediaManagerItem self.ListViewWithDnD_class = ImageListView - MediaManagerItem.__init__(self, parent, icon, title) + MediaManagerItem.__init__(self, parent, self, icon) def retranslateUi(self): self.OnNewPrompt = translate('ImagePlugin.MediaItem', diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 447d4ccb5..88c8ea282 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -46,9 +46,7 @@ class MediaMediaItem(MediaManagerItem): """ log.info(u'%s MediaMediaItem loaded', __name__) - def __init__(self, parent, icon, title): - self.PluginNameShort = u'Media' - self.pluginNameVisible = translate('MediaPlugin.MediaItem', 'Media') + def __init__(self, parent, plugin, icon): self.IconPath = u'images/image' self.background = False # this next is a class, not an instance of a class - it will @@ -56,7 +54,7 @@ class MediaMediaItem(MediaManagerItem): self.ListViewWithDnD_class = MediaListView self.PreviewFunction = QtGui.QPixmap( u':/media/media_video.png').toImage() - MediaManagerItem.__init__(self, parent, icon, title) + MediaManagerItem.__init__(self, parent, self, icon) self.singleServiceItem = False self.serviceItemIconName = u':/media/media_video.png' diff --git a/openlp/plugins/media/mediaplugin.py b/openlp/plugins/media/mediaplugin.py index e50333eb2..15a4d12c8 100644 --- a/openlp/plugins/media/mediaplugin.py +++ b/openlp/plugins/media/mediaplugin.py @@ -28,7 +28,7 @@ import logging from PyQt4.phonon import Phonon -from openlp.core.lib import Plugin, build_icon, translate +from openlp.core.lib import Plugin, StringContent, build_icon, translate from openlp.plugins.media.lib import MediaMediaItem log = logging.getLogger(__name__) @@ -70,9 +70,66 @@ class MediaPlugin(Plugin): def getMediaManagerItem(self): # Create the MediaManagerItem object - return MediaMediaItem(self, self.icon, self.name) + return MediaMediaItem(self, self, self.icon) def about(self): about_text = translate('MediaPlugin', 'Media Plugin' '
The media plugin provides playback of audio and video.') return about_text + + def setPluginTextStrings(self): + """ + Called to define all translatable texts of the plugin + """ + ## Name PluginList ## + self.textStrings[StringContent.Name] = { + u'singular': translate('MediaPlugin', 'Media'), + u'plural': translate('MediaPlugin', 'Media') + } + ## Name for MediaDockManager, SettingsManager ## + self.textStrings[StringContent.VisibleName] = { + u'title': translate('MediaPlugin', 'Media') + } + # Middle Header Bar + ## Load Button ## + self.textStrings[StringContent.Load] = { + u'title': translate('MediaPlugin', 'Load'), + u'tooltip': translate('MediaPlugin', + 'Load a new Media') + } + ## New Button ## + self.textStrings[StringContent.New] = { + u'title': translate('MediaPlugin', 'Add'), + u'tooltip': translate('MediaPlugin', + 'Add a new Media') + } + ## Edit Button ## + self.textStrings[StringContent.Edit] = { + u'title': translate('MediaPlugin', 'Edit'), + u'tooltip': translate('MediaPlugin', + 'Edit the selected Media') + } + ## Delete Button ## + self.textStrings[StringContent.Delete] = { + u'title': translate('MediaPlugin', 'Delete'), + u'tooltip': translate('MediaPlugin', + 'Delete the selected Media') + } + ## Preview ## + self.textStrings[StringContent.Preview] = { + u'title': translate('MediaPlugin', 'Preview'), + u'tooltip': translate('MediaPlugin', + 'Preview the selected Media') + } + ## Live Button ## + self.textStrings[StringContent.Live] = { + u'title': translate('MediaPlugin', 'Live'), + u'tooltip': translate('MediaPlugin', + 'Send the selected Media live') + } + ## Add to service Button ## + self.textStrings[StringContent.Service] = { + u'title': translate('MediaPlugin', 'Service'), + u'tooltip': translate('MediaPlugin', + 'Add the selected Media to the service') + } \ No newline at end of file diff --git a/openlp/plugins/presentations/lib/mediaitem.py b/openlp/plugins/presentations/lib/mediaitem.py index 60b455368..e6f456e5c 100644 --- a/openlp/plugins/presentations/lib/mediaitem.py +++ b/openlp/plugins/presentations/lib/mediaitem.py @@ -58,15 +58,12 @@ class PresentationMediaItem(MediaManagerItem): Constructor. Setup defaults """ self.controllers = controllers - self.PluginNameShort = u'Presentation' - self.pluginNameVisible = translate('PresentationPlugin.MediaItem', - 'Presentation') self.IconPath = u'presentations/presentation' self.Automatic = u'' # this next is a class, not an instance of a class - it will # be instanced by the base MediaManagerItem self.ListViewWithDnD_class = PresentationListView - MediaManagerItem.__init__(self, parent, icon, title) + MediaManagerItem.__init__(self, parent, self, icon) self.message_listener = MessageListener(self) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'mediaitem_presentation_rebuild'), self.rebuild) diff --git a/openlp/plugins/presentations/lib/presentationtab.py b/openlp/plugins/presentations/lib/presentationtab.py index c664221cc..a7b16cd5a 100644 --- a/openlp/plugins/presentations/lib/presentationtab.py +++ b/openlp/plugins/presentations/lib/presentationtab.py @@ -32,20 +32,18 @@ class PresentationTab(SettingsTab): """ PresentationsTab is the Presentations settings tab in the settings dialog. """ - def __init__(self, title, controllers): + def __init__(self, title, visible_title, controllers): """ Constructor """ self.controllers = controllers - SettingsTab.__init__(self, title) + SettingsTab.__init__(self, title, visible_title) def setupUi(self): """ Create the controls for the settings tab """ self.setObjectName(u'PresentationTab') - self.tabTitleVisible = translate('PresentationPlugin.PresentationTab', - 'Presentations') self.PresentationLayout = QtGui.QHBoxLayout(self) self.PresentationLayout.setSpacing(8) self.PresentationLayout.setMargin(8) diff --git a/openlp/plugins/presentations/presentationplugin.py b/openlp/plugins/presentations/presentationplugin.py index ada695625..780884075 100644 --- a/openlp/plugins/presentations/presentationplugin.py +++ b/openlp/plugins/presentations/presentationplugin.py @@ -30,7 +30,7 @@ presentations from a variety of document formats. import os import logging -from openlp.core.lib import Plugin, build_icon, translate +from openlp.core.lib import Plugin, StringContent, build_icon, translate from openlp.core.utils import AppLocation from openlp.plugins.presentations.lib import PresentationController, \ PresentationMediaItem, PresentationTab @@ -60,7 +60,8 @@ class PresentationPlugin(Plugin): """ Create the settings Tab """ - return PresentationTab(self.name, self.controllers) + visible_name = self.getString(StringContent.VisibleName) + return PresentationTab(self.name, visible_name[u'title'], self.controllers) def initialise(self): """ @@ -143,3 +144,48 @@ class PresentationPlugin(Plugin): 'programs. The choice of available presentation programs is ' 'available to the user in a drop down box.') return about_text + + def setPluginTextStrings(self): + """ + Called to define all translatable texts of the plugin + """ + ## Name PluginList ## + self.textStrings[StringContent.Name] = { + u'singular': translate('PresentationPlugin', 'Presentation'), + u'plural': translate('PresentationPlugin', 'Presentations') + } + ## Name for MediaDockManager, SettingsManager ## + self.textStrings[StringContent.VisibleName] = { + u'title': translate('PresentationPlugin', 'Presentations') + } + # Middle Header Bar + ## Load Button ## + self.textStrings[StringContent.Load] = { + u'title': translate('PresentationPlugin', 'Load'), + u'tooltip': translate('PresentationPlugin', + 'Load a new Presentation') + } + ## Delete Button ## + self.textStrings[StringContent.Delete] = { + u'title': translate('PresentationPlugin', 'Delete'), + u'tooltip': translate('PresentationPlugin', + 'Delete the selected Presentation') + } + ## Preview ## + self.textStrings[StringContent.Preview] = { + u'title': translate('PresentationPlugin', 'Preview'), + u'tooltip': translate('PresentationPlugin', + 'Preview the selected Presentation') + } + ## Live Button ## + self.textStrings[StringContent.Live] = { + u'title': translate('PresentationPlugin', 'Live'), + u'tooltip': translate('PresentationPlugin', + 'Send the selected Presentation live') + } + ## Add to service Button ## + self.textStrings[StringContent.Service] = { + u'title': translate('PresentationPlugin', 'Service'), + u'tooltip': translate('PresentationPlugin', + 'Add the selected Presentation to the service') + } \ No newline at end of file diff --git a/openlp/plugins/remotes/lib/remotetab.py b/openlp/plugins/remotes/lib/remotetab.py index ad1f4aac5..123aa291d 100644 --- a/openlp/plugins/remotes/lib/remotetab.py +++ b/openlp/plugins/remotes/lib/remotetab.py @@ -32,12 +32,11 @@ class RemoteTab(SettingsTab): """ RemoteTab is the Remotes settings tab in the settings dialog. """ - def __init__(self, title): - SettingsTab.__init__(self, title) + def __init__(self, title, visible_title): + SettingsTab.__init__(self, title, visible_title) def setupUi(self): self.setObjectName(u'RemoteTab') - self.tabTitleVisible = translate('RemotePlugin.RemoteTab', 'Remotes') self.remoteLayout = QtGui.QFormLayout(self) self.remoteLayout.setSpacing(8) self.remoteLayout.setMargin(8) diff --git a/openlp/plugins/remotes/remoteplugin.py b/openlp/plugins/remotes/remoteplugin.py index 927a706a3..4302486a3 100644 --- a/openlp/plugins/remotes/remoteplugin.py +++ b/openlp/plugins/remotes/remoteplugin.py @@ -26,7 +26,7 @@ import logging -from openlp.core.lib import Plugin, translate, build_icon +from openlp.core.lib import Plugin, StringContent, translate, build_icon from openlp.plugins.remotes.lib import RemoteTab, HttpServer log = logging.getLogger(__name__) @@ -65,7 +65,8 @@ class RemotesPlugin(Plugin): """ Create the settings Tab """ - return RemoteTab(self.name) + visible_name = self.getString(StringContent.VisibleName) + return RemoteTab(self.name, visible_name[u'title']) def about(self): """ @@ -76,3 +77,17 @@ class RemotesPlugin(Plugin): 'a running version of OpenLP on a different computer via a web ' 'browser or through the remote API.') return about_text + + def setPluginTextStrings(self): + """ + Called to define all translatable texts of the plugin + """ + ## Name PluginList ## + self.textStrings[StringContent.Name] = { + u'singular': translate('RemotePlugin', 'Remote'), + u'plural': translate('RemotePlugin', 'Remotes') + } + ## Name for MediaDockManager, SettingsManager ## + self.textStrings[StringContent.VisibleName] = { + u'title': translate('RemotePlugin', 'Remotes') + } \ No newline at end of file diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py index c62fa058e..3e5b41e46 100644 --- a/openlp/plugins/songs/forms/songimportform.py +++ b/openlp/plugins/songs/forms/songimportform.py @@ -112,6 +112,12 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): QtCore.QObject.connect(self.ewBrowseButton, QtCore.SIGNAL(u'clicked()'), self.onEWBrowseButtonClicked) + QtCore.QObject.connect(self.songBeamerAddButton, + QtCore.SIGNAL(u'clicked()'), + self.onSongBeamerAddButtonClicked) + QtCore.QObject.connect(self.songBeamerRemoveButton, + QtCore.SIGNAL(u'clicked()'), + self.onSongBeamerRemoveButtonClicked) QtCore.QObject.connect(self.cancelButton, QtCore.SIGNAL(u'clicked(bool)'), self.onCancelButtonClicked) @@ -227,23 +233,39 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): 'file to import from.')) self.ewBrowseButton.setFocus() return False + elif source_format == SongFormat.SongBeamer: + if self.songBeamerFileListWidget.count() == 0: + QtGui.QMessageBox.critical(self, + translate('SongsPlugin.ImportWizardForm', + 'No SongBeamer File Selected'), + translate('SongsPlugin.ImportWizardForm', + 'You need to add at least one SongBeamer ' + 'file to import from.')) + self.songBeamerAddButton.setFocus() + return False return True elif self.currentId() == 2: # Progress page return True - def getFileName(self, title, editbox): + def getFileName(self, title, editbox, + filters = '%s (*)' % translate('SongsPlugin.ImportWizardForm', + 'All Files')): filename = QtGui.QFileDialog.getOpenFileName(self, title, - SettingsManager.get_last_dir(self.plugin.settingsSection, 1)) + SettingsManager.get_last_dir(self.plugin.settingsSection, 1), + filters) if filename: editbox.setText(filename) SettingsManager.set_last_dir( self.plugin.settingsSection, os.path.split(unicode(filename))[0], 1) - def getFiles(self, title, listbox): + def getFiles(self, title, listbox, + filters = u'%s (*)' % translate('SongsPlugin.ImportWizardForm', + 'All Files')): filenames = QtGui.QFileDialog.getOpenFileNames(self, title, - SettingsManager.get_last_dir(self.plugin.settingsSection, 1)) + SettingsManager.get_last_dir(self.plugin.settingsSection, 1), + filters) if filenames: listbox.addItems(filenames) SettingsManager.set_last_dir( @@ -265,14 +287,24 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): self.getFileName( translate('SongsPlugin.ImportWizardForm', 'Select OpenLP 2.0 Database File'), - self.openLP2FilenameEdit + self.openLP2FilenameEdit, + u'%s (*.sqlite);;%s (*)' + % (translate('SongsPlugin.ImportWizardForm', + 'OpenLP 2.0 Databases'), + translate('SongsPlugin.ImportWizardForm', + 'All Files')) ) def onOpenLP1BrowseButtonClicked(self): self.getFileName( translate('SongsPlugin.ImportWizardForm', 'Select openlp.org 1.x Database File'), - self.openLP1FilenameEdit + self.openLP1FilenameEdit, + u'%s (*.olp);;%s (*)' + % (translate('SongsPlugin.ImportWizardForm', + 'openlp.org v1.x Databases'), + translate('SongsPlugin.ImportWizardForm', + 'All Files')) ) #def onOpenLyricsAddButtonClicked(self): @@ -299,7 +331,12 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): self.getFiles( translate('SongsPlugin.ImportWizardForm', 'Select Words of Worship Files'), - self.wordsOfWorshipFileListWidget + self.wordsOfWorshipFileListWidget, + u'%s (*.wsg *.wow-song);;%s (*)' + % (translate('SongsPlugin.ImportWizardForm', + 'Words Of Worship Song Files'), + translate('SongsPlugin.ImportWizardForm', + 'All Files')) ) def onWordsOfWorshipRemoveButtonClicked(self): @@ -319,7 +356,12 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): self.getFiles( translate('SongsPlugin.ImportWizardForm', 'Select Songs of Fellowship Files'), - self.songsOfFellowshipFileListWidget + self.songsOfFellowshipFileListWidget, + u'%s (*.rtf);;%s (*)' + % (translate('SongsPlugin.ImportWizardForm', + 'Songs Of Felloship Song Files'), + translate('SongsPlugin.ImportWizardForm', + 'All Files')) ) def onSongsOfFellowshipRemoveButtonClicked(self): @@ -342,6 +384,16 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): self.ewFilenameEdit ) + def onSongBeamerAddButtonClicked(self): + self.getFiles( + translate('SongsPlugin.ImportWizardForm', + 'Select SongBeamer Files'), + self.songBeamerFileListWidget + ) + + def onSongBeamerRemoveButtonClicked(self): + self.removeSelectedItems(self.songBeamerFileListWidget) + def onCancelButtonClicked(self, checked): """ Stop the import on pressing the cancel button. @@ -373,6 +425,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): self.songsOfFellowshipFileListWidget.clear() self.genericFileListWidget.clear() self.ewFilenameEdit.setText(u'') + self.songBeamerFileListWidget.clear() #self.csvFilenameEdit.setText(u'') def incrementProgressBar(self, status_text, increment=1): @@ -448,6 +501,12 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): importer = self.plugin.importSongs(SongFormat.EasyWorship, filename=unicode(self.ewFilenameEdit.text()) ) + elif source_format == SongFormat.SongBeamer: + # Import SongBeamer songs + importer = self.plugin.importSongs(SongFormat.SongBeamer, + filenames=self.getListOfFiles( + self.songBeamerFileListWidget) + ) success = importer.do_import() if success: # reload songs diff --git a/openlp/plugins/songs/forms/songimportwizard.py b/openlp/plugins/songs/forms/songimportwizard.py index bad85676f..5be8ccfba 100644 --- a/openlp/plugins/songs/forms/songimportwizard.py +++ b/openlp/plugins/songs/forms/songimportwizard.py @@ -116,6 +116,8 @@ class Ui_SongImportWizard(object): self.addMultiFileSelectItem(u'generic', None, True) # EasyWorship self.addSingleFileSelectItem(u'ew') + # Words of Worship + self.addMultiFileSelectItem(u'songBeamer') # Commented out for future use. # self.addSingleFileSelectItem(u'csv', u'CSV') self.sourceLayout.addWidget(self.formatStackedWidget) @@ -180,6 +182,8 @@ class Ui_SongImportWizard(object): 'Generic Document/Presentation')) self.formatComboBox.setItemText(8, translate('SongsPlugin.ImportWizardForm', 'EasyWorship')) + self.formatComboBox.setItemText(9, + translate('SongsPlugin.ImportWizardForm', 'SongBeamer')) # self.formatComboBox.setItemText(9, # translate('SongsPlugin.ImportWizardForm', 'CSV')) self.openLP2FilenameLabel.setText( @@ -236,6 +240,10 @@ class Ui_SongImportWizard(object): translate('SongsPlugin.ImportWizardForm', 'Filename:')) self.ewBrowseButton.setText( translate('SongsPlugin.ImportWizardForm', 'Browse...')) + self.songBeamerAddButton.setText( + translate('SongsPlugin.ImportWizardForm', 'Add Files...')) + self.songBeamerRemoveButton.setText( + translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) # self.csvFilenameLabel.setText( # translate('SongsPlugin.ImportWizardForm', 'Filename:')) # self.csvBrowseButton.setText( diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index d8028db24..63d19b95c 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -29,6 +29,7 @@ from olpimport import OpenLPSongImport from wowimport import WowImport from cclifileimport import CCLIFileImport from ewimport import EasyWorshipSongImport +from songbeamerimport import SongBeamerImport # Imports that might fail try: from olp1import import OpenLP1SongImport @@ -64,6 +65,7 @@ class SongFormat(object): Generic = 7 #CSV = 8 EasyWorship = 8 + SongBeamer = 9 @staticmethod def get_class(format): @@ -89,6 +91,8 @@ class SongFormat(object): return CCLIFileImport elif format == SongFormat.EasyWorship: return EasyWorshipSongImport + elif format == SongFormat.SongBeamer: + return SongBeamerImport # else: return None @@ -106,7 +110,8 @@ class SongFormat(object): SongFormat.CCLI, SongFormat.SongsOfFellowship, SongFormat.Generic, - SongFormat.EasyWorship + SongFormat.EasyWorship, + SongFormat.SongBeamer ] @staticmethod diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 008dae2d7..b50005486 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -48,12 +48,10 @@ class SongMediaItem(MediaManagerItem): """ log.info(u'Song Media Item loaded') - def __init__(self, parent, icon, title): - self.PluginNameShort = u'Song' - self.pluginNameVisible = translate('SongsPlugin.MediaItem', 'Song') + def __init__(self, parent, plugin, icon): self.IconPath = u'songs/song' self.ListViewWithDnD_class = SongListView - MediaManagerItem.__init__(self, parent, icon, title) + MediaManagerItem.__init__(self, parent, self, icon) self.edit_song_form = EditSongForm(self, self.parent.manager) self.singleServiceItem = False #self.edit_song_form = EditSongForm(self.parent.manager, self) @@ -62,6 +60,7 @@ class SongMediaItem(MediaManagerItem): # Holds information about whether the edit is remotly triggered and # which Song is required. self.remoteSong = -1 + self.editItem = None def requiredIcons(self): MediaManagerItem.requiredIcons(self) @@ -125,7 +124,7 @@ class SongMediaItem(MediaManagerItem): QtCore.SIGNAL(u'textChanged(const QString&)'), self.onSearchTextEditChanged) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'songs_load_list'), self.onSearchTextButtonClick) + QtCore.SIGNAL(u'songs_load_list'), self.onSongListLoad) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'config_updated'), self.configUpdated) QtCore.QObject.connect(Receiver.get_receiver(), @@ -139,6 +138,12 @@ class SongMediaItem(MediaManagerItem): self.searchAsYouType = QtCore.QSettings().value( self.settingsSection + u'/search as type', QtCore.QVariant(u'False')).toBool() + self.updateServiceOnEdit = QtCore.QSettings().value( + self.settingsSection + u'/update service on edit', + QtCore.QVariant(u'False')).toBool() + self.AddSongFromServide = QtCore.QSettings().value( + self.settingsSection + u'/add song from service', + QtCore.QVariant(u'True')).toBool() def retranslateUi(self): self.SearchTextLabel.setText( @@ -181,14 +186,26 @@ class SongMediaItem(MediaManagerItem): Author.display_name.like(u'%' + search_keywords + u'%'), Author.display_name.asc()) self.displayResultsAuthor(search_results) - #Called to redisplay the song list screen edith from a search - #or from the exit of the Song edit dialog. If remote editing is active - #Trigger it and clean up so it will not update again. + + def onSongListLoad(self): + """ + Handle the exit from the edit dialog and trigger remote updates + of songs + """ + # Called to redisplay the song list screen edit from a search + # or from the exit of the Song edit dialog. If remote editing is active + # Trigger it and clean up so it will not update again. if self.remoteTriggered == u'L': self.onAddClick() if self.remoteTriggered == u'P': self.onPreviewClick() + # Push edits to the service manager to update items + if self.editItem and self.updateServiceOnEdit and \ + not self.remoteTriggered: + item = self.buildServiceItem(self.editItem) + self.parent.serviceManager.replaceServiceItem(item) self.onRemoteEditClear() + self.onSearchTextButtonClick() def displayResultsSong(self, searchresults): log.debug(u'display results Song') @@ -273,8 +290,8 @@ class SongMediaItem(MediaManagerItem): if check_item_selected(self.listView, translate('SongsPlugin.MediaItem', 'You must select an item to edit.')): - item = self.listView.currentItem() - item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0] + self.editItem = self.listView.currentItem() + item_id = (self.editItem.data(QtCore.Qt.UserRole)).toInt()[0] self.edit_song_form.loadSong(item_id, False) self.edit_song_form.exec_() @@ -324,6 +341,8 @@ class SongMediaItem(MediaManagerItem): service_item.add_capability(ItemCapabilities.AllowsEdit) service_item.add_capability(ItemCapabilities.AllowsPreview) service_item.add_capability(ItemCapabilities.AllowsLoop) + service_item.add_capability(ItemCapabilities.OnLoadUpdate) + service_item.add_capability(ItemCapabilities.AddIfNewItem) song = self.parent.manager.get_object(Song, item_id) service_item.theme = song.theme_name service_item.editId = item_id @@ -370,4 +389,31 @@ class SongMediaItem(MediaManagerItem): service_item.audit = [ song.title, author_audit, song.copyright, unicode(song.ccli_number) ] + service_item.data_string = {u'title':song.search_title, u'authors':author_list} return True + + def serviceLoad(self, item): + """ + Triggered by a song being loaded by the service item + """ + if item.data_string: + search_results = self.parent.manager.get_all_objects(Song, + Song.search_title.like(u'%' + + item.data_string[u'title'].split(u'@')[0] + u'%'), + Song.search_title.asc()) + author_list = item.data_string[u'authors'].split(u',') + editId = 0 + uuid = 0 + if search_results: + for song in search_results: + count = 0 + for author in song.authors: + if author.display_name in author_list: + count += 1 + if count == len(author_list): + editId = song.id + uuid = item._uuid + if editId != 0: + Receiver.send_message(u'service_item_update', + u'%s:%s' %(editId, uuid)) + diff --git a/openlp/plugins/songs/lib/songbeamerimport.py b/openlp/plugins/songs/lib/songbeamerimport.py new file mode 100644 index 000000000..a839e2418 --- /dev/null +++ b/openlp/plugins/songs/lib/songbeamerimport.py @@ -0,0 +1,236 @@ +# -*- 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, Meinert Jordan, Andreas Preikschat, Christian # +# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, # +# Carsten Tinggaard, Frode Woldsund # +# --------------------------------------------------------------------------- # +# 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 # +############################################################################### +""" +The :mod:`songbeamerimport` module provides the functionality for importing + SongBeamer songs into the OpenLP database. +""" +import logging +import os +import re +import chardet +import codecs + +from openlp.plugins.songs.lib.songimport import SongImport + +log = logging.getLogger(__name__) + +class SongBeamerTypes(object): + MarkTypes = { + u'Refrain': u'C', + u'Chorus': u'C', + u'Vers': u'V', + u'Verse': u'V', + u'Strophe': u'V', + u'Intro': u'I', + u'Coda': u'E', + u'Ending': u'E', + u'Bridge': u'B', + u'Interlude': u'B', + u'Zwischenspiel': u'B', + u'Pre-Chorus': u'P', + u'Pre-Refrain': u'P', + u'Pre-Bridge': u'O', + u'Pre-Coda': u'O', + u'Unbekannt': u'O', + u'Unknown': u'O' + } + +class SongBeamerImport(SongImport): + """ + Import Song Beamer files(s) + Song Beamer file format is text based + in the beginning are one or more control tags written + """ + def __init__(self, master_manager, **kwargs): + """ + Initialise the import. + ``master_manager`` + The song manager for the running OpenLP installation. + """ + SongImport.__init__(self, master_manager) + self.master_manager = master_manager + if kwargs.has_key(u'filename'): + self.import_source = kwargs[u'filename'] + if kwargs.has_key(u'filenames'): + self.import_source = kwargs[u'filenames'] + log.debug(self.import_source) + + def do_import(self): + """ + Recieve a single file, or a list of files to import. + """ + if isinstance(self.import_source, list): + self.import_wizard.importProgressBar.setMaximum( + len(self.import_source)) + for file in self.import_source: + # TODO: check that it is a valid SongBeamer file + self.current_verse = u'' + self.current_verse_type = u'V' + self.file_name = os.path.split(file)[1] + self.import_wizard.incrementProgressBar( + "Importing %s" % (self.file_name), 0) + if os.path.isfile(file): + detect_file = open(file, u'r') + details = chardet.detect(detect_file.read(2048)) + detect_file.close() + infile = codecs.open(file, u'r', details['encoding']) + self.songData = infile.readlines() + else: + return False + for line in self.songData: + line = line.strip() + if line.startswith('#'): + log.debug(u'find tag: %s' % line) + if not self.parse_tags(line): + return False + elif line.startswith('---'): + log.debug(u'find ---') + if len(self.current_verse) > 0: + self.add_verse(self.current_verse, + self.current_verse_type) + self.current_verse = u'' + self.current_verse_type = u'V' + self.read_verse = True + self.verse_start = True + elif self.read_verse: + if self.verse_start: + self.check_verse_marks(line) + self.verse_start = False + else: + self.current_verse += u'%s\n' % line + if len(self.current_verse) > 0: + self.add_verse(self.current_verse, self.current_verse_type) + self.finish() + self.import_wizard.incrementProgressBar( + "Importing %s" % (self.file_name)) + return True + + def parse_tags(self, line): + tag_val = line.split('=') + if len(tag_val[0]) == 0 or \ + len(tag_val[1]) == 0: + return True + if tag_val[0] == '#(c)': + self.add_copyright(tag_val[1]) + elif tag_val[0] == '#AddCopyrightInfo': + pass + elif tag_val[0] == '#Author': + #TODO split Authors + self.add_author(tag_val[1]) + elif tag_val[0] == '#BackgroundImage': + pass + elif tag_val[0] == '#Bible': + pass + elif tag_val[0] == '#Categories': + self.topics = line.split(',') + elif tag_val[0] == '#CCLI': + self.ccli_number = tag_val[1] + elif tag_val[0] == '#Chords': + pass + elif tag_val[0] == '#ChurchSongID': + pass + elif tag_val[0] == '#ColorChords': + pass + elif tag_val[0] == '#Comments': + self.comments = tag_val[1] + elif tag_val[0] == '#Editor': + pass + elif tag_val[0] == '#Font': + pass + elif tag_val[0] == '#FontLang2': + pass + elif tag_val[0] == '#FontSize': + pass + elif tag_val[0] == '#Format': + pass + elif tag_val[0] == '#Format_PreLine': + pass + elif tag_val[0] == '#Format_PrePage': + pass + elif tag_val[0] == '#ID': + pass + elif tag_val[0] == '#Key': + pass + elif tag_val[0] == '#Keywords': + pass + elif tag_val[0] == '#LangCount': + pass + elif tag_val[0] == '#Melody': + #TODO split Authors + self.add_author(tag_val[1]) + elif tag_val[0] == '#NatCopyright': + pass + elif tag_val[0] == '#OTitle': + pass + elif tag_val[0] == '#OutlineColor': + pass + elif tag_val[0] == '#OutlinedFont': + pass + elif tag_val[0] == '#QuickFind': + pass + elif tag_val[0] == '#Rights': + song_book_pub = tag_val[1] + elif tag_val[0] == '#Songbook': + book_num = tag_val[1].split(' / ') + self.song_book_name = book_num[0] + if len(book_num) == book_num[1]: + self.song_number = u'' + elif tag_val[0] == '#Speed': + pass + elif tag_val[0] == '#TextAlign': + pass + elif tag_val[0] == '#Title': + self.title = u'%s' % tag_val[1] + elif tag_val[0] == '#TitleAlign': + pass + elif tag_val[0] == '#TitleFontSize': + pass + elif tag_val[0] == '#TitleLang2': + pass + elif tag_val[0] == '#TitleLang3': + pass + elif tag_val[0] == '#TitleLang4': + pass + elif tag_val[0] == '#Translation': + pass + elif tag_val[0] == '#Transpose': + pass + elif tag_val[0] == '#TransposeAccidental': + pass + elif tag_val[0] == '#Version': + pass + else: + pass + return True + + def check_verse_marks(self, line): + marks = line.split(' ') + if len(marks) <= 2 and \ + marks[0] in SongBeamerTypes.MarkTypes: + self.current_verse_type = SongBeamerTypes.MarkTypes[marks[0]] + if len(marks) == 2: + #TODO: may check, because of only digits are allowed + self.current_verse_type += marks[1] diff --git a/openlp/plugins/songs/lib/songstab.py b/openlp/plugins/songs/lib/songstab.py index 274370065..03c1e8844 100644 --- a/openlp/plugins/songs/lib/songstab.py +++ b/openlp/plugins/songs/lib/songstab.py @@ -32,12 +32,11 @@ class SongsTab(SettingsTab): """ SongsTab is the Songs settings tab in the settings dialog. """ - def __init__(self, title): - SettingsTab.__init__(self, title) + def __init__(self, title, visible_title): + SettingsTab.__init__(self, title, visible_title) def setupUi(self): self.setObjectName(u'SongsTab') - self.tabTitleVisible = translate('SongsPlugin.SongsTab', 'Songs') self.SongsLayout = QtGui.QFormLayout(self) self.SongsLayout.setSpacing(8) self.SongsLayout.setMargin(8) @@ -52,8 +51,14 @@ class SongsTab(SettingsTab): self.SearchAsTypeCheckBox.setObjectName(u'SearchAsTypeCheckBox') self.SongsModeLayout.addWidget(self.SearchAsTypeCheckBox) self.SongBarActiveCheckBox = QtGui.QCheckBox(self.SongsModeGroupBox) - self.SongBarActiveCheckBox.setObjectName(u'SearchAsTypeCheckBox') + self.SongBarActiveCheckBox.setObjectName(u'SongBarActiveCheckBox') self.SongsModeLayout.addWidget(self.SongBarActiveCheckBox) + self.SongUpdateOnEditCheckBox = QtGui.QCheckBox(self.SongsModeGroupBox) + self.SongUpdateOnEditCheckBox.setObjectName(u'SongUpdateOnEditCheckBox') + self.SongsModeLayout.addWidget(self.SongUpdateOnEditCheckBox) + self.SongAddFromServiceCheckBox = QtGui.QCheckBox(self.SongsModeGroupBox) + self.SongAddFromServiceCheckBox.setObjectName(u'SongAddFromServiceCheckBox') + self.SongsModeLayout.addWidget(self.SongAddFromServiceCheckBox) self.SongsLayout.setWidget( 0, QtGui.QFormLayout.LabelRole, self.SongsModeGroupBox) QtCore.QObject.connect(self.SearchAsTypeCheckBox, @@ -61,7 +66,13 @@ class SongsTab(SettingsTab): self.onSearchAsTypeCheckBoxChanged) QtCore.QObject.connect(self.SongBarActiveCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), - self.SongBarActiveCheckBoxChanged) + self.onSongBarActiveCheckBoxChanged) + QtCore.QObject.connect(self.SongUpdateOnEditCheckBox, + QtCore.SIGNAL(u'stateChanged(int)'), + self.onSongUpdateOnEditCheckBoxChanged) + QtCore.QObject.connect(self.SongBarActiveCheckBox, + QtCore.SIGNAL(u'stateChanged(int)'), + self.onSongAddFromServiceCheckBoxChanged) def retranslateUi(self): self.SongsModeGroupBox.setTitle( @@ -70,6 +81,10 @@ class SongsTab(SettingsTab): translate('SongsPlugin.SongsTab', 'Enable search as you type')) self.SongBarActiveCheckBox.setText(translate('SongsPlugin.SongsTab', 'Display verses on live tool bar')) + self.SongUpdateOnEditCheckBox.setText( + translate('SongsPlugin.SongsTab', 'Update service from song edit')) + self.SongAddFromServiceCheckBox.setText(translate('SongsPlugin.SongsTab', + 'Add missing songs when opening service')) def onSearchAsTypeCheckBoxChanged(self, check_state): self.song_search = False @@ -77,12 +92,24 @@ class SongsTab(SettingsTab): if check_state == QtCore.Qt.Checked: self.song_search = True - def SongBarActiveCheckBoxChanged(self, check_state): + def onSongBarActiveCheckBoxChanged(self, check_state): self.song_bar = False # we have a set value convert to True/False if check_state == QtCore.Qt.Checked: self.song_bar = True + def onSongUpdateOnEditCheckBoxChanged(self, check_state): + self.update_edit = False + # we have a set value convert to True/False + if check_state == QtCore.Qt.Checked: + self.update_edit = True + + def onSongAddFromServiceCheckBoxChanged(self, check_state): + self.update_load = False + # we have a set value convert to True/False + if check_state == QtCore.Qt.Checked: + self.update_load = True + def load(self): settings = QtCore.QSettings() settings.beginGroup(self.settingsSection) @@ -90,8 +117,14 @@ class SongsTab(SettingsTab): u'search as type', QtCore.QVariant(False)).toBool() self.song_bar = settings.value( u'display songbar', QtCore.QVariant(True)).toBool() + self.update_edit = settings.value( + u'update service on edit', QtCore.QVariant(False)).toBool() + self.update_load = settings.value( + u'add song from service', QtCore.QVariant(True)).toBool() self.SearchAsTypeCheckBox.setChecked(self.song_search) self.SongBarActiveCheckBox.setChecked(self.song_bar) + self.SongUpdateOnEditCheckBox.setChecked(self.update_edit) + self.SongAddFromServiceCheckBox.setChecked(self.update_load) settings.endGroup() def save(self): @@ -99,4 +132,6 @@ class SongsTab(SettingsTab): settings.beginGroup(self.settingsSection) settings.setValue(u'search as type', QtCore.QVariant(self.song_search)) settings.setValue(u'display songbar', QtCore.QVariant(self.song_bar)) + settings.setValue(u'update service on edit', QtCore.QVariant(self.update_edit)) + settings.setValue(u'add song from service', QtCore.QVariant(self.update_load)) settings.endGroup() diff --git a/openlp/plugins/songs/lib/wowimport.py b/openlp/plugins/songs/lib/wowimport.py index 474a9b19d..879d56704 100644 --- a/openlp/plugins/songs/lib/wowimport.py +++ b/openlp/plugins/songs/lib/wowimport.py @@ -116,16 +116,16 @@ class WowImport(SongImport): self.import_wizard.importProgressBar.setMaximum( len(self.import_source)) for file in self.import_source: - # TODO: check that it is a valid words of worship file (could - # check header for WoW File Song Word) self.author = u'' self.copyright = u'' - # Get the song title self.file_name = os.path.split(file)[1] self.import_wizard.incrementProgressBar( "Importing %s" % (self.file_name), 0) + # Get the song title self.title = self.file_name.rpartition(u'.')[0] self.songData = open(file, 'rb') + if self.songData.read(19) != u'WoW File\nSong Words': + continue # Seek to byte which stores number of blocks in the song self.songData.seek(56) self.no_of_blocks = ord(self.songData.read(1)) diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index 27d71cdd7..47ae72632 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -28,7 +28,7 @@ import logging from PyQt4 import QtCore, QtGui -from openlp.core.lib import Plugin, build_icon, translate +from openlp.core.lib import Plugin, StringContent, build_icon, translate from openlp.core.lib.db import Manager from openlp.plugins.songs.lib import SongMediaItem, SongsTab from openlp.plugins.songs.lib.db import init_schema, Song @@ -57,7 +57,8 @@ class SongsPlugin(Plugin): self.icon = build_icon(self.icon_path) def getSettingsTab(self): - return SongsTab(self.name) + visible_name = self.getString(StringContent.VisibleName) + return SongsTab(self.name, visible_name[u'title']) def initialise(self): log.info(u'Songs Initialising') @@ -70,7 +71,7 @@ class SongsPlugin(Plugin): Create the MediaManagerItem object, which is displaed in the Media Manager. """ - return SongMediaItem(self, self.icon, self.name) + return SongMediaItem(self, self, self.icon) def addImportMenuItem(self, import_menu): """ @@ -147,3 +148,54 @@ class SongsPlugin(Plugin): importer = class_(self.manager, **kwargs) importer.register(self.mediaItem.import_wizard) return importer + + def setPluginTextStrings(self): + """ + Called to define all translatable texts of the plugin + """ + ## Name PluginList ## + self.textStrings[StringContent.Name] = { + u'singular': translate('SongsPlugin', 'Song'), + u'plural': translate('SongsPlugin', 'Songs') + } + ## Name for MediaDockManager, SettingsManager ## + self.textStrings[StringContent.VisibleName] = { + u'title': translate('SongsPlugin', 'Songs') + } + # Middle Header Bar + ## New Button ## + self.textStrings[StringContent.New] = { + u'title': translate('SongsPlugin', 'Add'), + u'tooltip': translate('SongsPlugin', + 'Add a new Song') + } + ## Edit Button ## + self.textStrings[StringContent.Edit] = { + u'title': translate('SongsPlugin', 'Edit'), + u'tooltip': translate('SongsPlugin', + 'Edit the selected Song') + } + ## Delete Button ## + self.textStrings[StringContent.Delete] = { + u'title': translate('SongsPlugin', 'Delete'), + u'tooltip': translate('SongsPlugin', + 'Delete the selected Song') + } + ## Preview ## + self.textStrings[StringContent.Preview] = { + u'title': translate('SongsPlugin', 'Preview'), + u'tooltip': translate('SongsPlugin', + 'Preview the selected Song') + } + ## Live Button ## + self.textStrings[StringContent.Live] = { + u'title': translate('SongsPlugin', 'Live'), + u'tooltip': translate('SongsPlugin', + 'Send the selected Song live') + } + ## Add to service Button ## + self.textStrings[StringContent.Service] = { + u'title': translate('SongsPlugin', 'Service'), + u'tooltip': translate('SongsPlugin', + 'Add the selected Song to the service') + } \ No newline at end of file diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index f0eb1f73d..c4eb55adc 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -29,7 +29,7 @@ from datetime import datetime from PyQt4 import QtCore, QtGui -from openlp.core.lib import Plugin, Receiver, build_icon, translate +from openlp.core.lib import Plugin, StringContent, Receiver, build_icon, translate from openlp.core.lib.db import Manager from openlp.plugins.songusage.forms import SongUsageDetailForm, \ SongUsageDeleteForm @@ -162,3 +162,17 @@ class SongUsagePlugin(Plugin): '
This plugin tracks the usage of songs in ' 'services.') return about_text + + def setPluginTextStrings(self): + """ + Called to define all translatable texts of the plugin + """ + ## Name PluginList ## + self.textStrings[StringContent.Name] = { + u'singular': translate('SongUsagePlugin', 'SongUsage'), + u'plural': translate('SongUsagePlugin', 'SongUsage') + } + ## Name for MediaDockManager, SettingsManager ## + self.textStrings[StringContent.VisibleName] = { + u'title': translate('SongUsagePlugin', 'SongUsage') + } \ No newline at end of file