Upstream merges

This commit is contained in:
Ken Roberts 2014-10-28 13:45:53 -07:00
commit 6ae179d672
16 changed files with 360 additions and 40 deletions

View File

@ -109,6 +109,6 @@ class ListWidgetWithDnD(QtGui.QListWidget):
listing = os.listdir(local_file)
for file in listing:
files.append(os.path.join(local_file, file))
Registry().execute('%s_dnd' % self.mime_data_text, files)
Registry().execute('%s_dnd' % self.mime_data_text, {'files': files, 'target': self.itemAt(event.pos())})
else:
event.ignore()

View File

@ -127,7 +127,7 @@ class TreeWidgetWithDnD(QtGui.QTreeWidget):
listing = os.listdir(local_file)
for file_name in listing:
files.append(os.path.join(local_file, file_name))
Registry().execute('%s_dnd' % self.mime_Data_Text, {'files': files, 'target': self.itemAt(event.pos())})
Registry().execute('%s_dnd' % self.mime_data_text, {'files': files, 'target': self.itemAt(event.pos())})
elif self.allow_internal_dnd:
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()

View File

@ -146,7 +146,7 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
if player.is_active:
for item in player.video_extensions_list:
if item not in self.video_extensions_list:
self.video_extensions_list.extend(item)
self.video_extensions_list.append(item)
suffix_list.append(item[2:])
self.service_manager.supported_suffixes(suffix_list)

View File

