From b34da371ba615b313f65b4fbcb68e448aa4f61a1 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Sat, 25 Oct 2014 22:26:19 +0200 Subject: [PATCH 1/9] [fix #1385438] Make list widget items select tab pages via user data rather than just their position. Fixes: https://launchpad.net/bugs/1385438 --- openlp/core/ui/settingsdialog.py | 1 - openlp/core/ui/settingsform.py | 55 +++++++----- tests/__init__.py | 31 +++++++ .../openlp_core_ui/test_servicemanager.py | 2 +- .../openlp_core_ui/test_settingsform.py | 85 +++++++++++++++++++ 5 files changed, 149 insertions(+), 25 deletions(-) create mode 100644 tests/functional/openlp_core_ui/test_settingsform.py diff --git a/openlp/core/ui/settingsdialog.py b/openlp/core/ui/settingsdialog.py index fbac6a155..ab5931584 100644 --- a/openlp/core/ui/settingsdialog.py +++ b/openlp/core/ui/settingsdialog.py @@ -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): """ diff --git a/openlp/core/ui/settingsform.py b/openlp/core/ui/settingsform.py index a1077e1f4..e953da011 100644 --- a/openlp/core/ui/settingsform.py +++ b/openlp/core/ui/settingsform.py @@ -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 @@ -55,6 +55,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): """ @@ -65,33 +66,30 @@ 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.advanced_tab, 2, PluginStatus.Active) - self.insert_tab(self.player_tab, 3, PluginStatus.Active) - count = 4 + self.insert_tab(self.general_tab) + self.insert_tab(self.themes_tab) + self.insert_tab(self.advanced_tab) + self.insert_tab(self.player_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): """ @@ -137,12 +135,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): """ diff --git a/tests/__init__.py b/tests/__init__.py index e69de29bb..6917a5968 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -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 +""" diff --git a/tests/functional/openlp_core_ui/test_servicemanager.py b/tests/functional/openlp_core_ui/test_servicemanager.py index d8d2be50e..4ff6b330a 100644 --- a/tests/functional/openlp_core_ui/test_servicemanager.py +++ b/tests/functional/openlp_core_ui/test_servicemanager.py @@ -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): diff --git a/tests/functional/openlp_core_ui/test_settingsform.py b/tests/functional/openlp_core_ui/test_settingsform.py new file mode 100644 index 000000000..5d9b413df --- /dev/null +++ b/tests/functional/openlp_core_ui/test_settingsform.py @@ -0,0 +1,85 @@ +# -*- 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 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') From 3693e55f5c2673adbfd8698e22cba06b9fa15995 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 27 Oct 2014 11:37:22 +0100 Subject: [PATCH 2/9] Change filename encoding to only apply to local variable. --- openlp/plugins/presentations/lib/pptviewcontroller.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/plugins/presentations/lib/pptviewcontroller.py b/openlp/plugins/presentations/lib/pptviewcontroller.py index 4aea501b4..8bde0b213 100644 --- a/openlp/plugins/presentations/lib/pptviewcontroller.py +++ b/openlp/plugins/presentations/lib/pptviewcontroller.py @@ -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() From 6d2cfedd7e0689cbb20d42a3bf58d336cbde16bf Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 27 Oct 2014 13:52:56 +0100 Subject: [PATCH 3/9] Remove prints --- openlp/plugins/remotes/lib/httprouter.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openlp/plugins/remotes/lib/httprouter.py b/openlp/plugins/remotes/lib/httprouter.py index ff28de399..22e2495c0 100644 --- a/openlp/plugins/remotes/lib/httprouter.py +++ b/openlp/plugins/remotes/lib/httprouter.py @@ -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: From 3d387cb296f6b7a009850b1aface780ca5dcd664 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 27 Oct 2014 13:58:59 +0100 Subject: [PATCH 4/9] Fixed a tiny glitch, remove author button became always disabled even if not needed to. Copied from lp:~mahfiaz/openlp/author-delete-button-not-active-in-edit-dialog --- openlp/plugins/songs/forms/editsongform.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index d71cde304..624b409ec 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -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) From d2f388bb5908e7ae1e73b62bfbd67188225e55fd Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 27 Oct 2014 14:11:55 +0100 Subject: [PATCH 5/9] Fix for another occurrence of bug #1296574. Copied from lp:~erik-lundin/openlp/bug-1296574 Fixes: https://launchpad.net/bugs/1296574 --- openlp/core/ui/slidecontroller.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 062a8440f..f706dd929 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -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 """ From e9a151cec0ab8e765377278d2f4451c883e47de9 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 27 Oct 2014 14:14:12 +0100 Subject: [PATCH 6/9] This fixes the adding of images and media to the media manager. Copied from lp:~rafaellerm/openlp/media_import_fix --- openlp/core/lib/listwidgetwithdnd.py | 2 +- openlp/core/lib/treewidgetwithdnd.py | 2 +- openlp/core/ui/media/mediacontroller.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openlp/core/lib/listwidgetwithdnd.py b/openlp/core/lib/listwidgetwithdnd.py index 2618d13c3..cbedbc79c 100644 --- a/openlp/core/lib/listwidgetwithdnd.py +++ b/openlp/core/lib/listwidgetwithdnd.py @@ -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() diff --git a/openlp/core/lib/treewidgetwithdnd.py b/openlp/core/lib/treewidgetwithdnd.py index cdb6cbbdb..0bdd664e8 100644 --- a/openlp/core/lib/treewidgetwithdnd.py +++ b/openlp/core/lib/treewidgetwithdnd.py @@ -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() diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index 4a2d475c1..e3517ba0f 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -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) From afde4a25ad26cff0c544f36be884c21dd5735399 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Mon, 27 Oct 2014 20:22:57 +0000 Subject: [PATCH 7/9] Fix missing dummy values for debug --- openlp/core/ui/slidecontroller.py | 6 ++--- .../openlp_plugins/remotes/test_router.py | 27 +++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 062a8440f..1b8b45815 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -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 """ diff --git a/tests/functional/openlp_plugins/remotes/test_router.py b/tests/functional/openlp_plugins/remotes/test_router.py index 8d239a5f0..b1a157574 100644 --- a/tests/functional/openlp_plugins/remotes/test_router.py +++ b/tests/functional/openlp_plugins/remotes/test_router.py @@ -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 From 11b2b4dc3b58ecc11ed6f6afa7dfe1d5259a14dd Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 27 Oct 2014 21:38:19 +0000 Subject: [PATCH 8/9] Added test for checking extension list creation --- tests/functional/openlp_core_ui/__init__.py | 31 +++++++++ .../openlp_core_ui_media/__init__.py | 31 +++++++++ .../test_mediacontroller.py | 67 +++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 tests/functional/openlp_core_ui_media/__init__.py create mode 100644 tests/functional/openlp_core_ui_media/test_mediacontroller.py diff --git a/tests/functional/openlp_core_ui/__init__.py b/tests/functional/openlp_core_ui/__init__.py index e69de29bb..00a1db85c 100644 --- a/tests/functional/openlp_core_ui/__init__.py +++ b/tests/functional/openlp_core_ui/__init__.py @@ -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. +""" diff --git a/tests/functional/openlp_core_ui_media/__init__.py b/tests/functional/openlp_core_ui_media/__init__.py new file mode 100644 index 000000000..c489203a2 --- /dev/null +++ b/tests/functional/openlp_core_ui_media/__init__.py @@ -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. +""" diff --git a/tests/functional/openlp_core_ui_media/test_mediacontroller.py b/tests/functional/openlp_core_ui_media/test_mediacontroller.py new file mode 100644 index 000000000..17fcba954 --- /dev/null +++ b/tests/functional/openlp_core_ui_media/test_mediacontroller.py @@ -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') From 743dc59d516938e03600bde3ea2f224a7fe58ed7 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Tue, 28 Oct 2014 21:40:01 +0200 Subject: [PATCH 9/9] [fix 1386710] Fix traceback after settings form is saved Fixes: https://launchpad.net/bugs/1386710 --- openlp/core/ui/settingsform.py | 18 ++++++++++-- .../openlp_core_ui/test_settingsform.py | 29 +++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/openlp/core/ui/settingsform.py b/openlp/core/ui/settingsform.py index e953da011..a92c6583c 100644 --- a/openlp/core/ui/settingsform.py +++ b/openlp/core/ui/settingsform.py @@ -96,9 +96,21 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog, RegistryProperties): 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 diff --git a/tests/functional/openlp_core_ui/test_settingsform.py b/tests/functional/openlp_core_ui/test_settingsform.py index 5d9b413df..bc9d0621f 100644 --- a/tests/functional/openlp_core_ui/test_settingsform.py +++ b/tests/functional/openlp_core_ui/test_settingsform.py @@ -29,6 +29,7 @@ """ Package to test the openlp.core.ui.settingsform package. """ +from PyQt4 import QtGui from unittest import TestCase from openlp.core.common import Registry @@ -83,3 +84,31 @@ class TestSettingsForm(TestCase): # 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')