def setUp(self): Registry.create() self.registry = Registry() self.setup_application() # Mock cursor busy/normal methods. self.app.set_busy_cursor = MagicMock() self.app.set_normal_cursor = MagicMock() self.app.args = [] Registry().register('application', self.app) # Mock classes and methods used by mainwindow. with patch('openlp.core.ui.mainwindow.SettingsForm') as mocked_settings_form, \ patch('openlp.core.ui.mainwindow.ImageManager') as mocked_image_manager, \ patch('openlp.core.ui.mainwindow.LiveController') as mocked_live_controller, \ patch('openlp.core.ui.mainwindow.PreviewController') as mocked_preview_controller, \ patch('openlp.core.ui.mainwindow.OpenLPDockWidget') as mocked_dock_widget, \ patch('openlp.core.ui.mainwindow.QtWidgets.QToolBox') as mocked_q_tool_box_class, \ patch('openlp.core.ui.mainwindow.QtWidgets.QMainWindow.addDockWidget') as mocked_add_dock_method, \ patch('openlp.core.ui.mainwindow.ThemeManager') as mocked_theme_manager, \ patch('openlp.core.ui.mainwindow.Renderer') as mocked_renderer: self.mocked_settings_form = mocked_settings_form self.mocked_image_manager = mocked_image_manager self.mocked_live_controller = mocked_live_controller self.mocked_preview_controller = mocked_preview_controller self.mocked_dock_widget = mocked_dock_widget self.mocked_q_tool_box_class = mocked_q_tool_box_class self.mocked_add_dock_method = mocked_add_dock_method self.mocked_theme_manager = mocked_theme_manager self.mocked_renderer = mocked_renderer self.main_window = MainWindow()
def run(self, args): """ Run the OpenLP application. """ self.is_event_loop_active = False # On Windows, the args passed into the constructor are ignored. Not # very handy, so set the ones we want to use. On Linux and FreeBSD, in # order to set the WM_CLASS property for X11, we pass "OpenLP" in as a # command line argument. This interferes with files being passed in as # command line arguments, so we remove it from the list. if 'OpenLP' in args: args.remove('OpenLP') self.args.extend(args) # Decide how many screens we have and their size screens = ScreenList.create(self.desktop()) # First time checks in settings has_run_wizard = Settings().value(u'general/has run wizard') if not has_run_wizard: if FirstTimeForm(screens).exec_() == QtGui.QDialog.Accepted: Settings().setValue(u'general/has run wizard', True) # Correct stylesheet bugs application_stylesheet = u'' if not Settings().value(u'advanced/alternate rows'): base_color = self.palette().color(QtGui.QPalette.Active, QtGui.QPalette.Base) alternate_rows_repair_stylesheet = \ u'QTableWidget, QListWidget, QTreeWidget {alternate-background-color: ' + base_color.name() + ';}\n' application_stylesheet += alternate_rows_repair_stylesheet if os.name == u'nt': application_stylesheet += nt_repair_stylesheet if application_stylesheet: self.setStyleSheet(application_stylesheet) show_splash = Settings().value(u'general/show splash') if show_splash: self.splash = SplashScreen() self.splash.show() # make sure Qt really display the splash screen self.processEvents() # start the main app window self.main_window = MainWindow() self.main_window.show() if show_splash: # now kill the splashscreen self.splash.finish(self.main_window) log.debug(u'Splashscreen closed') # make sure Qt really display the splash screen self.processEvents() self.main_window.repaint() self.processEvents() if not has_run_wizard: self.main_window.first_time() update_check = Settings().value(u'general/update check') if update_check: VersionThread(self.main_window).start() Receiver.send_message(u'live_display_blank_check') self.main_window.app_startup() return self.exec_()
class TestMainWindow(TestCase, TestMixin): def setUp(self): Registry.create() self.registry = Registry() self.setup_application() # Mock cursor busy/normal methods. self.app.set_busy_cursor = MagicMock() self.app.set_normal_cursor = MagicMock() self.app.args = [] Registry().register('application', self.app) # Mock classes and methods used by mainwindow. with patch('openlp.core.ui.mainwindow.SettingsForm') as mocked_settings_form, \ patch('openlp.core.ui.mainwindow.ImageManager') as mocked_image_manager, \ patch('openlp.core.ui.mainwindow.LiveController') as mocked_live_controller, \ patch('openlp.core.ui.mainwindow.PreviewController') as mocked_preview_controller, \ patch('openlp.core.ui.mainwindow.OpenLPDockWidget') as mocked_dock_widget, \ patch('openlp.core.ui.mainwindow.QtGui.QToolBox') as mocked_q_tool_box_class, \ patch('openlp.core.ui.mainwindow.QtGui.QMainWindow.addDockWidget') as mocked_add_dock_method, \ patch('openlp.core.ui.mainwindow.ThemeManager') as mocked_theme_manager, \ patch('openlp.core.ui.mainwindow.Renderer') as mocked_renderer: self.main_window = MainWindow() def tearDown(self): del self.main_window def cmd_line_file_test(self): """ Test that passing a service file from the command line loads the service. """ # GIVEN a service as an argument to openlp service = os.path.join(TEST_RESOURCES_PATH, 'service', 'test.osz') self.main_window.arguments = [service] with patch('openlp.core.ui.servicemanager.ServiceManager.load_file' ) as mocked_load_path: # WHEN the argument is processed self.main_window.open_cmd_line_files() # THEN the service from the arguments is loaded mocked_load_path.assert_called_with( service ), 'load_path should have been called with the service\'s path' def cmd_line_arg_test(self): """ Test that passing a non service file does nothing. """ # GIVEN a non service file as an argument to openlp service = os.path.join('openlp.py') self.main_window.arguments = [service] with patch('openlp.core.ui.servicemanager.ServiceManager.load_file' ) as mocked_load_path: # WHEN the argument is processed self.main_window.open_cmd_line_files() # THEN the file should not be opened assert not mocked_load_path.called, 'load_path should not have been called' def main_window_title_test(self): """ Test that running a new instance of OpenLP set the window title correctly """ # GIVEN a newly opened OpenLP instance # WHEN no changes are made to the service # THEN the main window's title shoud be the same as the OLPV2x string in the UiStrings class self.assertEqual( self.main_window.windowTitle(), UiStrings().OLPV2x, 'The main window\'s title should be the same as the OLPV2x string in UiStrings class' ) def set_service_modifed_test(self): """ Test that when setting the service's title the main window's title is set correctly """ # GIVEN a newly opened OpenLP instance # WHEN set_service_modified is called with with the modified flag set true and a file name self.main_window.set_service_modified(True, 'test.osz') # THEN the main window's title should be set to the self.assertEqual( self.main_window.windowTitle(), '%s - %s*' % (UiStrings().OLPV2x, 'test.osz'), 'The main window\'s title should be set to "<the contents of UiStrings().OLPV2x> - test.osz*"' ) def set_service_unmodified_test(self): """ Test that when setting the service's title the main window's title is set correctly """ # GIVEN a newly opened OpenLP instance # WHEN set_service_modified is called with with the modified flag set False and a file name self.main_window.set_service_modified(False, 'test.osz') # THEN the main window's title should be set to the self.assertEqual( self.main_window.windowTitle(), '%s - %s' % (UiStrings().OLPV2x, 'test.osz'), 'The main window\'s title should be set to "<the contents of UiStrings().OLPV2x> - test.osz"' ) def mainwindow_configuration_test(self): """ Check that the Main Window initialises the Registry Correctly """ # GIVEN: A built main window # WHEN: you check the started functions # THEN: the following registry functions should have been registered self.assertEqual(len(self.registry.service_list), 6, 'The registry should have 6 services.') self.assertEqual(len(self.registry.functions_list), 16, 'The registry should have 16 functions') self.assertTrue('application' in self.registry.service_list, 'The application should have been registered.') self.assertTrue('main_window' in self.registry.service_list, 'The main_window should have been registered.') self.assertTrue('media_controller' in self.registry.service_list, 'The media_controller should have been ' 'registered.') self.assertTrue('plugin_manager' in self.registry.service_list, 'The plugin_manager should have been registered.')
class OpenLP(QtGui.QApplication): """ The core application class. This class inherits from Qt's QApplication class in order to provide the core of the application. """ args = [] def exec_(self): """ Override exec method to allow the shared memory to be released on exit """ self.is_event_loop_active = True result = QtGui.QApplication.exec_() self.shared_memory.detach() return result def run(self, args): """ Run the OpenLP application. """ self.is_event_loop_active = False # On Windows, the args passed into the constructor are ignored. Not # very handy, so set the ones we want to use. On Linux and FreeBSD, in # order to set the WM_CLASS property for X11, we pass "OpenLP" in as a # command line argument. This interferes with files being passed in as # command line arguments, so we remove it from the list. if 'OpenLP' in args: args.remove('OpenLP') self.args.extend(args) # Decide how many screens we have and their size screens = ScreenList.create(self.desktop()) # First time checks in settings has_run_wizard = Settings().value(u'general/has run wizard') if not has_run_wizard: if FirstTimeForm(screens).exec_() == QtGui.QDialog.Accepted: Settings().setValue(u'general/has run wizard', True) # Correct stylesheet bugs application_stylesheet = u'' if not Settings().value(u'advanced/alternate rows'): base_color = self.palette().color(QtGui.QPalette.Active, QtGui.QPalette.Base) alternate_rows_repair_stylesheet = \ u'QTableWidget, QListWidget, QTreeWidget {alternate-background-color: ' + base_color.name() + ';}\n' application_stylesheet += alternate_rows_repair_stylesheet if os.name == u'nt': application_stylesheet += nt_repair_stylesheet if application_stylesheet: self.setStyleSheet(application_stylesheet) show_splash = Settings().value(u'general/show splash') if show_splash: self.splash = SplashScreen() self.splash.show() # make sure Qt really display the splash screen self.processEvents() # start the main app window self.main_window = MainWindow() self.main_window.show() if show_splash: # now kill the splashscreen self.splash.finish(self.main_window) log.debug(u'Splashscreen closed') # make sure Qt really display the splash screen self.processEvents() self.main_window.repaint() self.processEvents() if not has_run_wizard: self.main_window.first_time() update_check = Settings().value(u'general/update check') if update_check: VersionThread(self.main_window).start() Receiver.send_message(u'live_display_blank_check') self.main_window.app_startup() return self.exec_() def close_splash_screen(self): """ Close the splash screen when requested. """ self.splash.close() def is_already_running(self): """ Look to see if OpenLP is already running and ask if a 2nd copy is to be started. """ self.shared_memory = QtCore.QSharedMemory('OpenLP') if self.shared_memory.attach(): status = QtGui.QMessageBox.critical(None, UiStrings().Error, UiStrings().OpenLPStart, QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)) if status == QtGui.QMessageBox.No: return True return False else: self.shared_memory.create(1) return False def hook_exception(self, exctype, value, traceback): """ Add an exception hook so that any uncaught exceptions are displayed in this window rather than somewhere where users cannot see it and cannot report when we encounter these problems. ``exctype`` The class of exception. ``value`` The actual exception object. ``traceback`` A traceback object with the details of where the exception occurred. """ if not hasattr(self, u'mainWindow'): log.exception(''.join(format_exception(exctype, value, traceback))) return if not hasattr(self, u'exceptionForm'): self.exception_form = ExceptionForm(self.main_window) self.exception_form.exceptionTextEdit.setPlainText(''.join(format_exception(exctype, value, traceback))) self.set_normal_cursor() self.exception_form.exec_() def process_events(self): """ Wrapper to make ProcessEvents visible and named correctly """ self.processEvents() def set_busy_cursor(self): """ Sets the Busy Cursor for the Application """ self.setOverrideCursor(QtCore.Qt.BusyCursor) self.processEvents() def set_normal_cursor(self): """ Sets the Normal Cursor for the Application """ self.restoreOverrideCursor() self.processEvents() def event(self, event): """ Enables direct file opening on OS X """ if event.type() == QtCore.QEvent.FileOpen: file_name = event.file() log.debug(u'Got open file event for %s!', file_name) self.args.insert(0, file_name) return True else: return QtGui.QApplication.event(self, event)
class TestMainWindow(TestCase, TestMixin): """ Test the main window """ def _create_mock_action(self, parent, name, **kwargs): """ Create a fake action with some "real" attributes """ action = QtWidgets.QAction(parent) action.setObjectName(name) if kwargs.get('triggers'): action.triggered.connect(kwargs.pop('triggers')) return action def setUp(self): """ Set up the objects we need for all of the tests """ Registry.create() self.registry = Registry() self.setup_application() # Mock cursor busy/normal methods. self.app.set_busy_cursor = MagicMock() self.app.set_normal_cursor = MagicMock() self.app.process_events = MagicMock() self.app.args = [] Registry().register('application', self.app) Registry().set_flag('no_web_server', True) self.add_toolbar_action_patcher = patch( 'openlp.core.ui.mainwindow.create_action') self.mocked_add_toolbar_action = self.add_toolbar_action_patcher.start( ) self.mocked_add_toolbar_action.side_effect = self._create_mock_action with patch('openlp.core.display.screens.ScreenList.__instance__', spec=ScreenList) as mocked_screen_list: mocked_screen_list.current = { 'number': 0, 'size': QtCore.QSize(600, 800), 'primary': True } self.main_window = MainWindow() def tearDown(self): """ Delete all the C++ objects and stop all the patchers """ del self.main_window self.add_toolbar_action_patcher.stop() def test_cmd_line_file(self): """ Test that passing a service file from the command line loads the service. """ # GIVEN a service as an argument to openlp service = os.path.join(TEST_RESOURCES_PATH, 'service', 'test.osz') # WHEN the argument is processed with patch.object(self.main_window.service_manager, 'load_file') as mocked_load_file: self.main_window.open_cmd_line_files(service) # THEN the service from the arguments is loaded mocked_load_file.assert_called_with(Path(service)) @patch('openlp.core.ui.servicemanager.ServiceManager.load_file') def test_cmd_line_arg(self, mocked_load_file): """ Test that passing a non service file does nothing. """ # GIVEN a non service file as an argument to openlp service = os.path.join('openlp.py') self.main_window.arguments = [service] # WHEN the argument is processed self.main_window.open_cmd_line_files(service) # THEN the file should not be opened assert mocked_load_file.called is False, 'load_file should not have been called' def test_main_window_title(self): """ Test that running a new instance of OpenLP set the window title correctly """ # GIVEN a newly opened OpenLP instance # WHEN no changes are made to the service # THEN the main window's title shoud be the same as the OpenLP string in the UiStrings class assert self.main_window.windowTitle() == UiStrings().OpenLP, \ 'The main window\'s title should be the same as the OpenLP string in UiStrings class' def test_set_service_modifed(self): """ Test that when setting the service's title the main window's title is set correctly """ # GIVEN a newly opened OpenLP instance # WHEN set_service_modified is called with with the modified flag set true and a file name self.main_window.set_service_modified(True, 'test.osz') # THEN the main window's title should be set to the assert self.main_window.windowTitle(), '%s - %s*' % (UiStrings().OpenLP, 'test.osz') == \ 'The main window\'s title should be set to "<the contents of UiStrings().OpenLP> - test.osz*"' def test_set_service_unmodified(self): """ Test that when setting the service's title the main window's title is set correctly """ # GIVEN a newly opened OpenLP instance # WHEN set_service_modified is called with with the modified flag set False and a file name self.main_window.set_service_modified(False, 'test.osz') # THEN the main window's title should be set to the assert self.main_window.windowTitle(), '%s - %s' % (UiStrings().OpenLP, 'test.osz') == \ 'The main window\'s title should be set to "<the contents of UiStrings().OpenLP> - test.osz"' def test_mainwindow_configuration(self): """ Check that the Main Window initialises the Registry Correctly """ # GIVEN: A built main window # WHEN: you check the started functions # THEN: the following registry functions should have been registered assert len(self.registry.service_list) == 13, \ 'The registry should have 12 services, got {}'.format(self.registry.service_list.keys()) assert len(self.registry.functions_list) == 19, \ 'The registry should have 19 functions, got {}'.format(self.registry.functions_list.keys()) assert 'application' in self.registry.service_list, 'The application should have been registered.' assert 'main_window' in self.registry.service_list, 'The main_window should have been registered.' assert 'media_controller' in self.registry.service_list, 'The media_controller should have been registered.' assert 'plugin_manager' in self.registry.service_list, 'The plugin_manager should have been registered.' def test_projector_manager_hidden_on_startup(self): """ Test that the projector manager is hidden on startup """ # GIVEN: A built main window # WHEN: OpenLP is started # THEN: The projector manager should be hidden assert self.main_window.projector_manager_dock.isVisible() is False def test_on_search_shortcut_triggered_shows_media_manager(self): """ Test that the media manager is made visible when the search shortcut is triggered """ # GIVEN: A build main window set up for testing with patch.object(self.main_window, 'media_manager_dock') as mocked_media_manager_dock, \ patch.object(self.main_window, 'media_tool_box') as mocked_media_tool_box: mocked_media_manager_dock.isVisible.return_value = False mocked_media_tool_box.currentWidget.return_value = None # WHEN: The search shortcut is triggered self.main_window.on_search_shortcut_triggered() # THEN: The media manager dock is made visible mocked_media_manager_dock.setVisible.assert_called_with(True) def test_on_search_shortcut_triggered_focuses_widget(self): """ Test that the focus is set on the widget when the search shortcut is triggered """ # GIVEN: A build main window set up for testing with patch.object(self.main_window, 'media_manager_dock') as mocked_media_manager_dock, \ patch.object(self.main_window, 'media_tool_box') as mocked_media_tool_box: mocked_media_manager_dock.isVisible.return_value = True mocked_widget = MagicMock() mocked_media_tool_box.currentWidget.return_value = mocked_widget # WHEN: The search shortcut is triggered self.main_window.on_search_shortcut_triggered() # THEN: The media manager dock is made visible assert 0 == mocked_media_manager_dock.setVisible.call_count mocked_widget.on_focus.assert_called_with() @patch('openlp.core.ui.mainwindow.FirstTimeForm') @patch('openlp.core.ui.mainwindow.QtWidgets.QMessageBox.warning') @patch('openlp.core.ui.mainwindow.Settings') def test_on_first_time_wizard_clicked_show_projectors_after( self, MockSettings, mocked_warning, MockWizard): """Test that the projector manager is shown after the FTW is run""" # GIVEN: Main_window, patched things, patched "Yes" as confirmation to re-run wizard, settings to True. MockSettings.return_value.value.return_value = True mocked_warning.return_value = QtWidgets.QMessageBox.Yes MockWizard.return_value.was_cancelled = False with patch.object(self.main_window, 'projector_manager_dock') as mocked_dock, \ patch.object(self.registry, 'execute'), patch.object(self.main_window, 'theme_manager_contents'): # WHEN: on_first_time_wizard_clicked is called self.main_window.on_first_time_wizard_clicked() # THEN: projector_manager_dock.setVisible should had been called once mocked_dock.setVisible.assert_called_once_with(True) @patch('openlp.core.ui.mainwindow.FirstTimeForm') @patch('openlp.core.ui.mainwindow.QtWidgets.QMessageBox.warning') @patch('openlp.core.ui.mainwindow.Settings') def test_on_first_time_wizard_clicked_hide_projectors_after( self, MockSettings, mocked_warning, MockWizard): """Test that the projector manager is hidden after the FTW is run""" # GIVEN: Main_window, patched things, patched "Yes" as confirmation to re-run wizard, settings to False. MockSettings.return_value.value.return_value = False mocked_warning.return_value = QtWidgets.QMessageBox.Yes MockWizard.return_value.was_cancelled = False # WHEN: on_first_time_wizard_clicked is called with patch.object(self.main_window, 'projector_manager_dock') as mocked_dock, \ patch.object(self.registry, 'execute'), patch.object(self.main_window, 'theme_manager_contents'): self.main_window.on_first_time_wizard_clicked() # THEN: projector_manager_dock.setVisible should had been called once mocked_dock.setVisible.assert_called_once_with(False) def test_increment_progress_bar_default_increment(self): """ Test that increment_progress_bar increments the progress bar by 1 when called without the `increment` arg. """ # GIVEN: A mocked progress bar with patch.object(self.main_window, 'load_progress_bar', **{'value.return_value': 0}) as mocked_progress_bar: # WHEN: Calling increment_progress_bar without the `increment` arg self.main_window.increment_progress_bar() # THEN: The progress bar value should have been incremented by 1 mocked_progress_bar.setValue.assert_called_once_with(1) def test_increment_progress_bar_custom_increment(self): """ Test that increment_progress_bar increments the progress bar by the `increment` arg when called with the `increment` arg with a set value. """ # GIVEN: A mocked progress bar with patch.object(self.main_window, 'load_progress_bar', **{'value.return_value': 0}) as mocked_progress_bar: # WHEN: Calling increment_progress_bar with `increment` set to 10 self.main_window.increment_progress_bar(increment=10) # THEN: The progress bar value should have been incremented by 10 mocked_progress_bar.setValue.assert_called_once_with(10)
class TestMainWindow(TestCase, TestMixin): def setUp(self): Registry.create() self.registry = Registry() self.setup_application() # Mock cursor busy/normal methods. self.app.set_busy_cursor = MagicMock() self.app.set_normal_cursor = MagicMock() self.app.args = [] Registry().register('application', self.app) # Mock classes and methods used by mainwindow. with patch('openlp.core.ui.mainwindow.SettingsForm') as mocked_settings_form, \ patch('openlp.core.ui.mainwindow.ImageManager') as mocked_image_manager, \ patch('openlp.core.ui.mainwindow.LiveController') as mocked_live_controller, \ patch('openlp.core.ui.mainwindow.PreviewController') as mocked_preview_controller, \ patch('openlp.core.ui.mainwindow.OpenLPDockWidget') as mocked_dock_widget, \ patch('openlp.core.ui.mainwindow.QtGui.QToolBox') as mocked_q_tool_box_class, \ patch('openlp.core.ui.mainwindow.QtGui.QMainWindow.addDockWidget') as mocked_add_dock_method, \ patch('openlp.core.ui.mainwindow.ThemeManager') as mocked_theme_manager, \ patch('openlp.core.ui.mainwindow.Renderer') as mocked_renderer: self.main_window = MainWindow() def tearDown(self): del self.main_window def cmd_line_file_test(self): """ Test that passing a service file from the command line loads the service. """ # GIVEN a service as an argument to openlp service = os.path.join(TEST_RESOURCES_PATH, 'service', 'test.osz') self.main_window.arguments = [service] with patch('openlp.core.ui.servicemanager.ServiceManager.load_file') as mocked_load_path: # WHEN the argument is processed self.main_window.open_cmd_line_files() # THEN the service from the arguments is loaded mocked_load_path.assert_called_with(service), 'load_path should have been called with the service\'s path' def cmd_line_arg_test(self): """ Test that passing a non service file does nothing. """ # GIVEN a non service file as an argument to openlp service = os.path.join('openlp.py') self.main_window.arguments = [service] with patch('openlp.core.ui.servicemanager.ServiceManager.load_file') as mocked_load_path: # WHEN the argument is processed self.main_window.open_cmd_line_files() # THEN the file should not be opened assert not mocked_load_path.called, 'load_path should not have been called' def main_window_title_test(self): """ Test that running a new instance of OpenLP set the window title correctly """ # GIVEN a newly opened OpenLP instance # WHEN no changes are made to the service # THEN the main window's title shoud be the same as the OLPV2x string in the UiStrings class self.assertEqual(self.main_window.windowTitle(), UiStrings().OLPV2x, 'The main window\'s title should be the same as the OLPV2x string in UiStrings class') def set_service_modifed_test(self): """ Test that when setting the service's title the main window's title is set correctly """ # GIVEN a newly opened OpenLP instance # WHEN set_service_modified is called with with the modified flag set true and a file name self.main_window.set_service_modified(True, 'test.osz') # THEN the main window's title should be set to the self.assertEqual(self.main_window.windowTitle(), '%s - %s*' % (UiStrings().OLPV2x, 'test.osz'), 'The main window\'s title should be set to "<the contents of UiStrings().OLPV2x> - test.osz*"') def set_service_unmodified_test(self): """ Test that when setting the service's title the main window's title is set correctly """ # GIVEN a newly opened OpenLP instance # WHEN set_service_modified is called with with the modified flag set False and a file name self.main_window.set_service_modified(False, 'test.osz') # THEN the main window's title should be set to the self.assertEqual(self.main_window.windowTitle(), '%s - %s' % (UiStrings().OLPV2x, 'test.osz'), 'The main window\'s title should be set to "<the contents of UiStrings().OLPV2x> - test.osz"') def mainwindow_configuration_test(self): """ Check that the Main Window initialises the Registry Correctly """ # GIVEN: A built main window # WHEN: you check the started functions # THEN: the following registry functions should have been registered self.assertEqual(len(self.registry.service_list), 6, 'The registry should have 6 services.') self.assertEqual(len(self.registry.functions_list), 16, 'The registry should have 16 functions') self.assertTrue('application' in self.registry.service_list, 'The application should have been registered.') self.assertTrue('main_window' in self.registry.service_list, 'The main_window should have been registered.') self.assertTrue('media_controller' in self.registry.service_list, 'The media_controller should have been ' 'registered.') self.assertTrue('plugin_manager' in self.registry.service_list, 'The plugin_manager should have been registered.')
def run(self, args): """ Run the OpenLP application. :param args: Some Args """ self.is_event_loop_active = False # On Windows, the args passed into the constructor are ignored. Not very handy, so set the ones we want to use. # On Linux and FreeBSD, in order to set the WM_CLASS property for X11, we pass "OpenLP" in as a command line # argument. This interferes with files being passed in as command line arguments, so we remove it from the list. if 'OpenLP' in args: args.remove('OpenLP') self.args.extend(args) # Decide how many screens we have and their size screens = ScreenList.create(self.desktop()) # First time checks in settings has_run_wizard = Settings().value('core/has run wizard') if not has_run_wizard: ftw = FirstTimeForm() ftw.initialize(screens) if ftw.exec() == QtWidgets.QDialog.Accepted: Settings().setValue('core/has run wizard', True) elif ftw.was_cancelled: QtCore.QCoreApplication.exit() sys.exit() # Correct stylesheet bugs application_stylesheet = '' if not Settings().value('advanced/alternate rows'): base_color = self.palette().color(QtGui.QPalette.Active, QtGui.QPalette.Base) alternate_rows_repair_stylesheet = \ 'QTableWidget, QListWidget, QTreeWidget {alternate-background-color: ' + base_color.name() + ';}\n' application_stylesheet += alternate_rows_repair_stylesheet if is_win(): application_stylesheet += WIN_REPAIR_STYLESHEET if application_stylesheet: self.setStyleSheet(application_stylesheet) can_show_splash = Settings().value('core/show splash') if can_show_splash: self.splash = SplashScreen() self.splash.show() # make sure Qt really display the splash screen self.processEvents() # Check if OpenLP has been upgrade and if a backup of data should be created self.backup_on_upgrade(has_run_wizard, can_show_splash) # start the main app window self.main_window = MainWindow() Registry().execute('bootstrap_initialise') Registry().execute('bootstrap_post_set_up') Registry().initialise = False self.main_window.show() if can_show_splash: # now kill the splashscreen self.splash.finish(self.main_window) log.debug('Splashscreen closed') # make sure Qt really display the splash screen self.processEvents() self.main_window.repaint() self.processEvents() if not has_run_wizard: self.main_window.first_time() update_check = Settings().value('core/update check') if update_check: version = VersionThread(self.main_window) version.start() self.main_window.is_display_blank() self.main_window.app_startup() return self.exec()
def run(self, args): """ Run the OpenLP application. :param args: Some Args """ self.is_event_loop_active = False # On Windows, the args passed into the constructor are ignored. Not very handy, so set the ones we want to use. # On Linux and FreeBSD, in order to set the WM_CLASS property for X11, we pass "OpenLP" in as a command line # argument. This interferes with files being passed in as command line arguments, so we remove it from the list. if 'OpenLP' in args: args.remove('OpenLP') self.args.extend(args) # Decide how many screens we have and their size screens = ScreenList.create(QtWidgets.QApplication.desktop()) # First time checks in settings has_run_wizard = Settings().value('core/has run wizard') if not has_run_wizard: ftw = FirstTimeForm() ftw.initialize(screens) if ftw.exec() == QtWidgets.QDialog.Accepted: Settings().setValue('core/has run wizard', True) else: QtCore.QCoreApplication.exit() sys.exit() can_show_splash = Settings().value('core/show splash') if can_show_splash: self.splash = SplashScreen() self.splash.show() # make sure Qt really display the splash screen QtWidgets.QApplication.processEvents() # Check if OpenLP has been upgrade and if a backup of data should be created self.backup_on_upgrade(has_run_wizard, can_show_splash) # start the main app window loader() self.main_window = MainWindow() self.main_window.installEventFilter(self.main_window) # Correct stylesheet bugs application_stylesheet = get_application_stylesheet() if application_stylesheet: self.main_window.setStyleSheet(application_stylesheet) Registry().execute('bootstrap_initialise') State().flush_preconditions() Registry().execute('bootstrap_post_set_up') Registry().initialise = False self.main_window.show() if can_show_splash: # now kill the splashscreen log.debug('Splashscreen closing') self.splash.close() log.debug('Splashscreen closed') # make sure Qt really display the splash screen QtWidgets.QApplication.processEvents() self.main_window.repaint() QtWidgets.QApplication.processEvents() if not has_run_wizard: self.main_window.first_time() if Settings().value('core/update check'): check_for_update(self.main_window) self.main_window.is_display_blank() Registry().execute('bootstrap_completion') return self.exec()
class TestMainWindow(TestCase, TestMixin): def setUp(self): Registry.create() self.registry = Registry() self.setup_application() # Mock cursor busy/normal methods. self.app.set_busy_cursor = MagicMock() self.app.set_normal_cursor = MagicMock() self.app.args = [] Registry().register('application', self.app) # Mock classes and methods used by mainwindow. with patch('openlp.core.ui.mainwindow.SettingsForm') as mocked_settings_form, \ patch('openlp.core.ui.mainwindow.ImageManager') as mocked_image_manager, \ patch('openlp.core.ui.mainwindow.LiveController') as mocked_live_controller, \ patch('openlp.core.ui.mainwindow.PreviewController') as mocked_preview_controller, \ patch('openlp.core.ui.mainwindow.OpenLPDockWidget') as mocked_dock_widget, \ patch('openlp.core.ui.mainwindow.QtWidgets.QToolBox') as mocked_q_tool_box_class, \ patch('openlp.core.ui.mainwindow.QtWidgets.QMainWindow.addDockWidget') as mocked_add_dock_method, \ patch('openlp.core.ui.mainwindow.ThemeManager') as mocked_theme_manager, \ patch('openlp.core.ui.mainwindow.Renderer') as mocked_renderer: self.mocked_settings_form = mocked_settings_form self.mocked_image_manager = mocked_image_manager self.mocked_live_controller = mocked_live_controller self.mocked_preview_controller = mocked_preview_controller self.mocked_dock_widget = mocked_dock_widget self.mocked_q_tool_box_class = mocked_q_tool_box_class self.mocked_add_dock_method = mocked_add_dock_method self.mocked_theme_manager = mocked_theme_manager self.mocked_renderer = mocked_renderer self.main_window = MainWindow() def tearDown(self): del self.main_window def test_cmd_line_file(self): """ Test that passing a service file from the command line loads the service. """ # GIVEN a service as an argument to openlp service = os.path.join(TEST_RESOURCES_PATH, 'service', 'test.osz') self.main_window.arguments = [service] with patch('openlp.core.ui.servicemanager.ServiceManager.load_file') as mocked_load_path: # WHEN the argument is processed self.main_window.open_cmd_line_files(service) # THEN the service from the arguments is loaded mocked_load_path.assert_called_with(service), 'load_path should have been called with the service\'s path' def test_cmd_line_arg(self): """ Test that passing a non service file does nothing. """ # GIVEN a non service file as an argument to openlp service = os.path.join('openlp.py') self.main_window.arguments = [service] with patch('openlp.core.ui.servicemanager.ServiceManager.load_file') as mocked_load_path: # WHEN the argument is processed self.main_window.open_cmd_line_files("") # THEN the file should not be opened assert not mocked_load_path.called, 'load_path should not have been called' def test_main_window_title(self): """ Test that running a new instance of OpenLP set the window title correctly """ # GIVEN a newly opened OpenLP instance # WHEN no changes are made to the service # THEN the main window's title shoud be the same as the OLP string in the UiStrings class self.assertEqual(self.main_window.windowTitle(), UiStrings().OLP, 'The main window\'s title should be the same as the OLP string in UiStrings class') def test_set_service_modifed(self): """ Test that when setting the service's title the main window's title is set correctly """ # GIVEN a newly opened OpenLP instance # WHEN set_service_modified is called with with the modified flag set true and a file name self.main_window.set_service_modified(True, 'test.osz') # THEN the main window's title should be set to the self.assertEqual(self.main_window.windowTitle(), '%s - %s*' % (UiStrings().OLP, 'test.osz'), 'The main window\'s title should be set to "<the contents of UiStrings().OLP> - test.osz*"') def test_set_service_unmodified(self): """ Test that when setting the service's title the main window's title is set correctly """ # GIVEN a newly opened OpenLP instance # WHEN set_service_modified is called with with the modified flag set False and a file name self.main_window.set_service_modified(False, 'test.osz') # THEN the main window's title should be set to the self.assertEqual(self.main_window.windowTitle(), '%s - %s' % (UiStrings().OLP, 'test.osz'), 'The main window\'s title should be set to "<the contents of UiStrings().OLP> - test.osz"') def test_mainwindow_configuration(self): """ Check that the Main Window initialises the Registry Correctly """ # GIVEN: A built main window # WHEN: you check the started functions # THEN: the following registry functions should have been registered self.assertEqual(len(self.registry.service_list), 6, 'The registry should have 6 services.') self.assertEqual(len(self.registry.functions_list), 17, 'The registry should have 17 functions') self.assertTrue('application' in self.registry.service_list, 'The application should have been registered.') self.assertTrue('main_window' in self.registry.service_list, 'The main_window should have been registered.') self.assertTrue('media_controller' in self.registry.service_list, 'The media_controller should have been ' 'registered.') self.assertTrue('plugin_manager' in self.registry.service_list, 'The plugin_manager should have been registered.') def test_projector_manager_hidden_on_startup(self): """ Test that the projector manager is hidden on startup """ # GIVEN: A built main window # WHEN: OpenLP is started # THEN: The projector manager should be hidden self.main_window.projector_manager_dock.setVisible.assert_called_once_with(False) def test_on_search_shortcut_triggered_shows_media_manager(self): """ Test that the media manager is made visible when the search shortcut is triggered """ # GIVEN: A build main window set up for testing with patch.object(self.main_window, 'media_manager_dock') as mocked_media_manager_dock, \ patch.object(self.main_window, 'media_tool_box') as mocked_media_tool_box: mocked_media_manager_dock.isVisible.return_value = False mocked_media_tool_box.currentWidget.return_value = None # WHEN: The search shortcut is triggered self.main_window.on_search_shortcut_triggered() # THEN: The media manager dock is made visible mocked_media_manager_dock.setVisible.assert_called_with(True) def test_on_search_shortcut_triggered_focuses_widget(self): """ Test that the focus is set on the widget when the search shortcut is triggered """ # GIVEN: A build main window set up for testing with patch.object(self.main_window, 'media_manager_dock') as mocked_media_manager_dock, \ patch.object(self.main_window, 'media_tool_box') as mocked_media_tool_box: mocked_media_manager_dock.isVisible.return_value = True mocked_widget = MagicMock() mocked_media_tool_box.currentWidget.return_value = mocked_widget # WHEN: The search shortcut is triggered self.main_window.on_search_shortcut_triggered() # THEN: The media manager dock is made visible self.assertEqual(0, mocked_media_manager_dock.setVisible.call_count) mocked_widget.on_focus.assert_called_with() @patch('openlp.core.ui.mainwindow.MainWindow.plugin_manager') @patch('openlp.core.ui.mainwindow.MainWindow.first_time') @patch('openlp.core.ui.mainwindow.MainWindow.application') @patch('openlp.core.ui.mainwindow.FirstTimeForm') @patch('openlp.core.ui.mainwindow.QtWidgets.QMessageBox.warning') @patch('openlp.core.ui.mainwindow.Settings') def test_on_first_time_wizard_clicked_show_projectors_after(self, mocked_Settings, mocked_warning, mocked_FirstTimeForm, mocked_application, mocked_first_time, mocked_plugin_manager): # GIVEN: Main_window, patched things, patched "Yes" as confirmation to re-run wizard, settings to True. mocked_Settings_obj = MagicMock() mocked_Settings_obj.value.return_value = True mocked_Settings.return_value = mocked_Settings_obj mocked_warning.return_value = QtWidgets.QMessageBox.Yes mocked_FirstTimeForm_obj = MagicMock() mocked_FirstTimeForm_obj.was_cancelled = False mocked_FirstTimeForm.return_value = mocked_FirstTimeForm_obj mocked_plugin_manager.plugins = [] self.main_window.projector_manager_dock = MagicMock() # WHEN: on_first_time_wizard_clicked is called self.main_window.on_first_time_wizard_clicked() # THEN: projector_manager_dock.setVisible should had been called once self.main_window.projector_manager_dock.setVisible.assert_called_once_with(True) @patch('openlp.core.ui.mainwindow.MainWindow.plugin_manager') @patch('openlp.core.ui.mainwindow.MainWindow.first_time') @patch('openlp.core.ui.mainwindow.MainWindow.application') @patch('openlp.core.ui.mainwindow.FirstTimeForm') @patch('openlp.core.ui.mainwindow.QtWidgets.QMessageBox.warning') @patch('openlp.core.ui.mainwindow.Settings') def test_on_first_time_wizard_clicked_hide_projectors_after(self, mocked_Settings, mocked_warning, mocked_FirstTimeForm, mocked_application, mocked_first_time, mocked_plugin_manager): # GIVEN: Main_window, patched things, patched "Yes" as confirmation to re-run wizard, settings to False. mocked_Settings_obj = MagicMock() mocked_Settings_obj.value.return_value = False mocked_Settings.return_value = mocked_Settings_obj mocked_warning.return_value = QtWidgets.QMessageBox.Yes mocked_FirstTimeForm_obj = MagicMock() mocked_FirstTimeForm_obj.was_cancelled = False mocked_FirstTimeForm.return_value = mocked_FirstTimeForm_obj mocked_plugin_manager.plugins = [] self.main_window.projector_manager_dock = MagicMock() # WHEN: on_first_time_wizard_clicked is called self.main_window.on_first_time_wizard_clicked() # THEN: projector_manager_dock.setVisible should had been called once self.main_window.projector_manager_dock.setVisible.assert_called_once_with(False)
def run(self, args): """ Run the OpenLP application. :param args: Some Args """ self.is_event_loop_active = False # On Windows, the args passed into the constructor are ignored. Not very handy, so set the ones we want to use. # On Linux and FreeBSD, in order to set the WM_CLASS property for X11, we pass "OpenLP" in as a command line # argument. This interferes with files being passed in as command line arguments, so we remove it from the list. if 'OpenLP' in args: args.remove('OpenLP') self.args.extend(args) # Decide how many screens we have and their size screens = ScreenList.create(self.desktop()) # First time checks in settings has_run_wizard = Settings().value('core/has run wizard') if not has_run_wizard: ftw = FirstTimeForm() ftw.initialize(screens) if ftw.exec_() == QtGui.QDialog.Accepted: Settings().setValue('core/has run wizard', True) elif ftw.was_cancelled: QtCore.QCoreApplication.exit() sys.exit() # Correct stylesheet bugs application_stylesheet = '' if not Settings().value('advanced/alternate rows'): base_color = self.palette().color(QtGui.QPalette.Active, QtGui.QPalette.Base) alternate_rows_repair_stylesheet = \ 'QTableWidget, QListWidget, QTreeWidget {alternate-background-color: ' + base_color.name() + ';}\n' application_stylesheet += alternate_rows_repair_stylesheet if is_win(): application_stylesheet += WIN_REPAIR_STYLESHEET if application_stylesheet: self.setStyleSheet(application_stylesheet) show_splash = Settings().value('core/show splash') if show_splash: self.splash = SplashScreen() self.splash.show() # make sure Qt really display the splash screen self.processEvents() # Check if OpenLP has been upgrade and if a backup of data should be created self.backup_on_upgrade(has_run_wizard) # start the main app window self.main_window = MainWindow() Registry().execute('bootstrap_initialise') Registry().execute('bootstrap_post_set_up') Registry().initialise = False self.main_window.show() if show_splash: # now kill the splashscreen self.splash.finish(self.main_window) log.debug('Splashscreen closed') # make sure Qt really display the splash screen self.processEvents() self.main_window.repaint() self.processEvents() if not has_run_wizard: self.main_window.first_time() update_check = Settings().value('core/update check') #if update_check: # version = VersionThread(self.main_window) # version.start() self.main_window.is_display_blank() self.main_window.app_startup() return self.exec_()
class OpenLP(OpenLPMixin, QtGui.QApplication): """ The core application class. This class inherits from Qt's QApplication class in order to provide the core of the application. """ args = [] def exec_(self): """ Override exec method to allow the shared memory to be released on exit """ self.is_event_loop_active = True result = QtGui.QApplication.exec_() self.shared_memory.detach() return result def run(self, args): """ Run the OpenLP application. :param args: Some Args """ self.is_event_loop_active = False # On Windows, the args passed into the constructor are ignored. Not very handy, so set the ones we want to use. # On Linux and FreeBSD, in order to set the WM_CLASS property for X11, we pass "OpenLP" in as a command line # argument. This interferes with files being passed in as command line arguments, so we remove it from the list. if 'OpenLP' in args: args.remove('OpenLP') self.args.extend(args) # Decide how many screens we have and their size screens = ScreenList.create(self.desktop()) # First time checks in settings has_run_wizard = Settings().value('core/has run wizard') if not has_run_wizard: ftw = FirstTimeForm() ftw.initialize(screens) if ftw.exec_() == QtGui.QDialog.Accepted: Settings().setValue('core/has run wizard', True) elif ftw.was_cancelled: QtCore.QCoreApplication.exit() sys.exit() # Correct stylesheet bugs application_stylesheet = '' if not Settings().value('advanced/alternate rows'): base_color = self.palette().color(QtGui.QPalette.Active, QtGui.QPalette.Base) alternate_rows_repair_stylesheet = \ 'QTableWidget, QListWidget, QTreeWidget {alternate-background-color: ' + base_color.name() + ';}\n' application_stylesheet += alternate_rows_repair_stylesheet if is_win(): application_stylesheet += WIN_REPAIR_STYLESHEET if application_stylesheet: self.setStyleSheet(application_stylesheet) show_splash = Settings().value('core/show splash') if show_splash: self.splash = SplashScreen() self.splash.show() # make sure Qt really display the splash screen self.processEvents() # Check if OpenLP has been upgrade and if a backup of data should be created self.backup_on_upgrade(has_run_wizard) # start the main app window self.main_window = MainWindow() Registry().execute('bootstrap_initialise') Registry().execute('bootstrap_post_set_up') Registry().initialise = False self.main_window.show() if show_splash: # now kill the splashscreen self.splash.finish(self.main_window) log.debug('Splashscreen closed') # make sure Qt really display the splash screen self.processEvents() self.main_window.repaint() self.processEvents() if not has_run_wizard: self.main_window.first_time() update_check = Settings().value('core/update check') #if update_check: # version = VersionThread(self.main_window) # version.start() self.main_window.is_display_blank() self.main_window.app_startup() return self.exec_() def is_already_running(self): """ Look to see if OpenLP is already running and ask if a 2nd instance is to be started. """ self.shared_memory = QtCore.QSharedMemory('OpenLP') if self.shared_memory.attach(): status = QtGui.QMessageBox.critical(None, UiStrings().Error, UiStrings().OpenLPStart, QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)) if status == QtGui.QMessageBox.No: return True return False else: self.shared_memory.create(1) return False def hook_exception(self, exc_type, value, traceback): """ Add an exception hook so that any uncaught exceptions are displayed in this window rather than somewhere where users cannot see it and cannot report when we encounter these problems. :param exc_type: The class of exception. :param value: The actual exception object. :param traceback: A traceback object with the details of where the exception occurred. """ # We can't log.exception here because the last exception no longer exists, we're actually busy handling it. log.critical(''.join(format_exception(exc_type, value, traceback))) if not hasattr(self, 'exception_form'): self.exception_form = ExceptionForm() self.exception_form.exception_text_edit.setPlainText(''.join(format_exception(exc_type, value, traceback))) self.set_normal_cursor() self.exception_form.exec_() def backup_on_upgrade(self, has_run_wizard): """ Check if OpenLP has been upgraded, and ask if a backup of data should be made :param has_run_wizard: OpenLP has been run before """ data_version = Settings().value('core/application version') openlp_version = get_application_version()['version'] # New installation, no need to create backup if not has_run_wizard: Settings().setValue('core/application version', openlp_version) # If data_version is different from the current version ask if we should backup the data folder elif data_version != openlp_version: if QtGui.QMessageBox.question(None, translate('OpenLP', 'Backup'), translate('OpenLP', 'OpenLP has been upgraded, ' 'do you want to create a backup of OpenLPs data folder?'), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.Yes) == QtGui.QMessageBox.Yes: # Create copy of data folder data_folder_path = AppLocation.get_data_path() timestamp = time.strftime("%Y%m%d-%H%M%S") data_folder_backup_path = data_folder_path + '-' + timestamp try: shutil.copytree(data_folder_path, data_folder_backup_path) except OSError: QtGui.QMessageBox.warning(None, translate('OpenLP', 'Backup'), translate('OpenLP', 'Backup of the data folder failed!')) return QtGui.QMessageBox.information(None, translate('OpenLP', 'Backup'), translate('OpenLP', 'A backup of the data folder has been created at %s') % data_folder_backup_path) # Update the version in the settings Settings().setValue('core/application version', openlp_version) def process_events(self): """ Wrapper to make ProcessEvents visible and named correctly """ self.processEvents() def set_busy_cursor(self): """ Sets the Busy Cursor for the Application """ self.setOverrideCursor(QtCore.Qt.BusyCursor) self.processEvents() def set_normal_cursor(self): """ Sets the Normal Cursor for the Application """ self.restoreOverrideCursor() self.processEvents() def event(self, event): """ Enables platform specific event handling i.e. direct file opening on OS X :param event: The event """ if event.type() == QtCore.QEvent.FileOpen: file_name = event.file() log.debug('Got open file event for %s!', file_name) self.args.insert(0, file_name) return True # Mac OS X should restore app window when user clicked on the OpenLP icon # in the Dock bar. However, OpenLP consists of multiple windows and this # does not work. This workaround fixes that. # The main OpenLP window is restored when it was previously minimized. elif event.type() == QtCore.QEvent.ApplicationActivate: if is_macosx() and hasattr(self, 'main_window'): if self.main_window.isMinimized(): # Copied from QWidget.setWindowState() docs on how to restore and activate a minimized window # while preserving its maximized and/or full-screen state. self.main_window.setWindowState(self.main_window.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive) return True return QtGui.QApplication.event(self, event)
class OpenLP(OpenLPMixin, QtGui.QApplication): """ The core application class. This class inherits from Qt's QApplication class in order to provide the core of the application. """ args = [] def exec_(self): """ Override exec method to allow the shared memory to be released on exit """ self.is_event_loop_active = True result = QtGui.QApplication.exec_() self.shared_memory.detach() return result def run(self, args): """ Run the OpenLP application. :param args: Some Args """ self.is_event_loop_active = False # On Windows, the args passed into the constructor are ignored. Not very handy, so set the ones we want to use. # On Linux and FreeBSD, in order to set the WM_CLASS property for X11, we pass "OpenLP" in as a command line # argument. This interferes with files being passed in as command line arguments, so we remove it from the list. if 'OpenLP' in args: args.remove('OpenLP') self.args.extend(args) # Decide how many screens we have and their size screens = ScreenList.create(self.desktop()) # First time checks in settings has_run_wizard = Settings().value('core/has run wizard') if not has_run_wizard: ftw = FirstTimeForm() ftw.initialize(screens) if ftw.exec_() == QtGui.QDialog.Accepted: Settings().setValue('core/has run wizard', True) elif ftw.was_cancelled: QtCore.QCoreApplication.exit() sys.exit() # Correct stylesheet bugs application_stylesheet = '' if not Settings().value('advanced/alternate rows'): base_color = self.palette().color(QtGui.QPalette.Active, QtGui.QPalette.Base) alternate_rows_repair_stylesheet = \ 'QTableWidget, QListWidget, QTreeWidget {alternate-background-color: ' + base_color.name() + ';}\n' application_stylesheet += alternate_rows_repair_stylesheet if is_win(): application_stylesheet += WIN_REPAIR_STYLESHEET if application_stylesheet: self.setStyleSheet(application_stylesheet) show_splash = Settings().value('core/show splash') if show_splash: self.splash = SplashScreen() self.splash.show() # make sure Qt really display the splash screen self.processEvents() # Check if OpenLP has been upgrade and if a backup of data should be created self.backup_on_upgrade(has_run_wizard) # start the main app window self.main_window = MainWindow() Registry().execute('bootstrap_initialise') Registry().execute('bootstrap_post_set_up') Registry().initialise = False self.main_window.show() if show_splash: # now kill the splashscreen self.splash.finish(self.main_window) log.debug('Splashscreen closed') # make sure Qt really display the splash screen self.processEvents() self.main_window.repaint() self.processEvents() if not has_run_wizard: self.main_window.first_time() update_check = Settings().value('core/update check') #if update_check: # version = VersionThread(self.main_window) # version.start() self.main_window.is_display_blank() self.main_window.app_startup() return self.exec_() def is_already_running(self): """ Look to see if OpenLP is already running and ask if a 2nd instance is to be started. """ self.shared_memory = QtCore.QSharedMemory('OpenLP') if self.shared_memory.attach(): status = QtGui.QMessageBox.critical( None, UiStrings().Error, UiStrings().OpenLPStart, QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)) if status == QtGui.QMessageBox.No: return True return False else: self.shared_memory.create(1) return False def hook_exception(self, exc_type, value, traceback): """ Add an exception hook so that any uncaught exceptions are displayed in this window rather than somewhere where users cannot see it and cannot report when we encounter these problems. :param exc_type: The class of exception. :param value: The actual exception object. :param traceback: A traceback object with the details of where the exception occurred. """ # We can't log.exception here because the last exception no longer exists, we're actually busy handling it. log.critical(''.join(format_exception(exc_type, value, traceback))) if not hasattr(self, 'exception_form'): self.exception_form = ExceptionForm() self.exception_form.exception_text_edit.setPlainText(''.join( format_exception(exc_type, value, traceback))) self.set_normal_cursor() self.exception_form.exec_() def backup_on_upgrade(self, has_run_wizard): """ Check if OpenLP has been upgraded, and ask if a backup of data should be made :param has_run_wizard: OpenLP has been run before """ data_version = Settings().value('core/application version') openlp_version = get_application_version()['version'] # New installation, no need to create backup if not has_run_wizard: Settings().setValue('core/application version', openlp_version) # If data_version is different from the current version ask if we should backup the data folder elif data_version != openlp_version: if QtGui.QMessageBox.question( None, translate('OpenLP', 'Backup'), translate( 'OpenLP', 'OpenLP has been upgraded, ' 'do you want to create a backup of OpenLPs data folder?' ), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.Yes) == QtGui.QMessageBox.Yes: # Create copy of data folder data_folder_path = AppLocation.get_data_path() timestamp = time.strftime("%Y%m%d-%H%M%S") data_folder_backup_path = data_folder_path + '-' + timestamp try: shutil.copytree(data_folder_path, data_folder_backup_path) except OSError: QtGui.QMessageBox.warning( None, translate('OpenLP', 'Backup'), translate('OpenLP', 'Backup of the data folder failed!')) return QtGui.QMessageBox.information( None, translate('OpenLP', 'Backup'), translate( 'OpenLP', 'A backup of the data folder has been created at %s') % data_folder_backup_path) # Update the version in the settings Settings().setValue('core/application version', openlp_version) def process_events(self): """ Wrapper to make ProcessEvents visible and named correctly """ self.processEvents() def set_busy_cursor(self): """ Sets the Busy Cursor for the Application """ self.setOverrideCursor(QtCore.Qt.BusyCursor) self.processEvents() def set_normal_cursor(self): """ Sets the Normal Cursor for the Application """ self.restoreOverrideCursor() self.processEvents() def event(self, event): """ Enables platform specific event handling i.e. direct file opening on OS X :param event: The event """ if event.type() == QtCore.QEvent.FileOpen: file_name = event.file() log.debug('Got open file event for %s!', file_name) self.args.insert(0, file_name) return True # Mac OS X should restore app window when user clicked on the OpenLP icon # in the Dock bar. However, OpenLP consists of multiple windows and this # does not work. This workaround fixes that. # The main OpenLP window is restored when it was previously minimized. elif event.type() == QtCore.QEvent.ApplicationActivate: if is_macosx() and hasattr(self, 'main_window'): if self.main_window.isMinimized(): # Copied from QWidget.setWindowState() docs on how to restore and activate a minimized window # while preserving its maximized and/or full-screen state. self.main_window.setWindowState( self.main_window.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive) return True return QtGui.QApplication.event(self, event)
class TestMainWindow(TestCase, TestMixin): def setUp(self): """ Create the UI """ Registry.create() self.registry = Registry() self.setup_application() # Mock cursor busy/normal methods. self.app.set_busy_cursor = MagicMock() self.app.set_normal_cursor = MagicMock() self.app.args = [] Registry().register('application', self.app) # Mock classes and methods used by mainwindow. with patch('openlp.core.ui.mainwindow.SettingsForm') as mocked_settings_form, \ patch('openlp.core.ui.mainwindow.ImageManager') as mocked_image_manager, \ patch('openlp.core.ui.mainwindow.LiveController') as mocked_live_controller, \ patch('openlp.core.ui.mainwindow.PreviewController') as mocked_preview_controller, \ patch('openlp.core.ui.mainwindow.OpenLPDockWidget') as mocked_dock_widget, \ patch('openlp.core.ui.mainwindow.QtGui.QToolBox') as mocked_q_tool_box_class, \ patch('openlp.core.ui.mainwindow.QtGui.QMainWindow.addDockWidget') as mocked_add_dock_method, \ patch('openlp.core.ui.mainwindow.ServiceManager') as mocked_service_manager, \ patch('openlp.core.ui.mainwindow.ThemeManager') as mocked_theme_manager, \ patch('openlp.core.ui.mainwindow.ProjectorManager') as mocked_projector_manager, \ patch('openlp.core.ui.mainwindow.Renderer') as mocked_renderer: self.main_window = MainWindow() def tearDown(self): """ Delete all the C++ objects at the end so that we don't have a segfault """ del self.main_window def restore_current_media_manager_item_test(self): """ Regression test for bug #1152509. """ # GIVEN: Mocked Settings().value method. with patch('openlp.core.ui.mainwindow.Settings.value') as mocked_value: # save current plugin: True; current media plugin: 2 mocked_value.side_effect = [True, 2] # WHEN: Call the restore method. self.main_window.restore_current_media_manager_item() # THEN: The current widget should have been set. self.main_window.media_tool_box.setCurrentIndex.assert_called_with(2) def projector_manager_dock_locked_test(self): """ Projector Manager enable UI options - bug #1390702 """ # GIVEN: A mocked projector manager dock item: projector_dock = self.main_window.projector_manager_dock # WHEN: main_window.lock_panel action is triggered self.main_window.lock_panel.triggered.emit(True) # THEN: Projector manager dock should have been called with disable UI features projector_dock.setFeatures.assert_called_with(0) def projector_manager_dock_unlocked_test(self): """ Projector Manager disable UI options - bug #1390702 """ # GIVEN: A mocked projector manager dock item: projector_dock = self.main_window.projector_manager_dock # WHEN: main_window.lock_panel action is triggered self.main_window.lock_panel.triggered.emit(False) # THEN: Projector manager dock should have been called with enable UI features projector_dock.setFeatures.assert_called_with(7)
class TestMainWindow(TestCase, TestMixin): def setUp(self): Registry.create() self.registry = Registry() self.setup_application() # Mock cursor busy/normal methods. self.app.set_busy_cursor = MagicMock() self.app.set_normal_cursor = MagicMock() self.app.args = [] Registry().register('application', self.app) # Mock classes and methods used by mainwindow. with patch('openlp.core.ui.mainwindow.SettingsForm') as mocked_settings_form, \ patch('openlp.core.ui.mainwindow.ImageManager') as mocked_image_manager, \ patch('openlp.core.ui.mainwindow.LiveController') as mocked_live_controller, \ patch('openlp.core.ui.mainwindow.PreviewController') as mocked_preview_controller, \ patch('openlp.core.ui.mainwindow.OpenLPDockWidget') as mocked_dock_widget, \ patch('openlp.core.ui.mainwindow.QtWidgets.QToolBox') as mocked_q_tool_box_class, \ patch('openlp.core.ui.mainwindow.QtWidgets.QMainWindow.addDockWidget') as mocked_add_dock_method, \ patch('openlp.core.ui.mainwindow.ThemeManager') as mocked_theme_manager, \ patch('openlp.core.ui.mainwindow.Renderer') as mocked_renderer: self.mocked_settings_form = mocked_settings_form self.mocked_image_manager = mocked_image_manager self.mocked_live_controller = mocked_live_controller self.mocked_preview_controller = mocked_preview_controller self.mocked_dock_widget = mocked_dock_widget self.mocked_q_tool_box_class = mocked_q_tool_box_class self.mocked_add_dock_method = mocked_add_dock_method self.mocked_theme_manager = mocked_theme_manager self.mocked_renderer = mocked_renderer self.main_window = MainWindow() def tearDown(self): del self.main_window def test_cmd_line_file(self): """ Test that passing a service file from the command line loads the service. """ # GIVEN a service as an argument to openlp service = os.path.join(TEST_RESOURCES_PATH, 'service', 'test.osz') self.main_window.arguments = [service] with patch('openlp.core.ui.servicemanager.ServiceManager.load_file' ) as mocked_load_path: # WHEN the argument is processed self.main_window.open_cmd_line_files(service) # THEN the service from the arguments is loaded mocked_load_path.assert_called_with( service ), 'load_path should have been called with the service\'s path' def test_cmd_line_arg(self): """ Test that passing a non service file does nothing. """ # GIVEN a non service file as an argument to openlp service = os.path.join('openlp.py') self.main_window.arguments = [service] with patch('openlp.core.ui.servicemanager.ServiceManager.load_file' ) as mocked_load_path: # WHEN the argument is processed self.main_window.open_cmd_line_files("") # THEN the file should not be opened assert not mocked_load_path.called, 'load_path should not have been called' def test_main_window_title(self): """ Test that running a new instance of OpenLP set the window title correctly """ # GIVEN a newly opened OpenLP instance # WHEN no changes are made to the service # THEN the main window's title shoud be the same as the OLP string in the UiStrings class self.assertEqual( self.main_window.windowTitle(), UiStrings().OLP, 'The main window\'s title should be the same as the OLP string in UiStrings class' ) def test_set_service_modifed(self): """ Test that when setting the service's title the main window's title is set correctly """ # GIVEN a newly opened OpenLP instance # WHEN set_service_modified is called with with the modified flag set true and a file name self.main_window.set_service_modified(True, 'test.osz') # THEN the main window's title should be set to the self.assertEqual( self.main_window.windowTitle(), '%s - %s*' % (UiStrings().OLP, 'test.osz'), 'The main window\'s title should be set to "<the contents of UiStrings().OLP> - test.osz*"' ) def test_set_service_unmodified(self): """ Test that when setting the service's title the main window's title is set correctly """ # GIVEN a newly opened OpenLP instance # WHEN set_service_modified is called with with the modified flag set False and a file name self.main_window.set_service_modified(False, 'test.osz') # THEN the main window's title should be set to the self.assertEqual( self.main_window.windowTitle(), '%s - %s' % (UiStrings().OLP, 'test.osz'), 'The main window\'s title should be set to "<the contents of UiStrings().OLP> - test.osz"' ) def test_mainwindow_configuration(self): """ Check that the Main Window initialises the Registry Correctly """ # GIVEN: A built main window # WHEN: you check the started functions # THEN: the following registry functions should have been registered self.assertEqual(len(self.registry.service_list), 6, 'The registry should have 6 services.') self.assertEqual(len(self.registry.functions_list), 17, 'The registry should have 17 functions') self.assertTrue('application' in self.registry.service_list, 'The application should have been registered.') self.assertTrue('main_window' in self.registry.service_list, 'The main_window should have been registered.') self.assertTrue('media_controller' in self.registry.service_list, 'The media_controller should have been ' 'registered.') self.assertTrue('plugin_manager' in self.registry.service_list, 'The plugin_manager should have been registered.') def test_on_search_shortcut_triggered_shows_media_manager(self): """ Test that the media manager is made visible when the search shortcut is triggered """ # GIVEN: A build main window set up for testing with patch.object(self.main_window, 'media_manager_dock') as mocked_media_manager_dock, \ patch.object(self.main_window, 'media_tool_box') as mocked_media_tool_box: mocked_media_manager_dock.isVisible.return_value = False mocked_media_tool_box.currentWidget.return_value = None # WHEN: The search shortcut is triggered self.main_window.on_search_shortcut_triggered() # THEN: The media manager dock is made visible mocked_media_manager_dock.setVisible.assert_called_with(True) def test_on_search_shortcut_triggered_focuses_widget(self): """ Test that the focus is set on the widget when the search shortcut is triggered """ # GIVEN: A build main window set up for testing with patch.object(self.main_window, 'media_manager_dock') as mocked_media_manager_dock, \ patch.object(self.main_window, 'media_tool_box') as mocked_media_tool_box: mocked_media_manager_dock.isVisible.return_value = True mocked_widget = MagicMock() mocked_media_tool_box.currentWidget.return_value = mocked_widget # WHEN: The search shortcut is triggered self.main_window.on_search_shortcut_triggered() # THEN: The media manager dock is made visible self.assertEqual(0, mocked_media_manager_dock.setVisible.call_count) mocked_widget.on_focus.assert_called_with() @patch('openlp.core.ui.mainwindow.MainWindow.plugin_manager') @patch('openlp.core.ui.mainwindow.MainWindow.first_time') @patch('openlp.core.ui.mainwindow.MainWindow.application') @patch('openlp.core.ui.mainwindow.FirstTimeForm') @patch('openlp.core.ui.mainwindow.QtWidgets.QMessageBox.warning') @patch('openlp.core.ui.mainwindow.Settings') def test_on_first_time_wizard_clicked_show_projectors_after( self, mocked_Settings, mocked_warning, mocked_FirstTimeForm, mocked_application, mocked_first_time, mocked_plugin_manager): # GIVEN: Main_window, patched things, patched "Yes" as confirmation to re-run wizard, settings to True. mocked_Settings_obj = MagicMock() mocked_Settings_obj.value.return_value = True mocked_Settings.return_value = mocked_Settings_obj mocked_warning.return_value = QtWidgets.QMessageBox.Yes mocked_FirstTimeForm_obj = MagicMock() mocked_FirstTimeForm_obj.was_cancelled = False mocked_FirstTimeForm.return_value = mocked_FirstTimeForm_obj mocked_plugin_manager.plugins = [] self.main_window.projector_manager_dock = MagicMock() # WHEN: on_first_time_wizard_clicked is called self.main_window.on_first_time_wizard_clicked() # THEN: projector_manager_dock.setVisible should had been called once self.main_window.projector_manager_dock.setVisible.assert_called_once_with( True) @patch('openlp.core.ui.mainwindow.MainWindow.plugin_manager') @patch('openlp.core.ui.mainwindow.MainWindow.first_time') @patch('openlp.core.ui.mainwindow.MainWindow.application') @patch('openlp.core.ui.mainwindow.FirstTimeForm') @patch('openlp.core.ui.mainwindow.QtWidgets.QMessageBox.warning') @patch('openlp.core.ui.mainwindow.Settings') def test_on_first_time_wizard_clicked_hide_projectors_after( self, mocked_Settings, mocked_warning, mocked_FirstTimeForm, mocked_application, mocked_first_time, mocked_plugin_manager): # GIVEN: Main_window, patched things, patched "Yes" as confirmation to re-run wizard, settings to False. mocked_Settings_obj = MagicMock() mocked_Settings_obj.value.return_value = False mocked_Settings.return_value = mocked_Settings_obj mocked_warning.return_value = QtWidgets.QMessageBox.Yes mocked_FirstTimeForm_obj = MagicMock() mocked_FirstTimeForm_obj.was_cancelled = False mocked_FirstTimeForm.return_value = mocked_FirstTimeForm_obj mocked_plugin_manager.plugins = [] self.main_window.projector_manager_dock = MagicMock() # WHEN: on_first_time_wizard_clicked is called self.main_window.on_first_time_wizard_clicked() # THEN: projector_manager_dock.setVisible should had been called once self.main_window.projector_manager_dock.setVisible.assert_called_once_with( False)
class OpenLP(QtWidgets.QApplication): """ The core application class. This class inherits from Qt's QApplication class in order to provide the core of the application. """ args = [] worker_threads = {} def exec(self): """ Override exec method to allow the shared memory to be released on exit """ self.is_event_loop_active = True result = QtWidgets.QApplication.exec() self.server.close_server() return result def run(self, args): """ Run the OpenLP application. :param args: Some Args """ self.is_event_loop_active = False # On Windows, the args passed into the constructor are ignored. Not very handy, so set the ones we want to use. # On Linux and FreeBSD, in order to set the WM_CLASS property for X11, we pass "OpenLP" in as a command line # argument. This interferes with files being passed in as command line arguments, so we remove it from the list. if 'OpenLP' in args: args.remove('OpenLP') self.args.extend(args) # Decide how many screens we have and their size screens = ScreenList.create(self.desktop()) # First time checks in settings has_run_wizard = Settings().value('core/has run wizard') if not has_run_wizard: ftw = FirstTimeForm() ftw.initialize(screens) if ftw.exec() == QtWidgets.QDialog.Accepted: Settings().setValue('core/has run wizard', True) elif ftw.was_cancelled: QtCore.QCoreApplication.exit() sys.exit() # Correct stylesheet bugs application_stylesheet = get_application_stylesheet() if application_stylesheet: self.setStyleSheet(application_stylesheet) can_show_splash = Settings().value('core/show splash') if can_show_splash: self.splash = SplashScreen() self.splash.show() # make sure Qt really display the splash screen self.processEvents() # Check if OpenLP has been upgrade and if a backup of data should be created self.backup_on_upgrade(has_run_wizard, can_show_splash) # start the main app window self.main_window = MainWindow() Registry().execute('bootstrap_initialise') Registry().execute('bootstrap_post_set_up') Registry().initialise = False self.main_window.show() if can_show_splash: # now kill the splashscreen log.debug('Splashscreen closing') self.splash.close() log.debug('Splashscreen closed') # make sure Qt really display the splash screen self.processEvents() self.main_window.repaint() self.processEvents() if not has_run_wizard: self.main_window.first_time() if Settings().value('core/update check'): check_for_update(self.main_window) self.main_window.is_display_blank() self.main_window.app_startup() return self.exec() @staticmethod def is_already_running(): """ Tell the user there is a 2nd instance running. """ QtWidgets.QMessageBox.critical( None, UiStrings().Error, UiStrings().OpenLPStart, QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok)) @staticmethod def is_data_path_missing(): """ Check if the data folder path exists. """ data_folder_path = AppLocation.get_data_path() if not data_folder_path.exists(): log.critical('Database was not found in: %s', data_folder_path) status = QtWidgets.QMessageBox.critical( None, translate('OpenLP', 'Data Directory Error'), translate( 'OpenLP', 'OpenLP data folder was not found in:\n\n{path}\n\nThe location of the data folder ' 'was previously changed from the OpenLP\'s default location. If the data was ' 'stored on removable device, that device needs to be made available.\n\nYou may ' 'reset the data location back to the default location, or you can try to make the ' 'current location available.\n\nDo you want to reset to the default data location? ' 'If not, OpenLP will be closed so you can try to fix the the problem.' ).format(path=data_folder_path), QtWidgets.QMessageBox.StandardButtons( QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No), QtWidgets.QMessageBox.No) if status == QtWidgets.QMessageBox.No: # If answer was "No", return "True", it will shutdown OpenLP in def main log.info('User requested termination') return True # If answer was "Yes", remove the custom data path thus resetting the default location. Settings().remove('advanced/data path') log.info( 'Database location has been reset to the default settings.') return False def hook_exception(self, exc_type, value, traceback): """ Add an exception hook so that any uncaught exceptions are displayed in this window rather than somewhere where users cannot see it and cannot report when we encounter these problems. :param exc_type: The class of exception. :param value: The actual exception object. :param traceback: A traceback object with the details of where the exception occurred. """ # We can't log.exception here because the last exception no longer exists, we're actually busy handling it. log.critical(''.join(format_exception(exc_type, value, traceback))) if not hasattr(self, 'exception_form'): self.exception_form = ExceptionForm() self.exception_form.exception_text_edit.setPlainText(''.join( format_exception(exc_type, value, traceback))) self.set_normal_cursor() is_splash_visible = False if hasattr(self, 'splash') and self.splash.isVisible(): is_splash_visible = True self.splash.hide() self.exception_form.exec() if is_splash_visible: self.splash.show() def backup_on_upgrade(self, has_run_wizard, can_show_splash): """ Check if OpenLP has been upgraded, and ask if a backup of data should be made :param has_run_wizard: OpenLP has been run before :param can_show_splash: Should OpenLP show the splash screen """ data_version = Settings().value('core/application version') openlp_version = get_version()['version'] # New installation, no need to create backup if not has_run_wizard: Settings().setValue('core/application version', openlp_version) # If data_version is different from the current version ask if we should backup the data folder elif data_version != openlp_version: if can_show_splash and self.splash.isVisible(): self.splash.hide() if QtWidgets.QMessageBox.question( None, translate('OpenLP', 'Backup'), translate( 'OpenLP', 'OpenLP has been upgraded, do you want to create\n' 'a backup of the old data folder?'), defaultButton=QtWidgets.QMessageBox.Yes ) == QtWidgets.QMessageBox.Yes: # Create copy of data folder data_folder_path = AppLocation.get_data_path() timestamp = time.strftime("%Y%m%d-%H%M%S") data_folder_backup_path = data_folder_path.with_name( data_folder_path.name + '-' + timestamp) try: copytree(data_folder_path, data_folder_backup_path) except OSError: QtWidgets.QMessageBox.warning( None, translate('OpenLP', 'Backup'), translate('OpenLP', 'Backup of the data folder failed!')) return message = translate( 'OpenLP', 'A backup of the data folder has been created at:\n\n' '{text}').format(text=data_folder_backup_path) QtWidgets.QMessageBox.information( None, translate('OpenLP', 'Backup'), message) # Update the version in the settings Settings().setValue('core/application version', openlp_version) if can_show_splash: self.splash.show() def process_events(self): """ Wrapper to make ProcessEvents visible and named correctly """ self.processEvents() def set_busy_cursor(self): """ Sets the Busy Cursor for the Application """ self.setOverrideCursor(QtCore.Qt.BusyCursor) self.processEvents() def set_normal_cursor(self): """ Sets the Normal Cursor for the Application """ self.restoreOverrideCursor() self.processEvents() def event(self, event): """ Enables platform specific event handling i.e. direct file opening on OS X :param event: The event """ if event.type() == QtCore.QEvent.FileOpen: file_name = event.file() log.debug('Got open file event for {name}!'.format(name=file_name)) self.args.insert(0, file_name) return True # Mac OS X should restore app window when user clicked on the OpenLP icon # in the Dock bar. However, OpenLP consists of multiple windows and this # does not work. This workaround fixes that. # The main OpenLP window is restored when it was previously minimized. elif event.type() == QtCore.QEvent.ApplicationActivate: if is_macosx() and hasattr(self, 'main_window'): if self.main_window.isMinimized(): # Copied from QWidget.setWindowState() docs on how to restore and activate a minimized window # while preserving its maximized and/or full-screen state. self.main_window.setWindowState( self.main_window.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive) return True return QtWidgets.QApplication.event(self, event)
class TestMainWindow(TestCase, TestMixin): def setUp(self): """ Create the UI """ Registry.create() self.registry = Registry() self.setup_application() # Mock cursor busy/normal methods. self.app.set_busy_cursor = MagicMock() self.app.set_normal_cursor = MagicMock() self.app.args = [] Registry().register('application', self.app) Registry().set_flag('no_web_server', True) # Mock classes and methods used by mainwindow. with patch('openlp.core.ui.mainwindow.SettingsForm'), \ patch('openlp.core.ui.mainwindow.ImageManager'), \ patch('openlp.core.ui.mainwindow.LiveController'), \ patch('openlp.core.ui.mainwindow.PreviewController'), \ patch('openlp.core.ui.mainwindow.OpenLPDockWidget'), \ patch('openlp.core.ui.mainwindow.QtWidgets.QToolBox'), \ patch('openlp.core.ui.mainwindow.QtWidgets.QMainWindow.addDockWidget'), \ patch('openlp.core.ui.mainwindow.ServiceManager'), \ patch('openlp.core.ui.mainwindow.ThemeManager'), \ patch('openlp.core.ui.mainwindow.ProjectorManager'), \ patch('openlp.core.ui.mainwindow.Renderer'), \ patch('openlp.core.ui.mainwindow.websockets.WebSocketServer'), \ patch('openlp.core.ui.mainwindow.server.HttpServer'): self.main_window = MainWindow() def tearDown(self): """ Delete all the C++ objects at the end so that we don't have a segfault """ del self.main_window def test_restore_current_media_manager_item(self): """ Regression test for bug #1152509. """ # GIVEN: Mocked Settings().value method. with patch('openlp.core.ui.mainwindow.Settings.value') as mocked_value: # save current plugin: True; current media plugin: 2 mocked_value.side_effect = [True, 2] # WHEN: Call the restore method. self.main_window.restore_current_media_manager_item() # THEN: The current widget should have been set. self.main_window.media_tool_box.setCurrentIndex.assert_called_with( 2) def test_projector_manager_dock_locked(self): """ Projector Manager enable UI options - bug #1390702 """ # GIVEN: A mocked projector manager dock item: projector_dock = self.main_window.projector_manager_dock # WHEN: main_window.lock_panel action is triggered self.main_window.lock_panel.triggered.emit(True) # THEN: Projector manager dock should have been called with disable UI features projector_dock.setFeatures.assert_called_with(0) def test_projector_manager_dock_unlocked(self): """ Projector Manager disable UI options - bug #1390702 """ # GIVEN: A mocked projector manager dock item: projector_dock = self.main_window.projector_manager_dock # WHEN: main_window.lock_panel action is triggered self.main_window.lock_panel.triggered.emit(False) # THEN: Projector manager dock should have been called with enable UI features projector_dock.setFeatures.assert_called_with(7)
class TestMainWindow(TestCase, TestMixin): """ Test the main window """ def _create_mock_action(self, parent, name, **kwargs): """ Create a fake action with some "real" attributes """ action = QtWidgets.QAction(parent) action.setObjectName(name) if kwargs.get('triggers'): action.triggered.connect(kwargs.pop('triggers')) return action def setUp(self): """ Set up the objects we need for all of the tests """ Registry.create() self.registry = Registry() self.setup_application() # Mock cursor busy/normal methods. self.app.set_busy_cursor = MagicMock() self.app.set_normal_cursor = MagicMock() self.app.process_events = MagicMock() self.app.args = [] Registry().register('application', self.app) Registry().set_flag('no_web_server', True) self.add_toolbar_action_patcher = patch( 'openlp.core.ui.mainwindow.create_action') self.mocked_add_toolbar_action = self.add_toolbar_action_patcher.start( ) self.mocked_add_toolbar_action.side_effect = self._create_mock_action self.renderer_patcher = patch('openlp.core.display.render.Renderer') self.mocked_renderer = self.renderer_patcher.start() mocked_desktop = MagicMock() mocked_desktop.screenCount.return_value = 1 mocked_desktop.screenGeometry.return_value = QtCore.QRect( 0, 0, 1024, 768) mocked_desktop.primaryScreen.return_value = 1 ScreenList.create(mocked_desktop) State().load_settings() self.main_window = MainWindow() def tearDown(self): """ Delete all the C++ objects and stop all the patchers """ del self.main_window self.renderer_patcher.stop() self.add_toolbar_action_patcher.stop() def test_cmd_line_file(self): """ Test that passing a service file from the command line loads the service. """ # GIVEN a service as an argument to openlp service = os.path.join(TEST_RESOURCES_PATH, 'service', 'test.osz') # WHEN the argument is processed with patch.object(self.main_window.service_manager, 'load_file') as mocked_load_file: self.main_window.open_cmd_line_files([service]) # THEN the service from the arguments is loaded mocked_load_file.assert_called_with(Path(service)) @patch('openlp.core.ui.servicemanager.ServiceManager.load_file') def test_cmd_line_arg(self, mocked_load_file): """ Test that passing a non service file does nothing. """ # GIVEN a non service file as an argument to openlp service = 'run_openlp.py' # WHEN the argument is processed self.main_window.open_cmd_line_files(service) # THEN the file should not be opened assert mocked_load_file.called is False, 'load_file should not have been called' def test_main_window_title(self): """ Test that running a new instance of OpenLP set the window title correctly """ # GIVEN a newly opened OpenLP instance # WHEN no changes are made to the service # THEN the main window's title shoud be the same as the OpenLP string in the UiStrings class assert self.main_window.windowTitle() == UiStrings().OpenLP, \ 'The main window\'s title should be the same as the OpenLP string in UiStrings class' def test_set_service_modifed(self): """ Test that when setting the service's title the main window's title is set correctly """ # GIVEN a newly opened OpenLP instance # WHEN set_service_modified is called with with the modified flag set true and a file name self.main_window.set_service_modified(True, 'test.osz') # THEN the main window's title should be set to the assert self.main_window.windowTitle(), '%s - %s*' % (UiStrings().OpenLP, 'test.osz') == \ 'The main window\'s title should be set to "<the contents of UiStrings().OpenLP> - test.osz*"' def test_set_service_unmodified(self): """ Test that when setting the service's title the main window's title is set correctly """ # GIVEN a newly opened OpenLP instance # WHEN set_service_modified is called with with the modified flag set False and a file name self.main_window.set_service_modified(False, 'test.osz') # THEN the main window's title should be set to the assert self.main_window.windowTitle(), '%s - %s' % (UiStrings().OpenLP, 'test.osz') == \ 'The main window\'s title should be set to "<the contents of UiStrings().OpenLP> - test.osz"' def test_mainwindow_configuration(self): """ Check that the Main Window initialises the Registry Correctly """ # GIVEN: A built main window # WHEN: you check the started functions # THEN: the following registry functions should have been registered expected_service_list = [ 'application', 'main_window', 'http_server', 'settings_form', 'service_manager', 'theme_manager', 'projector_manager' ] expected_functions_list = [ 'bootstrap_initialise', 'bootstrap_post_set_up', 'bootstrap_completion', 'theme_update_global', 'config_screen_changed' ] assert list(self.registry.service_list.keys()) == expected_service_list, \ 'The service list should have been {}'.format(self.registry.service_list.keys()) assert list(self.registry.functions_list.keys()) == expected_functions_list, \ 'The function list should have been {}'.format(self.registry.functions_list.keys()) assert 'application' in self.registry.service_list, 'The application should have been registered.' assert 'main_window' in self.registry.service_list, 'The main_window should have been registered.' def test_projector_manager_hidden_on_startup(self): """ Test that the projector manager is hidden on startup """ # GIVEN: A built main window # WHEN: OpenLP is started # THEN: The projector manager should be hidden assert self.main_window.projector_manager_dock.isVisible() is False def test_on_search_shortcut_triggered_shows_media_manager(self): """ Test that the media manager is made visible when the search shortcut is triggered """ # GIVEN: A build main window set up for testing with patch.object(self.main_window, 'media_manager_dock') as mocked_media_manager_dock, \ patch.object(self.main_window, 'media_tool_box') as mocked_media_tool_box: mocked_media_manager_dock.isVisible.return_value = False mocked_media_tool_box.currentWidget.return_value = None # WHEN: The search shortcut is triggered self.main_window.on_search_shortcut_triggered() # THEN: The media manager dock is made visible mocked_media_manager_dock.setVisible.assert_called_with(True) def test_on_search_shortcut_triggered_focuses_widget(self): """ Test that the focus is set on the widget when the search shortcut is triggered """ # GIVEN: A build main window set up for testing with patch.object(self.main_window, 'media_manager_dock') as mocked_media_manager_dock, \ patch.object(self.main_window, 'media_tool_box') as mocked_media_tool_box: mocked_media_manager_dock.isVisible.return_value = True mocked_widget = MagicMock() mocked_media_tool_box.currentWidget.return_value = mocked_widget # WHEN: The search shortcut is triggered self.main_window.on_search_shortcut_triggered() # THEN: The media manager dock is made visible assert 0 == mocked_media_manager_dock.setVisible.call_count mocked_widget.on_focus.assert_called_with() @patch('openlp.core.ui.mainwindow.FirstTimeForm') @patch('openlp.core.ui.mainwindow.QtWidgets.QMessageBox.warning') @patch('openlp.core.ui.mainwindow.Settings') def test_on_first_time_wizard_clicked_show_projectors_after( self, MockSettings, mocked_warning, MockWizard): """Test that the projector manager is shown after the FTW is run""" # GIVEN: Main_window, patched things, patched "Yes" as confirmation to re-run wizard, settings to True. MockSettings.return_value.value.return_value = True mocked_warning.return_value = QtWidgets.QMessageBox.Yes MockWizard.return_value.was_cancelled = False with patch.object(self.main_window, 'projector_manager_dock') as mocked_dock, \ patch.object(self.registry, 'execute'), patch.object(self.main_window, 'theme_manager_contents'): # WHEN: on_first_time_wizard_clicked is called self.main_window.on_first_time_wizard_clicked() # THEN: projector_manager_dock.setVisible should had been called once mocked_dock.setVisible.assert_called_once_with(True) @patch('openlp.core.ui.mainwindow.FirstTimeForm') @patch('openlp.core.ui.mainwindow.QtWidgets.QMessageBox.warning') @patch('openlp.core.ui.mainwindow.Settings') def test_on_first_time_wizard_clicked_hide_projectors_after( self, MockSettings, mocked_warning, MockWizard): """Test that the projector manager is hidden after the FTW is run""" # GIVEN: Main_window, patched things, patched "Yes" as confirmation to re-run wizard, settings to False. MockSettings.return_value.value.return_value = False mocked_warning.return_value = QtWidgets.QMessageBox.Yes MockWizard.return_value.was_cancelled = False # WHEN: on_first_time_wizard_clicked is called with patch.object(self.main_window, 'projector_manager_dock') as mocked_dock, \ patch.object(self.registry, 'execute'), patch.object(self.main_window, 'theme_manager_contents'): self.main_window.on_first_time_wizard_clicked() # THEN: projector_manager_dock.setVisible should had been called once mocked_dock.setVisible.assert_called_once_with(False) def test_increment_progress_bar_default_increment(self): """ Test that increment_progress_bar increments the progress bar by 1 when called without the `increment` arg. """ # GIVEN: A mocked progress bar with patch.object(self.main_window, 'load_progress_bar', **{'value.return_value': 0}) as mocked_progress_bar: # WHEN: Calling increment_progress_bar without the `increment` arg self.main_window.increment_progress_bar() # THEN: The progress bar value should have been incremented by 1 mocked_progress_bar.setValue.assert_called_once_with(1) def test_increment_progress_bar_custom_increment(self): """ Test that increment_progress_bar increments the progress bar by the `increment` arg when called with the `increment` arg with a set value. """ # GIVEN: A mocked progress bar with patch.object(self.main_window, 'load_progress_bar', **{'value.return_value': 0}) as mocked_progress_bar: # WHEN: Calling increment_progress_bar with `increment` set to 10 self.main_window.increment_progress_bar(increment=10) # THEN: The progress bar value should have been incremented by 10 mocked_progress_bar.setValue.assert_called_once_with(10) def test_eventFilter(self): """ Test the reimplemented event method """ # GIVEN: A file path and a QEvent. file_path = str(RESOURCE_PATH / 'church.jpg') mocked_file_method = MagicMock(return_value=file_path) event = QtCore.QEvent(QtCore.QEvent.FileOpen) event.file = mocked_file_method # WHEN: Call the vent method. result = self.main_window.eventFilter(MagicMock(), event) # THEN: The path should be inserted. assert result is True, "The method should have returned True." mocked_file_method.assert_called_once_with() assert self.app.args[0] == file_path, "The path should be in args." @patch('openlp.core.ui.mainwindow.is_macosx') def test_application_activate_event(self, mocked_is_macosx): """ Test that clicking on the dock icon on Mac OS X restores the main window if it is minimized """ # GIVEN: Mac OS X and an ApplicationActivate event mocked_is_macosx.return_value = True event = QtCore.QEvent(QtCore.QEvent.ApplicationActivate) self.main_window.showMinimized() # WHEN: The icon in the dock is clicked result = self.main_window.eventFilter(MagicMock(), event) # THEN: assert result is True, "The method should have returned True." assert self.main_window.isMinimized() is False