Ejemplo n.º 1
0
    def delete_local_noaa_support_files(self):

        try:
            if os.path.exists(self.local_zip_path):
                os.remove(self.local_zip_path)

        except Exception as e:
            logger.error('during cleaning zip archive: %s' % e)
            return False

        for folder in os.listdir(Helper(lib_info=self._li).package_folder()):

            candidate_path = os.path.join(Helper(lib_info=self._li).package_folder(), folder)
            if os.path.isfile(candidate_path):
                continue

            if ("Caris_Support_Files_%s" % self.v_version()) in folder:

                try:
                    # remove all the content
                    for root, dirs, files in os.walk(candidate_path, topdown=False):
                        for name in files:
                            os.remove(os.path.join(root, name))
                        for name in dirs:
                            os.rmdir(os.path.join(root, name))

                    os.rmdir(candidate_path)

                except Exception as e:
                    logger.error('during cleaning folder %s: %s' % (candidate_path, e))
                    return False

        return True
Ejemplo n.º 2
0
    def local_noaa_support_folder(self):
        ret = str()
        for folder in sorted(os.listdir(Helper(lib_info=self._li).package_folder())):
            # logger.debug("folder: %s" % folder)
            if ("Caris_Support_Files" in folder) and (len(folder) > 24):
                ret = os.path.join(Helper(lib_info=self._li).package_folder(), folder)

        return ret
Ejemplo n.º 3
0
    def _check_web_page(self, token: str = ""):
        try:
            if len(token) > 0:
                url = "%s_%s" % (Helper(lib_info=lib_info).web_url(), token)
            else:
                url = "%s" % Helper(lib_info=lib_info).web_url()
            self._web.open(url=url)
            logger.debug('check %s' % url)

        except Exception as e:
            logger.warning(e)
Ejemplo n.º 4
0
    def click_bag_checks_v2(self):
        """abstract the BAG checks calling mechanism"""

        url_suffix = "survey_bag_checks_v2"
        self.parent_win.change_info_url(
            Helper(lib_info=lib_info).web_url(suffix=url_suffix))

        try:
            self.prj.bag_checks_v2(
                use_nooa_nbs_profile=self.use_noaa_nbs_rules.isChecked(),
                check_structure=self.check_structure.isChecked(),
                check_metadata=self.check_metadata.isChecked(),
                check_elevation=self.check_elevation.isChecked(),
                check_uncertainty=self.check_uncertainty.isChecked(),
                check_tracking_list=self.check_tracking_list.isChecked(),
                check_gdal_compatibility=self.check_gdal_compatibility.
                isChecked())

        except Exception as e:
            # noinspection PyCallByClass,PyArgumentList
            QtWidgets.QMessageBox.critical(self, "Error", "%s" % e,
                                           QtWidgets.QMessageBox.Ok)
            self.prj.progress.end()
            return

        # noinspection PyCallByClass,PyArgumentList
        QtWidgets.QMessageBox.information(self, "BAG Checks v2",
                                          self.prj.bag_checks_message,
                                          QtWidgets.QMessageBox.Ok)
Ejemplo n.º 5
0
 def __init__(self, lib_info: LibInfo, app_info: AppInfo, progress=CliProgress()):
     self._li = lib_info
     self._ai = app_info
     self.progress = progress
     self.local_zip_path = os.path.abspath(os.path.join(Helper(lib_info=self._li).package_folder(),
                                                        "Caris_Support_Files_%s.zip" % self.v_version()))
     self.local_batch_file = None
Ejemplo n.º 6
0
    def unzip_internal_zip(self):

        if not self.delete_local_noaa_support_files():
            return False

        try:
            z = zipfile.ZipFile(self.internal_zip_path(), "r")
            unzip_path = Helper(lib_info=self._li).package_folder()

            logger.debug("unzipping %s to %s" %
                         (self.internal_zip_path(), unzip_path))

            name_list = z.namelist()
            file_nr = len(name_list)
            self.progress.start(title="Unzipping")

            file_count = 0
            for item in name_list:
                # print(item)
                z.extract(item, unzip_path)
                file_count += 1
                pct = int((file_count / file_nr) * 100.0)
                self.progress.update(value=pct)

            z.close()
            self.progress.end()
            return True

        except Exception as e:
            logger.warning("unable to unzip the file: %s, %s" %
                           (self.internal_zip_path(), e))
            return False
Ejemplo n.º 7
0
    def default_output_folder(cls):

        output_folder = Helper(lib_info=lib_info).package_folder()
        if not os.path.exists(output_folder):  # create it if it does not exist
            os.makedirs(output_folder)

        return output_folder
