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 = f"v_edit_{geom_type}"
        if self.schema_name not in table_name:
            table_name = self.schema_name + "." + table_name

        # Set the model
        model = QSqlTableModel(db=self.controller.db)
        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:
            # self.controller.log_debug(f"set_table_model (str): {table_object}")
            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:
            # self.controller.log_debug(f"set_table_model: {table_object.objectName()}")
            widget = table_object
        else:
            msg = "Table_object is not a table name or QTableView"
            self.controller.log_info(msg)
            return expr

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

        return expr
Exemple #2
0
    def data(self, index, role):
        if role == Qt.BackgroundRole:
            if self.colorFunction:
                if self.colorFunction(index):
                    return self.color_function(index)

        return QSqlTableModel.data(self, index, role)
Exemple #3
0
 def data(self, index, role):
     """
     Custom reimplementation of the method data.
     It is necessary to work with value map and value relation.
     index: column index
     role: role used to get the data
     """
     dbdata = QSqlTableModel.data(self, index, role)
     column = self.headerData(index.column(), Qt.Horizontal)
     if column in self.dict:
         if isinstance(self.dict[column], dict):
             valueMap = self.dict[column]
             if str(dbdata) in list(valueMap.values()):
                 id = list(valueMap.values()).index(str(dbdata))
                 return list(valueMap.keys())[id]
         elif isinstance(self.dict[column], tuple):
             tupla = self.dict[column]
             valueMap = self.makeValueRelationDict(tupla[0], tupla[1])
             codes = str(dbdata)[1:-1].split(',')
             code_names = list()
             for c in codes:
                 if str(c) in list(valueMap.values()):
                     id = list(valueMap.values()).index(str(c))
                     code_name = list(valueMap.keys())[id]
                     code_names.append(code_name)
             if len(code_names) > 0:
                 return '{%s}' % ','.join(code_names)
     return dbdata
Exemple #4
0
 def setData(self, index, value, role=Qt.EditRole):
     """
     Custom reimplementation of the method setData.
     It is necessary to work with value map and value relation.
     index: column index to be set
     value: value to be set
     role: role used
     """
     column = self.headerData(index.column(), Qt.Horizontal)
     newValue = value
     if column in self.dict:
         if isinstance(self.dict[column], dict):
             valueMap = self.dict[column]
             if value in valueMap:
                 newValue = int(valueMap[value])
             else:
                 newValue = value
         elif isinstance(self.dict[column], tuple):
             tupla = self.dict[column]
             valueMap = self.makeValueRelationDict(tupla[0], tupla[1])
             code_names = value[1:-1].split(',')
             codes = []
             for code_name in code_names:
                 code = valueMap[code_name]
                 codes.append(code)
             if len(codes) > 0:
                 newValue = '{%s}' % ','.join(map(str, codes))
     return QSqlTableModel.setData(self, index, newValue, role)
def set_table_model(dialog, table_object, table_name, 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) = check_expression_filter(expr_filter)
        if not is_valid:
            return expr

    if global_vars.schema_name and global_vars.schema_name not in table_name:
        table_name = f"{global_vars.schema_name}.{table_name}"

    # Set a model with selected filter expression
    model = QSqlTableModel(db=global_vars.qgis_db_credentials)
    model.setTable(table_name)
    model.setEditStrategy(QSqlTableModel.OnManualSubmit)
    model.select()
    if model.lastError().isValid():
        tools_qgis.show_warning(model.lastError().text())
        return expr

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

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

    return expr
    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
Exemple #7
0
    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)
Exemple #8
0
def fill_table(widget, table_name, set_edit_strategy=QSqlTableModel.OnManualSubmit, expr_filter=None):
    """ Set a model with selected filter.
    Attach that model to selected table """

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

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

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

    # Attach model to table view
    widget.setModel(model)
    if expr_filter:
        widget.model().setFilter(expr_filter)
Exemple #9
0
    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)
