def update_models_completer(self):
     completer = QCompleter(self.ilicache.model, self.ili_models_line_edit)
     completer.setCaseSensitivity(Qt.CaseInsensitive)
     completer.setFilterMode(Qt.MatchContains)
     self.delegate = ModelCompleterDelegate()
     completer.popup().setItemDelegate(self.delegate)
     self.ili_models_line_edit.setCompleter(completer)
     self.multiple_models_dialog.models_line_edit.setCompleter(completer)
Exemplo n.º 2
0
    def __init__(self, parent, title):
        QWizardPage.__init__(self, parent)
        self.workflow_wizard = parent

        self.setupUi(self)
        self.setTitle(title)

        self.workflow_wizard = parent
        self.is_complete = True

        self.model_list_view.setModel(self.workflow_wizard.import_models_model)
        self.model_list_view.clicked.connect(
            self.workflow_wizard.import_models_model.check)
        self.model_list_view.space_pressed.connect(
            self.workflow_wizard.import_models_model.check)
        self.model_list_view.model().modelReset.connect(
            self._update_models_dependent_info)

        self.crs = QgsCoordinateReferenceSystem()
        self.ili2db_options = Ili2dbOptionsDialog(self)
        self.ili2db_options_button.clicked.connect(self.ili2db_options.open)
        self.ili2db_options.finished.connect(self._fill_toml_file_info_label)

        self.crsSelector.crsChanged.connect(self._crs_changed)

        self.ilimetaconfigcache = IliDataCache(
            self.workflow_wizard.import_schema_configuration.base_configuration
        )
        self.metaconfig_delegate = MetaConfigCompleterDelegate()
        self.metaconfig = configparser.ConfigParser()
        self.current_models = None
        self.current_metaconfig_id = None
        self.ili_metaconfig_line_edit.setPlaceholderText(
            self.tr("[Search metaconfig / topping from UsabILIty Hub]"))
        self.ili_metaconfig_line_edit.setEnabled(False)
        completer = QCompleter(self.ilimetaconfigcache.model,
                               self.ili_metaconfig_line_edit)
        completer.setCaseSensitivity(Qt.CaseInsensitive)
        completer.setFilterMode(Qt.MatchContains)
        completer.popup().setItemDelegate(self.metaconfig_delegate)
        self.ili_metaconfig_line_edit.setCompleter(completer)
        self.ili_metaconfig_line_edit.textChanged.emit(
            self.ili_metaconfig_line_edit.text())
        self.ili_metaconfig_line_edit.textChanged.connect(
            self._complete_metaconfig_completer)
        self.ili_metaconfig_line_edit.punched.connect(
            self._complete_metaconfig_completer)
        self.ili_metaconfig_line_edit.textChanged.connect(
            self._on_metaconfig_completer_activated)
        self.workflow_wizard.ilireferencedatacache.model_refreshed.connect(
            self._update_linked_models)
Exemplo n.º 3
0
class ExtendedComboBox(QComboBox):
    def __init__(self, parent=None):
        super(ExtendedComboBox, self).__init__(parent)

        self.setFocusPolicy(Qt.StrongFocus)
        self.setEditable(True)
        self.pFilterModel = QSortFilterProxyModel(self)
        self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.pFilterModel.setSourceModel(self.model())
        self.completer = QCompleter(self.pFilterModel, self)
        self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        self.completer.popup().setStyleSheet("min-height: 150px")
        self.completer.popup().setAlternatingRowColors(True)
        self.setCompleter(self.completer)
        self.lineEdit().textEdited[str].connect(self.pFilterModel.setFilterFixedString)
Exemplo n.º 4
0
class ExtendedComboBox(QComboBox):
    def __init__(self, parent=None):
        super(ExtendedComboBox, self).__init__(parent)

        self.setFocusPolicy(Qt.StrongFocus)
        self.setEditable(True)
        self.pFilterModel = QSortFilterProxyModel(self)
        self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.pFilterModel.setSourceModel(self.model())
        self.completer = QCompleter(self.pFilterModel, self)
        self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        self.completer.popup().setStyleSheet('min-height: 150px')
        self.completer.popup().setAlternatingRowColors(True)
        self.setCompleter(self.completer)
        self.lineEdit().textEdited[unicode].connect(
            self.pFilterModel.setFilterFixedString)
