예제 #1
0
 def click_open_manual(cls):
     logger.debug("open manual")
     Helper.explore_folder(
         "https://www.hydroffice.org/manuals/abc/user_manual_info.html#noaa-s-57-support-files-for-caris"
     )
예제 #2
0
 def open_output_folder(self):
     Helper.explore_folder(self.output_folder)
예제 #3
0
    def open_local_noaa_support_folder(self):
        if self.local_noaa_support_folder_present():
            Helper.explore_folder(self.local_noaa_support_folder())
            return

        Helper(lib_info=self._li).explore_package_folder()
예제 #4
0
 def default_output_folder(cls):
     output_folder = Helper(lib_info=lib_info).package_folder()
     # create it if it does not exist
     if not os.path.exists(output_folder):
         os.makedirs(output_folder)
     return output_folder
예제 #5
0
 def click_open_manual(cls):
     logger.debug("open manual")
     Helper.explore_folder(
         "https://www.hydroffice.org/manuals/qctools/user_manual_chart_triangle_rule.html"
     )
예제 #6
0
 def link_activated(self, url):
     if "mailto:" in url:
         self.email_bug_report()
     else:
         Helper.explore_folder(url)
예제 #7
0
 def click_open_manual(cls):
     logger.debug("open manual")
     Helper.explore_folder(
         "https://www.hydroffice.org/manuals/qctools/stable/user_manual_survey_sbdare_export.html"
     )
예제 #8
0
    def _click_feature_scan(self, version):
        """abstract the feature scan calling mechanism"""

        self.parent_win.change_info_url(Helper(lib_info=lib_info).web_url(suffix="survey_feature_scan_%d" % version))

        # library takes care of progress bar

        try:

            specs_version = None
            survey_area = 0
            use_mhw = False
            mhw_value = 0.0
            sorind = None
            sordat = None
            images_folder = None

            if version == 8:

                specs_version = self.toggle_specs_v8.value()
                if specs_version == 2017:
                    specs_version = "2017"
                elif specs_version == 2018:
                    specs_version = "2018"
                elif specs_version == 2019:
                    specs_version = "2019"
                elif specs_version == 2020:
                    specs_version = "2020"
                else:
                    raise RuntimeError("unknown specs version: %s" % specs_version)

                toggle_survey_area = self.toggle_area_v8.value()
                if toggle_survey_area == 0:
                    survey_area = survey_areas["Pacific Coast"]
                elif toggle_survey_area == 1:
                    survey_area = survey_areas["Great Lakes"]
                elif toggle_survey_area == 2:
                    survey_area = survey_areas["Atlantic Coast"]
                else:
                    raise RuntimeError("unknown survey area: %s" % survey_area)

                use_mhw = self.use_mhw_v8.isChecked()
                mhw_str = self.mhw_value_v8.text()
                mhw_value = float(mhw_str)

                if self.check_sorind_v8.isChecked():
                    sorind = self.sorind_value_v8.text()
                    is_valid = self.prj.check_sorind(value=sorind)
                    if not is_valid:
                        msg = "An invalid SORIND was entered!\n\nCheck: %s" % sorind
                        # noinspection PyCallByClass
                        QtWidgets.QMessageBox.critical(self, "Feature scan v%d[%s]" % (version, specs_version),
                                                       msg, QtWidgets.QMessageBox.Ok)
                        return

                if self.check_sordat_v8.isChecked():
                    sordat = self.sordat_value_v8.text()
                    is_valid = self.prj.check_sordat(value=sordat)
                    if not is_valid:
                        msg = "An invalid SORDAT was entered!\n\nCheck: %s" % sordat
                        # noinspection PyCallByClass
                        QtWidgets.QMessageBox.critical(self, "Feature scan v%d[%s]" % (version, specs_version),
                                                       msg, QtWidgets.QMessageBox.Ok)
                        return

            elif version == 9:

                specs_version = self.toggle_specs_v9.value()
                if specs_version == 2017:
                    specs_version = "2017"
                elif specs_version == 2018:
                    specs_version = "2018"
                elif specs_version == 2019:
                    specs_version = "2019"
                elif specs_version == 2020:
                    specs_version = "2020"
                else:
                    raise RuntimeError("unknown specs version: %s" % specs_version)

                toggle_survey_area = self.toggle_area_v9.value()
                if toggle_survey_area == 0:
                    survey_area = survey_areas["Pacific Coast"]
                elif toggle_survey_area == 1:
                    survey_area = survey_areas["Great Lakes"]
                elif toggle_survey_area == 2:
                    survey_area = survey_areas["Atlantic Coast"]
                else:
                    raise RuntimeError("unknown survey area: %s" % survey_area)

                if self.ask_multimedia_folder_v9.isChecked():
                    # ask for images folder
                    # noinspection PyCallByClass
                    images_folder = QtWidgets.QFileDialog.getExistingDirectory(self,
                                                                               "Select the folder with the images",
                                                                               QtCore.QSettings().value(
                                                                                   "feature_scan_images_folder", ""),
                                                                               )
                    if images_folder == "":
                        logger.debug('selecting multimedia folder: aborted')
                        images_folder = None

                    else:
                        logger.debug("selected images folder: %s" % images_folder)
                        QtCore.QSettings().setValue("feature_scan_images_folder", images_folder)

                use_mhw = self.use_mhw_v9.isChecked()
                mhw_value = 0.0
                if use_mhw:
                    mhw_str = self.mhw_value_v9.text()
                    if mhw_str == "":
                        msg = "The MHW field is empty! Enter a valid value or disable the WATLEV check."
                        # noinspection PyArgumentList
                        QtWidgets.QMessageBox.critical(self, "Feature scan v%d[%s]" % (version, specs_version),
                                                       msg, QtWidgets.QMessageBox.Ok)
                        return
                    else:
                        mhw_value = float(mhw_str)

                if self.check_sorind_v9.isChecked():
                    sorind = self.sorind_value_v9.text()
                    is_valid = self.prj.check_sorind(value=sorind)
                    if not is_valid:
                        msg = "An invalid SORIND was entered!\n\nCheck: %s" % sorind
                        # noinspection PyCallByClass
                        QtWidgets.QMessageBox.critical(self, "Feature scan v%d[%s]" % (version, specs_version),
                                                       msg, QtWidgets.QMessageBox.Ok)
                        return

                if self.check_sordat_v9.isChecked():
                    sordat = self.sordat_value_v9.text()
                    is_valid = self.prj.check_sordat(value=sordat)
                    if not is_valid:
                        msg = "An invalid SORDAT was entered!\n\nCheck: %s" % sordat
                        # noinspection PyCallByClass
                        QtWidgets.QMessageBox.critical(self, "Feature scan v%d[%s]" % (version, specs_version),
                                                       msg, QtWidgets.QMessageBox.Ok)
                        return

            else:
                RuntimeError("unknown Feature Scan version: %s" % version)

            self.prj.feature_scan(version=version, specs_version=specs_version,
                                  survey_area=survey_area, use_mhw=use_mhw, mhw_value=mhw_value,
                                  sorind=sorind, sordat=sordat, multimedia_folder=images_folder)

            # noinspection PyCallByClass
            QtWidgets.QMessageBox.information(self, "Feature scan v%d[%s]" % (version, specs_version),
                                              self.prj.scan_msg, QtWidgets.QMessageBox.Ok)

        except Exception as e:
            traceback.print_exc()
            # noinspection PyCallByClass
            QtWidgets.QMessageBox.critical(self, "Error", "While running survey's feature scan v%d, %s" % (version, e),
                                           QtWidgets.QMessageBox.Ok)
            return