Exemple #10
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)
        self.user_current_layer = None
        self.rubber_point = None
        self.rubber_polygon = None


    def init_rubber(self):

        try:
            self.rubber_point = QgsRubberBand(self.canvas, 0)
            self.rubber_point.setColor(Qt.yellow)
            self.rubber_point.setIconSize(10)
            self.rubber_polygon = QgsRubberBand(self.canvas, 2)
            self.rubber_polygon.setColor(Qt.darkRed)
            self.rubber_polygon.setIconSize(20)
        except:
            pass


    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"
        files_path, filter_ = file_dialog.getOpenFileNames(parent=None, caption=self.controller.tr(message))
        file_text = ""
        for file in files_path:
            file_text += f"{file}\n\n"
        if files_path:
            utils_giswater.setWidgetText(dialog, widget, str(file_text))
        return files_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'))

            v_screens = ctypes.windll.user32
            screen_x = v_screens.GetSystemMetrics(78)  # Width of virtual screen
            screen_y = v_screens.GetSystemMetrics(79)  # Height of virtual screen
            monitors = v_screens.GetSystemMetrics(80)  # Will return an integer of the num of display monitors present.
            if (int(x) < 0 and monitors == 1) or (int(y) < 0 and monitors == 1):
                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.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 get_last_tab(self, dialog, selector_name):
        """ Get the name of the last tab used by the user from QSettings()
        :param dialog: QDialog
        :param selector_name: Name of the selector (String)
        :return: Name of the last tab used by the user (string)
        """

        tab_name = self.controller.plugin_settings_value(f"{dialog.objectName()}_{selector_name}")
        return tab_name


    def save_current_tab(self, dialog, tab_widget, selector_name):
        """ Save the name of current tab used by the user into QSettings()
        :param dialog: QDialog
        :param tab_widget:  QTabWidget
        :param selector_name: Name of the selector (String)
        """

        index = tab_widget.currentIndex()
        tab = tab_widget.widget(index)
        if tab:
            tab_name = tab.objectName()
            dlg_name = dialog.objectName()
            self.controller.plugin_settings_set_value(f"{dlg_name}_{selector_name}", tab_name)


    def open_dialog(self, dlg=None, dlg_name=None, info=True, maximize_button=True, stay_on_top=True, title=None):
        """ 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

        # Set window title
        if title is not None:
            dlg.setWindowTitle(title)
        else:
            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 """

        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:
            self.controller.log_info(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 {schema_name}.{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 + f" ORDER BY {name};")
        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 + f" ORDER BY {name};")
        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, aql))

        # 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(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', aql=''):
        """ Fill the QTableView by filtering through the QLineEdit"""

        schema_name = self.schema_name.replace('"', '')
        query = utils_giswater.getWidgetText(dialog, text_line, return_string_null=False).lower()
        sql = (f"SELECT * FROM {schema_name}.{tableleft} WHERE {name} NOT IN "
               f"(SELECT {tableleft}.{name} FROM {schema_name}.{tableleft}"
               f" RIGHT JOIN {schema_name}.{tableright}"
               f" ON {tableleft}.{field_id_l} = {tableright}.{field_id_r}"
               f" WHERE cur_user = current_user) AND LOWER({name}::text) LIKE '%{query}%'"
               f"  AND  {field_id_l} > -1")
        sql += aql
        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 columnindex, width, alias, status"
               f" FROM config_form_tableview"
               f" WHERE tablename = '{table_name}'"
               f" ORDER BY columnindex")
        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 None:
                    width = 100
                widget.setColumnWidth(row['columnindex'] - 1, width)
                widget.model().setHeaderData(row['columnindex'] - 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='plan_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 groupbox """

        grb_list = {}
        grbox_list = dialog.findChildren(QGroupBox)
        for grbox in grbox_list:

            widget_list = grbox.findChildren(QWidget)
            if len(widget_list) == 0:
                grb_list[grbox.objectName()] = 0
                grbox.setVisible(False)

        return grb_list


    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 make_list_for_completer(self, sql):
        """ Prepare a list with the necessary items for the completer
        :param sql: Query to be executed, where will we get the list of items (string)
        :return list_items: List with the result of the query executed (List) ["item1","item2","..."]
        """

        rows = self.controller.get_rows(sql)
        list_items = []
        if rows:
            for row in rows:
                list_items.append(str(row[0]))
        return list_items


    def set_completer_lineedit(self, 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 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:
            # Remove layer
            QgsProject.instance().removeMapLayer(layer)

            # Remove group if is void
            root = QgsProject.instance().layerTreeRoot()
            group = root.findGroup('GW Temporal Layers')
            if group:
                layers = group.findLayers()
                if not layers:
                    root.removeChildNode(group)
            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 = f'$${{"client":{{"device":4, "infoType":1, "lang":"ES"}}, '
        form = f'"form":{{{form}}}, '
        feature = f'"feature":{{{feature}}}, '
        filter_fields = f'"filterFields":{{{filter_fields}}}'
        page_info = f'"pageInfo":{{}}'
        data = f'"data":{{{filter_fields}, {page_info}'
        if extras is not None:
            data += ', ' + extras
        data += f'}}}}$$'
        body = "" + client + form + feature + data

        return body


    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 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)
        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(None)
            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(None)
            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 = DialogTextUi()
        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_infolog, msg)
        self.open_dialog(self.dlg_info, dlg_name='dialog_text', title=title)



    def put_combobox(self, qtable, rows, field, widget_pos, combo_values):
        """ 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 field: Field to set QComboBox (String)
        :param widget_pos: Position of the column where we want to put the QComboBox (integer)
        :param combo_values: List of items to populate QComboBox (["..", "..."])
        :return:
        """

        for x in range(0, len(rows)):
            combo = QComboBox()
            row = rows[x]
            # 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]), 1)
            # Get index and put QComboBox into QTableView at index position
            idx = qtable.model().index(x, widget_pos)
            qtable.setIndexWidget(idx, combo)
            combo.currentIndexChanged.connect(partial(self.update_status, combo, qtable, x, widget_pos))


    def update_status(self, combo, qtable, pos_x, widget_pos):
        """ Update values from QComboBox to QTableView
        :param combo: QComboBox from which we will take the value
        :param qtable: QTableView Where update values
        :param pos_x: Position of the row where we want to update value (integer)
        :param widget_pos:Position of the widget where we want to update value (integer)
        :return:
        """

        elem = combo.itemData(combo.currentIndex())
        i = qtable.model().index(pos_x, widget_pos)
        qtable.model().setData(i, elem[0])
        i = qtable.model().index(pos_x, widget_pos + 1)
        qtable.model().setData(i, elem[1])


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

        expr = "" + str(field_id) + "= '" + str(id_) + "'"
        features = layer.getFeatures(QgsFeatureRequest().setFilterExpression(expr))
        for feature in features:
            if str(feature[field_id]) == str(id_):
                return feature
        return False


    def document_insert(self, dialog, tablename, field, field_value):
        """ Insert a document related to the current visit
        :param dialog: (QDialog )
        :param tablename: Name of the table to make the queries (string)
        :param field: Field of the table to make the where clause (string)
        :param field_value: Value to compare in the clause where (string)
        """

        doc_id = dialog.doc_id.text()
        if not doc_id:
            message = "You need to insert doc_id"
            self.controller.show_warning(message)
            return

        # Check if document already exist
        sql = (f"SELECT doc_id"
               f" FROM {tablename}"
               f" WHERE doc_id = '{doc_id}' AND {field} = '{field_value}'")
        row = self.controller.get_row(sql)
        if row:
            msg = "Document already exist"
            self.controller.show_warning(msg)
            return

        # Insert into new table
        sql = (f"INSERT INTO {tablename} (doc_id, {field})"
               f" VALUES ('{doc_id}', '{field_value}')")
        status = self.controller.execute_sql(sql)
        if status:
            message = "Document inserted successfully"
            self.controller.show_info(message)

        dialog.tbl_document.model().select()


    def document_open(self, qtable):
        """ Open selected document """

        # Get selected rows
        field_index = qtable.model().fieldIndex('path')
        selected_list = qtable.selectionModel().selectedRows(field_index)
        if not selected_list:
            message = "Any record selected"
            self.controller.show_info_box(message)
            return
        elif len(selected_list) > 1:
            message = "More then one document selected. Select just one document."
            self.controller.show_warning(message)
            return

        path = selected_list[0].data()
        # Check if file exist
        if os.path.exists(path):
            # Open the document
            if sys.platform == "win32":
                os.startfile(path)
            else:
                opener = "open" if sys.platform == "darwin" else "xdg-open"
                subprocess.call([opener, path])
        else:
            webbrowser.open(path)


    def document_delete(self, qtable, tablename):
        """ Delete record from selected rows in tbl_document """

        # Get selected rows. 0 is the column of the pk 0 'id'
        selected_list = qtable.selectionModel().selectedRows(0)
        if len(selected_list) == 0:
            message = "Any record selected"
            self.controller.show_info_box(message)
            return

        selected_id = []
        for index in selected_list:
            doc_id = index.data()
            selected_id.append(str(doc_id))
        message = "Are you sure you want to delete these records?"
        title = "Delete records"
        answer = self.controller.ask_question(message, title, ','.join(selected_id))
        if answer:
            sql = (f"DELETE FROM {tablename}"
                   f" WHERE id IN ({','.join(selected_id)})")
            status = self.controller.execute_sql(sql)
            if not status:
                message = "Error deleting data"
                self.controller.show_warning(message)
                return
            else:
                message = "Document deleted"
                self.controller.show_info(message)
                qtable.model().select()


    def get_all_actions(self):

        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 get_points(self, list_coord=None):
        """ Return list of QgsPoints taken from geometry
        :type list_coord: list of coors in format ['x1 y1', 'x2 y2',....,'x99 y99']
        """

        coords = list_coord.group(1)
        polygon = coords.split(',')
        points = []

        for i in range(0, len(polygon)):
            x, y = polygon[i].split(' ')
            point = QgsPointXY(float(x), float(y))
            points.append(point)

        return points


    def hilight_feature_by_id(self, qtable, layer_name, field_id, width, index):
        """ Based on the received index and field_id, the id of the received field_id is searched within the table
         and is painted in red on the canvas """

        self.resetRubberbands()
        layer = self.controller.get_layer_by_tablename(layer_name)
        if not layer: return

        row = index.row()
        column_index = utils_giswater.get_col_index_by_col_name(qtable, field_id)
        _id = index.sibling(row, column_index).data()
        feature = self.get_feature_by_id(layer, _id, field_id)
        try:
            geometry = feature.geometry()
            self.rubber_polygon.setToGeometry(geometry, None)
            self.rubber_polygon.setColor(QColor(255, 0, 0, 100))
            self.rubber_polygon.setWidth(width)
            self.rubber_polygon.show()
        except AttributeError:
            pass


    def draw_polyline(self, points, color=QColor(255, 0, 0, 100), width=5, duration_time=None):
        """ Draw 'line' over canvas following list of points
         :param duration_time: integer milliseconds ex: 3000 for 3 seconds
         """

        if self.rubber_polygon is None:
            self.init_rubber()

        rb = self.rubber_polygon
        polyline = QgsGeometry.fromPolylineXY(points)
        rb.setToGeometry(polyline, None)
        rb.setColor(color)
        rb.setWidth(width)
        rb.show()

        # wait to simulate a flashing effect
        if duration_time is not None:
            QTimer.singleShot(duration_time, self.resetRubberbands)

        return rb


    def resetRubberbands(self):

        if self.rubber_polygon is None:
            self.init_rubber()

        self.rubber_point.reset(0)
        self.rubber_polygon.reset(2)


    def restore_user_layer(self):

        if self.user_current_layer:
            self.iface.setActiveLayer(self.user_current_layer)
        else:
            layer = self.controller.get_layer_by_tablename('v_edit_node')
            if layer:
                self.iface.setActiveLayer(layer)


    def set_style_mapzones(self):

        extras = f'"mapzones":""'
        body = self.create_body(extras=extras)
        json_return = self.controller.get_json('gw_fct_getstylemapzones', body)
        if not json_return:
            return False

        for mapzone in json_return['body']['data']['mapzones']:

            # Loop for each mapzone returned on json
            lyr = self.controller.get_layer_by_tablename(mapzone['layer'])
            categories = []
            status = mapzone['status']
            if status == 'Disable':
                pass

            if lyr:
                # Loop for each id returned on json
                for id in mapzone['values']:
                    # initialize the default symbol for this geometry type
                    symbol = QgsSymbol.defaultSymbol(lyr.geometryType())
                    symbol.setOpacity(float(mapzone['opacity']))

                    # Setting simp
                    R = random.randint(0, 255)
                    G = random.randint(0, 255)
                    B = random.randint(0, 255)
                    if status == 'Stylesheet':
                        try:
                            R = id['stylesheet']['color'][0]
                            G = id['stylesheet']['color'][1]
                            B = id['stylesheet']['color'][2]
                        except TypeError:
                            R = random.randint(0, 255)
                            G = random.randint(0, 255)
                            B = random.randint(0, 255)

                    elif status == 'Random':
                        R = random.randint(0, 255)
                        G = random.randint(0, 255)
                        B = random.randint(0, 255)

                    # Setting sytle
                    layer_style = {'color': '{}, {}, {}'.format(int(R), int(G), int(B))}
                    symbol_layer = QgsSimpleFillSymbolLayer.create(layer_style)

                    if symbol_layer is not None:
                        symbol.changeSymbolLayer(0, symbol_layer)
                    category = QgsRendererCategory(id['id'], symbol, str(id['id']))
                    categories.append(category)
					
					# apply symbol to layer renderer
                    if 'idname' in mapzone:
                        lyr.setRenderer(QgsCategorizedSymbolRenderer(mapzone['idname'], categories))

                    # repaint layer
                    lyr.triggerRepaint()
