def set_completer_object(dialog, table_object):
    """ Set autocomplete of widget @table_object + "_id"
        getting id's from selected @table_object
    """

    widget = qt_tools.getWidget(dialog, table_object + "_id")
    if not widget:
        return

    # Set SQL
    field_object_id = "id"
    if table_object == "element":
        field_object_id = table_object + "_id"
    sql = (f"SELECT DISTINCT({field_object_id})" f" FROM {table_object}")
    rows = global_vars.controller.get_rows(sql)
    if rows is None:
        return

    for i in range(0, len(rows)):
        aux = rows[i]
        rows[i] = str(aux[0])

    # Set completer and model: add autocomplete in the widget
    completer = QCompleter()
    completer.setCaseSensitivity(Qt.CaseInsensitive)
    widget.setCompleter(completer)
    model = QStringListModel()
    model.setStringList(rows)
    completer.setModel(model)
 def setCompleter(self, values, wgt):
     completer = QCompleter(self)
     completerModel = QStringListModel(self)
     wgt.setCompleter(completer)
     completer.setModel(completerModel)
     completer.setCaseSensitivity(False)
     completerModel.setStringList(values)
Example #3
0
    def setupCompleter(self):
        # set up string list for completer

        TOMsMessageLog.logMessage("In setupCompleter:", level=Qgis.Info)
        lookupStringSet = set()
        # https://gis.stackexchange.com/questions/155805/qstringlist-error-in-plugin-of-qgis-2-10

        self.GazetteerLayer = QgsProject.instance().mapLayersByName("StreetGazetteerRecords")[0]

        for row in self.GazetteerLayer.getFeatures():
            streetName = row.attribute("Descriptor_")
            locality = row.attribute("Locality")
            nameString = streetName
            if locality:
                nameString = nameString + ", " + locality

            if nameString:
                TOMsMessageLog.logMessage("In setupCompleter: nameString: " + nameString, level=Qgis.Info)
                lookupStringSet.add(nameString)
                # self.gazetteerStringList.append((nameString))

        completer = QCompleter()
        completer.setCaseSensitivity(Qt.CaseInsensitive)
        completer.setFilterMode(Qt.MatchContains)
        self.searchTextbox.setCompleter(completer)
        model = QStringListModel()
        completer.setModel(model)
        model.setStringList(self.gazetteerStringList)
        model.setStringList(sorted(lookupStringSet))
Example #4
0
    def _set_completer(self):
        """ Set autocompleters of the form """

        # Adding auto-completion to a QLineEdit - visit_id
        completer = QCompleter()
        self.dlg_work.arc_id.setCompleter(completer)
        model = QStringListModel()

        model.setStringList(self.selected_list)
        completer.setModel(model)
Example #5
0
def set_completer_lineedit(qlineedit, list_items):
    """ Set a completer into a QLineEdit
    :param qlineedit: Object where to set the completer (QLineEdit)
    :param list_items: List of items to set into the completer (List)["item1","item2","..."]
    """

    completer = QCompleter()
    completer.setCaseSensitivity(Qt.CaseInsensitive)
    completer.setMaxVisibleItems(10)
    completer.setCompletionMode(0)
    completer.setFilterMode(Qt.MatchContains)
    completer.popup().setStyleSheet("color: black;")
    qlineedit.setCompleter(completer)
    model = QStringListModel()
    model.setStringList(list_items)
    completer.setModel(model)
def set_model_by_list(string_list, widget, proxy_model):
    """ Set the model according to the list """

    model = QStringListModel()
    model.setStringList(string_list)
    proxy_model.setSourceModel(model)
    proxy_model.setFilterKeyColumn(0)
    proxy_model_aux = QSortFilterProxyModel()
    proxy_model_aux.setSourceModel(model)
    proxy_model_aux.setFilterKeyColumn(0)
    widget.setModel(proxy_model_aux)
    widget.setModelColumn(0)
    completer = QCompleter()
    completer.setModel(proxy_model)
    completer.setCompletionColumn(0)
    completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
    widget.setCompleter(completer)
Example #7
0
class ExtendedComboBox(QComboBox):
    """Extended class of QComboBox so we can perform a filtering of items.
    """
    def __init__(self, parent=None):
        super(ExtendedComboBox, self).__init__(parent)

        self.setFocusPolicy(Qt.StrongFocus)
        self.setEditable(True)

        # add a filter model to filter matching items
        self.pFilterModel = QSortFilterProxyModel(self)
        self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.pFilterModel.setSourceModel(self.model())

        # add a completer, which uses the filter model
        self.completer = QCompleter(self.pFilterModel, self)
        # always show all (filtered) completions
        self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        self.setCompleter(self.completer)

        # connect signals
        self.lineEdit().textEdited[str].connect(
            self.pFilterModel.setFilterFixedString)
        self.completer.activated.connect(self.on_completer_activated)

    # on selection of an item from the completer,
    # select the corresponding item from combobox
    def on_completer_activated(self, text):
        if text:
            index = self.findText(text)
            self.setCurrentIndex(index)

    # on model change, update the models of the filter and completer as well
    def setModel(self, model):
        super(ExtendedComboBox, self).setModel(model)
        self.pFilterModel.setSourceModel(model)
        self.completer.setModel(self.pFilterModel)

    # on model column change, update the model column of
    # the filter and completer as well
    def setModelColumn(self, column):
        self.completer.setCompletionColumn(column)
        self.pFilterModel.setFilterKeyColumn(column)
        super(ExtendedComboBox, self).setModelColumn(column)
class FilteredComboBox(QComboBox):
    """Custom QComboBox with filtering option."""
    def __init__(self, parent=None):
        super(FilteredComboBox, self).__init__(parent)

        self.setFocusPolicy(Qt.StrongFocus)
        self.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLength)
        self.setEditable(True)
        self.filter_proxy_model = QSortFilterProxyModel(self)
        self.filter_proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.filter_proxy_model.setSortCaseSensitivity(Qt.CaseInsensitive)
        self.filter_proxy_model.setSourceModel(self.model())
        self.completer = QCompleter(self.filter_proxy_model, self)
        self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        self.setCompleter(self.completer)
        self.setMinimumSize(150, 25)
        self.setFont(QFont("Segoe UI", 10))
        self.setStyleSheet("QComboBox {background-color: white;}")
        self.setMaxVisibleItems(10)
        self.completer.activated.connect(self.on_completer_activated)
        self.lineEdit().textEdited.connect(
            self.filter_proxy_model.setFilterFixedString)

    def on_completer_activated(self, text):
        """Set active combobox item when a completer item is picked."""
        if not text:
            return
        idx = self.findText(text)
        self.setCurrentIndex(idx)
        self.activated[str].emit(self.itemText(idx))

    def setModel(self, model):
        """Set completer model after the combobox model."""
        super(FilteredComboBox, self).setModel(model)
        self.filter_proxy_model.setSourceModel(model)
        self.completer.setModel(self.filter_proxy_model)

    def setModelColumn(self, column_idx):
        """Set the correct column for completer and combobox model using column index."""
        self.completer.setCompletionColumn(column_idx)
        self.filter_proxy_model.setFilterKeyColumn(column_idx)
        super(FilteredComboBox, self).setModelColumn(column_idx)
def set_completer_rows(widget, rows):
    """ Set a completer into a widget
    :param widget: Object where to set the completer (QLineEdit)
    :param rows: rows to set into the completer (List)["item1","item2","..."]
    """

    if rows is None:
        return

    list_values = []
    for row in rows:
        list_values.append(str(row[0]))

    # Set completer and model: add autocomplete in the widget
    completer = QCompleter()
    completer.setCaseSensitivity(Qt.CaseInsensitive)
    widget.setCompleter(completer)
    model = QStringListModel()
    model.setStringList(list_values)
    completer.setModel(model)
def set_completer_feature_id(widget, geom_type, viewname):
    """ Set autocomplete of widget 'feature_id'
        getting id's from selected @viewname
    """

    if geom_type == '':
        return

    # Adding auto-completion to a QLineEdit
    completer = QCompleter()
    completer.setCaseSensitivity(Qt.CaseInsensitive)
    widget.setCompleter(completer)
    model = QStringListModel()

    sql = (f"SELECT {geom_type}_id" f" FROM {viewname}")
    row = global_vars.controller.get_rows(sql)
    if row:
        for i in range(0, len(row)):
            aux = row[i]
            row[i] = str(aux[0])

        model.setStringList(row)
        completer.setModel(model)
Example #11
0
 def finished(self, result):
     if result == True:
         self.dlg.layerconcepts.clear()
         self.dlg.comboBox.setCurrentIndex(0)
         self.maindlg.currentgraph = self.graph
         self.dlg.layercount.setText("[" + str(len(self.geoconcepts)) + "]")
         for geo in self.geoconcepts:
             self.dlg.layerconcepts.addItem(geo)
         comp = QCompleter(self.dlg.layerconcepts)
         comp.setCompletionMode(QCompleter.PopupCompletion)
         comp.setModel(self.dlg.layerconcepts.model())
         self.dlg.layerconcepts.setCompleter(comp)
         self.dlg.inp_sparql2.setPlainText(
             self.triplestoreconf[0]["querytemplate"][0]["query"].replace(
                 "%%concept%%", self.geoconcepts[0]))
         self.dlg.inp_sparql2.columnvars = {}
         self.maindlg.loadedfromfile = True
         self.maindlg.justloadingfromfile = False
         self.loadgraphdlg.close()
     else:
         msgBox = QMessageBox()
         msgBox.setText(self.exception)
         msgBox.exec()
     self.progress.close()
def set_completer_widget(tablename, widget, field_id):
    """ Set autocomplete of widget @table_object + "_id"
        getting id's from selected @table_object
    """

    if not widget:
        return

    # Set SQL
    sql = (f"SELECT DISTINCT({field_id})"
           f" FROM {tablename}"
           f" ORDER BY {field_id}")
    row = global_vars.controller.get_rows(sql)
    for i in range(0, len(row)):
        aux = row[i]
        row[i] = str(aux[0])

    # Set completer and model: add autocomplete in the widget
    completer = QCompleter()
    completer.setCaseSensitivity(Qt.CaseInsensitive)
    widget.setCompleter(completer)
    model = QStringListModel()
    model.setStringList(row)
    completer.setModel(model)
Example #13
0
class ExtendedCombobox(QComboBox):
    """
    Overwrite combobox to provide text filtering of
    combobox list.
    """

    def __init__(self, parent):
        """
        Initialise  ExtendedCombobox

        :param parent: Parent of combobox
        :type parent: PyQt5.QtWidgets.QWidget
        """

        super().__init__(parent)

        self.setFocusPolicy(Qt.StrongFocus)
        self.setEditable(True)
        self.completer = QCompleter(self)

        # always show all completions
        self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        self.p_filter_model = QSortFilterProxyModel(self)
        self.p_filter_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.completer.setPopup(self.view())
        self.setCompleter(self.completer)
        self.lineEdit().textEdited.connect(self.p_filter_model.setFilterFixedString)
        self.completer.activated.connect(self.setTextIfCompleterIsClicked)

    def setModel(self, model):  # pylint:disable=invalid-name
        """
        Set the model to use the Filter model

        :param model: The model to be used by the combobox
        :type model: PyQt5.QtGui.QStandardItemModel
        """

        super().setModel(model)
        self.p_filter_model.setSourceModel(model)
        self.completer.setModel(self.p_filter_model)

    def setModelColumn(self, column):  # pylint:disable=invalid-name
        """
        :param model: The model to be used by the combobox
        :type model: PyQt5.QtGui.QStandardItemModel
        """

        self.completer.setCompletionColumn(column)
        self.p_filter_model.setFilterKeyColumn(column)
        super().setModelColumn(column)

    def view(self):
        """
        A QListView of items stored in the model

        :return: items stored in the model
        :rtype: PyQt5.QtWidgets.QListView
        """

        return self.completer.popup()

    def index(self):
        """
        Index of the current item in the combobox.

        :return: index of the current item
        :rtype: int
        """

        return self.currentIndex()

    def setTextIfCompleterIsClicked(self, text):  # pylint:disable=invalid-name
        """
        :param text: The current text of the qlineedit
        :type text: str

        If the combobx lineedit is clicked, set the lineedits
        current item as the combobox's current item
        """

        if text:
            index = self.findText(text)
            self.setCurrentIndex(index)
Example #14
0
class GwMincutTools:
    def __init__(self, mincut):

        self.mincut = mincut
        self.canvas = global_vars.canvas
        self.plugin_dir = global_vars.plugin_dir
        self.schema_name = global_vars.schema_name
        self.settings = global_vars.giswater_settings

    def set_dialog(self, dialog):
        self.dlg_mincut_man = dialog

    def get_mincut_manager(self):

        self.action = "manage_mincuts"

        # Create the dialog and signals
        tools_gw.load_settings(self.dlg_mincut_man)
        tools_gw.set_dates_from_to(self.dlg_mincut_man.date_from,
                                   self.dlg_mincut_man.date_to, 'om_mincut',
                                   'forecast_start, exec_start',
                                   'forecast_end, exec_end')
        self.dlg_mincut_man.date_from.setEnabled(False)
        self.dlg_mincut_man.date_to.setEnabled(False)
        tools_gw.add_icon(self.dlg_mincut_man.btn_selector_mincut, "191")

        self.tbl_mincut_edit = self.dlg_mincut_man.findChild(
            QTableView, "tbl_mincut_edit")
        self.txt_mincut_id = self.dlg_mincut_man.findChild(
            QLineEdit, "txt_mincut_id")
        tools_qt.set_tableview_config(self.tbl_mincut_edit)

        # Adding auto-completion to a QLineEdit
        self.completer = QCompleter()
        self.txt_mincut_id.setCompleter(self.completer)
        model = QStringListModel()

        sql = "SELECT DISTINCT(id) FROM om_mincut WHERE id > 0 "
        rows = tools_db.get_rows(sql)
        values = []
        if rows:
            for row in rows:
                values.append(str(row[0]))

        model.setStringList(values)
        self.completer.setModel(model)
        self.txt_mincut_id.textChanged.connect(
            partial(self._filter_by_id, self.tbl_mincut_edit))
        self.dlg_mincut_man.date_from.dateChanged.connect(
            partial(self._filter_by_id, self.tbl_mincut_edit))
        self.dlg_mincut_man.date_to.dateChanged.connect(
            partial(self._filter_by_id, self.tbl_mincut_edit))
        self.dlg_mincut_man.cmb_expl.currentIndexChanged.connect(
            partial(self._filter_by_id, self.tbl_mincut_edit))
        self.dlg_mincut_man.spn_next_days.setRange(-9999, 9999)
        self.dlg_mincut_man.btn_next_days.clicked.connect(self._filter_by_days)
        self.dlg_mincut_man.spn_next_days.valueChanged.connect(
            self._filter_by_days)
        self.dlg_mincut_man.btn_cancel_mincut.clicked.connect(
            self._set_state_cancel_mincut)
        self.dlg_mincut_man.tbl_mincut_edit.doubleClicked.connect(
            partial(self._open_mincut))
        self.dlg_mincut_man.btn_cancel.clicked.connect(
            partial(tools_gw.close_dialog, self.dlg_mincut_man))
        self.dlg_mincut_man.rejected.connect(
            partial(tools_gw.close_dialog, self.dlg_mincut_man))
        self.dlg_mincut_man.btn_delete.clicked.connect(
            partial(self._delete_mincut_management, self.tbl_mincut_edit,
                    "om_mincut", "id"))
        self.dlg_mincut_man.btn_selector_mincut.clicked.connect(
            partial(self._mincut_selector, self.tbl_mincut_edit, 'id'))

        self._populate_combos()
        self.dlg_mincut_man.state_edit.activated.connect(
            partial(self._filter_by_id, self.tbl_mincut_edit))

        # Set a model with selected filter. Attach that model to selected table
        self._fill_table_mincut_management(self.tbl_mincut_edit,
                                           self.schema_name + ".v_ui_mincut")
        tools_gw.set_tablemodel_config(self.dlg_mincut_man,
                                       self.tbl_mincut_edit,
                                       "v_ui_mincut",
                                       sort_order=1)

        # self.mincut.tools_gw.set_tablemodel_config(self.tbl_mincut_edit, "v_ui_mincut")

        # Open the dialog
        tools_gw.open_dialog(self.dlg_mincut_man, dlg_name='mincut_manager')

    # region private functions

    def _set_state_cancel_mincut(self):

        selected_list = self.tbl_mincut_edit.selectionModel().selectedRows()
        if len(selected_list) == 0:
            message = "Any record selected"
            tools_qgis.show_warning(message)
            return
        inf_text = ""
        list_id = ""
        for i in range(0, len(selected_list)):
            row = selected_list[i].row()
            id_ = self.tbl_mincut_edit.model().record(row).value("id")
            inf_text += f"{id_}, "
            list_id += f"'{id_}', "
        inf_text = inf_text[:-2]
        list_id = list_id[:-2]
        message = "Are you sure you want to cancel these mincuts?"
        title = "Cancel mincuts"
        answer = tools_qt.show_question(message, title, inf_text)
        if answer:
            sql = (f"UPDATE om_mincut SET mincut_state = 3 "
                   f" WHERE id::text IN ({list_id})")
            tools_db.execute_sql(sql, log_sql=False)
            self.tbl_mincut_edit.model().select()

    def _mincut_selector(self, qtable, field_id):
        """ Manage mincut selector """

        model = qtable.model()
        selected_mincuts = []
        for x in range(0, model.rowCount()):
            i = int(model.fieldIndex(field_id))
            value = model.data(model.index(x, i))
            selected_mincuts.append(value)

        if len(selected_mincuts) == 0:
            msg = "There are no visible mincuts in the table. Try a different filter or make one"
            tools_qgis.show_message(msg)
            return
        selector_values = f'"selector_mincut", "ids":{selected_mincuts}'
        mincut_selector = GwSelector()

        self.dlg_selector = GwSelectorUi()
        tools_gw.load_settings(self.dlg_selector)
        current_tab = tools_gw.get_config_parser('dialogs_tab',
                                                 "dlg_selector_mincut", "user",
                                                 "session")
        self.dlg_selector.btn_close.clicked.connect(
            partial(tools_gw.close_dialog, self.dlg_selector))
        self.dlg_selector.rejected.connect(
            partial(tools_gw.save_settings, self.dlg_selector))
        self.dlg_selector.rejected.connect(
            partial(tools_gw.save_current_tab, self.dlg_selector,
                    self.dlg_selector.main_tab, 'mincut'))

        selector_vars = {}
        mincut_selector.get_selector(self.dlg_selector,
                                     selector_values,
                                     current_tab=current_tab,
                                     selector_vars=selector_vars)

        tools_gw.open_dialog(self.dlg_selector, dlg_name='selector')

    def _populate_combos(self):

        # Fill ComboBox state
        sql = ("SELECT id, idval "
               "FROM om_typevalue WHERE typevalue = 'mincut_state' "
               "ORDER BY id")
        rows = tools_db.get_rows(sql, add_empty_row=True)
        tools_qt.fill_combo_values(self.dlg_mincut_man.state_edit, rows, 1)

        # Fill ComboBox exploitation
        sql = "SELECT expl_id, name FROM exploitation WHERE expl_id > 0 ORDER BY name"
        rows = tools_db.get_rows(sql, add_empty_row=True)
        tools_qt.fill_combo_values(self.dlg_mincut_man.cmb_expl, rows, 1)

    def _open_mincut(self):
        """ Open mincut form with selected record of the table """

        dlg_mincut = GwMincutUi()
        selected_list = self.tbl_mincut_edit.selectionModel().selectedRows()
        if len(selected_list) == 0:
            message = "Any record selected"
            tools_qgis.show_warning(message)
            return

        row = selected_list[0].row()

        # Get mincut_id from selected row
        result_mincut_id = self.tbl_mincut_edit.model().record(row).value("id")

        # Close this dialog and open selected mincut
        keep_open_form = tools_gw.get_config_parser('dialogs_actions',
                                                    'mincut_manager_keep_open',
                                                    "user",
                                                    "init",
                                                    prefix=True)
        if tools_os.set_boolean(keep_open_form, False) is not True:
            tools_gw.close_dialog(self.dlg_mincut_man)
        self.mincut.is_new = False
        self.mincut.set_dialog(dlg_mincut)
        self.mincut.init_mincut_form()
        self.mincut.load_mincut(result_mincut_id)
        self.mincut.manage_docker()
        self.mincut.set_visible_mincut_layers(True)

    def _filter_by_days(self):

        date_from = datetime.datetime.now()
        days_added = self.dlg_mincut_man.spn_next_days.text()
        date_to = datetime.datetime.now()
        date_to += datetime.timedelta(days=int(days_added))

        # If the date_to is less than the date_from, you have to exchange them or the interval will not work
        if date_to < date_from:
            aux = date_from
            date_from = date_to
            date_to = aux

        format_low = '%Y-%m-%d 00:00:00.000'
        format_high = '%Y-%m-%d 23:59:59.999'
        interval = f"'{date_from.strftime(format_low)}'::timestamp AND '{date_to.strftime(format_high)}'::timestamp"

        expr = f"(forecast_start BETWEEN {interval})"
        self.tbl_mincut_edit.model().setFilter(expr)
        self.tbl_mincut_edit.model().select()

    def _filter_by_id(self, qtable):

        expr = ""
        id_ = tools_qt.get_text(self.dlg_mincut_man,
                                self.dlg_mincut_man.txt_mincut_id, False,
                                False)
        state_id = tools_qt.get_combo_value(self.dlg_mincut_man,
                                            self.dlg_mincut_man.state_edit, 0)
        state_text = tools_qt.get_combo_value(self.dlg_mincut_man,
                                              self.dlg_mincut_man.state_edit,
                                              1)
        expl = tools_qt.get_combo_value(self.dlg_mincut_man,
                                        self.dlg_mincut_man.cmb_expl, 1)
        dates_filter = ""
        if state_id == '':
            self.dlg_mincut_man.date_from.setEnabled(False)
            self.dlg_mincut_man.date_to.setEnabled(False)
        else:
            self.dlg_mincut_man.date_from.setEnabled(True)
            self.dlg_mincut_man.date_to.setEnabled(True)

            # Get selected dates
            visit_start = self.dlg_mincut_man.date_from.date()
            visit_end = self.dlg_mincut_man.date_to.date()
            date_from = visit_start.toString('yyyyMMdd 00:00:00')
            date_to = visit_end.toString('yyyyMMdd 23:59:59')
            if date_from > date_to:
                message = "Selected date interval is not valid"
                tools_qgis.show_warning(message)
                return

            # Create interval dates
            format_low = 'yyyy-MM-dd 00:00:00.000'
            format_high = 'yyyy-MM-dd 23:59:59.999'
            interval = f"'{visit_start.toString(format_low)}'::timestamp AND '{visit_end.toString(format_high)}'::timestamp"
            if str(state_id) == '0':
                tools_qt.set_widget_text(self.dlg_mincut_man,
                                         self.dlg_mincut_man.lbl_date_from,
                                         'Date from: forecast_start')
                tools_qt.set_widget_text(self.dlg_mincut_man,
                                         self.dlg_mincut_man.lbl_date_to,
                                         'Date to: forecast_end')
                dates_filter = f"AND (forecast_start BETWEEN {interval}) AND (forecast_end BETWEEN {interval})"
            elif str(state_id) == '3':
                tools_qt.set_widget_text(self.dlg_mincut_man,
                                         self.dlg_mincut_man.lbl_date_from,
                                         'Date from: received_date')
                tools_qt.set_widget_text(self.dlg_mincut_man,
                                         self.dlg_mincut_man.lbl_date_to,
                                         'Date to: received_date')
                dates_filter = f"AND received_date BETWEEN {interval}"
            elif str(state_id) in ('1', '2'):
                tools_qt.set_widget_text(self.dlg_mincut_man,
                                         self.dlg_mincut_man.lbl_date_from,
                                         'Date from: exec_start')
                tools_qt.set_widget_text(self.dlg_mincut_man,
                                         self.dlg_mincut_man.lbl_date_to,
                                         'Date to: exec_end')
                dates_filter = f"AND (exec_start BETWEEN {interval}) AND (exec_end BETWEEN {interval})"
            else:
                tools_qt.set_widget_text(self.dlg_mincut_man,
                                         self.dlg_mincut_man.lbl_date_from,
                                         'Date from:')
                tools_qt.set_widget_text(self.dlg_mincut_man,
                                         self.dlg_mincut_man.lbl_date_to,
                                         'Date to:')

        expr += f" (id::text ILIKE '%{id_}%'"
        expr += f" OR work_order::text ILIKE '%{id_}%')"
        expr += f" {dates_filter}"
        if state_text != '':
            expr += f" AND state::text ILIKE '%{state_text}%' "
        expr += f" AND (exploitation::text ILIKE '%{expl}%' OR exploitation IS null)"

        # Refresh model with selected filter
        qtable.model().setFilter(expr)
        qtable.model().select()

    def _fill_table_mincut_management(self, widget, table_name):
        """ Set a model with selected filter. Attach that model to selected table """

        if self.schema_name not in table_name:
            table_name = self.schema_name + "." + table_name

        # Set model
        model = QSqlTableModel(db=global_vars.qgis_db_credentials)
        model.setTable(table_name)
        model.setEditStrategy(QSqlTableModel.OnManualSubmit)
        model.sort(0, 1)
        model.select()

        # Check for errors
        if model.lastError().isValid():
            tools_qgis.show_warning(model.lastError().text())

        # Attach model to table view
        widget.setModel(model)

    def _delete_mincut_management(self, widget, table_name, column_id):
        """ Delete selected elements of the table (by id) """

        # Get selected rows
        selected_list = widget.selectionModel().selectedRows()
        if len(selected_list) == 0:
            message = "Any record selected"
            tools_qgis.show_warning(message)
            return

        inf_text = ""
        list_id = ""
        for i in range(0, len(selected_list)):
            row = selected_list[i].row()
            id_ = widget.model().record(row).value(str(column_id))
            inf_text += f"{id_}, "
            list_id += f"'{id_}', "
        inf_text = inf_text[:-2]
        list_id = list_id[:-2]
        message = "Are you sure you want to delete these mincuts?"
        title = "Delete mincut"
        answer = tools_qt.show_question(message, title, inf_text)
        if answer:
            sql = (f"DELETE FROM {table_name}"
                   f" WHERE {column_id} IN ({list_id})")
            tools_db.execute_sql(sql)
            widget.model().select()
            layer = tools_qgis.get_layer_by_tablename('v_om_mincut_node')
            if layer is not None:
                layer.triggerRepaint()
            layer = tools_qgis.get_layer_by_tablename('v_om_mincut_connec')
            if layer is not None:
                layer.triggerRepaint()
            layer = tools_qgis.get_layer_by_tablename('v_om_mincut_arc')
            if layer is not None:
                layer.triggerRepaint()
            layer = tools_qgis.get_layer_by_tablename('v_om_mincut_valve')
            if layer is not None:
                layer.triggerRepaint()
            layer = tools_qgis.get_layer_by_tablename('v_om_mincut')
            if layer is not None:
                layer.triggerRepaint()
            layer = tools_qgis.get_layer_by_tablename('v_om_mincut_hydrometer')
            if layer is not None:
                layer.triggerRepaint()
class TmManageVisit(TmParentManage, QObject):

    # event emitted when a new Visit is added when GUI is closed/accepted
    visit_added = pyqtSignal(int)

    def __init__(self, iface, settings, controller, plugin_dir):
        """ Class to control 'Add visit' of toolbar 'edit' """

        QObject.__init__(self)
        TmParentManage.__init__(self, iface, settings, controller, plugin_dir)

    def manage_visit(self,
                     visit_id=None,
                     geom_type=None,
                     feature_id=None,
                     single_tool=True,
                     expl_id=None):
        """ Button 64. Add visit.
        if visit_id => load record related to the visit_id
        if geom_type => lock geom_type in relations tab
        if feature_id => load related feature basing on geom_type in relation
        if single_tool notify that the tool is used called from another dialog.
        """

        # parameter to set if the dialog is working as single tool or integrated in another tool
        self.single_tool_mode = single_tool

        # turnoff autocommit of this and base class. Commit will be done at dialog button box level management
        self.autocommit = True
        # bool to distinguish if we entered to edit an existing Visit or creating a new one
        self.it_is_new_visit = (not visit_id)

        # set vars to manage if GUI have to lock the relation
        self.locked_geom_type = geom_type
        self.locked_feature_id = feature_id

        # Create the dialog and signals and related ORM Visit class
        self.current_visit = OmVisit(self.controller)
        self.dlg_add_visit = AddVisitTm()
        self.load_settings(self.dlg_add_visit)

        # Get expl_id from previous dialog
        self.expl_id = expl_id

        # Get layers of every geom_type
        self.reset_lists()
        self.reset_layers()

        self.layers['node'] = self.controller.get_group_layers('node')
        self.visible_layers = self.get_visible_layers()
        self.remove_selection()

        # Reset geometry
        self.x = None
        self.y = None

        # Set icons
        self.set_icon(self.dlg_add_visit.btn_feature_insert, "111")
        self.set_icon(self.dlg_add_visit.btn_feature_delete, "112")
        self.set_icon(self.dlg_add_visit.btn_feature_snapping, "137")
        self.set_icon(self.dlg_add_visit.btn_add_geom, "133")

        # tab events
        self.tabs = self.dlg_add_visit.findChild(QTabWidget, 'tab_widget')
        self.button_box = self.dlg_add_visit.findChild(QDialogButtonBox,
                                                       'button_box')
        self.button_box.button(QDialogButtonBox.Ok).setEnabled(False)

        # Tab 'Data'/'Visit'
        self.visit_id = self.dlg_add_visit.findChild(QLineEdit, "visit_id")
        self.user_name = self.dlg_add_visit.findChild(QLineEdit, "user_name")
        self.ext_code = self.dlg_add_visit.findChild(QLineEdit, "ext_code")
        self.visitcat_id = self.dlg_add_visit.findChild(
            QComboBox, "visitcat_id")

        # Tab 'Relations'
        self.feature_type = self.dlg_add_visit.findChild(
            QComboBox, "feature_type")
        self.feature_id = self.dlg_add_visit.findChild(QLineEdit, "feature_id")
        self.tbl_relation = self.dlg_add_visit.findChild(
            QTableView, "tbl_relation")
        self.tbl_relation.setSelectionBehavior(QAbstractItemView.SelectRows)
        # TODO controlar este combo
        self.feature_type.setVisible(False)

        # tab 'Event'
        self.tbl_event = self.dlg_add_visit.findChild(QTableView, "tbl_event")
        self.parameter_type_id = self.dlg_add_visit.findChild(
            QComboBox, "parameter_type_id")
        self.parameter_id = self.dlg_add_visit.findChild(
            QComboBox, "parameter_id")
        self.tbl_event.setSelectionBehavior(QAbstractItemView.SelectRows)

        # Set current date and time
        current_date = QDate.currentDate()
        self.dlg_add_visit.startdate.setDate(current_date)
        self.dlg_add_visit.enddate.setDate(current_date)

        # set User name get from controller login
        if self.controller.user and self.user_name:
            self.user_name.setText(str(self.controller.user))

        # set the start tab to be shown (e.g. VisitTab)
        self.current_tab_index = self.tab_index('VisitTab')
        self.tabs.setCurrentIndex(self.current_tab_index)

        # Set signals
        self.dlg_add_visit.rejected.connect(
            partial(self.close_dialog, self.dlg_add_visit))
        self.dlg_add_visit.rejected.connect(self.manage_rejected)
        self.dlg_add_visit.accepted.connect(self.manage_accepted)
        self.dlg_add_visit.btn_event_insert.clicked.connect(self.event_insert)
        self.dlg_add_visit.btn_event_delete.clicked.connect(self.event_delete)
        self.dlg_add_visit.btn_event_update.clicked.connect(self.event_update)
        self.dlg_add_visit.btn_feature_insert.clicked.connect(
            partial(self.insert_feature, self.feature_id, self.tbl_relation))
        self.dlg_add_visit.btn_feature_delete.clicked.connect(
            partial(self.delete_records, self.dlg_add_visit,
                    self.tbl_relation))
        self.dlg_add_visit.btn_feature_snapping.clicked.connect(
            partial(self.selection_init, self.tbl_relation))
        self.tabs.currentChanged.connect(partial(self.manage_tab_changed))
        self.visit_id.textChanged.connect(self.manage_visit_id_change)
        self.dlg_add_visit.btn_add_geom.clicked.connect(self.add_point)

        # self.event_feature_type_selected()

        # Fill combo boxes of the form and related events
        self.feature_type.currentIndexChanged.connect(
            partial(self.event_feature_type_selected))
        self.parameter_type_id.currentIndexChanged.connect(
            partial(self.set_parameter_id_combo))
        self.fill_combos()
        sql = (
            "SELECT value FROM config_param_user "
            " WHERE parameter = 'visitcat_id' AND cur_user = current_user AND context='arbrat'"
        )
        row = self.controller.get_row(sql)
        if row:
            utils_giswater.set_combo_itemData(self.visitcat_id,
                                              str(row['value']), 1)
        self.set_combos(self.dlg_add_visit,
                        self.dlg_add_visit.parameter_type_id,
                        'parameter_type_id')
        self.set_combos(self.dlg_add_visit, self.dlg_add_visit.parameter_id,
                        'parameter_id')
        # Set autocompleters of the form
        self.set_completers(self.dlg_add_visit.visit_id, 'om_visit')

        # Show id of visit. If not set, infer a new value
        if not visit_id:
            visit_id = self.current_visit.max_pk(commit=self.autocommit) + 1
        self.visit_id.setText(str(visit_id))

        # manage relation locking
        if self.locked_geom_type:
            self.set_locked_relation()
        # Open the dialog
        self.open_dialog(self.dlg_add_visit, dlg_name="add_visit")

    def set_combos(self, dialog, qcombo, parameter):

        sql = (
            f"SELECT value FROM config_param_user "
            f" WHERE parameter = '{parameter}' AND cur_user= current_user AND context='arbrat'"
        )
        row = self.controller.get_row(sql)
        if row:
            utils_giswater.setWidgetText(dialog, qcombo, str(row['value']))

    def manage_accepted(self):
        """ Do all action when closed the dialog with Ok.
        e.g. all necessary commits and cleanings.
        A) Trigger SELECT gw_fct_om_visit_multiplier (visit_id, feature_type)
        for multiple visits management.
        """

        # notify that a new visit has been added
        self.visit_added.emit(self.current_visit.id)

        # Update geometry field (if user have selected a point)
        if self.x:
            self.update_geom()
        self.refresh_map_canvas()
        self.canvas.setMapTool(self.previous_map_tool)
        #self.iface.actionPan().trigger()

    def update_geom(self):
        """ Update geometry field """

        srid = self.controller.plugin_settings_value('srid')
        sql = (
            f"UPDATE om_visit"
            f" SET the_geom = ST_SetSRID(ST_MakePoint({self.x},{self.y}), {srid})"
            f" WHERE id = {self.current_visit.id}")
        self.controller.execute_sql(sql, log_sql=True)

    def manage_rejected(self):
        """ Do all action when closed the dialog with Cancel or X.
        e.g. all necessary rollbacks and cleanings.
        """

        self.canvas.setMapTool(self.previous_map_tool)
        # removed current working visit. This should cascade removing of all related records
        if hasattr(self, 'it_is_new_visit') and self.it_is_new_visit:
            self.current_visit.delete()

        # Remove all previous selections
        self.remove_selection()

    def tab_index(self, tab_name):
        """ Get the index of a tab basing on objectName. """

        for idx in range(self.tabs.count()):
            if self.tabs.widget(idx).objectName() == tab_name:
                return idx
        return -1

    def manage_visit_id_change(self, text):
        """ manage action when the visit id is changed.
        A) Update current Visit record
        B) Fill the GUI values of the current visit
        C) load all related events in the relative table
        D) load all related documents in the relative table.
        """

        # A) Update current Visit record
        self.current_visit.id = int(text)
        exist = self.current_visit.fetch()
        if exist:
            # B) Fill the GUI values of the current visit
            self.fill_widget_with_fields(self.dlg_add_visit,
                                         self.current_visit,
                                         self.current_visit.field_names())

        # C) load all related events in the relative table
        self.filter = f"visit_id = '{text}'"
        table_name = self.schema_name + ".om_visit_event"
        self.fill_table_visit(self.tbl_event, table_name, self.filter)
        self.set_configuration(self.tbl_event, table_name)
        self.manage_events_changed()

        # # D) load all related documents in the relative table
        # table_name = self.schema_name + ".v_ui_doc_x_visit"
        # self.fill_table_visit(self.tbl_document, self.schema_name + ".v_ui_doc_x_visit", self.filter)
        # self.set_configuration(self.tbl_document, table_name)

        # E) load all related Relations in the relative table
        self.set_feature_type_by_visit_id()

    def set_feature_type_by_visit_id(self):
        """ Set the feature_type in Relation tab basing on visit_id.
        The steps to follow are:
        1) check geometry type looking what table contain records related with visit_id
        2) set gemetry type.
        """

        feature_type = None
        feature_type_index = None
        for index in range(self.feature_type.count()):
            # feture_type combobox is filled before the visit_id is changed
            # it will contain all the geometry type allows basing on project type
            geometry_type = self.feature_type.itemText(index).lower()
            table_name = 'om_visit_x_' + geometry_type
            sql = f"SELECT id FROM {table_name} WHERE visit_id = '{self.current_visit.id}'"
            rows = self.controller.get_rows(sql, commit=self.autocommit)
            if not rows or not rows[0]:
                continue

            feature_type = geometry_type
            feature_type_index = index
            break

        # if no related records found do nothing
        if not feature_type:
            return

        # set default combo box value = trigger model and selection
        # of related features
        if self.feature_type.currentIndex() != feature_type_index:
            self.feature_type.setCurrentIndex(feature_type_index)
        else:
            self.feature_type.currentIndexChanged.emit(feature_type_index)

    def manage_leave_visit_tab(self):
        """ manage all the action when leaving the VisitTab
        A) Manage sync between GUI values and Visit record in DB
        """

        # A) fill Visit basing on GUI values
        self.current_visit.id = int(self.visit_id.text())
        self.current_visit.startdate = self.dlg_add_visit.startdate.date(
        ).toString(Qt.ISODate)
        self.current_visit.enddate = self.dlg_add_visit.enddate.date(
        ).toString(Qt.ISODate)
        self.current_visit.user_name = self.user_name.text()
        self.current_visit.ext_code = self.ext_code.text()
        self.current_visit.visitcat_id = utils_giswater.get_item_data(
            self.dlg_add_visit, self.dlg_add_visit.visitcat_id, 0)
        self.current_visit.descript = self.dlg_add_visit.descript.text()
        if self.expl_id:
            self.current_visit.expl_id = self.expl_id

        # update or insert but without closing the transaction: autocommit=False
        self.current_visit.upsert(commit=self.autocommit)

    def update_relations(self):
        """ Save current selected features in tbl_relations. Steps are:
        A) remove all old relations related with current visit_id.
        B) save new relations get from that listed in tbl_relations.
        """

        # A) remove all old relations related with current visit_id.
        db_record = None
        for index in range(self.feature_type.count()):
            # feture_type combobox contain all the geometry type
            # allows basing on project type
            geometry_type = self.feature_type.itemText(index).lower()

            # TODO: the next "if" code can be substituded with something like:
            # exec("db_record = OmVisitX{}{}(self.controller)".format(geometry_type[0].upper(), geometry_type[1:]))"

            if geometry_type == 'node':
                db_record = OmVisitXNode(self.controller)

            # remove all actual saved records related with visit_id
            where_clause = "visit_id = '{}'".format(self.visit_id.text())
            db_record.delete(where_clause=where_clause, commit=self.autocommit)

        # do nothing if model is None or no element is present
        if not self.tbl_relation.model() or not self.tbl_relation.model(
        ).rowCount():
            return

        # set the current db_record tyope to do insert of new records
        # all the new records belong to the same geom_type
        # TODO: the next "if" code can be substituded with something like:
        # exec("db_record = OmVisitX{}{}(self.controller)".format(geometry_type[0].upper(), geometry_type[1:]))"
        if self.geom_type == 'node':
            db_record = OmVisitXNode(self.controller)

        # for each showed element of a specific geom_type create an db entry
        column_name = self.geom_type + "_id"
        for row in range(self.tbl_relation.model().rowCount()):
            # get modelIndex to get data
            index = self.tbl_relation.model().index(row, 0)

            # set common fields
            db_record.id = db_record.max_pk() + 1
            db_record.visit_id = int(self.visit_id.text())

            # set value for column <geom_type>_id
            setattr(db_record, column_name, index.data())

            # than save the showed records
            db_record.upsert(commit=self.autocommit)

    def manage_tab_changed(self, index):
        """ Do actions when tab is exit and entered. Actions depend on tab index """

        # manage leaving tab
        # tab Visit
        if self.current_tab_index == self.tab_index('VisitTab'):
            self.manage_leave_visit_tab()
            # need to create the relation record that is done only
            # changing tab
            if self.locked_geom_type:
                self.update_relations()

        # tab Relation
        if self.current_tab_index == self.tab_index('RelationsTab'):
            self.update_relations()

        # manage arriving tab

        # tab Visit
        self.current_tab_index = index
        if index == self.tab_index('VisitTab'):
            pass
        # tab Relation
        if index == self.tab_index('RelationsTab'):
            pass
        # tab Event
        if index == self.tab_index('EventTab'):
            pass
            # self.entered_event_tab()

    def entered_event_tab(self):
        """ Manage actions when the Event tab is entered """

        self.set_parameter_id_combo()

    def set_parameter_id_combo(self):
        """ Set parameter_id combo basing on current selections """

        sql = (
            f"SELECT id, descript"
            f" FROM om_visit_parameter"
            f" WHERE UPPER (parameter_type) = '{self.parameter_type_id.currentText().upper()}'"
            f" AND UPPER (feature_type) = '{self.feature_type.currentText().upper()}'"
            f" ORDER BY id")
        rows = self.controller.get_rows(sql, commit=self.autocommit)

        if rows:
            utils_giswater.set_item_data(self.dlg_add_visit.parameter_id, rows,
                                         1)

    def config_relation_table(self, qtable):
        """ Set all actions related to the table, model and selectionModel.
        It's necessary a centralised call because base class can create a None model
        where all callbacks are lost ance can't be registered
        """

        # configure model visibility
        table_name = "v_edit_" + self.geom_type
        self.set_configuration(qtable, table_name)

    def event_feature_type_selected(self):
        """ Manage selection change in feature_type combo box.
        THis means that have to set completer for feature_id QTextLine and
        setup model for features to select table.
        """

        # 1) set the model linked to selecte features
        # 2) check if there are features related to the current visit
        # 3) if so, select them => would appear in the table associated to the model
        self.geom_type = self.feature_type.currentText().lower()
        viewname = "v_edit_" + self.geom_type
        self.set_completer_feature_id(self.dlg_add_visit.feature_id,
                                      self.geom_type, viewname)

        # set table model and completer
        # set a fake where expression to avoid to set model to None
        fake_filter = f'{self.geom_type}_id IN ("-1")'
        self.set_table_model(self.tbl_relation, self.geom_type, fake_filter)

        # set the callback to setup all events later
        # its not possible to setup listener in this moment beacouse set_table_model without
        # a valid expression parameter return a None model => no events can be triggered
        self.lazy_configuration(self.tbl_relation, self.config_relation_table)

        # check if there are features related to the current visit
        if not self.visit_id.text():
            return

        table_name = 'om_visit_x_' + self.geom_type
        sql = f"SELECT {self.geom_type}_id FROM {table_name} WHERE visit_id = '{int(self.visit_id.text())}'"
        rows = self.controller.get_rows(sql, commit=self.autocommit)
        if not rows or not rows[0]:
            return
        ids = [x[0] for x in rows]

        # select list of related features
        # Set 'expr_filter' with features that are in the list
        expr_filter = f'"{self.geom_type}_id" IN ({",".join(ids)})'

        # Check expression
        (is_valid,
         expr) = self.check_expression(expr_filter)  # @UnusedVariable
        if not is_valid:
            return

        # do selection allowing the tbl_relation to be linked to canvas selectionChanged
        self.disconnect_signal_selection_changed()
        self.connect_signal_selection_changed(self.tbl_relation)
        self.select_features_by_ids(self.geom_type, expr)
        self.disconnect_signal_selection_changed()

    def fill_combos(self):
        """ Fill combo boxes of the form """

        # Visit tab
        # Fill ComboBox visitcat_id
        # save result in self.visitcat_ids to get id depending on selected combo
        sql = (
            "SELECT id, name FROM om_visit_cat"
            # " WHERE active is true"
            " ORDER BY name")
        self.visitcat_ids = self.controller.get_rows(sql,
                                                     commit=self.autocommit)

        if self.visitcat_ids:
            utils_giswater.set_item_data(self.dlg_add_visit.visitcat_id,
                                         self.visitcat_ids, 1)
            # now get default value to be show in visitcat_id
            sql = (
                "SELECT value FROM config_param_user"
                " WHERE parameter = 'visitcat_vdefault' AND cur_user = current_user"
            )
            row = self.controller.get_row(sql, commit=self.autocommit)
            if row:
                # if int then look for default row ans set it
                try:
                    utils_giswater.set_combo_itemData(
                        self.dlg_add_visit.visitcat_id, row[0], 0)
                    for i in range(0, self.dlg_add_visit.visitcat_id.count()):
                        elem = self.dlg_add_visit.visitcat_id.itemData(i)
                        if str(row[0]) == str(elem[0]):
                            utils_giswater.setWidgetText(
                                self.dlg_add_visit,
                                self.dlg_add_visit.visitcat_id, (elem[1]))
                except TypeError:
                    pass
                except ValueError:
                    pass

        # Relations tab
        rows = [['node']]
        utils_giswater.fillComboBox(self.dlg_add_visit,
                                    self.dlg_add_visit.feature_type,
                                    rows,
                                    allow_nulls=False)

        # Event tab
        # Fill ComboBox parameter_type_id
        sql = ("SELECT id FROM om_visit_parameter_type" " ORDER BY id")
        parameter_type_ids = self.controller.get_rows(sql,
                                                      commit=self.autocommit)
        utils_giswater.fillComboBox(self.dlg_add_visit,
                                    self.dlg_add_visit.parameter_type_id,
                                    parameter_type_ids,
                                    allow_nulls=False)

    def set_completers(self, widget, table_name):
        """ Set autocompleters of the form """

        # Adding auto-completion to a QLineEdit - visit_id
        self.completer = QCompleter()
        widget.setCompleter(self.completer)
        model = QStringListModel()

        sql = f"SELECT DISTINCT(id) FROM {table_name}"
        rows = self.controller.get_rows(sql, commit=self.autocommit)
        values = []
        if rows:
            for row in rows:
                values.append(str(row[0]))

        model.setStringList(values)
        self.completer.setModel(model)

    def fill_table_visit(self, widget, table_name, filter_):
        """ Set a model with selected filter. Attach that model to selected table """

        if self.schema_name not in table_name:
            table_name = self.schema_name + "." + table_name

        # Set model
        model = QSqlTableModel()
        model.setTable(table_name)
        model.setEditStrategy(QSqlTableModel.OnManualSubmit)
        model.setFilter(filter_)
        model.select()

        # Check for errors
        if model.lastError().isValid():
            self.controller.show_warning(model.lastError().text())

        # Attach model to table view
        widget.setModel(model)
        widget.show()

    def event_insert(self):
        """ Add and event basing on form associated to the selected parameter_id """

        # check a parameter_id is selected (can be that no value is available)
        parameter_id = utils_giswater.get_item_data(
            self.dlg_add_visit, self.dlg_add_visit.parameter_id, 0)
        if not parameter_id:
            message = "You need to select a valid parameter id"
            self.controller.show_info_box(message)
            return

        # get form associated
        sql = (f"SELECT form_type FROM om_visit_parameter"
               f" WHERE id = '{parameter_id}'")
        row = self.controller.get_row(sql, commit=False)
        form_type = str(row[0])

        if form_type == 'event_standard':
            self.dlg_event = EventStandardTm()
            self.load_settings(self.dlg_event)
        else:
            message = "Unrecognised form type"
            self.controller.show_info_box(message, parameter=form_type)
            return

        # because of multiple view disable add picture and view gallery
        self.dlg_event.btn_add_picture.setEnabled(False)
        self.dlg_event.btn_view_gallery.setEnabled(False)

        # set fixed values
        self.dlg_event.parameter_id.setText(parameter_id)

        self.dlg_event.setWindowFlags(Qt.WindowStaysOnTopHint)
        ret = self.dlg_event.exec_()

        # check return
        if not ret:
            # clicked cancel
            return

        # create an empty Event
        event = OmVisitEvent(self.controller)
        event.id = event.max_pk() + 1
        event.parameter_id = parameter_id
        event.visit_id = int(self.visit_id.text())

        for field_name in event.field_names():
            if not hasattr(self.dlg_event, field_name):
                continue
            value = getattr(self.dlg_event, field_name).text()
            if value:
                setattr(event, field_name, value)

        # save new event
        event.upsert()

        # update Table
        self.tbl_event.model().select()
        self.manage_events_changed()

    def manage_events_changed(self):
        """ Action when at a Event model is changed.
        A) if some record is available => enable OK button of VisitDialog
        """

        state = (self.tbl_event.model().rowCount() > 0)
        self.button_box.button(QDialogButtonBox.Ok).setEnabled(state)

    def event_update(self):
        """ Update selected event """

        if not self.tbl_event.selectionModel().hasSelection():
            message = "Any record selected"
            self.controller.show_info_box(message)
            return

        # Get selected rows
        # TODO: use tbl_event.model().fieldIndex(event.pk()) to be pk name independent
        # 0 is the column of the pk 0 'id'
        selected_list = self.tbl_event.selectionModel().selectedRows(0)
        if selected_list == 0:
            message = "Any record selected"
            self.controller.show_info_box(message)
            return

        elif len(selected_list) > 1:
            message = "More then one event selected. Select just one"
            self.controller.show_warning(message)
            return

        # fetch the record
        event = OmVisitEvent(self.controller)
        event.id = selected_list[0].data()
        if not event.fetch(commit=self.autocommit):
            return

        # get parameter_id code to select the widget useful to edit the event
        om_event_parameter = OmVisitParameter(self.controller)
        om_event_parameter.id = event.parameter_id
        if not om_event_parameter.fetch(commit=self.autocommit):
            return

        if om_event_parameter.form_type == 'event_standard':
            self.dlg_event_standard = EventStandardTm()
            self.load_settings(self.dlg_event_standard)

        # because of multiple view disable add picture and view gallery
        self.dlg_event_standard.btn_add_picture.setEnabled(False)
        self.dlg_event_standard.btn_view_gallery.setEnabled(False)

        # fill widget values if the values are present
        for field_name in event.field_names():
            if not hasattr(self.dlg_event, field_name):
                continue
            value = getattr(event, field_name)
            if value:
                getattr(self.dlg_event, field_name).setText(str(value))

        self.dlg_event_standard.setWindowFlags(Qt.WindowStaysOnTopHint)
        if self.dlg_event_standard.exec_():
            # set record values basing on widget
            for field_name in event.field_names():
                if not hasattr(self.dlg_event_standard, field_name):
                    continue
                value = getattr(self.dlg_event_standard, field_name).text()
                if value:
                    setattr(event, field_name, str(value))

            # update the record
            event.upsert(commit=self.autocommit)

        # update Table
        self.tbl_event.model().select()
        self.tbl_event.setModel(self.tbl_event.model())
        self.manage_events_changed()

    def event_delete(self):
        """ Delete a selected event """

        if not self.tbl_event.selectionModel().hasSelection():
            message = "Any record selected"
            self.controller.show_info_box(message)
            return

        # a fake event to get some ancyllary data
        event = OmVisitEvent(self.controller)

        # Get selected rows
        # TODO: use tbl_event.model().fieldIndex(event.pk()) to be pk name independent
        # 0 is the column of the pk 0 'id'
        selected_list = self.tbl_event.selectionModel().selectedRows(0)
        selected_id = []
        for index in selected_list:
            selected_id.append(str(index.data()))
        list_id = ','.join(selected_id)

        # ask for deletion
        message = "Are you sure you want to delete these records?"
        title = "Delete records"
        answer = self.controller.ask_question(message, title, list_id)
        if not answer:
            return

        # do the action
        if not event.delete(pks=selected_id, commit=self.autocommit):
            message = "Error deleting records"
            self.controller.show_warning(message)
            return

        message = "Records deleted"
        self.controller.show_info(message)

        # update Table
        self.tbl_event.model().select()
        self.manage_events_changed()

    def set_configuration(self, qtable, table_name):
        """ Configuration of tables. Set visibility and width of columns """

        if not qtable:
            return

        # Set width and alias of visible columns
        columns_to_delete = []
        sql = (f"SELECT column_index, width, alias, status"
               f" FROM config_client_forms"
               f" WHERE table_id = '{table_name}'"
               f" ORDER BY column_index")
        rows = self.controller.get_rows(sql,
                                        log_info=False,
                                        commit=self.autocommit)
        if not rows:
            return

        for row in rows:
            if not row['status']:
                columns_to_delete.append(row['column_index'] - 1)
            else:
                width = row['width']
                if width is None:
                    width = 100
                qtable.setColumnWidth(row['column_index'] - 1, width)
                qtable.model().setHeaderData(row['column_index'] - 1,
                                             Qt.Horizontal, row['alias'])

        # Set order
        qtable.model().setSort(0, Qt.AscendingOrder)
        qtable.model().select()

        # Delete columns
        for column in columns_to_delete:
            qtable.hideColumn(column)
Example #16
0
class GwMincutManager(ParentAction):
    def __init__(self, mincut):
        """ Class constructor """

        self.mincut = mincut
        self.canvas = mincut.canvas
        self.plugin_dir = mincut.plugin_dir
        self.controller = self.mincut.controller
        self.schema_name = self.controller.schema_name
        self.settings = self.mincut.settings
        self.api_parent = ApiParent(mincut.iface, self.settings,
                                    self.controller, self.plugin_dir)

    def mg_mincut_management(self):
        """ Button 27: Mincut management """

        self.action = "mg_mincut_management"

        # Create the dialog and signals
        self.dlg_min_edit = MincutManagerUi()
        self.load_settings(self.dlg_min_edit)
        self.set_dates_from_to(self.dlg_min_edit.date_from,
                               self.dlg_min_edit.date_to, 'om_mincut',
                               'forecast_start, exec_start',
                               'forecast_end, exec_end')
        self.dlg_min_edit.date_from.setEnabled(False)
        self.dlg_min_edit.date_to.setEnabled(False)
        self.set_icon(self.dlg_min_edit.btn_selector_mincut, "191")

        self.tbl_mincut_edit = self.dlg_min_edit.findChild(
            QTableView, "tbl_mincut_edit")
        self.txt_mincut_id = self.dlg_min_edit.findChild(
            QLineEdit, "txt_mincut_id")
        self.tbl_mincut_edit.setSelectionBehavior(QAbstractItemView.SelectRows)

        # Adding auto-completion to a QLineEdit
        self.completer = QCompleter()
        self.txt_mincut_id.setCompleter(self.completer)
        model = QStringListModel()

        sql = "SELECT DISTINCT(id) FROM om_mincut WHERE id > 0 "
        rows = self.controller.get_rows(sql)
        values = []
        if rows:
            for row in rows:
                values.append(str(row[0]))

        model.setStringList(values)
        self.completer.setModel(model)
        self.txt_mincut_id.textChanged.connect(
            partial(self.filter_by_id, self.tbl_mincut_edit))
        self.dlg_min_edit.date_from.dateChanged.connect(
            partial(self.filter_by_id, self.tbl_mincut_edit))
        self.dlg_min_edit.date_to.dateChanged.connect(
            partial(self.filter_by_id, self.tbl_mincut_edit))
        self.dlg_min_edit.cmb_expl.currentIndexChanged.connect(
            partial(self.filter_by_id, self.tbl_mincut_edit))
        self.dlg_min_edit.spn_next_days.setRange(-9999, 9999)
        self.dlg_min_edit.btn_next_days.clicked.connect(self.filter_by_days)
        self.dlg_min_edit.spn_next_days.valueChanged.connect(
            self.filter_by_days)
        self.dlg_min_edit.btn_cancel_mincut.clicked.connect(
            self.set_state_cancel_mincut)
        self.dlg_min_edit.tbl_mincut_edit.doubleClicked.connect(
            self.open_mincut)
        self.dlg_min_edit.btn_cancel.clicked.connect(
            partial(self.close_dialog, self.dlg_min_edit))
        self.dlg_min_edit.rejected.connect(
            partial(self.close_dialog, self.dlg_min_edit))
        self.dlg_min_edit.btn_delete.clicked.connect(
            partial(self.delete_mincut_management, self.tbl_mincut_edit,
                    "om_mincut", "id"))
        self.dlg_min_edit.btn_selector_mincut.clicked.connect(
            partial(self.mincut_selector, self.tbl_mincut_edit, 'id'))
        self.btn_notify = self.dlg_min_edit.findChild(QPushButton,
                                                      "btn_notify")
        self.btn_notify.clicked.connect(
            partial(self.get_clients_codes, self.dlg_min_edit.tbl_mincut_edit))
        self.set_icon(self.btn_notify, "307")

        try:
            row = self.controller.get_config('om_mincut_enable_alerts',
                                             'value', 'config_param_system')
            if row:
                self.custom_action_sms = json.loads(
                    row[0], object_pairs_hook=OrderedDict)
                self.btn_notify.setVisible(
                    self.custom_action_sms['show_mincut_sms'])
        except KeyError:
            self.btn_notify.setVisible(False)

        self.populate_combos()
        self.dlg_min_edit.state_edit.activated.connect(
            partial(self.filter_by_id, self.tbl_mincut_edit))

        # Set a model with selected filter. Attach that model to selected table
        self.fill_table_mincut_management(self.tbl_mincut_edit,
                                          self.schema_name + ".v_ui_mincut")
        self.set_table_columns(self.dlg_min_edit, self.tbl_mincut_edit,
                               "v_ui_mincut")

        #self.mincut.set_table_columns(self.tbl_mincut_edit, "v_ui_mincut")

        # Open the dialog
        self.open_dialog(self.dlg_min_edit, dlg_name='mincut_manager')

    def get_clients_codes(self, qtable):

        selected_list = qtable.selectionModel().selectedRows()
        if len(selected_list) == 0:
            message = "Any record selected"
            self.controller.show_warning(message)
            return

        field_code = self.custom_action_sms['field_code']
        inf_text = "Are you sure you want to send smd to this clients?"
        for i in range(0, len(selected_list)):
            row = selected_list[i].row()
            id_ = qtable.model().record(row).value(str('id'))
            inf_text += f"\n\nMincut: {id_}"
            sql = (
                f"SELECT t3.{field_code}, t2.forecast_start, t2.forecast_end, anl_cause "
                f"FROM om_mincut_hydrometer AS t1 "
                f"JOIN ext_rtc_hydrometer AS t3 ON t1.hydrometer_id::bigint = t3.id::bigint "
                f"JOIN om_mincut AS t2 ON t1.result_id = t2.id "
                f"WHERE result_id = {id_}")
            rows = self.controller.get_rows(sql, log_sql=True)
            if not rows:
                inf_text += "\nClients: None(No messages will be sent)"
                continue

            inf_text += "\nClients: \n"
            for row in rows:
                inf_text += str(row[0]) + ", "

        inf_text = inf_text[:-2]
        inf_text += "\n"
        answer = self.controller.ask_question(str(inf_text))
        if answer:
            self.call_sms_script(qtable)

    def call_sms_script(self, qtable):

        path = self.custom_action_sms['path_sms_script']
        if path is None or not os.path.exists(path):
            self.controller.show_warning("File not found", parameter=path)
            return

        selected_list = qtable.selectionModel().selectedRows()
        field_code = self.custom_action_sms['field_code']

        for i in range(0, len(selected_list)):
            row = selected_list[i].row()
            id_ = qtable.model().record(row).value(str('id'))
            sql = (
                f"SELECT t3.{field_code}, t2.forecast_start, t2.forecast_end, anl_cause, notified  "
                f"FROM om_mincut_hydrometer AS t1 "
                f"JOIN ext_rtc_hydrometer AS t3 ON t1.hydrometer_id::bigint = t3.id::bigint "
                f"JOIN om_mincut AS t2 ON t1.result_id = t2.id "
                f"WHERE result_id = {id_}")
            rows = self.controller.get_rows(sql, log_sql=True)
            if not rows:
                continue

            from_date = ""
            if rows[0][1] is not None:
                from_date = str(rows[0][1].strftime('%d/%m/%Y %H:%M'))

            to_date = ""
            if rows[0][2] is not None:
                to_date = str(rows[0][2].strftime('%d/%m/%Y %H:%M'))

            _cause = ""
            if rows[0][3] is not None:
                _cause = rows[0][3]

            list_clients = ""
            for row in rows:
                list_clients += str(row[0]) + ", "
            if len(list_clients) != 0:
                list_clients = list_clients[:-2]

            # Call script
            result = subprocess.call(
                [path, _cause, from_date, to_date, list_clients])

            _date_sended = datetime.datetime.now().strftime('%d/%m/%Y %H:%M')
            sql = ("UPDATE " + self.schema_name + ".om_mincut ")
            if row[4] is None:
                sql += f"SET notified = ('[{{\"code\":\"{result[0]}\",\"date\":\"{_date_sended}\",\"avisats\":\"{result[1]}\",\"afectats\":\"{result[2]}\"}}]') "
            else:
                sql += f"SET notified= concat(replace(notified::text,']',','),'{{\"code\":\"{result[0]}\",\"date\":\"{_date_sended}\",\"avisats\":\"{result[1]}\",\"afectats\":\"{result[2]}\"}}]')::json "
            sql += f"WHERE id = '{id_}'"
            self.controller.execute_sql(sql)

            # Set a model with selected filter. Attach that model to selected table
            self.fill_table_mincut_management(
                self.tbl_mincut_edit, self.schema_name + ".v_ui_mincut")
            self.set_table_columns(self.dlg_min_edit, self.tbl_mincut_edit,
                                   "v_ui_mincut")

    def set_state_cancel_mincut(self):

        selected_list = self.tbl_mincut_edit.selectionModel().selectedRows()
        if len(selected_list) == 0:
            message = "Any record selected"
            self.controller.show_warning(message)
            return
        inf_text = ""
        list_id = ""
        for i in range(0, len(selected_list)):
            row = selected_list[i].row()
            id_ = self.tbl_mincut_edit.model().record(row).value("id")
            inf_text += f"{id_}, "
            list_id += f"'{id_}', "
        inf_text = inf_text[:-2]
        list_id = list_id[:-2]
        message = "Are you sure you want to cancel these mincuts?"
        title = "Cancel mincuts"
        answer = self.controller.ask_question(message, title, inf_text)
        if answer:
            sql = (f"UPDATE om_mincut SET mincut_state = 3 "
                   f" WHERE id::text IN ({list_id})")
            self.controller.execute_sql(sql, log_sql=False)
            self.tbl_mincut_edit.model().select()

    def mincut_selector(self, qtable, field_id):
        """ Manage mincut selector """

        model = qtable.model()
        selected_mincuts = []
        for x in range(0, model.rowCount()):
            i = int(model.fieldIndex(field_id))
            value = model.data(model.index(x, i))
            selected_mincuts.append(value)

        if len(selected_mincuts) == 0:
            msg = "There are no visible mincuts in the table. Try a different filter or make one"
            self.controller.show_message(msg)
            return
        selector_values = f'"selector_mincut", "ids":{selected_mincuts}'
        self.dlg_selector = SelectorUi()
        self.load_settings(self.dlg_selector)
        current_tab = self.get_last_tab(self.dlg_selector, 'mincut')
        self.dlg_selector.btn_close.clicked.connect(
            partial(self.close_dialog, self.dlg_selector))
        self.dlg_selector.rejected.connect(
            partial(self.save_settings, self.dlg_selector))
        self.dlg_selector.rejected.connect(
            partial(self.save_current_tab, self.dlg_selector,
                    self.dlg_selector.main_tab, 'mincut'))

        self.api_parent.get_selector(self.dlg_selector,
                                     selector_values,
                                     current_tab=current_tab)

        self.open_dialog(self.dlg_selector,
                         dlg_name='selector',
                         maximize_button=False)

    def populate_combos(self):

        # Fill ComboBox state
        sql = ("SELECT id, idval "
               "FROM om_typevalue WHERE typevalue = 'mincut_state' "
               "ORDER BY id")
        rows = self.controller.get_rows(sql, add_empty_row=True)
        qt_tools.set_item_data(self.dlg_min_edit.state_edit, rows, 1)

        # Fill ComboBox exploitation
        sql = "SELECT expl_id, name FROM exploitation WHERE expl_id > 0 ORDER BY name"
        rows = self.controller.get_rows(sql, add_empty_row=True)
        qt_tools.set_item_data(self.dlg_min_edit.cmb_expl, rows, 1)

    def open_mincut(self):
        """ Open mincut form with selected record of the table """

        selected_list = self.tbl_mincut_edit.selectionModel().selectedRows()
        if len(selected_list) == 0:
            message = "Any record selected"
            self.controller.show_warning(message)
            return

        row = selected_list[0].row()

        # Get mincut_id from selected row
        result_mincut_id = self.tbl_mincut_edit.model().record(row).value("id")

        # Close this dialog and open selected mincut
        self.close_dialog(self.dlg_min_edit)
        self.mincut.is_new = False
        self.mincut.init_mincut_form()
        self.mincut.load_mincut(result_mincut_id)
        self.mincut.manage_docker()

    def filter_by_days(self):

        date_from = datetime.datetime.now()
        days_added = self.dlg_min_edit.spn_next_days.text()
        date_to = datetime.datetime.now()
        date_to += datetime.timedelta(days=int(days_added))

        # If the date_to is less than the date_from, you have to exchange them or the interval will not work
        if date_to < date_from:
            aux = date_from
            date_from = date_to
            date_to = aux

        format_low = '%Y-%m-%d 00:00:00.000'
        format_high = '%Y-%m-%d 23:59:59.999'
        interval = f"'{date_from.strftime(format_low)}'::timestamp AND '{date_to.strftime(format_high)}'::timestamp"

        expr = f"(forecast_start BETWEEN {interval})"
        self.tbl_mincut_edit.model().setFilter(expr)
        self.tbl_mincut_edit.model().select()

    def filter_by_id(self, qtable):

        expr = ""
        id_ = qt_tools.getWidgetText(self.dlg_min_edit,
                                     self.dlg_min_edit.txt_mincut_id, False,
                                     False)
        state_id = qt_tools.get_item_data(self.dlg_min_edit,
                                          self.dlg_min_edit.state_edit, 0)
        state_text = qt_tools.get_item_data(self.dlg_min_edit,
                                            self.dlg_min_edit.state_edit, 1)
        expl = qt_tools.get_item_data(self.dlg_min_edit,
                                      self.dlg_min_edit.cmb_expl, 1)
        dates_filter = ""
        if state_id == '':
            self.dlg_min_edit.date_from.setEnabled(False)
            self.dlg_min_edit.date_to.setEnabled(False)
        else:
            self.dlg_min_edit.date_from.setEnabled(True)
            self.dlg_min_edit.date_to.setEnabled(True)

            # Get selected dates
            visit_start = self.dlg_min_edit.date_from.date()
            visit_end = self.dlg_min_edit.date_to.date()
            date_from = visit_start.toString('yyyyMMdd 00:00:00')
            date_to = visit_end.toString('yyyyMMdd 23:59:59')
            if date_from > date_to:
                message = "Selected date interval is not valid"
                self.controller.show_warning(message)
                return

            # Create interval dates
            format_low = 'yyyy-MM-dd 00:00:00.000'
            format_high = 'yyyy-MM-dd 23:59:59.999'
            interval = f"'{visit_start.toString(format_low)}'::timestamp AND '{visit_end.toString(format_high)}'::timestamp"
            if str(state_id) in ('0', '3'):
                qt_tools.setWidgetText(self.dlg_min_edit,
                                       self.dlg_min_edit.lbl_date_from,
                                       'Date from: forecast_start')
                qt_tools.setWidgetText(self.dlg_min_edit,
                                       self.dlg_min_edit.lbl_date_to,
                                       'Date to: forecast_end')
                dates_filter = f"AND (forecast_start BETWEEN {interval}) AND (forecast_end BETWEEN {interval})"
            elif str(state_id) in ('1', '2'):
                qt_tools.setWidgetText(self.dlg_min_edit,
                                       self.dlg_min_edit.lbl_date_from,
                                       'Date from: exec_start')
                qt_tools.setWidgetText(self.dlg_min_edit,
                                       self.dlg_min_edit.lbl_date_to,
                                       'Date to: exec_end')
                dates_filter = f"AND (exec_start BETWEEN {interval}) AND (exec_end BETWEEN {interval})"
            else:
                qt_tools.setWidgetText(self.dlg_min_edit,
                                       self.dlg_min_edit.lbl_date_from,
                                       'Date from:')
                qt_tools.setWidgetText(self.dlg_min_edit,
                                       self.dlg_min_edit.lbl_date_to,
                                       'Date to:')

        expr += f" (id::text ILIKE '%{id_}%'"
        expr += f" OR work_order::text ILIKE '%{id_}%')"
        expr += f" {dates_filter}"
        if state_text != '':
            expr += f" AND state::text ILIKE '%{state_text}%' "
        expr += f" AND (exploitation::text ILIKE '%{expl}%' OR exploitation IS null)"

        # Refresh model with selected filter
        qtable.model().setFilter(expr)
        qtable.model().select()

    def fill_table_mincut_management(self, widget, table_name):
        """ Set a model with selected filter. Attach that model to selected table """

        if self.schema_name not in table_name:
            table_name = self.schema_name + "." + table_name

        # Set model
        model = QSqlTableModel()
        model.setTable(table_name)
        model.setEditStrategy(QSqlTableModel.OnManualSubmit)
        model.sort(0, 1)
        model.select()

        # Check for errors
        if model.lastError().isValid():
            self.controller.show_warning(model.lastError().text())

        # Attach model to table view
        widget.setModel(model)

    def delete_mincut_management(self, widget, table_name, column_id):
        """ Delete selected elements of the table (by id) """

        # Get selected rows
        selected_list = widget.selectionModel().selectedRows()
        if len(selected_list) == 0:
            message = "Any record selected"
            self.controller.show_warning(message)
            return

        inf_text = ""
        list_id = ""
        for i in range(0, len(selected_list)):
            row = selected_list[i].row()
            id_ = widget.model().record(row).value(str(column_id))
            inf_text += f"{id_}, "
            list_id += f"'{id_}', "
        inf_text = inf_text[:-2]
        list_id = list_id[:-2]
        message = "Are you sure you want to delete these mincuts?"
        title = "Delete mincut"
        answer = self.controller.ask_question(message, title, inf_text)
        if answer:
            sql = (f"DELETE FROM {table_name}"
                   f" WHERE {column_id} IN ({list_id})")
            self.controller.execute_sql(sql)
            widget.model().select()
            layer = self.controller.get_layer_by_tablename('v_om_mincut_node')
            if layer is not None:
                layer.triggerRepaint()
            layer = self.controller.get_layer_by_tablename(
                'v_om_mincut_connec')
            if layer is not None:
                layer.triggerRepaint()
            layer = self.controller.get_layer_by_tablename('v_om_mincut_arc')
            if layer is not None:
                layer.triggerRepaint()
            layer = self.controller.get_layer_by_tablename('v_om_mincut_valve')
            if layer is not None:
                layer.triggerRepaint()
            layer = self.controller.get_layer_by_tablename('v_om_mincut')
            if layer is not None:
                layer.triggerRepaint()
            layer = self.controller.get_layer_by_tablename(
                'v_om_mincut_hydrometer')
            if layer is not None:
                layer.triggerRepaint()
Example #17
0
class ParentManage(ParentAction, object):

    def __init__(self, iface, settings, controller, plugin_dir):
        """ Class to keep common functions of classes
        'ManageDocument', 'ManageElement' and 'ManageVisit' of toolbar 'edit' """

        super(ParentManage, self).__init__(iface, settings, controller, plugin_dir)

        self.x = ""
        self.y = ""
        self.canvas = self.iface.mapCanvas()
        self.plan_om = None
        self.previous_map_tool = None
        self.autocommit = True
        self.lazy_widget = None
        self.workcat_id_end = None
        self.xyCoordinates_conected = False
        self.remove_ids = True
        self.snapper_manager = None


    def reset_lists(self):
        """ Reset list of selected records """

        self.ids = []
        self.list_ids = {}
        self.list_ids['arc'] = []
        self.list_ids['node'] = []
        self.list_ids['connec'] = []
        self.list_ids['gully'] = []
        self.list_ids['element'] = []


    def reset_layers(self):
        """ Reset list of layers """

        self.layers = {}
        self.layers['arc'] = []
        self.layers['node'] = []
        self.layers['connec'] = []
        self.layers['gully'] = []
        self.layers['element'] = []


    def reset_model(self, dialog, table_object, geom_type):
        """ Reset model of the widget """ 

        table_relation = table_object + "_x_" + geom_type
        widget_name = "tbl_" + table_relation
        widget = utils_giswater.getWidget(dialog, widget_name)
        if widget:              
            widget.setModel(None)


    def remove_selection(self, remove_groups=True):
        """ Remove all previous selections """

        layer = self.controller.get_layer_by_tablename("v_edit_arc")
        if layer:
            layer.removeSelection()
        layer = self.controller.get_layer_by_tablename("v_edit_node")
        if layer:
            layer.removeSelection()
        layer = self.controller.get_layer_by_tablename("v_edit_connec")
        if layer:
            layer.removeSelection()
        layer = self.controller.get_layer_by_tablename("v_edit_element")
        if layer:
            layer.removeSelection()
            
        if self.project_type == 'ud':
            layer = self.controller.get_layer_by_tablename("v_edit_gully")
            if layer:
                layer.removeSelection()

        try:
            if remove_groups:
                for layer in self.layers['arc']:
                    layer.removeSelection()
                for layer in self.layers['node']:
                    layer.removeSelection()
                for layer in self.layers['connec']:
                    layer.removeSelection()
                for layer in self.layers['gully']:
                    layer.removeSelection()
                for layer in self.layers['element']:
                    layer.removeSelection()
        except:
            pass

        self.canvas.refresh()
    
    
    def reset_widgets(self, dialog, table_object):
        """ Clear contents of input widgets """
        
        if table_object == "doc":
            utils_giswater.setWidgetText(dialog, "doc_type", "")
            utils_giswater.setWidgetText(dialog, "observ", "")
            utils_giswater.setWidgetText(dialog, "path", "")
        elif table_object == "element":
            utils_giswater.setWidgetText(dialog, "elementcat_id", "")
            utils_giswater.setWidgetText(dialog, "state", "")
            utils_giswater.setWidgetText(dialog, "expl_id","")
            utils_giswater.setWidgetText(dialog, "ownercat_id", "")
            utils_giswater.setWidgetText(dialog, "location_type", "")
            utils_giswater.setWidgetText(dialog, "buildercat_id", "")
            utils_giswater.setWidgetText(dialog, "workcat_id", "")
            utils_giswater.setWidgetText(dialog, "workcat_id_end", "")
            utils_giswater.setWidgetText(dialog, "comment", "")
            utils_giswater.setWidgetText(dialog, "observ", "")
            utils_giswater.setWidgetText(dialog, "path", "")
            utils_giswater.setWidgetText(dialog, "rotation", "")
            utils_giswater.setWidgetText(dialog, "verified", "")
            utils_giswater.setWidgetText(dialog, dialog.num_elements, "")
                    
    
    def fill_widgets(self, dialog, table_object, row):
        """ Fill input widgets with data int he @row """
        
        if table_object == "doc":
            
            utils_giswater.setWidgetText(dialog, "doc_type", row["doc_type"])
            utils_giswater.setWidgetText(dialog, "observ",  row["observ"])
            utils_giswater.setWidgetText(dialog, "path",  row["path"])
             
        elif table_object == "element":
                    
            state = ""  
            if row['state']:          
                sql = (f"SELECT name FROM value_state"
                       f" WHERE id = '{row['state']}'")
                row_aux = self.controller.get_row(sql, commit=self.autocommit)
                if row_aux:
                    state = row_aux[0]
    
            expl_id = ""
            if row['expl_id']:
                sql = (f"SELECT name FROM exploitation"
                       f" WHERE expl_id = '{row['expl_id']}'")
                row_aux = self.controller.get_row(sql, commit=self.autocommit)
                if row_aux:
                    expl_id = row_aux[0]

            utils_giswater.setWidgetText(dialog, "code", row['code'])
            sql = (f"SELECT elementtype_id FROM cat_element"
                   f" WHERE id = '{row['elementcat_id']}'")
            row_type = self.controller.get_row(sql)
            if row_type:
                utils_giswater.setWidgetText(dialog, "element_type", row_type[0])

            utils_giswater.setWidgetText(dialog, "elementcat_id", row['elementcat_id'])
            utils_giswater.setWidgetText(dialog, "num_elements", row['num_elements'])
            utils_giswater.setWidgetText(dialog, "state", state)
            utils_giswater.setWidgetText(dialog, "expl_id", expl_id)
            utils_giswater.setWidgetText(dialog, "ownercat_id", row['ownercat_id'])
            utils_giswater.setWidgetText(dialog, "location_type", row['location_type'])
            utils_giswater.setWidgetText(dialog, "buildercat_id", row['buildercat_id'])
            utils_giswater.setWidgetText(dialog, "builtdate", row['builtdate'])
            utils_giswater.setWidgetText(dialog, "workcat_id", row['workcat_id'])
            utils_giswater.setWidgetText(dialog, "workcat_id_end", row['workcat_id_end'])
            utils_giswater.setWidgetText(dialog, "comment", row['comment'])
            utils_giswater.setWidgetText(dialog, "observ", row['observ'])
            utils_giswater.setWidgetText(dialog, "link", row['link'])
            utils_giswater.setWidgetText(dialog, "verified", row['verified'])
            utils_giswater.setWidgetText(dialog, "rotation", row['rotation'])
            if str(row['undelete']) == 'True':
                dialog.undelete.setChecked(True)
            
              
    def get_records_geom_type(self, dialog, table_object, geom_type):
        """ Get records of @geom_type associated to selected @table_object """
        
        object_id = utils_giswater.getWidgetText(dialog, table_object + "_id")
        table_relation = table_object + "_x_" + geom_type
        widget_name = "tbl_" + table_relation           
        
        exists = self.controller.check_table(table_relation)
        if not exists:
            self.controller.log_info(f"Not found: {table_relation}")
            return
              
        sql = (f"SELECT {geom_type}_id "
               f"FROM {table_relation} "
               f"WHERE {table_object}_id = '{object_id}'")
        rows = self.controller.get_rows(sql, commit=True, log_info=False)
        if rows:
            for row in rows:
                self.list_ids[geom_type].append(str(row[0]))
                self.ids.append(str(row[0]))

            expr_filter = self.get_expr_filter(geom_type)
            self.set_table_model(dialog, widget_name, geom_type, expr_filter)
    
    
    def exist_object(self, dialog, table_object):
        """ Check if selected object (document or element) already exists """
        
        # Reset list of selected records
        self.reset_lists()
        
        field_object_id = "id"
        if table_object == "element":
            field_object_id = table_object + "_id"           
        object_id = utils_giswater.getWidgetText(dialog, table_object + "_id")

        # Check if we already have data with selected object_id
        sql = (f"SELECT * "
               f" FROM {table_object}"
               f" WHERE {field_object_id} = '{object_id}'")
        row = self.controller.get_row(sql, log_info=False)

        # If object_id not found: Clear data
        if not row:    
            self.reset_widgets(dialog, table_object)
            if table_object == 'element':
                self.set_combo(dialog, 'state', 'value_state', 'state_vdefault', field_name='name')
                self.set_combo(dialog, 'expl_id', 'exploitation', 'exploitation_vdefault', field_id='expl_id',field_name='name')
                self.set_calendars(dialog, 'builtdate', 'config_param_user', 'value', 'builtdate_vdefault')
                self.set_combo(dialog, 'workcat_id', 'cat_work', 'workcat_vdefault', field_id='id', field_name='id')
            if hasattr(self, 'single_tool_mode'):
                # some tools can work differently if standalone or integrated in
                # another tool
                if self.single_tool_mode:
                    self.remove_selection(True)
            else:
                self.remove_selection(True)
            self.reset_model(dialog, table_object, "arc")
            self.reset_model(dialog, table_object, "node")
            self.reset_model(dialog, table_object, "connec")
            self.reset_model(dialog, table_object, "element")
            if self.project_type == 'ud':
                self.reset_model(dialog, table_object, "gully")

            return

        # Fill input widgets with data of the @row
        self.fill_widgets(dialog, table_object, row)

        # Check related 'arcs'
        self.get_records_geom_type(dialog, table_object, "arc")
        
        # Check related 'nodes'
        self.get_records_geom_type(dialog, table_object, "node")
        
        # Check related 'connecs'
        self.get_records_geom_type(dialog, table_object, "connec")

        # Check related 'elements'
        self.get_records_geom_type(dialog, table_object, "element")

        # Check related 'gullys'
        if self.project_type == 'ud':        
            self.get_records_geom_type(dialog, table_object, "gully")


    def populate_combo(self, dialog, widget, table_name, field_name="id"):
        """ Executes query and fill combo box """

        sql = (f"SELECT {field_name}"
               f" FROM {table_name}"
               f" ORDER BY {field_name}")
        rows = self.controller.get_rows(sql, commit=self.autocommit)
        utils_giswater.fillComboBox(dialog, widget, rows)
        if rows:
            utils_giswater.setCurrentIndex(dialog, widget, 0)


    def set_combo(self, dialog, widget, table_name, parameter, field_id='id', field_name='id'):
        """ Executes query and set combo box """
        
        sql = (f"SELECT t1.{field_name} FROM {table_name} as t1"
               f" INNER JOIN config_param_user as t2 ON t1.{field_id}::text = t2.value::text"
               f" WHERE parameter = '{parameter}' AND cur_user = current_user")
        row = self.controller.get_row(sql)
        if row:
            utils_giswater.setWidgetText(dialog, widget, row[0])


    def set_calendars(self, dialog, widget, table_name, value, parameter):
        """ Executes query and set QDateEdit """
        
        sql = (f"SELECT {value} FROM {table_name}"
               f" WHERE parameter = '{parameter}' AND cur_user = current_user")
        row = self.controller.get_row(sql)
        if row:
            date = QDate.fromString(row[0], 'yyyy-MM-dd')
        else:
            date = QDate.currentDate()
        utils_giswater.setCalendarDate(dialog, widget, date)


    def add_point(self):
        """ Create the appropriate map tool and connect to the corresponding signal """

        active_layer = self.iface.activeLayer()
        if active_layer is None:
            active_layer = self.controller.get_layer_by_tablename('version')
            self.iface.setActiveLayer(active_layer)

        # Vertex marker
        self.vertex_marker = QgsVertexMarker(self.canvas)
        self.vertex_marker.setColor(QColor(255, 100, 255))
        self.vertex_marker.setIconSize(15)
        self.vertex_marker.setIconType(QgsVertexMarker.ICON_CROSS)
        self.vertex_marker.setPenWidth(3)

        # Snapper
        if self.snapper_manager is None:
            self.snapper_manager = SnappingConfigManager(self.iface)
            self.snapper = self.snapper_manager.get_snapper()
            if self.snapper_manager.controller is None:
                self.snapper_manager.set_controller(self.controller)

        self.emit_point = QgsMapToolEmitPoint(self.canvas)
        self.previous_map_tool = self.canvas.mapTool()
        self.canvas.setMapTool(self.emit_point)
        self.canvas.xyCoordinates.connect(self.mouse_move)
        self.xyCoordinates_conected = True
        self.emit_point.canvasClicked.connect(partial(self.get_xy))


    def mouse_move(self, point):

        # Hide marker and get coordinates
        self.snapped_point = None
        self.vertex_marker.hide()
        event_point = self.snapper_manager.get_event_point(point=point)

        # Snapping
        result = self.snapper_manager.snap_to_background_layers(event_point)
        if self.snapper_manager.result_is_valid():
            self.snapper_manager.add_marker(result, self.vertex_marker)
        else:
            self.vertex_marker.hide()


    def get_xy(self, point):
        """ Get coordinates of selected point """

        if self.snapped_point:
            self.x = self.snapped_point.x()
            self.y = self.snapped_point.y()
        else:
            self.x = point.x()
            self.y = point.y()

        message = "Geometry has been added!"
        self.controller.show_info(message)
        self.emit_point.canvasClicked.disconnect()
        self.canvas.xyCoordinates.disconnect()
        self.xyCoordinates_conected = False
        self.iface.mapCanvas().refreshAllLayers()
        self.vertex_marker.hide()


    def get_values_from_form(self, dialog):

        self.enddate = utils_giswater.getCalendarDate(dialog, "enddate")
        self.workcat_id_end = utils_giswater.getWidgetText(dialog, "workcat_id_end")
        self.description = utils_giswater.getWidgetText(dialog, "descript")


    def tab_feature_changed(self, dialog, table_object):
        """ Set geom_type and layer depending selected tab
            @table_object = ['doc' | 'element' | 'cat_work']
        """

        self.get_values_from_form(dialog)
        tab_position = dialog.tab_feature.currentIndex()
        if tab_position == 0:
            self.geom_type = "arc"   
        elif tab_position == 1:
            self.geom_type = "node"
        elif tab_position == 2:
            self.geom_type = "connec"
        elif tab_position == 3:
            self.geom_type = "element"
        elif tab_position == 4:
            self.geom_type = "gully"

        self.hide_generic_layers()                  
        widget_name = f"tbl_{table_object}_x_{self.geom_type}"
        viewname = f"v_edit_{self.geom_type}"
        self.widget = utils_giswater.getWidget(dialog, widget_name)
            
        # Adding auto-completion to a QLineEdit
        self.set_completer_feature_id(dialog.feature_id, self.geom_type, viewname)
        
        self.iface.actionPan().trigger()    
        

    def set_completer_object(self, dialog, table_object):
        """ Set autocomplete of widget @table_object + "_id" 
            getting id's from selected @table_object 
        """
                     
        widget = utils_giswater.getWidget(dialog, table_object + "_id")
        if not widget:
            return
        
        # Set SQL
        field_object_id = "id"
        if table_object == "element":
            field_object_id = table_object + "_id"
        sql = (f"SELECT DISTINCT({field_object_id})"
               f" FROM {table_object}")
        rows = self.controller.get_rows(sql, commit=self.autocommit)
        if rows is None:
            return

        for i in range(0, len(rows)):
            aux = rows[i]
            rows[i] = str(aux[0])

        # Set completer and model: add autocomplete in the widget
        self.completer = QCompleter()
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        widget.setCompleter(self.completer)
        model = QStringListModel()
        model.setStringList(rows)
        self.completer.setModel(model)
        
        
    def set_completer_widget(self, tablename, widget, field_id):
        """ Set autocomplete of widget @table_object + "_id"
            getting id's from selected @table_object
        """

        if not widget:
            return

        # Set SQL
        sql = (f"SELECT DISTINCT({field_id})"
               f" FROM {tablename}"
               f" ORDER BY {field_id}")
        row = self.controller.get_rows(sql, commit=True)
        for i in range(0, len(row)):
            aux = row[i]
            row[i] = str(aux[0])

        # Set completer and model: add autocomplete in the widget
        self.completer = QCompleter()
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        widget.setCompleter(self.completer)
        model = QStringListModel()
        model.setStringList(row)
        self.completer.setModel(model)
                

    def set_completer_feature_id(self, widget, geom_type, viewname):
        """ Set autocomplete of widget 'feature_id' 
            getting id's from selected @viewname 
        """
             
        # Adding auto-completion to a QLineEdit
        self.completer = QCompleter()
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        widget.setCompleter(self.completer)
        model = QStringListModel()

        sql = (f"SELECT {geom_type}_id"
               f" FROM {viewname}")
        row = self.controller.get_rows(sql, commit=self.autocommit)
        if row:
            for i in range(0, len(row)):
                aux = row[i]
                row[i] = str(aux[0])

            model.setStringList(row)
            self.completer.setModel(model)


    def get_expr_filter(self, geom_type):
        """ Set an expression filter with the contents of the list.
            Set a model with selected filter. Attach that model to selected table 
        """

        list_ids = self.list_ids[geom_type]
        field_id = geom_type + "_id"
        if len(list_ids) == 0:
            return None

        # Set expression filter with features in the list        
        expr_filter = field_id + " IN ("
        for i in range(len(list_ids)):
            expr_filter += f"'{list_ids[i]}', "
        expr_filter = expr_filter[:-2] + ")"

        # Check expression
        (is_valid, expr) = self.check_expression(expr_filter)
        if not is_valid:
            return None

        # Select features of layers applying @expr
        self.select_features_by_ids(geom_type, expr)
        
        return expr_filter


    def reload_table(self, dialog, table_object, geom_type, expr_filter):
        """ Reload @widget with contents of @tablename applying selected @expr_filter """

        if type(table_object) is str:
            widget_name = f"tbl_{table_object}_x_{geom_type}"
            widget = utils_giswater.getWidget(dialog, widget_name)

            if not widget:
                message = "Widget not found"
                self.controller.log_info(message, parameter=widget_name)
                return None

        elif type(table_object) is QTableView:
            widget = table_object
        else:
            message = "Table_object is not a table name or QTableView"
            self.controller.log_info(message)
            return None

        expr = self.set_table_model(dialog, widget, geom_type, expr_filter)
        return expr


    def set_table_model(self, dialog, table_object, geom_type, expr_filter):
        """ Sets a TableModel to @widget_name attached to
            @table_name and filter @expr_filter 
        """

        expr = None
        if expr_filter:
            # Check expression
            (is_valid, expr) = self.check_expression(expr_filter)    #@UnusedVariable
            if not is_valid:
                return expr

        # Set a model with selected filter expression
        table_name = "v_edit_" + geom_type
        if self.schema_name not in table_name:
            table_name = self.schema_name + "." + table_name

        # Set the model
        model = QSqlTableModel()
        model.setTable(table_name)
        model.setEditStrategy(QSqlTableModel.OnManualSubmit)
        model.select()
        if model.lastError().isValid():
            self.controller.show_warning(model.lastError().text())
            return expr

        # Attach model to selected widget
        if type(table_object) is str:
            widget = utils_giswater.getWidget(dialog, table_object)
            if not widget:
                message = "Widget not found"
                self.controller.log_info(message, parameter=table_object)
                return expr
        elif type(table_object) is QTableView:
            widget = table_object
        else:
            message = "Table_object is not a table name or QTableView"
            self.controller.log_info(message)
            return expr

        if expr_filter:
            widget.setModel(model)
            widget.model().setFilter(expr_filter)
            widget.model().select()
        else:
            widget.setModel(None)

        return expr


    def apply_lazy_init(self, widget):
        """Apply the init function related to the model. It's necessary
        a lazy init because model is changed everytime is loaded."""

        if self.lazy_widget is None:
            return
        if widget != self.lazy_widget:
            return
        self.lazy_init_function(self.lazy_widget)


    def lazy_configuration(self, widget, init_function):
        """set the init_function where all necessary events are set.
        This is necessary to allow a lazy setup of the events because set_table_events
        can create a table with a None model loosing any event connection."""

        # TODO: create a dictionary with key:widged.objectName value:initFuction
        # to allow multiple lazy initialization
        self.lazy_widget = widget
        self.lazy_init_function = init_function


    def select_features_by_ids(self, geom_type, expr):
        """ Select features of layers of group @geom_type applying @expr """

        # Build a list of feature id's and select them
        for layer in self.layers[geom_type]:
            if expr is None:
                layer.removeSelection()  
            else:                
                it = layer.getFeatures(QgsFeatureRequest(expr))
                id_list = [i.id() for i in it]
                if len(id_list) > 0:
                    layer.selectByIds(id_list)   
                else:
                    layer.removeSelection()             
        
             
    def delete_records(self, dialog, table_object, query=False):
        """ Delete selected elements of the table """

        self.disconnect_signal_selection_changed()

        if type(table_object) is str:
            widget_name = f"tbl_{table_object}_x_{self.geom_type}"
            widget = utils_giswater.getWidget(dialog, widget_name)
            if not widget:
                message = "Widget not found"
                self.controller.show_warning(message, parameter=widget_name)
                return
        elif type(table_object) is QTableView:
            widget = table_object
        else:
            message = "Table_object is not a table name or QTableView"
            self.controller.log_info(message)
            return

        # Control when QTableView is void or has no model
        try:
            # Get selected rows
            selected_list = widget.selectionModel().selectedRows()
        except AttributeError as e:
            selected_list = []


        if len(selected_list) == 0:
            message = "Any record selected"
            self.controller.show_info_box(message)
            return

        if query:
            full_list = widget.model()
            for x in range(0, full_list.rowCount()):
                self.ids.append(widget.model().record(x).value(f"{self.geom_type}_id"))
        else:
            self.ids = self.list_ids[self.geom_type]

        field_id = self.geom_type + "_id"
        
        del_id = []
        inf_text = ""
        list_id = ""
        for i in range(0, len(selected_list)):
            row = selected_list[i].row()
            id_feature = widget.model().record(row).value(field_id)
            inf_text += f"{id_feature}, "
            list_id += f"'{id_feature}', "
            del_id.append(id_feature)
        inf_text = inf_text[:-2]
        list_id = list_id[:-2]
        message = "Are you sure you want to delete these records?"
        title = "Delete records"
        answer = self.controller.ask_question(message, title, inf_text)
        if answer:
            for el in del_id:
                self.ids.remove(el)
        else:
            return

        expr_filter = None
        expr = None
        if len(self.ids) > 0:

            # Set expression filter with features in the list
            expr_filter = f'"{field_id}" IN ('
            for i in range(len(self.ids)):
                expr_filter += f"'{self.ids[i]}', "
            expr_filter = expr_filter[:-2] + ")"

            # Check expression
            (is_valid, expr) = self.check_expression(expr_filter) #@UnusedVariable
            if not is_valid:
                return

        # Update model of the widget with selected expr_filter
        if query:
            self.delete_feature_at_plan(dialog, self.geom_type, list_id)
            self.reload_qtable(dialog, self.geom_type, self.plan_om)
        else:
            self.reload_table(dialog, table_object, self.geom_type, expr_filter)
            self.apply_lazy_init(table_object)

        # Select features with previous filter
        # Build a list of feature id's and select them
        self.select_features_by_ids(self.geom_type, expr)

        if query:
            self.remove_selection()
        # Update list
        self.list_ids[self.geom_type] = self.ids
        self.enable_feature_type(dialog)
        self.connect_signal_selection_changed(dialog, table_object)


    def manage_close(self, dialog, table_object, cur_active_layer=None):
        """ Close dialog and disconnect snapping """

        if cur_active_layer:
            self.iface.setActiveLayer(cur_active_layer)
        if hasattr(self, 'single_tool_mode'):
            # some tools can work differently if standalone or integrated in
            # another tool
            if self.single_tool_mode:
                self.remove_selection(True)
        else:
            self.remove_selection(True)
        self.reset_model(dialog, table_object, "arc")
        self.reset_model(dialog, table_object, "node")
        self.reset_model(dialog, table_object, "connec")
        self.reset_model(dialog, table_object, "element")
        if self.project_type == 'ud':
            self.reset_model(dialog, table_object, "gully")
        self.close_dialog(dialog)
        self.hide_generic_layers()
        self.disconnect_snapping()   
        self.disconnect_signal_selection_changed()


    def selection_init(self, dialog, table_object, query=False):
        """ Set canvas map tool to an instance of class 'MultipleSelection' """

        multiple_selection = MultipleSelection(self.iface, self.controller, self.layers[self.geom_type], 
            parent_manage=self, table_object=table_object, dialog=dialog)
        self.disconnect_signal_selection_changed()
        self.previous_map_tool = self.canvas.mapTool()        
        self.canvas.setMapTool(multiple_selection)              
        self.connect_signal_selection_changed(dialog, table_object, query)
        cursor = self.get_cursor_multiple_selection()
        self.canvas.setCursor(cursor)


    def selection_changed(self, dialog, table_object, geom_type, query=False):
        """ Slot function for signal 'canvas.selectionChanged' """
        self.disconnect_signal_selection_changed()
        field_id = geom_type + "_id"

        if self.remove_ids:
            self.ids = []

        # Iterate over all layers of the group
        for layer in self.layers[self.geom_type]:
            if layer.selectedFeatureCount() > 0:
                # Get selected features of the layer
                features = layer.selectedFeatures()
                for feature in features:
                    # Append 'feature_id' into the list
                    selected_id = feature.attribute(field_id)
                    if selected_id not in self.ids:
                        self.ids.append(selected_id)

        if geom_type == 'arc':
            self.list_ids['arc'] = self.ids
        elif geom_type == 'node':
            self.list_ids['node'] = self.ids
        elif geom_type == 'connec':
            self.list_ids['connec'] = self.ids
        elif geom_type == 'gully':
            self.list_ids['gully'] = self.ids
        elif geom_type == 'element':
            self.list_ids['element'] = self.ids

        expr_filter = None
        if len(self.ids) > 0:
            # Set 'expr_filter' with features that are in the list
            expr_filter = f'"{field_id}" IN ('
            for i in range(len(self.ids)):
                expr_filter += f"'{self.ids[i]}', "
            expr_filter = expr_filter[:-2] + ")"

            # Check expression
            (is_valid, expr) = self.check_expression(expr_filter)   #@UnusedVariable
            if not is_valid:
                return                                           
                          
            self.select_features_by_ids(geom_type, expr)
                        
        # Reload contents of table 'tbl_@table_object_x_@geom_type'
        if query:
            self.insert_feature_to_plan(dialog, self.geom_type)
            if self.plan_om == 'plan':
                self.remove_selection()
            self.reload_qtable(dialog, geom_type, self.plan_om)
        else:
            self.reload_table(dialog, table_object, self.geom_type, expr_filter)
            self.apply_lazy_init(table_object)

        # Remove selection in generic 'v_edit' layers
        if self.plan_om == 'plan':
            self.remove_selection(False)
        self.enable_feature_type(dialog)
        self.connect_signal_selection_changed(dialog, table_object)


    def delete_feature_at_plan(self, dialog, geom_type, list_id):
        """ Delete features_id to table plan_@geom_type_x_psector"""

        value = utils_giswater.getWidgetText(dialog, dialog.psector_id)
        sql = (f"DELETE FROM {self.plan_om}_psector_x_{geom_type} "
               f"WHERE {geom_type}_id IN ({list_id}) AND psector_id = '{value}'")
        self.controller.execute_sql(sql)


    def enable_feature_type(self, dialog):

        feature_type = dialog.findChild(QComboBox, 'feature_type')
        table = dialog.findChild(QTableView, 'tbl_relation')
        if feature_type is not None and table is not None:
            if len(self.ids) > 0:
                feature_type.setEnabled(False)
            else:
                feature_type.setEnabled(True)


    def insert_feature(self, dialog, table_object, query=False, remove_ids=True):
        """ Select feature with entered id. Set a model with selected filter.
            Attach that model to selected table
        """

        self.disconnect_signal_selection_changed()

        # Clear list of ids
        if remove_ids:
            self.ids = []
        field_id = self.geom_type + "_id"

        feature_id = utils_giswater.getWidgetText(dialog, "feature_id")
        if feature_id == 'null':
            message = "You need to enter a feature id"
            self.controller.show_info_box(message)
            return

        # Iterate over all layers of the group
        for layer in self.layers[self.geom_type]:
            if layer.selectedFeatureCount() > 0:
                # Get selected features of the layer
                features = layer.selectedFeatures()
                for feature in features:
                    # Append 'feature_id' into the list
                    selected_id = feature.attribute(field_id)
                    if selected_id not in self.ids:
                        self.ids.append(selected_id)
            if feature_id not in self.ids:
                # If feature id doesn't exist in list -> add
                self.ids.append(str(feature_id))

        # Set expression filter with features in the list
        expr_filter = f'"{field_id}" IN ('
        for i in range(len(self.ids)):
            expr_filter += f"'{self.ids[i]}', "
        expr_filter = expr_filter[:-2] + ")"

        # Check expression
        (is_valid, expr) = self.check_expression(expr_filter)
        if not is_valid:
            return

        # Select features with previous filter
        # Build a list of feature id's and select them
        for layer in self.layers[self.geom_type]:
            it = layer.getFeatures(QgsFeatureRequest(expr))
            id_list = [i.id() for i in it]
            if len(id_list) > 0:
                layer.selectByIds(id_list)

        # Reload contents of table 'tbl_???_x_@geom_type'
        if query:
            self.insert_feature_to_plan(dialog, self.geom_type)
            self.remove_selection()
        else:
            self.reload_table(dialog, table_object, self.geom_type, expr_filter)
            self.apply_lazy_init(table_object)            

        # Update list
        self.list_ids[self.geom_type] = self.ids
        self.enable_feature_type(dialog)
        self.connect_signal_selection_changed(dialog, table_object)


    def insert_feature_to_plan(self, dialog, geom_type):
        """ Insert features_id to table plan_@geom_type_x_psector """

        value = utils_giswater.getWidgetText(dialog, dialog.psector_id)
        for i in range(len(self.ids)):
            sql = (f"SELECT {geom_type}_id "
                   f"FROM {self.plan_om}_psector_x_{geom_type} "
                   f"WHERE {geom_type}_id = '{self.ids[i]}' AND psector_id = '{value}'")
            row = self.controller.get_row(sql)
            if not row:
                sql = (f"INSERT INTO {self.plan_om}_psector_x_{geom_type}"
                       f"({geom_type}_id, psector_id) VALUES('{self.ids[i]}', '{value}')")
                self.controller.execute_sql(sql)
            self.reload_qtable(dialog, geom_type, self.plan_om)


    def reload_qtable(self, dialog, geom_type, plan_om):
        """ Reload QtableView """
        
        value = utils_giswater.getWidgetText(dialog, dialog.psector_id)
        expr = f"psector_id = '{value}'"
        qtable = utils_giswater.getWidget(dialog, f'tbl_psector_x_{geom_type}')
        self.fill_table_by_expr(qtable, f"{plan_om}_psector_x_{geom_type}", expr)
        self.set_table_columns(dialog, qtable, f"{plan_om}_psector_x_{geom_type}")
        self.refresh_map_canvas()


    def fill_table_by_expr(self, qtable, table_name, expr):
        """
        :param qtable: QTableView to show
        :param expr: expression to set model
        """
        if self.schema_name not in table_name:
            table_name = self.schema_name + "." + table_name
            
        model = QSqlTableModel()
        model.setTable(table_name)
        model.setFilter(expr)
        model.setEditStrategy(QSqlTableModel.OnFieldChange)
        qtable.setEditTriggers(QTableView.DoubleClicked)
        model.select()
        qtable.setModel(model)
        qtable.show()

        # Check for errors
        if model.lastError().isValid():
            self.controller.show_warning(model.lastError().text())

    def disconnect_snapping(self):
        """ Select 'Pan' as current map tool and disconnect snapping """

        try:
            self.iface.actionPan().trigger()
            self.canvas.xyCoordinates.disconnect()
            if self.emit_point:       
                self.emit_point.canvasClicked.disconnect()
        except:
            pass


    def fill_table_object(self, widget, table_name, expr_filter=None):
        """ Set a model with selected filter. Attach that model to selected table """

        if self.schema_name not in table_name:
            table_name = self.schema_name + "." + table_name

        # Set model
        model = QSqlTableModel()
        model.setTable(table_name)
        model.setEditStrategy(QSqlTableModel.OnManualSubmit)
        model.sort(0, 1)
        if expr_filter:
            model.setFilter(expr_filter)            
        model.select()

        # Check for errors
        if model.lastError().isValid():
            self.controller.show_warning(model.lastError().text())

        # Attach model to table view
        widget.setModel(model)


    def filter_by_id(self, dialog, widget_table, widget_txt, table_object, field_object_id='id'):

        field_object_id = "id"
        if table_object == "element":
            field_object_id = table_object + "_id"
        object_id = utils_giswater.getWidgetText(dialog, widget_txt)
        if object_id != 'null':
            expr = f"{field_object_id}::text ILIKE '%{object_id}%'"
            # Refresh model with selected filter
            widget_table.model().setFilter(expr)
            widget_table.model().select()
        else:
            self.fill_table_object(widget_table, self.schema_name + "." + table_object)


    def delete_selected_object(self, widget, table_object):
        """ Delete selected objects of the table (by object_id) """

        # Get selected rows
        selected_list = widget.selectionModel().selectedRows()
        if len(selected_list) == 0:
            message = "Any record selected"
            self.controller.show_warning(message)
            return

        inf_text = ""
        list_id = ""
        field_object_id = "id"

        if table_object == "element":
            field_object_id = table_object + "_id"
        elif "v_ui_om_visitman_x_" in table_object:
            field_object_id = "visit_id"

        for i in range(0, len(selected_list)):
            row = selected_list[i].row()
            id_ = widget.model().record(row).value(str(field_object_id))
            inf_text += f"{id_}, "
            list_id += f"'{id_}', "
        inf_text = inf_text[:-2]
        list_id = list_id[:-2]
        message = "Are you sure you want to delete these records?"
        title = "Delete records"
        answer = self.controller.ask_question(message, title, inf_text)
        if answer:
            sql = (f"DELETE FROM {table_object} "
                   f"WHERE {field_object_id} IN ({list_id})")
            self.controller.execute_sql(sql, commit=self.autocommit)
            widget.model().select()

    
    def open_selected_object(self, dialog, widget, table_object):
        """ Open object form with selected record of the table """

        selected_list = widget.selectionModel().selectedRows()
        if len(selected_list) == 0:
            message = "Any record selected"
            self.controller.show_warning(message)
            return

        row = selected_list[0].row()

        # Get object_id from selected row
        field_object_id = "id"
        widget_id = table_object + "_id"
        if table_object == "element":
            field_object_id = table_object + "_id"
        if table_object == "v_ui_om_visit":
            widget_id = "visit_id"
        elif "v_ui_om_visitman_x_" in table_object:
            field_object_id = "visit_id"
        selected_object_id = widget.model().record(row).value(field_object_id)

        # Close this dialog and open selected object
        dialog.close()

        if table_object == "doc":
            self.manage_document()
            utils_giswater.setWidgetText(self.dlg_add_doc, widget_id, selected_object_id)
        elif table_object == "element":
            self.manage_element(new_element_id=False)
            utils_giswater.setWidgetText(self.dlg_add_element, widget_id, selected_object_id)
        elif table_object == "v_ui_om_visit":
            self.manage_visit(visit_id=selected_object_id)
        elif "v_ui_om_visitman_x_" in table_object:
            self.manage_visit(visit_id=selected_object_id)


    def set_selectionbehavior(self, dialog):
        
        # Get objects of type: QTableView
        widget_list = dialog.findChildren(QTableView)
        for widget in widget_list:
            widget.setSelectionBehavior(QAbstractItemView.SelectRows) 
        
        
    def hide_generic_layers(self, visible=False):       
        """ Hide generic layers """
        
        layer = self.controller.get_layer_by_tablename("v_edit_arc")
        if layer:
            self.controller.set_layer_visible(layer)
        layer = self.controller.get_layer_by_tablename("v_edit_node")
        if layer:
            self.controller.set_layer_visible(layer)
        layer = self.controller.get_layer_by_tablename("v_edit_connec")
        if layer:
            self.controller.set_layer_visible(layer)
        layer = self.controller.get_layer_by_tablename("v_edit_element")
        if layer:
            self.controller.set_layer_visible(layer)
            
        if self.project_type == 'ud':
            layer = self.controller.get_layer_by_tablename("v_edit_gully")
            if layer:
                self.controller.set_layer_visible(layer)
        
    
    def connect_signal_selection_changed(self, dialog, table_object, query=False):
        """ Connect signal selectionChanged """
        
        try:
            self.canvas.selectionChanged.connect(partial(self.selection_changed, dialog,  table_object, self.geom_type, query))
        except Exception:    
            pass
    
    
    def disconnect_signal_selection_changed(self):
        """ Disconnect signal selectionChanged """
        
        try:
            self.canvas.selectionChanged.disconnect()  
            self.iface.actionPan().trigger()
        except Exception:   
            pass
        

    def fill_widget_with_fields(self, dialog, data_object, field_names):
        """Fill the Widget with value get from data_object limited to 
        the list of field_names."""
        
        for field_name in field_names:
            value = getattr(data_object, field_name)
            if not hasattr(dialog, field_name):
                continue

            widget = getattr(dialog, field_name)
            if type(widget) == QDateEdit:
                widget.setDate(value if value else QDate.currentDate())
            elif type(widget) == QDateTimeEdit:
                widget.setDateTime(value if value else QDateTime.currentDateTime())


            if type(widget) in [QLineEdit, QTextEdit]:
                if value:
                    widget.setText(value)
                else:
                    widget.clear()
            if type(widget) in [QComboBox]:
                if not value:
                    widget.setCurrentIndex(0)
                    continue
                # look the value in item text
                index = widget.findText(str(value))
                if index >= 0:
                    widget.setCurrentIndex(index)
                    continue
                # look the value in itemData
                index = widget.findData(value)
                if index >= 0:
                    widget.setCurrentIndex(index)
                    continue


    def set_model_to_table(self, widget, table_name, expr_filter):
        """ Set a model with selected filter.
        Attach that model to selected table """

        if self.schema_name not in table_name:
            table_name = self.schema_name + "." + table_name

        # Set model
        model = QSqlTableModel();
        model.setTable(table_name)
        model.setEditStrategy(QSqlTableModel.OnManualSubmit)
        model.setFilter(expr_filter)
        model.select()

        # Check for errors
        if model.lastError().isValid():
            self.controller.show_warning(model.lastError().text())

        # Attach model to table view
        if widget:
            widget.setModel(model)
        else:
            self.controller.log_info("set_model_to_table: widget not found")
class TmParentAction(object):
    def __init__(self, iface, settings, controller, plugin_dir):
        """ Class constructor """

        # Initialize instance attributes
        self.tree_manage_version = "1.0"
        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.settings = settings
        self.controller = controller
        self.plugin_dir = plugin_dir
        self.dao = self.controller.dao
        self.schema_name = self.controller.schema_name
        self.project_type = None
        self.file_gsw = None
        self.gsw_settings = None
        self.lazy_widget = None

    def set_controller(self, controller):
        """ Set controller class """

        self.controller = controller
        self.schema_name = self.controller.schema_name

    def get_plugin_version(self):
        """ Get plugin version from metadata.txt file """

        # Check if metadata file exists
        metadata_file = os.path.join(self.plugin_dir, 'metadata.txt')
        if not os.path.exists(metadata_file):
            message = "Metadata file not found" + metadata_file
            self.controller.show_warning(message, parameter=metadata_file)
            return None

        metadata = configparser.ConfigParser()
        metadata.read(metadata_file)
        plugin_version = metadata.get('general', 'version')
        if plugin_version is None:
            message = "Plugin version not found"
            self.controller.show_warning(message)

        return plugin_version

    def load_settings(self, dialog=None):
        """ Load QGIS settings related with dialog position and size """

        if dialog is None:
            dialog = self.dlg

        try:
            screens = ctypes.windll.user32
            screen_x = screens.GetSystemMetrics(78)
            screen_y = screens.GetSystemMetrics(79)
            x = self.controller.plugin_settings_value(dialog.objectName() +
                                                      "_x")
            y = self.controller.plugin_settings_value(dialog.objectName() +
                                                      "_y")
            width = self.controller.plugin_settings_value(
                dialog.objectName() + "_width", dialog.property('width'))
            height = self.controller.plugin_settings_value(
                dialog.objectName() + "_height", dialog.property('height'))

            if int(x) < 0 or int(y) < 0:
                dialog.resize(int(width), int(height))
            else:
                if int(x) > screen_x:
                    x = int(screen_x) - int(width)
                if int(y) > screen_y:
                    y = int(screen_y)
                dialog.setGeometry(int(x), int(y), int(width), int(height))
        except:
            pass

    def save_settings(self, dialog=None):
        """ Save QGIS settings related with dialog position and size """

        if dialog is None:
            dialog = self.dlg

        self.controller.plugin_settings_set_value(
            dialog.objectName() + "_width", dialog.width())
        self.controller.plugin_settings_set_value(
            dialog.objectName() + "_height", dialog.height())
        self.controller.plugin_settings_set_value(dialog.objectName() + "_x",
                                                  dialog.pos().x() + 8)
        self.controller.plugin_settings_set_value(dialog.objectName() + "_y",
                                                  dialog.pos().y() + 31)

    def open_dialog(self,
                    dlg=None,
                    dlg_name=None,
                    info=True,
                    maximize_button=True,
                    stay_on_top=True):
        """ Open dialog """

        if dlg is None or type(dlg) is bool:
            dlg = self.dlg

        # Manage i18n of the dialog
        if dlg_name:
            self.controller.manage_translation(dlg_name, dlg)

        # Manage stay on top, maximize/minimize button and information button
        # if info is True maximize flag will be ignored
        # To enable maximize button you must set info to False
        flags = Qt.WindowCloseButtonHint
        if info:
            flags |= Qt.WindowSystemMenuHint | Qt.WindowContextHelpButtonHint
        else:
            if maximize_button:
                flags |= Qt.WindowMinMaxButtonsHint

        if stay_on_top:
            flags |= Qt.WindowStaysOnTopHint

        dlg.setWindowFlags(flags)

        # Open dialog
        if issubclass(type(dlg), GwDialog):
            dlg.open()
        elif issubclass(type(dlg), GwMainWindow):
            dlg.show()
        else:
            print(f"WARNING: dialog type {type(dlg)} is not handled!")
            dlg.show()

    def close_dialog(self, dlg=None):
        """ Close dialog """

        try:
            self.save_settings(dlg)
            dlg.close()
            map_tool = self.canvas.mapTool()
            # If selected map tool is from the plugin, set 'Pan' as current one
            if map_tool.toolName() == '':
                self.iface.actionPan().trigger()
        except AttributeError:
            pass

    def hide_colums(self, widget, comuns_to_hide):
        for i in range(0, len(comuns_to_hide)):
            widget.hideColumn(comuns_to_hide[i])

    def set_icon(self, widget, icon):
        """ Set @icon to selected @widget """

        # Get icons folder
        icons_folder = os.path.join(self.plugin_dir, 'icons')
        icon_path = os.path.join(icons_folder, str(icon) + ".png")
        if os.path.exists(icon_path):
            widget.setIcon(QIcon(icon_path))
        else:
            self.controller.log_info("File not found", parameter=icon_path)

    def check_expression(self, expr_filter, log_info=False):
        """ Check if expression filter @expr_filter is valid """

        if log_info:
            self.controller.log_info(expr_filter)
        expr = QgsExpression(expr_filter)
        if expr.hasParserError():
            message = "Expression Error"
            self.controller.log_warning(message, parameter=expr_filter)
            return False, expr

        return True, expr

    def set_table_columns(self, dialog, widget, table_name, project_type=None):
        """ Configuration of tables. Set visibility and width of columns """

        widget = utils_giswater.getWidget(dialog, widget)
        if not widget:
            return

        # Set width and alias of visible columns
        columns_to_delete = []
        sql = (f"SELECT column_index, width, alias, status"
               f" FROM config_client_forms"
               f" WHERE table_id = '{table_name}'")
        if project_type is not None:
            sql += f" AND project_type = '{project_type}' "
        sql += " ORDER BY column_index"

        rows = self.controller.get_rows(sql, log_info=False)
        if not rows:
            return

        for row in rows:
            if not row['status']:
                columns_to_delete.append(row['column_index'] - 1)
            else:
                width = row['width']
                if width is not None:
                    widget.setColumnWidth(row['column_index'] - 1, width)
                widget.model().setHeaderData(row['column_index'] - 1,
                                             Qt.Horizontal, row['alias'])

        widget.model().select()

        # Delete columns
        for column in columns_to_delete:
            widget.hideColumn(column)

    def set_completer_object(self, tablename, widget, field_search):
        """ Set autocomplete of widget @table_object + "_id"
            getting id's from selected @table_object
        """

        if not widget:
            return

        # Set SQL
        sql = (f"SELECT DISTINCT({field_search})"
               f" FROM {tablename}"
               f" ORDER BY {field_search}")
        rows = self.controller.get_rows(sql)
        if rows is None:
            return

        for i in range(0, len(rows)):
            aux = rows[i]
            rows[i] = aux[0]

        # Set completer and model: add autocomplete in the widget
        self.completer = QCompleter()
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.completer.setCompletionMode(0)
        widget.setCompleter(self.completer)
        model = QStringListModel()
        model.setStringList(rows)
        self.completer.setModel(model)

    def refresh_map_canvas(self, restore_cursor=False):
        """ Refresh all layers present in map canvas """

        self.canvas.refreshAllLayers()
        for layer_refresh in self.canvas.layers():
            layer_refresh.triggerRepaint()

        if restore_cursor:
            self.set_cursor_restore()

    def set_cursor_restore(self):
        """ Restore to previous cursors """
        QApplication.restoreOverrideCursor()

    def get_cursor_multiple_selection(self):
        """ Set cursor for multiple selection """

        path_folder = os.path.join(os.path.dirname(__file__), os.pardir)
        path_cursor = os.path.join(path_folder, 'icons', '201.png')
        if os.path.exists(path_cursor):
            cursor = QCursor(QPixmap(path_cursor))
        else:
            cursor = QCursor(Qt.ArrowCursor)

        return cursor

    def fill_table(self,
                   qtable,
                   table_name,
                   set_edit_triggers=QTableView.NoEditTriggers,
                   expr_filter=None):
        """ Fill table @widget filtering query by @workcat_id
            Set a model with selected filter.
            Attach that model to selected table
            @setEditStrategy:
             0: OnFieldChange
             1: OnRowChange
             2: OnManualSubmit
        """

        expr = None
        if expr_filter:
            # Check expression
            (is_valid,
             expr) = self.check_expression(expr_filter)  # @UnusedVariable
            if not is_valid:
                return expr

        # Set a model with selected filter expression
        if self.schema_name not in table_name:
            table_name = self.schema_name + "." + table_name

        # Set model
        model = QSqlTableModel()
        model.setTable(table_name)
        model.setEditStrategy(QSqlTableModel.OnManualSubmit)
        model.setSort(0, 0)
        model.select()

        # When change some field we need to refresh Qtableview and filter by psector_id
        qtable.setEditTriggers(set_edit_triggers)

        # Check for errors
        if model.lastError().isValid():
            self.controller.show_warning(model.lastError().text())
        # Attach model to table view
        if expr:
            qtable.setModel(model)
            qtable.model().setFilter(expr_filter)
        else:
            qtable.setModel(model)

        return expr

    def get_feature_by_id(self, layer, id, field_id):

        features = layer.getFeatures()
        for feature in features:
            if feature[field_id] == id:
                return feature

        return False
class GwGo2Epa:
    def __init__(self):
        """ Class to control toolbar 'go2epa' """

        self.g2epa_opt = GwGo2EpaOptions()
        self.iterations = 0
        self.controller = global_vars.controller
        self.project_type = self.controller.get_project_type()
        self.plugin_dir = global_vars.plugin_dir

    def go2epa(self):
        """ Button 23: Open form to set INP, RPT and project """

        # Show form in docker?
        self.controller.init_docker('qgis_form_docker')

        # Create dialog
        self.dlg_go2epa = Go2EpaUI()
        load_settings(self.dlg_go2epa)
        self.load_user_values()
        if self.project_type in 'ws':
            self.dlg_go2epa.chk_export_subcatch.setVisible(False)

        # Set signals
        self.set_signals()

        if self.project_type == 'ws':
            self.dlg_go2epa.btn_hs_ds.setText("Dscenario Selector")
            tableleft = "cat_dscenario"
            tableright = "selector_inp_demand"
            field_id_left = "dscenario_id"
            field_id_right = "dscenario_id"
            self.dlg_go2epa.btn_hs_ds.clicked.connect(
                partial(self.sector_selection,
                        tableleft,
                        tableright,
                        field_id_left,
                        field_id_right,
                        aql=""))

        elif self.project_type == 'ud':
            self.dlg_go2epa.btn_hs_ds.setText("Hydrology selector")
            self.dlg_go2epa.btn_hs_ds.clicked.connect(
                self.ud_hydrology_selector)

        # Check OS and enable/disable checkbox execute EPA software
        if sys.platform != "win32":
            qt_tools.setChecked(self.dlg_go2epa, self.dlg_go2epa.chk_exec,
                                False)
            self.dlg_go2epa.chk_exec.setEnabled(False)
            self.dlg_go2epa.chk_exec.setText(
                'Execute EPA software (Runs only on Windows)')

        self.set_completer_result(self.dlg_go2epa.txt_result_name,
                                  'v_ui_rpt_cat_result', 'result_id')

        if self.controller.dlg_docker:
            self.controller.manage_translation('go2epa', self.dlg_go2epa)
            self.controller.dock_dialog(self.dlg_go2epa)
            self.dlg_go2epa.btn_cancel.clicked.disconnect()
            self.dlg_go2epa.btn_cancel.clicked.connect(
                self.controller.close_docker)
        else:
            open_dialog(self.dlg_go2epa, dlg_name='go2epa')

    def set_signals(self):

        self.dlg_go2epa.txt_result_name.textChanged.connect(
            partial(self.check_result_id))
        self.dlg_go2epa.btn_file_inp.clicked.connect(
            self.go2epa_select_file_inp)
        self.dlg_go2epa.btn_file_rpt.clicked.connect(
            self.go2epa_select_file_rpt)
        self.dlg_go2epa.btn_accept.clicked.connect(self.go2epa_accept)
        self.dlg_go2epa.btn_cancel.clicked.connect(
            partial(close_dialog, self.dlg_go2epa))
        self.dlg_go2epa.rejected.connect(partial(close_dialog,
                                                 self.dlg_go2epa))
        self.dlg_go2epa.btn_options.clicked.connect(self.epa_options)

    def check_inp_chk(self, file_inp):

        if file_inp is None:
            msg = "Select valid INP file"
            self.controller.show_warning(msg, parameter=str(file_inp))
            return False

    def check_rpt(self):

        file_inp = qt_tools.getWidgetText(self.dlg_go2epa,
                                          self.dlg_go2epa.txt_file_inp)
        file_rpt = qt_tools.getWidgetText(self.dlg_go2epa,
                                          self.dlg_go2epa.txt_file_rpt)

        # Control execute epa software
        if qt_tools.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_exec):
            if self.check_inp_chk(file_inp) is False:
                return False

            if file_rpt is None:
                msg = "Select valid RPT file"
                self.controller.show_warning(msg, parameter=str(file_rpt))
                return False

            if not qt_tools.isChecked(self.dlg_go2epa,
                                      self.dlg_go2epa.chk_export):
                if not os.path.exists(file_inp):
                    msg = "File INP not found"
                    self.controller.show_warning(msg, parameter=str(file_rpt))
                    return False

    def check_fields(self):

        file_inp = qt_tools.getWidgetText(self.dlg_go2epa,
                                          self.dlg_go2epa.txt_file_inp)
        file_rpt = qt_tools.getWidgetText(self.dlg_go2epa,
                                          self.dlg_go2epa.txt_file_rpt)
        result_name = qt_tools.getWidgetText(self.dlg_go2epa,
                                             self.dlg_go2epa.txt_result_name,
                                             False, False)

        # Control export INP
        if qt_tools.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_export):
            if self.check_inp_chk(file_inp) is False:
                return False

        # Control execute epa software
        if self.check_rpt() is False:
            return False

        # Control import result
        if qt_tools.isChecked(self.dlg_go2epa,
                              self.dlg_go2epa.chk_import_result):
            if file_rpt is None:
                msg = "Select valid RPT file"
                self.controller.show_warning(msg, parameter=str(file_rpt))
                return False
            if not qt_tools.isChecked(self.dlg_go2epa,
                                      self.dlg_go2epa.chk_exec):
                if not os.path.exists(file_rpt):
                    msg = "File RPT not found"
                    self.controller.show_warning(msg, parameter=str(file_rpt))
                    return False
            else:
                if self.check_rpt() is False:
                    return False

        # Control result name
        if result_name == '':
            self.dlg_go2epa.txt_result_name.setStyleSheet(
                "border: 1px solid red")
            msg = "This parameter is mandatory. Please, set a value"
            self.controller.show_details(msg, title="Rpt fail", inf_text=None)
            return False

        sql = (f"SELECT result_id FROM rpt_cat_result "
               f"WHERE result_id = '{result_name}' LIMIT 1")
        row = self.controller.get_row(sql)
        if row:
            msg = "Result name already exists, do you want overwrite?"
            answer = self.controller.ask_question(msg, title="Alert")
            if not answer:
                return False

        return True

    def load_user_values(self):
        """ Load QGIS settings related with file_manager """

        self.dlg_go2epa.txt_result_name.setMaxLength(16)
        self.result_name = get_parser_value('go2epa', 'go2epa_RESULT_NAME')
        self.dlg_go2epa.txt_result_name.setText(self.result_name)
        self.file_inp = get_parser_value('go2epa', 'go2epa_FILE_INP')
        self.dlg_go2epa.txt_file_inp.setText(self.file_inp)
        self.file_rpt = get_parser_value('go2epa', 'go2epa_FILE_RPT')
        self.dlg_go2epa.txt_file_rpt.setText(self.file_rpt)

        value = get_parser_value('go2epa', 'go2epa_chk_NETWORK_GEOM')
        qt_tools.setChecked(self.dlg_go2epa, self.dlg_go2epa.chk_only_check,
                            value)
        value = get_parser_value('go2epa', 'go2epa_chk_INP')
        qt_tools.setChecked(self.dlg_go2epa, self.dlg_go2epa.chk_export, value)
        value = get_parser_value('go2epa', 'go2epa_chk_UD')
        qt_tools.setChecked(self.dlg_go2epa,
                            self.dlg_go2epa.chk_export_subcatch, value)
        value = get_parser_value('go2epa', 'go2epa_chk_EPA')
        qt_tools.setChecked(self.dlg_go2epa, self.dlg_go2epa.chk_exec, value)
        value = get_parser_value('go2epa', 'go2epa_chk_RPT')
        qt_tools.setChecked(self.dlg_go2epa, self.dlg_go2epa.chk_import_result,
                            value)

    def save_user_values(self):
        """ Save QGIS settings related with file_manager """

        set_parser_value(
            'go2epa', 'go2epa_RESULT_NAME',
            f"{qt_tools.getWidgetText(self.dlg_go2epa, 'txt_result_name', return_string_null=False)}"
        )
        set_parser_value(
            'go2epa', 'go2epa_FILE_INP',
            f"{qt_tools.getWidgetText(self.dlg_go2epa, 'txt_file_inp', return_string_null=False)}"
        )
        set_parser_value(
            'go2epa', 'go2epa_FILE_RPT',
            f"{qt_tools.getWidgetText(self.dlg_go2epa, 'txt_file_rpt', return_string_null=False)}"
        )
        set_parser_value(
            'go2epa', 'go2epa_chk_NETWORK_GEOM',
            f"{qt_tools.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_only_check)}"
        )
        set_parser_value(
            'go2epa', 'go2epa_chk_INP',
            f"{qt_tools.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_export)}"
        )
        set_parser_value(
            'go2epa', 'go2epa_chk_UD',
            f"{qt_tools.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_export_subcatch)}"
        )
        set_parser_value(
            'go2epa', 'go2epa_chk_EPA',
            f"{qt_tools.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_exec)}")
        set_parser_value(
            'go2epa', 'go2epa_chk_RPT',
            f"{qt_tools.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_import_result)}"
        )

    def sector_selection(self,
                         tableleft,
                         tableright,
                         field_id_left,
                         field_id_right,
                         aql=""):
        """ Load the tables in the selection form """

        dlg_psector_sel = Multirow_selector('dscenario')
        load_settings(dlg_psector_sel)
        dlg_psector_sel.btn_ok.clicked.connect(dlg_psector_sel.close)

        if tableleft == 'cat_dscenario':
            dlg_psector_sel.setWindowTitle(" Dscenario selector")
            qt_tools.setWidgetText(
                dlg_psector_sel, dlg_psector_sel.lbl_filter,
                self.controller.tr('Filter by: Dscenario name',
                                   context_name='labels'))
            qt_tools.setWidgetText(
                dlg_psector_sel, dlg_psector_sel.lbl_unselected,
                self.controller.tr('Unselected dscenarios',
                                   context_name='labels'))
            qt_tools.setWidgetText(
                dlg_psector_sel, dlg_psector_sel.lbl_selected,
                self.controller.tr('Selected dscenarios',
                                   context_name='labels'))

        multi_row_selector(dlg_psector_sel,
                           tableleft,
                           tableright,
                           field_id_left,
                           field_id_right,
                           aql=aql)

        open_dialog(dlg_psector_sel)

    def epa_options(self):
        """ Open dialog api_epa_options.ui.ui """

        self.g2epa_opt.go2epa_options()
        return

    def ud_hydrology_selector(self):
        """ Dialog hydrology_selector.ui """

        self.dlg_hydrology_selector = HydrologySelector()
        load_settings(self.dlg_hydrology_selector)

        self.dlg_hydrology_selector.btn_accept.clicked.connect(
            self.save_hydrology)
        self.dlg_hydrology_selector.hydrology.currentIndexChanged.connect(
            self.update_labels)
        self.dlg_hydrology_selector.txt_name.textChanged.connect(
            partial(self.filter_cbx_by_text, "cat_hydrology",
                    self.dlg_hydrology_selector.txt_name,
                    self.dlg_hydrology_selector.hydrology))

        sql = "SELECT DISTINCT(name), hydrology_id FROM cat_hydrology ORDER BY name"
        rows = self.controller.get_rows(sql)
        if not rows:
            message = "Any data found in table"
            self.controller.show_warning(message, parameter='cat_hydrology')
            return False

        qt_tools.set_item_data(self.dlg_hydrology_selector.hydrology, rows)

        sql = (
            "SELECT DISTINCT(t1.name) FROM cat_hydrology AS t1 "
            "INNER JOIN selector_inp_hydrology AS t2 ON t1.hydrology_id = t2.hydrology_id "
            "WHERE t2.cur_user = current_user")
        row = self.controller.get_row(sql)
        if row:
            qt_tools.setWidgetText(self.dlg_hydrology_selector,
                                   self.dlg_hydrology_selector.hydrology,
                                   row[0])
        else:
            qt_tools.setWidgetText(self.dlg_hydrology_selector,
                                   self.dlg_hydrology_selector.hydrology, 0)

        self.update_labels()
        open_dialog(self.dlg_hydrology_selector)

    def save_hydrology(self):

        hydrology_id = qt_tools.get_item_data(
            self.dlg_hydrology_selector, self.dlg_hydrology_selector.hydrology,
            1)
        sql = ("SELECT cur_user FROM selector_inp_hydrology "
               "WHERE cur_user = current_user")
        row = self.controller.get_row(sql)
        if row:
            sql = (f"UPDATE selector_inp_hydrology "
                   f"SET hydrology_id = {hydrology_id} "
                   f"WHERE cur_user = current_user")
        else:
            sql = (
                f"INSERT INTO selector_inp_hydrology (hydrology_id, cur_user) "
                f"VALUES('{hydrology_id}', current_user)")
        self.controller.execute_sql(sql)

        message = "Values has been update"
        self.controller.show_info(message)
        close_dialog(self.dlg_hydrology_selector)

    def update_labels(self):
        """ Show text in labels from SELECT """

        sql = (
            f"SELECT infiltration, text FROM cat_hydrology"
            f" WHERE name = '{self.dlg_hydrology_selector.hydrology.currentText()}'"
        )
        row = self.controller.get_row(sql)
        if row is not None:
            qt_tools.setText(self.dlg_hydrology_selector,
                             self.dlg_hydrology_selector.infiltration, row[0])
            qt_tools.setText(self.dlg_hydrology_selector,
                             self.dlg_hydrology_selector.descript, row[1])

    def filter_cbx_by_text(self, tablename, widgettxt, widgetcbx):

        sql = (f"SELECT DISTINCT(name), hydrology_id FROM {tablename}"
               f" WHERE name LIKE '%{widgettxt.text()}%'"
               f" ORDER BY name ")
        rows = self.controller.get_rows(sql)
        if not rows:
            message = "Check the table 'cat_hydrology' "
            self.controller.show_warning(message)
            return False
        qt_tools.set_item_data(widgetcbx, rows)
        self.update_labels()

    def go2epa_select_file_inp(self):
        """ Select INP file """

        self.file_inp = qt_tools.getWidgetText(self.dlg_go2epa,
                                               self.dlg_go2epa.txt_file_inp)
        # Set default value if necessary
        if self.file_inp is None or self.file_inp == '':
            self.file_inp = global_vars.plugin_dir

        # Get directory of that file
        folder_path = os.path.dirname(self.file_inp)
        if not os.path.exists(folder_path):
            folder_path = os.path.dirname(__file__)
        os.chdir(folder_path)
        message = self.controller.tr("Select INP file")
        self.file_inp, filter_ = QFileDialog.getSaveFileName(
            None, message, "", '*.inp')
        qt_tools.setWidgetText(self.dlg_go2epa, self.dlg_go2epa.txt_file_inp,
                               self.file_inp)

    def go2epa_select_file_rpt(self):
        """ Select RPT file """

        # Set default value if necessary
        if self.file_rpt is None or self.file_rpt == '':
            self.file_rpt = global_vars.plugin_dir

        # Get directory of that file
        folder_path = os.path.dirname(self.file_rpt)
        if not os.path.exists(folder_path):
            folder_path = os.path.dirname(__file__)
        os.chdir(folder_path)
        message = self.controller.tr("Select RPT file")
        self.file_rpt, filter_ = QFileDialog.getSaveFileName(
            None, message, "", '*.rpt')
        qt_tools.setWidgetText(self.dlg_go2epa, self.dlg_go2epa.txt_file_rpt,
                               self.file_rpt)

    def go2epa_accept(self):
        """ Save INP, RPT and result name into GSW file """

        # Save user values
        self.save_user_values()

        self.dlg_go2epa.txt_infolog.clear()
        self.dlg_go2epa.txt_file_rpt.setStyleSheet(None)
        status = self.check_fields()
        if status is False:
            return

        # Get widgets values
        self.result_name = qt_tools.getWidgetText(
            self.dlg_go2epa, self.dlg_go2epa.txt_result_name, False, False)
        self.net_geom = qt_tools.isChecked(self.dlg_go2epa,
                                           self.dlg_go2epa.chk_only_check)
        self.export_inp = qt_tools.isChecked(self.dlg_go2epa,
                                             self.dlg_go2epa.chk_export)
        self.export_subcatch = qt_tools.isChecked(
            self.dlg_go2epa, self.dlg_go2epa.chk_export_subcatch)
        self.file_inp = qt_tools.getWidgetText(self.dlg_go2epa,
                                               self.dlg_go2epa.txt_file_inp)
        self.exec_epa = qt_tools.isChecked(self.dlg_go2epa,
                                           self.dlg_go2epa.chk_exec)
        self.file_rpt = qt_tools.getWidgetText(self.dlg_go2epa,
                                               self.dlg_go2epa.txt_file_rpt)
        self.import_result = qt_tools.isChecked(
            self.dlg_go2epa, self.dlg_go2epa.chk_import_result)

        # Check for sector selector
        if self.export_inp:
            sql = "SELECT sector_id FROM selector_sector LIMIT 1"
            row = self.controller.get_row(sql)
            if row is None:
                msg = "You need to select some sector"
                self.controller.show_info_box(msg)
                return

        # Set background task 'Go2Epa'
        description = f"Go2Epa"
        self.task_go2epa = GwGo2EpaTask(description, self)
        QgsApplication.taskManager().addTask(self.task_go2epa)
        QgsApplication.taskManager().triggerTask(self.task_go2epa)

    def set_completer_result(self, widget, viewname, field_name):
        """ Set autocomplete of widget 'feature_id'
            getting id's from selected @viewname
        """

        result_name = qt_tools.getWidgetText(self.dlg_go2epa,
                                             self.dlg_go2epa.txt_result_name)

        # Adding auto-completion to a QLineEdit
        self.completer = QCompleter()
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        widget.setCompleter(self.completer)
        model = QStringListModel()

        sql = f"SELECT {field_name} FROM {viewname}"
        rows = self.controller.get_rows(sql)

        if rows:
            for i in range(0, len(rows)):
                aux = rows[i]
                rows[i] = str(aux[0])

            model.setStringList(rows)
            self.completer.setModel(model)
            if result_name in rows:
                self.dlg_go2epa.chk_only_check.setEnabled(True)

    def check_result_id(self):
        """ Check if selected @result_id already exists """

        result_id = qt_tools.getWidgetText(self.dlg_go2epa,
                                           self.dlg_go2epa.txt_result_name)
        sql = (f"SELECT result_id FROM v_ui_rpt_cat_result"
               f" WHERE result_id = '{result_id}'")
        row = self.controller.get_row(sql, log_info=False)
        if not row:
            self.dlg_go2epa.chk_only_check.setChecked(False)
            self.dlg_go2epa.chk_only_check.setEnabled(False)
        else:
            self.dlg_go2epa.chk_only_check.setEnabled(True)

    def go2epa_options_get_data(self, tablename, dialog):
        """ Get data from selected table """

        sql = f"SELECT * FROM {tablename}"
        row = self.controller.get_row(sql)
        if not row:
            message = "Any data found in table"
            self.controller.show_warning(message, parameter=tablename)
            return None

        # Iterate over all columns and populate its corresponding widget
        columns = []
        for i in range(0, len(row)):
            column_name = self.controller.dao.get_column_name(i)
            widget = dialog.findChild(QWidget, column_name)
            widget_type = qt_tools.getWidgetType(dialog, widget)
            if row[column_name] is not None:
                if widget_type is QCheckBox:
                    qt_tools.setChecked(dialog, widget, row[column_name])
                elif widget_type is QComboBox:
                    qt_tools.set_combo_itemData(widget, row[column_name], 0)
                elif widget_type is QDateEdit:
                    dateaux = row[column_name].replace('/', '-')
                    date = QDate.fromString(dateaux, 'dd-MM-yyyy')
                    qt_tools.setCalendarDate(dialog, widget, date)
                elif widget_type is QTimeEdit:
                    timeparts = str(row[column_name]).split(':')
                    if len(timeparts) < 3:
                        timeparts.append("0")
                    days = int(timeparts[0]) / 24
                    hours = int(timeparts[0]) % 24
                    minuts = int(timeparts[1])
                    seconds = int(timeparts[2])
                    time = QTime(hours, minuts, seconds)
                    qt_tools.setTimeEdit(dialog, widget, time)
                    qt_tools.setText(dialog, column_name + "_day", days)
                else:
                    qt_tools.setWidgetText(dialog, widget,
                                           str(row[column_name]))

            columns.append(column_name)

        return columns

    def update_sql(self):
        usql = GwAdmin()
        usql.init_sql()
Example #20
0
class GwFeatureEnd(ParentManage):
    def __init__(self, iface, settings, controller, plugin_dir):
        """ Class to control 'Workcat end' of toolbar 'edit' """
        ParentManage.__init__(self, iface, settings, controller, plugin_dir)

    def manage_workcat_end(self):

        self.remove_selection(True)

        # Create the dialog and signals
        self.dlg_work_end = FeatureEndUi()
        self.load_settings(self.dlg_work_end)
        self.set_edit_arc_downgrade_force('True')

        # Capture the current layer to return it at the end of the operation
        self.cur_active_layer = self.iface.activeLayer()

        self.set_selectionbehavior(self.dlg_work_end)

        # Get layers of every geom_type
        self.reset_lists()
        self.reset_layers()
        self.layers['arc'] = self.controller.get_group_layers('arc')
        self.layers['node'] = self.controller.get_group_layers('node')
        self.layers['connec'] = self.controller.get_group_layers('connec')
        self.layers['element'] = [
            self.controller.get_layer_by_tablename('v_edit_element')
        ]

        # Remove 'gully' for 'WS'
        self.project_type = self.controller.get_project_type()
        if self.project_type == 'ws':
            self.dlg_work_end.tab_feature.removeTab(4)
        else:
            self.layers['gully'] = self.controller.get_group_layers('gully')

        # Set icons
        self.set_icon(self.dlg_work_end.btn_insert, "111")
        self.set_icon(self.dlg_work_end.btn_delete, "112")
        self.set_icon(self.dlg_work_end.btn_snapping, "137")
        self.set_icon(self.dlg_work_end.btn_new_workcat, "193")

        # Adding auto-completion to a QLineEdit
        self.table_object = "cat_work"
        self.set_completer_object(self.dlg_work_end, self.table_object)

        # Set signals
        self.dlg_work_end.btn_accept.clicked.connect(
            partial(self.manage_workcat_end_accept))
        self.dlg_work_end.btn_cancel.clicked.connect(
            partial(self.manage_close,
                    self.dlg_work_end,
                    self.table_object,
                    self.cur_active_layer,
                    force_downgrade=True))
        self.dlg_work_end.rejected.connect(
            partial(self.manage_close,
                    self.dlg_work_end,
                    self.table_object,
                    self.cur_active_layer,
                    force_downgrade=True,
                    show_warning=True))
        self.dlg_work_end.workcat_id_end.editTextChanged.connect(
            partial(self.fill_workids))
        self.dlg_work_end.btn_new_workcat.clicked.connect(
            partial(self.new_workcat))
        self.dlg_work_end.btn_insert.clicked.connect(
            partial(self.insert_feature, self.dlg_work_end, self.table_object))
        self.dlg_work_end.btn_delete.clicked.connect(
            partial(self.delete_records, self.dlg_work_end, self.table_object))
        self.dlg_work_end.btn_snapping.clicked.connect(
            partial(self.selection_init, self.dlg_work_end, self.table_object))
        self.dlg_work_end.workcat_id_end.activated.connect(
            partial(self.fill_workids))
        self.dlg_work_end.tab_feature.currentChanged.connect(
            partial(self.tab_feature_changed,
                    self.dlg_work_end,
                    self.table_object,
                    excluded_layers=["v_edit_element"]))

        # Set values
        self.fill_fields()

        # Adding auto-completion to a QLineEdit for default feature
        geom_type = "arc"
        viewname = "v_edit_" + geom_type
        self.set_completer_feature_id(self.dlg_work_end.feature_id, geom_type,
                                      viewname)

        # Set default tab 'arc'
        self.dlg_work_end.tab_feature.setCurrentIndex(0)
        self.geom_type = "arc"
        self.tab_feature_changed(self.dlg_work_end,
                                 self.table_object,
                                 excluded_layers=["v_edit_element"])

        # Open dialog
        self.open_dialog(self.dlg_work_end,
                         dlg_name='feature_end',
                         maximize_button=False)

    def set_edit_arc_downgrade_force(self, value):

        # Update (or insert) on config_param_user the value of edit_arc_downgrade_force to true
        row = self.controller.get_config('edit_arc_downgrade_force')
        if row:
            sql = (
                f"UPDATE config_param_user "
                f"SET value = '{value}' "
                f"WHERE parameter = 'edit_arc_downgrade_force' AND cur_user=current_user"
            )
            self.controller.execute_sql(sql, log_sql=True)
        else:
            sql = (
                f"INSERT INTO config_param_user (parameter, value, cur_user) "
                f"VALUES ('edit_arc_downgrade_force', '{value}', current_user)"
            )
            self.controller.execute_sql(sql)

    def fill_fields(self):
        """ Fill dates and combos cat_work/state type end """

        sql = 'SELECT id as id, name as idval FROM value_state_type WHERE id IS NOT NULL AND state = 0'
        rows = self.controller.get_rows(sql)
        qt_tools.set_item_data(self.dlg_work_end.cmb_statetype_end, rows, 1)
        row = self.controller.get_config('statetype_end_vdefault')

        if row:
            qt_tools.set_combo_itemData(self.dlg_work_end.cmb_statetype_end,
                                        row[0], 0)
        row = self.controller.get_config('edit_enddate_vdefault')

        if row:
            enddate = self.manage_dates(row[0]).date()
            self.dlg_work_end.enddate.setDate(enddate)
        else:
            enddate = QDate.currentDate()
        qt_tools.setCalendarDate(self.dlg_work_end, "enddate", enddate)

        sql = "SELECT id FROM cat_work"
        rows = self.controller.get_rows(sql)
        qt_tools.fillComboBox(self.dlg_work_end,
                              self.dlg_work_end.workcat_id_end,
                              rows,
                              allow_nulls=False)
        qt_tools.set_autocompleter(self.dlg_work_end.workcat_id_end)
        row = self.controller.get_config('edit_workcat_end_vdefault')
        if row:
            qt_tools.setWidgetText(self.dlg_work_end,
                                   self.dlg_work_end.workcat_id_end, row[0])

    def manage_dates(self, date_value):
        """ Manage dates """

        date_result = None
        try:
            date_result = str(date_value)
            date_result = date_result.replace("-", "/")
            date_result = datetime.strptime(date_result, '%Y/%m/%d')
        except Exception as e:
            self.controller.log_warning(str(e))
        finally:
            return date_result

    def fill_workids(self):
        """ Auto fill descriptions and workid's """

        workcat_id = qt_tools.getWidgetText(self.dlg_work_end,
                                            self.dlg_work_end.workcat_id_end)
        if not workcat_id:
            return
        sql = (f"SELECT descript, builtdate "
               f"FROM cat_work "
               f"WHERE id = '{workcat_id}'")
        row = self.controller.get_row(sql)
        if row:
            qt_tools.setText(self.dlg_work_end, self.dlg_work_end.descript,
                             row['descript'])
            qt_tools.setCalendarDate(self.dlg_work_end,
                                     self.dlg_work_end.builtdate,
                                     row['builtdate'], False)
        else:
            qt_tools.setText(self.dlg_work_end, self.dlg_work_end.descript, '')
            qt_tools.setCalendarDate(self.dlg_work_end,
                                     self.dlg_work_end.builtdate, None, False)

    def get_list_selected_id(self, qtable):

        selected_list = qtable.model()
        self.selected_list = []
        ids_list = ""
        if selected_list is None:
            self.manage_close(self.dlg_work_end,
                              self.table_object,
                              self.cur_active_layer,
                              force_downgrade=False)
            return

        for x in range(0, selected_list.rowCount()):
            index = selected_list.index(x, 0)
            id_ = selected_list.data(index)
            self.selected_list.append(id_)
            ids_list += f"'{id_}',"
        ids_list = ids_list[:-1]

        return ids_list

    def manage_workcat_end_accept(self):
        """ Get elements from all the tables and update his data """

        # Setting values
        self.workcat_id_end = qt_tools.getWidgetText(
            self.dlg_work_end, self.dlg_work_end.workcat_id_end)
        self.enddate = qt_tools.getCalendarDate(self.dlg_work_end,
                                                self.dlg_work_end.enddate)
        self.statetype_id_end = qt_tools.get_item_data(
            self.dlg_work_end, self.dlg_work_end.cmb_statetype_end, 0)

        if self.workcat_id_end in ('null', None):
            message = "Please select a workcat id end"
            self.controller.show_warning(message)
            return

        ids_list = self.get_list_selected_id(
            self.dlg_work_end.tbl_cat_work_x_arc)
        row = None
        if ids_list:
            sql = (f"SELECT * FROM v_ui_arc_x_relations "
                   f"WHERE arc_id IN ( {ids_list}) AND arc_state = '1'")
            row = self.controller.get_row(sql)

        if row:
            self.dlg_work = FeatureEndConnecUi()
            self.load_settings(self.dlg_work)

            self.dlg_work.btn_cancel.clicked.connect(
                partial(self.close_dialog_workcat_list, self.dlg_work))
            self.dlg_work.btn_accept.clicked.connect(self.exec_downgrade)
            self.set_completer()

            table_relations = "v_ui_arc_x_relations"
            self.dlg_work.arc_id.textChanged.connect(
                partial(self.filter_by_id, self.dlg_work.tbl_arc_x_relations,
                        self.dlg_work.arc_id, table_relations))

            self.tbl_arc_x_relations = self.dlg_work.findChild(
                QTableView, "tbl_arc_x_relations")
            self.tbl_arc_x_relations.setSelectionBehavior(
                QAbstractItemView.SelectRows)

            filter_ = ""
            for row in self.selected_list:
                filter_ += f"arc_id = '{row}' OR "
            filter_ = filter_[:-3] + ""
            filter_ += " AND arc_state = '1' "

            self.fill_table(self.tbl_arc_x_relations, table_relations, filter_)
            self.tbl_arc_x_relations.doubleClicked.connect(
                partial(self.open_selected_object, self.tbl_arc_x_relations))

            self.open_dialog(self.dlg_work, dlg_name='feature_end_connec')

        # TODO: Function update_geom_type() don't use parameter ids_list
        else:
            # Update tablename of every geom_type
            ids_list = self.get_list_selected_id(
                self.dlg_work_end.tbl_cat_work_x_arc)
            self.update_geom_type("arc", ids_list)
            ids_list = self.get_list_selected_id(
                self.dlg_work_end.tbl_cat_work_x_node)
            self.update_geom_type("node", ids_list)
            ids_list = self.get_list_selected_id(
                self.dlg_work_end.tbl_cat_work_x_connec)
            self.update_geom_type("connec", ids_list)
            ids_list = self.get_list_selected_id(
                self.dlg_work_end.tbl_cat_work_x_element)
            self.update_geom_type("element", ids_list)
            if str(self.project_type) == 'ud':
                ids_list = self.get_list_selected_id(
                    self.dlg_work_end.tbl_cat_work_x_gully)
                self.update_geom_type("gully", ids_list)

            self.manage_close(self.dlg_work_end,
                              self.table_object,
                              self.cur_active_layer,
                              force_downgrade=True)

            # Remove selection for all layers in TOC
            for layer in self.iface.mapCanvas().layers():
                if layer.type() == layer.VectorLayer:
                    layer.removeSelection()
            self.iface.mapCanvas().refresh()

    def update_geom_type(self, geom_type, ids_list):
        """ Get elements from @geom_type and update his corresponding table """

        tablename = "v_edit_" + geom_type
        if self.selected_list is None:
            return

        sql = ""
        for id_ in self.selected_list:
            sql += (
                f"UPDATE {tablename} "
                f"SET state = '0', state_type = '{self.statetype_id_end}', workcat_id_end = '{self.workcat_id_end}', "
                f"enddate = '{self.enddate}' "
                f"WHERE {geom_type}_id = '{id_}';\n")
        if sql != "":
            status = self.controller.execute_sql(sql, log_sql=False)
            if status:
                self.controller.show_info("Features updated successfully!")

    def fill_table(self, widget, table_name, filter_):
        """ Set a model with selected filter.
        Attach that model to selected table """

        if self.schema_name not in table_name:
            table_name = self.schema_name + "." + table_name

        # Set model
        self.model = QSqlTableModel()
        self.model.setTable(table_name)
        self.model.setEditStrategy(QSqlTableModel.OnManualSubmit)
        if filter_:
            self.model.setFilter(filter_)
        self.model.setSort(0, 0)
        self.model.select()

        # Check for errors
        if self.model.lastError().isValid():
            self.controller.show_warning(self.model.lastError().text())

        # Attach model to table view
        widget.setModel(self.model)

    def open_selected_object(self, widget):
        """ Open object form with selected record of the table """

        selected_list = widget.selectionModel().selectedRows()
        if len(selected_list) == 0:
            message = "Any record selected"
            self.controller.show_warning(message)
            return

        row = selected_list[0].row()
        feature_id = widget.model().record(row).value("arc_id")

        self.open_arc_form(feature_id)

    def open_arc_form(self, arc_id):
        """ Open form corresponding to start or end node of the current arc """

        # Get sys_feature_cat.id from cat_feature.id
        sql = (f"SELECT sys_type"
               f" FROM v_edit_arc"
               f" WHERE arc_id = '{arc_id}'")
        row = self.controller.get_row(sql)
        if not row:
            return

        arc_type = row[0].lower()
        arc_table = "v_edit_man_" + arc_type
        layer_arc = self.controller.get_layer_by_tablename(arc_table)

        aux = "\"arc_id\" = "
        aux += f"'{arc_id}'"
        expr = QgsExpression(aux)
        if expr.hasParserError():
            message = "Expression Error"
            self.controller.show_warning(message,
                                         parameter=expr.parserErrorString())
            return

        id_list = None
        if layer_arc:
            # Get a featureIterator from this expression:
            it = layer_arc.getFeatures(QgsFeatureRequest(expr))
            id_list = [i for i in it]
            if id_list:
                self.iface.openFeatureForm(layer_arc, id_list[0])

        # Zoom to object
        if id_list:
            canvas = self.iface.mapCanvas()
            layer_arc.selectByIds([id_list[0].id()])
            canvas.zoomToSelected(layer_arc)
            canvas.zoomIn()

    def exec_downgrade(self):

        message = "Are you sure you want to disconnect this elements?"
        title = "Disconnect elements"
        answer = self.controller.ask_question(message, title)
        if not answer:
            return

        # Update tablename of every geom_type
        ids_list = self.get_list_selected_id(
            self.dlg_work_end.tbl_cat_work_x_arc)
        self.update_geom_type("arc", ids_list)

        self.canvas.refresh()
        self.dlg_work.close()
        self.manage_workcat_end_accept()

    def set_completer(self):
        """ Set autocompleters of the form """

        # Adding auto-completion to a QLineEdit - visit_id
        self.completer = QCompleter()
        self.dlg_work.arc_id.setCompleter(self.completer)
        model = QStringListModel()

        model.setStringList(self.selected_list)
        self.completer.setModel(model)

    def filter_by_id(self, table, widget_txt, tablename):

        id_ = qt_tools.getWidgetText(self.dlg_work, widget_txt)
        if id_ != 'null':
            expr = f" arc_id = '{id_}'"
            # Refresh model with selected filter
            table.model().setFilter(expr)
            table.model().select()
        else:
            self.fill_table_relations(table,
                                      self.schema_name + "." + tablename)

    def fill_table_relations(self, widget, table_name):
        """ Set a model with selected filter. Attach that model to selected table """

        if self.schema_name not in table_name:
            table_name = self.schema_name + "." + table_name

        filter_ = ""
        for row in self.selected_list:
            filter_ += f"arc_id = '{row}' OR "
        filter_ = filter_[:-3] + ""
        filter_ += " AND arc_state = '1' "

        # Set model
        model = QSqlTableModel()
        model.setTable(table_name)
        model.setEditStrategy(QSqlTableModel.OnManualSubmit)
        model.setFilter(filter_)
        model.select()

        # Check for errors
        if model.lastError().isValid():
            self.controller.show_warning(model.lastError().text())

        # Attach model to table view
        widget.setModel(model)
        widget.show()

    def close_dialog_workcat_list(self, dlg=None):
        """ Close dialog """

        try:
            self.save_settings(dlg)
            dlg.close()
            map_tool = self.canvas.mapTool()
            # If selected map tool is from the plugin, set 'Pan' as current one
            if map_tool.toolName() == '':
                self.iface.actionPan().trigger()
        except AttributeError:
            pass

        self.open_dialog(self.dlg_work_end)

    def manage_close(self,
                     dialog,
                     table_object,
                     cur_active_layer=None,
                     force_downgrade=False,
                     show_warning=False):
        """ Close dialog and disconnect snapping """

        self.close_dialog(dialog)
        self.hide_generic_layers(excluded_layers=["v_edit_element"])
        self.disconnect_snapping()
        self.disconnect_signal_selection_changed()
        if force_downgrade:
            sql = ("SELECT feature_type, feature_id, log_message "
                   "FROM audit_log_data "
                   "WHERE  fid = 128 AND cur_user = current_user")
            rows = self.controller.get_rows(sql, log_sql=False)
            ids_ = ""
            if rows:
                for row in rows:
                    ids_ += str(row[1]) + ", "
                    state_statetype = str(row['log_message']).split(',')
                    sql = (
                        f"UPDATE {row[0].lower()} "
                        f"SET state = '{state_statetype[0]}', state_type = '{state_statetype[1]}' "
                        f"WHERE {row[0]}_id = '{row[1]}';")
                    self.controller.execute_sql(sql)

                ids_ = ids_[:-2]
                if show_warning and len(ids_) != 0:
                    msg = 'These items could not be downgrade to state 0'
                    self.controller.show_info_box(msg,
                                                  title="Warning",
                                                  inf_text=str(ids_))
                sql = ("DELETE FROM audit_log_data "
                       "WHERE fid = 128 AND cur_user = current_user")
                self.controller.execute_sql(sql)
        self.set_edit_arc_downgrade_force('False')
        self.canvas.refresh()

    def new_workcat(self):

        self.dlg_new_workcat = InfoWorkcatUi()
        self.load_settings(self.dlg_new_workcat)

        qt_tools.setCalendarDate(self.dlg_new_workcat,
                                 self.dlg_new_workcat.builtdate, None, True)
        table_object = "cat_work"
        self.set_completer_widget(table_object,
                                  self.dlg_new_workcat.cat_work_id, 'id')

        # Set signals
        self.dlg_new_workcat.btn_accept.clicked.connect(
            partial(self.manage_new_workcat_accept, table_object))
        self.dlg_new_workcat.btn_cancel.clicked.connect(
            partial(self.close_dialog, self.dlg_new_workcat))

        # Open dialog
        self.open_dialog(self.dlg_new_workcat, dlg_name='info_workcat')

    def manage_new_workcat_accept(self, table_object):
        """ Insert table 'cat_work'. Add cat_work """

        # Get values from dialog
        values = ""
        fields = ""

        cat_work_id = qt_tools.getWidgetText(self.dlg_new_workcat,
                                             self.dlg_new_workcat.cat_work_id)
        if cat_work_id != "null":
            fields += 'id, '
            values += f"'{cat_work_id}', "
        descript = qt_tools.getWidgetText(self.dlg_new_workcat, "descript")
        if descript != "null":
            fields += 'descript, '
            values += f"'{descript}', "
        link = qt_tools.getWidgetText(self.dlg_new_workcat, "link")
        if link != "null":
            fields += 'link, '
            values += f"'{link}', "
        workid_key_1 = qt_tools.getWidgetText(self.dlg_new_workcat,
                                              "workid_key_1")
        if workid_key_1 != "null":
            fields += 'workid_key1, '
            values += f"'{workid_key_1}', "
        workid_key_2 = qt_tools.getWidgetText(self.dlg_new_workcat,
                                              "workid_key_2")
        if workid_key_2 != "null":
            fields += 'workid_key2, '
            values += f"'{workid_key_2}', "
        builtdate = self.dlg_new_workcat.builtdate.dateTime().toString(
            'yyyy-MM-dd')

        if builtdate != "null":
            fields += 'builtdate, '
            values += f"'{builtdate}', "

        if values == "":
            return

        fields = fields[:-2]
        values = values[:-2]
        if cat_work_id == 'null':
            msg = "Work_id field is empty"
            self.controller.show_info_box(msg, "Warning")
        else:
            # Check if this element already exists
            sql = (f"SELECT DISTINCT(id)"
                   f" FROM {table_object}"
                   f" WHERE id = '{cat_work_id}'")
            row = self.controller.get_row(sql, log_info=False, log_sql=True)
            if row is None:
                sql = f"INSERT INTO cat_work ({fields}) VALUES ({values})"
                self.controller.execute_sql(sql, log_sql=True)
                sql = "SELECT id FROM cat_work ORDER BY id"
                rows = self.controller.get_rows(sql)
                if rows:
                    qt_tools.fillComboBox(self.dlg_work_end,
                                          self.dlg_work_end.workcat_id_end,
                                          rows)
                    aux = self.dlg_work_end.workcat_id_end.findText(
                        str(cat_work_id))
                    self.dlg_work_end.workcat_id_end.setCurrentIndex(aux)

                self.close_dialog(self.dlg_new_workcat)

            else:
                msg = "This Workcat already exist"
                self.controller.show_info_box(msg, "Warning")
Example #21
0
class TmParentAction(object):
    def __init__(self, iface, settings, controller, plugin_dir):
        """ Class constructor """

        # Initialize instance attributes
        self.tree_manage_version = "1.0"
        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.settings = settings
        self.controller = controller
        self.plugin_dir = plugin_dir
        self.dao = self.controller.dao
        self.schema_name = self.controller.schema_name
        self.project_type = None
        self.file_gsw = None
        self.gsw_settings = None
        self.lazy_widget = None

    def set_controller(self, controller):
        """ Set controller class """

        self.controller = controller
        self.schema_name = self.controller.schema_name

    def get_plugin_version(self):
        """ Get plugin version from metadata.txt file """

        # Check if metadata file exists
        metadata_file = os.path.join(self.plugin_dir, 'metadata.txt')
        if not os.path.exists(metadata_file):
            message = "Metadata file not found" + metadata_file
            self.controller.show_warning(message, parameter=metadata_file)
            return None

        metadata = configparser.ConfigParser()
        metadata.read(metadata_file)
        plugin_version = metadata.get('general', 'version')
        if plugin_version is None:
            message = "Plugin version not found"
            self.controller.show_warning(message)

        return plugin_version

    def load_settings(self, dialog=None):
        """ Load QGIS settings related with dialog position and size """

        if dialog is None:
            dialog = self.dlg

        try:
            screens = ctypes.windll.user32
            screen_x = screens.GetSystemMetrics(78)
            screen_y = screens.GetSystemMetrics(79)
            x = self.controller.plugin_settings_value(dialog.objectName() +
                                                      "_x")
            y = self.controller.plugin_settings_value(dialog.objectName() +
                                                      "_y")
            width = self.controller.plugin_settings_value(
                dialog.objectName() + "_width", dialog.property('width'))
            height = self.controller.plugin_settings_value(
                dialog.objectName() + "_height", dialog.property('height'))

            if int(x) < 0 or int(y) < 0:
                dialog.resize(int(width), int(height))
            else:
                if int(x) > screen_x:
                    x = int(screen_x) - int(width)
                if int(y) > screen_y:
                    y = int(screen_y)
                dialog.setGeometry(int(x), int(y), int(width), int(height))
        except:
            pass

    def save_settings(self, dialog=None):
        """ Save QGIS settings related with dialog position and size """

        if dialog is None:
            dialog = self.dlg

        self.controller.plugin_settings_set_value(
            dialog.objectName() + "_width", dialog.width())
        self.controller.plugin_settings_set_value(
            dialog.objectName() + "_height", dialog.height())
        self.controller.plugin_settings_set_value(dialog.objectName() + "_x",
                                                  dialog.pos().x() + 8)
        self.controller.plugin_settings_set_value(dialog.objectName() + "_y",
                                                  dialog.pos().y() + 31)

    def open_dialog(self,
                    dlg=None,
                    dlg_name=None,
                    info=True,
                    maximize_button=True,
                    stay_on_top=True):
        """ Open dialog """

        # Check database connection before opening dialog
        if not self.controller.check_db_connection():
            return

        if dlg is None or type(dlg) is bool:
            dlg = self.dlg

        # Manage i18n of the dialog
        if dlg_name:
            self.controller.manage_translation(dlg_name, dlg)

        # Manage stay on top, maximize/minimize button and information button
        # if info is True maximize flag will be ignored
        # To enable maximize button you must set info to False
        flags = Qt.WindowCloseButtonHint
        if info:
            flags |= Qt.WindowSystemMenuHint | Qt.WindowContextHelpButtonHint
        else:
            if maximize_button:
                flags |= Qt.WindowMinMaxButtonsHint

        if stay_on_top:
            flags |= Qt.WindowStaysOnTopHint

        dlg.setWindowFlags(flags)

        # Open dialog
        if issubclass(type(dlg), GwDialog):
            dlg.open()
        elif issubclass(type(dlg), GwMainWindow):
            dlg.show()
        else:
            dlg.show()

    def close_dialog(self, dlg=None):
        """ Close dialog """

        try:
            self.save_settings(dlg)
            dlg.close()
            map_tool = self.canvas.mapTool()
            # If selected map tool is from the plugin, set 'Pan' as current one
            if map_tool.toolName() == '':
                self.iface.actionPan().trigger()
        except AttributeError:
            pass

    def hide_colums(self, widget, comuns_to_hide):
        for i in range(0, len(comuns_to_hide)):
            widget.hideColumn(comuns_to_hide[i])

    def set_icon(self, widget, icon):
        """ Set @icon to selected @widget """

        # Get icons folder
        icons_folder = os.path.join(self.plugin_dir, 'icons')
        icon_path = os.path.join(icons_folder, str(icon) + ".png")
        if os.path.exists(icon_path):
            widget.setIcon(QIcon(icon_path))
        else:
            self.controller.log_info("File not found", parameter=icon_path)

    def check_expression(self, expr_filter, log_info=False):
        """ Check if expression filter @expr_filter is valid """

        if log_info:
            self.controller.log_info(expr_filter)
        expr = QgsExpression(expr_filter)
        if expr.hasParserError():
            message = "Expression Error"
            self.controller.log_warning(message, parameter=expr_filter)
            return False, expr

        return True, expr

    def set_table_columns(self, dialog, widget, table_name, project_type=None):
        """ Configuration of tables. Set visibility and width of columns """

        widget = utils_giswater.getWidget(dialog, widget)
        if not widget:
            return

        # Set width and alias of visible columns
        columns_to_delete = []
        sql = (f"SELECT columnindex, width, alias, status"
               f" FROM config_form_tableview"
               f" WHERE tablename = '{table_name}'")
        if project_type is not None:
            sql += f" AND project_type = '{project_type}' "
        sql += " ORDER BY column_index"

        rows = self.controller.get_rows(sql, log_info=False)
        if not rows:
            return

        for row in rows:
            if not row['status']:
                columns_to_delete.append(row['columnindex'] - 1)
            else:
                width = row['width']
                if width is not None:
                    widget.setColumnWidth(row['columnindex'] - 1, width)
                widget.model().setHeaderData(row['columnindex'] - 1,
                                             Qt.Horizontal, row['alias'])

        widget.model().select()

        # Delete columns
        for column in columns_to_delete:
            widget.hideColumn(column)

    def set_completer_object(self, tablename, widget, field_search):
        """ Set autocomplete of widget @table_object + "_id"
            getting id's from selected @table_object
        """

        if not widget:
            return

        # Set SQL
        sql = (f"SELECT DISTINCT({field_search})"
               f" FROM {tablename}"
               f" ORDER BY {field_search}")
        rows = self.controller.get_rows(sql)
        if rows is None:
            return

        for i in range(0, len(rows)):
            aux = rows[i]
            rows[i] = aux[0]

        # Set completer and model: add autocomplete in the widget
        self.completer = QCompleter()
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.completer.setCompletionMode(0)
        widget.setCompleter(self.completer)
        model = QStringListModel()
        model.setStringList(rows)
        self.completer.setModel(model)

    def refresh_map_canvas(self, restore_cursor=False):
        """ Refresh all layers present in map canvas """

        self.canvas.refreshAllLayers()
        for layer_refresh in self.canvas.layers():
            layer_refresh.triggerRepaint()

        if restore_cursor:
            self.set_cursor_restore()

    def set_cursor_restore(self):
        """ Restore to previous cursors """
        QApplication.restoreOverrideCursor()

    def get_cursor_multiple_selection(self):
        """ Set cursor for multiple selection """

        path_folder = os.path.join(os.path.dirname(__file__), os.pardir)
        path_cursor = os.path.join(path_folder, 'icons', '201.png')
        if os.path.exists(path_cursor):
            cursor = QCursor(QPixmap(path_cursor))
        else:
            cursor = QCursor(Qt.ArrowCursor)

        return cursor

    def fill_table(self,
                   qtable,
                   table_name,
                   set_edit_triggers=QTableView.NoEditTriggers,
                   expr_filter=None):
        """ Fill table @widget filtering query by @workcat_id
            Set a model with selected filter.
            Attach that model to selected table
            @setEditStrategy:
             0: OnFieldChange
             1: OnRowChange
             2: OnManualSubmit
        """

        expr = None
        if expr_filter:
            # Check expression
            (is_valid,
             expr) = self.check_expression(expr_filter)  # @UnusedVariable
            if not is_valid:
                return expr

        # Set a model with selected filter expression
        if self.schema_name not in table_name:
            table_name = self.schema_name + "." + table_name

        # Set model
        model = QSqlTableModel()
        model.setTable(table_name)
        model.setEditStrategy(QSqlTableModel.OnManualSubmit)
        model.setSort(0, 0)
        model.select()

        # When change some field we need to refresh Qtableview and filter by psector_id
        qtable.setEditTriggers(set_edit_triggers)

        # Check for errors
        if model.lastError().isValid():
            self.controller.show_warning(model.lastError().text())
        # Attach model to table view
        if expr:
            qtable.setModel(model)
            qtable.model().setFilter(expr_filter)
        else:
            qtable.setModel(model)

        return expr

    def get_feature_by_id(self, layer, id, field_id):

        features = layer.getFeatures()
        for feature in features:
            if feature[field_id] == id:
                return feature

        return False

    def put_combobox(self, qtable, rows, combo_values, field, combo_pos,
                     col_update):
        """ Set one column of a QtableView as QComboBox with values from database.
        :param qtable: QTableView to fill
        :param rows: List of items to set QComboBox (["..", "..."])
        :param combo_values: List of items to populate QComboBox (["..", "..."])
        :param field: Field to set QComboBox (String)
        :param combo_pos: Position of the column where we want to put the QComboBox (integer)
        :param col_update: Column to update into QTableView.Model() (integer)
        :return:
        """
        self.controller.log_info(str())
        for x, row in enumerate(rows):
            combo = QComboBox()
            combo.setSizeAdjustPolicy(2)
            # Populate QComboBox
            utils_giswater.set_item_data(combo, combo_values, 1)
            # Set QCombobox to wanted item
            utils_giswater.set_combo_itemData(combo, str(row[field]), 0)
            # Get index and put QComboBox into QTableView at index position
            idx = qtable.model().index(x, combo_pos)
            qtable.setIndexWidget(idx, combo)
            combo.currentIndexChanged.connect(
                partial(self.update_real_field, qtable, combo, x, combo_pos,
                        col_update))

    def update_real_field(self, qtable, combo, pos_x, combo_pos, col_update):
        """ Update values from QComboBox to QTableView
        :param qtable: QTableView Where update values
         :param combo: QComboBox from which we will take the value
        :param pos_x: Position of the row where we want to update value (integer)
        :param combo_pos: Position of the column where we want to put the QComboBox (integer)
        :param col_update: Column to update into QTableView.Model() (integer)
        :return:
        """

        elem = combo.itemData(combo.currentIndex())
        i = qtable.model().index(pos_x, combo_pos)
        qtable.model().setData(i, elem[0])
        i = qtable.model().index(pos_x, col_update)
        qtable.model().setData(i, elem[0])

    def create_body(self, form='', feature='', filter_fields='', extras=None):
        """ Create and return parameters as body to functions"""

        client = f'$${{"client":{{"device":4, "infoType":1, "lang":"ES"}}, '
        form = '"form":{' + form + '}, '
        feature = '"feature":{' + feature + '}, '
        filter_fields = '"filterFields":{' + filter_fields + '}'
        page_info = '"pageInfo":{}'
        data = '"data":{' + filter_fields + ', ' + page_info
        if extras is not None:
            data += ', ' + extras
        data += f'}}}}$$'
        body = "" + client + form + feature + data

        return body

    def set_dates_from_to(self, widget_from, widget_to, table_name, field_from,
                          field_to):

        sql = ("SELECT MIN(LEAST(" + field_from + ", " + field_to + ")),"
               " MAX(GREATEST(" + field_from + ", " + field_to + "))"
               " FROM " + table_name + "")
        row = self.controller.get_row(sql, log_sql=False)
        current_date = QDate.currentDate()
        if row:
            if row[0]:
                widget_from.setDate(row[0])
            else:
                widget_from.setDate(current_date)
            if row[1]:
                widget_to.setDate(row[1])
            else:
                widget_to.setDate(current_date)

    def remove_selection(self):
        """ Remove selected features of all layers """

        for layer in self.canvas.layers():
            if type(layer) is QgsVectorLayer:
                layer.removeSelection()
        self.canvas.refresh()

        for a in self.iface.attributesToolBar().actions():
            if a.objectName() == 'mActionDeselectAll':
                a.trigger()
                break
class geopunt4QgisDataCatalog(QDialog):
    def __init__(self, iface):
        QDialog.__init__(self, None)
        self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
        self.iface = iface

        # initialize locale
        locale = QSettings().value("locale/userLocale", "en")
        if not locale: locale = 'en'
        else: locale = locale[0:2]
        localePath = os.path.join(os.path.dirname(__file__), 'i18n', 'geopunt4qgis_{}.qm'.format(locale))
        if os.path.exists(localePath):
            self.translator = QTranslator()
            self.translator.load(localePath)
            QCoreApplication.installTranslator(self.translator)

        self._initGui()

    def _initGui(self):
        """setup the user interface"""
        self.ui = Ui_geopunt4QgisDataCatalogDlg()
        self.ui.setupUi(self)

        # get settings
        self.s = QSettings()
        self.loadSettings()

        self.gh = geometryHelper(self.iface)

        # setup a message bar
        self.bar = QgsMessageBar()
        self.bar.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.ui.verticalLayout.addWidget(self.bar)

        self.ui.buttonBox.addButton(QPushButton("Sluiten"), QDialogButtonBox.RejectRole)
        for btn in self.ui.buttonBox.buttons():
            btn.setAutoDefault(0)

        # vars
        self.firstShow = True
        self.wms = None
        self.wfs = None
        self.dl = None
        self.zoek = ''
        self.bronnen = None

        self.model = QStandardItemModel(self)
        self.proxyModel = QSortFilterProxyModel(self)
        self.proxyModel.setSourceModel(self.model)
        self.ui.resultView.setModel(self.proxyModel)

        self.completer = QCompleter(self)
        self.completerModel = QStringListModel(self)
        self.ui.zoekTxt.setCompleter(self.completer)
        self.completer.setModel(self.completerModel)

        # eventhandlers
        self.ui.zoekBtn.clicked.connect(self.onZoekClicked)
        self.ui.addWMSbtn.clicked.connect(self.addWMS)
        self.ui.addWFSbtn.clicked.connect(self.addWFS)
        self.ui.DLbtn.clicked.connect(lambda: self.openUrl(self.dl))
        self.ui.resultView.clicked.connect(self.resultViewClicked)
        self.ui.modelFilterCbx.currentIndexChanged.connect(self.modelFilterCbxIndexChanged)
        self.ui.filterWgt.setHidden(1)
        self.ui.buttonBox.helpRequested.connect(self.openHelp)
        self.finished.connect(self.clean)

    def loadSettings(self):
        self.timeout = int(self.s.value("geopunt4qgis/timeout", 15))
        if settings().proxyUrl:
            self.proxy = settings().proxyUrl
        else:
            self.proxy = ""

        self.md = MDReader(self.timeout, self.proxy)

    def openHelp(self):
        webbrowser.open_new_tab("http://www.geopunt.be/voor-experts/geopunt-plug-ins/functionaliteiten/catalogus")

    def _setModel(self, records):
        self.model.clear()
        records = sorted(records, key=lambda k: k['title']) 

        for rec in records:
            title = QStandardItem(rec['title'])  # 0
            wms = QStandardItem(rec['wms'])  # 1
            downloadLink = QStandardItem(rec['download'])  # 2
            id = QStandardItem(rec['uuid'])  # 3
            abstract = QStandardItem(rec['abstract'])  # 4
            wfs = QStandardItem(rec['wfs'])  # 5
            self.model.appendRow([title, wms, downloadLink, id, abstract, wfs])

    # overwrite
    def show(self):
        QDialog.show(self)
        self.setWindowModality(0)
        metadataUrl = "https://metadata.geopunt.be"
        inet = internet_on(proxyUrl=self.proxy, timeout=self.timeout, testSite= metadataUrl)
        if not inet:
            msg = "Kan geen verbing maken met de metadata van Geopunt: {} \nMogelijke is deze site niet bereikbaar, dan zal deze tool ook niet werken.\nProbeer later opnieuw. Indien dit probleem zich blijft voordoen contacteer informatie Vlaanderen.".format(metadataUrl)
            QMessageBox.warning(self.iface.mainWindow(),  "Waarschuwing: kan geen verbinding maken", msg)
            self.bar.pushMessage( QCoreApplication.translate("geopunt4QgisPoidialog","Waarschuwing"),  msg, level=Qgis.Warning, duration=3)  
            return 
        
        if self.firstShow:
            self.ui.GDIThemaCbx.addItems([''] + self.md.list_GDI_theme())
            self.ui.organisatiesCbx.addItems([''] + self.md.list_organisations())
            keywords = sorted(self.md.list_suggestionKeyword())
            self.completerModel.setStringList(keywords)
            self.bronnen = self.md.list_bronnen()
            self.ui.bronCbx.addItems([''] + [n[1] for n in self.bronnen])
            self.ui.typeCbx.addItems([''] + [n[0] for n in self.md.dataTypes])

            self.ui.INSPIREannexCbx.addItems([''] + self.md.inspireannex)
            self.ui.INSPIREserviceCbx.addItems([''] + self.md.inspireServiceTypes)
            self.ui.INSPIREthemaCbx.addItems([''] + self.md.list_inspire_theme())
            self.firstShow = False


    # eventhandlers
    def resultViewClicked(self):
        if self.ui.resultView.selectedIndexes():
            row = self.ui.resultView.selectedIndexes()[0].row()

            title = self.proxyModel.data(self.proxyModel.index(row, 0))
            self.wms = self.proxyModel.data(self.proxyModel.index(row, 1))
            self.dl = self.proxyModel.data(self.proxyModel.index(row, 2))
            self.wfs = self.proxyModel.data(self.proxyModel.index(row, 5))
            uuid = self.proxyModel.data(self.proxyModel.index(row, 3))
            abstract = self.proxyModel.data(self.proxyModel.index(row, 4))

            self.ui.descriptionText.setText(
                """<h3>%s</h3><div>%s</div><br/><div>
             <a href='https://metadata.geopunt.be/zoekdienst/apps/tabsearch/index.html?uuid=%s'>
             Ga naar fiche</a></div>""" % (title, abstract, uuid))

            if self.wms:
                self.ui.addWMSbtn.setEnabled(1)
            else:
                self.ui.addWMSbtn.setEnabled(0)

            if self.wfs:
                self.ui.addWFSbtn.setEnabled(1)
            else:
                self.ui.addWFSbtn.setEnabled(0)

            if self.dl:
                self.ui.DLbtn.setEnabled(1)
            else:
                self.ui.DLbtn.setEnabled(0)

    def onZoekClicked(self):
        self.zoek = self.ui.zoekTxt.currentText()
        self.search()

    def modelFilterCbxIndexChanged(self):
        value = self.ui.modelFilterCbx.currentIndex()
        if value == 1:
            self.filterModel(1)
        elif value == 2:
            self.filterModel(5)
        elif value == 3:
            self.filterModel(2)
        else:
            self.filterModel()

    def filterModel(self, col=None):
        if col != None:
            self.proxyModel.setFilterKeyColumn(col)
            expr = QRegExp("?*", Qt.CaseInsensitive, QRegExp.Wildcard)
            self.proxyModel.setFilterRegExp(expr)
        else:
            self.proxyModel.setFilterRegExp(None)

    def search(self):
        try:
            if self.ui.filterBox.isChecked():
                themekey = self.ui.GDIThemaCbx.currentText()
                orgName = self.ui.organisatiesCbx.currentText()
                dataTypes = [n[1] for n in self.md.dataTypes if n[0] == self.ui.typeCbx.currentText()]
                if dataTypes != []:
                    dataType = dataTypes[0]
                else:
                    dataType = ''
                siteIds = [n[0] for n in self.bronnen if n[1] == self.ui.bronCbx.currentText()]
                if siteIds != []:
                    siteId = siteIds[0]
                else:
                    siteId = ''
                inspiretheme = self.ui.INSPIREthemaCbx.currentText()
                inspireannex = self.ui.INSPIREannexCbx.currentText()
                inspireServiceType = self.ui.INSPIREserviceCbx.currentText()
                searchResult = MDdata(self.md.searchAll(
                    self.zoek, themekey, orgName, dataType, siteId, inspiretheme, inspireannex, inspireServiceType))
            else:
                searchResult = MDdata(self.md.searchAll(self.zoek))
        except:
            self.bar.pushMessage("Error", str(sys.exc_info()[1]), level=Qgis.Critical, duration=3)
            return

        self.ui.countLbl.setText("Aantal gevonden: %s" % searchResult.count)
        self.ui.descriptionText.setText('')
        self._setModel(searchResult.records)
        if searchResult.count == 0:
            self.bar.pushMessage(
                QCoreApplication.translate("geopunt4QgisPoidialog", "Waarschuwing "),
                QCoreApplication.translate("geopunt4QgisPoidialog",
                                                  "Er werden geen resultaten gevonde voor deze zoekopdracht"),
                duration=5)

    def openUrl(self, url):
        if url: webbrowser.open_new_tab(url.encode("utf-8"))

    def addWMS(self):
        if self.wms == None: return

        crs = self.gh.getGetMapCrs(self.iface).authid()
        if crs != 'EPSG:31370' or crs != 'EPSG:3857' or crs != 'EPSG:3043':
            crs = 'EPSG:31370'
        try:
            lyrs = getWmsLayerNames(self.wms, self.proxy)
        except:
            self.bar.pushMessage("Error", str(sys.exc_info()[1]), level=Qgis.Critical, duration=10)
            return
        if len(lyrs) == 0:
            self.bar.pushMessage("WMS",
                                 QCoreApplication.translate("geopunt4QgisDataCatalog",
                                                                   "Kan geen lagen vinden in: %s" % self.wms),
                                 level=Qgis.Warning, duration=10)
            return
        elif len(lyrs) == 1:
            layerTitle = lyrs[0][1]
        else:
            layerTitle, accept = QInputDialog.getItem(self, "WMS toevoegen",
                                                            "Kies een laag om toe te voegen", [n[1] for n in lyrs],
                                                            editable=0)
            if not accept: return

        layerName = [n[0] for n in lyrs if n[1] == layerTitle][0]
        style = [n[2] for n in lyrs if n[1] == layerTitle][0]
        if not style: style = ""
        
        url = self.wms.split('?')[0]

        if crs != 'EPSG:31370' or crs != 'EPSG:3857':
            crs = 'EPSG:31370'
        wmsUrl = "contextualWMSLegend=0&dpiMode=7&url=%s&layers=%s&format=image/png&styles=%s&crs=%s" % (
                                                                         url, layerName, style, crs)

        try:
            rlayer = QgsRasterLayer(wmsUrl, layerTitle, 'wms')
            if rlayer.isValid():
                QgsProject.instance().addMapLayer(rlayer)
            else:
                self.bar.pushMessage("Error",
                                     QCoreApplication.translate("geopunt4QgisDataCatalog", "Kan WMS niet laden"),
                                     level=Qgis.Critical, duration=10)
        except:
            self.bar.pushMessage("Error", str(sys.exc_info()[1]), level=Qgis.Critical, duration=10)
            return

    def addWFS(self):
        if self.wfs == None: return
        try:
            lyrs = getWFSLayerNames(self.wfs, self.proxy)
        except:
            self.bar.pushMessage("Error", str(sys.exc_info()[1]), level=Qgis.Critical, duration=10)
            return
        if len(lyrs) == 0:
            self.bar.pushMessage("WFS",
                 QCoreApplication.translate("geopunt4QgisDataCatalog",
                 "Kan geen lagen vinden in: %s" % self.wfs), level=Qgis.Warning, duration=10)
            return
        elif len(lyrs) == 1:
            layerTitle = lyrs[0][1]
        else:
            layerTitle, accept = QInputDialog.getItem(self, "WFS toevoegen",
                                                            "Kies een laag om toe te voegen", [n[1] for n in lyrs],
                                                            editable=0)
            if not accept: return

        layerName = [n[0] for n in lyrs if n[1] == layerTitle][0]
        crs = [n[2] for n in lyrs if n[1] == layerTitle][0]
        url = self.wfs.split('?')[0]

        wfsUri = makeWFSuri(url, layerName, crs )

        try:
          vlayer = QgsVectorLayer(wfsUri, layerTitle, "WFS")
          QgsProject.instance().addMapLayer(vlayer)
        except:
            self.bar.pushMessage("Error", str(sys.exc_info()[1]), level=Qgis.Critical, duration=10)
            return

    def clean(self):
        self.model.clear()
        self.wms = None
        self.wfs = None
        self.dl = None
        self.ui.zoekTxt.setCurrentIndex(0)
        self.ui.descriptionText.setText('')
        self.ui.countLbl.setText("")
        self.ui.msgLbl.setText("")
        self.ui.DLbtn.setEnabled(0)
        self.ui.addWFSbtn.setEnabled(0)
        self.ui.addWMSbtn.setEnabled(0)
        self.ui.modelFilterCbx.setCurrentIndex(0)
Example #23
0
class geopunt4QgisAdresDialog(QDialog):
    def __init__(self, iface):
        QDialog.__init__(self, None)
        self.setWindowFlags(self.windowFlags()
                            & ~Qt.WindowContextHelpButtonHint)
        self.iface = iface

        # initialize locale
        locale = QSettings().value("locale/userLocale", "nl")
        if not locale: locale == 'nl'
        else: locale = locale[0:2]
        localePath = os.path.join(os.path.dirname(__file__), 'i18n',
                                  'geopunt4qgis_{}.qm'.format(locale))
        if os.path.exists(localePath):
            self.translator = QTranslator()
            self.translator.load(localePath)
            QCoreApplication.installTranslator(self.translator)

        self._initGui()

    def _initGui(self):
        """setup the user interface"""
        self.ui = Ui_geopunt4Qgis()
        self.ui.setupUi(self)

        #get settings
        self.s = QSettings()
        self.loadSettings()

        #setup geometryHelper object
        self.gh = geometryHelper(self.iface)

        #create graphicsLayer
        self.graphicsLayer = []

        self.firstShow = True

        self.completer = QCompleter(self)
        self.completerModel = QStringListModel(self)
        self.ui.gemeenteBox.setCompleter(self.completer)
        self.completer.setModel(self.completerModel)
        self.completer.setCaseSensitivity(False)

        #setup a message bar
        self.bar = QgsMessageBar()
        self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.ui.verticalLayout.addWidget(self.bar)

        self.ui.buttonBox.addButton(QPushButton("Sluiten"),
                                    QDialogButtonBox.RejectRole)
        for btn in self.ui.buttonBox.buttons():
            btn.setAutoDefault(0)

        #event handlers
        if self.adresSearchOnEnter:
            self.ui.zoekText.returnPressed.connect(self.onZoekActivated)
        else:
            self.ui.zoekText.textEdited.connect(self.onZoekActivated)
        self.ui.gemeenteBox.currentIndexChanged.connect(self.onZoekActivated)
        self.ui.resultLijst.itemDoubleClicked.connect(self.onItemActivated)
        self.ui.resultLijst.itemClicked.connect(self.onItemClick)
        self.ui.ZoomKnop.clicked.connect(self.onZoomKnopClick)
        self.ui.Add2mapKnop.clicked.connect(self.onAdd2mapKnopClick)
        self.ui.buttonBox.helpRequested.connect(self.openHelp)
        self.finished.connect(self.clean)

    def loadSettings(self):
        self.saveToFile = int(self.s.value("geopunt4qgis/adresSavetoFile", 1))
        layerName = self.s.value("geopunt4qgis/adreslayerText", "")
        if layerName:
            self.layerName = layerName
        self.adresSearchOnEnter = int(
            self.s.value("geopunt4qgis/adresSearchOnEnter", 0))
        self.timeout = int(self.s.value("geopunt4qgis/timeout", 15))
        if settings().proxyUrl:
            self.proxy = settings().proxyUrl
        else:
            self.proxy = ""
        self.startDir = self.s.value("geopunt4qgis/startDir",
                                     os.path.expanduser("~"))
        self.gp = Adres(self.timeout, self.proxy)

    # overwrite
    def show(self):
        QDialog.show(self)
        self.setWindowModality(0)
        arUrl = "http://loc.api.geopunt.be/"
        inet = internet_on(proxyUrl=self.proxy,
                           timeout=self.timeout,
                           testSite=arUrl)

        if not inet:
            msg = "Kan geen verbing maken met de site van Geopunt: {} \nMogelijke is deze site niet bereikbaar, dan zal deze tool ook niet werken.\nProbeer later opnieuw. Indien dit probleem zich blijft voordoen contacteer informatie Vlaanderen.".format(
                arUrl)
            QMessageBox.warning(self.iface.mainWindow(),
                                "Waarschuwing: kan geen verbinding maken", msg)
            self.bar.pushMessage(QCoreApplication.translate(
                "geopunt4QgisPoidialog", "Waarschuwing"),
                                 msg,
                                 level=Qgis.Warning,
                                 duration=3)
            return

        if self.firstShow:
            self.am = basisregisters.adresMatch(self.timeout, self.proxy)
            gemeenteNamen = [n["Naam"] for n in self.am.gemeenten()]

            self.ui.gemeenteBox.addItems(gemeenteNamen)
            self.completerModel.setStringList(gemeenteNamen)
            self.ui.gemeenteBox.setEditText(
                QCoreApplication.translate("geopunt4QgisAdresDialog",
                                           "gemeente"))
            self.ui.gemeenteBox.setStyleSheet('QComboBox {color: #808080}')
            self.ui.gemeenteBox.setFocus()
            self.firstShow = False

    def openHelp(self):
        webbrowser.open_new_tab(
            "http://www.geopunt.be/voor-experts/geopunt-plug-ins/functionaliteiten/zoek-een-adres"
        )

    def onZoekActivated(self):
        self._clearGraphicsLayer()
        self.bar.clearWidgets()

        gemeente = self.ui.gemeenteBox.currentText()
        if gemeente != QCoreApplication.translate("geopunt4QgisAdresDialog",
                                                  "gemeente"):
            self.ui.gemeenteBox.setStyleSheet('QComboBox {color: #000000}')

            txt = self.ui.zoekText.text() + ", " + gemeente

            suggesties = self.gp.fetchSuggestion(txt, 25)

            self.ui.resultLijst.clear()
            if type(suggesties) is list and len(suggesties) != 0:
                self.ui.resultLijst.addItems(suggesties)
                if len(suggesties) == 1:
                    self.ui.resultLijst.setCurrentRow(0)

    def onItemActivated(self, item):
        txt = item.text()
        self._zoomLoc(txt)

    def onItemClick(self, item):
        txt = item.text()
        streetNr = txt.split(",")[:-1]
        self.ui.zoekText.setText(",".join(streetNr))

    def onZoomKnopClick(self):
        item = self.ui.resultLijst.currentItem()
        if item:
            self._zoomLoc(item.text())

    def onAdd2mapKnopClick(self):
        item = self.ui.resultLijst.currentItem()
        if item:
            self._addToMap(item.text())

    def _clearGraphicsLayer(self):
        for graphic in self.graphicsLayer:
            self.iface.mapCanvas().scene().removeItem(graphic)
        self.graphicsLayer = []

    def _zoomLoc(self, txt):
        self._clearGraphicsLayer()
        locations = self.gp.fetchLocation(txt)
        if type(locations) is list and len(locations):
            loc = locations[0]

            LowerLeftX = loc['BoundingBox']['LowerLeft']['X_Lambert72']
            LowerLeftY = loc['BoundingBox']['LowerLeft']['Y_Lambert72']
            UpperRightX = loc['BoundingBox']['UpperRight']['X_Lambert72']
            UpperRightY = loc['BoundingBox']['UpperRight']['Y_Lambert72']

            self.gh.zoomtoRec(QgsPointXY(LowerLeftX, LowerLeftY),
                              QgsPointXY(UpperRightX, UpperRightY), 31370)

            xlb, ylb = loc["Location"]["X_Lambert72"], loc["Location"][
                "Y_Lambert72"]
            x, y = self.gh.prjPtToMapCrs(QgsPointXY(xlb, ylb), 31370)

            m = QgsVertexMarker(self.iface.mapCanvas())
            self.graphicsLayer.append(m)
            m.setCenter(QgsPointXY(x, y))
            m.setColor(QColor(255, 255, 0))
            m.setIconSize(1)
            m.setIconType(QgsVertexMarker.ICON_BOX)
            m.setPenWidth(9)

        elif type(locations) is str:
            self.bar.pushMessage(QCoreApplication.translate(
                "geopunt4QgisAdresDialog", "Waarschuwing"),
                                 locations,
                                 level=Qgis.Warning,
                                 duration=3)
        else:
            self.bar.pushMessage("Error",
                                 QCoreApplication.translate(
                                     "geopunt4QgisAdresDialog",
                                     "onbekende fout"),
                                 level=Qgis.Critical,
                                 duration=3)

    def _addToMap(self, txt):
        if not self.layernameValid(): return
        locations = self.gp.fetchLocation(txt)
        if type(locations) is list and len(locations):
            loc = locations[0]
            x, y = loc["Location"]["X_Lambert72"], loc["Location"][
                "Y_Lambert72"]
            adres = loc["FormattedAddress"]
            LocationType = loc["LocationType"]

            pt = self.gh.prjPtToMapCrs(QgsPointXY(x, y), 31370)

            self.gh.save_adres_point(pt,
                                     adres,
                                     typeAddress=LocationType,
                                     layername=self.layerName,
                                     saveToFile=self.saveToFile,
                                     sender=self,
                                     startFolder=os.path.join(
                                         self.startDir, self.layerName))

    def layernameValid(self):
        if not hasattr(self, 'layerName'):
            layerName, accept = QInputDialog.getText(
                None,
                QCoreApplication.translate("geopunt4Qgis", 'Laag toevoegen'),
                QCoreApplication.translate("geopunt4Qgis",
                                           'Geef een naam voor de laag op:'))
            if accept == False:
                return False
            else:
                self.layerName = layerName
        return True

    def clean(self):
        self.bar.clearWidgets()
        self.ui.resultLijst.clear()
        self.ui.zoekText.setText("")
        self.ui.gemeenteBox.setEditText(
            QCoreApplication.translate("geopunt4QgisAdresDialog", "gemeente"))
        self.ui.gemeenteBox.setStyleSheet('QComboBox {color: #808080}')
        self._clearGraphicsLayer()
class TmParentManage(TmParentAction, object):
    def __init__(self, iface, settings, controller, plugin_dir):
        """ Class to keep common functions of classes
        'ManageDocument', 'ManageElement' and 'ManageVisit' of toolbar 'edit' """

        super(TmParentManage, self).__init__(iface, settings, controller,
                                             plugin_dir)
        self.x = ""
        self.y = ""
        self.canvas = self.iface.mapCanvas()
        self.plan_om = None
        self.previous_map_tool = None
        self.autocommit = True
        self.lazy_widget = None
        self.workcat_id_end = None

    def reset_lists(self):
        """ Reset list of selected records """

        self.ids = []
        self.list_ids = {}
        self.list_ids['node'] = []

    def reset_layers(self):
        """ Reset list of layers """

        self.layers = {}
        self.layers['node'] = []
        self.visible_layers = []

    def remove_selection(self):
        """ Remove all previous selections """

        try:
            for layer in self.layers['node']:
                if layer in self.visible_layers:
                    self.controller.set_layer_visible(layer, False)
            for layer in self.layers['node']:
                if layer in self.visible_layers:
                    self.controller.set_layer_visible(layer, True)
                    layer.removeSelection()
        except:
            pass

        self.canvas.refresh()
        self.canvas.setMapTool(self.previous_map_tool)

    def add_point(self):
        """ Create the appropriate map tool and connect to the corresponding signal """

        self.emit_point = QgsMapToolEmitPoint(self.canvas)
        self.previous_map_tool = self.canvas.mapTool()
        self.canvas.setMapTool(self.emit_point)
        self.emit_point.canvasClicked.connect(partial(self.get_xy))

    def get_xy(self, point):
        """ Get coordinates of selected point """

        self.x = point.x()
        self.y = point.y()
        message = "Geometry has been added!"
        self.controller.show_info(message)
        self.emit_point.canvasClicked.disconnect()

    def set_completer_feature_id(self, widget, geom_type, viewname):
        """ Set autocomplete of widget 'feature_id'. Getting id's from selected @viewname """

        # Adding auto-completion to a QLineEdit
        self.completer = QCompleter()
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        widget.setCompleter(self.completer)
        model = QStringListModel()

        sql = (f"SELECT {geom_type}_id" f" FROM {viewname}")
        row = self.controller.get_rows(sql, commit=self.autocommit)
        if row:
            for i in range(0, len(row)):
                aux = row[i]
                row[i] = str(aux[0])

            model.setStringList(row)
            self.completer.setModel(model)

    def set_table_model(self, qtable, geom_type, expr_filter):
        """ Sets a TableModel to @widget_name attached to @table_name and filter @expr_filter """

        expr = None
        if expr_filter:
            # Check expression
            (is_valid,
             expr) = self.check_expression(expr_filter)  # @UnusedVariable
            if not is_valid:
                return expr

        # Set a model with selected filter expression
        table_name = "v_edit_" + geom_type
        if self.schema_name not in table_name:
            table_name = self.schema_name + "." + table_name

        # Set the model
        model = QSqlTableModel()
        model.setTable(table_name)
        model.setEditStrategy(QSqlTableModel.OnManualSubmit)
        model.select()
        if model.lastError().isValid():
            self.controller.show_warning(model.lastError().text())
            return expr

        # Attach model to selected widget
        if type(qtable) is QTableView:
            widget = qtable
        else:
            message = "Table_object is not a table name or QTableView"
            self.controller.log_info(message)
            return expr

        if expr_filter:
            widget.setModel(model)
            widget.model().setFilter(expr_filter)
            widget.model().select()
        else:
            widget.setModel(None)

        return expr

    def apply_lazy_init(self, widget):
        """ Apply the init function related to the model. It's necessary
        a lazy init because model is changed everytime is loaded """

        if self.lazy_widget is None:
            return
        if widget != self.lazy_widget:
            return
        self.lazy_init_function(self.lazy_widget)

    def lazy_configuration(self, widget, init_function):
        """ set the init_function where all necessary events are set.
        This is necessary to allow a lazy setup of the events because set_table_events
        can create a table with a None model loosing any event connection """

        # TODO: create a dictionary with key:widged.objectName value:initFuction
        # to allow multiple lazy initialization
        self.lazy_widget = widget
        self.lazy_init_function = init_function

    def select_features_by_ids(self, geom_type, expr):
        """ Select features of layers of group @geom_type applying @expr """

        # Build a list of feature id's and select them
        for layer in self.layers[geom_type]:
            if expr is None:
                layer.removeSelection()
            else:
                it = layer.getFeatures(QgsFeatureRequest(expr))
                id_list = [i.id() for i in it]
                if len(id_list) > 0:
                    layer.selectByIds(id_list)
                else:
                    layer.removeSelection()

    def delete_records(self, dialog, table_object):
        """ Delete selected elements of the table """

        self.disconnect_signal_selection_changed()

        if type(table_object) is str:
            widget_name = f"tbl_{table_object}_x_{self.geom_type}"
            widget = utils_giswater.getWidget(dialog, widget_name)
            if not widget:
                message = "Widget not found"
                self.controller.show_warning(message, parameter=widget_name)
                return
        elif type(table_object) is QTableView:
            widget = table_object
        else:
            message = "Table_object is not a table name or QTableView"
            self.controller.log_info(message)
            return

        # Get selected rows
        selected_list = widget.selectionModel().selectedRows()
        if len(selected_list) == 0:
            message = "Any record selected"
            self.controller.show_info_box(message)
            return

        self.ids = self.list_ids[self.geom_type]
        field_id = self.geom_type + "_id"

        del_id = []
        inf_text = ""

        for i in range(0, len(selected_list)):
            row = selected_list[i].row()
            id_feature = widget.model().record(row).value(field_id)
            inf_text += f"{id_feature}, "

            del_id.append(id_feature)
        inf_text = inf_text[:-2]

        message = "Are you sure you want to delete these records?"
        title = "Delete records"
        answer = self.controller.ask_question(message, title, inf_text)
        if answer:
            for el in del_id:
                self.ids.remove(el)
        else:
            return

        expr_filter = None
        expr = None
        if len(self.ids) > 0:

            # Set expression filter with features in the list
            expr_filter = f'"{field_id}" IN ('
            for i in range(len(self.ids)):
                expr_filter += f"'{self.ids[i]}', "
            expr_filter = expr_filter[:-2] + ")"

            # Check expression
            (is_valid,
             expr) = self.check_expression(expr_filter)  # @UnusedVariable
            if not is_valid:
                return

        # Update model of the widget with selected expr_filter
        self.reload_table(table_object, self.geom_type, expr_filter)
        self.apply_lazy_init(table_object)

        # Select features with previous filter
        # Build a list of feature id's and select them
        self.select_features_by_ids(self.geom_type, expr)

        # Update list
        self.list_ids[self.geom_type] = self.ids

        self.connect_signal_selection_changed(table_object)

    def selection_init(self, table_object):
        """ Set canvas map tool to an instance of class 'MultipleSelection' """

        current_visible_layers = self.get_visible_layers()
        for layer in current_visible_layers:
            if layer not in self.visible_layers:
                self.visible_layers.append(layer)
        self.controller.log_info(str(self.visible_layers))
        multiple_selection = TmMultipleSelection(self.iface,
                                                 self.controller,
                                                 self.layers[self.geom_type],
                                                 parent_manage=self,
                                                 table_object=table_object)
        self.disconnect_signal_selection_changed()
        self.previous_map_tool = self.canvas.mapTool()
        self.canvas.setMapTool(multiple_selection)
        self.connect_signal_selection_changed(table_object)
        cursor = self.get_cursor_multiple_selection()
        self.canvas.setCursor(cursor)

    def selection_changed(self, qtable, geom_type):
        """ Slot function for signal 'canvas.selectionChanged' """

        self.disconnect_signal_selection_changed()

        field_id = geom_type + "_id"
        self.ids = []

        # Iterate over all layers of the group
        for layer in self.layers[self.geom_type]:
            if layer.selectedFeatureCount(
            ) > 0 and self.controller.is_layer_visible(layer):
                # Get selected features of the layer
                features = layer.selectedFeatures()
                for feature in features:
                    # Append 'feature_id' into the list
                    selected_id = feature.attribute(field_id)
                    if selected_id not in self.ids:
                        self.ids.append(selected_id)

        if geom_type == 'node':
            self.list_ids['node'] = self.ids

        expr_filter = None
        if len(self.ids) > 0:
            # Set 'expr_filter' with features that are in the list
            expr_filter = f'"{field_id}" IN ('
            for i in range(len(self.ids)):
                expr_filter += f"'{self.ids[i]}', "
            expr_filter = expr_filter[:-2] + ")"

            # Check expression
            (is_valid,
             expr) = self.check_expression(expr_filter)  # @UnusedVariable
            if not is_valid:
                return

            self.select_features_by_ids(geom_type, expr)

        # Reload contents of table 'tbl_@table_object_x_@geom_type'
        self.reload_table(qtable, self.geom_type, expr_filter)
        self.apply_lazy_init(qtable)
        # Remove selection in generic 'v_edit' layers
        #self.remove_selection(False)

        self.connect_signal_selection_changed(qtable)

    def insert_feature(self, widget, table_object):
        """ Select feature with entered id. Set a model with selected filter.
        Attach that model to selected table
        """

        self.disconnect_signal_selection_changed()

        # Clear list of ids
        self.ids = []
        field_id = self.geom_type + "_id"

        feature_id = widget.text()
        if feature_id == 'null':
            message = "You need to enter a feature id"
            self.controller.show_info_box(message)
            return

        # Iterate over all layers of the group
        for layer in self.layers[self.geom_type]:
            if layer.selectedFeatureCount() > 0:
                # Get selected features of the layer
                features = layer.selectedFeatures()
                for feature in features:
                    # Append 'feature_id' into the list
                    selected_id = feature.attribute(field_id)
                    self.ids.append(selected_id)
            if feature_id not in self.ids:
                # If feature id doesn't exist in list -> add
                self.ids.append(str(feature_id))

        # Set expression filter with features in the list
        expr_filter = f'"{field_id}" IN ('
        for i in range(len(self.ids)):
            expr_filter += f"'{self.ids[i]}', "
        expr_filter = expr_filter[:-2] + ")"

        # Check expression
        (is_valid, expr) = self.check_expression(expr_filter)
        if not is_valid:
            return

        # Select features with previous filter
        # Build a list of feature id's and select them
        for layer in self.layers[self.geom_type]:
            it = layer.getFeatures(QgsFeatureRequest(expr))
            id_list = [i.id() for i in it]
            if len(id_list) > 0:
                layer.selectByIds(id_list)

        # Reload contents of table 'tbl_???_x_@geom_type'
        self.reload_table(table_object, self.geom_type, expr_filter)
        self.apply_lazy_init(table_object)

        # Update list
        self.list_ids[self.geom_type] = self.ids

        self.connect_signal_selection_changed(table_object)

    def disconnect_snapping(self):
        """ Select 'Pan' as current map tool and disconnect snapping """

        try:
            self.iface.actionPan().trigger()
            self.canvas.xyCoordinates.disconnect()
            if self.emit_point:
                self.emit_point.canvasClicked.disconnect()
        except:
            pass

    def connect_signal_selection_changed(self, table_object):
        """ Connect signal selectionChanged """

        try:
            self.canvas.selectionChanged.connect(
                partial(self.selection_changed, table_object, self.geom_type))
        except Exception:
            pass

    def disconnect_signal_selection_changed(self):
        """ Disconnect signal selectionChanged """

        try:
            self.canvas.selectionChanged.disconnect()
        except Exception:
            pass

    def fill_widget_with_fields(self, dialog, data_object, field_names):
        """ Fill the Widget with value get from data_object limited to the list of field_names. """

        for field_name in field_names:
            value = getattr(data_object, field_name)
            if not hasattr(dialog, field_name):
                continue

            widget = getattr(dialog, field_name)
            if type(widget) in [QDateEdit, QDateTimeEdit]:
                widget.setDateTime(value if value else QDate.currentDate())
            if type(widget) in [QLineEdit, QTextEdit]:
                if value:
                    widget.setText(value)
                else:
                    widget.clear()
            if type(widget) in [QComboBox]:
                if not value:
                    widget.setCurrentIndex(0)
                    continue
                # look the value in item text
                index = widget.findText(str(value))
                if index >= 0:
                    widget.setCurrentIndex(index)
                    continue
                # look the value in itemData
                index = widget.findData(value)
                if index >= 0:
                    widget.setCurrentIndex(index)
                    continue

    def reload_table(self, qtable, geom_type, expr_filter):
        """ Reload @widget with contents of @tablename applying selected @expr_filter """

        if type(qtable) is QTableView:
            widget = qtable
        else:
            message = "Table_object is not a table name or QTableView"
            self.controller.log_info(message)
            return None

        expr = self.set_table_model(widget, geom_type, expr_filter)
        return expr

    def get_visible_layers(self, return_as_list=True):
        """ Return list or string as {...} with all visible layer in TOC """

        visible_layer = []
        layers = self.controller.get_layers()
        if return_as_list:
            for layer in layers:
                if self.controller.is_layer_visible(layer):
                    visible_layer.append(layer)
            return visible_layer

        for layer in layers:
            if self.controller.is_layer_visible(layer):
                visible_layer += f'"{layer.name()}", '
        visible_layer = visible_layer[:-2] + "}"

        return visible_layer
class ReplaceFeatureMapTool(ParentMapTool):
    """ Button 44: User select one feature. Execute SQL function: 'gw_fct_feature_replace' """
    def __init__(self, iface, settings, action, index_action):
        """ Class constructor """

        super(ReplaceFeatureMapTool, self).__init__(iface, settings, action,
                                                    index_action)
        self.current_date = QDate.currentDate().toString('yyyy-MM-dd')
        self.project_type = None
        self.geom_type = None
        self.geom_view = None
        self.cat_table = None
        self.feature_type_ws = None
        self.feature_type_ud = None

    def manage_dates(self, date_value):
        """ Manage dates """

        date_result = None
        try:
            date_result = str(date_value)
            date_result = date_result.replace("-", "/")
            date_result = datetime.strptime(date_result, '%Y/%m/%d')
        except Exception as e:
            self.controller.log_warning(str(e))
        finally:
            return date_result

    def init_replace_feature_form(self, feature):

        # Create the dialog and signals
        self.dlg_replace = FeatureReplace()
        self.load_settings(self.dlg_replace)

        sql = "SELECT id FROM cat_work ORDER BY id"
        rows = self.controller.get_rows(sql)
        if rows:
            utils_giswater.fillComboBox(self.dlg_replace,
                                        self.dlg_replace.workcat_id_end, rows)
            utils_giswater.set_autocompleter(self.dlg_replace.workcat_id_end)

        row = self.controller.get_config('edit_workcat_vdefault')
        if row:
            edit_workcat_vdefault = self.dlg_replace.workcat_id_end.findText(
                row[0])
            self.dlg_replace.workcat_id_end.setCurrentIndex(
                edit_workcat_vdefault)

        row = self.controller.get_config('edit_enddate_vdefault')
        if row:
            self.enddate_aux = self.manage_dates(row[0]).date()
        else:
            work_id = utils_giswater.getWidgetText(
                self.dlg_replace, self.dlg_replace.workcat_id_end)
            sql = (f"SELECT builtdate FROM cat_work "
                   f"WHERE id = '{work_id}'")
            row = self.controller.get_row(sql)
            current_date = self.manage_dates(self.current_date)
            if row and row[0]:
                builtdate = self.manage_dates(row[0])
                if builtdate != 'null' and builtdate:
                    self.enddate_aux = builtdate.date()
                else:
                    self.enddate_aux = current_date.date()
            else:
                self.enddate_aux = current_date.date()

        self.dlg_replace.enddate.setDate(self.enddate_aux)

        # Get feature type from current feature
        feature_type = None
        if self.project_type == 'ws':
            feature_type = feature.attribute(self.feature_type_ws)
        elif self.project_type == 'ud':
            feature_type = feature.attribute(self.feature_type_ud)
            if self.geom_type in ('node', 'connec'):
                sql = f"SELECT DISTINCT(id) FROM {self.cat_table} ORDER BY id"
                rows = self.controller.get_rows(sql)
                utils_giswater.fillComboBox(self.dlg_replace,
                                            "featurecat_id",
                                            rows,
                                            allow_nulls=False)
            elif self.geom_type in ('gully'):
                sql = f"SELECT DISTINCT(id) FROM cat_grate ORDER BY id"
                rows = self.controller.get_rows(sql)
                utils_giswater.fillComboBox(self.dlg_replace,
                                            "featurecat_id",
                                            rows,
                                            allow_nulls=False)

        self.dlg_replace.feature_type.setText(feature_type)
        self.dlg_replace.feature_type_new.currentIndexChanged.connect(
            self.edit_change_elem_type_get_value)
        self.dlg_replace.btn_catalog.clicked.connect(partial(
            self.open_catalog))
        self.dlg_replace.workcat_id_end.currentIndexChanged.connect(
            self.update_date)

        # Fill 1st combo boxes-new system node type
        sql = (
            f"SELECT DISTINCT(id) FROM cat_feature WHERE lower(feature_type) = '{self.geom_type}' "
            f"AND active is True "
            f"ORDER BY id")
        rows = self.controller.get_rows(sql)
        utils_giswater.fillComboBox(self.dlg_replace, "feature_type_new", rows)

        self.dlg_replace.btn_new_workcat.clicked.connect(
            partial(self.new_workcat))
        self.dlg_replace.btn_accept.clicked.connect(
            partial(self.get_values, self.dlg_replace))
        self.dlg_replace.btn_cancel.clicked.connect(
            partial(self.close_dialog, self.dlg_replace))
        self.dlg_replace.rejected.connect(self.cancel_map_tool)
        # Open dialog
        self.open_dialog(self.dlg_replace, maximize_button=False)

    def open_catalog(self):

        # Get feature_type
        feature_type = utils_giswater.getWidgetText(
            self.dlg_replace, self.dlg_replace.feature_type_new)

        if feature_type is 'null':
            msg = "New feature type is null. Please, select a valid value."
            self.controller.show_info_box(msg, "Info")
            return

        sql = f"SELECT lower(feature_type) FROM cat_feature WHERE id = '{feature_type}'"
        row = self.controller.get_row(sql)

        self.catalog = ApiCatalog(self.iface, self.settings, self.controller,
                                  self.plugin_dir)
        self.catalog.api_catalog(self.dlg_replace, 'featurecat_id', row[0],
                                 feature_type)

    def update_date(self):

        row = self.controller.get_config('edit_enddate_vdefault')
        if row:
            self.enddate_aux = self.manage_dates(row[0]).date()
        else:
            work_id = utils_giswater.getWidgetText(
                self.dlg_replace, self.dlg_replace.workcat_id_end)
            sql = (f"SELECT builtdate FROM cat_work "
                   f"WHERE id = '{work_id}'")
            row = self.controller.get_row(sql)
            current_date = self.manage_dates(self.current_date)
            if row and row[0]:
                builtdate = self.manage_dates(row[0])
                if builtdate != 'null' and builtdate:
                    self.enddate_aux = builtdate.date()
                else:
                    self.enddate_aux = current_date.date()
            else:
                self.enddate_aux = current_date.date()

        self.dlg_replace.enddate.setDate(self.enddate_aux)

    def new_workcat(self):

        self.dlg_new_workcat = InfoWorkcatUi()
        self.load_settings(self.dlg_new_workcat)
        utils_giswater.setCalendarDate(self.dlg_new_workcat,
                                       self.dlg_new_workcat.builtdate, None,
                                       True)

        table_object = "cat_work"
        self.set_completer_object(table_object,
                                  self.dlg_new_workcat.cat_work_id, 'id')

        # Set signals
        self.dlg_new_workcat.btn_accept.clicked.connect(
            partial(self.manage_new_workcat_accept, table_object))
        self.dlg_new_workcat.btn_cancel.clicked.connect(
            partial(self.close_dialog, self.dlg_new_workcat))

        # Open dialog
        self.open_dialog(self.dlg_new_workcat, dlg_name='info_workcat')

    def manage_new_workcat_accept(self, table_object):
        """ Insert table 'cat_work'. Add cat_work """

        # Get values from dialog
        values = ""
        fields = ""
        cat_work_id = utils_giswater.getWidgetText(
            self.dlg_new_workcat, self.dlg_new_workcat.cat_work_id)
        if cat_work_id != "null":
            fields += 'id, '
            values += ("'" + str(cat_work_id) + "', ")
        descript = utils_giswater.getWidgetText(self.dlg_new_workcat,
                                                "descript")
        if descript != "null":
            fields += 'descript, '
            values += ("'" + str(descript) + "', ")
        link = utils_giswater.getWidgetText(self.dlg_new_workcat, "link")
        if link != "null":
            fields += 'link, '
            values += ("'" + str(link) + "', ")
        workid_key_1 = utils_giswater.getWidgetText(self.dlg_new_workcat,
                                                    "workid_key_1")
        if workid_key_1 != "null":
            fields += 'workid_key1, '
            values += ("'" + str(workid_key_1) + "', ")
        workid_key_2 = utils_giswater.getWidgetText(self.dlg_new_workcat,
                                                    "workid_key_2")
        if workid_key_2 != "null":
            fields += 'workid_key2, '
            values += ("'" + str(workid_key_2) + "', ")
        builtdate = self.dlg_new_workcat.builtdate.dateTime().toString(
            'yyyy-MM-dd')
        if builtdate != "null":
            fields += 'builtdate, '
            values += ("'" + str(builtdate) + "', ")

        if values != "":
            fields = fields[:-2]
            values = values[:-2]
            if cat_work_id == 'null':
                msg = "Work_id field is empty"
                self.controller.show_info_box(msg, "Warning")
            else:
                # Check if this element already exists
                sql = (f"SELECT DISTINCT(id) "
                       f"FROM {table_object} "
                       f"WHERE id = '{cat_work_id}'")
                row = self.controller.get_row(sql, log_info=False)
                if row is None:
                    sql = f"INSERT INTO cat_work ({fields}) VALUES ({values})"
                    self.controller.execute_sql(sql, log_sql=True)

                    sql = "SELECT id FROM cat_work ORDER BY id"
                    rows = self.controller.get_rows(sql)
                    if rows:
                        utils_giswater.fillComboBox(
                            self.dlg_replace, self.dlg_replace.workcat_id_end,
                            rows)
                        current_index = self.dlg_replace.workcat_id_end.findText(
                            str(cat_work_id))
                        self.dlg_replace.workcat_id_end.setCurrentIndex(
                            current_index)

                    self.close_dialog(self.dlg_new_workcat)
                else:
                    msg = "This Workcat is already exist"
                    self.controller.show_info_box(msg, "Warning")

    def set_completer_object(self, tablename, widget, field_id):
        """ Set autocomplete of widget @table_object + "_id"
            getting id's from selected @table_object
        """

        if not widget:
            return

        sql = (f"SELECT DISTINCT({field_id}) "
               f"FROM {tablename} "
               f"ORDER BY {field_id}")
        rows = self.controller.get_rows(sql)
        if rows is None:
            return

        for i in range(0, len(rows)):
            aux = rows[i]
            rows[i] = str(aux[0])

        # Set completer and model: add autocomplete in the widget
        self.completer = QCompleter()
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        widget.setCompleter(self.completer)
        model = QStringListModel()
        model.setStringList(rows)
        self.completer.setModel(model)

    def get_values(self, dialog):

        self.workcat_id_end_aux = utils_giswater.getWidgetText(
            dialog, dialog.workcat_id_end)
        self.enddate_aux = dialog.enddate.date().toString('yyyy-MM-dd')

        # Check null values
        if self.workcat_id_end_aux in (None, 'null'):
            message = "Mandatory field is missing. Please, set a value"
            self.controller.show_warning(message, parameter='Workcat_id')
            return

        feature_type_new = utils_giswater.getWidgetText(
            dialog, dialog.feature_type_new)
        featurecat_id = utils_giswater.getWidgetText(dialog,
                                                     dialog.featurecat_id)

        # Ask question before executing
        message = "Are you sure you want to replace selected feature with a new one?"
        answer = self.controller.ask_question(message, "Replace feature")
        if answer:

            # Get function input parameters
            feature = f'"type":"{self.geom_type}"'
            extras = f'"old_feature_id":"{self.feature_id}"'
            extras += f', "workcat_id_end":"{self.workcat_id_end_aux}"'
            extras += f', "enddate":"{self.enddate_aux}"'
            extras += f', "keep_elements":"{utils_giswater.isChecked(dialog, "keep_elements")}"'
            body = self.create_body(feature=feature, extras=extras)

            # Execute SQL function and show result to the user
            function_name = "gw_fct_feature_replace"
            sql = f"SELECT {function_name}({body})::text"
            row = self.controller.get_row(sql, log_sql=True)
            if not row:
                message = "Error replacing feature"
                self.controller.show_warning(message)
                self.deactivate()
                self.set_action_pan()
                self.close_dialog(dialog, set_action_pan=False)
                return

            complet_result = [
                json.loads(row[0], object_pairs_hook=OrderedDict)
            ]
            message = "Feature replaced successfully"
            self.controller.show_info(message)

            # Force user to manage with state = 1 features
            current_user = self.controller.get_project_user()
            sql = (f"DELETE FROM selector_state "
                   f"WHERE state_id = 1 AND cur_user = '******';"
                   f"\nINSERT INTO selector_state (state_id, cur_user) "
                   f"VALUES (1, '{current_user}');")
            self.controller.execute_sql(sql)

            if feature_type_new != "null" and featurecat_id != "null":
                # Get id of new generated feature
                sql = (f"SELECT {self.geom_type}_id "
                       f"FROM {self.geom_view} "
                       f"ORDER BY {self.geom_type}_id::int4 DESC LIMIT 1")
                row = self.controller.get_row(sql)
                if row:
                    if self.geom_type == 'connec':
                        field_cat_id = "connecat_id"
                    else:
                        field_cat_id = self.geom_type + "cat_id"
                    if self.geom_type != 'gully':
                        sql = (f"UPDATE {self.geom_view} "
                               f"SET {field_cat_id} = '{featurecat_id}' "
                               f"WHERE {self.geom_type}_id = '{row[0]}'")
                    self.controller.execute_sql(sql, log_sql=True)
                    if self.project_type == 'ud':
                        sql = (
                            f"UPDATE {self.geom_view} "
                            f"SET {self.geom_type}_type = '{feature_type_new}' "
                            f"WHERE {self.geom_type}_id = '{row[0]}'")
                        self.controller.execute_sql(sql, log_sql=True)

                message = "Values has been updated"
                self.controller.show_info(message)

            # Fill tab 'Info log'
            if complet_result and complet_result[0]['status'] == "Accepted":
                self.populate_info_text(self.dlg_replace,
                                        complet_result[0]['body']['data'])

            # Refresh canvas
            self.refresh_map_canvas()
            self.controller.set_layer_index('v_edit_arc')
            self.controller.set_layer_index('v_edit_connec')
            self.controller.set_layer_index('v_edit_gully')
            self.controller.set_layer_index('v_edit_node')
            self.refresh_legend()

            # Deactivate map tool
            self.deactivate()
            self.set_action_pan()

            # Disable ok button at the end of process
            self.dlg_replace.btn_accept.setEnabled(False)

    """ QgsMapTools inherited event functions """

    def keyPressEvent(self, event):

        if event.key() == Qt.Key_Escape:
            self.cancel_map_tool()
            return

    def canvasMoveEvent(self, event):

        # Hide marker and clicked point
        self.vertex_marker.hide()
        event_point = self.snapper_manager.get_event_point(event)

        # Snapping layers 'v_edit_'
        result = self.snapper_manager.snap_to_background_layers(event_point)
        if self.snapper_manager.result_is_valid():
            layer = self.snapper_manager.get_snapped_layer(result)
            tablename = self.controller.get_layer_source_table_name(layer)
            if tablename and 'v_edit' in tablename:
                self.snapper_manager.add_marker(result, self.vertex_marker)

    def canvasReleaseEvent(self, event):

        if event.button() == Qt.RightButton:
            self.cancel_map_tool()
            return

        event_point = self.snapper_manager.get_event_point(event)

        # Snapping
        result = self.snapper_manager.snap_to_background_layers(event_point)
        if not self.snapper_manager.result_is_valid():
            return

        # Get snapped feature
        snapped_feat = self.snapper_manager.get_snapped_feature(result)
        if snapped_feat:
            layer = self.snapper_manager.get_snapped_layer(result)
            tablename = self.controller.get_layer_source_table_name(layer)

            if tablename and 'v_edit' in tablename:
                if tablename == 'v_edit_node':
                    self.geom_type = 'node'
                elif tablename == 'v_edit_connec':
                    self.geom_type = 'connec'
                elif tablename == 'v_edit_gully':
                    self.geom_type = 'gully'

                self.geom_view = tablename
                self.cat_table = 'cat_' + self.geom_type
                self.feature_type_ws = self.geom_type + 'type_id'
                self.feature_type_ud = self.geom_type + '_type'
                self.feature_id = snapped_feat.attribute(self.geom_type +
                                                         '_id')
                self.init_replace_feature_form(snapped_feat)

    def activate(self):

        # Set active and current layer
        self.layer_node = self.controller.get_layer_by_tablename("v_edit_node")
        self.iface.setActiveLayer(self.layer_node)
        self.current_layer = self.layer_node

        # Check button
        self.action().setChecked(True)

        # Set main snapping layers
        self.snapper_manager.set_snapping_layers()

        # Store user snapping configuration
        self.snapper_manager.store_snapping_options()

        # Disable snapping
        self.snapper_manager.enable_snapping()

        # Set snapping to 'node', 'connec' and 'gully'
        self.snapper_manager.snap_to_node()
        self.snapper_manager.snap_to_connec_gully()

        self.snapper_manager.set_snapping_mode()

        # Change cursor
        self.canvas.setCursor(self.cursor)

        self.project_type = self.controller.get_project_type()

        # Show help message when action is activated
        if self.show_help:
            message = "Select the feature by clicking on it and it will be replaced"
            self.controller.show_info(message)

    def deactivate(self):

        ParentMapTool.deactivate(self)

    def edit_change_elem_type_get_value(self, index):
        """ Just select item to 'real' combo 'featurecat_id' (that is hidden) """

        if index == -1:
            return

        # Get selected value from 2nd combobox
        feature_type_new = utils_giswater.getWidgetText(
            self.dlg_replace, "feature_type_new")

        # When value is selected, enabled 3rd combo box
        if feature_type_new == 'null':
            return

        if self.project_type == 'ws':
            # Fill 3rd combo_box-catalog_id
            utils_giswater.setWidgetEnabled(self.dlg_replace,
                                            self.dlg_replace.featurecat_id,
                                            True)
            sql = (f"SELECT DISTINCT(id) "
                   f"FROM {self.cat_table} "
                   f"WHERE {self.feature_type_ws} = '{feature_type_new}'")
            rows = self.controller.get_rows(sql)
            utils_giswater.fillComboBox(self.dlg_replace,
                                        self.dlg_replace.featurecat_id, rows)
Example #26
0
class ParentAction(object):
    def __init__(self, iface, settings, controller, plugin_dir):
        """ Class constructor """

        # Initialize instance attributes
        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.settings = settings
        self.controller = controller
        self.plugin_dir = plugin_dir
        self.dao = self.controller.dao
        self.schema_name = self.controller.schema_name
        self.project_type = None
        self.plugin_version = self.get_plugin_version()
        self.add_layer = AddLayer(iface, settings, controller, plugin_dir)

    def set_controller(self, controller):
        """ Set controller class """

        self.controller = controller
        self.schema_name = self.controller.schema_name

    def open_web_browser(self, dialog, widget=None):
        """ Display url using the default browser """

        if widget is not None:
            url = utils_giswater.getWidgetText(dialog, widget)
            if url == 'null':
                url = 'http://www.giswater.org'
        else:
            url = 'http://www.giswater.org'

        webbrowser.open(url)

    def get_plugin_version(self):
        """ Get plugin version from metadata.txt file """

        # Check if metadata file exists
        metadata_file = os.path.join(self.plugin_dir, 'metadata.txt')
        if not os.path.exists(metadata_file):
            message = "Metadata file not found"
            self.controller.show_warning(message, parameter=metadata_file)
            return None

        metadata = configparser.ConfigParser()
        metadata.read(metadata_file)
        plugin_version = metadata.get('general', 'version')
        if plugin_version is None:
            message = "Plugin version not found"
            self.controller.show_warning(message)

        return plugin_version

    def get_file_dialog(self, dialog, widget):
        """ Get file dialog """

        # Check if selected file exists. Set default value if necessary
        file_path = utils_giswater.getWidgetText(dialog, widget)
        if file_path is None or file_path == 'null' or not os.path.exists(
                str(file_path)):
            folder_path = self.plugin_dir
        else:
            folder_path = os.path.dirname(file_path)

        # Open dialog to select file
        os.chdir(folder_path)
        file_dialog = QFileDialog()
        file_dialog.setFileMode(QFileDialog.AnyFile)
        message = "Select file"
        folder_path, filter_ = file_dialog.getOpenFileName(
            parent=None, caption=self.controller.tr(message))
        if folder_path:
            utils_giswater.setWidgetText(dialog, widget, str(folder_path))

    def get_folder_dialog(self, dialog, widget):
        """ Get folder dialog """

        # Check if selected folder exists. Set default value if necessary
        folder_path = utils_giswater.getWidgetText(dialog, widget)
        if folder_path is None or folder_path == 'null' or not os.path.exists(
                folder_path):
            folder_path = os.path.expanduser("~")

        # Open dialog to select folder
        os.chdir(folder_path)
        file_dialog = QFileDialog()
        file_dialog.setFileMode(QFileDialog.Directory)
        message = "Select folder"
        folder_path = file_dialog.getExistingDirectory(
            parent=None,
            caption=self.controller.tr(message),
            directory=folder_path)
        if folder_path:
            utils_giswater.setWidgetText(dialog, widget, str(folder_path))

    def load_settings(self, dialog=None):
        """ Load QGIS settings related with dialog position and size """

        if dialog is None:
            dialog = self.dlg

        try:
            x = self.controller.plugin_settings_value(dialog.objectName() +
                                                      "_x")
            y = self.controller.plugin_settings_value(dialog.objectName() +
                                                      "_y")
            width = self.controller.plugin_settings_value(
                dialog.objectName() + "_width", dialog.property('width'))
            height = self.controller.plugin_settings_value(
                dialog.objectName() + "_height", dialog.property('height'))

            if int(x) < 0 or int(y) < 0:
                dialog.resize(int(width), int(height))
            else:
                screens = ctypes.windll.user32
                screen_x = screens.GetSystemMetrics(78)
                screen_y = screens.GetSystemMetrics(79)
                if int(x) > screen_x:
                    x = int(screen_x) - int(width)
                if int(y) > screen_y:
                    y = int(screen_y)
                dialog.setGeometry(int(x), int(y), int(width), int(height))
        except:
            pass

    def save_settings(self, dialog=None):
        """ Save QGIS settings related with dialog position and size """

        if dialog is None:
            dialog = self.dlg

        self.controller.plugin_settings_set_value(
            dialog.objectName() + "_width", dialog.property('width'))
        self.controller.plugin_settings_set_value(
            dialog.objectName() + "_height", dialog.property('height'))
        self.controller.plugin_settings_set_value(dialog.objectName() + "_x",
                                                  dialog.pos().x() + 8)
        self.controller.plugin_settings_set_value(dialog.objectName() + "_y",
                                                  dialog.pos().y() + 31)

    def open_dialog(self,
                    dlg=None,
                    dlg_name=None,
                    info=True,
                    maximize_button=True,
                    stay_on_top=True):
        """ Open dialog """

        if dlg is None or type(dlg) is bool:
            dlg = self.dlg

        # Manage i18n of the dialog
        if dlg_name:
            self.controller.manage_translation(dlg_name, dlg)

        # Manage stay on top, maximize/minimize button and information button
        # if info is True maximize flag will be ignored
        # To enable maximize button you must set info to False
        flags = Qt.WindowCloseButtonHint
        if info:
            flags |= Qt.WindowSystemMenuHint | Qt.WindowContextHelpButtonHint
        else:
            if maximize_button:
                flags |= Qt.WindowMinMaxButtonsHint

        if stay_on_top:
            flags |= Qt.WindowStaysOnTopHint

        dlg.setWindowFlags(flags)

        # Open dialog
        if issubclass(type(dlg), GwDialog):
            dlg.open()
        elif issubclass(type(dlg), GwMainWindow):
            dlg.show()
        else:
            print(f"WARNING: dialog type {type(dlg)} is not handled!")
            dlg.show()

    def close_dialog(self, dlg=None):
        """ Close dialog """

        if dlg is None or type(dlg) is bool:
            dlg = self.dlg
        try:
            self.save_settings(dlg)
            dlg.close()
            map_tool = self.canvas.mapTool()
            # If selected map tool is from the plugin, set 'Pan' as current one
            if map_tool.toolName() == '':
                self.iface.actionPan().trigger()
        except AttributeError:
            pass
        except Exception as e:
            print(type(e).__name__)

    def multi_row_selector(self,
                           dialog,
                           tableleft,
                           tableright,
                           field_id_left,
                           field_id_right,
                           name='name',
                           hide_left=[
                               0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
                               15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
                               27, 28, 29, 30
                           ],
                           hide_right=[1, 2, 3],
                           aql=""):
        """
        :param dialog:
        :param tableleft: Table to consult and load on the left side
        :param tableright: Table to consult and load on the right side
        :param field_id_left: ID field of the left table
        :param field_id_right: ID field of the right table
        :param name: field name (used in add_lot.py)
        :param hide_left: Columns to hide from the left table
        :param hide_right: Columns to hide from the right table
        :param aql: (add query left) Query added to the left side (used in basic.py def basic_exploitation_selector())
        :return:
        """
        # fill QTableView all_rows
        tbl_all_rows = dialog.findChild(QTableView, "all_rows")
        tbl_all_rows.setSelectionBehavior(QAbstractItemView.SelectRows)
        schema_name = self.schema_name.replace('"', '')
        query_left = f"SELECT * FROM {schema_name}.{tableleft} WHERE {name} NOT IN "
        query_left += f"(SELECT {tableleft}.{name} FROM {schema_name}.{tableleft}"
        query_left += f" RIGHT JOIN {schema_name}.{tableright} ON {tableleft}.{field_id_left} = {tableright}.{field_id_right}"
        query_left += f" WHERE cur_user = current_user)"
        query_left += f" AND  {field_id_left} > -1"
        query_left += aql

        self.fill_table_by_query(tbl_all_rows, query_left)
        self.hide_colums(tbl_all_rows, hide_left)
        tbl_all_rows.setColumnWidth(1, 200)

        # fill QTableView selected_rows
        tbl_selected_rows = dialog.findChild(QTableView, "selected_rows")
        tbl_selected_rows.setSelectionBehavior(QAbstractItemView.SelectRows)

        query_right = f"SELECT {tableleft}.{name}, cur_user, {tableleft}.{field_id_left}, {tableright}.{field_id_right}"
        query_right += f" FROM {schema_name}.{tableleft}"
        query_right += f" JOIN {schema_name}.{tableright} ON {tableleft}.{field_id_left} = {tableright}.{field_id_right}"

        query_right += " WHERE cur_user = current_user"

        self.fill_table_by_query(tbl_selected_rows, query_right)
        self.hide_colums(tbl_selected_rows, hide_right)
        tbl_selected_rows.setColumnWidth(0, 200)
        # Button select
        dialog.btn_select.clicked.connect(
            partial(self.multi_rows_selector, tbl_all_rows, tbl_selected_rows,
                    field_id_left, tableright, field_id_right, query_left,
                    query_right, field_id_right))

        # Button unselect
        query_delete = f"DELETE FROM {schema_name}.{tableright}"
        query_delete += f" WHERE current_user = cur_user AND {tableright}.{field_id_right}="
        dialog.btn_unselect.clicked.connect(
            partial(self.unselector, tbl_all_rows, tbl_selected_rows,
                    query_delete, query_left, query_right, field_id_right))

        # QLineEdit
        dialog.txt_name.textChanged.connect(
            partial(self.query_like_widget_text, dialog, dialog.txt_name,
                    tbl_all_rows, tableleft, tableright, field_id_right,
                    field_id_left, name))

        # Order control
        tbl_all_rows.horizontalHeader().sectionClicked.connect(
            partial(self.order_by_column, tbl_all_rows, query_left))
        tbl_selected_rows.horizontalHeader().sectionClicked.connect(
            partial(self.order_by_column, tbl_selected_rows, query_right))

    def order_by_column(self, qtable, query, idx):
        """
        :param qtable: QTableView widget
        :param query: Query for populate QsqlQueryModel
        :param idx: The index of the clicked column
        :return:
        """
        oder_by = {0: "ASC", 1: "DESC"}
        sort_order = qtable.horizontalHeader().sortIndicatorOrder()
        col_to_sort = qtable.model().headerData(idx, Qt.Horizontal)
        query += f" ORDER BY {col_to_sort} {oder_by[sort_order]}"
        self.fill_table_by_query(qtable, query)
        self.refresh_map_canvas()

    def hide_colums(self, widget, comuns_to_hide):
        for i in range(0, len(comuns_to_hide)):
            widget.hideColumn(comuns_to_hide[i])

    def unselector(self, qtable_left, qtable_right, query_delete, query_left,
                   query_right, field_id_right):

        selected_list = qtable_right.selectionModel().selectedRows()
        if len(selected_list) == 0:
            message = "Any record selected"
            self.controller.show_warning(message)
            return
        expl_id = []
        for i in range(0, len(selected_list)):
            row = selected_list[i].row()
            id_ = str(qtable_right.model().record(row).value(field_id_right))
            expl_id.append(id_)
        for i in range(0, len(expl_id)):
            self.controller.execute_sql(query_delete + str(expl_id[i]))

        # Refresh
        oder_by = {0: "ASC", 1: "DESC"}
        sort_order = qtable_left.horizontalHeader().sortIndicatorOrder()
        idx = qtable_left.horizontalHeader().sortIndicatorSection()
        col_to_sort = qtable_left.model().headerData(idx, Qt.Horizontal)
        query_left += f" ORDER BY {col_to_sort} {oder_by[sort_order]}"
        self.fill_table_by_query(qtable_left, query_left)

        sort_order = qtable_right.horizontalHeader().sortIndicatorOrder()
        idx = qtable_right.horizontalHeader().sortIndicatorSection()
        col_to_sort = qtable_right.model().headerData(idx, Qt.Horizontal)
        query_right += f" ORDER BY {col_to_sort} {oder_by[sort_order]}"
        self.fill_table_by_query(qtable_right, query_right)
        self.refresh_map_canvas()

    def multi_rows_selector(self, qtable_left, qtable_right, id_ori,
                            tablename_des, id_des, query_left, query_right,
                            field_id):
        """
            :param qtable_left: QTableView origin
            :param qtable_right: QTableView destini
            :param id_ori: Refers to the id of the source table
            :param tablename_des: table destini
            :param id_des: Refers to the id of the target table, on which the query will be made
            :param query_right:
            :param query_left:
            :param field_id:
        """

        selected_list = qtable_left.selectionModel().selectedRows()

        if len(selected_list) == 0:
            message = "Any record selected"
            self.controller.show_warning(message)
            return
        expl_id = []
        curuser_list = []
        for i in range(0, len(selected_list)):
            row = selected_list[i].row()
            id_ = qtable_left.model().record(row).value(id_ori)
            expl_id.append(id_)
            curuser = qtable_left.model().record(row).value("cur_user")
            curuser_list.append(curuser)
        for i in range(0, len(expl_id)):
            # Check if expl_id already exists in expl_selector
            sql = (
                f"SELECT DISTINCT({id_des}, cur_user)"
                f" FROM {tablename_des}"
                f" WHERE {id_des} = '{expl_id[i]}' AND cur_user = current_user"
            )
            row = self.controller.get_row(sql)

            if row:
                # if exist - show warning
                message = "Id already selected"
                self.controller.show_info_box(message,
                                              "Info",
                                              parameter=str(expl_id[i]))
            else:
                sql = (f"INSERT INTO {tablename_des} ({field_id}, cur_user) "
                       f" VALUES ({expl_id[i]}, current_user)")
                self.controller.execute_sql(sql)

        # Refresh
        oder_by = {0: "ASC", 1: "DESC"}
        sort_order = qtable_left.horizontalHeader().sortIndicatorOrder()
        idx = qtable_left.horizontalHeader().sortIndicatorSection()
        col_to_sort = qtable_left.model().headerData(idx, Qt.Horizontal)
        query_left += f" ORDER BY {col_to_sort} {oder_by[sort_order]}"
        self.fill_table_by_query(qtable_right, query_right)

        sort_order = qtable_right.horizontalHeader().sortIndicatorOrder()
        idx = qtable_right.horizontalHeader().sortIndicatorSection()
        col_to_sort = qtable_right.model().headerData(idx, Qt.Horizontal)
        query_right += f" ORDER BY {col_to_sort} {oder_by[sort_order]}"
        self.fill_table_by_query(qtable_left, query_left)
        self.refresh_map_canvas()

    def fill_table_psector(self,
                           widget,
                           table_name,
                           set_edit_strategy=QSqlTableModel.OnManualSubmit):
        """ Set a model with selected @table_name. Attach that model to selected table """

        if self.schema_name not in table_name:
            table_name = self.schema_name + "." + table_name

        # Set model
        self.model = QSqlTableModel()
        self.model.setTable(table_name)
        self.model.setEditStrategy(set_edit_strategy)
        self.model.setSort(0, 0)
        self.model.select()

        # Check for errors
        if self.model.lastError().isValid():
            self.controller.show_warning(self.model.lastError().text())

        # Attach model to table view
        widget.setModel(self.model)

    def fill_table(self,
                   widget,
                   table_name,
                   set_edit_strategy=QSqlTableModel.OnManualSubmit,
                   expr_filter=None):
        """ Set a model with selected filter.
        Attach that model to selected table """

        if self.schema_name not in table_name:
            table_name = self.schema_name + "." + table_name

        # Set model
        self.model = QSqlTableModel()
        self.model.setTable(table_name)
        self.model.setEditStrategy(set_edit_strategy)
        self.model.setSort(0, 0)
        self.model.select()

        # Check for errors
        if self.model.lastError().isValid():
            self.controller.show_warning(self.model.lastError().text())

        # Attach model to table view
        widget.setModel(self.model)
        if expr_filter:
            widget.model().setFilter(expr_filter)

    def fill_table_by_query(self, qtable, query):
        """
        :param qtable: QTableView to show
        :param query: query to set model
        """

        model = QSqlQueryModel()
        model.setQuery(query)
        qtable.setModel(model)
        qtable.show()

        # Check for errors
        if model.lastError().isValid():
            self.controller.show_warning(model.lastError().text())

    def query_like_widget_text(self,
                               dialog,
                               text_line,
                               qtable,
                               tableleft,
                               tableright,
                               field_id_r,
                               field_id_l,
                               name='name'):
        """ Fill the QTableView by filtering through the QLineEdit"""

        query = utils_giswater.getWidgetText(dialog,
                                             text_line,
                                             return_string_null=False).lower()
        sql = (
            f"SELECT * FROM {tableleft} WHERE {name} NOT IN "
            f"(SELECT {tableleft}.{name} FROM {tableleft}"
            f" RIGHT JOIN {tableright}"
            f" ON {tableleft}.{field_id_l} = {tableright}.{field_id_r}"
            f" WHERE cur_user = current_user) AND LOWER({name}::text) LIKE '%{query}%'"
        )
        self.fill_table_by_query(qtable, sql)

    def set_icon(self, widget, icon):
        """ Set @icon to selected @widget """

        # Get icons folder
        icons_folder = os.path.join(self.plugin_dir, 'icons')
        icon_path = os.path.join(icons_folder, str(icon) + ".png")
        if os.path.exists(icon_path):
            widget.setIcon(QIcon(icon_path))
        else:
            self.controller.log_info("File not found", parameter=icon_path)

    def check_expression(self, expr_filter, log_info=False):
        """ Check if expression filter @expr_filter is valid """

        if log_info:
            self.controller.log_info(expr_filter)
        expr = QgsExpression(expr_filter)
        if expr.hasParserError():
            message = "Expression Error"
            self.controller.log_warning(message, parameter=expr_filter)
            return False, expr

        return True, expr

    def refresh_map_canvas(self, restore_cursor=False):
        """ Refresh all layers present in map canvas """

        self.canvas.refreshAllLayers()
        for layer_refresh in self.canvas.layers():
            layer_refresh.triggerRepaint()

        if restore_cursor:
            self.set_cursor_restore()

    def set_cursor_wait(self):
        """ Change cursor to 'WaitCursor' """
        QApplication.setOverrideCursor(Qt.WaitCursor)

    def set_cursor_restore(self):
        """ Restore to previous cursors """
        QApplication.restoreOverrideCursor()

    def get_cursor_multiple_selection(self):
        """ Set cursor for multiple selection """

        path_folder = os.path.join(os.path.dirname(__file__), os.pardir)
        path_cursor = os.path.join(path_folder, 'icons', '201.png')
        if os.path.exists(path_cursor):
            cursor = QCursor(QPixmap(path_cursor))
        else:
            cursor = QCursor(Qt.ArrowCursor)

        return cursor

    def set_table_columns(self,
                          dialog,
                          widget,
                          table_name,
                          sort_order=0,
                          isQStandardItemModel=False):
        """ Configuration of tables. Set visibility and width of columns """

        widget = utils_giswater.getWidget(dialog, widget)
        if not widget:
            return

        # Set width and alias of visible columns
        columns_to_delete = []
        sql = (f"SELECT column_index, width, alias, status"
               f" FROM config_client_forms"
               f" WHERE table_id = '{table_name}'"
               f" ORDER BY column_index")
        rows = self.controller.get_rows(sql, commit=True, log_info=False)
        if not rows:
            return

        for row in rows:
            if not row['status']:
                columns_to_delete.append(row['column_index'] - 1)
            else:
                width = row['width']
                if width is None:
                    width = 100
                widget.setColumnWidth(row['column_index'] - 1, width)
                widget.model().setHeaderData(row['column_index'] - 1,
                                             Qt.Horizontal, row['alias'])

        # Set order
        if isQStandardItemModel:
            widget.model().sort(sort_order, Qt.AscendingOrder)
        else:
            widget.model().setSort(sort_order, Qt.AscendingOrder)
            widget.model().select()
        # Delete columns
        for column in columns_to_delete:
            widget.hideColumn(column)

        return widget

    def connect_signal_selection_changed(self, option):
        """ Connect signal selectionChanged """

        try:
            if option == "mincut_connec":
                self.canvas.selectionChanged.connect(
                    partial(self.snapping_selection_connec))
            elif option == "mincut_hydro":
                self.canvas.selectionChanged.connect(
                    partial(self.snapping_selection_hydro))
        except Exception:
            pass

    def disconnect_signal_selection_changed(self):
        """ Disconnect signal selectionChanged """

        try:
            self.canvas.selectionChanged.disconnect()
        except Exception:
            pass
        finally:
            self.iface.actionPan().trigger()

    def set_label_current_psector(self, dialog):

        sql = (
            "SELECT t1.name FROM plan_psector AS t1 "
            " INNER JOIN config_param_user AS t2 ON t1.psector_id::text = t2.value "
            " WHERE t2.parameter='psector_vdefault' AND cur_user = current_user"
        )
        row = self.controller.get_row(sql)
        if not row:
            return
        utils_giswater.setWidgetText(dialog, 'lbl_vdefault_psector', row[0])

    def multi_rows_delete(self, widget, table_name, column_id):
        """ Delete selected elements of the table
        :param QTableView widget: origin
        :param table_name: table origin
        :param column_id: Refers to the id of the source table
        """

        # Get selected rows
        selected_list = widget.selectionModel().selectedRows()
        if len(selected_list) == 0:
            message = "Any record selected"
            self.controller.show_warning(message)
            return

        inf_text = ""
        list_id = ""
        for i in range(0, len(selected_list)):
            row = selected_list[i].row()
            id_ = widget.model().record(row).value(str(column_id))
            inf_text += f"{id_}, "
            list_id += f"'{id_}', "
        inf_text = inf_text[:-2]
        list_id = list_id[:-2]
        message = "Are you sure you want to delete these records?"
        title = "Delete records"
        answer = self.controller.ask_question(message, title, inf_text)
        if answer:
            sql = f"DELETE FROM {table_name}"
            sql += f" WHERE {column_id} IN ({list_id})"
            self.controller.execute_sql(sql)
            widget.model().select()

    def select_features_by_expr(self, layer, expr):
        """ Select features of @layer applying @expr """

        if not layer:
            return

        if expr is None:
            layer.removeSelection()
        else:
            it = layer.getFeatures(QgsFeatureRequest(expr))
            # Build a list of feature id's from the previous result and select them
            id_list = [i.id() for i in it]
            if len(id_list) > 0:
                layer.selectByIds(id_list)
            else:
                layer.removeSelection()

    def hide_void_groupbox(self, dialog):
        """ Hide empty grupbox """

        grbox_list = dialog.findChildren(QGroupBox)
        for grbox in grbox_list:
            widget_list = grbox.findChildren(QWidget)
            if len(widget_list) == 0:
                grbox.setVisible(False)

    def zoom_to_selected_features(self, layer, geom_type=None, zoom=None):
        """ Zoom to selected features of the @layer with @geom_type """

        if not layer:
            return

        self.iface.setActiveLayer(layer)
        self.iface.actionZoomToSelected().trigger()

        if geom_type:

            # Set scale = scale_zoom
            if geom_type in ('node', 'connec', 'gully'):
                scale = self.scale_zoom

            # Set scale = max(current_scale, scale_zoom)
            elif geom_type == 'arc':
                scale = self.iface.mapCanvas().scale()
                if int(scale) < int(self.scale_zoom):
                    scale = self.scale_zoom
            else:
                scale = 5000

            if zoom is not None:
                scale = zoom

            self.iface.mapCanvas().zoomScale(float(scale))

    def set_completer(self, tablename, widget, field_search, color='black'):
        """ Set autocomplete of widget @table_object + "_id"
            getting id's from selected @table_object
        """

        if not widget:
            return

        # Set SQL
        sql = (f"SELECT DISTINCT({field_search})"
               f" FROM {tablename}"
               f" ORDER BY {field_search}")
        row = self.controller.get_rows(sql, commit=True)

        for i in range(0, len(row)):
            aux = row[i]
            row[i] = str(aux[0])

        # Set completer and model: add autocomplete in the widget
        self.completer = QCompleter()
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.completer.setCompletionMode(0)
        self.completer.popup().setStyleSheet("color: " + color + ";")
        widget.setCompleter(self.completer)

        model = QStringListModel()
        model.setStringList(row)
        self.completer.setModel(model)

    def get_max_rectangle_from_coords(self, list_coord):
        """ Returns the minimum rectangle(x1, y1, x2, y2) of a series of coordinates
        :type list_coord: list of coors in format ['x1 y1', 'x2 y2',....,'x99 y99']
        """

        coords = list_coord.group(1)
        polygon = coords.split(',')
        x, y = polygon[0].split(' ')
        min_x = x  # start with something much higher than expected min
        min_y = y
        max_x = x  # start with something much lower than expected max
        max_y = y
        for i in range(0, len(polygon)):
            x, y = polygon[i].split(' ')
            if x < min_x:
                min_x = x
            if x > max_x:
                max_x = x
            if y < min_y:
                min_y = y
            if y > max_y:
                max_y = y

        return max_x, max_y, min_x, min_y

    def zoom_to_rectangle(self, x1, y1, x2, y2, margin=5):

        rect = QgsRectangle(
            float(x1) - margin,
            float(y1) - margin,
            float(x2) + margin,
            float(y2) + margin)
        self.canvas.setExtent(rect)
        self.canvas.refresh()

    def create_action(self,
                      action_name,
                      action_group,
                      icon_num=None,
                      text=None):
        """ Creates a new action with selected parameters """

        icon = None
        icon_folder = self.plugin_dir + '/icons/'
        icon_path = icon_folder + icon_num + '.png'
        if os.path.exists(icon_path):
            icon = QIcon(icon_path)

        if icon is None:
            action = QAction(text, action_group)
        else:
            action = QAction(icon, text, action_group)
        action.setObjectName(action_name)

        return action

    def set_wait_cursor(self):
        QApplication.instance().setOverrideCursor(Qt.WaitCursor)

    def set_arrow_cursor(self):
        QApplication.instance().setOverrideCursor(Qt.ArrowCursor)

    def delete_layer_from_toc(self, layer_name):
        """ Delete layer from toc if exist """

        layer = None
        for lyr in list(QgsProject.instance().mapLayers().values()):
            if lyr.name() == layer_name:
                layer = lyr
                break
        if layer is not None:
            QgsProject.instance().removeMapLayer(layer)
            self.delete_layer_from_toc(layer_name)

    def create_body(self, form='', feature='', filter_fields='', extras=None):
        """ Create and return parameters as body to functions"""

        client = '"client":{"device":9, "infoType":100, "lang":"ES"}, '
        form = f'"form":{{{form}}}, '
        feature = f'"feature":{{{feature}}}, '
        filter_fields = f'"filterFields":{{{filter_fields}}}'
        page_info = '"pageInfo":{}'
        data = f'"data":{{{filter_fields}, {page_info}'
        if extras is not None:
            data += ', ' + extras
        data += '}'
        body = "" + client + form + feature + data

        return body

    def set_layers_visible(self, layers):
        for layer in layers:
            lyr = self.controller.get_layer_by_tablename(layer)
            if lyr:
                self.controller.set_layer_visible(lyr)

    def add_temp_layer(self,
                       dialog,
                       data,
                       function_name,
                       force_tab=True,
                       reset_text=True,
                       tab_idx=1,
                       del_old_layers=True):
        if del_old_layers:
            self.delete_layer_from_toc(function_name)
        srid = self.controller.plugin_settings_value('srid')
        for k, v in list(data.items()):
            if str(k) == 'setVisibleLayers':
                self.set_layers_visible(v)
            elif str(k) == "info":
                self.populate_info_text(dialog, data, force_tab, reset_text,
                                        tab_idx)
            else:
                counter = len(data[k]['values'])
                if counter > 0:
                    counter = len(data[k]['values'])
                    geometry_type = data[k]['geometryType']
                    v_layer = QgsVectorLayer(
                        f"{geometry_type}?crs=epsg:{srid}", function_name,
                        'memory')
                    self.populate_vlayer(v_layer, data, k, counter)
                    if 'qmlPath' in data[k]:
                        qml_path = data[k]['qmlPath']
                        self.load_qml(v_layer, qml_path)

    def populate_info_text(self,
                           dialog,
                           data,
                           force_tab=True,
                           reset_text=True,
                           tab_idx=1):

        change_tab = False
        text = utils_giswater.getWidgetText(dialog,
                                            dialog.txt_infolog,
                                            return_string_null=False)

        if reset_text:
            text = ""
        for item in data['info']['values']:
            if 'message' in item:
                if item['message'] is not None:
                    text += str(item['message']) + "\n"
                    if force_tab:
                        change_tab = True
                else:
                    text += "\n"

        utils_giswater.setWidgetText(dialog, 'txt_infolog', text + "\n")
        qtabwidget = dialog.findChild(QTabWidget, 'mainTab')
        if change_tab and qtabwidget is not None:
            qtabwidget.setCurrentIndex(tab_idx)

        return change_tab

    def populate_vlayer(self, virtual_layer, data, layer_type, counter):

        prov = virtual_layer.dataProvider()

        # Enter editing mode
        virtual_layer.startEditing()
        if counter > 0:
            for key, value in list(data[layer_type]['values'][0].items()):
                # add columns
                if str(key) != 'the_geom':
                    prov.addAttributes([QgsField(str(key), QVariant.String)])

        # Add features
        for item in data[layer_type]['values']:
            attributes = []
            fet = QgsFeature()

            for k, v in list(item.items()):
                if str(k) != 'the_geom':
                    attributes.append(v)
                if str(k) in 'the_geom':
                    sql = f"SELECT St_AsText('{v}')"
                    row = self.controller.get_row(sql, log_sql=False)
                    geometry = QgsGeometry.fromWkt(str(row[0]))
                    fet.setGeometry(geometry)
            fet.setAttributes(attributes)
            prov.addFeatures([fet])

        # Commit changes
        virtual_layer.commitChanges()
        QgsProject.instance().addMapLayer(virtual_layer, False)
        root = QgsProject.instance().layerTreeRoot()
        my_group = root.findGroup('GW Functions results')
        if my_group is None:
            my_group = root.insertGroup(0, 'GW Functions results')

        my_group.insertLayer(0, virtual_layer)

    def get_composers_list(self):

        layour_manager = QgsProject.instance().layoutManager().layouts()
        active_composers = [layout for layout in layour_manager]
        return active_composers

    def get_composer_index(self, name):

        index = 0
        composers = self.get_composers_list()
        for comp_view in composers:
            composer_name = comp_view.name()
            if composer_name == name:
                break
            index += 1

        return index

    def get_all_actions(self):

        self.controller.log_info(str("TEST"))
        actions_list = self.iface.mainWindow().findChildren(QAction)
        for action in actions_list:
            self.controller.log_info(str(action.objectName()))
            action.triggered.connect(partial(self.show_action_name, action))

    def show_action_name(self, action):
        self.controller.log_info(str(action.objectName()))

    def set_restriction(self, dialog, widget_to_ignore, restriction):
        """
        Set all widget enabled(False) or readOnly(True) except those on the tuple
        :param dialog:
        :param widget_to_ignore: tuple = ('widgetname1', 'widgetname2', 'widgetname3', ...)
        :param restriction: roles that do not have access. tuple = ('role1', 'role1', 'role1', ...)
        :return:
        """

        role = self.controller.get_restriction()
        if role in restriction:
            widget_list = dialog.findChildren(QWidget)
            for widget in widget_list:
                if widget.objectName() in widget_to_ignore:
                    continue
                # Set editable/readonly
                if type(widget) in (QLineEdit, QDoubleSpinBox, QTextEdit):
                    widget.setReadOnly(True)
                    widget.setStyleSheet(
                        "QWidget {background: rgb(242, 242, 242);color: rgb(100, 100, 100)}"
                    )
                elif type(widget) in (QComboBox, QCheckBox, QTableView,
                                      QPushButton):
                    widget.setEnabled(False)

    def set_dates_from_to(self, widget_from, widget_to, table_name, field_from,
                          field_to):

        sql = (f"SELECT MIN(LEAST({field_from}, {field_to})),"
               f" MAX(GREATEST({field_from}, {field_to}))"
               f" FROM {table_name}")
        row = self.controller.get_row(sql, log_sql=False)
        current_date = QDate.currentDate()
        if row:
            if row[0]:
                widget_from.setDate(row[0])
            else:
                widget_from.setDate(current_date)
            if row[1]:
                widget_to.setDate(row[1])
            else:
                widget_to.setDate(current_date)

    def get_values_from_catalog(self, table_name, typevalue, order_by='id'):

        sql = (f"SELECT id, idval"
               f" FROM {table_name}"
               f" WHERE typevalue = '{typevalue}'"
               f" ORDER BY {order_by}")
        rows = self.controller.get_rows(sql, commit=True)
        return rows

    def integer_validator(self, value, widget, btn_accept):
        """ Check if the value is an integer or not.
            This function is called in def set_datatype_validator(self, value, widget, btn)
            widget = getattr(self, f"{widget.property('datatype')}_validator")( value, widget, btn)
        """
        if value is None or bool(re.search("^\d*$", value)):
            widget.setStyleSheet(
                "QLineEdit{background:rgb(255, 255, 255); color:rgb(0, 0, 0)}")
            btn_accept.setEnabled(True)
        else:
            widget.setStyleSheet("border: 1px solid red")
            btn_accept.setEnabled(False)

    def double_validator(self, value, widget, btn_accept):
        """ Check if the value is double or not.
            This function is called in def set_datatype_validator(self, value, widget, btn)
            widget = getattr(self, f"{widget.property('datatype')}_validator")( value, widget, btn)
        """
        if value is None or bool(re.search("^\d*$", value)) or bool(
                re.search("^\d+\.\d+$", value)):
            widget.setStyleSheet(
                "QLineEdit{background:rgb(255, 255, 255); color:rgb(0, 0, 0)}")
            btn_accept.setEnabled(True)
        else:
            widget.setStyleSheet("border: 1px solid red")
            btn_accept.setEnabled(False)

    def load_qml(self, layer, qml_path):
        """ Apply QML style located in @qml_path in @layer """

        if layer is None:
            return False

        if not os.path.exists(qml_path):
            self.controller.log_warning("File not found", parameter=qml_path)
            return False

        if not qml_path.endswith(".qml"):
            self.controller.log_warning("File extension not valid",
                                        parameter=qml_path)
            return False

        layer.loadNamedStyle(qml_path)
        layer.triggerRepaint()

        return True

    def open_file_path(self, filter_="All (*.*)"):
        """ Open QFileDialog """
        msg = self.controller.tr("Select DXF file")
        path, filter_ = QFileDialog.getOpenFileName(None, msg, "", filter_)

        return path, filter_

    def show_exceptions_msg(self, title, msg=""):
        cat_exception = {
            'KeyError': 'Key on returned json from ddbb is missed.'
        }
        self.dlg_info = BasicInfo()
        self.dlg_info.btn_accept.setVisible(False)
        self.dlg_info.btn_close.clicked.connect(
            partial(self.close_dialog, self.dlg_info))
        self.dlg_info.setWindowTitle(title)
        utils_giswater.setWidgetText(self.dlg_info, self.dlg_info.txt_info,
                                     msg)
        self.open_dialog(self.dlg_info)
Example #27
0
class Go2Epa(ApiParent):
    def __init__(self, iface, settings, controller, plugin_dir):
        """ Class to control toolbar 'go2epa' """

        ApiParent.__init__(self, iface, settings, controller, plugin_dir)

        self.g2epa_opt = Go2EpaOptions(iface, settings, controller, plugin_dir)
        self.iterations = 0

    def set_project_type(self, project_type):
        self.project_type = project_type

    def go2epa(self):
        """ Button 23: Open form to set INP, RPT and project """

        # Show form in docker?
        self.controller.init_docker('qgis_form_docker')

        # Create dialog
        self.dlg_go2epa = Go2EpaUI()
        self.load_settings(self.dlg_go2epa)
        self.load_user_values()
        if self.project_type in 'ws':
            self.dlg_go2epa.chk_export_subcatch.setVisible(False)

        # Set signals
        self.set_signals()

        if self.project_type == 'ws':
            self.dlg_go2epa.btn_hs_ds.setText("Dscenario Selector")
            tableleft = "cat_dscenario"
            tableright = "selector_inp_demand"
            field_id_left = "dscenario_id"
            field_id_right = "dscenario_id"
            self.dlg_go2epa.btn_hs_ds.clicked.connect(
                partial(self.sector_selection,
                        tableleft,
                        tableright,
                        field_id_left,
                        field_id_right,
                        aql=""))

        elif self.project_type == 'ud':
            self.dlg_go2epa.btn_hs_ds.setText("Hydrology selector")
            self.dlg_go2epa.btn_hs_ds.clicked.connect(
                self.ud_hydrology_selector)

        # Check OS and enable/disable checkbox execute EPA software
        if sys.platform != "win32":
            utils_giswater.setChecked(self.dlg_go2epa,
                                      self.dlg_go2epa.chk_exec, False)
            self.dlg_go2epa.chk_exec.setEnabled(False)
            self.dlg_go2epa.chk_exec.setText(
                'Execute EPA software (Runs only on Windows)')

        self.set_completer_result(self.dlg_go2epa.txt_result_name,
                                  'v_ui_rpt_cat_result', 'result_id')

        if self.controller.dlg_docker:
            self.controller.manage_translation('go2epa', self.dlg_go2epa)
            self.controller.dock_dialog(self.dlg_go2epa)
            self.dlg_go2epa.btn_cancel.clicked.disconnect()
            self.dlg_go2epa.btn_cancel.clicked.connect(
                self.controller.close_docker)
        else:
            self.open_dialog(self.dlg_go2epa, dlg_name='go2epa')

    def set_signals(self):

        self.dlg_go2epa.txt_result_name.textChanged.connect(
            partial(self.check_result_id))
        self.dlg_go2epa.btn_file_inp.clicked.connect(
            self.go2epa_select_file_inp)
        self.dlg_go2epa.btn_file_rpt.clicked.connect(
            self.go2epa_select_file_rpt)
        self.dlg_go2epa.btn_accept.clicked.connect(self.go2epa_accept)
        self.dlg_go2epa.btn_cancel.clicked.connect(
            partial(self.close_dialog, self.dlg_go2epa))
        self.dlg_go2epa.rejected.connect(
            partial(self.close_dialog, self.dlg_go2epa))
        self.dlg_go2epa.btn_options.clicked.connect(self.epa_options)

    def check_inp_chk(self, file_inp):

        if file_inp is None:
            msg = "Select valid INP file"
            self.controller.show_warning(msg, parameter=str(file_inp))
            return False

    def check_rpt(self):

        file_inp = utils_giswater.getWidgetText(self.dlg_go2epa,
                                                self.dlg_go2epa.txt_file_inp)
        file_rpt = utils_giswater.getWidgetText(self.dlg_go2epa,
                                                self.dlg_go2epa.txt_file_rpt)

        # Control execute epa software
        if utils_giswater.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_exec):
            if self.check_inp_chk(file_inp) is False:
                return False

            if file_rpt is None:
                msg = "Select valid RPT file"
                self.controller.show_warning(msg, parameter=str(file_rpt))
                return False

            if not utils_giswater.isChecked(self.dlg_go2epa,
                                            self.dlg_go2epa.chk_export):
                if not os.path.exists(file_inp):
                    msg = "File INP not found"
                    self.controller.show_warning(msg, parameter=str(file_rpt))
                    return False

    def check_fields(self):

        file_inp = utils_giswater.getWidgetText(self.dlg_go2epa,
                                                self.dlg_go2epa.txt_file_inp)
        file_rpt = utils_giswater.getWidgetText(self.dlg_go2epa,
                                                self.dlg_go2epa.txt_file_rpt)
        result_name = utils_giswater.getWidgetText(
            self.dlg_go2epa, self.dlg_go2epa.txt_result_name, False, False)

        # Check if at least one process is selected
        export_checked = utils_giswater.isChecked(self.dlg_go2epa,
                                                  self.dlg_go2epa.chk_export)
        exec_checked = utils_giswater.isChecked(self.dlg_go2epa,
                                                self.dlg_go2epa.chk_exec)
        import_result_checked = utils_giswater.isChecked(
            self.dlg_go2epa, self.dlg_go2epa.chk_import_result)

        if not export_checked and not exec_checked and not import_result_checked:
            msg = "You need to select at least one process"
            self.controller.show_info_box(msg, title="Go2Epa")
            return False

        # Control export INP
        if utils_giswater.isChecked(self.dlg_go2epa,
                                    self.dlg_go2epa.chk_export):
            if self.check_inp_chk(file_inp) is False:
                return False

        # Control execute epa software
        if self.check_rpt() is False:
            return False

        # Control import result
        if utils_giswater.isChecked(self.dlg_go2epa,
                                    self.dlg_go2epa.chk_import_result):
            if file_rpt is None:
                msg = "Select valid RPT file"
                self.controller.show_warning(msg, parameter=str(file_rpt))
                return False
            if not utils_giswater.isChecked(self.dlg_go2epa,
                                            self.dlg_go2epa.chk_exec):
                if not os.path.exists(file_rpt):
                    msg = "File RPT not found"
                    self.controller.show_warning(msg, parameter=str(file_rpt))
                    return False
            else:
                if self.check_rpt() is False:
                    return False

        # Control result name
        if result_name == '':
            self.dlg_go2epa.txt_result_name.setStyleSheet(
                "border: 1px solid red")
            msg = "This parameter is mandatory. Please, set a value"
            self.controller.show_details(msg, title="Rpt fail", inf_text=None)
            return False

        sql = (f"SELECT result_id FROM rpt_cat_result "
               f"WHERE result_id = '{result_name}' LIMIT 1")
        row = self.controller.get_row(sql)
        if row:
            msg = "Result name already exists, do you want overwrite?"
            answer = self.controller.ask_question(msg, title="Alert")
            if not answer:
                return False

        return True

    def load_user_values(self):
        """ Load QGIS settings related with file_manager """

        cur_user = self.controller.get_current_user()

        self.dlg_go2epa.txt_result_name.setMaxLength(16)
        self.result_name = self.controller.plugin_settings_value(
            'go2epa_RESULT_NAME' + cur_user)
        self.dlg_go2epa.txt_result_name.setText(self.result_name)
        self.file_inp = self.controller.plugin_settings_value(
            'go2epa_FILE_INP' + cur_user)
        self.dlg_go2epa.txt_file_inp.setText(self.file_inp)
        self.file_rpt = self.controller.plugin_settings_value(
            'go2epa_FILE_RPT' + cur_user)
        self.dlg_go2epa.txt_file_rpt.setText(self.file_rpt)

        value = self.controller.plugin_settings_value(
            'go2epa_chk_NETWORK_GEOM' + cur_user)
        if str(value) == 'true':
            utils_giswater.setChecked(self.dlg_go2epa,
                                      self.dlg_go2epa.chk_only_check, True)
        value = self.controller.plugin_settings_value('go2epa_chk_INP' +
                                                      cur_user)
        if str(value) == 'true':
            utils_giswater.setChecked(self.dlg_go2epa,
                                      self.dlg_go2epa.chk_export, True)
        value = self.controller.plugin_settings_value('go2epa_chk_UD' +
                                                      cur_user)
        if str(value) == 'true':
            utils_giswater.setChecked(self.dlg_go2epa,
                                      self.dlg_go2epa.chk_export_subcatch,
                                      True)
        value = self.controller.plugin_settings_value('go2epa_chk_EPA' +
                                                      cur_user)
        if str(value) == 'true':
            utils_giswater.setChecked(self.dlg_go2epa,
                                      self.dlg_go2epa.chk_exec, True)
        value = self.controller.plugin_settings_value('go2epa_chk_RPT' +
                                                      cur_user)
        if str(value) == 'true':
            utils_giswater.setChecked(self.dlg_go2epa,
                                      self.dlg_go2epa.chk_import_result, True)

    def save_user_values(self):
        """ Save QGIS settings related with file_manager """

        cur_user = self.controller.get_current_user()
        self.controller.plugin_settings_set_value(
            'go2epa_RESULT_NAME' + cur_user,
            utils_giswater.getWidgetText(self.dlg_go2epa,
                                         'txt_result_name',
                                         return_string_null=False))
        self.controller.plugin_settings_set_value(
            'go2epa_FILE_INP' + cur_user,
            utils_giswater.getWidgetText(self.dlg_go2epa,
                                         'txt_file_inp',
                                         return_string_null=False))
        self.controller.plugin_settings_set_value(
            'go2epa_FILE_RPT' + cur_user,
            utils_giswater.getWidgetText(self.dlg_go2epa,
                                         'txt_file_rpt',
                                         return_string_null=False))
        self.controller.plugin_settings_set_value(
            'go2epa_chk_NETWORK_GEOM' + cur_user,
            utils_giswater.isChecked(self.dlg_go2epa,
                                     self.dlg_go2epa.chk_only_check))
        self.controller.plugin_settings_set_value(
            'go2epa_chk_INP' + cur_user,
            utils_giswater.isChecked(self.dlg_go2epa,
                                     self.dlg_go2epa.chk_export))
        self.controller.plugin_settings_set_value(
            'go2epa_chk_UD' + cur_user,
            utils_giswater.isChecked(self.dlg_go2epa,
                                     self.dlg_go2epa.chk_export_subcatch))
        self.controller.plugin_settings_set_value(
            'go2epa_chk_EPA' + cur_user,
            utils_giswater.isChecked(self.dlg_go2epa,
                                     self.dlg_go2epa.chk_exec))
        self.controller.plugin_settings_set_value(
            'go2epa_chk_RPT' + cur_user,
            utils_giswater.isChecked(self.dlg_go2epa,
                                     self.dlg_go2epa.chk_import_result))

    def sector_selection(self,
                         tableleft,
                         tableright,
                         field_id_left,
                         field_id_right,
                         aql=""):
        """ Load the tables in the selection form """

        dlg_psector_sel = Multirow_selector('dscenario')
        self.load_settings(dlg_psector_sel)
        dlg_psector_sel.btn_ok.clicked.connect(dlg_psector_sel.close)

        if tableleft == 'cat_dscenario':
            dlg_psector_sel.setWindowTitle(" Dscenario selector")
            utils_giswater.setWidgetText(
                dlg_psector_sel, dlg_psector_sel.lbl_filter,
                self.controller.tr('Filter by: Dscenario name',
                                   context_name='labels'))
            utils_giswater.setWidgetText(
                dlg_psector_sel, dlg_psector_sel.lbl_unselected,
                self.controller.tr('Unselected dscenarios',
                                   context_name='labels'))
            utils_giswater.setWidgetText(
                dlg_psector_sel, dlg_psector_sel.lbl_selected,
                self.controller.tr('Selected dscenarios',
                                   context_name='labels'))

        self.multi_row_selector(dlg_psector_sel,
                                tableleft,
                                tableright,
                                field_id_left,
                                field_id_right,
                                aql=aql)

        self.open_dialog(dlg_psector_sel)

    def epa_options(self):
        """ Open dialog api_epa_options.ui.ui """

        self.g2epa_opt.go2epa_options()
        return

    def ud_hydrology_selector(self):
        """ Dialog hydrology_selector.ui """

        self.dlg_hydrology_selector = HydrologySelector()
        self.load_settings(self.dlg_hydrology_selector)

        self.dlg_hydrology_selector.btn_accept.clicked.connect(
            self.save_hydrology)
        self.dlg_hydrology_selector.hydrology.currentIndexChanged.connect(
            self.update_labels)
        self.dlg_hydrology_selector.txt_name.textChanged.connect(
            partial(self.filter_cbx_by_text, "cat_hydrology",
                    self.dlg_hydrology_selector.txt_name,
                    self.dlg_hydrology_selector.hydrology))

        sql = "SELECT DISTINCT(name), hydrology_id FROM cat_hydrology ORDER BY name"
        rows = self.controller.get_rows(sql)
        if not rows:
            message = "Any data found in table"
            self.controller.show_warning(message, parameter='cat_hydrology')
            return False

        utils_giswater.set_item_data(self.dlg_hydrology_selector.hydrology,
                                     rows)

        sql = (
            "SELECT DISTINCT(t1.name) FROM cat_hydrology AS t1 "
            "INNER JOIN selector_inp_hydrology AS t2 ON t1.hydrology_id = t2.hydrology_id "
            "WHERE t2.cur_user = current_user")
        row = self.controller.get_row(sql)
        if row:
            utils_giswater.setWidgetText(self.dlg_hydrology_selector,
                                         self.dlg_hydrology_selector.hydrology,
                                         row[0])
        else:
            utils_giswater.setWidgetText(self.dlg_hydrology_selector,
                                         self.dlg_hydrology_selector.hydrology,
                                         0)

        self.update_labels()
        self.open_dialog(self.dlg_hydrology_selector)

    def save_hydrology(self):

        hydrology_id = utils_giswater.get_item_data(
            self.dlg_hydrology_selector, self.dlg_hydrology_selector.hydrology,
            1)
        sql = ("SELECT cur_user FROM selector_inp_hydrology "
               "WHERE cur_user = current_user")
        row = self.controller.get_row(sql)
        if row:
            sql = (f"UPDATE selector_inp_hydrology "
                   f"SET hydrology_id = {hydrology_id} "
                   f"WHERE cur_user = current_user")
        else:
            sql = (
                f"INSERT INTO selector_inp_hydrology (hydrology_id, cur_user) "
                f"VALUES('{hydrology_id}', current_user)")
        self.controller.execute_sql(sql)

        message = "Values has been update"
        self.controller.show_info(message)
        self.close_dialog(self.dlg_hydrology_selector)

    def update_labels(self):
        """ Show text in labels from SELECT """

        sql = (
            f"SELECT infiltration, text FROM cat_hydrology"
            f" WHERE name = '{self.dlg_hydrology_selector.hydrology.currentText()}'"
        )
        row = self.controller.get_row(sql)
        if row is not None:
            utils_giswater.setText(self.dlg_hydrology_selector,
                                   self.dlg_hydrology_selector.infiltration,
                                   row[0])
            utils_giswater.setText(self.dlg_hydrology_selector,
                                   self.dlg_hydrology_selector.descript,
                                   row[1])

    def filter_cbx_by_text(self, tablename, widgettxt, widgetcbx):

        sql = (f"SELECT DISTINCT(name), hydrology_id FROM {tablename}"
               f" WHERE name LIKE '%{widgettxt.text()}%'"
               f" ORDER BY name ")
        rows = self.controller.get_rows(sql)
        if not rows:
            message = "Check the table 'cat_hydrology' "
            self.controller.show_warning(message)
            return False
        utils_giswater.set_item_data(widgetcbx, rows)
        self.update_labels()

    def go2epa_select_file_inp(self):
        """ Select INP file """

        self.file_inp = utils_giswater.getWidgetText(
            self.dlg_go2epa, self.dlg_go2epa.txt_file_inp)
        # Set default value if necessary
        if self.file_inp is None or self.file_inp == '':
            self.file_inp = self.plugin_dir

        # Get directory of that file
        folder_path = os.path.dirname(self.file_inp)
        if not os.path.exists(folder_path):
            folder_path = os.path.dirname(__file__)
        os.chdir(folder_path)
        message = self.controller.tr("Select INP file")
        widget_is_checked = utils_giswater.isChecked(
            self.dlg_go2epa, self.dlg_go2epa.chk_export)
        if widget_is_checked:
            self.file_inp, filter_ = QFileDialog.getSaveFileName(
                None, message, "", '*.inp')
        else:
            self.file_inp, filter_ = QFileDialog.getOpenFileName(
                None, message, "", '*.inp')
        utils_giswater.setWidgetText(self.dlg_go2epa,
                                     self.dlg_go2epa.txt_file_inp,
                                     self.file_inp)

    def go2epa_select_file_rpt(self):
        """ Select RPT file """

        # Set default value if necessary
        if self.file_rpt is None or self.file_rpt == '':
            self.file_rpt = self.plugin_dir

        # Get directory of that file
        folder_path = os.path.dirname(self.file_rpt)
        if not os.path.exists(folder_path):
            folder_path = os.path.dirname(__file__)
        os.chdir(folder_path)
        message = self.controller.tr("Select RPT file")
        widget_is_checked = utils_giswater.isChecked(
            self.dlg_go2epa, self.dlg_go2epa.chk_export)
        if widget_is_checked:
            self.file_rpt, filter_ = QFileDialog.getSaveFileName(
                None, message, "", '*.rpt')
        else:
            self.file_rpt, filter_ = QFileDialog.getOpenFileName(
                None, message, "", '*.rpt')
        utils_giswater.setWidgetText(self.dlg_go2epa,
                                     self.dlg_go2epa.txt_file_rpt,
                                     self.file_rpt)

    def go2epa_accept(self):
        """ Save INP, RPT and result name into GSW file """

        # Save user values
        self.save_user_values()

        self.dlg_go2epa.txt_infolog.clear()
        self.dlg_go2epa.txt_file_rpt.setStyleSheet(None)
        status = self.check_fields()
        if status is False:
            return

        # Get widgets values
        self.result_name = utils_giswater.getWidgetText(
            self.dlg_go2epa, self.dlg_go2epa.txt_result_name, False, False)
        self.net_geom = utils_giswater.isChecked(
            self.dlg_go2epa, self.dlg_go2epa.chk_only_check)
        self.export_inp = utils_giswater.isChecked(self.dlg_go2epa,
                                                   self.dlg_go2epa.chk_export)
        self.export_subcatch = utils_giswater.isChecked(
            self.dlg_go2epa, self.dlg_go2epa.chk_export_subcatch)
        self.file_inp = utils_giswater.getWidgetText(
            self.dlg_go2epa, self.dlg_go2epa.txt_file_inp)
        self.exec_epa = utils_giswater.isChecked(self.dlg_go2epa,
                                                 self.dlg_go2epa.chk_exec)
        self.file_rpt = utils_giswater.getWidgetText(
            self.dlg_go2epa, self.dlg_go2epa.txt_file_rpt)
        self.import_result = utils_giswater.isChecked(
            self.dlg_go2epa, self.dlg_go2epa.chk_import_result)

        # Check for sector selector
        if self.export_inp:
            sql = "SELECT sector_id FROM selector_sector LIMIT 1"
            row = self.controller.get_row(sql)
            if row is None:
                msg = "You need to select some sector"
                self.controller.show_info_box(msg)
                return

        # Set background task 'Go2Epa'
        description = f"Go2Epa"
        self.task_go2epa = TaskGo2Epa(description, self.controller, self)
        QgsApplication.taskManager().addTask(self.task_go2epa)
        QgsApplication.taskManager().triggerTask(self.task_go2epa)

    def set_completer_result(self, widget, viewname, field_name):
        """ Set autocomplete of widget 'feature_id'
            getting id's from selected @viewname
        """

        result_name = utils_giswater.getWidgetText(
            self.dlg_go2epa, self.dlg_go2epa.txt_result_name)

        # Adding auto-completion to a QLineEdit
        self.completer = QCompleter()
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        widget.setCompleter(self.completer)
        model = QStringListModel()

        sql = f"SELECT {field_name} FROM {viewname}"
        rows = self.controller.get_rows(sql)

        if rows:
            for i in range(0, len(rows)):
                aux = rows[i]
                rows[i] = str(aux[0])

            model.setStringList(rows)
            self.completer.setModel(model)
            if result_name in rows:
                self.dlg_go2epa.chk_only_check.setEnabled(True)

    def check_result_id(self):
        """ Check if selected @result_id already exists """

        result_id = utils_giswater.getWidgetText(
            self.dlg_go2epa, self.dlg_go2epa.txt_result_name)
        sql = (f"SELECT result_id FROM v_ui_rpt_cat_result"
               f" WHERE result_id = '{result_id}'")
        row = self.controller.get_row(sql, log_info=False)
        if not row:
            self.dlg_go2epa.chk_only_check.setChecked(False)
            self.dlg_go2epa.chk_only_check.setEnabled(False)
        else:
            self.dlg_go2epa.chk_only_check.setEnabled(True)

    def check_data(self):
        """ Check data executing function 'gw_fct_pg2epa' """

        sql = f"SELECT gw_fct_pg2epa('{self.project_name}', 'True');"
        row = self.controller.get_row(sql)
        if not row:
            return False

        if row[0] > 0:
            message = ("It is not possible to execute the epa model."
                       "There are errors on your project. Review it!")
            sql_details = (
                f"SELECT table_id, column_id, error_message"
                f" FROM audit_check_data"
                f" WHERE fid = 114 AND result_id = '{self.project_name}'")
            inf_text = "For more details execute query:\n" + sql_details
            title = "Execute epa model"
            self.controller.show_info_box(message,
                                          title,
                                          inf_text,
                                          parameter=row[0])
            self.csv_audit_check_data("audit_check_data",
                                      "audit_check_data_log.csv")
            return False

        else:
            message = "Data is ok. You can try to generate the INP file"
            title = "Execute epa model"
            self.controller.show_info_box(message, title)
            return True

    def csv_audit_check_data(self, tablename, filename):

        # Get columns name in order of the table
        rows = self.controller.get_columns_list(tablename)
        if not rows:
            message = "Table not found"
            self.controller.show_warning(message, parameter=tablename)
            return

        columns = []
        for i in range(0, len(rows)):
            column_name = rows[i]
            columns.append(str(column_name[0]))
        sql = (f"SELECT table_id, column_id, error_message"
               f" FROM {tablename}"
               f" WHERE fid = 114 AND result_id = '{self.project_name}'")
        rows = self.controller.get_rows(sql)
        if not rows:
            message = "No records found with selected 'result_id'"
            self.controller.show_warning(message, parameter=self.project_name)
            return

        all_rows = []
        all_rows.append(columns)
        for i in rows:
            all_rows.append(i)
        path = self.controller.get_log_folder() + filename
        try:
            with open(path, "w") as output:
                writer = csv.writer(output, lineterminator='\n')
                writer.writerows(all_rows)
            message = "File created successfully"
            self.controller.show_info(message, parameter=path)
        except IOError:
            message = "File cannot be created. Check if it is already opened"
            self.controller.show_warning(message, parameter=path)

    def save_file_parameters(self):
        """ Save INP, RPT and result name into GSW file """

        self.gsw_settings.setValue('FILE_INP', self.file_inp)
        self.gsw_settings.setValue('FILE_RPT', self.file_rpt)
        self.gsw_settings.setValue('RESULT_NAME', self.result_name)

    def go2epa_result_selector(self):
        """ Button 29: Epa result selector """

        # Create the dialog and signals
        self.dlg_go2epa_result = Go2EpaSelectorUi()
        self.load_settings(self.dlg_go2epa_result)
        if self.project_type == 'ud':
            utils_giswater.remove_tab_by_tabName(
                self.dlg_go2epa_result.tabWidget, "tab_time")
        if self.project_type == 'ws':
            utils_giswater.remove_tab_by_tabName(
                self.dlg_go2epa_result.tabWidget, "tab_datetime")
        self.dlg_go2epa_result.btn_accept.clicked.connect(
            self.result_selector_accept)
        self.dlg_go2epa_result.btn_cancel.clicked.connect(
            partial(self.close_dialog, self.dlg_go2epa_result))
        self.dlg_go2epa_result.rejected.connect(
            partial(self.close_dialog, self.dlg_go2epa_result))

        # Set values from widgets of type QComboBox
        sql = ("SELECT DISTINCT(result_id), result_id "
               "FROM v_ui_rpt_cat_result ORDER BY result_id")
        rows = self.controller.get_rows(sql)
        utils_giswater.set_item_data(
            self.dlg_go2epa_result.rpt_selector_result_id, rows)
        rows = self.controller.get_rows(sql, add_empty_row=True)
        utils_giswater.set_item_data(
            self.dlg_go2epa_result.rpt_selector_compare_id, rows)

        if self.project_type == 'ws':

            sql = ("SELECT DISTINCT time, time FROM rpt_arc "
                   "WHERE result_id ILIKE '%%' ORDER BY time")
            rows = self.controller.get_rows(sql, add_empty_row=True)
            utils_giswater.set_item_data(
                self.dlg_go2epa_result.cmb_time_to_show, rows)
            utils_giswater.set_item_data(
                self.dlg_go2epa_result.cmb_time_to_compare, rows)

            self.dlg_go2epa_result.rpt_selector_result_id.currentIndexChanged.connect(
                partial(self.populate_time,
                        self.dlg_go2epa_result.rpt_selector_result_id,
                        self.dlg_go2epa_result.cmb_time_to_show))
            self.dlg_go2epa_result.rpt_selector_compare_id.currentIndexChanged.connect(
                partial(self.populate_time,
                        self.dlg_go2epa_result.rpt_selector_compare_id,
                        self.dlg_go2epa_result.cmb_time_to_compare))

        elif self.project_type == 'ud':

            # Populate GroupBox Selector date
            result_id = utils_giswater.get_item_data(
                self.dlg_go2epa_result,
                self.dlg_go2epa_result.rpt_selector_result_id, 0)
            sql = (f"SELECT DISTINCT(resultdate), resultdate FROM rpt_arc "
                   f"WHERE result_id = '{result_id}' "
                   f"ORDER BY resultdate")
            rows = self.controller.get_rows(sql)
            if rows is not None:
                utils_giswater.set_item_data(
                    self.dlg_go2epa_result.cmb_sel_date, rows)
                selector_date = utils_giswater.get_item_data(
                    self.dlg_go2epa_result,
                    self.dlg_go2epa_result.cmb_sel_date, 0)
                sql = (f"SELECT DISTINCT(resulttime), resulttime FROM rpt_arc "
                       f"WHERE result_id = '{result_id}' "
                       f"AND resultdate = '{selector_date}' "
                       f"ORDER BY resulttime")
                rows = self.controller.get_rows(sql, add_empty_row=True)
                utils_giswater.set_item_data(
                    self.dlg_go2epa_result.cmb_sel_time, rows)

            self.dlg_go2epa_result.rpt_selector_result_id.currentIndexChanged.connect(
                partial(self.populate_date_time,
                        self.dlg_go2epa_result.cmb_sel_date))

            self.dlg_go2epa_result.cmb_sel_date.currentIndexChanged.connect(
                partial(self.populate_time,
                        self.dlg_go2epa_result.rpt_selector_result_id,
                        self.dlg_go2epa_result.cmb_sel_time))

            # Populate GroupBox Selector compare
            result_id_to_comp = utils_giswater.get_item_data(
                self.dlg_go2epa_result,
                self.dlg_go2epa_result.rpt_selector_result_id, 0)
            sql = (f"SELECT DISTINCT(resultdate), resultdate FROM rpt_arc "
                   f"WHERE result_id = '{result_id_to_comp}' "
                   f"ORDER BY resultdate ")
            rows = self.controller.get_rows(sql)
            if rows is not None:
                utils_giswater.set_item_data(
                    self.dlg_go2epa_result.cmb_com_date, rows)
                selector_cmp_date = utils_giswater.get_item_data(
                    self.dlg_go2epa_result,
                    self.dlg_go2epa_result.cmb_com_date, 0)
                sql = (f"SELECT DISTINCT(resulttime), resulttime FROM rpt_arc "
                       f"WHERE result_id = '{result_id_to_comp}' "
                       f"AND resultdate = '{selector_cmp_date}' "
                       f"ORDER BY resulttime")
                rows = self.controller.get_rows(sql, add_empty_row=True)
                utils_giswater.set_item_data(
                    self.dlg_go2epa_result.cmb_com_time, rows)

            self.dlg_go2epa_result.rpt_selector_compare_id.currentIndexChanged.connect(
                partial(self.populate_date_time,
                        self.dlg_go2epa_result.cmb_com_date))
            self.dlg_go2epa_result.cmb_com_date.currentIndexChanged.connect(
                partial(self.populate_time,
                        self.dlg_go2epa_result.rpt_selector_compare_id,
                        self.dlg_go2epa_result.cmb_com_time))

        # Get current data from tables 'rpt_selector_result' and 'rpt_selector_compare'
        sql = "SELECT result_id FROM selector_rpt_main"
        row = self.controller.get_row(sql)
        if row:
            utils_giswater.set_combo_itemData(
                self.dlg_go2epa_result.rpt_selector_result_id,
                row["result_id"], 0)
        sql = "SELECT result_id FROM selector_rpt_compare"
        row = self.controller.get_row(sql)
        if row:
            utils_giswater.set_combo_itemData(
                self.dlg_go2epa_result.rpt_selector_compare_id,
                row["result_id"], 0)

        # Open the dialog
        self.open_dialog(self.dlg_go2epa_result, dlg_name='go2epa_selector')

    def populate_date_time(self, combo_date):

        result_id = utils_giswater.get_item_data(
            self.dlg_go2epa_result,
            self.dlg_go2epa_result.rpt_selector_result_id, 0)
        sql = (f"SELECT DISTINCT(resultdate), resultdate FROM rpt_arc "
               f"WHERE result_id = '{result_id}' "
               f"ORDER BY resultdate")
        rows = self.controller.get_rows(sql)
        utils_giswater.set_item_data(combo_date, rows)

    def populate_time(self, combo_result, combo_time):
        """ Populate combo times """

        result_id = utils_giswater.get_item_data(self.dlg_go2epa_result,
                                                 combo_result)
        if self.project_type == 'ws':
            field = "time"
        else:
            field = "resulttime"

        sql = (f"SELECT DISTINCT {field}, {field} "
               f"FROM rpt_arc "
               f"WHERE result_id ILIKE '{result_id}' "
               f"ORDER BY {field};")

        rows = self.controller.get_rows(sql, add_empty_row=True)
        utils_giswater.set_item_data(combo_time, rows)

    def result_selector_accept(self):
        """ Update current values to the table """

        # Set project user
        user = self.controller.get_project_user()

        # Delete previous values
        sql = (
            f"DELETE FROM selector_rpt_main WHERE cur_user = '******';\n"
            f"DELETE FROM selector_rpt_compare WHERE cur_user = '******';\n")
        sql += (
            f"DELETE FROM selector_rpt_main_tstep WHERE cur_user = '******';\n"
            f"DELETE FROM selector_rpt_compare_tstep WHERE cur_user = '******';\n"
        )
        self.controller.execute_sql(sql)

        # Get new values from widgets of type QComboBox
        rpt_selector_result_id = utils_giswater.get_item_data(
            self.dlg_go2epa_result,
            self.dlg_go2epa_result.rpt_selector_result_id)
        rpt_selector_compare_id = utils_giswater.get_item_data(
            self.dlg_go2epa_result,
            self.dlg_go2epa_result.rpt_selector_compare_id)

        if rpt_selector_result_id not in (None, -1, ''):
            sql = (f"INSERT INTO selector_rpt_main (result_id, cur_user)"
                   f" VALUES ('{rpt_selector_result_id}', '{user}');\n")
            self.controller.execute_sql(sql)

        if rpt_selector_compare_id not in (None, -1, ''):
            sql = (f"INSERT INTO selector_rpt_compare (result_id, cur_user)"
                   f" VALUES ('{rpt_selector_compare_id}', '{user}');\n")
            self.controller.execute_sql(sql)

        if self.project_type == 'ws':
            time_to_show = utils_giswater.get_item_data(
                self.dlg_go2epa_result,
                self.dlg_go2epa_result.cmb_time_to_show)
            time_to_compare = utils_giswater.get_item_data(
                self.dlg_go2epa_result,
                self.dlg_go2epa_result.cmb_time_to_compare)
            if time_to_show not in (None, -1, ''):
                sql = (
                    f"INSERT INTO selector_rpt_main_tstep (timestep, cur_user)"
                    f" VALUES ('{time_to_show}', '{user}');\n")
                self.controller.execute_sql(sql)
            if time_to_compare not in (None, -1, ''):
                sql = (
                    f"INSERT INTO selector_rpt_compare_tstep (timestep, cur_user)"
                    f" VALUES ('{time_to_compare}', '{user}');\n")
                self.controller.execute_sql(sql)

        elif self.project_type == 'ud':
            date_to_show = utils_giswater.get_item_data(
                self.dlg_go2epa_result, self.dlg_go2epa_result.cmb_sel_date)
            time_to_show = utils_giswater.get_item_data(
                self.dlg_go2epa_result, self.dlg_go2epa_result.cmb_sel_time)
            date_to_compare = utils_giswater.get_item_data(
                self.dlg_go2epa_result, self.dlg_go2epa_result.cmb_com_date)
            time_to_compare = utils_giswater.get_item_data(
                self.dlg_go2epa_result, self.dlg_go2epa_result.cmb_com_time)
            if date_to_show not in (None, -1, ''):
                sql = (
                    f"INSERT INTO selector_rpt_main_tstep (resultdate, resulttime, cur_user)"
                    f" VALUES ('{date_to_show}', '{time_to_show}', '{user}');\n"
                )
                self.controller.execute_sql(sql)
            if date_to_compare not in (None, -1, ''):
                sql = (
                    f"INSERT INTO selector_rpt_compare_tstep (resultdate, resulttime, cur_user)"
                    f" VALUES ('{date_to_compare}', '{time_to_compare}', '{user}');\n"
                )
                self.controller.execute_sql(sql)

        # Show message to user
        message = "Values has been updated"
        self.controller.show_info(message)
        self.close_dialog(self.dlg_go2epa_result)

    def go2epa_options_get_data(self, tablename, dialog):
        """ Get data from selected table """

        sql = f"SELECT * FROM {tablename}"
        row = self.controller.get_row(sql)
        if not row:
            message = "Any data found in table"
            self.controller.show_warning(message, parameter=tablename)
            return None

        # Iterate over all columns and populate its corresponding widget
        columns = []
        for i in range(0, len(row)):
            column_name = self.dao.get_column_name(i)
            widget = dialog.findChild(QWidget, column_name)
            widget_type = utils_giswater.getWidgetType(dialog, widget)
            if row[column_name] is not None:
                if widget_type is QCheckBox:
                    utils_giswater.setChecked(dialog, widget, row[column_name])
                elif widget_type is QComboBox:
                    utils_giswater.set_combo_itemData(widget, row[column_name],
                                                      0)
                elif widget_type is QDateEdit:
                    dateaux = row[column_name].replace('/', '-')
                    date = QDate.fromString(dateaux, 'dd-MM-yyyy')
                    utils_giswater.setCalendarDate(dialog, widget, date)
                elif widget_type is QTimeEdit:
                    timeparts = str(row[column_name]).split(':')
                    if len(timeparts) < 3:
                        timeparts.append("0")
                    days = int(timeparts[0]) / 24
                    hours = int(timeparts[0]) % 24
                    minuts = int(timeparts[1])
                    seconds = int(timeparts[2])
                    time = QTime(hours, minuts, seconds)
                    utils_giswater.setTimeEdit(dialog, widget, time)
                    utils_giswater.setText(dialog, column_name + "_day", days)
                else:
                    utils_giswater.setWidgetText(dialog, widget,
                                                 str(row[column_name]))

            columns.append(column_name)

        return columns

    def go2epa_result_manager(self):
        """ Button 25: Epa result manager """

        # Create the dialog
        self.dlg_manager = EpaManager()
        self.load_settings(self.dlg_manager)

        # Manage widgets
        reg_exp = QRegExp("^[A-Za-z0-9_]{1,16}$")
        self.dlg_manager.txt_result_id.setValidator(QRegExpValidator(reg_exp))

        # Fill combo box and table view
        self.fill_combo_result_id()
        self.dlg_manager.tbl_rpt_cat_result.setSelectionBehavior(
            QAbstractItemView.SelectRows)
        self.fill_table(self.dlg_manager.tbl_rpt_cat_result,
                        'v_ui_rpt_cat_result')
        self.set_table_columns(self.dlg_manager,
                               self.dlg_manager.tbl_rpt_cat_result,
                               'v_ui_rpt_cat_result')

        # Set signals
        self.dlg_manager.btn_delete.clicked.connect(
            partial(self.multi_rows_delete,
                    self.dlg_manager.tbl_rpt_cat_result, 'rpt_cat_result',
                    'result_id'))
        self.dlg_manager.btn_close.clicked.connect(
            partial(self.close_dialog, self.dlg_manager))
        self.dlg_manager.rejected.connect(
            partial(self.close_dialog, self.dlg_manager))
        self.dlg_manager.txt_result_id.editTextChanged.connect(
            self.filter_by_result_id)

        # Open form
        self.open_dialog(self.dlg_manager, dlg_name='go2epa_manager')

    def fill_combo_result_id(self):

        sql = "SELECT result_id FROM v_ui_rpt_cat_result ORDER BY result_id"
        rows = self.controller.get_rows(sql)
        utils_giswater.fillComboBox(self.dlg_manager,
                                    self.dlg_manager.txt_result_id, rows)

    def filter_by_result_id(self):

        table = self.dlg_manager.tbl_rpt_cat_result
        widget_txt = self.dlg_manager.txt_result_id
        tablename = 'v_ui_rpt_cat_result'
        result_id = utils_giswater.getWidgetText(self.dlg_manager, widget_txt)
        if result_id != 'null':
            expr = f" result_id ILIKE '%{result_id}%'"
            # Refresh model with selected filter
            table.model().setFilter(expr)
            table.model().select()
        else:
            self.fill_table(table, tablename)

    def update_sql(self):
        usql = UpdateSQL(self.iface, self.settings, self.controller,
                         self.plugin_dir)
        usql.init_sql()
Example #28
0
class GwGo2EpaButton(GwAction):
    """ Button 23: Go2epa """
    def __init__(self, icon_path, action_name, text, toolbar, action_group):

        super().__init__(icon_path, action_name, text, toolbar, action_group)
        self.project_type = global_vars.project_type
        self.epa_options_list = []

    def clicked_event(self):

        self._open_go2epa()

    def check_result_id(self):
        """ Check if selected @result_id already exists """

        self.dlg_go2epa.txt_result_name.setStyleSheet(None)

    # region private functions

    def _open_go2epa(self):

        self._go2epa()

    def _go2epa(self):
        """ Button 23: Open form to set INP, RPT and project """

        # Show form in docker?
        tools_gw.init_docker('qgis_form_docker')

        # Create dialog
        self.dlg_go2epa = GwGo2EpaUI()
        tools_gw.load_settings(self.dlg_go2epa)
        self._load_user_values()
        if self.project_type in 'ws':
            self.dlg_go2epa.chk_export_subcatch.setVisible(False)

        # Set signals
        self._set_signals()
        self.dlg_go2epa.btn_cancel.setEnabled(False)

        # Disable tab log
        tools_gw.disable_tab_log(self.dlg_go2epa)

        # Set shortcut keys
        self.dlg_go2epa.key_escape.connect(partial(tools_gw.close_docker))

        self.dlg_go2epa.btn_hs_ds.clicked.connect(
            partial(self._sector_selection))

        # Check OS and enable/disable checkbox execute EPA software
        if sys.platform != "win32":
            tools_qt.set_checked(self.dlg_go2epa, self.dlg_go2epa.chk_exec,
                                 False)
            self.dlg_go2epa.chk_exec.setEnabled(False)
            self.dlg_go2epa.chk_exec.setText(
                'Execute EPA software (Runs only on Windows)')

        self._set_completer_result(self.dlg_go2epa.txt_result_name,
                                   'v_ui_rpt_cat_result', 'result_id')
        self.check_result_id()
        if global_vars.session_vars['dialog_docker']:
            tools_qt.manage_translation('go2epa', self.dlg_go2epa)
            tools_gw.docker_dialog(self.dlg_go2epa)
            self.dlg_go2epa.btn_close.clicked.disconnect()
            self.dlg_go2epa.btn_close.clicked.connect(
                partial(tools_gw.close_docker, option_name='position'))
        else:
            tools_gw.open_dialog(self.dlg_go2epa, dlg_name='go2epa')

    def _set_signals(self):

        self.dlg_go2epa.btn_cancel.clicked.connect(self._cancel_task)
        self.dlg_go2epa.txt_result_name.textChanged.connect(
            partial(self.check_result_id))
        self.dlg_go2epa.btn_file_inp.clicked.connect(
            self._go2epa_select_file_inp)
        self.dlg_go2epa.btn_file_rpt.clicked.connect(
            self._go2epa_select_file_rpt)
        self.dlg_go2epa.btn_accept.clicked.connect(self._go2epa_accept)
        self.dlg_go2epa.btn_close.clicked.connect(
            partial(tools_gw.close_dialog, self.dlg_go2epa))
        self.dlg_go2epa.rejected.connect(
            partial(tools_gw.close_dialog, self.dlg_go2epa))
        self.dlg_go2epa.btn_options.clicked.connect(self._go2epa_options)
        self.dlg_go2epa.mainTab.currentChanged.connect(
            partial(self._manage_btn_accept))

    def _manage_btn_accept(self, index):
        """
        Disable btn_accept when on tab info log and/or if go2epa_task is active
            :param index: tab index (passed by signal)
        """

        if index == 1:
            self.dlg_go2epa.btn_accept.setEnabled(False)
        else:
            # Disable if task is active, enabled otherwise
            if hasattr(self, 'go2epa_task') and self.go2epa_task is not None:
                try:
                    if self.go2epa_task.isActive():
                        self.dlg_go2epa.btn_accept.setEnabled(False)
                        return
                except RuntimeError:
                    pass
            self.dlg_go2epa.btn_accept.setEnabled(True)

    def _check_inp_chk(self, file_inp):

        if file_inp is None:
            msg = "Select valid INP file"
            tools_qgis.show_warning(msg, parameter=str(file_inp))
            return False

        return True

    def _check_rpt(self):

        file_inp = tools_qt.get_text(self.dlg_go2epa,
                                     self.dlg_go2epa.txt_file_inp)
        file_rpt = tools_qt.get_text(self.dlg_go2epa,
                                     self.dlg_go2epa.txt_file_rpt)

        # Control execute epa software
        if tools_qt.is_checked(self.dlg_go2epa, self.dlg_go2epa.chk_exec):
            if not self._check_inp_chk(file_inp):
                return False

            if file_rpt is None:
                msg = "Select valid RPT file"
                tools_qgis.show_warning(msg, parameter=str(file_rpt))
                return False

            if not tools_qt.is_checked(self.dlg_go2epa,
                                       self.dlg_go2epa.chk_export):
                if not os.path.exists(file_inp):
                    msg = "File INP not found"
                    tools_qgis.show_warning(msg, parameter=str(file_inp))
                    return False

        return True

    def _check_fields(self):

        file_inp = tools_qt.get_text(self.dlg_go2epa,
                                     self.dlg_go2epa.txt_file_inp)
        file_rpt = tools_qt.get_text(self.dlg_go2epa,
                                     self.dlg_go2epa.txt_file_rpt)
        result_name = tools_qt.get_text(self.dlg_go2epa,
                                        self.dlg_go2epa.txt_result_name, False,
                                        False)

        # Check if at least one process is selected
        export_checked = tools_qt.is_checked(self.dlg_go2epa,
                                             self.dlg_go2epa.chk_export)
        exec_checked = tools_qt.is_checked(self.dlg_go2epa,
                                           self.dlg_go2epa.chk_exec)
        import_result_checked = tools_qt.is_checked(
            self.dlg_go2epa, self.dlg_go2epa.chk_import_result)

        if not export_checked and not exec_checked and not import_result_checked:
            msg = "You need to select at least one process"
            tools_qt.show_info_box(msg, title="Go2Epa")
            return False

        # Control export INP
        if export_checked:
            if not self._check_inp_chk(file_inp):
                return False

        # Control execute epa software
        if not self._check_rpt():
            return False

        # Control import result
        if import_result_checked:
            if file_rpt is None:
                msg = "Select valid RPT file"
                tools_qgis.show_warning(msg, parameter=str(file_rpt))
                return False
            if not tools_qt.is_checked(self.dlg_go2epa,
                                       self.dlg_go2epa.chk_exec):
                if not os.path.exists(file_rpt):
                    msg = "File RPT not found"
                    tools_qgis.show_warning(msg, parameter=str(file_rpt))
                    return False
            else:
                if not self._check_rpt():
                    return False

        # Control result name
        if result_name == '':
            self.dlg_go2epa.txt_result_name.setStyleSheet(
                "border: 1px solid red")
            msg = "This parameter is mandatory. Please, set a value"
            tools_qt.show_details(msg, title="Rpt fail", inf_text=None)
            return False

        self.dlg_go2epa.txt_result_name.setStyleSheet(None)

        sql = (f"SELECT result_id FROM rpt_cat_result "
               f"WHERE result_id = '{result_name}' LIMIT 1")
        row = tools_db.get_row(sql)
        if import_result_checked and not export_checked and not exec_checked:
            if not row:
                msg = "Result name not found. It's not possible to import RPT file into database"
                tools_qt.show_info_box(msg, "Import RPT file")
                return False
        else:
            if row:
                msg = "Result name already exists, do you want overwrite?"
                answer = tools_qt.show_question(msg, title="Alert")
                if not answer:
                    return False

        return True

    def _load_user_values(self):
        """ Load QGIS settings related with file_manager """

        self.dlg_go2epa.txt_result_name.setMaxLength(16)
        self.result_name = tools_gw.get_config_parser('btn_go2epa',
                                                      'go2epa_RESULT_NAME',
                                                      "user", "session")
        self.dlg_go2epa.txt_result_name.setText(self.result_name)
        self.file_inp = tools_gw.get_config_parser('btn_go2epa',
                                                   'go2epa_FILE_INP', "user",
                                                   "session")
        self.dlg_go2epa.txt_file_inp.setText(self.file_inp)
        self.file_rpt = tools_gw.get_config_parser('btn_go2epa',
                                                   'go2epa_FILE_RPT', "user",
                                                   "session")
        self.dlg_go2epa.txt_file_rpt.setText(self.file_rpt)

        value = tools_gw.get_config_parser('btn_go2epa', 'go2epa_chk_INP',
                                           "user", "session")
        tools_qt.set_checked(self.dlg_go2epa, self.dlg_go2epa.chk_export,
                             value)
        value = tools_gw.get_config_parser('btn_go2epa', 'go2epa_chk_UD',
                                           "user", "session")
        tools_qt.set_checked(self.dlg_go2epa,
                             self.dlg_go2epa.chk_export_subcatch, value)
        value = tools_gw.get_config_parser('btn_go2epa', 'go2epa_chk_EPA',
                                           "user", "session")
        tools_qt.set_checked(self.dlg_go2epa, self.dlg_go2epa.chk_exec, value)
        value = tools_gw.get_config_parser('btn_go2epa', 'go2epa_chk_RPT',
                                           "user", "session")
        tools_qt.set_checked(self.dlg_go2epa,
                             self.dlg_go2epa.chk_import_result, value)

    def _save_user_values(self):
        """ Save QGIS settings related with file_manager """

        txt_result_name = f"{tools_qt.get_text(self.dlg_go2epa, 'txt_result_name', return_string_null=False)}"
        tools_gw.set_config_parser('btn_go2epa', 'go2epa_RESULT_NAME',
                                   f"{txt_result_name}")
        txt_file_inp = f"{tools_qt.get_text(self.dlg_go2epa, 'txt_file_inp', return_string_null=False)}"
        tools_gw.set_config_parser('btn_go2epa', 'go2epa_FILE_INP',
                                   f"{txt_file_inp}")
        txt_file_rpt = f"{tools_qt.get_text(self.dlg_go2epa, 'txt_file_rpt', return_string_null=False)}"
        tools_gw.set_config_parser('btn_go2epa', 'go2epa_FILE_RPT',
                                   f"{txt_file_rpt}")
        chk_export = f"{tools_qt.is_checked(self.dlg_go2epa, self.dlg_go2epa.chk_export)}"
        tools_gw.set_config_parser('btn_go2epa', 'go2epa_chk_INP',
                                   f"{chk_export}")
        chk_export_subcatch = f"{tools_qt.is_checked(self.dlg_go2epa, self.dlg_go2epa.chk_export_subcatch)}"
        tools_gw.set_config_parser('btn_go2epa', 'go2epa_chk_UD',
                                   f"{chk_export_subcatch}")
        chk_exec = f"{tools_qt.is_checked(self.dlg_go2epa, self.dlg_go2epa.chk_exec)}"
        tools_gw.set_config_parser('btn_go2epa', 'go2epa_chk_EPA',
                                   f"{chk_exec}")
        chk_import_result = f"{tools_qt.is_checked(self.dlg_go2epa, self.dlg_go2epa.chk_import_result)}"
        tools_gw.set_config_parser('btn_go2epa', 'go2epa_chk_RPT',
                                   f"{chk_import_result}")

    def _sector_selection(self):
        """ Load the tables in the selection form """

        # Get class Selector from selector.py
        go2epa_selector = GwSelector()

        # Create the dialog
        dlg_selector = GwSelectorUi()
        tools_gw.load_settings(dlg_selector)

        # Create the common signals
        go2epa_selector.get_selector(dlg_selector,
                                     '"selector_basic"',
                                     current_tab='tab_dscenario')
        tools_gw.save_current_tab(dlg_selector, dlg_selector.main_tab, 'basic')

        # Open form
        if global_vars.session_vars['dialog_docker']:
            # Set signals when have docker form
            dlg_selector.btn_close.clicked.connect(
                partial(tools_gw.docker_dialog, self.dlg_go2epa))
            dlg_selector.btn_close.clicked.connect(
                partial(self._manage_form_settings, 'restore'))
            # Save widgets settings from go2epa form
            self._manage_form_settings('save')
            # Open form
            tools_gw.docker_dialog(dlg_selector)
        else:
            # Set signals when have not docker form
            dlg_selector.btn_close.clicked.connect(
                partial(tools_gw.close_dialog, dlg_selector))
            # Open form
            tools_gw.open_dialog(dlg_selector)

    def _manage_form_settings(self, action):

        if action == 'save':
            # Get widgets form values
            self.txt_result_name = tools_qt.get_text(
                self.dlg_go2epa, self.dlg_go2epa.txt_result_name)
            self.chk_export = self.dlg_go2epa.chk_export.isChecked()
            self.chk_export_subcatch = self.dlg_go2epa.chk_export_subcatch.isChecked(
            )
            self.txt_file_inp = tools_qt.get_text(self.dlg_go2epa,
                                                  self.dlg_go2epa.txt_file_inp)
            self.chk_exec = self.dlg_go2epa.chk_exec.isChecked()
            self.txt_file_rpt = tools_qt.get_text(self.dlg_go2epa,
                                                  self.dlg_go2epa.txt_file_rpt)
            self.chk_import_result = self.dlg_go2epa.chk_import_result.isChecked(
            )
        elif action == 'restore':
            # Set widgets form values
            if self.txt_result_name is not 'null':
                tools_qt.set_widget_text(self.dlg_go2epa,
                                         self.dlg_go2epa.txt_result_name,
                                         self.txt_result_name)
            if self.chk_export is not 'null':
                tools_qt.set_widget_text(self.dlg_go2epa,
                                         self.dlg_go2epa.chk_export,
                                         self.chk_export)
            if self.chk_export_subcatch is not 'null':
                tools_qt.set_widget_text(self.dlg_go2epa,
                                         self.dlg_go2epa.chk_export_subcatch,
                                         self.chk_export_subcatch)
            if self.txt_file_inp is not 'null':
                tools_qt.set_widget_text(self.dlg_go2epa,
                                         self.dlg_go2epa.txt_file_inp,
                                         self.txt_file_inp)
            if self.chk_exec is not 'null':
                tools_qt.set_widget_text(self.dlg_go2epa,
                                         self.dlg_go2epa.chk_exec,
                                         self.chk_exec)
            if self.txt_file_rpt is not 'null':
                tools_qt.set_widget_text(self.dlg_go2epa,
                                         self.dlg_go2epa.txt_file_rpt,
                                         self.txt_file_rpt)
            if self.chk_import_result is not 'null':
                tools_qt.set_widget_text(self.dlg_go2epa,
                                         self.dlg_go2epa.chk_import_result,
                                         self.chk_import_result)

    def _go2epa_select_file_inp(self):
        """ Select INP file """

        self.file_inp = tools_qt.get_text(self.dlg_go2epa,
                                          self.dlg_go2epa.txt_file_inp)
        # Set default value if necessary
        if self.file_inp is None or self.file_inp == '':
            self.file_inp = global_vars.plugin_dir

        # Get directory of that file
        folder_path = os.path.dirname(self.file_inp)
        if not os.path.exists(folder_path):
            folder_path = os.path.dirname(__file__)
        os.chdir(folder_path)
        message = tools_qt.tr("Select INP file")
        widget_is_checked = tools_qt.is_checked(self.dlg_go2epa,
                                                self.dlg_go2epa.chk_export)
        if widget_is_checked:
            self.file_inp, filter_ = QFileDialog.getSaveFileName(
                None, message, "", '*.inp')
        else:
            self.file_inp, filter_ = QFileDialog.getOpenFileName(
                None, message, "", '*.inp')
        tools_qt.set_widget_text(self.dlg_go2epa, self.dlg_go2epa.txt_file_inp,
                                 self.file_inp)

    def _go2epa_select_file_rpt(self):
        """ Select RPT file """

        # Set default value if necessary
        if self.file_rpt is None or self.file_rpt == '':
            self.file_rpt = global_vars.plugin_dir

        # Get directory of that file
        folder_path = os.path.dirname(self.file_rpt)
        if not os.path.exists(folder_path):
            folder_path = os.path.dirname(__file__)
        os.chdir(folder_path)
        message = tools_qt.tr("Select RPT file")
        widget_is_checked = tools_qt.is_checked(self.dlg_go2epa,
                                                self.dlg_go2epa.chk_export)
        if widget_is_checked:
            self.file_rpt, filter_ = QFileDialog.getSaveFileName(
                None, message, "", '*.rpt')
        else:
            self.file_rpt, filter_ = QFileDialog.getOpenFileName(
                None, message, "", '*.rpt')
        tools_qt.set_widget_text(self.dlg_go2epa, self.dlg_go2epa.txt_file_rpt,
                                 self.file_rpt)

    def _go2epa_accept(self):
        """ Save INP, RPT and result name"""

        # Manage if task is already running
        if hasattr(self, 'go2epa_task') and self.go2epa_task is not None:
            try:
                if self.go2epa_task.isActive():
                    message = "Go2Epa task is already active!"
                    tools_qgis.show_warning(message)
                    return
            except RuntimeError:
                pass

        # Save user values
        self._save_user_values()

        self.dlg_go2epa.txt_infolog.clear()
        self.dlg_go2epa.txt_file_rpt.setStyleSheet(None)
        status = self._check_fields()
        if status is False:
            return

        # Get widgets values
        self.result_name = tools_qt.get_text(self.dlg_go2epa,
                                             self.dlg_go2epa.txt_result_name,
                                             False, False)
        self.export_inp = tools_qt.is_checked(self.dlg_go2epa,
                                              self.dlg_go2epa.chk_export)
        self.export_subcatch = tools_qt.is_checked(
            self.dlg_go2epa, self.dlg_go2epa.chk_export_subcatch)
        self.file_inp = tools_qt.get_text(self.dlg_go2epa,
                                          self.dlg_go2epa.txt_file_inp)
        self.exec_epa = tools_qt.is_checked(self.dlg_go2epa,
                                            self.dlg_go2epa.chk_exec)
        self.file_rpt = tools_qt.get_text(self.dlg_go2epa,
                                          self.dlg_go2epa.txt_file_rpt)
        self.import_result = tools_qt.is_checked(
            self.dlg_go2epa, self.dlg_go2epa.chk_import_result)

        # Check for sector selector
        if self.export_inp:
            sql = "SELECT sector_id FROM selector_sector WHERE sector_id > 0 LIMIT 1"
            row = tools_db.get_row(sql)
            if row is None:
                msg = "You need to select some sector"
                tools_qt.show_info_box(msg)
                return

        self.dlg_go2epa.btn_accept.setEnabled(False)
        self.dlg_go2epa.btn_cancel.setEnabled(True)

        # Set background task 'Go2Epa'
        description = f"Go2Epa"
        self.go2epa_task = GwEpaFileManager(description, self)
        QgsApplication.taskManager().addTask(self.go2epa_task)
        QgsApplication.taskManager().triggerTask(self.go2epa_task)

    def _cancel_task(self):

        if hasattr(self, 'go2epa_task'):
            self.go2epa_task.cancel()

    def _set_completer_result(self, widget, viewname, field_name):
        """ Set autocomplete of widget 'feature_id'
            getting id's from selected @viewname
        """

        # Adding auto-completion to a QLineEdit
        self.completer = QCompleter()
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        widget.setCompleter(self.completer)
        model = QStringListModel()

        sql = f"SELECT {field_name} FROM {viewname}"
        rows = tools_db.get_rows(sql)

        if rows:
            for i in range(0, len(rows)):
                aux = rows[i]
                rows[i] = str(aux[0])

            model.setStringList(rows)
            self.completer.setModel(model)

    def _go2epa_options(self):
        """ Button 23: Open form to set INP, RPT and project """

        # Clear list
        self.epa_options_list = []

        # Create dialog
        self.dlg_go2epa_options = GwGo2EpaOptionsUi()
        tools_gw.load_settings(self.dlg_go2epa_options)

        form = '"formName":"epaoptions"'
        body = tools_gw.create_body(form=form)
        json_result = tools_gw.execute_procedure('gw_fct_getconfig', body)
        if not json_result or json_result['status'] == 'Failed':
            return False

        tools_gw.build_dialog_options(self.dlg_go2epa_options,
                                      json_result['body']['form']['formTabs'],
                                      0, self.epa_options_list)
        grbox_list = self.dlg_go2epa_options.findChildren(QGroupBox)
        for grbox in grbox_list:
            widget_list = grbox.findChildren(QWidget)
            if len(widget_list) == 0:
                grbox.setVisible(False)
            else:
                layout_list = grbox.findChildren(QGridLayout)
                for lyt in layout_list:
                    spacer = QSpacerItem(20, 40, QSizePolicy.Minimum,
                                         QSizePolicy.Expanding)
                    lyt.addItem(spacer)

        # Event on change from combo parent
        self._get_event_combo_parent(json_result)
        self.dlg_go2epa_options.btn_accept.clicked.connect(
            partial(self._update_values, self.epa_options_list))
        self.dlg_go2epa_options.btn_cancel.clicked.connect(
            partial(tools_gw.close_dialog, self.dlg_go2epa_options))
        self.dlg_go2epa_options.rejected.connect(
            partial(tools_gw.close_dialog, self.dlg_go2epa_options))

        tools_gw.open_dialog(self.dlg_go2epa_options,
                             dlg_name='go2epa_options')

    def _update_values(self, _json):

        my_json = json.dumps(_json)
        form = '"formName":"epaoptions"'
        extras = f'"fields":{my_json}'
        body = tools_gw.create_body(form=form, extras=extras)
        json_result = tools_gw.execute_procedure('gw_fct_setconfig', body)
        if not json_result or json_result['status'] == 'Failed':
            return False

        tools_gw.manage_current_selections_docker(json_result)

        message = "Values has been updated"
        tools_qgis.show_info(message)
        # Close dialog
        tools_gw.close_dialog(self.dlg_go2epa_options)

    def _get_event_combo_parent(self, complet_result):

        for field in complet_result['body']['form']['formTabs'][0]["fields"]:
            if field['isparent']:
                widget = self.dlg_go2epa_options.findChild(
                    QComboBox, field['widgetname'])
                if widget:
                    widget.currentIndexChanged.connect(
                        partial(self._fill_child, self.dlg_go2epa_options,
                                widget))

    def _fill_child(self, dialog, widget):

        combo_parent = widget.objectName()
        combo_id = tools_qt.get_combo_value(dialog, widget)
        # TODO cambiar por gw_fct_getchilds then unified with tools_gw.get_child if posible
        json_result = tools_gw.execute_procedure(
            'gw_fct_getcombochilds',
            f"'epaoptions', '', '', '{combo_parent}', '{combo_id}', ''")
        if not json_result or json_result['status'] == 'Failed':
            return False

        for combo_child in json_result['fields']:
            if combo_child is not None:
                tools_gw.manage_combo_child(dialog, widget, combo_child)