Esempio n. 1
0
 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()
Esempio n. 2
0
 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_()
Esempio n. 3
0
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.')
Esempio n. 4
0
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)
Esempio n. 5
0
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)
Esempio n. 6
0
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.')
Esempio n. 7
0
    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()
Esempio n. 8
0
File: app.py Progetto: ipic/projecao
    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()
Esempio n. 9
0
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)
Esempio n. 10
0
    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_()
Esempio n. 11
0
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)
Esempio n. 12
0
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)
Esempio n. 13
0
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)
Esempio n. 14
0
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)
Esempio n. 15
0
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)
Esempio n. 16
0
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)
Esempio n. 17
0
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