Exemplo n.º 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)
Exemplo n.º 6
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)
Exemplo n.º 7
0
class QCercadorAdreca(QObject):
    sHanTrobatCoordenades = pyqtSignal(int, 'QString')  # atencion

    def __init__(self, lineEditCarrer, lineEditNumero, origen='SQLITE'):
        super().__init__()

        # self.pare= pare

        self.origen = origen
        self.leCarrer = lineEditCarrer
        self.leNumero = lineEditNumero
        self.connectarLineEdits()
        self.carrerActivat = False

        self.dictCarrers = {}
        self.dictNumeros = collections.defaultdict(dict)

        # self.db.setConnectOptions("QSQLITE_OPEN_READONLY")
        self.numClick=0
        self.db = QvApp().dbGeo

        if self.db is None:  # not self.db.open(): # En caso de que no se abra
            QMessageBox.critical(None, "Error al abrir la base de datos.\n\n"
                                 "Click para cancelar y salir.", QMessageBox.Cancel)

        self.query = QSqlQuery(self.db)  # Intancia del Query
        self.txto = ''
        self.calle_con_acentos = ''
        self.habilitaLeNum()

        self.iniAdreca()

        if self.llegirAdreces():
            # si se ha podido leer las direciones... creando el diccionario...
            self.prepararCompleterCarrer()

    def habilitaLeNum(self):
        self.carrerActivat = False
        return  # De moment no es desactivarà mai
        # Hauria de funcionar només amb la primera condició, però per raons que escapen al meu coneixement, no anava :()
        self.leNumero.setEnabled(
            self.calle_con_acentos != '' or self.txto != '')

    def cercadorAdrecaFi(self):
        if self.db.isOpen():
            self.db.close()

    def prepararCompleterCarrer(self):
        # creo instancia de completer que relaciona diccionario de calles con lineEdit
        # self.completerCarrer = QCompleter(self.dictCarrers, self.leCarrer)
        self.completerCarrer = CompleterAdreces(
            self.dictCarrers, self.leCarrer)
        # Determino funcionamiento del completer
        self.completerCarrer.setFilterMode(QtCore.Qt.MatchContains)
        self.completerCarrer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
        # Funcion que se ejecutará cuando
        self.completerCarrer.activated.connect(self.activatCarrer)
        # Asigno el completer al lineEdit
        self.leCarrer.setCompleter(self.completerCarrer)

    def prepararCompleterNumero(self):
        self.dictNumerosFiltre = self.dictNumeros[self.codiCarrer]
        self.completerNumero = QCompleter(
            self.dictNumerosFiltre, self.leNumero)
        self.completerNumero.activated.connect(self.activatNumero)
        self.completerNumero.setFilterMode(QtCore.Qt.MatchStartsWith)
        self.completerNumero.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
        self.leNumero.setCompleter(self.completerNumero)
        # self.leNumero.setValidator(ValidadorNums(self.dictNumeros[self.codiCarrer],self))

    def iniAdreca(self):
        self.iniAdrecaCarrer()
        self.iniAdrecaNumero()

    def iniAdrecaCarrer(self):
        self.nomCarrer = ''
        self.codiCarrer = ''

    def iniAdrecaNumero(self):
        self.numeroCarrer = ''
        self.coordAdreca = None
        self.infoAdreca = None

    def connectarLineEdits(self):
        self.leCarrer.textChanged.connect(self.esborrarNumero)
        self.leCarrer.editingFinished.connect(self.trobatCarrer)
        # CUARENTENA
        # self.leCarrer.mouseDoubleClickEvent = self.clear_leNumero_leCarrer
        self.leCarrer.mouseDoubleClickEvent = self.SeleccPalabraOTodoEnFrase
        self.leCarrer.setAlignment(Qt.AlignLeft)

        self.leNumero.editingFinished.connect(self.trobatNumero)
        # self.leNumero.returnPressed.connect(self.trobatNumero)

    def SeleccPalabraOTodoEnFrase(self, event):
        """
          Funcion conectada al dobleclick.
          Si se dobleclica 1 vez---> selecciona la palabra (lo que hay entre dos blancos)
          Se se dobleclica 2 veces---> selecciona toda la frase 
        """
        self.carrerActivat=False
        #  self.numClick en def __init__ se inicializa a 0
        if self.numClick == 1:  # segundo doble click => seleccionar toda la frase
            self.leCarrer.selectAll()
            self.numClick =-1
        else:      # primer doble click selecciona la palabra
            # Limite de la palabra por la izquierda (blanco o inicio por izquierda)
            self.ii = self.leCarrer.cursorPosition() - 1
            while self.ii >=0 and self.leCarrer.text()[self.ii] != ' ': 
                self.ii -= 1 ;   self.inicio= self.ii

            # Limite de la palabra por la derecha (blanco o fin por derecha)
            self.ii= self.leCarrer.cursorPosition() - 1 
            while self.ii < len(self.leCarrer.text()) and self.leCarrer.text()[self.ii] != ' ': 
                self.ii += 1 ;   self.fin= self.ii                

            # selecciona palabra en frase por posicion
            self.leCarrer.setSelection(self.inicio+1,self.fin-self.inicio-1)
            
        self.numClick += 1  
    # CUARENTENA
    # def clear_leNumero_leCarrer(self, carrer):
    #     self.carrerActivat = False
    #     self.leNumero.clear()
    #     self.leCarrer.clear()

    # Venimos del completer, un click en desplegable ....
    def activatCarrer(self, carrer):
        self.carrerActivat = True
        # print(carrer)

        carrer=carrer.replace('(var) ','')
        # if chr(29) in carrer:
        #     carrer=carrer.split(chr(29))[0]
        nn = carrer.find(chr(30))
        if nn == -1:
            ss = carrer
        else:
            ss = carrer[0:nn-1]
        # ss=ss.replace('(var) ','')

        self.calle_con_acentos = ss.rstrip()

        self.leCarrer.setAlignment(Qt.AlignLeft)
        self.leCarrer.setText(self.calle_con_acentos)

        # self.leCarrer.setText(carrer)
        self.iniAdreca()
        if carrer in self.dictCarrers:
            self.nomCarrer = carrer
            self.codiCarrer = self.dictCarrers[self.nomCarrer]

            try:
                index = 0
                # self.query = QSqlQuery() # Intancia del Query
                # self.query.exec_("select codi, num_lletra_post, etrs89_coord_x, etrs89_coord_y, num_oficial  from Numeros where codi = '" + self.codiCarrer +"'")

                self.query.exec_(
                    "select codi,case num_lletra_post when '0' then ' ' else num_lletra_post end,  etrs89_coord_x, etrs89_coord_y, num_oficial  from Numeros   where codi = '" + self.codiCarrer + "'")
                # self.query.exec_("select codi,case num_lletra_post when '0' then ' ' else num_lletra_post end,  etrs89_coord_x, etrs89_coord_y, case num_oficial when '0' then ' ' else num_oficial end  from Numeros   where codi = '" + self.codiCarrer +"'")

                while self.query.next():
                    row = collections.OrderedDict()
                    row['NUM_LLETRA_POST'] = self.query.value(
                        1)  # Numero y Letra
                    row['ETRS89_COORD_X'] = self.query.value(2)  # coor x
                    row['ETRS89_COORD_Y'] = self.query.value(3)  # coor y
                    row['NUM_OFICIAL'] = self.query.value(4)  # numero oficial

                    self.dictNumeros[self.codiCarrer][self.query.value(
                        1)] = row
                    index += 1

                self.query.finish()
                # self.db.close()

                self.prepararCompleterNumero()
                self.focusANumero()

            except Exception as e:
                print(str(e))
                msg = QMessageBox()
                msg.setIcon(QMessageBox.Warning)

                msg.setText(str(sys.exc_info()[1]))
                # msg.setInformativeText("OK para salir del programa \nCANCEL para seguir en el programa")
                msg.setWindowTitle("qVista ERROR")
                msg.setStandardButtons(QMessageBox.Close)
                retval = msg.exec_()  # No fem res amb el valor de retorn (???)

                print('QCercadorAdreca.iniAdreca(): ',
                      sys.exc_info()[0], sys.exc_info()[1])
                return False
            else:
                pass

        else:
            info = "ERROR >> [1]"
            self.sHanTrobatCoordenades.emit(1, info)  # adreça vacia
        self.habilitaLeNum()
        # self.prepararCompleterNumero()
        # self.focusANumero()

    def trobatCarrer(self):
        if self.leCarrer.text() == '':
            self.leNumero.setCompleter(None)
            return
        if not self.carrerActivat:
            # print(self.leCarrer.text())
            # així obtenim el carrer on estàvem encara que no l'haguem seleccionat explícitament
            self.txto = self.completerCarrer.popup().currentIndex().data()
            if self.txto is None:
                self.txto = self.completerCarrer.currentCompletion()
            if self.txto == '':
                return
            # self.txto=self.txto.split(chr(29))[0]

            nn = self.txto.find(chr(30))
            self.txto=self.txto.replace('(var) ','')
            if nn == -1:
                ss = self.txto
            else:
                ss = self.txto[0:nn-1]
            # ss=ss.replace('(var) ','')

            # ss= self.txto[0:nn-1]
            self.calle_con_acentos = ss.rstrip()

            self.leCarrer.setAlignment(Qt.AlignLeft)
            self.leCarrer.setText(self.calle_con_acentos)

            self.iniAdreca()
            if self.txto != self.nomCarrer:
                # self.iniAdreca()
                if self.txto in self.dictCarrers:
                    self.nomCarrer = self.txto
                    self.codiCarrer = self.dictCarrers[self.nomCarrer]
                    self.focusANumero()

                    try:
                        index = 0
                        # self.query = QSqlQuery() # Intancia del Query
                        # self.query.exec_("select codi, num_lletra_post, etrs89_coord_x, etrs89_coord_y, num_oficial  from Numeros where codi = '" + self.codiCarrer +"'")
                        self.query.exec_(
                            "select codi,case num_lletra_post when '0' then ' ' else num_lletra_post end,  etrs89_coord_x, etrs89_coord_y, num_oficial  from Numeros   where codi = '" + self.codiCarrer + "'")

                        while self.query.next():
                            row = collections.OrderedDict()
                            row['NUM_LLETRA_POST'] = self.query.value(
                                1)  # Numero y Letra
                            row['ETRS89_COORD_X'] = self.query.value(
                                2)  # coor x
                            row['ETRS89_COORD_Y'] = self.query.value(
                                3)  # coor y
                            row['NUM_OFICIAL'] = self.query.value(
                                4)  # numero oficial

                            self.dictNumeros[self.codiCarrer][self.query.value(
                                1)] = row
                            index += 1

                        self.query.finish()
                        # self.db.close()
                        self.prepararCompleterNumero()
                        self.focusANumero()

                    except Exception as e:
                        print(str(e))
                        msg = QMessageBox()
                        msg.setIcon(QMessageBox.Warning)

                        msg.setText(str(sys.exc_info()[1]))
                        # msg.setInformativeText("OK para salir del programa \nCANCEL para seguir en el programa")
                        msg.setWindowTitle("qVista ERROR")
                        msg.setStandardButtons(QMessageBox.Close)
                        retval = msg.exec_()  # No fem res amb el valor de retorn (???)

                        print('QCercadorAdreca.iniAdreca(): ',
                              sys.exc_info()[0], sys.exc_info()[1])
                        return False

                else:
                    info = "ERROR >> [2]"
                    # direccion no está en diccicionario
                    self.sHanTrobatCoordenades.emit(2, info)
                    self.iniAdreca()
            else:
                info = "ERROR >> [3]"
                self.sHanTrobatCoordenades.emit(3, info)  # nunca
        else:
            info = "ERROR >> [4]"
            self.sHanTrobatCoordenades.emit(4, info)  # adreça vac
        self.habilitaLeNum()

    def llegirAdreces(self):
        if self.origen == 'SQLITE':
            ok = self.llegirAdrecesSQlite()
        else:
            ok = False
        return ok

    def llegirAdrecesSQlite(self):
        try:
            index = 0
            # self.query = QSqlQuery() # Intancia del Query
            self.query.exec_(
                "select codi , nom_oficial , variants  from Carrers")

            while self.query.next():
                codi_carrer = self.query.value(0)  # Codigo calle
                nombre = self.query.value(1)  # numero oficial
                variants = self.query.value(2).lower()  # Variants del nom
                nombre_sin_acentos = self.remove_accents(nombre)
                if nombre == nombre_sin_acentos:
                    # clave= nombre + "  (" + codi_carrer + ")"
                    clave = nombre + \
                        "  (" + codi_carrer + \
                        ")                                                  " + \
                        chr(30)
                else:
                    clave = nombre + "  (" + codi_carrer + ")                                                  "+chr(
                        30)+"                                                         " + nombre_sin_acentos
                    # asignacion al diccionario
                variants.replace(',', 50*' ')
                clave += chr(29)+50*' '+variants
                self.dictCarrers[clave] = codi_carrer

                index += 1

            self.query.finish()
            # self.db.close()
            return True
        except Exception as e:
            print(str(e))
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Warning)

            msg.setText(str(sys.exc_info()[1]))
            # msg.setInformativeText("OK para salir del programa \nCANCEL para seguir en el programa")
            msg.setWindowTitle("qVista ERROR")
            msg.setStandardButtons(QMessageBox.Close)
            retval = msg.exec_()  # No fem res amb el valor de retorn (???)

            print('QCercadorAdreca.llegirAdrecesSQlite(): ',
                  sys.exc_info()[0], sys.exc_info()[1])
            return False

    # Normalización caracteres quitando acentos

    def remove_accents(self, input_str):
        nfkd_form = unicodedata.normalize('NFKD', input_str)
        only_ascii = nfkd_form.encode('ASCII', 'ignore')
        return only_ascii.decode("utf8")

    def activatNumero(self, txt):
        self.leNumero.setText(txt)
        self.iniAdrecaNumero()
        # if self.leCarrer.text() in self.dictCarrers:
        # self.txto = self.completerCarrer.currentCompletion()
        self.txto = self.completerCarrer.popup().currentIndex().data()
        if self.txto is None:
            self.txto = self.completerCarrer.currentCompletion()
        self.txto=self.txto.replace('(var) ','')
        if self.txto in self.dictCarrers:
            if txt in self.dictNumerosFiltre:
                self.numeroCarrer = txt
                self.infoAdreca = self.dictNumerosFiltre[self.numeroCarrer]
                self.coordAdreca = QgsPointXY(float(self.infoAdreca['ETRS89_COORD_X']),
                                              float(self.infoAdreca['ETRS89_COORD_Y']))

                self.NumeroOficial = self.infoAdreca['NUM_OFICIAL']
                self.leNumero.setText(self.NumeroOficial)
                self.leNumero.clearFocus()

                info = "[0]"
                self.sHanTrobatCoordenades.emit(0, info)
                if self.leNumero.text() == ' ':
                    self.leNumero.clear()

        else:
            info = "ERROR >> [5]"
            self.sHanTrobatCoordenades.emit(5, info)  # numero

    def trobatNumero(self):
        # Si no hi ha carrer, eliminem el completer del número
        if self.leCarrer.text() == '':
            self.leNumero.setCompleter(None)
        if self.leNumero.text() == '':
            return
        # self.txto = self.completerCarrer.currentCompletion()
        try:
            # if self.leCarrer.text() in self.dictCarrers:
            self.txto = self.completerCarrer.popup().currentIndex().data()
            if self.txto is None:
                self.txto = self.completerCarrer.currentCompletion()
            self.txto=self.txto.replace('(var) ','')
            if self.txto in self.dictCarrers:

                if self.leNumero.text() != '':
                    txt = self.completerNumero.popup().currentIndex().data()
                    if txt is None:
                        txt = self.completerNumero.currentCompletion()
                    # txt = self.completerNumero.currentCompletion()
                    self.leNumero.setText(txt)
                else:
                    txt = ' '

                if txt != '':  # and txt != self.numeroCarrer:
                    self.iniAdrecaNumero()
                    if self.nomCarrer != '':
                        if txt in self.dictNumerosFiltre:
                            self.numeroCarrer = txt
                            self.infoAdreca = self.dictNumerosFiltre[self.numeroCarrer]
                            self.coordAdreca = QgsPointXY(float(self.infoAdreca['ETRS89_COORD_X']),
                                                          float(self.infoAdreca['ETRS89_COORD_Y']))
                            self.NumeroOficial = self.infoAdreca['NUM_OFICIAL']
                            self.leNumero.clearFocus()
                            self.leNumero.setText(self.NumeroOficial)
                            info = "[0]"
                            self.sHanTrobatCoordenades.emit(0, info)
                            if self.leNumero.text() == ' ':
                                self.leNumero.clear()

                        else:
                            info = "ERROR >> [6]"
                            # numero no está en diccicionario
                            self.sHanTrobatCoordenades.emit(6, info)
                    else:
                        info = "ERROR >> [7]"
                        self.sHanTrobatCoordenades.emit(
                            7, info)  # adreça vacia  nunca
                else:
                    info = "ERROR >> [8]"
                    self.sHanTrobatCoordenades.emit(
                        8, info)  # numero en blanco
            else:
                self.leNumero.clear()
                info = "ERROR >> [9]"
                self.sHanTrobatCoordenades.emit(9, info)  # numero en blanco
        except:
            return
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Warning)
            info_rsc = 'ERROR: ' + str(sys.exc_info()[0])
            msg.setText(info_rsc)
            # msg.setInformativeText("OK para salir del programa \nCANCEL para seguir en el programa")
            msg.setWindowTitle("qVista >> QVCercadorAdreca>> trobatNumero")

            msg.setStandardButtons(QMessageBox.Close)
            retval = msg.exec_()  # No fem res amb el valor de retorn (???)

    def focusANumero(self):
        self.leNumero.setFocus()

    def esborrarNumero(self):
        # self.carrerActivat = False
        self.calle_con_acentos = ''
        self.leNumero.clear()
    def __init__(self, parent, title):
        QWizardPage.__init__(self, parent)
        self.workflow_wizard = parent

        self.setupUi(self)
        self.setTitle(title)

        self.workflow_wizard = parent
        self.is_complete = True
        self.basket_handling = False

        self.workflow_wizard.ilireferencedatacache.file_download_succeeded.connect(
            lambda dataset_id, path: self._on_referencedata_received(path)
        )
        self.workflow_wizard.ilireferencedatacache.file_download_failed.connect(
            self._on_referencedata_failed
        )
        self.ilireferencedata_delegate = MetaConfigCompleterDelegate()
        self.ilireferencedata_line_edit.setPlaceholderText(
            self.tr("[Search referenced data files from UsabILIty Hub]")
        )
        self.ilireferencedata_line_edit.setEnabled(False)
        completer = QCompleter(
            self.workflow_wizard.ilireferencedatacache.model,
            self.ilireferencedata_line_edit,
        )
        completer.setCaseSensitivity(Qt.CaseInsensitive)
        completer.setFilterMode(Qt.MatchContains)
        completer.popup().setItemDelegate(self.ilireferencedata_delegate)
        self.ilireferencedata_line_edit.setCompleter(completer)
        self.ilireferencedata_line_edit.textChanged.emit(
            self.ilireferencedata_line_edit.text()
        )
        self.ilireferencedata_line_edit.textChanged.connect(
            self._complete_referencedata_completer
        )
        self.ilireferencedata_line_edit.punched.connect(
            self._complete_referencedata_completer
        )

        self.add_button.clicked.connect(self._add_row)
        self.remove_button.clicked.connect(self._remove_selected_rows)

        self.add_button.setEnabled(False)
        self.ilireferencedata_line_edit.textChanged.connect(
            lambda: self.add_button.setEnabled(self._valid_referencedata())
        )
        self.remove_button.setEnabled(self._valid_selection())
        self.file_table_view.clicked.connect(
            lambda: self.remove_button.setEnabled(self._valid_selection())
        )

        self.add_button.setIcon(QgsApplication.getThemeIcon("/symbologyAdd.svg"))
        self.remove_button.setIcon(QgsApplication.getThemeIcon("/symbologyRemove.svg"))

        self.workflow_wizard.import_data_file_model.sourceModel().setHorizontalHeaderLabels(
            [self.tr("Import File"), self.tr("Catalogue"), self.tr("Dataset")]
        )
        self.file_table_view.setModel(self.workflow_wizard.import_data_file_model)
        self.file_table_view.horizontalHeader().setSectionResizeMode(
            gui_utils.SourceModel.Columns.SOURCE, QHeaderView.Stretch
        )
        self.file_table_view.horizontalHeader().setSectionResizeMode(
            gui_utils.SourceModel.Columns.IS_CATALOGUE, QHeaderView.ResizeToContents
        )
        self.file_table_view.horizontalHeader().setSectionResizeMode(
            gui_utils.SourceModel.Columns.DATASET, QHeaderView.ResizeToContents
        )

        self.file_table_view.verticalHeader().setSectionsMovable(True)
        self.file_table_view.verticalHeader().setDragEnabled(True)
        self.file_table_view.verticalHeader().setDragDropMode(QHeaderView.InternalMove)
        self.file_table_view.resizeColumnsToContents()
        self.workflow_wizard.import_data_file_model.dataChanged.connect(
            self._update_delegates
        )

        self.db_connector = None

        self.datasetmanager_dlg = None
        self.datasetmanager_button.setCheckable(True)
        self.datasetmanager_button.clicked.connect(self._show_datasetmanager_dialog)
        self.datasetmanager_button.setIcon(
            QIcon(
                os.path.join(
                    os.path.dirname(__file__),
                    "../../images/QgisModelBaker-datasetmanager-icon.svg",
                )
            )
        )
Exemplo n.º 9
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)
 def update_models_completer(self):
     completer = QCompleter(self.ilicache.model, self.input_line_edit)
     completer.setCaseSensitivity(Qt.CaseInsensitive)
     completer.setFilterMode(Qt.MatchContains)
     completer.popup().setItemDelegate(self.model_delegate)
     self.input_line_edit.setCompleter(completer)