@ -62,7 +62,6 @@ class Ui_SettingsDialog(object):
self.button_box = create_button_box(settings_dialog, 'button_box', ['cancel', 'ok'])
self.dialog_layout.addWidget(self.button_box, 1, 1, 1, 1)
self.retranslateUi(settings_dialog)
self.setting_list_widget.currentRowChanged.connect(self.tab_changed)
def retranslateUi(self, settings_dialog):
"""

View File

@ -31,10 +31,10 @@ The :mod:`settingsform` provides a user interface for the OpenLP settings
"""
import logging
from PyQt4 import QtGui
from PyQt4 import QtCore, QtGui
from openlp.core.common import Registry, RegistryProperties
from openlp.core.lib import PluginStatus, build_icon
from openlp.core.lib import build_icon
from openlp.core.ui import AdvancedTab, GeneralTab, ThemesTab
from openlp.core.ui.media import PlayerTab
from .settingsdialog import Ui_SettingsDialog
@ -56,6 +56,7 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog, RegistryProperties):
super(SettingsForm, self).__init__(parent)
self.processes = []
self.setupUi(self)
self.setting_list_widget.currentRowChanged.connect(self.list_item_changed)
def exec_(self):
"""
@ -66,43 +67,52 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog, RegistryProperties):
while self.stacked_layout.count():
# take at 0 and the rest shuffle up.
self.stacked_layout.takeAt(0)
self.insert_tab(self.general_tab, 0, PluginStatus.Active)
self.insert_tab(self.themes_tab, 1, PluginStatus.Active)
self.insert_tab(self.projector_tab, 2, PluginStatus.Active)
self.insert_tab(self.advanced_tab, 3, PluginStatus.Active)
self.insert_tab(self.player_tab, 4, PluginStatus.Active)
count = 5
self.insert_tab(self.general_tab)
self.insert_tab(self.themes_tab)
self.insert_tab(self.advanced_tab)
self.insert_tab(self.player_tab)
self.insert_tab(self.projector_tab)
for plugin in self.plugin_manager.plugins:
if plugin.settings_tab:
self.insert_tab(plugin.settings_tab, count, plugin.status)
count += 1
self.insert_tab(plugin.settings_tab, plugin.is_active())
self.setting_list_widget.setCurrentRow(0)
return QtGui.QDialog.exec_(self)
def insert_tab(self, tab, location, is_active):
def insert_tab(self, tab_widget, is_visible=True):
"""
Add a tab to the form at a specific location
:param tab_widget: The widget to add
:param is_visible: If this tab should be visible
"""
log.debug('Inserting %s tab' % tab.tab_title)
log.debug('Inserting %s tab' % tab_widget.tab_title)
# add the tab to get it to display in the correct part of the screen
pos = self.stacked_layout.addWidget(tab)
if is_active:
item_name = QtGui.QListWidgetItem(tab.tab_title_visible)
icon = build_icon(tab.icon_path)
item_name.setIcon(icon)
self.setting_list_widget.insertItem(location, item_name)
else:
# then remove tab to stop the UI displaying it even if it is not required.
self.stacked_layout.takeAt(pos)
self.stacked_layout.addWidget(tab_widget)
if is_visible:
list_item = QtGui.QListWidgetItem(build_icon(tab_widget.icon_path), tab_widget.tab_title_visible)
list_item.setData(QtCore.Qt.UserRole, tab_widget.tab_title)
self.setting_list_widget.addItem(list_item)
def accept(self):
"""
Process the form saving the settings
"""
log.debug('Processing settings exit')
for tabIndex in range(self.stacked_layout.count()):
self.stacked_layout.widget(tabIndex).save()
# if the display of image background are changing we need to regenerate the image cache
# We add all the forms into the stacked layout, even if the plugin is inactive,
# but we don't add the item to the list on the side if the plugin is inactive,
# so loop through the list items, and then find the tab for that item.
for item_index in range(self.setting_list_widget.count()):
# Get the list item
list_item = self.setting_list_widget.item(item_index)
if not list_item:
continue
# Now figure out if there's a tab for it, and save the tab.
plugin_name = list_item.data(QtCore.Qt.UserRole)
for tab_index in range(self.stacked_layout.count()):
tab_widget = self.stacked_layout.widget(tab_index)
if tab_widget.tab_title == plugin_name:
tab_widget.save()
# if the image background has been changed we need to regenerate the image cache
if 'images_config_updated' in self.processes or 'config_screen_changed' in self.processes:
self.register_post_process('images_regenerate')
# Now lets process all the post save handlers
@ -141,12 +151,23 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog, RegistryProperties):
if plugin.settings_tab:
plugin.settings_tab.post_set_up()
def tab_changed(self, tab_index):
def list_item_changed(self, item_index):
"""
A different settings tab is selected
:param item_index: The index of the item that was selected
"""
self.stacked_layout.setCurrentIndex(tab_index)
self.stacked_layout.currentWidget().tab_visible()
# Get the item we clicked on
list_item = self.setting_list_widget.item(item_index)
# Loop through the list of tabs in the stacked layout
for tab_index in range(self.stacked_layout.count()):
# Get the widget
tab_widget = self.stacked_layout.itemAt(tab_index).widget()
# Check that the title of the tab (i.e. plugin name) is the same as the data in the list item
if tab_widget.tab_title == list_item.data(QtCore.Qt.UserRole):
# Make the matching tab visible
self.stacked_layout.setCurrentIndex(tab_index)
self.stacked_layout.currentWidget().tab_visible()
def register_post_process(self, function):
"""

View File

@ -1245,7 +1245,7 @@ class SlideController(DisplayController, RegistryProperties):
if event.timerId() == self.timer_id:
self.on_slide_selected_next(self.play_slides_loop.isChecked())
def on_edit_song(self):
def on_edit_song(self, field=None):
"""
From the preview display requires the service Item to be editied
"""
@ -1254,7 +1254,7 @@ class SlideController(DisplayController, RegistryProperties):
if new_item:
self.add_service_item(new_item)
def on_preview_add_to_service(self):
def on_preview_add_to_service(self, field=None):
"""
From the preview display request the Item to be added to service
"""
@ -1351,7 +1351,7 @@ class SlideController(DisplayController, RegistryProperties):
seconds %= 60
self.audio_time_label.setText(' %02d:%02d ' % (minutes, seconds))
def on_track_triggered(self):
def on_track_triggered(self, field=None):
"""
Start playing a track
"""

View File