Exemple #11
0
    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())
Exemple #12
0
    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")
Exemple #13
0
    def fill_main_table(self, dialog, table_name, set_edit_triggers=QTableView.NoEditTriggers, refresh_model=True):
        """ Set a model with selected filter and attach it to selected table
        @setEditStrategy: 0: OnFieldChange, 1: OnRowChange, 2: OnManualSubmit
        """

        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.OnFieldChange)
        
        dialog.all_rows.setEditTriggers(set_edit_triggers)
        # Check for errors
        if model.lastError().isValid():
            self.controller.show_warning(model.lastError().text())
            return

        # Get all ids from Qtable selected_rows
        id_all_selected_rows = self.select_all_rows(dialog.selected_rows, 'mu_id')

        # Convert id_all_selected_rows to string
        ids = "0, "
        for x in range(0, len(id_all_selected_rows)):
            ids += str(id_all_selected_rows[x]) + ", "
        ids = ids[:-2] + ""

        # Build expression
        expr = (f" mu_name ILIKE '%{dialog.txt_search.text()}%'"
                f" AND mu_id NOT IN ({ids})"
                f" AND campaign_id::text = '{self.campaign_id}'"
                f" OR campaign_id IS null")
        self.controller.log_info(expr)
        # (is_valid, expr) = self.check_expression(expr)  # @UnusedVariable
        # # if not is_valid:
        # #     return
        model.setFilter(expr)
        
        # Refresh model?
        if refresh_model:               
            model.select()
                    
        # Attach model to table view
        dialog.all_rows.setModel(model)
