def accept(self):
        """
        This method is invoked when the OK button is pressed. If at least one parameter has been
        changed, all text fields are tested for valid input data. Valid data are stored in the
        configuration object. If a test fails, a dialog prompts the user for correction.

        :return: -
        """
        if self.configuration_changed:
            # Check if the web browser path entered is valid. If it is not, give an example
            # of a valid path.
            if not os.path.exists(str(self.input_web_browser_path.text())):
                Miscellaneous.show_input_error("Standard web browser",
                                               "/usr/bin/firefox")
                return

            # Check if the URL entered is valid. If it is not, give an example of a valid URL.
            if not Miscellaneous.testipaddress(
                    str(self.input_indi_server_url.text())):
                Miscellaneous.show_input_error("URL of the INDI server",
                                               "localhost")
                return

            # Check if the float entered is within the given bounds [0., 3.]. If the return value
            # is None, an error was detected. In this case give an example for a correct value.
            if not Miscellaneous.testfloat(
                    str(self.input_guiding_interval.text()), 0., 3.):
                Miscellaneous.show_input_error("Guide pulse duration", "0.5")
                return

            # Repeat the same logic for "wait interval".
            if not Miscellaneous.testfloat(
                    str(self.input_wait_interval.text()), 0., 20.):
                Miscellaneous.show_input_error("Wait interval", "1.")
                return

            # Repeat the same logic for "telescope lookup precision".
            if not Miscellaneous.testfloat(
                    str(self.input_telescope_lookup_precision.text()), 0.1,
                    10.):
                Miscellaneous.show_input_error(
                    "Telescope position lookup precision", "0.5")
                return

        # Close the editing gui.
        self.close()
    def open_indi_manager(self):
        """
        Open the INDI manager in a web browser to configure the hardware drivers. First,
        the 'indi-web' process must be started on the system where the INDI server is running.
        If this is on localhost, MoonPanoramaMaker can test if the process is running, and,
        if not, start it. If the INDI server runs on a remote system, it is the
        user's responsibility to start the process there.

        :return: -
        """

        # Check if the given URL of the INDI server is valid.
        server_url = str(self.input_indi_server_url.text())
        if Miscellaneous.testipaddress(server_url):
            if server_url == "localhost" or server_url == "127.0.0.1":
                # The server is running locally: Check if 'indi-web' is running. If not, start it.
                indi_web_is_running = len(
                    os.popen('pgrep indi-web').read()) > 0
                if not indi_web_is_running:
                    os.system('indi-web &')
                    # Check if 'indi-web' appears in the list of active processes.
                    success = False
                    for trial in range(5):
                        time.sleep(self.c.polling_interval)
                        if len(os.popen('pgrep indi-web').read()) > 0:
                            success = True
                            break
                    if not success:
                        # The 'indi-web' process could not be started. Issue an error message.
                        if self.c.protocol_level > 0:
                            Miscellaneous.protocol(
                                "Unable to start the 'indi-web' process locally. Please "
                                "check the INDI installation.")
                        return

            else:
                # If the server is on a remote system, MoonPanoramaMaker cannot start 'indi-web'
                # there. Ask the user for confirmation that 'indi-web' is started.
                msg = "Make sure that 'indi-web' is started on the system where the INDI server " \
                      "is running. To start the 'indi-web' process, open a terminal on the remote" \
                      " system and enter 'indi-web &'. Please confirm that 'indi-web' is running."

                reply = QtWidgets.QMessageBox.question(
                    self, 'Message', msg,
                    QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
                    QtWidgets.QMessageBox.No)
                # Negative reply: Issue an error message and exit.
                if reply != QtWidgets.QMessageBox.Yes:
                    Miscellaneous.show_detailed_error_message(
                        "The INDI manager cannot be opened.",
                        "MoonPanoramaMaker can only handle the INDI server configuration if the "
                        "'indi-web' process is started on the server system. Alternatively, "
                        "you may configure the INDI server outside MoonPanoramaMaker using some "
                        "other program.")
                    return

            # 'indi-web' is running. Check if the web browser path exists,
            #  and open the URL in the standard web browser.
            if not os.path.exists(str(self.input_web_browser_path.text())):
                Miscellaneous.show_detailed_error_message(
                    "The standard web browser cannot be launched.",
                    "The parameter 'Standard web browser' is wrong. Please make sure that it "
                    "points to a web browser executable, e.g. '/usr/bin/firefox'."
                )
                return
            try:
                import subprocess
                subprocess.Popen([
                    str(self.input_web_browser_path.text()),
                    "http://" + server_url + ":8624"
                ])
                self.configuration_changed = True
                self.telescope_changed = True
            except:
                if self.c.protocol_level > 0:
                    Miscellaneous.show_detailed_error_message(
                        "Unable to access the indi-web manager.",
                        "Please check the standard web browser path and the INDI installation."
                    )

        else:
            # The given URL is invalid. Issue an error message and exit.
            Miscellaneous.show_detailed_error_message(
                "Invalid URL entered.",
                "The URL of the INDI server is not correct. "
                "It must be eigher 'localhost' or the IP "
                "number "
                "of the system where the INDI "
                "server is executed. (e.g. '192.168.0.2') ")
    def accept(self):
        """
        If the OK button is clicked and the configuration has been changed, test all parameters for
        validity. In case an out-of-bound value is entered, open an error correction dialog window.

        :return: -
        """

        if self.configuration_changed:
            # If the tesselation is changed, most of the work done so far has to be repeated.
            # If not at begin of execution, ask the user if this is really what he/she wants to do.
            if self.initialized and self.tesselation_changed:
                # Ask the user for confirmation.
                quit_msg = "The configuration change will invalidate the videos recorded so far. " \
                           "Do you really want to restart the recording workflow?"
                reply = QtWidgets.QMessageBox.question(self, 'Message', quit_msg,
                                                       QtWidgets.QMessageBox.Yes,
                                                       QtWidgets.QMessageBox.No)
                # Negative reply: Ignore changed inputs and close the editor.
                if reply == QtWidgets.QMessageBox.No:
                    self.reject()

            # Get the input string from the GUI text field.
            input_string = str(self.input_longitude.text())
            # Test the input value if it is within the allowed interval (here [-360., +360.])
            if Miscellaneous.testfloat(input_string, -360., 360.):
                self.c.conf.set("Geographical Position", "longitude", input_string)
            else:
                # The value entered is out of bound, show a valid input value example.
                Miscellaneous.show_input_error("Longitude", "7.39720")
                return

            # Repeat the same logic for the other input fields.
            input_string = str(self.input_latitude.text())
            if Miscellaneous.testfloat(input_string, -90., 90.):
                self.c.conf.set("Geographical Position", "latitude", input_string)
            else:
                Miscellaneous.show_input_error("Latitude", "50.69190")
                return

            input_string = str(self.input_elevation.text())
            if Miscellaneous.testint(input_string, -100, 9000):
                self.c.conf.set("Geographical Position", "elevation", input_string)
            else:
                Miscellaneous.show_input_error("Elevation", "250")
                return

            self.c.conf.set("Geographical Position", "timezone",
                            self.timezone_chooser.currentText())

            input_string = str(self.input_ip_address.text())
            if Miscellaneous.testipaddress(input_string):
                self.c.conf.set("Camera", "ip address", input_string)
            else:
                Miscellaneous.show_input_error("IP address to access FireCapture", "192.168.0.34")
                return

            input_string = str(self.input_focal_length.text())
            if Miscellaneous.testfloat(input_string, 0., 100000.):
                self.c.conf.set("Telescope", "focal length", input_string)
            else:
                Miscellaneous.show_input_error("Focal length", "4670.")
                return

            self.c.conf.set("Telescope", "interface type",
                            str(self.mount_interface_chooser.currentText()))
            self.c.conf.set("Workflow", "protocol level", self.protocol_level_chooser.currentText())
            self.c.set_protocol_level()
            self.c.conf.set("Workflow", "protocol to file",
                            ['True', 'False'][self.protocol_to_file_chooser.currentIndex()])
            self.c.conf.set("Workflow", "focus on star",
                            ['True', 'False'][self.focus_on_star_chooser.currentIndex()])
            self.c.conf.set("Workflow", "limb first",
                            ['True', 'False'][self.limb_first_chooser.currentIndex()])
            self.c.conf.set("Workflow", "camera automation",
                            ['True', 'False'][self.camera_automation_chooser.currentIndex()])

            input_string = str(self.input_camera_trigger_delay.text())
            if Miscellaneous.testfloat(input_string, 0., 60.):
                self.c.conf.set("Workflow", "camera trigger delay", input_string)
            else:
                Miscellaneous.show_input_error("Camera trigger delay", "10.")
                return

            input_string = str(self.input_fig_size_horizontal.text())
            if Miscellaneous.testfloat(input_string, 2., 25.):
                self.c.conf.set("Tile Visualization", "figsize horizontal", input_string)
            else:
                Miscellaneous.show_input_error("Figure size horizontal", "10.")
                return

            input_string = str(self.input_fig_size_vertical.text())
            if Miscellaneous.testfloat(input_string, 2., 25.):
                self.c.conf.set("Tile Visualization", "figsize vertical", input_string)
            else:
                Miscellaneous.show_input_error("Figure size vertical", "10.")
                return

            input_string = str(self.input_label_font_size.text())
            if Miscellaneous.testint(input_string, 6, 16):
                self.c.conf.set("Tile Visualization", "label fontsize", input_string)
            else:
                Miscellaneous.show_input_error("Font size for labels", "11")
                return

            input_string = str(self.input_label_shift.text())
            if Miscellaneous.testfloat(input_string, 0., 1.):
                self.c.conf.set("Tile Visualization", "label shift", input_string)
            else:
                Miscellaneous.show_input_error("Label shift parameter", "0.8")
                return

            input_string = str(self.input_min_autoalign_interval.text())
            if Miscellaneous.testfloat(input_string, 20., 1800.):
                self.c.conf.set("Alignment", "min autoalign interval", input_string)
            else:
                Miscellaneous.show_input_error("Minimum auto-alignment interval", "120.")
                return

            input_string = str(self.input_max_autoalign_interval.text())
            if Miscellaneous.testfloat(input_string, 30., 3600.):
                self.c.conf.set("Alignment", "max autoalign interval", input_string)
            else:
                Miscellaneous.show_input_error("Maximum auto-alignment interval", "900.")
                return

            input_string = str(self.input_max_alignment_error.text())
            if Miscellaneous.testfloat(input_string, 10., 60.):
                self.c.conf.set("Alignment", "max alignment error", input_string)
            else:
                Miscellaneous.show_input_error("Max alignment error", "30.")
                return

            if self.ascomeditor_called:
                # If the AscomEditor was called, new parameters are already checked for validity.
                self.c.conf.set("ASCOM", "guiding interval", self.new_ascom_guiding_interval)
                self.c.conf.set("ASCOM", "wait interval", self.new_ascom_wait_interval)
                self.c.conf.set("ASCOM", "pulse guide speed RA",
                                self.new_ascom_pulse_guide_speed_ra)
                self.c.conf.set("ASCOM", "pulse guide speed DE",
                                self.new_ascom_pulse_guide_speed_de)
                self.c.conf.set("ASCOM", "telescope lookup precision",
                                self.new_ascom_telescope_lookup_precision)
                self.c.conf.set('ASCOM', 'telescope driver', self.ascomeditor.new_driver_name)

            if self.indieditor_called:
                # If the IndiEditor was called, copy back the current new values.
                self.c.conf.set("INDI", "web browser path", self.new_web_browser_path)
                self.c.conf.set("INDI", "server url", self.new_indi_server_url)
                self.c.conf.set("INDI", "pulse guide speed index",
                                self.new_indi_pulse_guide_speed_index)
                self.c.conf.set("INDI", "guiding interval", self.new_indi_guiding_interval)
                self.c.conf.set("INDI", "wait interval", self.new_indi_wait_interval)
                self.c.conf.set("INDI", "telescope lookup precision",
                                self.new_indi_telescope_lookup_precision)

        # All tests passed successfully, and all parameters have been written to the
        # configuration object. Close the GUI window.
        self.close()