예제 #9
0
 def click_open_manual_v9(cls):
     logger.debug("open manual")
     Helper.explore_folder(
         "https://www.hydroffice.org/manuals/qctools/stable/user_manual_survey_detect_fliers.html"
     )
예제 #10
0
파일: scan.py 프로젝트: hydroffice/hyo2_qc
 def click_open_manual(cls):
     logger.debug("open manual")
     Helper.explore_folder(
         "https://www.hydroffice.org/manuals/qctools/stable/user_manual_chart_scan_features.html"
     )
예제 #11
0
    def save_to_db(self):
        """Save setup to db"""
        logger.info("*** > SETUP: saving ...")

        try:
            db = self.db
            # db.setup_version = self.setup_version  # not overwrite the version since it implies different tables
            # db.active_setup_id = self.setup_id  # obviously, unactivated to avoid db logic corruption
            # db.setup_status  # only the current setup is visualized
            # db.setup_name = self.setup_name

            # input
            db.use_woa09 = self.use_woa09
            db.use_woa13 = self.use_woa13
            if db.setup_version > 1:
                db.use_woa18 = self.use_woa18
            db.use_rtofs = self.use_rtofs
            if db.setup_version > 1:
                db.use_gomofs = self.use_gomofs
            db.ssp_extension_source = Helper.first_match(
                Dicts.atlases, self.ssp_extension_source)
            db.ssp_salinity_source = Helper.first_match(
                Dicts.atlases, self.ssp_salinity_source)
            db.ssp_temp_sal_source = Helper.first_match(
                Dicts.atlases, self.ssp_temp_sal_source)
            db.ssp_up_or_down = Helper.first_match(Dicts.ssp_directions,
                                                   self.ssp_up_or_down)

            db.rx_max_wait_time = self.rx_max_wait_time
            db.use_sis4 = self.use_sis4
            if db.setup_version > 1:
                db.use_sis5 = self.use_sis5
            db.use_sippican = self.use_sippican
            db.use_mvp = self.use_mvp

            # output
            db.log_user = self.log_user
            db.log_server = self.log_server

            # client list
            db.delete_clients()
            for client in self.client_list.clients:
                logger.debug('- save: %s' % client.name)
                db.add_client(client_name=client.name,
                              client_ip=client.ip,
                              client_port=client.port,
                              client_protocol=client.protocol)

            # listeners - sis4
            db.sis4_listen_port = self.sis4_listen_port
            db.sis4_listen_timeout = self.sis4_listen_timeout

            # output - sis 4 and 5
            db.sis_auto_apply_manual_casts = self.sis_auto_apply_manual_casts

            # listeners - sis5
            if db.setup_version > 1:
                db.sis5_listen_ip = self.sis5_listen_ip
                db.sis5_listen_port = self.sis5_listen_port
                db.sis5_listen_timeout = self.sis5_listen_timeout

            # listeners - sippican
            db.sippican_listen_port = self.sippican_listen_port
            db.sippican_listen_timeout = self.sippican_listen_timeout

            # listeners - mvp
            db.mvp_ip_address = self.mvp_ip_address
            db.mvp_listen_port = self.mvp_listen_port
            db.mvp_listen_timeout = self.mvp_listen_timeout
            db.mvp_transmission_protocol = self.mvp_transmission_protocol
            db.mvp_format = self.mvp_format
            db.mvp_winch_port = self.mvp_winch_port
            db.mvp_fish_port = self.mvp_fish_port
            db.mvp_nav_port = self.mvp_nav_port
            db.mvp_system_port = self.mvp_system_port
            db.mvp_sw_version = self.mvp_sw_version
            db.mvp_instrument_id = self.mvp_instrument_id
            db.mvp_instrument = self.mvp_instrument

            # server
            db.server_source = self.server_source
            db.server_apply_surface_sound_speed = self.server_apply_surface_sound_speed

            # current settings
            db.current_project = self.current_project
            db.custom_projects_folder = self.custom_projects_folder
            db.custom_outputs_folder = self.custom_outputs_folder
            db.custom_woa09_folder = self.custom_woa09_folder
            db.custom_woa13_folder = self.custom_woa13_folder
            if db.setup_version > 1:
                db.custom_woa18_folder = self.custom_woa18_folder
            db.noaa_tools = self.noaa_tools
            db.default_institution = self.default_institution
            db.default_survey = self.default_survey
            db.default_vessel = self.default_vessel
            db.auto_apply_default_metadata = self.auto_apply_default_metadata

            db.close()

        except Exception as e:
            raise RuntimeError("while saving setup to db, %s" % e)

        logger.info("*** > SETUP: saved!")
예제 #12
0
    def _click_submission_checks(self, version):
        """abstract the calling mechanism"""

        # sanity checks
        # - version
        if not isinstance(version, int):
            raise RuntimeError("passed invalid type for version: %s" %
                               type(version))
        if version not in [
                4,
        ]:
            raise RuntimeError("passed invalid version: %s" % version)
        # - list of folders (although the buttons should be never been enabled without a folder)
        if len(self.prj.submission_list) == 0:
            msg = "First add one or more submission folders!"
            # noinspection PyCallByClass
            QtWidgets.QMessageBox.warning(self, "Warning", msg,
                                          QtWidgets.QMessageBox.Ok)
            return

        self.parent_win.change_info_url(
            Helper(lib_info=lib_info).web_url(
                suffix="survey_submission_check_%d" % version))

        # for each file in the project grid list
        msg = "Errors/warnings per submission folder:\n"
        opened_folders = list()

        for i, path in enumerate(self.prj.submission_list):

            logger.debug("submission folder: %s" % path)

            # switcher between different versions of find fliers
            if version == 4:

                saved = self._submission_checks(path=path,
                                                version=version,
                                                idx=i,
                                                total=len(
                                                    self.prj.submission_list))

            else:  # this case should be never reached after the sanity checks
                raise RuntimeError("unknown Submission checks version: %s" %
                                   version)

            if not saved:
                # noinspection PyCallByClass
                QtWidgets.QMessageBox.critical(
                    self, "Error", "While checking submission: %s" % path,
                    QtWidgets.QMessageBox.Ok)
                continue

            msg += "- %s:  %2d errors, %2d warnings   \n" % (
                self.prj.cur_root_name, self.prj.number_of_submission_errors(),
                self.prj.number_of_submission_warnings())

            # open the output folder (if not already open)
            # print("output folder: %s" % self.prj.submission_output_folder)
            if self.prj.submission_output_folder not in opened_folders:
                self.prj.open_submission_output_folder()
                opened_folders.append(self.prj.submission_output_folder)

        # noinspection PyCallByClass
        QtWidgets.QMessageBox.information(
            self, "Submission checks v%d [HSSD %s]" %
            (version, self.prj.cur_submission_hssd), msg,
            QtWidgets.QMessageBox.Ok)