Exemple #14
0
 def setTable(self, table):
     QSqlTableModel.setTable(self, table)
     self.colsEditable = {
         col: True
         for col in range(0, self.columnCount())
     }  #dict of column index:editable
def fill_table(qtable,
               table_name,
               expr_filter=None,
               edit_strategy=QSqlTableModel.OnManualSubmit,
               sort_order=Qt.AscendingOrder):
    """ Set a model with selected filter. Attach that model to selected table
    :param qtable: tableview where set the model (QTableView)
    :param table_name: database table name or view name (String)
    :param expr_filter: expression to filter the model (String)
    :param edit_strategy: (QSqlTableModel.OnFieldChange, QSqlTableModel.OnManualSubmit, QSqlTableModel.OnRowChange)
    :param sort_order: can be 0 or 1 (Qt.AscendingOrder or Qt.AscendingOrder)
    :return:
    """

    if global_vars.schema_name and global_vars.schema_name not in table_name:
        table_name = f"{global_vars.schema_name}.{table_name}"

    # Set model
    model = QSqlTableModel(db=global_vars.qgis_db_credentials)
    model.setTable(table_name)
    model.setEditStrategy(edit_strategy)
    model.setSort(0, sort_order)
    if expr_filter is not None:
        model.setFilter(expr_filter)
    model.select()

    # Check for errors
    if model.lastError().isValid():
        tools_log.log_warning(f"fill_table: {model.lastError().text()}")

    # Attach model to tableview
    qtable.setModel(model)
Exemple #16
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)
Exemple #17
0
    def fill_table_planned_month(self, qtable, txt_filter, tableright, expression=None, set_edit_triggers=QTableView.NoEditTriggers):
        """ Set a model with selected filter and attach it to selected table
        @setEditStrategy: 0: OnFieldChange, 1: OnRowChange, 2: OnManualSubmit
        """
        if self.schema_name not in tableright:
            tableright = f"{self.schema_name}.{tableright}"

        # Set model
        model = QSqlTableModel()
        model.setTable(tableright)
        model.setEditStrategy(QSqlTableModel.OnManualSubmit)
        model.setSort(2, 0)
        model.select()
        qtable.setEditTriggers(set_edit_triggers)
        # Check for errors
        if model.lastError().isValid():
            self.controller.show_warning(model.lastError().text())

        # Create expresion
        expr = (f" mu_name ILIKE '%{txt_filter.text()}%' "
                f" AND campaign_id = '{self.planned_camp_id}' ")

        if expression is not None:
            expr += expression

        qtable.setModel(model)
        qtable.model().setFilter(expr)
Exemple #18
0
    def fill_table(self, dialog, table_view, set_edit_triggers=QTableView.NoEditTriggers, update=False):
        """ Set a model with selected filter and attach it to selected table
        @setEditStrategy: 0: OnFieldChange, 1: OnRowChange, 2: OnManualSubmit
        """

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

        # Set model
        model = QSqlTableModel()
        model.setTable(table_view)
        model.setEditStrategy(QSqlTableModel.OnManualSubmit)
        model.setSort(2, 0)
        model.select()
                
        dialog.selected_rows.setEditTriggers(set_edit_triggers)
        
        # Check for errors
        if model.lastError().isValid():
            self.controller.show_warning(model.lastError().text())

        # Create expresion
        expr = f" mu_name ILIKE '%{dialog.txt_selected_filter.text()}%'"
        if self.selected_camp is not None:
            expr += f" AND campaign_id = '{self.campaign_id}'"
            if update:
                expr += f" OR campaign_id = '{self.selected_camp}'"

        # Attach model to table or view
        dialog.selected_rows.setModel(model)
        dialog.selected_rows.model().setFilter(expr)

        # Set year to plan to all rows in list
        for x in range(0, model.rowCount()):
            i = int(dialog.selected_rows.model().fieldIndex('campaign_id'))
            index = dialog.selected_rows.model().index(x, i)
            model.setData(index, self.campaign_id)
            
        self.calculate_total_price(dialog, self.campaign_id)