@ -135,11 +135,11 @@ class PptviewDocument(PresentationDocument):
self.file_path = os.path.normpath(self.file_path)
preview_path = os.path.join(temp_folder, 'slide')
# Ensure that the paths are null terminated
self.file_path = self.file_path.encode('utf-16-le') + b'\0'
byte_file_path = self.file_path.encode('utf-16-le') + b'\0'
preview_path = preview_path.encode('utf-16-le') + b'\0'
if not os.path.isdir(temp_folder):
os.makedirs(temp_folder)
self.ppt_id = self.controller.process.OpenPPT(self.file_path, None, rect, preview_path)
self.ppt_id = self.controller.process.OpenPPT(byte_file_path, None, rect, preview_path)
if self.ppt_id >= 0:
self.create_thumbnails()
self.stop_presentation()

View File

@ -526,7 +526,6 @@ class HttpRouter(RegistryProperties):
Settings().value('remotes/thumbnails'):
# If the file is under our app directory tree send the portion after the match
data_path = AppLocation.get_data_path()
print(frame)
if frame['image'][0:len(data_path)] == data_path:
item['img'] = urllib.request.pathname2url(frame['image'][len(data_path):])
item['text'] = str(frame['title'])
@ -534,7 +533,6 @@ class HttpRouter(RegistryProperties):
item['selected'] = (self.live_controller.selected_row == index)
if current_item.notes:
item['notes'] = item.get('notes', '') + '\n' + current_item.notes
print(item)
data.append(item)
json_data = {'results': {'slides': data}}
if current_item:

View File

@ -625,7 +625,8 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog, RegistryProperties):
"""
Remove the author from the list when the delete button is clicked.
"""
self.author_remove_button.setEnabled(False)
if self.authors_list_view.count() <= 2:
self.author_remove_button.setEnabled(False)
item = self.authors_list_view.currentItem()
row = self.authors_list_view.row(item)
self.authors_list_view.takeItem(row)

View File

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
"""
All the tests
"""

View File

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
"""
Package to test the openlp.core.ui package.
"""

View File

@ -35,7 +35,7 @@ from openlp.core.common import Registry, ThemeLevel
from openlp.core.lib import ServiceItem, ServiceItemType, ItemCapabilities
from openlp.core.ui import ServiceManager
from tests.interfaces import MagicMock, patch
from tests.functional import MagicMock
class TestServiceManager(TestCase):

View File

@ -0,0 +1,114 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
"""
Package to test the openlp.core.ui.settingsform package.
"""
from PyQt4 import QtGui
from unittest import TestCase
from openlp.core.common import Registry
from openlp.core.ui.generaltab import GeneralTab
from openlp.core.ui.settingsform import SettingsForm
from tests.functional import MagicMock, patch
class TestSettingsForm(TestCase):
def setUp(self):
"""
Set up a few things for the tests
"""
Registry.create()
def insert_tab_visible_test(self):
"""
Test that the insert_tab() method works correctly when a visible tab is inserted
"""
# GIVEN: A mocked tab and a Settings Form
settings_form = SettingsForm(None)
general_tab = MagicMock()
general_tab.tab_title = 'mock'
general_tab.tab_title_visible = 'Mock'
general_tab.icon_path = ':/icon/openlp-logo-16x16.png'
# WHEN: We insert the general tab
with patch.object(settings_form.stacked_layout, 'addWidget') as mocked_add_widget, \
patch.object(settings_form.setting_list_widget, 'addItem') as mocked_add_item:
settings_form.insert_tab(general_tab, is_visible=True)
# THEN: Stuff should happen
mocked_add_widget.assert_called_with(general_tab)
self.assertEqual(1, mocked_add_item.call_count, 'addItem should have been called')
def insert_tab_not_visible_test(self):
"""
Test that the insert_tab() method works correctly when a tab that should not be visible is inserted
"""
# GIVEN: A general tab and a Settings Form
settings_form = SettingsForm(None)
general_tab = MagicMock()
general_tab.tab_title = 'mock'
# WHEN: We insert the general tab
with patch.object(settings_form.stacked_layout, 'addWidget') as mocked_add_widget, \
patch.object(settings_form.setting_list_widget, 'addItem') as mocked_add_item:
settings_form.insert_tab(general_tab, is_visible=False)
# THEN: Stuff should happen
mocked_add_widget.assert_called_with(general_tab)
self.assertEqual(0, mocked_add_item.call_count, 'addItem should not have been called')
def accept_with_inactive_plugins_test(self):
"""
Test that the accept() method works correctly when some of the plugins are inactive
"""
# GIVEN: A visible general tab and an invisible theme tab in a Settings Form
settings_form = SettingsForm(None)
general_tab = QtGui.QWidget(None)
general_tab.tab_title = 'mock-general'
general_tab.tab_title_visible = 'Mock General'
general_tab.icon_path = ':/icon/openlp-logo-16x16.png'
mocked_general_save = MagicMock()
general_tab.save = mocked_general_save
settings_form.insert_tab(general_tab, is_visible=True)
themes_tab = QtGui.QWidget(None)
themes_tab.tab_title = 'mock-themes'
themes_tab.tab_title_visible = 'Mock Themes'
themes_tab.icon_path = ':/icon/openlp-logo-16x16.png'
mocked_theme_save = MagicMock()
themes_tab.save = mocked_theme_save
settings_form.insert_tab(themes_tab, is_visible=False)
# WHEN: The accept() method is called
settings_form.accept()
# THEN: The general tab's save() method should have been called, but not the themes tab
mocked_general_save.assert_called_with()
self.assertEqual(0, mocked_theme_save.call_count, 'The Themes tab\'s save() should not have been called')

