def validate_impact_function(self):
        """Helper method to evaluate the current state of the impact function.

        This function will determine if it is appropriate for the OK button to
        be enabled or not. Only this function is able to change the status of
        the button.

        This function will return a ready to run impact function or None if it
        is not ready.

        This slot is called on pan, zoom, layer visibility changes.

        .. versionadded:: 4.0
        """
        # First, we check if the dock is not busy.
        if self.busy:
            return False, None

        # Then, we need to check if the question area is correct.
        flag, message = self._validate_question_area()
        if not flag:
            send_static_message(self, message)
            self.run_button.setEnabled(False)
            self.extent.clear_next_analysis_extent()
            self.impact_function = None
            return False, None

        # Finally, we need to check if an IF can run.
        impact_function = ImpactFunction()
        impact_function.hazard = layer_from_combo(self.hazard_layer_combo)
        impact_function.exposure = layer_from_combo(self.exposure_layer_combo)
        aggregation = layer_from_combo(self.aggregation_layer_combo)

        if aggregation:
            impact_function.aggregation = aggregation
            impact_function.use_selected_features_only = (
                self.use_selected_features_only)

            if self.use_selected_features_only and (
                    aggregation.selectedFeatureCount() > 0):
                self.aggregation_question_label.setText(
                    self.label_with_selection)
            else:
                self.aggregation_question_label.setText(
                    self.label_without_selection)
        else:
            # self.extent.crs is the map canvas CRS.
            impact_function.crs = self.extent.crs
            self.aggregation_question_label.setText(
                self.label_without_selection)
            mode = setting('analysis_extents_mode')
            if self.extent.user_extent:
                # This like a hack to transform a geometry to a rectangle.
                # self.extent.user_extent is a QgsGeometry.
                # impact_function.requested_extent needs a QgsRectangle.
                wkt = self.extent.user_extent.asWkt()
                impact_function.requested_extent = wkt_to_rectangle(wkt)

            elif mode == EXPOSURE:
                impact_function.use_exposure_view_only = True

            elif mode == HAZARD_EXPOSURE_VIEW:
                impact_function.requested_extent = (
                    self.iface.mapCanvas().extent())

        status, message = impact_function.prepare()
        if status == PREPARE_SUCCESS:

            show_confirmations = setting(
                'show_extent_confirmations', True, bool)

            if show_confirmations:
                message = self.tr(
                    'The hazard layer, exposure layer and your '
                    'defined analysis area extents all overlap. Press the '
                    'run button below to continue with the analysis.')

                display_information_message_bar(
                    'InaSAFE',
                    self.tr('Analysis environment ready'),
                    message,
                    self.tr('More info ...'),
                    duration=2,
                    iface_object=self.iface)

            if self.aggregation:
                crs = self.aggregation.crs()
            else:
                crs = self.extent.crs
            self.extent.set_next_analysis_extent(
                impact_function.analysis_extent, crs)

            self.run_button.setEnabled(True)
            send_static_message(self, ready_message())
            self.impact_function = None
            return impact_function

        elif status == PREPARE_FAILED_BAD_LAYER:
            self.extent.clear_next_analysis_extent()
            send_error_message(self, message)
            self.run_button.setEnabled(False)
            self.impact_function = None
            return None

        elif status == PREPARE_FAILED_INSUFFICIENT_OVERLAP_REQUESTED_EXTENT:
            self.extent.clear_next_analysis_extent()
            show_warnings = setting('show_extent_warnings', True, bool)
            if show_warnings:
                display_warning_message_bar(
                    'InaSAFE',
                    tr('The requested extent is not overlapping your layers.'),
                    iface_object=self.iface
                )
            self.run_button.setEnabled(False)
            self.impact_function = None
            return None

        elif status == PREPARE_FAILED_INSUFFICIENT_OVERLAP:
            self.extent.clear_next_analysis_extent()
            show_warnings = setting('show_extent_warnings', True, bool)
            if show_warnings:
                display_warning_message_bar(
                    'InaSAFE',
                    self.tr('No overlapping extents'),
                    no_overlap_message(),
                    iface_object=self.iface
                )
            self.run_button.setEnabled(False)
            self.impact_function = None
            return None

        elif status == PREPARE_FAILED_BAD_INPUT:
            # The user should fix the message. It should be in orange.
            self.extent.clear_next_analysis_extent()
            send_error_message(self, message)
            self.run_button.setEnabled(False)
            self.impact_function = None
            return None

        else:
            # An exception has been raised. It should be in red.
            self.extent.clear_next_analysis_extent()
            send_error_message(self, message)
            self.run_button.setEnabled(False)
            self.impact_function = None
            return None
Helper method to evaluate the current state of the impact function.

        This function will determine if it is appropriate for the OK button to
        be enabled or not. Only this function is able to change the status of
        the button.

        This function will return a ready to run impact function or None if it
        is not ready.

        This slot is called on pan, zoom, layer visibility changes.

        .. versionadded:: 4.0