예제 #13
0
 def click_open_manual_v4(cls):
     logger.debug("open manual")
     Helper.explore_folder(
         "https://www.hydroffice.org/manuals/qctools/stable/user_manual_survey_submission_checks.html"
     )
예제 #14
0
    def generate_pdf(self,
                     path: str,
                     title: str = "Document",
                     use_colors: bool = False,
                     small: bool = False) -> bool:
        """Generate a multiple-page document, with passed title and list of strings"""

        # this function heavily relies on PySide for pdf creation, the import is local
        # to the function so that the class can still be used also without Pyside

        try:
            from PySide2 import QtGui
            from PySide2 import QtCore
            from PySide2 import QtPrintSupport

        except (ImportError, ValueError, IOError):
            logger.warning(
                "PySide2 is not properly installed, thus you cannot create a pdf file"
            )
            self.display()
            return False

        # some preliminary tests
        if len(path) == 0:
            logger.warning("The passed file path is empty")
            return False
        path = os.path.abspath(path)
        if '.pdf' not in path.lower():
            logger.warning(
                "The passed file name has not the pdf extension: %s" % path)
            return False
        path = Helper.truncate_too_long(path)

        if len(self.records) == 0:
            logger.warning("The passed string list is empty")
            return False

        #
        # INITIAL SETTINGS
        #

        logger.debug("output: %s" % path)
        # delete the passed filename if it already exists
        if os.path.exists(path):
            os.remove(path)

        # prepare some drawing tools
        blue_pen = QtGui.QPen(QtGui.QColor(30, 30, 255))
        red_pen = QtGui.QPen(QtGui.QColor(255, 30, 30))
        orange_pen = QtGui.QPen(QtGui.QColor(255, 165, 30))
        green_pen = QtGui.QPen(QtGui.QColor(30, 200, 30))
        gray_pen = QtGui.QPen(QtGui.QColor(120, 120, 120))
        black_pen = QtGui.QPen(QtGui.QColor(30, 30, 30))
        if small:
            big_font = QtGui.QFont("Arial", 9)
            normal_font = QtGui.QFont("Arial", 5, QtGui.QFont.Light)
            section_font = QtGui.QFont("Arial", 7, QtGui.QFont.Bold)
            check_font = QtGui.QFont("Arial", 6)
            small_font = QtGui.QFont("Arial", 4)
        else:
            big_font = QtGui.QFont("Arial", 10)
            normal_font = QtGui.QFont("Arial", 7, QtGui.QFont.Light)
            section_font = QtGui.QFont("Arial", 9, QtGui.QFont.Bold)
            check_font = QtGui.QFont("Arial", 8)
            small_font = QtGui.QFont("Arial", 6)
        lc_flags = QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter | QtCore.Qt.TextWordWrap
        cc_flags = QtCore.Qt.AlignCenter | QtCore.Qt.TextWordWrap

        # create the printer for pdf
        printer = QtPrintSupport.QPrinter(
            QtPrintSupport.QPrinter.HighResolution)
        printer.setCreator("HydrOffice")
        printer.setDocName("HydrOffice.pdf")
        printer.setOutputFormat(QtPrintSupport.QPrinter.PdfFormat)
        printer.setPageSize(QtPrintSupport.QPrinter.A4)
        printer.setOrientation(QtPrintSupport.QPrinter.Portrait)
        printer.setOutputFileName(path)
        page_rect = printer.pageRect()
        doc_width = page_rect.width()
        doc_height = page_rect.height()
        doc_margin = page_rect.x()
        # print(printer.getPageMargins(QtGui.QPrinter.DevicePixel))
        # logger.info("Canvas: %sx%s" % (doc_width, doc_height))
        # logger.info("Margin: %s" % doc_margin)

        # check if everything is ok
        if not printer.isValid():
            logger.warning("the PDF printer is not valid")
            return False

        #
        # ACTUAL PRINTING
        #

        page_nr = 1  # a counter for pages
        section_nr = 0
        first_section = True
        subsection_nr = 1
        row_counter = 1
        if small:
            row_height = 330
        else:
            row_height = 220  # this represents the height of a single row of text
        max_rows = (doc_height - 2 * doc_margin) / row_height
        hor_pad = row_height / 2

        # logger.info("rows for page: %i" % max_rows)

        # here we start painting to the printer
        painter = QtGui.QPainter()
        if not painter.begin(printer):
            logger.warning("not painter begin on printer")
            return False

        def print_page_template():
            """Internal helper function that print borders, logo, time stamp, etc."""
            # external border
            painter.setPen(gray_pen)
            border_area = QtCore.QRect(doc_margin, doc_margin,
                                       doc_width - 2 * doc_margin,
                                       doc_height - 2 * doc_margin)
            painter.drawRect(border_area)

            # make top-area
            top_area = QtCore.QRect(doc_margin, doc_margin,
                                    doc_width - 2 * doc_margin, row_height * 2)
            painter.drawRect(top_area)
            # logo
            hyo_logo_path = os.path.join(AppInfo().app_media_path,
                                         'poweredby.png')
            if not os.path.exists(hyo_logo_path):
                raise RuntimeError("Unable to find logo: %s" % hyo_logo_path)
            hyo_logo = QtGui.QPixmap(hyo_logo_path)
            # print("logo size: %sx%s" % (hyo_logo.width(), hyo_logo.height()))
            logo_area = QtCore.QRect(
                doc_width / 2 - hyo_logo.width() / 2,
                doc_margin + (row_height * 2 - hyo_logo.height()) / 2,
                hyo_logo.width(), hyo_logo.height())
            painter.drawPixmap(logo_area, hyo_logo)

            # make bottom-area
            bottom_area = QtCore.QRect(doc_margin,
                                       doc_height - doc_margin - row_height,
                                       doc_width - 2 * doc_margin, row_height)
            painter.drawRect(bottom_area)
            # time-stamp
            now_time = datetime.datetime.now()
            painter.setFont(small_font)
            painter.drawText(
                bottom_area, cc_flags, "time-stamp: %s, %s v.%s" %
                (now_time.strftime("%a, %d %b %Y %H:%M:%S"), self.lib_name,
                 self.lib_version))
            # page number
            page_area = QtCore.QRect(doc_width - doc_margin - 2 * row_height,
                                     doc_height - doc_margin - row_height,
                                     2 * row_height, row_height)
            # painter.drawRect(page_area)
            painter.drawText(page_area, lc_flags, "Page %s" % page_nr)

            # set back to 'normal' font
            painter.setPen(black_pen)
            painter.setFont(normal_font)
            return True

        print_page_template()

        row_area = QtCore.QRect(doc_margin + hor_pad, doc_margin,
                                doc_width - 2 * doc_margin - 2 * hor_pad,
                                row_height)
        # painter.drawRect(row_area)

        alphabet = list(string.ascii_uppercase)

        first_page = True
        for content_item in self.records:

            # title document only for the first page
            if first_page:

                # document title
                if small:
                    row_counter = 4
                else:
                    row_counter = 3
                painter.setPen(blue_pen)
                painter.setFont(big_font)
                row_area.moveTo(row_area.x(),
                                row_area.y() + row_counter * row_height)
                painter.drawText(row_area, cc_flags, title)
                # painter.drawRect(row_area)
                # row_counter += 1

                # set back to 'normal' font
                painter.setPen(black_pen)
                painter.setFont(normal_font)

                first_page = False

            # manage a new page creation
            if row_counter >= (max_rows - 4):

                if not printer.newPage():
                    logger.warning(
                        "Failed in flushing page to disk, disk full?")
                    return False

                page_nr += 1
                print_page_template()
                row_area = QtCore.QRect(
                    doc_margin + hor_pad, doc_margin + row_height,
                    doc_width - 2 * doc_margin - 2 * hor_pad, row_height)
                row_counter = 1

            row_area.moveTo(row_area.x(), row_area.y() + row_height)
            # painter.drawRect(row_area)

            last_item = content_item.split(' ')[-1]
            first_item = content_item.split(' ')[0]
            if last_item.isdigit():

                if int(last_item) > 0:  # troubles -> red pen
                    if use_colors:
                        painter.setPen(red_pen)
                    painter.drawText(row_area, lc_flags, "- " + content_item)
                    if use_colors:
                        painter.setPen(black_pen)

                else:  # all good -> black pen
                    painter.drawText(row_area, lc_flags, "- " + content_item)

            elif last_item == "[SKIP_REP]":  # skip report for this item
                if use_colors:
                    painter.setPen(gray_pen)
                painter.drawText(row_area, lc_flags,
                                 "- " + content_item.rsplit(' ', 1)[0])
                if use_colors:
                    painter.setPen(black_pen)

            elif last_item == "[SECTION]":  # the string is a section separator
                if first_section:
                    first_section = False
                else:
                    section_nr += 1
                # leave two empty rows
                row_area.moveTo(row_area.x(), row_area.y() + 2 * row_height)
                row_counter += 2
                # write a numbered sections
                painter.setFont(section_font)
                painter.drawText(
                    row_area, lc_flags, "%s. %s" %
                    (alphabet[section_nr], content_item.rsplit(' ', 1)[0]))
                painter.setFont(normal_font)
                subsection_nr = 1

            elif last_item == "[SKIP_SEC]":  # the string is a section separator
                if use_colors:
                    painter.setPen(gray_pen)
                if first_section:
                    first_section = False
                else:
                    section_nr += 1
                # leave two empty rows
                row_area.moveTo(row_area.x(), row_area.y() + 2 * row_height)
                row_counter += 2
                # write a numbered sections
                painter.setFont(section_font)
                painter.drawText(
                    row_area, lc_flags, "%s. %s" %
                    (alphabet[section_nr], content_item.rsplit(' ', 1)[0]))
                painter.setFont(normal_font)
                subsection_nr = 1
                if use_colors:
                    painter.setPen(black_pen)

            elif last_item == "[CHECK]" or last_item == "[TOTAL]":  # the string is a section separator
                # leave an empty row
                row_area.moveTo(row_area.x(), row_area.y() + row_height)
                row_counter += 1
                # write a numbered sections
                painter.setFont(check_font)
                painter.drawText(
                    row_area, lc_flags,
                    "%s.%s. %s" % (alphabet[section_nr], subsection_nr,
                                   content_item.rsplit(' ', 1)[0]))
                painter.setFont(normal_font)
                subsection_nr += 1

            elif last_item == "[SKIP_CHK]":  # the string is a section separator
                if use_colors:
                    painter.setPen(gray_pen)
                # leave an empty row
                row_area.moveTo(row_area.x(), row_area.y() + row_height)
                row_counter += 1
                # write a numbered sections
                painter.setFont(check_font)
                painter.drawText(
                    row_area, lc_flags,
                    "%s.%s. %s" % (alphabet[section_nr], subsection_nr,
                                   content_item.rsplit(' ', 1)[0]))
                painter.setFont(normal_font)
                subsection_nr += 1
                if use_colors:
                    painter.setPen(black_pen)

            elif last_item == "OK":  # no issues, green ok
                if use_colors:
                    painter.setPen(green_pen)
                painter.drawText(row_area, lc_flags, content_item)
                if use_colors:
                    painter.setPen(black_pen)

            else:
                if first_item == "[WARNING]":
                    if use_colors:
                        painter.setPen(orange_pen)
                    painter.drawText(row_area, lc_flags, content_item)
                    if use_colors:
                        painter.setPen(black_pen)

                elif first_item == "[ERROR]":
                    if use_colors:
                        painter.setPen(red_pen)
                    painter.drawText(row_area, lc_flags, content_item)
                    if use_colors:
                        painter.setPen(black_pen)

                else:
                    painter.drawText(row_area, lc_flags, content_item)

            row_counter += 1
            # print("page %s, row %s" % (page_nr, row_counter))

        #
        # FINISHING THE PRINTING
        #
        painter.end()

        return True
