Exemplo n.º 1
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)
Exemplo n.º 2
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)
Exemplo n.º 3
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)
Exemplo 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('core/has run wizard')
        if not has_run_wizard:
            if FirstTimeForm(screens).exec_() == QtGui.QDialog.Accepted:
                Settings().setValue('core/has run wizard', True)
        # 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 os.name == 'nt':
            application_stylesheet += NT_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()
        # start the main app window
        self.main_window = MainWindow()
        Registry().execute('bootstrap_initialise')
        Registry().execute('bootstrap_post_set_up')
        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:
            VersionThread(self.main_window).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, 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.
        """
        log.exception(''.join(format_exception(exctype, value, traceback)))
        if not hasattr(self, 'exception_form'):
            self.exception_form = ExceptionForm()
        self.exception_form.exception_text_edit.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
        """
        log.debug('processing event flush')
        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('Got open file event for %s!', file_name)
            self.args.insert(0, file_name)
            return True
        else:
            return QtGui.QApplication.event(self, event)