View File

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
"""
Package to test the openlp.core.ui.media package.
"""

View File

@ -0,0 +1,67 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
"""
Package to test the openlp.core.ui.media package.
"""
from unittest import TestCase
from openlp.core.ui.media.mediacontroller import MediaController
from openlp.core.ui.media.mediaplayer import MediaPlayer
from openlp.core.common import Registry
from tests.functional import MagicMock
from tests.helpers.testmixin import TestMixin
class TestMediaController(TestCase, TestMixin):
def setUp(self):
Registry.create()
Registry().register('service_manager', MagicMock())
def generate_extensions_lists_test(self):
"""
Test that the extensions are create correctly
"""
# GIVEN: A MediaController and an active player with audio and video extensions
media_controller = MediaController()
media_player = MediaPlayer(None)
media_player.is_active = True
media_player.audio_extensions_list = ['*.mp3', '*.wav', '*.wma', '*.ogg']
media_player.video_extensions_list = ['*.mp4', '*.mov', '*.avi', '*.ogm']
media_controller.register_players(media_player)
# WHEN: calling _generate_extensions_lists
media_controller._generate_extensions_lists()
# THEN: extensions list should have been copied from the player to the mediacontroller
self.assertListEqual(media_player.video_extensions_list, media_controller.video_extensions_list,
'Video extensions should be the same')
self.assertListEqual(media_player.audio_extensions_list, media_controller.audio_extensions_list,
'Audio extensions should be the same')

View File

@ -107,6 +107,33 @@ class TestRouter(TestCase, TestMixin):
self.assertEqual(mocked_function, function['function'], 'The mocked function should match defined value.')
self.assertFalse(function['secure'], 'The mocked function should not require any security.')
def process_secure_http_request_test(self):
"""
Test the router control functionality
"""
# GIVEN: A testing set of Routes
mocked_function = MagicMock()
test_route = [
(r'^/stage/api/poll$', {'function': mocked_function, 'secure': True}),
]
self.router.routes = test_route
self.router.settings_section = 'remotes'
Settings().setValue('remotes/authentication enabled', True)
self.router.path = '/stage/api/poll'
self.router.auth = ''
self.router.headers = {'Authorization': None}
self.router.send_response = MagicMock()
self.router.send_header = MagicMock()
self.router.end_headers = MagicMock()
self.router.wfile = MagicMock()
# WHEN: called with a poll route
self.router.do_post_processor()
# THEN: the function should have been called only once
self.router.send_response.assert_called_once_with(401)
self.assertEqual(self.router.send_header.call_count, 2, 'The header should have been called twice.')
def get_content_type_test(self):
"""
Test the get_content_type logic