예제 #15
0
class TestABCLibHelper(unittest.TestCase):

    def setUp(self):

        self.h = Helper(lib_info=LibInfo())

    @unittest.skipIf(Helper.is_linux(), "test not supported on Linux")
    def test_explore_folder(self):
        self.assertTrue(self.h.explore_folder(__file__))
        self.assertFalse(self.h.explore_folder(__file__ + ".fake"))
        self.assertTrue(self.h.explore_folder(os.path.dirname(__file__)))
        self.assertFalse(self.h.explore_folder(os.path.dirname(__file__) + "fake"))

    def test_first_match(self):
        # fake dict
        a_dict = {
            "a": 1,
            "b": 99,
            "c": 1,
        }

        # test if it gives back the first matching key
        self.assertTrue(Helper.first_match(a_dict, 1) in ["a", "c"])

        # test if it raises with a not-existing value
        with self.assertRaises(RuntimeError):
            Helper.first_match(a_dict, 2)

    def test_is_64bit_os(self):
        self.assertIsInstance(self.h.is_64bit_os(), bool)

    def test_is_64bit_python(self):
        self.assertIsInstance(self.h.is_64bit_python(), bool)

    def test_is_darwin_linux_windows(self):
        self.assertIsInstance(self.h.is_darwin(), bool)
        self.assertIsInstance(self.h.is_linux(), bool)
        self.assertIsInstance(self.h.is_windows(), bool)

        self.assertTrue(any([self.h.is_linux(), self.h.is_darwin(), self.h.is_windows()]))

    def test_is_pydro(self):
        self.assertIsInstance(self.h.is_pydro(), bool)

    def test_is_url(self):
        self.assertTrue(self.h.is_url("https://www.hydroffice.org"))
        self.assertTrue(self.h.is_url("http://www.hydroffice.org"))
        self.assertFalse(self.h.is_url("ftp://fake/url"))

    def test_python_path(self):
        self.assertTrue(os.path.exists(self.h.python_path()))

    def test_package_info(self):
        self.assertIsInstance(self.h.package_info(qt_html=True), str)
        self.assertIsInstance(self.h.package_info(qt_html=False), str)

    def test_package_folder(self):
        self.assertTrue(os.path.exists(self.h.package_folder()))

    def test_hydroffice_folder(self):
        self.assertTrue(os.path.exists(self.h.hydroffice_folder()))
