forked from openlp/openlp
Add some small items from wish lists
Various cleanups. -------------------------------------------------------------------------------- lp:~trb143/openlp/cleanups02182 (revision 2835) https://ci.openlp.io/job/Branch-01-Pull/2480/ [SUCCESS] https://ci.openlp.io/job/Branch-02a-Linux-Tests/2381/ [SUCCESS] https://ci.openlp.io/job/Branch-02b-macOS-Tests/168/ [FAILURE] https://ci.openlp.io/job/Branch-03a-Build-Source/90/ ... bzr-revno: 2814
This commit is contained in:
commit
5b5dd16e13
@ -91,6 +91,7 @@ def controller_text(request):
|
||||
item['text'] = str(frame['title'])
|
||||
item['html'] = str(frame['title'])
|
||||
item['selected'] = (live_controller.selected_row == index)
|
||||
item['title'] = current_item.title
|
||||
data.append(item)
|
||||
json_data = {'results': {'slides': data}}
|
||||
if current_item:
|
||||
@ -117,12 +118,11 @@ def controller_set(request):
|
||||
return {'results': {'success': True}}
|
||||
|
||||
|
||||
@controller_endpoint.route('{action:next|previous}')
|
||||
@controller_endpoint.route('{controller}/{action:next|previous}')
|
||||
@requires_auth
|
||||
def controller_direction(request, controller, action):
|
||||
"""
|
||||
Handles requests for setting service items in the slide controller
|
||||
11
|
||||
:param request: The http request object.
|
||||
:param controller: the controller slides forward or backward.
|
||||
:param action: the controller slides forward or backward.
|
||||
@ -137,7 +137,7 @@ def controller_direction(request, controller, action):
|
||||
def controller_direction_api(request, controller, action):
|
||||
"""
|
||||
Handles requests for setting service items in the slide controller
|
||||
11
|
||||
|
||||
:param request: The http request object.
|
||||
:param controller: the controller slides forward or backward.
|
||||
:param action: the controller slides forward or backward.
|
||||
|
@ -62,7 +62,7 @@ def get_local_ip4():
|
||||
"""
|
||||
# Get the local IPv4 active address(es) that are NOT localhost (lo or '127.0.0.1')
|
||||
log.debug('Getting local IPv4 interface(es) information')
|
||||
MY_IP4 = {}
|
||||
my_ip4 = {}
|
||||
for iface in QNetworkInterface.allInterfaces():
|
||||
if not iface.isValid() or not (iface.flags() & (QNetworkInterface.IsUp | QNetworkInterface.IsRunning)):
|
||||
continue
|
||||
@ -70,25 +70,25 @@ def get_local_ip4():
|
||||
ip = address.ip()
|
||||
# NOTE: Next line will skip if interface is localhost - keep for now until we decide about it later
|
||||
# if (ip.protocol() == QAbstractSocket.IPv4Protocol) and (ip != QHostAddress.LocalHost):
|
||||
if (ip.protocol() == QAbstractSocket.IPv4Protocol):
|
||||
MY_IP4[iface.name()] = {'ip': ip.toString(),
|
||||
if ip.protocol() == QAbstractSocket.IPv4Protocol:
|
||||
my_ip4[iface.name()] = {'ip': ip.toString(),
|
||||
'broadcast': address.broadcast().toString(),
|
||||
'netmask': address.netmask().toString(),
|
||||
'prefix': address.prefixLength(),
|
||||
'localnet': QHostAddress(address.netmask().toIPv4Address() &
|
||||
ip.toIPv4Address()).toString()
|
||||
ip.toIPv4Address()).toString()
|
||||
}
|
||||
log.debug('Adding {iface} to active list'.format(iface=iface.name()))
|
||||
if len(MY_IP4) == 1:
|
||||
if 'lo' in MY_IP4:
|
||||
if len(my_ip4) == 1:
|
||||
if 'lo' in my_ip4:
|
||||
# No active interfaces - so leave localhost in there
|
||||
log.warning('No active IPv4 interfaces found except localhost')
|
||||
else:
|
||||
# Since we have a valid IP4 interface, remove localhost
|
||||
log.debug('Found at least one IPv4 interface, removing localhost')
|
||||
MY_IP4.pop('lo')
|
||||
my_ip4.pop('lo')
|
||||
|
||||
return MY_IP4
|
||||
return my_ip4
|
||||
|
||||
|
||||
def trace_error_handler(logger):
|
||||
|
@ -121,6 +121,9 @@ class ItemCapabilities(object):
|
||||
|
||||
``HasThumbnails``
|
||||
The item has related thumbnails available
|
||||
|
||||
``HasMetaData``
|
||||
The item has Meta Data about item
|
||||
"""
|
||||
CanPreview = 1
|
||||
CanEdit = 2
|
||||
@ -143,6 +146,7 @@ class ItemCapabilities(object):
|
||||
HasDisplayTitle = 19
|
||||
HasNotes = 20
|
||||
HasThumbnails = 21
|
||||
HasMetaData = 22
|
||||
|
||||
|
||||
class ServiceItem(RegistryProperties):
|
||||
@ -200,6 +204,7 @@ class ServiceItem(RegistryProperties):
|
||||
self.will_auto_start = False
|
||||
self.has_original_files = True
|
||||
self._new_item()
|
||||
self.metadata = []
|
||||
|
||||
def _new_item(self):
|
||||
"""
|
||||
@ -375,7 +380,8 @@ class ServiceItem(RegistryProperties):
|
||||
'background_audio': self.background_audio,
|
||||
'theme_overwritten': self.theme_overwritten,
|
||||
'will_auto_start': self.will_auto_start,
|
||||
'processor': self.processor
|
||||
'processor': self.processor,
|
||||
'metadata': self.metadata
|
||||
}
|
||||
service_data = []
|
||||
if self.service_item_type == ServiceItemType.Text:
|
||||
@ -426,6 +432,7 @@ class ServiceItem(RegistryProperties):
|
||||
self.will_auto_start = header.get('will_auto_start', False)
|
||||
self.processor = header.get('processor', None)
|
||||
self.has_original_files = True
|
||||
self.metadata = header.get('item_meta_data', [])
|
||||
if 'background_audio' in header:
|
||||
self.background_audio = []
|
||||
for file_path in header['background_audio']:
|
||||
|
@ -127,9 +127,6 @@ class UiFirstTimeWizard(object):
|
||||
self.media_check_box.setChecked(True)
|
||||
self.media_check_box.setObjectName('media_check_box')
|
||||
self.plugin_layout.addWidget(self.media_check_box)
|
||||
self.remote_check_box = QtWidgets.QCheckBox(self.plugin_page)
|
||||
self.remote_check_box.setObjectName('remote_check_box')
|
||||
self.plugin_layout.addWidget(self.remote_check_box)
|
||||
self.song_usage_check_box = QtWidgets.QCheckBox(self.plugin_page)
|
||||
self.song_usage_check_box.setChecked(True)
|
||||
self.song_usage_check_box.setObjectName('song_usage_check_box')
|
||||
@ -138,13 +135,6 @@ class UiFirstTimeWizard(object):
|
||||
self.alert_check_box.setChecked(True)
|
||||
self.alert_check_box.setObjectName('alert_check_box')
|
||||
self.plugin_layout.addWidget(self.alert_check_box)
|
||||
self.projectors_check_box = QtWidgets.QCheckBox(self.plugin_page)
|
||||
# If visibility setting for projector panel is True, check the box.
|
||||
if Settings().value('projector/show after wizard'):
|
||||
self.projectors_check_box.setChecked(True)
|
||||
self.projectors_check_box.setObjectName('projectors_check_box')
|
||||
self.projectors_check_box.clicked.connect(self.on_projectors_check_box_clicked)
|
||||
self.plugin_layout.addWidget(self.projectors_check_box)
|
||||
first_time_wizard.setPage(FirstTimePage.Plugins, self.plugin_page)
|
||||
# The song samples page
|
||||
self.songs_page = QtWidgets.QWizardPage()
|
||||
@ -256,13 +246,9 @@ class UiFirstTimeWizard(object):
|
||||
self.presentation_check_box.setText(translate('OpenLP.FirstTimeWizard',
|
||||
'Presentations – Show .ppt, .odp and .pdf files'))
|
||||
self.media_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Media – Playback of Audio and Video files'))
|
||||
self.remote_check_box.setText(str(UiStrings().WebDownloadText))
|
||||
self.song_usage_check_box.setText(translate('OpenLP.FirstTimeWizard', 'Song Usage Monitor'))
|
||||
self.alert_check_box.setText(translate('OpenLP.FirstTimeWizard',
|
||||
'Alerts – Display informative messages while showing other slides'))
|
||||
self.projectors_check_box.setText(translate('OpenLP.FirstTimeWizard',
|
||||
'Projector Controller – Control PJLink compatible projects on your'
|
||||
' network from OpenLP'))
|
||||
self.no_internet_page.setTitle(translate('OpenLP.FirstTimeWizard', 'No Internet Connection'))
|
||||
self.no_internet_page.setSubTitle(
|
||||
translate('OpenLP.FirstTimeWizard', 'Unable to detect an Internet connection.'))
|
||||
|
@ -179,7 +179,6 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties):
|
||||
"""
|
||||
Check to see if we have any media Player's available.
|
||||
"""
|
||||
log.debug('_check_available_media_players')
|
||||
controller_dir = os.path.join('core', 'ui', 'media')
|
||||
# Find all files that do not begin with '.' (lp:#1738047) and end with player.py
|
||||
glob_pattern = os.path.join(controller_dir, '[!.]*player.py')
|
||||
|
@ -751,7 +751,7 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi
|
||||
|
||||
def context_menu(self, point):
|
||||
"""
|
||||
The Right click context menu from the Serviceitem list
|
||||
The Right click context menu from the Service item list
|
||||
|
||||
:param point: The location of the cursor.
|
||||
"""
|
||||
@ -1136,7 +1136,6 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi
|
||||
def on_delete_from_service(self):
|
||||
"""
|
||||
Remove the current ServiceItem from the list.
|
||||
:param field:
|
||||
"""
|
||||
item = self.find_service_item()[0]
|
||||
if item != -1:
|
||||
@ -1205,6 +1204,9 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi
|
||||
tips.append('<strong>{text1}: </strong> {text2}'.format(text1=text1, text2=text2))
|
||||
if item['service_item'].is_capable(ItemCapabilities.HasVariableStartTime):
|
||||
tips.append(item['service_item'].get_media_time())
|
||||
if item['service_item'].is_capable(ItemCapabilities.HasMetaData):
|
||||
for meta in item['service_item'].metadata:
|
||||
tips.append(meta)
|
||||
tree_widget_item.setToolTip(0, '<br>'.join(tips))
|
||||
tree_widget_item.setData(0, QtCore.Qt.UserRole, item['order'])
|
||||
tree_widget_item.setSelected(item['selected'])
|
||||
@ -1362,7 +1364,6 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi
|
||||
def make_preview(self):
|
||||
"""
|
||||
Send the current item to the Preview slide controller
|
||||
:param field:
|
||||
"""
|
||||
self.application.set_busy_cursor()
|
||||
item, child = self.find_service_item()
|
||||
@ -1387,7 +1388,6 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi
|
||||
def on_double_click_live(self):
|
||||
"""
|
||||
Send the current item to the Live slide controller but triggered by a tablewidget click event.
|
||||
:param field:
|
||||
"""
|
||||
self.list_double_clicked = True
|
||||
self.make_live()
|
||||
@ -1396,7 +1396,6 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi
|
||||
"""
|
||||
If single click previewing is enabled, and triggered by a tablewidget click event,
|
||||
start a timeout to verify a double-click hasn't triggered.
|
||||
:param field:
|
||||
"""
|
||||
if Settings().value('advanced/single click service preview'):
|
||||
if not self.list_double_clicked:
|
||||
@ -1407,7 +1406,6 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi
|
||||
def on_single_click_preview_timeout(self):
|
||||
"""
|
||||
If a single click ok, but double click not triggered, send the current item to the Preview slide controller.
|
||||
:param field:
|
||||
"""
|
||||
if self.list_double_clicked:
|
||||
# If a double click has registered, clear it.
|
||||
@ -1447,7 +1445,6 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi
|
||||
def remote_edit(self):
|
||||
"""
|
||||
Triggers a remote edit to a plugin to allow item to be edited.
|
||||
:param field:
|
||||
"""
|
||||
item = self.find_service_item()[0]
|
||||
if self.service_items[item]['service_item'].is_capable(ItemCapabilities.CanEdit):
|
||||
@ -1459,8 +1456,6 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi
|
||||
def on_service_item_rename(self):
|
||||
"""
|
||||
Opens a dialog to rename the service item.
|
||||
|
||||
:param field: Not used, but PyQt needs this.
|
||||
"""
|
||||
item = self.find_service_item()[0]
|
||||
if not self.service_items[item]['service_item'].is_capable(ItemCapabilities.CanEditTitle):
|
||||
@ -1477,7 +1472,6 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi
|
||||
def create_custom(self):
|
||||
"""
|
||||
Saves the current text item as a custom slide
|
||||
:param field:
|
||||
"""
|
||||
item = self.find_service_item()[0]
|
||||
Registry().execute('custom_create_from_service', self.service_items[item]['service_item'])
|
||||
@ -1597,8 +1591,6 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi
|
||||
def on_theme_change_action(self):
|
||||
"""
|
||||
Handles theme change events
|
||||
|
||||
:param field:
|
||||
"""
|
||||
theme = self.sender().objectName()
|
||||
# No object name means that the "Default" theme is supposed to be used.
|
||||
|
@ -318,6 +318,10 @@ class SlideController(DisplayController, LogMixin, RegistryProperties):
|
||||
tooltip=translate('OpenLP.SlideController',
|
||||
'Edit and reload song preview.'),
|
||||
triggers=self.on_edit_song)
|
||||
self.toolbar.add_toolbar_action('clear', icon=':/general/general_delete.png',
|
||||
tooltip=translate('OpenLP.SlideController',
|
||||
'Clear'),
|
||||
triggers=self.on_clear)
|
||||
self.controller_layout.addWidget(self.toolbar)
|
||||
# Build the Media Toolbar
|
||||
self.media_controller.register_controller(self)
|
||||
@ -356,7 +360,7 @@ class SlideController(DisplayController, LogMixin, RegistryProperties):
|
||||
self.audio_time_label.setObjectName('audio_time_label')
|
||||
self.toolbar.add_toolbar_widget(self.audio_time_label)
|
||||
self.toolbar.set_widget_visible(AUDIO_LIST, False)
|
||||
self.toolbar.set_widget_visible(['song_menu'], False)
|
||||
self.toolbar.set_widget_visible('song_menu', False)
|
||||
# Screen preview area
|
||||
self.preview_frame = QtWidgets.QFrame(self.splitter)
|
||||
self.preview_frame.setGeometry(QtCore.QRect(0, 0, 300, 300 * self.ratio))
|
||||
@ -427,7 +431,8 @@ class SlideController(DisplayController, LogMixin, RegistryProperties):
|
||||
self.__add_actions_to_widget(self.controller)
|
||||
else:
|
||||
self.preview_widget.doubleClicked.connect(self.on_preview_double_click)
|
||||
self.toolbar.set_widget_visible(['editSong'], False)
|
||||
self.toolbar.set_widget_visible('editSong', False)
|
||||
self.toolbar.set_widget_visible('clear', False)
|
||||
self.controller.addActions([self.next_item, self.previous_item])
|
||||
Registry().register_function('slidecontroller_{text}_stop_loop'.format(text=self.type_prefix),
|
||||
self.on_stop_loop)
|
||||
@ -726,7 +731,7 @@ class SlideController(DisplayController, LogMixin, RegistryProperties):
|
||||
self.mediabar.hide()
|
||||
self.song_menu.hide()
|
||||
self.toolbar.set_widget_visible(LOOP_LIST, False)
|
||||
self.toolbar.set_widget_visible(['song_menu'], False)
|
||||
self.toolbar.set_widget_visible('song_menu', False)
|
||||
# Reset the button
|
||||
self.play_slides_once.setChecked(False)
|
||||
self.play_slides_once.setIcon(build_icon(':/media/media_time.png'))
|
||||
@ -737,7 +742,7 @@ class SlideController(DisplayController, LogMixin, RegistryProperties):
|
||||
if item.is_text():
|
||||
if (Settings().value(self.main_window.songs_settings_section + '/display songbar') and
|
||||
not self.song_menu.menu().isEmpty()):
|
||||
self.toolbar.set_widget_visible(['song_menu'], True)
|
||||
self.toolbar.set_widget_visible('song_menu', True)
|
||||
if item.is_capable(ItemCapabilities.CanLoop) and len(item.get_frames()) > 1:
|
||||
self.toolbar.set_widget_visible(LOOP_LIST)
|
||||
if item.is_media():
|
||||
@ -762,9 +767,10 @@ class SlideController(DisplayController, LogMixin, RegistryProperties):
|
||||
# See bug #791050
|
||||
self.toolbar.hide()
|
||||
self.mediabar.hide()
|
||||
self.toolbar.set_widget_visible(['editSong'], False)
|
||||
self.toolbar.set_widget_visible('editSong', False)
|
||||
self.toolbar.set_widget_visible('clear', True)
|
||||
if item.is_capable(ItemCapabilities.CanEdit) and item.from_plugin:
|
||||
self.toolbar.set_widget_visible(['editSong'])
|
||||
self.toolbar.set_widget_visible('editSong')
|
||||
elif item.is_media():
|
||||
self.mediabar.show()
|
||||
self.previous_item.setVisible(not item.is_media())
|
||||
@ -1381,6 +1387,14 @@ class SlideController(DisplayController, LogMixin, RegistryProperties):
|
||||
if new_item:
|
||||
self.add_service_item(new_item)
|
||||
|
||||
def on_clear(self):
|
||||
"""
|
||||
Clear the preview bar.
|
||||
"""
|
||||
self.preview_widget.clear_list()
|
||||
self.toolbar.set_widget_visible('editSong', False)
|
||||
self.toolbar.set_widget_visible('clear', False)
|
||||
|
||||
def on_preview_add_to_service(self):
|
||||
"""
|
||||
From the preview display request the Item to be added to service
|
||||
|
@ -428,8 +428,8 @@ class ThemeManager(QtWidgets.QWidget, RegistryBase, Ui_ThemeManager, LogMixin, R
|
||||
self.log_exception('Export Theme Failed')
|
||||
critical_error_message_box(translate('OpenLP.ThemeManager', 'Theme Export Failed'),
|
||||
translate('OpenLP.ThemeManager',
|
||||
'The theme_name export failed because this error occurred: {err}')
|
||||
.format(err=ose.strerror))
|
||||
'The {theme_name} export failed because this error occurred: {err}')
|
||||
.format(theme_name=theme_name, err=ose.strerror))
|
||||
if theme_path.exists():
|
||||
theme_path.rmtree(ignore_errors=True)
|
||||
return False
|
||||
|
@ -67,14 +67,20 @@ class OpenLPToolbar(QtWidgets.QToolBar):
|
||||
"""
|
||||
Set the visibility for a widget or a list of widgets.
|
||||
|
||||
:param widgets: A list of string with widget object names.
|
||||
:param widgets: A list of strings or individual string with widget object names.
|
||||
:param visible: The new state as bool.
|
||||
"""
|
||||
for handle in widgets:
|
||||
if handle in self.actions:
|
||||
self.actions[handle].setVisible(visible)
|
||||
if isinstance(widgets, list):
|
||||
for handle in widgets:
|
||||
if handle in self.actions:
|
||||
self.actions[handle].setVisible(visible)
|
||||
else:
|
||||
log.warning('No handle "%s" in actions list.', str(handle))
|
||||
else:
|
||||
if widgets in self.actions:
|
||||
self.actions[widgets].setVisible(visible)
|
||||
else:
|
||||
log.warning('No handle "%s" in actions list.', str(handle))
|
||||
log.warning('No handle "%s" in actions list.', str(widgets))
|
||||
|
||||
def set_widget_enabled(self, widgets, enabled=True):
|
||||
"""
|
||||
|
@ -146,6 +146,14 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
|
||||
self.screen_ratio = screen_ratio
|
||||
self.__recalculate_layout()
|
||||
|
||||
def clear_list(self):
|
||||
"""
|
||||
Clear the preview list
|
||||
:return:
|
||||
"""
|
||||
self.setRowCount(0)
|
||||
self.clear()
|
||||
|
||||
def replace_service_item(self, service_item, width, slide_number):
|
||||
"""
|
||||
Replace the current preview items with the ones in service_item and display the given slide
|
||||
@ -156,8 +164,7 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
|
||||
"""
|
||||
self.service_item = service_item
|
||||
self.setRowCount(0)
|
||||
self.clear()
|
||||
self.setColumnWidth(0, width)
|
||||
self.clear_list()
|
||||
row = 0
|
||||
text = []
|
||||
for frame_number, frame in enumerate(self.service_item.get_frames()):
|
||||
|
@ -30,6 +30,7 @@ from openlp.core.common.registry import Registry
|
||||
from openlp.core.common.settings import Settings
|
||||
from openlp.core.lib import MediaManagerItem, ItemCapabilities, ServiceItemContext, PluginStatus, \
|
||||
check_item_selected
|
||||
from openlp.core.lib.ui import create_widget_action
|
||||
from openlp.plugins.custom.forms.editcustomform import EditCustomForm
|
||||
from openlp.plugins.custom.lib import CustomXMLParser, CustomXMLBuilder
|
||||
from openlp.plugins.custom.lib.db import CustomSlide
|
||||
@ -84,6 +85,12 @@ class CustomMediaItem(MediaManagerItem):
|
||||
Registry().register_function('custom_preview', self.on_preview_click)
|
||||
Registry().register_function('custom_create_from_service', self.create_from_service_item)
|
||||
|
||||
def add_custom_context_actions(self):
|
||||
create_widget_action(self.list_view, separator=True)
|
||||
create_widget_action(
|
||||
self.list_view, text=translate('OpenLP.MediaManagerItem', '&Clone'), icon=':/general/general_clone.png',
|
||||
triggers=self.on_clone_click)
|
||||
|
||||
def config_update(self):
|
||||
"""
|
||||
Config has been updated so reload values
|
||||
@ -243,6 +250,23 @@ class CustomMediaItem(MediaManagerItem):
|
||||
service_item.raw_footer.append('')
|
||||
return True
|
||||
|
||||
def on_clone_click(self):
|
||||
"""
|
||||
Clone the selected Custom item
|
||||
"""
|
||||
item = self.list_view.currentItem()
|
||||
item_id = item.data(QtCore.Qt.UserRole)
|
||||
old_custom_slide = self.plugin.db_manager.get_object(CustomSlide, item_id)
|
||||
new_custom_slide = CustomSlide()
|
||||
new_custom_slide.title = '{title} <{text}>'.format(title=old_custom_slide.title,
|
||||
text=translate('CustomPlugin.MediaItem',
|
||||
'copy', 'For item cloning'))
|
||||
new_custom_slide.text = old_custom_slide.text
|
||||
new_custom_slide.credits = old_custom_slide.credits
|
||||
new_custom_slide.theme_name = old_custom_slide.theme_name
|
||||
self.plugin.db_manager.save_object(new_custom_slide)
|
||||
self.on_search_text_button_clicked()
|
||||
|
||||
def on_search_text_button_clicked(self):
|
||||
"""
|
||||
Search the plugin database
|
||||
|
@ -164,7 +164,7 @@ class Song(BaseModel):
|
||||
"""
|
||||
Add a Songbook Entry to the song if it not yet exists
|
||||
|
||||
:param songbook_name: Name of the Songbook.
|
||||
:param songbook: Name of the Songbook.
|
||||
:param entry: Entry in the Songbook (usually a number)
|
||||
"""
|
||||
for songbook_entry in self.songbook_entries:
|
||||
|
@ -572,10 +572,19 @@ class SongMediaItem(MediaManagerItem):
|
||||
service_item.add_capability(ItemCapabilities.OnLoadUpdate)
|
||||
service_item.add_capability(ItemCapabilities.AddIfNewItem)
|
||||
service_item.add_capability(ItemCapabilities.CanSoftBreak)
|
||||
service_item.add_capability(ItemCapabilities.HasMetaData)
|
||||
song = self.plugin.manager.get_object(Song, item_id)
|
||||
service_item.theme = song.theme_name
|
||||
service_item.edit_id = item_id
|
||||
verse_list = SongXML().get_verses(song.lyrics)
|
||||
if Settings().value('songs/add songbook slide') and song.songbook_entries:
|
||||
first_slide = '\n'
|
||||
for songbook_entry in song.songbook_entries:
|
||||
first_slide = first_slide + '{book}/{num}/{pub}\n\n'.format(book=songbook_entry.songbook.name,
|
||||
num=songbook_entry.entry,
|
||||
pub=songbook_entry.songbook.publisher)
|
||||
|
||||
service_item.add_from_text(first_slide, 'O1')
|
||||
# no verse list or only 1 space (in error)
|
||||
verse_tags_translated = False
|
||||
if VerseType.from_translated_string(str(verse_list[0][0]['type'])) is not None:
|
||||
@ -622,6 +631,9 @@ class SongMediaItem(MediaManagerItem):
|
||||
if song.media_files:
|
||||
service_item.add_capability(ItemCapabilities.HasBackgroundAudio)
|
||||
service_item.background_audio = [m.file_path for m in song.media_files]
|
||||
item.metadata.append('<em>{label}:</em> {media}'.
|
||||
format(label=translate('SongsPlugin.MediaItem', 'Media'),
|
||||
media=service_item.background_audio))
|
||||
return True
|
||||
|
||||
def generate_footer(self, item, song):
|
||||
@ -685,6 +697,23 @@ class SongMediaItem(MediaManagerItem):
|
||||
if Settings().value('core/ccli number'):
|
||||
item.raw_footer.append(translate('SongsPlugin.MediaItem',
|
||||
'CCLI License: ') + Settings().value('core/ccli number'))
|
||||
item.metadata.append('<em>{label}:</em> {title}'.format(label=translate('SongsPlugin.MediaItem', 'Title'),
|
||||
title=song.title))
|
||||
if song.alternate_title:
|
||||
item.metadata.append('<em>{label}:</em> {title}'.
|
||||
format(label=translate('SongsPlugin.MediaItem', 'Alt Title'),
|
||||
title=song.alternate_title))
|
||||
if song.songbook_entries:
|
||||
for songbook_entry in song.songbook_entries:
|
||||
item.metadata.append('<em>{label}:</em> {book}/{num}/{pub}'.
|
||||
format(label=translate('SongsPlugin.MediaItem', 'Songbook'),
|
||||
book=songbook_entry.songbook.name,
|
||||
num=songbook_entry.entry,
|
||||
pub=songbook_entry.songbook.publisher))
|
||||
if song.topics:
|
||||
for topics in song.topics:
|
||||
item.metadata.append('<em>{label}:</em> {topic}'.
|
||||
format(label=translate('SongsPlugin.MediaItem', 'Topic'), topic=topics.name))
|
||||
return authors_all
|
||||
|
||||
def service_load(self, item):
|
||||
|
@ -51,6 +51,9 @@ class SongsTab(SettingsTab):
|
||||
self.add_from_service_check_box = QtWidgets.QCheckBox(self.mode_group_box)
|
||||
self.add_from_service_check_box.setObjectName('add_from_service_check_box')
|
||||
self.mode_layout.addWidget(self.add_from_service_check_box)
|
||||
self.songbook_slide_check_box = QtWidgets.QCheckBox(self.mode_group_box)
|
||||
self.songbook_slide_check_box.setObjectName('songbook_slide_check_box')
|
||||
self.mode_layout.addWidget(self.songbook_slide_check_box)
|
||||
self.display_songbook_check_box = QtWidgets.QCheckBox(self.mode_group_box)
|
||||
self.display_songbook_check_box.setObjectName('songbook_check_box')
|
||||
self.mode_layout.addWidget(self.display_songbook_check_box)
|
||||
@ -95,6 +98,7 @@ class SongsTab(SettingsTab):
|
||||
self.tool_bar_active_check_box.stateChanged.connect(self.on_tool_bar_active_check_box_changed)
|
||||
self.update_on_edit_check_box.stateChanged.connect(self.on_update_on_edit_check_box_changed)
|
||||
self.add_from_service_check_box.stateChanged.connect(self.on_add_from_service_check_box_changed)
|
||||
self.songbook_slide_check_box.stateChanged.connect(self.on_songbook_slide_check_box_changed)
|
||||
self.display_songbook_check_box.stateChanged.connect(self.on_songbook_check_box_changed)
|
||||
self.display_written_by_check_box.stateChanged.connect(self.on_written_by_check_box_changed)
|
||||
self.display_copyright_check_box.stateChanged.connect(self.on_copyright_check_box_changed)
|
||||
@ -111,6 +115,8 @@ class SongsTab(SettingsTab):
|
||||
self.update_on_edit_check_box.setText(translate('SongsPlugin.SongsTab', 'Update service from song edit'))
|
||||
self.add_from_service_check_box.setText(translate('SongsPlugin.SongsTab',
|
||||
'Import missing songs from Service files'))
|
||||
self.songbook_slide_check_box.setText(translate('SongsPlugin.SongsTab',
|
||||
'Add Songbooks as first side'))
|
||||
self.display_songbook_check_box.setText(translate('SongsPlugin.SongsTab', 'Display songbook in footer'))
|
||||
self.display_written_by_check_box.setText(translate(
|
||||
'SongsPlugin.SongsTab', 'Show "Written by:" in footer for unspecified authors'))
|
||||
@ -141,6 +147,9 @@ class SongsTab(SettingsTab):
|
||||
def on_add_from_service_check_box_changed(self, check_state):
|
||||
self.update_load = (check_state == QtCore.Qt.Checked)
|
||||
|
||||
def on_songbook_slide_check_box_changed(self, check_state):
|
||||
self.songbook_slide = (check_state == QtCore.Qt.Checked)
|
||||
|
||||
def on_songbook_check_box_changed(self, check_state):
|
||||
self.display_songbook = (check_state == QtCore.Qt.Checked)
|
||||
|
||||
@ -171,6 +180,7 @@ class SongsTab(SettingsTab):
|
||||
self.tool_bar = settings.value('display songbar')
|
||||
self.update_edit = settings.value('update service on edit')
|
||||
self.update_load = settings.value('add song from service')
|
||||
self.songbook_slide = settings.value('add songbook slide')
|
||||
self.display_songbook = settings.value('display songbook')
|
||||
self.display_written_by = settings.value('display written by')
|
||||
self.display_copyright_symbol = settings.value('display copyright symbol')
|
||||
@ -208,6 +218,7 @@ class SongsTab(SettingsTab):
|
||||
settings.setValue('mainview chords', self.mainview_chords)
|
||||
settings.setValue('disable chords import', self.disable_chords_import)
|
||||
settings.setValue('chord notation', self.chord_notation)
|
||||
settings.setValue('add songbook slide', self.songbook_slide)
|
||||
settings.endGroup()
|
||||
if self.tab_visited:
|
||||
self.settings_form.register_post_process('songs_config_updated')
|
||||
|
@ -61,6 +61,7 @@ __default_settings__ = {
|
||||
'songs/last import type': SongFormat.OpenLyrics,
|
||||
'songs/update service on edit': False,
|
||||
'songs/add song from service': True,
|
||||
'songs/add songbook slide': False,
|
||||
'songs/display songbar': True,
|
||||
'songs/display songbook': False,
|
||||
'songs/display written by': True,
|
||||
|
@ -25,6 +25,7 @@ import asyncio
|
||||
import websockets
|
||||
import random
|
||||
|
||||
|
||||
async def tester():
|
||||
async with websockets.connect('ws://localhost:4317/poll') as websocket:
|
||||
|
||||
|
@ -20,10 +20,10 @@
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
from unittest import TestCase
|
||||
from unittest.mock import MagicMock, patch
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from openlp.core.common.registry import Registry
|
||||
from openlp.core.api.endpoint.controller import controller_text
|
||||
from openlp.core.api.endpoint.controller import controller_text, controller_direction
|
||||
|
||||
|
||||
class TestController(TestCase):
|
||||
@ -42,7 +42,7 @@ class TestController(TestCase):
|
||||
|
||||
def test_controller_text(self):
|
||||
"""
|
||||
Remote Deploy tests - test the dummy zip file is processed correctly
|
||||
Remote API Tests : test the controller text method can be called
|
||||
"""
|
||||
# GIVEN: A mocked service with a dummy service item
|
||||
self.mocked_live_controller.service_item = MagicMock()
|
||||
@ -52,3 +52,25 @@ class TestController(TestCase):
|
||||
results = ret['results']
|
||||
assert isinstance(results['item'], MagicMock)
|
||||
assert len(results['slides']) == 0
|
||||
|
||||
def test_controller_direction_next(self):
|
||||
"""
|
||||
Text the live next method is triggered
|
||||
"""
|
||||
# GIVEN: A mocked service with a dummy service item
|
||||
self.mocked_live_controller.service_item = MagicMock()
|
||||
# WHEN: I trigger the method
|
||||
controller_direction(None, 'live', 'next')
|
||||
# THEN: The correct method is called
|
||||
self.mocked_live_controller.slidecontroller_live_next.emit.assert_called_once_with()
|
||||
|
||||
def test_controller_direction_previous(self):
|
||||
"""
|
||||
Text the live next method is triggered
|
||||
"""
|
||||
# GIVEN: A mocked service with a dummy service item
|
||||
self.mocked_live_controller.service_item = MagicMock()
|
||||
# WHEN: I trigger the method
|
||||
controller_direction(None, 'live', 'previous')
|
||||
# THEN: The correct method is called
|
||||
self.mocked_live_controller.slidecontroller_live_previous.emit.assert_called_once_with()
|
||||
|
@ -431,14 +431,16 @@ class TestMediaItem(TestCase, TestMixin):
|
||||
# GIVEN: A Song and a Service Item
|
||||
song = Song()
|
||||
song.title = 'My Song'
|
||||
song.alternate_title = ''
|
||||
song.copyright = 'My copyright'
|
||||
song.authors_songs = []
|
||||
song.songbook_entries = []
|
||||
song.ccli_number = ''
|
||||
song.topics = None
|
||||
book1 = MagicMock()
|
||||
book1.name = "My songbook"
|
||||
book1.name = 'My songbook'
|
||||
book2 = MagicMock()
|
||||
book2.name = "Thy songbook"
|
||||
book2.name = 'Thy songbook'
|
||||
song.songbookentries = []
|
||||
song.add_songbook_entry(book1, '12')
|
||||
song.add_songbook_entry(book2, '502A')
|
||||
|
Loading…
Reference in New Issue
Block a user