Ejemplo n.º 8
0
    def do_import(self, idx):
        name = self.lib.name_readers[idx]
        desc = self.lib.desc_readers[idx]
        ext = self.lib.ext_readers[idx]

        # ask the file path to the user
        flt = "Format %s(*.%s);;All files (*.*)" % (desc, " *.".join(ext))
        settings = QtCore.QSettings()
        start_dir = settings.value("import_folders_%s" % name, settings.value("import_folder"))
        # noinspection PyCallByClass
        selection, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Load %s data file" % desc,
                                                             start_dir, flt)
        if not selection:
            return
        settings.setValue("import_folder", os.path.dirname(selection))
        settings.setValue("import_folders_%s" % name, os.path.dirname(selection))
        logger.debug('user selection: %s' % selection)

        self.main_win.change_info_url(Helper(lib_info=lib_info).web_url(suffix="%s" % name))

        self.progress.start()
        try:
            self.lib.import_data(data_path=selection, data_format=name)

        except RuntimeError as e:
            self.progress.end()
            traceback.print_exc()
            msg = "Issue in importing the data:\n\n> %s" % e
            # noinspection PyCallByClass,PyArgumentList
            QtWidgets.QMessageBox.critical(self, "Import error", msg, QtWidgets.QMessageBox.Ok)
            return

        if self.lib.ssp_list.nr_profiles > 1:
            ssp_list = list()
            for i, ssp in enumerate(self.lib.ssp_list.l):
                ssp_list.append(
                    "#%03d: %s (%.6f, %.6f)" % (i, ssp.meta.utc_time, ssp.meta.latitude, ssp.meta.longitude))

            # noinspection PyCallByClass
            sel, ok = QtWidgets.QInputDialog.getItem(self, 'Multiple profiles',
                                                     'Select a profile (if you want to import all of them,\n'
                                                     'use the multi-import dialog in Database tab):',
                                                     ssp_list, 0, False)

            if sel and ok:
                self.lib.ssp_list.current_index = ssp_list.index(sel)

            else:
                self.lib.clear_data()
                self.progress.end()
                self.accept()
                return

        self.progress.end()

        if settings.value("show_metadata_at_import") == 'true':
            if self.parent() is not None:
                self.parent().on_metadata()

        self.accept()
Ejemplo n.º 9
0
    def click_triangle_rule(self):

        # library takes care of progress bar

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

        if self.toggle_units_v2.value() == 0:
            sounding_unit = sounding_units['feet']
        elif self.toggle_units_v2.value() == 1:
            sounding_unit = sounding_units['meters']
        else:
            sounding_unit = sounding_units['fathoms']

        self.prj.triangle_rule(
            version=version,
            use_valsous=self.set_use_valsous_v2.isChecked(),
            use_depcnts=self.set_use_depcnt_v2.isChecked(),
            detect_deeps=self.set_detect_deeps_v2.isChecked(),
            sounding_unit=sounding_unit,
            meter_th=float(self.set_meter_th_v2.text()))

        # noinspection PyCallByClass
        QtWidgets.QMessageBox.information(self, "Triangle Rule v%d" % version,
                                          self.prj.triangle_msg,
                                          QtWidgets.QMessageBox.Ok)
Ejemplo n.º 10
0
    def click_truncate(self):
        # library takes care of progress bar

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

        if self.set_epsg_crs_xyv2.isChecked():
            epsg_txt = self.set_epsg_xyv2.currentText()
            if epsg_txt in self.crs.keys():
                epsg_code = self.crs[epsg_txt]
            else:
                try:
                    epsg_code = int(epsg_txt)
                except Exception as e:
                    # noinspection PyCallByClass,PyArgumentList
                    QtWidgets.QMessageBox.warning(
                        self, "Invalid EPSG Code",
                        "While reading '%s', %s" % (epsg_txt, e),
                        QtWidgets.QMessageBox.Ok)
                    return
        else:
            epsg_code = None

        self.prj.grid_xyz(version=version,
                          geographic=self.set_geo_crs_xyv2.isChecked(),
                          elevation=self.set_z_elevation.isChecked(),
                          truncate=self.set_flag_truncation_xyv2.isChecked(),
                          decimal_places=int(self.set_dec_places_xyv2.text()),
                          epsg_code=epsg_code,
                          order=self.set_output_order_xyv2.currentText())