예제 #16
0
    def click_find_fliers_v9(self):
        """trigger the find fliers v9"""

        # sanity checks
        # - list of grids (although the buttons should be never been enabled without grids)
        if len(self.prj.grid_list) == 0:
            raise RuntimeError("the grid list is empty")

        height_mode = "auto"
        if self.set_height_ffv9.text() != "":
            height_mode = self.set_height_ffv9.text()

        ck = "c"
        if self.set_check_laplacian_ffv9.isChecked():
            ck += "1"
        if self.set_check_curv_ffv9.isChecked():
            ck += "2"
        if self.set_check_adjacent_ffv9.isChecked():
            ck += "3"
        if self.set_check_slivers_ffv9.isChecked():
            ck += "4"
        if self.set_check_isolated_ffv9.isChecked():
            ck += "5"
        if self.set_check_edges_ffv9.isChecked():
            ck += "6"
        ck += "f"
        if self.set_filter_fff_ffv9.isChecked():
            ck += "1"
        if self.set_filter_designated_ffv9.isChecked():
            ck += "2"

        self.parent_win.change_info_url(
            Helper(lib_info=lib_info).web_url(
                suffix="survey_find_fliers_9_fh_%s_%s" % (height_mode, ck)))

        self._parse_user_height()

        grid_list = self.prj.grid_list

        # pre checks

        if self.set_filter_fff_ffv9.isChecked():

            if len(self.prj.s57_list) == 0:
                msg = "The 'Use Features from S57 File' option is active, but no S57 files have been selected!\n" \
                      "\n" \
                      "Do you want to continue with the analysis?"
                # noinspection PyCallByClass, PyArgumentList
                ret = QtWidgets.QMessageBox.warning(
                    self, "Find Fliers v9 filters", msg,
                    QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
                if ret == QtWidgets.QMessageBox.No:
                    return

        if self.set_filter_designated_ffv9.isChecked():
            at_least_one_bag = False
            for grid_file in grid_list:
                if os.path.splitext(grid_file)[-1] == ".bag":
                    at_least_one_bag = True

            if not at_least_one_bag:
                msg = "The 'Use Designated (SR BAG only)' option is active, " \
                      "but no BAG files have been selected!\n\n" \
                      "Do you want to continue with the analysis?"
                # noinspection PyCallByClass,PyArgumentList
                ret = QtWidgets.QMessageBox.warning(
                    self, "Find Fliers v9 filters", msg,
                    QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
                if ret == QtWidgets.QMessageBox.No:
                    return

        # for each file in the project grid list
        msg = "Potential fliers per input:\n"
        opened_folders = list()
        for i, grid_file in enumerate(grid_list):

            # we want to be sure that the label is based on the name of the new file input
            self.prj.clear_survey_label()

            # switcher between different versions of find fliers
            self._find_fliers(grid_file=grid_file,
                              idx=(i + 1),
                              total=len(grid_list))

            # export the fliers
            saved = self._export_fliers()
            msg += "- %s: %d\n" % (self.prj.cur_grid_basename,
                                   self.prj.number_of_fliers())

            # open the output folder (if not already open)
            if saved:

                if self.prj.fliers_output_folder not in opened_folders:
                    self.prj.open_fliers_output_folder()
                    opened_folders.append(self.prj.fliers_output_folder)

            self.prj.close_cur_grid()

        # noinspection PyCallByClass,PyArgumentList
        QtWidgets.QMessageBox.information(self, "Find fliers v9", msg,
                                          QtWidgets.QMessageBox.Ok)
예제 #17
0
    def setUp(self):

        self.h = Helper(lib_info=LibInfo())
예제 #18
0
 def click_open_manual_v2(cls):
     logger.debug("open manual")
     Helper.explore_folder(
         "https://www.hydroffice.org/manuals/qctools/stable/user_manual_survey_scan_designated.html"
     )
예제 #19
0
    def on_export_profile_btn(self):
        logger.debug("export profiles clicked")

        if len(self.selected_writers) == 0:
            msg = "Select output formats before data export!"
            # noinspection PyCallByClass
            QtWidgets.QMessageBox.warning(self, "Export warning", msg, QtWidgets.QMessageBox.Ok)
            return

        settings = QtCore.QSettings()

        select_output_folder = self.selectFolder.isChecked()
        settings.setValue("select_output_folder", select_output_folder)
        output_folders = dict()
        # each writer may potentially have is own folder
        if select_output_folder:

            dlg = OutputFoldersDialog(main_win=self.main_win, lib=self.lib, writers=self.selected_writers, parent=self)
            dlg.exec_()
            output_folders = dlg.output_folders
            if len(output_folders) == 0:
                return

        # case where all the writers will write to the same folder
        if len(output_folders) == 0:
            for writer in self.selected_writers:
                output_folders[writer] = self.lib.outputs_folder
            settings.setValue("export_folder", self.lib.outputs_folder)
            logger.debug('output folder: %s' % self.lib.outputs_folder)

        # CARIS-specific check for file concatenation
        for writer in self.selected_writers:

            if writer == 'caris':
                caris_path = os.path.join(output_folders[writer], "CARIS", self.lib.current_project + ".svp")
                if os.path.exists(caris_path):
                    msg = "An existing CARIS file is present in the output folder.\n\n" \
                          "Do you want to remove it to avoid possible profile duplications?"
                    # noinspection PyCallByClass
                    ret = QtWidgets.QMessageBox.question(self, "CARIS export", msg,
                                                         QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
                    if ret == QtWidgets.QMessageBox.Yes:
                        os.remove(caris_path)
                break

        # special case for Fugro ISS format
        force_writer_instrument_for_next_casts = None
        custom_writer_instrument = None

        # actually do the export
        current_project = None
        format_ok = False
        opened_folders = list()
        export_open_folder = self.openFolder.isChecked()
        settings.setValue("export_open_folder", export_open_folder)
        all_exported = True
        for pk in self._pks:

            success = self.lib.load_profile(pk, skip_atlas=True)
            if not success:
                # noinspection PyCallByClass
                QtWidgets.QMessageBox.warning(self, "Database", "Unable to load profile #%02d!" % pk,
                                              QtWidgets.QMessageBox.Ok)
                continue

            # special case: synthetic profile and NCEI
            skip_export = False
            for writer in self.selected_writers:

                if writer != 'ncei':
                    continue

                if self.lib.ssp.l[0].meta.sensor_type == Dicts.sensor_types['Synthetic']:
                    msg = "Attempt to export a synthetic profile in NCEI format!"
                    # noinspection PyCallByClass
                    QtWidgets.QMessageBox.warning(self, "Export warning", msg, QtWidgets.QMessageBox.Ok)
                    skip_export = True
                    continue

                if self.lib.current_project == 'default':

                    msg = "The 'default' project cannot be used for NCEI export.\n\n" \
                          "Rename the project in the Database tab!"
                    if self.lib.setup.noaa_tools:
                        msg += "\n\nRecommend in project_survey format, e.g. OPR-P999-RA-17_H12345"
                    # noinspection PyCallByClass
                    QtWidgets.QMessageBox.warning(self, "Export warning", msg, QtWidgets.QMessageBox.Ok)
                    skip_export = True
                    continue

                if self.lib.setup.noaa_tools and self.lib.not_noaa_project(self.lib.current_project):
                    if self.lib.not_noaa_project(current_project, format_ok):
                        current_project, format_ok = self.lib.cb.ask_formatted_text(default=self.lib.noaa_project)
                        if self.lib.not_noaa_project(current_project, format_ok):
                            msg = "The project name cannot be used for NCEI export.\n\n" \
                                  "Rename the project in the Database tab!\n\n" \
                                  "Recommend \"project_survey\" format, e.g. OPR-P999-RA-17_H12345"
                            # noinspection PyCallByClass
                            QtWidgets.QMessageBox.warning(self, "Export warning", msg, QtWidgets.QMessageBox.Ok)
                            skip_export = True
                            continue

                if not self.lib.ssp.cur.meta.survey or \
                        not self.lib.ssp.cur.meta.vessel or \
                        not self.lib.ssp.cur.meta.institution:
                    msg = "Survey, vessel, and institution metadata are mandatory for NCEI export.\n\n" \
                          "To fix the issue:\n" \
                          "- Load the profile (if not already loaded)\n" \
                          "- Set the missing values using the Metadata button on the Editor tool bar\n"
                    # noinspection PyCallByClass
                    QtWidgets.QMessageBox.warning(self, "Export warning", msg, QtWidgets.QMessageBox.Ok)
                    skip_export = True
                    continue

                # special case for Fugro ISS format with NCEI format
                if self.lib.ssp.cur.meta.probe_type == Dicts.probe_types['ISS']:
                    logger.info("special case: NCEI and ISS format")

                    if force_writer_instrument_for_next_casts is None:

                        msg = "Enter the instrument type and model \n(if you don't know, leave it blank):"
                        instrument, flag = self.lib.cb.ask_text_with_flag("ISS for NCEI", msg,
                                                                          flag_label="Apply to all the next profiles")
                        logger.debug("user input for ISS: %s, %r" % (instrument, flag))
                        # if empty, we just use the sensor type
                        if instrument is None or instrument == "":
                            instrument = self.lib.ssp.cur.meta.sensor
                        if flag:  # to skip the user dialog for next casts
                            force_writer_instrument_for_next_casts = instrument
                        else:
                            force_writer_instrument_for_next_casts = None
                        custom_writer_instrument = instrument

                    else:  # user asked to apply to all the next profiles
                        custom_writer_instrument = force_writer_instrument_for_next_casts

            if skip_export:
                all_exported = False
                continue

            self.progress.start(text="Exporting profile #%02d" % pk)
            try:
                self.progress.update(value=60)
                self.lib.export_data(data_paths=output_folders, data_formats=self.selected_writers,
                                     custom_writer_instrument=custom_writer_instrument)

            except RuntimeError as e:
                self.progress.end()
                msg = "Issue in exporting the data for profile #%02d.\nReason: %s" % (pk, e)
                # noinspection PyCallByClass
                QtWidgets.QMessageBox.critical(self, "Export error", msg, QtWidgets.QMessageBox.Ok)
                continue
            self.progress.end()

            # opening the output folder
            if export_open_folder:

                for output_folder in output_folders.values():
                    if output_folder not in opened_folders:
                        Helper.explore_folder(output_folder)
                        opened_folders.append(output_folder)

        if all_exported:
            msg = "Profiles successfully exported!"
            # noinspection PyCallByClass
            QtWidgets.QMessageBox.information(self, "Export profile", msg, QtWidgets.QMessageBox.Ok)
        else:
            msg = "At least one profile had issues in being exported!"
            # noinspection PyCallByClass
            QtWidgets.QMessageBox.warning(self, "Export profile", msg, QtWidgets.QMessageBox.Ok)

        self.accept()
예제 #20
0
    def _click_scan_designated(self, version):
        """abstract the grid qa calling mechanism"""

        # sanity checks
        # - version
        if not isinstance(version, int):
            raise RuntimeError("passed invalid type for version: %s" %
                               type(version))
        if version not in [
                2,
        ]:
            raise RuntimeError("passed invalid Designated Scan version: %s" %
                               version)
        if len(self.prj.s57_list) == 0:
            raise RuntimeError("the S57 list is empty")
        if len(self.prj.grid_list) == 0:
            raise RuntimeError("the grid list is empty")

        self.parent_win.change_info_url(
            Helper(lib_info=lib_info).web_url(
                suffix="survey_designated_scan_%d" % version))

        # check for user input as neighborhood check
        if version == 2:
            self.neighborhood_dsv2 = self.set_neighborhood_dsv2.isChecked()
        else:  # this case should be never reached after the sanity checks
            raise RuntimeError("unknown Designated Scan's version: %s" %
                               version)

        # for each file in the project grid list
        msg = "Flagged features per input:\n"
        s57_list = self.prj.s57_list
        grid_list = self.prj.grid_list
        opened_folders = list()

        for i, s57_file in enumerate(s57_list):

            # print("s57: %s" % s57_file)
            # we want to be sure that the label is based on the name of the new file input
            self.prj.clear_survey_label()

            try:
                self.prj.read_feature_file(feature_path=s57_file)

            except Exception as e:
                # noinspection PyCallByClass
                QtWidgets.QMessageBox.critical(
                    self, "Error", "While reading s57 file, %s" % e,
                    QtWidgets.QMessageBox.Ok)
                self.parent_win.progress.setValue(100)
                return

            for j, grid_file in enumerate(grid_list):

                idx = (j + 1) * (i * len(s57_list))
                total = len(s57_list) * len(grid_list)

                # switcher between different versions of find fliers
                if version == 2:
                    self._scan_designated(grid_file=grid_file,
                                          version=version,
                                          idx=idx,
                                          total=total)
                else:  # this case should be never reached after the sanity checks
                    raise RuntimeError("unknown Grid QA version: %s" % version)

                logger.info("survey label: %s" % self.prj.survey_label)

                # open the output folder (if not already open)
                if self.prj.save_designated():
                    if self.prj.designated_output_folder not in opened_folders:
                        self.prj.open_designated_output_folder()
                        opened_folders.append(
                            self.prj.designated_output_folder)

                msg += "- %s (S57: %s): %d\n" % \
                       (self.prj.cur_grid_basename, self.prj.cur_s57_basename, self.prj.number_of_designated())

                # close the grid file
                self.prj.close_cur_grid()

        # noinspection PyCallByClass
        QtWidgets.QMessageBox.information(self,
                                          "Designated Scan v%d" % version, msg,
                                          QtWidgets.QMessageBox.Ok)
예제 #21
0
    def _click_sbdare_export(self, version):
        """abstract the SBDARE export calling mechanism"""

        # sanity checks
        # - version
        if not isinstance(version, int):
            raise RuntimeError("passed invalid type for version: %s" %
                               type(version))

        if version not in [5]:
            raise RuntimeError("passed invalid Feature Scan version: %s" %
                               version)

        # - list of grids (although the buttons should be never been enabled without grids)
        if len(self.prj.s57_list) == 0:
            raise RuntimeError("the S57 list is empty")

        self.parent_win.change_info_url(
            Helper(lib_info=lib_info).web_url(
                suffix="survey_sbdare_export_%d" % version))

        # for each file in the project grid list
        msg = "Exported SBDARE features per input:\n"
        s57_list = self.prj.s57_list
        opened_folders = list()
        total = len(s57_list)
        for i, s57_file in enumerate(s57_list):

            self.parent_win.progress.start(
                title="SBDARE export v.%d" % version,
                text="Data loading [%d/%d]" % (i + 1, total),
                init_value=10)

            # we want to be sure that the label is based on the name of the new file input
            self.prj.clear_survey_label()

            self.parent_win.progress.update(value=20,
                                            text="SBDARE export v%d [%d/%d]" %
                                            (version, i + 1, total))

            # switcher between different versions of SBDARE export
            if version in [5]:
                self._sbdare_export(feature_file=s57_file,
                                    version=version,
                                    idx=(i + 1),
                                    total=len(s57_list))
            else:  # this case should be never reached after the sanity checks
                raise RuntimeError("unknown SBDARE export version: %s" %
                                   version)

            self.parent_win.progress.update(value=40,
                                            text="SBDARE export v%d [%d/%d]" %
                                            (version, i + 1, total))

            # export the flagged features
            logger.debug('exporting SBDARE features ...')
            saved = self.prj.save_sbdare()
            logger.debug('exporting SBDARE features: done')
            msg += "- %s: %d\n" % (self.prj.cur_s57_basename,
                                   self.prj.number_of_sbdare_features())

            # open the output folder (if not already open)
            if saved:

                if self.prj.sbdare_output_folder not in opened_folders:
                    self.prj.open_sbdare_output_folder()
                    opened_folders.append(self.prj.sbdare_output_folder)

        warnings = self.prj.sbdare_warnings()
        msg += "\nWarnings: %d\n" % len(warnings)
        logger.info("Warnings: %d" % len(warnings))

        for idx, warning in enumerate(warnings):

            logger.debug("#%02d: %s" % (idx, warning))
            if idx == 9:
                msg += "- ... \n\n" \
                       "The remaining warnings are listed in the Command Shell.\n"
                continue
            if idx > 9:
                continue
            msg += "- %s\n" % warning

        self.parent_win.progress.end()

        # noinspection PyCallByClass
        QtWidgets.QMessageBox.information(self, "SBDARE export v%d" % version,
                                          msg, QtWidgets.QMessageBox.Ok)
예제 #22
0
 def click_open_manual(cls):
     logger.debug("open manual")
     Helper.explore_folder("https://www.hydroffice.org/manuals/qctools/user_manual_survey_valsou_checks.html")
예제 #23
0
 def open_output_folder(self) -> None:
     if self.output_folder:
         Helper.explore_folder(str(self.output_folder))
     else:
         logger.warning('unable to define the output folder to open')
예제 #24
0
    def _click_valsou_check(self, version):
        """abstract the feature scan calling mechanism"""

        # sanity checks
        # - version
        if not isinstance(version, int):
            raise RuntimeError("passed invalid type for version: %s" % type(version))
        if version not in [7, ]:
            raise RuntimeError("passed invalid VALSOU check version: %s" % version)
        # - list of grids (although the buttons should be never been enabled without grids)
        if len(self.prj.s57_list) == 0:
            raise RuntimeError("the S57 list is empty")
        if len(self.prj.grid_list) == 0:
            raise RuntimeError("the grid list is empty")

        self.parent_win.change_info_url(Helper(lib_info=lib_info).web_url(suffix="survey_valsou_check_%d" % version))

        # for each file in the project grid list
        msg = "Flagged features per input pair:\n"
        s57_list = self.prj.s57_list
        grid_list = self.prj.grid_list
        opened_folders = list()

        for i, s57_file in enumerate(s57_list):

            # print("s57: %s" % s57_file)
            # we want to be sure that the label is based on the name of the new file input
            self.prj.clear_survey_label()

            try:
                self.prj.read_feature_file(feature_path=s57_file)

            except Exception as e:
                # noinspection PyCallByClass
                QtWidgets.QMessageBox.critical(self, "Error", "While reading s57 file, %s" % e,
                                               QtWidgets.QMessageBox.Ok)
                self.parent_win.progress.setValue(100)
                return

            for j, grid_file in enumerate(grid_list):

                idx = (j + 1)*(i*len(s57_list))
                total = len(s57_list)*len(grid_list)

                # switcher between different versions of find fliers
                if version in [7, ]:
                    self._valsou_check(grid_file=grid_file, version=version, idx=idx, total=total)
                else:  # this case should be never reached after the sanity checks
                    raise RuntimeError("unknown VALSOU check version: %s" % version)

                logger.info("survey label: %s" % self.prj.survey_label)

                # de-confliction
                if version == 7 and self.set_overlap_fsv7.isChecked():
                    self.parent_win.progress.start(title="VALSOU check v.%d" % version,
                                                   text="Deconflicting [%d/%d]" % (idx, total),
                                                   init_value=90)
                    self.prj.valsou_check_deconflict_v7()
                    self.parent_win.progress.end()

                # open the output folder (if not already open)
                if self._export_valsou_check():
                    if self.prj.valsou_output_folder not in opened_folders:
                        self.prj.open_valsou_output_folder()
                        opened_folders.append(self.prj.valsou_output_folder)

                if self.prj.valsou_out_of_bbox:
                    msg += "- %s VS. %s: %s\n" % (self.prj.cur_s57_basename, self.prj.cur_grid_basename,
                                                  "no overlap")
                else:
                    msg += "- %s VS. %s: %d\n" % (self.prj.cur_s57_basename, self.prj.cur_grid_basename,
                                                  self.prj.number_of_valsou_features())

                # close the grid file
                self.prj.close_cur_grid()

        # noinspection PyCallByClass
        QtWidgets.QMessageBox.information(self, "VALSOU check v%d" % version, msg, QtWidgets.QMessageBox.Ok)
예제 #25
0
 def timestamp(self):
     return Helper.timestamp()
예제 #26
0
else:
    for bag_with_fliers in bag_with_fliers_list:
        report += ("  . %s, %s\n" %
                   (bag_with_fliers, nr_fliers_per_bag_dict[bag_with_fliers]))
    report += "- crashes while processing: %d/%d\n" % (len(bag_crash_list),
                                                       nr_bag_todo)
    for bag_crash in bag_crash_list:
        report += ("  . %s\n" % bag_crash)
logger.info("\n%s" % report)

# save on disk a final report

if write_report_on_disk:

    report_path = os.path.join(output_folder, "Batch_Find_Fliers_Results.txt")
    try:  # Trapping Exceptions like OSError (File permissions)

        with open(report_path, "w") as fod:
            fod.write(report)

    except Exception as e:
        logger.warning("issue in saving report on disk: %s (%s)" %
                       (report_path, e))

# open the output folder

if open_output_folder:
    Helper.explore_folder(output_folder)

logger.debug("DONE!")
예제 #27
0
 def open_bagchecks_output_folder(self):
     logger.info("open %s" % self.bagchecks_output_folder)
     Helper.explore_folder(self.bagchecks_output_folder)
예제 #28
0
 def open_folder(self):
     Helper.explore_folder(self.data_folder)
예제 #29
0
 def open_system_noaa_support_folder(cls):
     if cls.system_noaa_support_folder_present():
         Helper.explore_folder(cls.system_noaa_support_folder())
         return
예제 #30
0
    def noaa_support_install(self):
        logger.debug("installing NOAA Support Files")

        noaa_support = NOAASupport(app_info=self._ai,
                                   lib_info=self._li,
                                   progress=QtProgress(parent=self))

        msg = "The batch file must be executed as administrator\n" \
              "with all other users logged off the system.\n" \
              "Once executed, follow the instructions in the Windows shell.\n\n" \
              "Do you want to continue with the installation?"
        # noinspection PyCallByClass,PyArgumentList
        ret = QtWidgets.QMessageBox.information(
            self, "Install files", msg,
            QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
        if ret == QtWidgets.QMessageBox.No:
            return

        if not noaa_support.system_noaa_support_folder_present():
            msg = "The support folder is not present!\n" \
                  "Did you copy it? Go to step #2."
            # noinspection PyCallByClass,PyArgumentList
            QtWidgets.QMessageBox.information(self, "Install files", msg,
                                              QtWidgets.QMessageBox.Ok)
            return

        if not noaa_support.system_batch_file_exists():
            msg = "The batch file does not exist!\n" \
                  "Did you execute steps #1 and #2? Try to execute them again."
            # noinspection PyCallByClass,PyArgumentList
            QtWidgets.QMessageBox.information(self, "Install files", msg,
                                              QtWidgets.QMessageBox.Ok)
            return

        if not Helper.is_user_admin():

            msg = "The app was not executed as admin!\n\n" \
                  "Do you want that this app executes the batch file?\n\n" \
                  "You will be prompted for permissions.\n"

            # noinspection PyCallByClass,PyArgumentList
            ret = QtWidgets.QMessageBox.information(
                self, "Install files", msg,
                QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
            if ret == QtWidgets.QMessageBox.No:

                msg = "You have then two alternatives:\n" \
                      "#1: Close the app and re-open it using the option \"Run as administrator\"\n" \
                      "or:\n" \
                      "#2: Manually run as administrator the batch file at:\n" \
                      "- %s\n\n" \
                      "For option #2, do you want that the appFMG_8880" \
                      " open the folder with the batch file?" \
                      % (noaa_support.system_batch_file())

                # noinspection PyCallByClass,PyArgumentList
                ret = QtWidgets.QMessageBox.information(
                    self, "Install files", msg,
                    QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
                if ret == QtWidgets.QMessageBox.Yes:
                    noaa_support.open_system_noaa_support_folder()
                return

            installed = noaa_support.exec_system_batch()
            if installed:
                msg = "Follow the instruction in the windows shell!"
                # noinspection PyCallByClass,PyArgumentList
                QtWidgets.QMessageBox.information(self, "Windows shell", msg,
                                                  QtWidgets.QMessageBox.Ok)
                return

            else:
                msg = "Unable to install the support files.\n" \
                      "Try to manually run as administrator the batch file at: %s\n\n" \
                      % (noaa_support.system_batch_file())
                # noinspection PyCallByClass,PyArgumentList
                QtWidgets.QMessageBox.critical(self, "Error", msg,
                                               QtWidgets.QMessageBox.Ok)
                noaa_support.open_system_noaa_support_folder()
                return

        else:

            installed = noaa_support.exec_system_batch()
            if installed:
                msg = "Success!"
                # noinspection PyCallByClass,PyArgumentList
                QtWidgets.QMessageBox.information(self, "Installation done!",
                                                  msg,
                                                  QtWidgets.QMessageBox.Ok)
                return

            else:
                msg = "Unable to install the support files.\n" \
                      "Try to manually run as administrator the batch file at: %s\n\n" \
                      % (noaa_support.system_batch_file())
                # noinspection PyCallByClass,PyArgumentList
                QtWidgets.QMessageBox.critical(self, "Error", msg,
                                               QtWidgets.QMessageBox.Ok)
                noaa_support.open_system_noaa_support_folder()
                return