Exemple #19
0
    def workcat_fill_table(self,
                           widget,
                           table_name,
                           hidde=False,
                           set_edit_triggers=QTableView.NoEditTriggers,
                           expr=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
        """

        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.OnFieldChange)
        model.setSort(0, 0)
        model.select()

        widget.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:
            widget.setModel(model)
            widget.model().setFilter(expr)
        else:
            widget.setModel(model)

        if hidde:
            self.refresh_table(widget)
Exemple #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")
    def fill_table_unit(self, qtable, table_name,  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.OnFieldChange)
        model.setSort(0, 0)
        model.select()

        # 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
Exemple #22
0
    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()
Exemple #23
0
    def fill_table_prices(self, qtable, table_view, new_camp, set_edit_triggers=QTableView.NoEditTriggers):
        """ Set a model with selected filter and attach it to selected table
        @setEditStrategy: 0: OnFieldChange, 1: OnRowChange, 2: OnManualSubmit
        """
        if self.schema_name not in table_view:
            table_view = self.schema_name + "." + table_view

        # Set model
        model = QSqlTableModel()
        model.setTable(table_view)
        model.setEditStrategy(QSqlTableModel.OnFieldChange)
        model.setSort(2, 0)
        model.select()

        qtable.setEditTriggers(set_edit_triggers)
        
        # Check for errors
        if model.lastError().isValid():
            self.controller.show_warning(model.lastError().text())
            return
        
        # Attach model to table view
        expr = f"campaign_id = '{new_camp}'"
        qtable.setModel(model)
        qtable.model().setFilter(expr)
class hsrrProcessorDockWidget(QDockWidget, FORM_CLASS):

    closingPlugin = pyqtSignal()

    def __init__(self, parent=None):
        super(hsrrProcessorDockWidget, self).__init__(parent)
        self.setupUi(self)

        self.connect_button.clicked.connect(self.connect)
        self.dd = hsrr_processor_dd.hsrr_dd(self)

        self.prepare_database_button.clicked.connect(self.prepare_database)

        self.rw = routes_widget(self, self.dd, 'hsrr.routes',
                                self.readings_box, self.network_box,
                                self.run_fieldbox, self.f_line_fieldbox,
                                self.sec_fieldbox)

        self.rw_placeholder.addWidget(self.rw)
        #self.tabs.insertTab(2,self.rw,'Fitting')

        self.upload_csv_button.clicked.connect(self.upload_runs_dialog)
        self.upload_folder_button.clicked.connect(self.upload_folder_dialog)

        self.open_help_button.clicked.connect(self.open_help)
        self.init_run_menu()
        self.init_requested_menu()
        self.rw.refit.connect(lambda: print('refit'))

    def connect(self):
        if self.dd.exec_():
            if self.dd.connected:
                self.database_label.setText('Connected to %s' %
                                            (self.dd.db.databaseName()))
                self.connect_run_info()
                self.connect_coverage()
                self.refresh_run_info()
            else:
                self.database_label.setText('Not Connected')

    def coverage_show_all(self):
        self.requested_model.setFilter('')
        self.requested_model.select()

    def coverage_show_missing(self):
        self.requested_model.setFilter("coverage=0")
        self.requested_model.select()

#opens help/index.html in default browser

    def open_help(self):
        help_path = os.path.join(os.path.dirname(__file__), 'help',
                                 'index.html')
        help_path = 'file:///' + os.path.abspath(help_path)
        QDesktopServices.openUrl(QUrl(help_path))

    def connect_run_info(self):
        self.run_info_model = QSqlTableModel(db=self.dd.db)
        self.run_info_model.setTable('hsrr.run_info')
        self.run_info_model.setSort(self.run_info_model.fieldIndex("run"),
                                    Qt.AscendingOrder)
        self.run_info_model.setEditStrategy(QSqlTableModel.OnFieldChange)
        self.run_info_view.setModel(self.run_info_model)

    def check_connected(self):
        if self.dd.con:
            return True
        else:
            iface.messageBar().pushMessage(
                'fitting tool: Not connected to database')
            return False

    def upload_runs(self, runs):
        for f in runs:
            r = self.dd.upload_run_csv(f)
            if r == True:
                self.upload_log.appendPlainText('sucessfully uploaded %s' %
                                                (f))
            else:
                self.upload_log.appendPlainText('error uploading %s:%s' %
                                                (f, str(r)))
                self.update()
        self.refresh_run_info()

    def upload_runs_dialog(self):
        if self.check_connected():
            files = file_dialogs.load_files_dialog('.xls',
                                                   'upload spreadsheets')
            if files:
                for f in files:
                    self.upload_runs(files)

    def upload_folder_dialog(self):
        folder = file_dialogs.load_directory_dialog(
            '.xls', 'upload all .xls in directory')
        if folder:
            self.upload_runs(file_dialogs.filter_files(folder, '.xls'))

    def closeEvent(self, event):
        self.dd.disconnect()
        self.closingPlugin.emit()
        event.accept()

    def after_refit(self):
        self.coverage_model.select()

    def connect_coverage(self):
        # self.requested_model = QSqlTableModel(db=self.dd.db)
        self.requested_model = betterTableModel(db=self.dd.db)
        self.requested_model.setEditStrategy(QSqlTableModel.OnFieldChange)
        self.requested_model.setTable('hsrr.requested')
        self.requested_model.setEditable(False)  #set all cols uneditable
        self.requested_model.setColEditable(
            self.requested_model.fieldIndex("note"),
            True)  #make note col editable

        self.requested_model.setSort(self.requested_model.fieldIndex("sec"),
                                     Qt.AscendingOrder)

        self.requested_view.setModel(self.requested_model)
        self.requested_view.setColumnHidden(
            self.requested_model.fieldIndex("pk"), True)  #hide pk column

        self.show_all_button.clicked.connect(self.coverage_show_all)
        self.show_missing_button.clicked.connect(self.coverage_show_missing)
        self.rw.refit.connect(self.requested_model.select)

        if self.show_missing_button.isChecked():
            self.coverage_show_missing()
        else:
            self.coverage_show_all()

        self.requested_view.resizeColumnsToContents()

    def prepare_database(self):
        if self.check_connected():
            msgBox = QMessageBox()
            msgBox.setText(
                "DON'T USE THIS PARTWAY THROUGH THE JOB! because this will erase any data in tables used by this plugin."
            )
            msgBox.setInformativeText("Continue?")
            msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            msgBox.setDefaultButton(QMessageBox.No)
            i = msgBox.exec_()
            if i == QMessageBox.Yes:
                self.dd.setup_database()
                iface.messageBar().pushMessage(
                    'fitting tool: prepared database')

    #drop selected run of run_info table
    def drop_run(self):
        r = self.run_box.currentText()
        self.dd.sql("delete from run_info where run='{run}'", {'run': r})
        self.rw.get_runs()

#for requested view

    def init_run_menu(self):
        self.run_info_menu = QMenu()
        act = self.run_info_menu.addAction('drop run')
        act.triggered.connect(lambda: self.dd.drop_runs([
            str(i.data())
            for i in self.run_info_view.selectionModel().selectedRows(0)
        ]))  # selectedRows(0) returns column 0 (sec)
        act.triggered.connect(
            self.refresh_run_info)  # selectedRows(0) returns column 0 (sec)

        self.run_info_view.setContextMenuPolicy(Qt.CustomContextMenu)
        self.run_info_view.customContextMenuRequested.connect(
            self.show_run_info_menu)

#for requested view

    def init_requested_menu(self):
        self.requested_menu = QMenu()
        act = self.requested_menu.addAction('zoom to section')
        act.triggered.connect(lambda: self.select_on_network([
            i.data()
            for i in self.requested_view.selectionModel().selectedRows()
        ]))
        self.requested_view.setContextMenuPolicy(Qt.CustomContextMenu)
        self.requested_view.customContextMenuRequested.connect(
            self.show_requested_menu)

    def show_run_info_menu(self, pt):
        self.run_info_menu.exec_(self.mapToGlobal(pt))

    def show_requested_menu(self, pt):
        self.requested_menu.exec_(self.mapToGlobal(pt))

    def refresh_run_info(self):
        self.run_info_model.select()
        self.rw.refresh_runs()

#select sec on network

    def select_on_network(self, sects):
        # inds=self.requested_view.selectionModel().selectedRows()#indexes of column 0
        have_network = self.network_box.currentLayer(
        ) and self.sec_fieldbox.currentField()

        if have_network:
            select_sections(sects,
                            self.network_box.currentLayer(),
                            self.sec_fieldbox.currentField(),
                            zoom=True)

        else:
            iface.messageBar().pushMessage(
                'fitting tool:network layer&section field not set')
class grip_testerDockWidget(QDockWidget, FORM_CLASS):

    closingPlugin = pyqtSignal()

    def __init__(self, parent=None):
        super(grip_testerDockWidget, self).__init__(parent)
        self.setupUi(self)

        self.connect_button.clicked.connect(self.connect)
        self.dd = grip_tester_dd.grip_dd(self)

        self.s10_button.clicked.connect(self.set_s10)
        self.zm3_button.clicked.connect(self.set_zm3)
        self.upload_button.clicked.connect(self.upload_run)

        self.to_hmd_button.clicked.connect(self.download_hmd)
        self.prepare_database_button.clicked.connect(self.prepare_database)

        self.search_hmds_button.clicked.connect(self.search_hmds)

        self.rw = routes_widget(self, self.dd, 'gtest.routes',
                                self.readings_box, self.network_box,
                                self.run_fieldbox, self.f_line_fieldbox,
                                self.sec_fieldbox)

        self.rw_placeholder.addWidget(self.rw)
        #self.tabs.insertTab(2,self.rw,'Fitting')

        self.upload_csv_button.clicked.connect(self.upload_run_csvs)

        self.init_requested_menu()
        self.init_missing_menu()
        self.init_run_menu()

        self.open_help_button.clicked.connect(self.open_help)

        self.copy_lengths_button.clicked.connect(
            lambda: copy_functions.copy_all(self.lengths_view))
        self.copy_missing_button.clicked.connect(
            lambda: copy_functions.copy_all(self.missing_view))
        self.copy_benchmarks_button.clicked.connect(
            lambda: copy_functions.copy_all(self.benchmarks_view))
        self.upload_folder_button.clicked.connect(self.upload_folder)

    def connect(self):
        if self.dd.exec_():
            if self.dd.connected:
                self.database_label.setText('Connected to %s' %
                                            (self.dd.db.databaseName()))
                self.dd.sql('set search_path to gtest,public;')
                self.connect_coverage()
                self.connect_lengths()
                self.connect_missing()
                self.connect_benchmarks()
                self.rw.refresh_runs()
                self.connect_run_info()
                self.tabs.currentChanged.connect(self.refresh_coverage)
                self.coverage_toolbox.currentChanged.connect(
                    self.refresh_coverage)
                self.requested_model.dataChanged.connect(
                    lambda: self.missing_model.setQuery(self.missing_model.
                                                        query()))

            else:
                self.database_label.setText('Not Connected')

#opens help/index.html in default browser

    def open_help(self):
        help_path = os.path.join(os.path.dirname(__file__), 'help',
                                 'index.html')
        help_path = 'file:///' + os.path.abspath(help_path)
        QDesktopServices.openUrl(QUrl(help_path))

    def connect_run_info(self):
        self.run_info_model = QSqlTableModel(db=self.dd.db)
        self.run_info_model.setTable('gtest.run_info')
        self.run_info_model.setSort(self.run_info_model.fieldIndex("run"),
                                    Qt.AscendingOrder)
        self.run_info_model.setEditStrategy(QSqlTableModel.OnFieldChange)

        self.run_info_view.setModel(self.run_info_model)
        self.run_info_model.select()

    def connect_coverage(self):
        # self.requested_model = QSqlTableModel(db=self.dd.db)
        self.requested_model = betterTableModel(db=self.dd.db)
        self.requested_model.setEditStrategy(QSqlTableModel.OnFieldChange)
        self.requested_model.setTable('gtest.requested')
        self.requested_model.setEditable(False)  #set all cols uneditable
        self.requested_model.setColEditable(
            self.requested_model.fieldIndex("note"),
            True)  #make note col editable

        self.requested_model.setSort(self.requested_model.fieldIndex("sec"),
                                     Qt.AscendingOrder)

        self.requested_view.setModel(self.requested_model)
        self.requested_view.setColumnHidden(
            self.requested_model.fieldIndex("pk"), True)  #hide pk column
        self.requested_view.setColumnHidden(
            self.requested_model.fieldIndex("coverage"),
            True)  #hide coverage column

        #self.show_all_button.clicked.connect(self.coverage_show_all)
        #self.show_missing_button.clicked.connect(self.coverage_show_missing)
        self.show_missing_button.clicked.connect(self.filter_requested)
        self.show_all_button.clicked.connect(self.filter_requested)
        self.partly_missing_button.clicked.connect(self.filter_requested)

        self.filter_requested()

        self.requested_view.resizeColumnsToContents()

    def filter_requested(self):
        if self.show_missing_button.isChecked():
            self.requested_model.setFilter("cardinality(hmds)=0")

        if self.show_all_button.isChecked():
            self.requested_model.setFilter('')

        if self.partly_missing_button.isChecked():
            self.requested_model.setFilter(
                'cardinality(hmds)>0 and (select count (sec) from gtest.resized where gtest.resized.sec=gtest.requested.sec and gtest.resized.reversed=gtest.requested.reversed and sfc is null)>1'
            )

        self.requested_model.select()

    def connect_benchmarks(self):
        self.benchmarks_model = QSqlQueryModel()
        self.benchmarks_model.setQuery(
            "select early,mid,late,com from gtest.benchmarks_view order by sec,xsp,s_ch",
            self.dd.db)
        self.benchmarks_view.setModel(self.benchmarks_model)
        self.benchmarks_view.resizeColumnsToContents()

    def refresh_coverage(self):
        self.requested_model.select()
        self.missing_model.setQuery(self.missing_model.query())
        self.lengths_model.setQuery(self.lengths_model.query())
        self.benchmarks_model.setQuery(self.benchmarks_model.query())

    def connect_missing(self):
        self.missing_model = QSqlQueryModel()
        self.missing_model.setQuery("select * from gtest.missing_view",
                                    self.dd.db)
        self.missing_view.setModel(self.missing_model)
        self.missing_view.resizeColumnsToContents()

    def connect_lengths(self):
        self.lengths_model = QSqlQueryModel()
        self.lengths_model.setQuery("select * from gtest.lengths", self.dd.db)
        self.lengths_view.setModel(self.lengths_model)
        self.lengths_view.resizeColumnsToContents()
        #make_copyable(self.lengths_view)

    def check_connected(self):
        if self.dd.con:
            return True
        else:
            iface.messageBar().pushMessage(
                'fitting tool: Not connected to database')
            return False

    def upload_run_csvs(self):
        if self.check_connected():
            files = file_dialogs.load_files_dialog('.csv', 'upload csv')
            if files:
                for f in files:
                    #r=self.dd.upload_run_csv(f)
                    r = self.dd.upload_run(f)
                    if r == True:
                        self.upload_log.appendPlainText(
                            'sucessfully uploaded %s' % (f))
                    else:
                        self.upload_log.appendPlainText(
                            'error uploading %s:%s' % (f, str(r)))
                #  self.upload_log.repaint()
                    self.update()
                    #processEvents()

                self.run_info_model.select()
                self.rw.refresh_runs()

    def upload_folder(self):
        folder = file_dialogs.load_directory_dialog(
            '.csv', 'upload all .csv in directory')
        if folder:
            self.dd.upload_runs(file_dialogs.filter_files(folder, '.csv'))

    def closeEvent(self, event):
        self.dd.disconnect()
        self.closingPlugin.emit()
        event.accept()

    def upload_run(self):
        if self.check_connected():
            if self.run_number.text() == '':
                iface.messageBar().pushMessage(
                    'fitting tool: run number not set')
            else:

                self.dd.sql(
                    "insert into run_info select '{run}',to_date('{date}','dd-mm-yyyy') where not exists (select run from run_info where run='{run}')",
                    {
                        'run':
                        self.run_number.text(),
                        'date':
                        str(self.survey_date.date().day()) + '-' +
                        str(self.survey_date.date().month()) + '-' +
                        str(self.survey_date.date().year())
                    })

                if self.s10.text() != '':
                    try:
                        upload_s10(self.run_number.text(), self.s10.text(),
                                   db_to_con(self.dd.db))
                        iface.messageBar().pushMessage(
                            'fitting tool: uploaded s10:' +
                            str(self.s10.text()))

                    except Exception as e:
                        iface.messageBar().pushMessage(
                            'fitting tool: error uploading s10:' +
                            self.s10.text() + ': ' + str(e))

                if self.zm3.text() != '':
                    try:  #zm3,con
                        upload_zm3(self.run_number.text(), self.zm3.text(),
                                   db_to_con(self.dd.db))
                        iface.messageBar().pushMessage(
                            'fitting tool: uploaded zm3:' + self.zm3.text())
                    except Exception as e:
                        iface.messageBar().pushMessage(
                            'fitting tool: error uploading zm3:' +
                            self.zm3.text() + ': ' + str(e))

                self.rw.refresh_runs()

    def set_s10(self):
        s = file_dialogs.load_file_dialog('.s10', 'load .s10')
        if s:
            self.s10.setText(s)

    def set_zm3(self):
        s = file_dialogs.load_file_dialog('.zm3', 'load .zm3')
        if s:
            self.zm3.setText(s)

    def download_hmd(self):
        if self.check_connected():
            s = file_dialogs.save_file_dialog('.hmd')
            print(s)
            if s:
                if self.include_snode_box.isChecked():
                    to_hmd_snode(s, self.forward_box.isChecked(),
                                 self.reversed_box.isChecked(), self.dd.db)
                else:
                    to_hmd(s, self.forward_box.isChecked(),
                           self.reversed_box.isChecked(), self.dd.db)
                iface.messageBar().pushMessage('fitting tool: saved:' + s)

    def prepare_database(self):
        if self.check_connected():
            msgBox = QMessageBox()
            msgBox.setText(
                "DON'T USE THIS PARTWAY THROUGH THE JOB! because this will erase any data in tables used by this plugin."
            )
            msgBox.setInformativeText("Continue?")
            msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            msgBox.setDefaultButton(QMessageBox.No)
            i = msgBox.exec_()
            if i == QMessageBox.Yes:
                self.dd.setup_database()
                iface.messageBar().pushMessage(
                    'fitting tool: prepared database')

    #drop selected run of run_info table
    def drop_run(self):
        r = self.run_box.currentText()
        self.dd.sql("delete from run_info where run='{run}'", {'run': r})
        self.rw.get_runs()

    def search_hmds(self):
        hmds = file_dialogs.load_files_dialog(ext='.hmd',
                                              caption='search hmds')
        if hmds and self.check_connected():
            self.dd.search_hmds(hmds, reset=True)
            iface.messageBar().pushMessage('fitting tool:searched hmds: ' +
                                           ','.join(hmds))
            self.missing_model.setQuery(
                "select * from missing_view")  #refresh missing_model
            self.lengths_model.setQuery("select * from lengths")
            self.requested_model.select()

#for requested view

    def init_requested_menu(self):
        self.requested_menu = QMenu()
        requested_zoom_act = self.requested_menu.addAction('zoom to section')
        requested_zoom_act.triggered.connect(lambda: self.select_on_network([
            i.data()
            for i in self.requested_view.selectionModel().selectedRows()
        ]))

        copy_all_requested_act = self.requested_menu.addAction(
            'copy all rows to clipboard')
        copy_all_requested_act.triggered.connect(
            lambda: copy_functions.copy_all(self.requested_view))

        self.requested_view.setContextMenuPolicy(Qt.CustomContextMenu)
        self.requested_view.customContextMenuRequested.connect(
            self.show_requested_menu)

#for missing_view

    def init_missing_menu(self):
        self.missing_menu = QMenu()
        act = self.missing_menu.addAction('zoom to section')
        act.triggered.connect(lambda: self.select_on_network([
            i.data()
            for i in self.missing_view.selectionModel().selectedRows(1)
        ]))  # selectedRows(1) returns column 1 (sec)
        self.missing_view.setContextMenuPolicy(Qt.CustomContextMenu)
        self.missing_view.customContextMenuRequested.connect(
            self.show_missing_menu)

#for run_info_view

    def init_run_menu(self):
        self.run_info_menu = QMenu()
        act = self.run_info_menu.addAction('drop run')
        act.triggered.connect(lambda: self.dd.drop_runs([
            str(i.data())
            for i in self.run_info_view.selectionModel().selectedRows(0)
        ]))  # selectedRows(0) returns column 0 (run)
        act.triggered.connect(
            self.refresh_runs)  # selectedRows(0) returns column 0 (sec)

        self.run_info_view.setContextMenuPolicy(Qt.CustomContextMenu)
        self.run_info_view.customContextMenuRequested.connect(
            self.show_run_info_menu)

    def show_requested_menu(self, pt):
        self.requested_menu.exec_(self.mapToGlobal(pt))

    def show_missing_menu(self, pt):
        self.missing_menu.exec_(self.mapToGlobal(pt))

    def show_run_info_menu(self, pt):
        self.run_info_menu.exec_(self.mapToGlobal(pt))

    def refresh_runs(self):
        self.rw.get_runs()
        self.run_info_model.select()

#select sec on network

    def select_on_network(self, sects):
        # inds=self.requested_view.selectionModel().selectedRows()#indexes of column 0
        have_network = self.network_box.currentLayer(
        ) and self.sec_fieldbox.currentField()

        if have_network:
            select_sections(sects,
                            self.network_box.currentLayer(),
                            self.sec_fieldbox.currentField(),
                            zoom=True)

        else:
            iface.messageBar().pushMessage(
                'fitting tool:network layer&section field not set')