Ejemplo n.º 11
0
    def on_click_import(self, btn):
        # print("clicked %s" % btn.text())
        idx = self.lib.desc_readers.index(btn.text())
        name = self.lib.name_readers[idx]
        desc = self.lib.desc_readers[idx]
        ext = self.lib.ext_readers[idx]

        if desc in ["CARIS", "ELAC", "Kongsberg", "Hypack"]:
            msg = "Do you really want to store profiles based \non pre-processed %s data?\n\n" \
                  "This operation may OVERWRITE existing raw data \nin the database!" \
                  % desc
            # noinspection PyCallByClass,PyArgumentList
            ret = QtWidgets.QMessageBox.warning(
                self, "Pre-processed source warning", msg,
                QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
            if ret == QtWidgets.QMessageBox.No:
                return

        # ask the file path to the user
        flt = "Format %s(*.%s);;All files (*.*)" % (desc, " *.".join(ext))
        settings = QtCore.QSettings()
        # noinspection PyCallByClass
        selections, _ = QtWidgets.QFileDialog.getOpenFileNames(
            self, "Load data files", settings.value("import_folder"), flt)
        if len(selections) == 0:
            return
        settings.setValue("import_folder", os.path.dirname(selections[0]))

        nr_profiles = len(selections)
        logger.debug('user selections: %s' % nr_profiles)
        quantum = 100 / (nr_profiles * 2 + 1)
        self.progress.start()

        self.main_win.change_info_url(
            Helper(lib_info=lib_info).web_url(suffix="%s" % name))

        for i, selection in enumerate(selections):

            try:
                self.progress.add(quantum=quantum,
                                  text="profile %s/%s" % (i, nr_profiles))
                self.lib.import_data(data_path=selection,
                                     data_format=name,
                                     skip_atlas=True)

                self.progress.add(quantum=quantum)
                self.lib.store_data()

            except RuntimeError as e:
                self.progress.end()
                msg = "Issue in importing the file #%s: %s\n\n> %s" % (
                    i, selection, e)
                # noinspection PyCallByClass,PyArgumentList
                QtWidgets.QMessageBox.critical(self, "Import error", msg,
                                               QtWidgets.QMessageBox.Ok)
                return

        self.progress.end()
        self.accept()
Ejemplo n.º 12
0
    def _click_grid_qa(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 [
                6,
        ]:
            raise RuntimeError("passed invalid Grid QA version: %s" % version)
        # - 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")

        url_suffix = "survey_grid_qa_%d" % version
        if self.hist_catzoc.isChecked():
            url_suffix += "_catzoc"
        self.parent_win.change_info_url(
            Helper(lib_info=lib_info).web_url(suffix=url_suffix))

        # check for user input as force TVU QC
        if version == 6:
            self.force_tvu_qc_gqv6 = self.set_force_tvu_qc_gqv6.isChecked()
            self.toggle_mode_gqv6 = self.set_toggle_mode_gqv6.value()
        else:  # this case should be never reached after the sanity checks
            raise RuntimeError("unknown Grid QA's version: %s" % version)

        # for each file in the project grid list
        msg = "QA results per input:\n"
        grid_list = self.prj.grid_list
        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
            if version == 6:
                success = self._grid_qa(grid_file=grid_file,
                                        version=version,
                                        idx=(i + 1),
                                        total=len(grid_list))
            else:  # this case should be never reached after the sanity checks
                raise RuntimeError("unknown Grid QA version: %s" % version)

            if success:
                msg += "- %s: done\n" % self.prj.cur_grid_basename
            else:
                msg += "- %s: skip\n" % self.prj.cur_grid_basename

            # open the output folder (if not already open)
            if self.prj.gridqa_output_folder not in opened_folders:
                self.prj.open_gridqa_output_folder()
                opened_folders.append(self.prj.gridqa_output_folder)

        # noinspection PyCallByClass
        QtWidgets.QMessageBox.information(self, "Grid QA v%d" % version, msg,
                                          QtWidgets.QMessageBox.Ok)
Ejemplo n.º 13
0
    def default_output_folder(cls):

        output_folder = os.path.join(Helper(lib_info=lib_info).package_folder(),
                                     cls.__name__.replace("Project", ""))
        if not os.path.exists(output_folder):  # create it if it does not exist
            os.makedirs(output_folder)

        return output_folder
Ejemplo n.º 14
0
    def _click_find_holes(self, version):
        """abstract the find holes 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 Find Holiday version: %s" %
                               version)
        # - 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")

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

        # for each file in the project grid list
        msg = "Potential holidays per input:\n"
        grid_list = self.prj.grid_list
        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
            if version == 4:
                self._find_holes(grid_file=grid_file,
                                 version=version,
                                 idx=(i + 1),
                                 total=len(grid_list))

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

            # export the fliers
            msg += "- %s: certain %d, possible %d\n" \
                   % (self.prj.cur_grid_basename, self.prj.number_of_certain_holes(),
                      self.prj.number_of_possible_holes())
            saved = self._export_holes()

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

                if self.prj.holes_output_folder not in opened_folders:
                    self.prj.open_holes_output_folder()
                    opened_folders.append(self.prj.holes_output_folder)

        # noinspection PyCallByClass
        QtWidgets.QMessageBox.information(self, "Find holidays v%d" % version,
                                          msg, QtWidgets.QMessageBox.Ok)
Ejemplo n.º 15
0
    def click_truncate(self):
        # library takes care of progress bar

        version = 2
        self.parent_win.change_info_url(
            Helper(lib_info=lib_info).web_url(suffix="chart_grid_truncate_%d" %
                                              version))
        self.prj.grid_truncate(version=version,
                               decimal_places=int(
                                   self.set_dec_places_gtv2.text()))
Ejemplo n.º 16
0
    def click_truncate(self):
        # library takes care of progress bar

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

        self.prj.grid_xyz(version=version,
                          geographic=self.set_geo_xyv1.isChecked(),
                          elevation=self.set_z_elevation.isChecked(),
                          truncate=self.set_flag_truncation_xyv1.isChecked(),
                          decimal_places=int(self.set_dec_places_xyv1.text()))
Ejemplo n.º 17
0
    def __init__(self, lib_info: LibInfo, parent: QtWidgets.QWidget = None):
        super().__init__(parent)
        self._li = lib_info

        self.layout = QtWidgets.QVBoxLayout()
        self.setLayout(self.layout)

        self.text = QtWidgets.QTextBrowser()
        self.text.setReadOnly(True)
        self.text.setMinimumWidth(200)
        self.text.setOpenLinks(True)
        self.text.setOpenExternalLinks(True)
        self.text.document().setDefaultStyleSheet(AppStyle.html_css())
        self.text.setHtml(Helper(lib_info=lib_info).package_info(qt_html=True))
        self.layout.addWidget(self.text)
Ejemplo n.º 18
0
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)

        logger.info("current configuration:\n%s" %
                    Helper(lib_info=lib_info).package_info())

        # set the application name
        self.name = app_info.app_name
        self.version = app_info.app_version
        self.setWindowTitle('{} {}'.format(self.name, self.version))
        self.setMinimumSize(QtCore.QSize(500, 800))
        self.resize(QtCore.QSize(920, 840))

        self.exception_signal.connect(self.show_exception_dialog)

        # noinspection PyArgumentList
        _app = QtCore.QCoreApplication.instance()
        _app.setApplicationName('%s' % self.name)
        _app.setOrganizationName("HydrOffice")
        _app.setOrganizationDomain("hydroffice.org")

        # set icons
        icon_info = QtCore.QFileInfo(app_info.app_icon_path)
        self.setWindowIcon(QtGui.QIcon(icon_info.absoluteFilePath()))
        if Helper.is_windows():

            try:
                # This is needed to display the app icon on the taskbar on
                # Windows 7
                import ctypes
                app_id = '%s v.%s' % (self.name, self.version)
                ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(
                    app_id)

            except AttributeError as e:
                logger.debug("Unable to change app icon: %s" % e)

        self.qax_widget = QAXWidget(main_win=self)
        self.qax_widget.setDocumentMode(True)
        self.qax_widget.status_message.connect(self.update_status_bar)

        self._add_menu_bar()

        self.status_bar = QtWidgets.QStatusBar()
        self.setStatusBar(self.status_bar)
        self.status_bar.showMessage('...')

        self.setCentralWidget(self.qax_widget)
Ejemplo n.º 19
0
    def _click_feature_scan(self, version):
        """abstract the feature scan calling mechanism"""

        # library takes care of progress bar

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

        try:

            specs_version = None

            if version == 3:

                specs_version = self.toggle_specs_v3.value()
                if specs_version == 1:  # trick: there is not version 2015
                    specs_version = "2014"
                elif specs_version == 2:
                    specs_version = "2016"
                elif specs_version == 3:
                    specs_version = "2018"
                else:
                    raise RuntimeError("unknown specs version: %s" %
                                       specs_version)

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

            self.prj.feature_scan(version=version, specs_version=specs_version)

            # 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:
            # noinspection PyCallByClass
            QtWidgets.QMessageBox.critical(
                self, "Error",
                "While running chart's feature scan v%d, %s" % (version, e),
                QtWidgets.QMessageBox.Ok)
            return
Ejemplo n.º 20
0
    def format_bug_report(self):
        separator = "-" * 120 + "\n"
        timestamp = "%s v.%s - %s\n" % (self._ai.app_name,
                                        self._ai.app_version,
                                        email.utils.formatdate(localtime=True))

        msg = [timestamp, separator]
        msg.extend(traceback.format_exception_only(self.ex_type,
                                                   self.ex_value))
        msg.append(separator)
        msg.append('Traceback:\n')
        if self.user_triggered:
            msg.extend(self.tb_editor.toPlainText() + "\n")
        else:
            msg.extend(traceback.format_tb(self.tb))
        msg.append(separator)
        msg.extend(Helper(lib_info=self._li).package_info().splitlines(True))
        msg[-1] = msg[-1] + '\n'
        msg.append(separator)

        return msg
Ejemplo n.º 21
0
import logging

from hyo2.abc.lib.helper import Helper
from hyo2.abc.lib.lib_info import LibInfo
from hyo2.abc.lib.logging import set_logging

logger = logging.getLogger(__name__)
set_logging(ns_list=["hyo2.abc"])

h = Helper(lib_info=LibInfo())

logger.debug("lib info:\n%s" % h.package_info())

logger.debug("is Pydro: %s" % Helper.is_pydro())

if Helper.is_pydro():
    logger.debug("HSTB folder: %s" % Helper.hstb_folder())
    logger.debug("atlases folder: %s" % Helper.hstb_atlases_folder())
    logger.debug("WOA09 folder: %s" % Helper.hstb_woa09_folder())
    logger.debug("WOA13 folder: %s" % Helper.hstb_woa13_folder())
Ejemplo n.º 22
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()
Ejemplo n.º 23
0
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)

        logger.info("* > APP: initializing ...")

        # set the application name and the version
        self.name = app_info.app_name
        self.version = app_info.app_version
        self.setWindowTitle('%s v.%s' % (self.name, self.version))
        # noinspection PyArgumentList
        _app = QtCore.QCoreApplication.instance()
        _app.setApplicationName('%s' % self.name)
        _app.setOrganizationName("HydrOffice")
        _app.setOrganizationDomain("hydroffice.org")

        # set the minimum and the initial size
        self.setMinimumSize(640, 480)
        self.resize(920, 640)

        # set icons
        self.setWindowIcon(QtGui.QIcon(app_info.app_icon_path))

        # check if setup db exists; if yes, ask to copy
        has_setup = SoundSpeedLibrary.setup_exists()
        logger.info("setup exists: %s" % has_setup)
        if not has_setup:
            other_setups = SoundSpeedLibrary.list_other_setups()
            if len(other_setups) != 0:
                logger.debug("other existing setups: %d" % len(other_setups))
                # noinspection PyCallByClass
                sel, ok = QtWidgets.QInputDialog.getItem(self, 'Do you want to copy an existing setup?',
                                                         'Select one (or click on Cancel to create a new one):',
                                                         other_setups, 0, False)
                if ok:
                    SoundSpeedLibrary.copy_setup(input_setup=sel)

        # create the project
        self.lib = SoundSpeedLibrary(callbacks=QtCallbacks(parent=self), progress=QtProgress(parent=self))
        logger.info("current configuration:\n%s" % Helper(lib_info=lib_info).package_info())
        self.check_woa09()
        self.check_woa13()
        # self.check_rtofs()  # no need to wait for the download at the beginning
        self.check_sis4()
        self.check_sis5()
        self.check_sippican()
        self.check_mvp()

        # init default settings
        settings = QtCore.QSettings()
        export_folder = settings.value("export_folder")
        if (export_folder is None) or (not os.path.exists(export_folder)):
            settings.setValue("export_folder", self.lib.data_folder)
        import_folder = settings.value("import_folder")
        if (import_folder is None) or (not os.path.exists(import_folder)):
            settings.setValue("import_folder", self.lib.data_folder)

        # menu

        self.menu = self.menuBar()
        self.file_menu = self.menu.addMenu("File")
        self.edit_menu = self.menu.addMenu("Process")
        self.database_menu = self.menu.addMenu("Database")
        self.monitor_menu = self.menu.addMenu("Monitor")
        self.server_menu = self.menu.addMenu("Server")
        self.setup_menu = self.menu.addMenu("Setup")
        self.help_menu = self.menu.addMenu("Help")

        # make tabs
        self.tabs = QtWidgets.QTabWidget()
        self.setCentralWidget(self.tabs)
        self.tabs.setIconSize(QtCore.QSize(42, 42))
        self.tabs.blockSignals(True)  # during the initialization
        # noinspection PyUnresolvedReferences
        self.tabs.currentChanged.connect(self.on_change)  # changed!
        # editor
        self.tab_editor = Editor(lib=self.lib, main_win=self)
        self.idx_editor = self.tabs.insertTab(0, self.tab_editor,
                                              QtGui.QIcon(os.path.join(app_info.app_media_path, 'editor.png')), "")
        self.tabs.setTabToolTip(self.idx_editor, "Editor")
        # database
        self.tab_database = Database(lib=self.lib, main_win=self)
        self.idx_database = self.tabs.insertTab(1, self.tab_database,
                                                QtGui.QIcon(os.path.join(app_info.app_media_path, 'database.png')), "")
        self.tabs.setTabToolTip(self.idx_database, "Database")
        # survey data monitor
        self.has_sdm_support = True
        try:  # try.. except to make SSM working also without SDM
            # noinspection PyUnresolvedReferences
            from hyo2.surveydatamonitor.app.widgets.monitor import SurveyDataMonitor
            self.tab_monitor = SurveyDataMonitor(lib=self.lib, main_win=self)
            self.idx_monitor = self.tabs.insertTab(3, self.tab_monitor,
                                                   QtGui.QIcon(
                                                       os.path.join(app_info.app_media_path, 'surveydatamonitor.png')),
                                                   "")
            self.tabs.setTabToolTip(self.idx_monitor, "Survey Data Monitor")
            logger.info("Support for Survey Monitor: ON")
        except Exception as e:
            traceback.print_exc()
            self.has_sdm_support = False
            logger.info("Support for Survey Monitor: OFF(%s)" % e)
        # server
        self.tab_server = Server(lib=self.lib, main_win=self)
        self.idx_server = self.tabs.insertTab(4, self.tab_server,
                                              QtGui.QIcon(os.path.join(app_info.app_media_path, 'server.png')), "")
        self.tabs.setTabToolTip(self.idx_server, "Synthetic Profile Server")

        # refraction
        # self.tab_refraction = Refraction(lib=self.lib, main_win=self)
        # idx = self.tabs.insertTab(5, self.tab_refraction,
        #                           QtGui.QIcon(os.path.join(app_info.app_media_path, 'refraction.png')), "")
        # self.tabs.setTabToolTip(idx, "Refraction Monitor")
        # setup
        self.tab_setup = Settings(lib=self.lib, main_win=self)
        self.idx_setup = self.tabs.insertTab(6, self.tab_setup,
                                             QtGui.QIcon(os.path.join(app_info.app_media_path, 'settings.png')), "")
        self.tabs.setTabToolTip(self.idx_setup, "Setup")
        # info
        self.tab_info = InfoTab(main_win=self, lib_info=lib_info, app_info=app_info,
                                with_online_manual=True,
                                with_offline_manual=True,
                                with_bug_report=True,
                                with_hydroffice_link=True,
                                with_ccom_link=True,
                                with_noaa_link=True,
                                with_unh_link=True,
                                with_license=True)
        self.idx_info = self.tabs.insertTab(6, self.tab_info,
                                            QtGui.QIcon(os.path.join(app_info.app_media_path, 'info.png')), "")
        self.tabs.setTabToolTip(self.idx_info, "Info")
        # Help menu
        self.help_menu.addAction(self.tab_info.open_online_manual_action)
        self.help_menu.addAction(self.tab_info.open_offline_manual_action)
        self.help_menu.addAction(self.tab_info.fill_bug_report_action)
        self.help_menu.addAction(self.tab_info.authors_action)
        self.help_menu.addAction(self.tab_info.show_about_action)

        self.statusBar().setStyleSheet("QStatusBar{color:rgba(0,0,0,128);font-size: 8pt;}")
        self.status_bar_normal_style = self.statusBar().styleSheet()
        self.statusBar().showMessage("%s" % app_info.app_name, 2000)
        self.releaseInfo = QtWidgets.QLabel()
        self.statusBar().addPermanentWidget(self.releaseInfo)
        self.releaseInfo.setStyleSheet("QLabel{color:rgba(0,0,0,128);font-size: 8pt;}")
        timer = QtCore.QTimer(self)
        # noinspection PyUnresolvedReferences
        timer.timeout.connect(self.update_gui)
        timer.start(1500)
        self.timer_execs = 0

        self.data_cleared()
        self.tabs.blockSignals(False)

        logger.info("* > APP: initialized!")
Ejemplo n.º 24
0
    def __init__(self,
                 main_win: QtWidgets.QMainWindow,
                 lib_info: LibInfo,
                 app_info: AppInfo,
                 tab_name: str = "App Info Tab",
                 start_url: Optional[str] = None,
                 default_url: str = "http://www.hydroffice.org",
                 with_online_manual: bool = False,
                 with_offline_manual: bool = False,
                 with_bug_report: bool = False,
                 with_hydroffice_link: bool = False,
                 with_ccom_link: bool = False,
                 with_noaa_link: bool = False,
                 with_unh_link: bool = False,
                 with_license: bool = False,
                 with_noaa_57: bool = False,
                 with_ausseabed_link: bool = False):
        super().__init__(main_win)
        self._li = lib_info
        self._ai = app_info
        self.defaul_url = default_url
        self.settings = QtCore.QSettings()

        self.setWindowTitle(tab_name)
        self.setContentsMargins(0, 0, 0, 0)

        # add main frame and layout
        self.frame = QtWidgets.QFrame(parent=self)
        self.setCentralWidget(self.frame)
        self.frame_layout = QtWidgets.QVBoxLayout()
        self.frame.setLayout(self.frame_layout)

        if start_url is None:
            start_url = Helper(lib_info=self._li).web_url()
        self.start_url = start_url

        # add browser
        self.browser = Browser(url=self.start_url)
        self.frame_layout.addWidget(self.browser)

        # add about dialog
        self.about_dlg = AboutDialog(lib_info=self._li,
                                     app_info=self._ai,
                                     parent=self,
                                     with_locale_tab=True,
                                     with_gdal_tab=True)
        self.about_dlg.hide()

        icon_size = QtCore.QSize(self._ai.app_toolbars_icon_size,
                                 self._ai.app_toolbars_icon_size)

        # noinspection PyArgumentList
        self.toolbar = self.addToolBar('Shortcuts')
        self.toolbar.setIconSize(icon_size)

        # home
        self.home_action = QtWidgets.QAction(
            QtGui.QIcon(os.path.join(self.media, 'home.png')), 'Home page',
            self)
        # noinspection PyUnresolvedReferences
        self.home_action.triggered.connect(self.load_default)
        self.toolbar.addAction(self.home_action)

        # online manual
        self.open_online_manual_action = None
        if with_online_manual:
            self.open_online_manual_action = QtWidgets.QAction(
                QtGui.QIcon(os.path.join(self.media, 'online_manual.png')),
                'Online Manual', self)
            self.open_online_manual_action.setStatusTip(
                'Open the online manual')
            # noinspection PyUnresolvedReferences
            self.open_online_manual_action.triggered.connect(
                self.open_online_manual)
            self.toolbar.addAction(self.open_online_manual_action)

        # offline manual
        self.open_offline_manual_action = None
        if with_offline_manual:
            self.open_offline_manual_action = QtWidgets.QAction(
                QtGui.QIcon(os.path.join(self.media, 'offline_manual.png')),
                'Offline Manual', self)
            self.open_offline_manual_action.setStatusTip(
                'Open the offline manual')
            # noinspection PyUnresolvedReferences
            self.open_offline_manual_action.triggered.connect(
                self.open_offline_manual)
            self.toolbar.addAction(self.open_offline_manual_action)

        # bug report
        self.fill_bug_report_action = None
        if with_bug_report:
            self.fill_bug_report_action = QtWidgets.QAction(
                QtGui.QIcon(os.path.join(self.media, 'bug.png')), 'Bug Report',
                self)
            self.fill_bug_report_action.setStatusTip('Fill a bug report')
            # noinspection PyUnresolvedReferences
            self.fill_bug_report_action.triggered.connect(self.fill_bug_report)
            self.toolbar.addAction(self.fill_bug_report_action)

        self.toolbar.addSeparator()

        # HydrOffice.org
        self.hyo_action = None
        if with_hydroffice_link:
            self.hyo_action = QtWidgets.QAction(
                QtGui.QIcon(os.path.join(self.media, 'hyo.png')),
                'HydrOffice.org', self)
            # noinspection PyUnresolvedReferences
            self.hyo_action.triggered.connect(self.load_hydroffice_org)
            self.toolbar.addAction(self.hyo_action)

        # noaa
        self.noaa_action = None
        if with_noaa_link:
            self.noaa_action = QtWidgets.QAction(
                QtGui.QIcon(os.path.join(self.media, 'noaa.png')),
                'nauticalcharts.noaa.gov', self)
            # noinspection PyUnresolvedReferences
            self.noaa_action.triggered.connect(self.load_noaa_ocs_gov)
            self.toolbar.addAction(self.noaa_action)

        # ccom.unh.edu
        self.ccom_action = None
        if with_ccom_link:
            self.ccom_action = QtWidgets.QAction(
                QtGui.QIcon(os.path.join(self.media, 'ccom.png')),
                'ccom.unh.edu', self)
            # noinspection PyUnresolvedReferences
            self.ccom_action.triggered.connect(self.load_ccom_unh_edu)
            self.toolbar.addAction(self.ccom_action)

        # unh.edu
        self.unh_action = None
        if with_unh_link:
            self.unh_action = QtWidgets.QAction(
                QtGui.QIcon(os.path.join(self.media, 'unh.png')), 'unh.edu',
                self)
            # noinspection PyUnresolvedReferences
            self.unh_action.triggered.connect(self.load_unh_edu)
            self.toolbar.addAction(self.unh_action)

        # http://www.ausseabed.gov.au/
        self.ausseabed_action = None
        if with_ausseabed_link:
            self.ausseabed_action = QtWidgets.QAction(
                QtGui.QIcon(os.path.join(self.media, 'ausseabed.png')),
                'ausseabed.gov.au', self)
            # noinspection PyUnresolvedReferences
            self.ausseabed_action.triggered.connect(self.load_ausseabed_gov_au)
            self.toolbar.addAction(self.ausseabed_action)

        self.toolbar.addSeparator()

        self.noaa_support_action = None
        if with_noaa_57:
            # noaa support
            self.toolbar.addSeparator()
            self.noaa_support_action = QtWidgets.QAction(
                QtGui.QIcon(os.path.join(self.media, 'noaa_support.png')),
                'NOAA S57 Support Files', self)
            # noinspection PyUnresolvedReferences
            self.noaa_support_action.triggered.connect(self.show_noaa_support)
            self.toolbar.addAction(self.noaa_support_action)

        self.toolbar.addSeparator()

        # license
        self.license_action = None
        if with_license:
            self.license_action = QtWidgets.QAction(
                QtGui.QIcon(os.path.join(self.media, 'license.png')),
                'License', self)
            self.license_action.setStatusTip('License info')
            # noinspection PyUnresolvedReferences
            self.license_action.triggered.connect(self.load_license)
            self.toolbar.addAction(self.license_action)

        # authors
        self.authors_dialog = None
        self.authors_action = QtWidgets.QAction(
            QtGui.QIcon(os.path.join(self.media, 'authors.png')), 'Contacts',
            self)
        self.authors_action.setStatusTip('Contact Authors')
        # noinspection PyUnresolvedReferences
        self.authors_action.triggered.connect(self.show_authors)
        self.toolbar.addAction(self.authors_action)

        # about
        self.show_about_action = QtWidgets.QAction(
            QtGui.QIcon(self._ai.app_icon_path), 'About', self)
        self.show_about_action.setStatusTip('Info about %s' %
                                            app_info.app_name)
        # noinspection PyUnresolvedReferences
        self.show_about_action.triggered.connect(self.about_dlg.switch_visible)
        self.toolbar.addAction(self.show_about_action)
Ejemplo n.º 25
0
 def show_noaa_support(self):
     self.change_url(Helper(lib_info=self._li).web_url("noaa_support"))
     noaa_s57 = NOAAS57Dialog(lib_info=self._li, app_info=self._ai)
     noaa_s57.exec_()
Ejemplo n.º 26
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)
Ejemplo n.º 27
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 [
                3,
        ]:
            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 == 3:

                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)
Ejemplo n.º 28
0
    def _click_find_fliers(self, version):
        """abstract the find fliers calling mechanism"""

        # sanity checks
        # - version
        if not isinstance(version, int):
            raise RuntimeError("passed invalid type for version: %s" %
                               type(version))
        if version not in [
                8,
        ]:
            raise RuntimeError("passed invalid Find Fliers version: %s" %
                               version)
        # - 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 version == 8:
            if self.set_height_ffv8.text() != "":
                height_mode = self.set_height_ffv8.text()
        else:
            raise RuntimeError("unknown Find Fliers' version: %s" % version)

        ck = "c"
        if self.set_check_laplacian_ffv8.isChecked():
            ck += "1"
        if self.set_check_curv_ffv8.isChecked():
            ck += "2"
        if self.set_check_adjacent_ffv8.isChecked():
            ck += "3"
        if self.set_check_slivers_ffv8.isChecked():
            ck += "4"
        if self.set_check_isolated_ffv8.isChecked():
            ck += "5"
        if self.set_check_edges_ffv8.isChecked():
            ck += "6"
        ck += "f"
        if self.set_filter_fff_ffv8.isChecked():
            ck += "1"
        if self.set_filter_designated_ffv8.isChecked():
            ck += "2"

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

        self._parse_user_height(version=version)

        grid_list = self.prj.grid_list

        # pre checks

        if version == 8:

            if self.set_filter_fff_ffv8.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
                    ret = QtWidgets.QMessageBox.warning(
                        self, "Find Fliers v8 filters", msg,
                        QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
                    if ret == QtWidgets.QMessageBox.No:
                        return

            if self.set_filter_designated_ffv8.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
                    ret = QtWidgets.QMessageBox.warning(
                        self, "Find Fliers v8 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
            if version in [
                    8,
            ]:
                self._find_fliers(grid_file=grid_file,
                                  version=version,
                                  idx=(i + 1),
                                  total=len(grid_list))

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

            # 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
        QtWidgets.QMessageBox.information(self, "Find fliers v%d" % version,
                                          msg, QtWidgets.QMessageBox.Ok)
Ejemplo n.º 29
0
    def click_valsou_check_v8(self):
        # - 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")

        version = 8
        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,PyArgumentList
                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)

                self._valsou_check_v8(grid_file=grid_file, version=version, idx=idx, total=total)

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

                # de-confliction
                if self.set_overlap_fsv8.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()
                    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)
Ejemplo n.º 30
0
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)

        logger.info("current configuration:\n%s" %
                    Helper(lib_info=lib_info).package_info())

        # set the application name
        self.name = app_info.app_name
        self.version = app_info.app_version
        self.setWindowTitle('%s v.%s' % (self.name, self.version))
        self.setMinimumSize(QtCore.QSize(500, 500))
        self.resize(QtCore.QSize(920, 840))

        # noinspection PyArgumentList
        _app = QtCore.QCoreApplication.instance()
        _app.setApplicationName('%s' % self.name)
        _app.setOrganizationName("HydrOffice")
        _app.setOrganizationDomain("hydroffice.org")

        # set icons
        icon_info = QtCore.QFileInfo(app_info.app_icon_path)
        self.setWindowIcon(QtGui.QIcon(icon_info.absoluteFilePath()))
        if Helper.is_windows():

            try:
                # This is needed to display the app icon on the taskbar on Windows 7
                import ctypes
                app_id = '%s v.%s' % (self.name, self.version)
                ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(
                    app_id)

            except AttributeError as e:
                logger.debug("Unable to change app icon: %s" % e)

        # make tabs
        self.tabs = QtWidgets.QTabWidget()
        self.setCentralWidget(self.tabs)
        self.tabs.setIconSize(QtCore.QSize(52, 52))
        # qaqc tab
        self.tab_qax = QAXWidget(main_win=self)
        # noinspection PyArgumentList
        idx = self.tabs.insertTab(0, self.tab_qax,
                                  QtGui.QIcon(app_info.app_icon_path), "")
        self.tabs.setTabToolTip(idx, "QAX")
        # info
        self.tab_info = InfoTab(lib_info=lib_info,
                                app_info=app_info,
                                with_online_manual=True,
                                with_offline_manual=True,
                                with_bug_report=True,
                                with_hydroffice_link=True,
                                with_ccom_link=True,
                                with_noaa_link=True,
                                with_unh_link=False,
                                with_license=True,
                                with_noaa_57=True,
                                with_ausseabed_link=True,
                                main_win=self)
        # noinspection PyArgumentList
        idx = self.tabs.insertTab(
            1, self.tab_info, QtGui.QIcon(os.path.join(self.media,
                                                       'info.png')), "")
        self.tabs.setTabToolTip(idx, "Info")

        # init default settings
        settings = QtCore.QSettings()
        start_tab = settings.value("start_tab")
        if (start_tab is None) or (start_tab > 0):
            start_tab = 0
            settings.setValue("start_tab", start_tab)
        self.tabs.setCurrentIndex(start_tab)

        self.statusBar().setStyleSheet(
            "QStatusBar{color:rgba(0,0,0,128);font-size: 8pt;}")
        self.status_bar_normal_style = self.statusBar().styleSheet()
        self.statusBar().showMessage("%s" % app_info.app_version, 2000)
        timer = QtCore.QTimer(self)
        # noinspection PyUnresolvedReferences
        timer.timeout.connect(self.update_gui)
        # noinspection PyArgumentList
        timer.start(300000)  # 5 mins
        self.update_gui()