def set_completer_object(dialog, table_object): """ Set autocomplete of widget @table_object + "_id" getting id's from selected @table_object """ widget = qt_tools.getWidget(dialog, table_object + "_id") if not widget: return # Set SQL field_object_id = "id" if table_object == "element": field_object_id = table_object + "_id" sql = (f"SELECT DISTINCT({field_object_id})" f" FROM {table_object}") rows = global_vars.controller.get_rows(sql) if rows is None: return for i in range(0, len(rows)): aux = rows[i] rows[i] = str(aux[0]) # Set completer and model: add autocomplete in the widget completer = QCompleter() completer.setCaseSensitivity(Qt.CaseInsensitive) widget.setCompleter(completer) model = QStringListModel() model.setStringList(rows) completer.setModel(model)
def setCompleter(self, values, wgt): completer = QCompleter(self) completerModel = QStringListModel(self) wgt.setCompleter(completer) completer.setModel(completerModel) completer.setCaseSensitivity(False) completerModel.setStringList(values)
def setupCompleter(self): # set up string list for completer TOMsMessageLog.logMessage("In setupCompleter:", level=Qgis.Info) lookupStringSet = set() # https://gis.stackexchange.com/questions/155805/qstringlist-error-in-plugin-of-qgis-2-10 self.GazetteerLayer = QgsProject.instance().mapLayersByName("StreetGazetteerRecords")[0] for row in self.GazetteerLayer.getFeatures(): streetName = row.attribute("Descriptor_") locality = row.attribute("Locality") nameString = streetName if locality: nameString = nameString + ", " + locality if nameString: TOMsMessageLog.logMessage("In setupCompleter: nameString: " + nameString, level=Qgis.Info) lookupStringSet.add(nameString) # self.gazetteerStringList.append((nameString)) completer = QCompleter() completer.setCaseSensitivity(Qt.CaseInsensitive) completer.setFilterMode(Qt.MatchContains) self.searchTextbox.setCompleter(completer) model = QStringListModel() completer.setModel(model) model.setStringList(self.gazetteerStringList) model.setStringList(sorted(lookupStringSet))
def _set_completer(self): """ Set autocompleters of the form """ # Adding auto-completion to a QLineEdit - visit_id completer = QCompleter() self.dlg_work.arc_id.setCompleter(completer) model = QStringListModel() model.setStringList(self.selected_list) completer.setModel(model)
def set_completer_lineedit(qlineedit, list_items): """ Set a completer into a QLineEdit :param qlineedit: Object where to set the completer (QLineEdit) :param list_items: List of items to set into the completer (List)["item1","item2","..."] """ completer = QCompleter() completer.setCaseSensitivity(Qt.CaseInsensitive) completer.setMaxVisibleItems(10) completer.setCompletionMode(0) completer.setFilterMode(Qt.MatchContains) completer.popup().setStyleSheet("color: black;") qlineedit.setCompleter(completer) model = QStringListModel() model.setStringList(list_items) completer.setModel(model)
def set_model_by_list(string_list, widget, proxy_model): """ Set the model according to the list """ model = QStringListModel() model.setStringList(string_list) proxy_model.setSourceModel(model) proxy_model.setFilterKeyColumn(0) proxy_model_aux = QSortFilterProxyModel() proxy_model_aux.setSourceModel(model) proxy_model_aux.setFilterKeyColumn(0) widget.setModel(proxy_model_aux) widget.setModelColumn(0) completer = QCompleter() completer.setModel(proxy_model) completer.setCompletionColumn(0) completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) widget.setCompleter(completer)
class ExtendedComboBox(QComboBox): """Extended class of QComboBox so we can perform a filtering of items. """ def __init__(self, parent=None): super(ExtendedComboBox, self).__init__(parent) self.setFocusPolicy(Qt.StrongFocus) self.setEditable(True) # add a filter model to filter matching items self.pFilterModel = QSortFilterProxyModel(self) self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive) self.pFilterModel.setSourceModel(self.model()) # add a completer, which uses the filter model self.completer = QCompleter(self.pFilterModel, self) # always show all (filtered) completions self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) self.setCompleter(self.completer) # connect signals self.lineEdit().textEdited[str].connect( self.pFilterModel.setFilterFixedString) self.completer.activated.connect(self.on_completer_activated) # on selection of an item from the completer, # select the corresponding item from combobox def on_completer_activated(self, text): if text: index = self.findText(text) self.setCurrentIndex(index) # on model change, update the models of the filter and completer as well def setModel(self, model): super(ExtendedComboBox, self).setModel(model) self.pFilterModel.setSourceModel(model) self.completer.setModel(self.pFilterModel) # on model column change, update the model column of # the filter and completer as well def setModelColumn(self, column): self.completer.setCompletionColumn(column) self.pFilterModel.setFilterKeyColumn(column) super(ExtendedComboBox, self).setModelColumn(column)
class FilteredComboBox(QComboBox): """Custom QComboBox with filtering option.""" def __init__(self, parent=None): super(FilteredComboBox, self).__init__(parent) self.setFocusPolicy(Qt.StrongFocus) self.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLength) self.setEditable(True) self.filter_proxy_model = QSortFilterProxyModel(self) self.filter_proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive) self.filter_proxy_model.setSortCaseSensitivity(Qt.CaseInsensitive) self.filter_proxy_model.setSourceModel(self.model()) self.completer = QCompleter(self.filter_proxy_model, self) self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) self.setCompleter(self.completer) self.setMinimumSize(150, 25) self.setFont(QFont("Segoe UI", 10)) self.setStyleSheet("QComboBox {background-color: white;}") self.setMaxVisibleItems(10) self.completer.activated.connect(self.on_completer_activated) self.lineEdit().textEdited.connect( self.filter_proxy_model.setFilterFixedString) def on_completer_activated(self, text): """Set active combobox item when a completer item is picked.""" if not text: return idx = self.findText(text) self.setCurrentIndex(idx) self.activated[str].emit(self.itemText(idx)) def setModel(self, model): """Set completer model after the combobox model.""" super(FilteredComboBox, self).setModel(model) self.filter_proxy_model.setSourceModel(model) self.completer.setModel(self.filter_proxy_model) def setModelColumn(self, column_idx): """Set the correct column for completer and combobox model using column index.""" self.completer.setCompletionColumn(column_idx) self.filter_proxy_model.setFilterKeyColumn(column_idx) super(FilteredComboBox, self).setModelColumn(column_idx)
def set_completer_rows(widget, rows): """ Set a completer into a widget :param widget: Object where to set the completer (QLineEdit) :param rows: rows to set into the completer (List)["item1","item2","..."] """ if rows is None: return list_values = [] for row in rows: list_values.append(str(row[0])) # Set completer and model: add autocomplete in the widget completer = QCompleter() completer.setCaseSensitivity(Qt.CaseInsensitive) widget.setCompleter(completer) model = QStringListModel() model.setStringList(list_values) completer.setModel(model)
def set_completer_feature_id(widget, geom_type, viewname): """ Set autocomplete of widget 'feature_id' getting id's from selected @viewname """ if geom_type == '': return # Adding auto-completion to a QLineEdit completer = QCompleter() completer.setCaseSensitivity(Qt.CaseInsensitive) widget.setCompleter(completer) model = QStringListModel() sql = (f"SELECT {geom_type}_id" f" FROM {viewname}") row = global_vars.controller.get_rows(sql) if row: for i in range(0, len(row)): aux = row[i] row[i] = str(aux[0]) model.setStringList(row) completer.setModel(model)
def finished(self, result): if result == True: self.dlg.layerconcepts.clear() self.dlg.comboBox.setCurrentIndex(0) self.maindlg.currentgraph = self.graph self.dlg.layercount.setText("[" + str(len(self.geoconcepts)) + "]") for geo in self.geoconcepts: self.dlg.layerconcepts.addItem(geo) comp = QCompleter(self.dlg.layerconcepts) comp.setCompletionMode(QCompleter.PopupCompletion) comp.setModel(self.dlg.layerconcepts.model()) self.dlg.layerconcepts.setCompleter(comp) self.dlg.inp_sparql2.setPlainText( self.triplestoreconf[0]["querytemplate"][0]["query"].replace( "%%concept%%", self.geoconcepts[0])) self.dlg.inp_sparql2.columnvars = {} self.maindlg.loadedfromfile = True self.maindlg.justloadingfromfile = False self.loadgraphdlg.close() else: msgBox = QMessageBox() msgBox.setText(self.exception) msgBox.exec() self.progress.close()
def set_completer_widget(tablename, widget, field_id): """ Set autocomplete of widget @table_object + "_id" getting id's from selected @table_object """ if not widget: return # Set SQL sql = (f"SELECT DISTINCT({field_id})" f" FROM {tablename}" f" ORDER BY {field_id}") row = global_vars.controller.get_rows(sql) for i in range(0, len(row)): aux = row[i] row[i] = str(aux[0]) # Set completer and model: add autocomplete in the widget completer = QCompleter() completer.setCaseSensitivity(Qt.CaseInsensitive) widget.setCompleter(completer) model = QStringListModel() model.setStringList(row) completer.setModel(model)
class ExtendedCombobox(QComboBox): """ Overwrite combobox to provide text filtering of combobox list. """ def __init__(self, parent): """ Initialise ExtendedCombobox :param parent: Parent of combobox :type parent: PyQt5.QtWidgets.QWidget """ super().__init__(parent) self.setFocusPolicy(Qt.StrongFocus) self.setEditable(True) self.completer = QCompleter(self) # always show all completions self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) self.p_filter_model = QSortFilterProxyModel(self) self.p_filter_model.setFilterCaseSensitivity(Qt.CaseInsensitive) self.completer.setPopup(self.view()) self.setCompleter(self.completer) self.lineEdit().textEdited.connect(self.p_filter_model.setFilterFixedString) self.completer.activated.connect(self.setTextIfCompleterIsClicked) def setModel(self, model): # pylint:disable=invalid-name """ Set the model to use the Filter model :param model: The model to be used by the combobox :type model: PyQt5.QtGui.QStandardItemModel """ super().setModel(model) self.p_filter_model.setSourceModel(model) self.completer.setModel(self.p_filter_model) def setModelColumn(self, column): # pylint:disable=invalid-name """ :param model: The model to be used by the combobox :type model: PyQt5.QtGui.QStandardItemModel """ self.completer.setCompletionColumn(column) self.p_filter_model.setFilterKeyColumn(column) super().setModelColumn(column) def view(self): """ A QListView of items stored in the model :return: items stored in the model :rtype: PyQt5.QtWidgets.QListView """ return self.completer.popup() def index(self): """ Index of the current item in the combobox. :return: index of the current item :rtype: int """ return self.currentIndex() def setTextIfCompleterIsClicked(self, text): # pylint:disable=invalid-name """ :param text: The current text of the qlineedit :type text: str If the combobx lineedit is clicked, set the lineedits current item as the combobox's current item """ if text: index = self.findText(text) self.setCurrentIndex(index)
class GwMincutTools: def __init__(self, mincut): self.mincut = mincut self.canvas = global_vars.canvas self.plugin_dir = global_vars.plugin_dir self.schema_name = global_vars.schema_name self.settings = global_vars.giswater_settings def set_dialog(self, dialog): self.dlg_mincut_man = dialog def get_mincut_manager(self): self.action = "manage_mincuts" # Create the dialog and signals tools_gw.load_settings(self.dlg_mincut_man) tools_gw.set_dates_from_to(self.dlg_mincut_man.date_from, self.dlg_mincut_man.date_to, 'om_mincut', 'forecast_start, exec_start', 'forecast_end, exec_end') self.dlg_mincut_man.date_from.setEnabled(False) self.dlg_mincut_man.date_to.setEnabled(False) tools_gw.add_icon(self.dlg_mincut_man.btn_selector_mincut, "191") self.tbl_mincut_edit = self.dlg_mincut_man.findChild( QTableView, "tbl_mincut_edit") self.txt_mincut_id = self.dlg_mincut_man.findChild( QLineEdit, "txt_mincut_id") tools_qt.set_tableview_config(self.tbl_mincut_edit) # Adding auto-completion to a QLineEdit self.completer = QCompleter() self.txt_mincut_id.setCompleter(self.completer) model = QStringListModel() sql = "SELECT DISTINCT(id) FROM om_mincut WHERE id > 0 " rows = tools_db.get_rows(sql) values = [] if rows: for row in rows: values.append(str(row[0])) model.setStringList(values) self.completer.setModel(model) self.txt_mincut_id.textChanged.connect( partial(self._filter_by_id, self.tbl_mincut_edit)) self.dlg_mincut_man.date_from.dateChanged.connect( partial(self._filter_by_id, self.tbl_mincut_edit)) self.dlg_mincut_man.date_to.dateChanged.connect( partial(self._filter_by_id, self.tbl_mincut_edit)) self.dlg_mincut_man.cmb_expl.currentIndexChanged.connect( partial(self._filter_by_id, self.tbl_mincut_edit)) self.dlg_mincut_man.spn_next_days.setRange(-9999, 9999) self.dlg_mincut_man.btn_next_days.clicked.connect(self._filter_by_days) self.dlg_mincut_man.spn_next_days.valueChanged.connect( self._filter_by_days) self.dlg_mincut_man.btn_cancel_mincut.clicked.connect( self._set_state_cancel_mincut) self.dlg_mincut_man.tbl_mincut_edit.doubleClicked.connect( partial(self._open_mincut)) self.dlg_mincut_man.btn_cancel.clicked.connect( partial(tools_gw.close_dialog, self.dlg_mincut_man)) self.dlg_mincut_man.rejected.connect( partial(tools_gw.close_dialog, self.dlg_mincut_man)) self.dlg_mincut_man.btn_delete.clicked.connect( partial(self._delete_mincut_management, self.tbl_mincut_edit, "om_mincut", "id")) self.dlg_mincut_man.btn_selector_mincut.clicked.connect( partial(self._mincut_selector, self.tbl_mincut_edit, 'id')) self._populate_combos() self.dlg_mincut_man.state_edit.activated.connect( partial(self._filter_by_id, self.tbl_mincut_edit)) # Set a model with selected filter. Attach that model to selected table self._fill_table_mincut_management(self.tbl_mincut_edit, self.schema_name + ".v_ui_mincut") tools_gw.set_tablemodel_config(self.dlg_mincut_man, self.tbl_mincut_edit, "v_ui_mincut", sort_order=1) # self.mincut.tools_gw.set_tablemodel_config(self.tbl_mincut_edit, "v_ui_mincut") # Open the dialog tools_gw.open_dialog(self.dlg_mincut_man, dlg_name='mincut_manager') # region private functions def _set_state_cancel_mincut(self): selected_list = self.tbl_mincut_edit.selectionModel().selectedRows() if len(selected_list) == 0: message = "Any record selected" tools_qgis.show_warning(message) return inf_text = "" list_id = "" for i in range(0, len(selected_list)): row = selected_list[i].row() id_ = self.tbl_mincut_edit.model().record(row).value("id") inf_text += f"{id_}, " list_id += f"'{id_}', " inf_text = inf_text[:-2] list_id = list_id[:-2] message = "Are you sure you want to cancel these mincuts?" title = "Cancel mincuts" answer = tools_qt.show_question(message, title, inf_text) if answer: sql = (f"UPDATE om_mincut SET mincut_state = 3 " f" WHERE id::text IN ({list_id})") tools_db.execute_sql(sql, log_sql=False) self.tbl_mincut_edit.model().select() def _mincut_selector(self, qtable, field_id): """ Manage mincut selector """ model = qtable.model() selected_mincuts = [] for x in range(0, model.rowCount()): i = int(model.fieldIndex(field_id)) value = model.data(model.index(x, i)) selected_mincuts.append(value) if len(selected_mincuts) == 0: msg = "There are no visible mincuts in the table. Try a different filter or make one" tools_qgis.show_message(msg) return selector_values = f'"selector_mincut", "ids":{selected_mincuts}' mincut_selector = GwSelector() self.dlg_selector = GwSelectorUi() tools_gw.load_settings(self.dlg_selector) current_tab = tools_gw.get_config_parser('dialogs_tab', "dlg_selector_mincut", "user", "session") self.dlg_selector.btn_close.clicked.connect( partial(tools_gw.close_dialog, self.dlg_selector)) self.dlg_selector.rejected.connect( partial(tools_gw.save_settings, self.dlg_selector)) self.dlg_selector.rejected.connect( partial(tools_gw.save_current_tab, self.dlg_selector, self.dlg_selector.main_tab, 'mincut')) selector_vars = {} mincut_selector.get_selector(self.dlg_selector, selector_values, current_tab=current_tab, selector_vars=selector_vars) tools_gw.open_dialog(self.dlg_selector, dlg_name='selector') def _populate_combos(self): # Fill ComboBox state sql = ("SELECT id, idval " "FROM om_typevalue WHERE typevalue = 'mincut_state' " "ORDER BY id") rows = tools_db.get_rows(sql, add_empty_row=True) tools_qt.fill_combo_values(self.dlg_mincut_man.state_edit, rows, 1) # Fill ComboBox exploitation sql = "SELECT expl_id, name FROM exploitation WHERE expl_id > 0 ORDER BY name" rows = tools_db.get_rows(sql, add_empty_row=True) tools_qt.fill_combo_values(self.dlg_mincut_man.cmb_expl, rows, 1) def _open_mincut(self): """ Open mincut form with selected record of the table """ dlg_mincut = GwMincutUi() selected_list = self.tbl_mincut_edit.selectionModel().selectedRows() if len(selected_list) == 0: message = "Any record selected" tools_qgis.show_warning(message) return row = selected_list[0].row() # Get mincut_id from selected row result_mincut_id = self.tbl_mincut_edit.model().record(row).value("id") # Close this dialog and open selected mincut keep_open_form = tools_gw.get_config_parser('dialogs_actions', 'mincut_manager_keep_open', "user", "init", prefix=True) if tools_os.set_boolean(keep_open_form, False) is not True: tools_gw.close_dialog(self.dlg_mincut_man) self.mincut.is_new = False self.mincut.set_dialog(dlg_mincut) self.mincut.init_mincut_form() self.mincut.load_mincut(result_mincut_id) self.mincut.manage_docker() self.mincut.set_visible_mincut_layers(True) def _filter_by_days(self): date_from = datetime.datetime.now() days_added = self.dlg_mincut_man.spn_next_days.text() date_to = datetime.datetime.now() date_to += datetime.timedelta(days=int(days_added)) # If the date_to is less than the date_from, you have to exchange them or the interval will not work if date_to < date_from: aux = date_from date_from = date_to date_to = aux format_low = '%Y-%m-%d 00:00:00.000' format_high = '%Y-%m-%d 23:59:59.999' interval = f"'{date_from.strftime(format_low)}'::timestamp AND '{date_to.strftime(format_high)}'::timestamp" expr = f"(forecast_start BETWEEN {interval})" self.tbl_mincut_edit.model().setFilter(expr) self.tbl_mincut_edit.model().select() def _filter_by_id(self, qtable): expr = "" id_ = tools_qt.get_text(self.dlg_mincut_man, self.dlg_mincut_man.txt_mincut_id, False, False) state_id = tools_qt.get_combo_value(self.dlg_mincut_man, self.dlg_mincut_man.state_edit, 0) state_text = tools_qt.get_combo_value(self.dlg_mincut_man, self.dlg_mincut_man.state_edit, 1) expl = tools_qt.get_combo_value(self.dlg_mincut_man, self.dlg_mincut_man.cmb_expl, 1) dates_filter = "" if state_id == '': self.dlg_mincut_man.date_from.setEnabled(False) self.dlg_mincut_man.date_to.setEnabled(False) else: self.dlg_mincut_man.date_from.setEnabled(True) self.dlg_mincut_man.date_to.setEnabled(True) # Get selected dates visit_start = self.dlg_mincut_man.date_from.date() visit_end = self.dlg_mincut_man.date_to.date() date_from = visit_start.toString('yyyyMMdd 00:00:00') date_to = visit_end.toString('yyyyMMdd 23:59:59') if date_from > date_to: message = "Selected date interval is not valid" tools_qgis.show_warning(message) return # Create interval dates format_low = 'yyyy-MM-dd 00:00:00.000' format_high = 'yyyy-MM-dd 23:59:59.999' interval = f"'{visit_start.toString(format_low)}'::timestamp AND '{visit_end.toString(format_high)}'::timestamp" if str(state_id) == '0': tools_qt.set_widget_text(self.dlg_mincut_man, self.dlg_mincut_man.lbl_date_from, 'Date from: forecast_start') tools_qt.set_widget_text(self.dlg_mincut_man, self.dlg_mincut_man.lbl_date_to, 'Date to: forecast_end') dates_filter = f"AND (forecast_start BETWEEN {interval}) AND (forecast_end BETWEEN {interval})" elif str(state_id) == '3': tools_qt.set_widget_text(self.dlg_mincut_man, self.dlg_mincut_man.lbl_date_from, 'Date from: received_date') tools_qt.set_widget_text(self.dlg_mincut_man, self.dlg_mincut_man.lbl_date_to, 'Date to: received_date') dates_filter = f"AND received_date BETWEEN {interval}" elif str(state_id) in ('1', '2'): tools_qt.set_widget_text(self.dlg_mincut_man, self.dlg_mincut_man.lbl_date_from, 'Date from: exec_start') tools_qt.set_widget_text(self.dlg_mincut_man, self.dlg_mincut_man.lbl_date_to, 'Date to: exec_end') dates_filter = f"AND (exec_start BETWEEN {interval}) AND (exec_end BETWEEN {interval})" else: tools_qt.set_widget_text(self.dlg_mincut_man, self.dlg_mincut_man.lbl_date_from, 'Date from:') tools_qt.set_widget_text(self.dlg_mincut_man, self.dlg_mincut_man.lbl_date_to, 'Date to:') expr += f" (id::text ILIKE '%{id_}%'" expr += f" OR work_order::text ILIKE '%{id_}%')" expr += f" {dates_filter}" if state_text != '': expr += f" AND state::text ILIKE '%{state_text}%' " expr += f" AND (exploitation::text ILIKE '%{expl}%' OR exploitation IS null)" # Refresh model with selected filter qtable.model().setFilter(expr) qtable.model().select() def _fill_table_mincut_management(self, widget, table_name): """ Set a model with selected filter. Attach that model to selected table """ if self.schema_name not in table_name: table_name = self.schema_name + "." + table_name # Set model model = QSqlTableModel(db=global_vars.qgis_db_credentials) model.setTable(table_name) model.setEditStrategy(QSqlTableModel.OnManualSubmit) model.sort(0, 1) model.select() # Check for errors if model.lastError().isValid(): tools_qgis.show_warning(model.lastError().text()) # Attach model to table view widget.setModel(model) def _delete_mincut_management(self, widget, table_name, column_id): """ Delete selected elements of the table (by id) """ # Get selected rows selected_list = widget.selectionModel().selectedRows() if len(selected_list) == 0: message = "Any record selected" tools_qgis.show_warning(message) return inf_text = "" list_id = "" for i in range(0, len(selected_list)): row = selected_list[i].row() id_ = widget.model().record(row).value(str(column_id)) inf_text += f"{id_}, " list_id += f"'{id_}', " inf_text = inf_text[:-2] list_id = list_id[:-2] message = "Are you sure you want to delete these mincuts?" title = "Delete mincut" answer = tools_qt.show_question(message, title, inf_text) if answer: sql = (f"DELETE FROM {table_name}" f" WHERE {column_id} IN ({list_id})") tools_db.execute_sql(sql) widget.model().select() layer = tools_qgis.get_layer_by_tablename('v_om_mincut_node') if layer is not None: layer.triggerRepaint() layer = tools_qgis.get_layer_by_tablename('v_om_mincut_connec') if layer is not None: layer.triggerRepaint() layer = tools_qgis.get_layer_by_tablename('v_om_mincut_arc') if layer is not None: layer.triggerRepaint() layer = tools_qgis.get_layer_by_tablename('v_om_mincut_valve') if layer is not None: layer.triggerRepaint() layer = tools_qgis.get_layer_by_tablename('v_om_mincut') if layer is not None: layer.triggerRepaint() layer = tools_qgis.get_layer_by_tablename('v_om_mincut_hydrometer') if layer is not None: layer.triggerRepaint()
class TmManageVisit(TmParentManage, QObject): # event emitted when a new Visit is added when GUI is closed/accepted visit_added = pyqtSignal(int) def __init__(self, iface, settings, controller, plugin_dir): """ Class to control 'Add visit' of toolbar 'edit' """ QObject.__init__(self) TmParentManage.__init__(self, iface, settings, controller, plugin_dir) def manage_visit(self, visit_id=None, geom_type=None, feature_id=None, single_tool=True, expl_id=None): """ Button 64. Add visit. if visit_id => load record related to the visit_id if geom_type => lock geom_type in relations tab if feature_id => load related feature basing on geom_type in relation if single_tool notify that the tool is used called from another dialog. """ # parameter to set if the dialog is working as single tool or integrated in another tool self.single_tool_mode = single_tool # turnoff autocommit of this and base class. Commit will be done at dialog button box level management self.autocommit = True # bool to distinguish if we entered to edit an existing Visit or creating a new one self.it_is_new_visit = (not visit_id) # set vars to manage if GUI have to lock the relation self.locked_geom_type = geom_type self.locked_feature_id = feature_id # Create the dialog and signals and related ORM Visit class self.current_visit = OmVisit(self.controller) self.dlg_add_visit = AddVisitTm() self.load_settings(self.dlg_add_visit) # Get expl_id from previous dialog self.expl_id = expl_id # Get layers of every geom_type self.reset_lists() self.reset_layers() self.layers['node'] = self.controller.get_group_layers('node') self.visible_layers = self.get_visible_layers() self.remove_selection() # Reset geometry self.x = None self.y = None # Set icons self.set_icon(self.dlg_add_visit.btn_feature_insert, "111") self.set_icon(self.dlg_add_visit.btn_feature_delete, "112") self.set_icon(self.dlg_add_visit.btn_feature_snapping, "137") self.set_icon(self.dlg_add_visit.btn_add_geom, "133") # tab events self.tabs = self.dlg_add_visit.findChild(QTabWidget, 'tab_widget') self.button_box = self.dlg_add_visit.findChild(QDialogButtonBox, 'button_box') self.button_box.button(QDialogButtonBox.Ok).setEnabled(False) # Tab 'Data'/'Visit' self.visit_id = self.dlg_add_visit.findChild(QLineEdit, "visit_id") self.user_name = self.dlg_add_visit.findChild(QLineEdit, "user_name") self.ext_code = self.dlg_add_visit.findChild(QLineEdit, "ext_code") self.visitcat_id = self.dlg_add_visit.findChild( QComboBox, "visitcat_id") # Tab 'Relations' self.feature_type = self.dlg_add_visit.findChild( QComboBox, "feature_type") self.feature_id = self.dlg_add_visit.findChild(QLineEdit, "feature_id") self.tbl_relation = self.dlg_add_visit.findChild( QTableView, "tbl_relation") self.tbl_relation.setSelectionBehavior(QAbstractItemView.SelectRows) # TODO controlar este combo self.feature_type.setVisible(False) # tab 'Event' self.tbl_event = self.dlg_add_visit.findChild(QTableView, "tbl_event") self.parameter_type_id = self.dlg_add_visit.findChild( QComboBox, "parameter_type_id") self.parameter_id = self.dlg_add_visit.findChild( QComboBox, "parameter_id") self.tbl_event.setSelectionBehavior(QAbstractItemView.SelectRows) # Set current date and time current_date = QDate.currentDate() self.dlg_add_visit.startdate.setDate(current_date) self.dlg_add_visit.enddate.setDate(current_date) # set User name get from controller login if self.controller.user and self.user_name: self.user_name.setText(str(self.controller.user)) # set the start tab to be shown (e.g. VisitTab) self.current_tab_index = self.tab_index('VisitTab') self.tabs.setCurrentIndex(self.current_tab_index) # Set signals self.dlg_add_visit.rejected.connect( partial(self.close_dialog, self.dlg_add_visit)) self.dlg_add_visit.rejected.connect(self.manage_rejected) self.dlg_add_visit.accepted.connect(self.manage_accepted) self.dlg_add_visit.btn_event_insert.clicked.connect(self.event_insert) self.dlg_add_visit.btn_event_delete.clicked.connect(self.event_delete) self.dlg_add_visit.btn_event_update.clicked.connect(self.event_update) self.dlg_add_visit.btn_feature_insert.clicked.connect( partial(self.insert_feature, self.feature_id, self.tbl_relation)) self.dlg_add_visit.btn_feature_delete.clicked.connect( partial(self.delete_records, self.dlg_add_visit, self.tbl_relation)) self.dlg_add_visit.btn_feature_snapping.clicked.connect( partial(self.selection_init, self.tbl_relation)) self.tabs.currentChanged.connect(partial(self.manage_tab_changed)) self.visit_id.textChanged.connect(self.manage_visit_id_change) self.dlg_add_visit.btn_add_geom.clicked.connect(self.add_point) # self.event_feature_type_selected() # Fill combo boxes of the form and related events self.feature_type.currentIndexChanged.connect( partial(self.event_feature_type_selected)) self.parameter_type_id.currentIndexChanged.connect( partial(self.set_parameter_id_combo)) self.fill_combos() sql = ( "SELECT value FROM config_param_user " " WHERE parameter = 'visitcat_id' AND cur_user = current_user AND context='arbrat'" ) row = self.controller.get_row(sql) if row: utils_giswater.set_combo_itemData(self.visitcat_id, str(row['value']), 1) self.set_combos(self.dlg_add_visit, self.dlg_add_visit.parameter_type_id, 'parameter_type_id') self.set_combos(self.dlg_add_visit, self.dlg_add_visit.parameter_id, 'parameter_id') # Set autocompleters of the form self.set_completers(self.dlg_add_visit.visit_id, 'om_visit') # Show id of visit. If not set, infer a new value if not visit_id: visit_id = self.current_visit.max_pk(commit=self.autocommit) + 1 self.visit_id.setText(str(visit_id)) # manage relation locking if self.locked_geom_type: self.set_locked_relation() # Open the dialog self.open_dialog(self.dlg_add_visit, dlg_name="add_visit") def set_combos(self, dialog, qcombo, parameter): sql = ( f"SELECT value FROM config_param_user " f" WHERE parameter = '{parameter}' AND cur_user= current_user AND context='arbrat'" ) row = self.controller.get_row(sql) if row: utils_giswater.setWidgetText(dialog, qcombo, str(row['value'])) def manage_accepted(self): """ Do all action when closed the dialog with Ok. e.g. all necessary commits and cleanings. A) Trigger SELECT gw_fct_om_visit_multiplier (visit_id, feature_type) for multiple visits management. """ # notify that a new visit has been added self.visit_added.emit(self.current_visit.id) # Update geometry field (if user have selected a point) if self.x: self.update_geom() self.refresh_map_canvas() self.canvas.setMapTool(self.previous_map_tool) #self.iface.actionPan().trigger() def update_geom(self): """ Update geometry field """ srid = self.controller.plugin_settings_value('srid') sql = ( f"UPDATE om_visit" f" SET the_geom = ST_SetSRID(ST_MakePoint({self.x},{self.y}), {srid})" f" WHERE id = {self.current_visit.id}") self.controller.execute_sql(sql, log_sql=True) def manage_rejected(self): """ Do all action when closed the dialog with Cancel or X. e.g. all necessary rollbacks and cleanings. """ self.canvas.setMapTool(self.previous_map_tool) # removed current working visit. This should cascade removing of all related records if hasattr(self, 'it_is_new_visit') and self.it_is_new_visit: self.current_visit.delete() # Remove all previous selections self.remove_selection() def tab_index(self, tab_name): """ Get the index of a tab basing on objectName. """ for idx in range(self.tabs.count()): if self.tabs.widget(idx).objectName() == tab_name: return idx return -1 def manage_visit_id_change(self, text): """ manage action when the visit id is changed. A) Update current Visit record B) Fill the GUI values of the current visit C) load all related events in the relative table D) load all related documents in the relative table. """ # A) Update current Visit record self.current_visit.id = int(text) exist = self.current_visit.fetch() if exist: # B) Fill the GUI values of the current visit self.fill_widget_with_fields(self.dlg_add_visit, self.current_visit, self.current_visit.field_names()) # C) load all related events in the relative table self.filter = f"visit_id = '{text}'" table_name = self.schema_name + ".om_visit_event" self.fill_table_visit(self.tbl_event, table_name, self.filter) self.set_configuration(self.tbl_event, table_name) self.manage_events_changed() # # D) load all related documents in the relative table # table_name = self.schema_name + ".v_ui_doc_x_visit" # self.fill_table_visit(self.tbl_document, self.schema_name + ".v_ui_doc_x_visit", self.filter) # self.set_configuration(self.tbl_document, table_name) # E) load all related Relations in the relative table self.set_feature_type_by_visit_id() def set_feature_type_by_visit_id(self): """ Set the feature_type in Relation tab basing on visit_id. The steps to follow are: 1) check geometry type looking what table contain records related with visit_id 2) set gemetry type. """ feature_type = None feature_type_index = None for index in range(self.feature_type.count()): # feture_type combobox is filled before the visit_id is changed # it will contain all the geometry type allows basing on project type geometry_type = self.feature_type.itemText(index).lower() table_name = 'om_visit_x_' + geometry_type sql = f"SELECT id FROM {table_name} WHERE visit_id = '{self.current_visit.id}'" rows = self.controller.get_rows(sql, commit=self.autocommit) if not rows or not rows[0]: continue feature_type = geometry_type feature_type_index = index break # if no related records found do nothing if not feature_type: return # set default combo box value = trigger model and selection # of related features if self.feature_type.currentIndex() != feature_type_index: self.feature_type.setCurrentIndex(feature_type_index) else: self.feature_type.currentIndexChanged.emit(feature_type_index) def manage_leave_visit_tab(self): """ manage all the action when leaving the VisitTab A) Manage sync between GUI values and Visit record in DB """ # A) fill Visit basing on GUI values self.current_visit.id = int(self.visit_id.text()) self.current_visit.startdate = self.dlg_add_visit.startdate.date( ).toString(Qt.ISODate) self.current_visit.enddate = self.dlg_add_visit.enddate.date( ).toString(Qt.ISODate) self.current_visit.user_name = self.user_name.text() self.current_visit.ext_code = self.ext_code.text() self.current_visit.visitcat_id = utils_giswater.get_item_data( self.dlg_add_visit, self.dlg_add_visit.visitcat_id, 0) self.current_visit.descript = self.dlg_add_visit.descript.text() if self.expl_id: self.current_visit.expl_id = self.expl_id # update or insert but without closing the transaction: autocommit=False self.current_visit.upsert(commit=self.autocommit) def update_relations(self): """ Save current selected features in tbl_relations. Steps are: A) remove all old relations related with current visit_id. B) save new relations get from that listed in tbl_relations. """ # A) remove all old relations related with current visit_id. db_record = None for index in range(self.feature_type.count()): # feture_type combobox contain all the geometry type # allows basing on project type geometry_type = self.feature_type.itemText(index).lower() # TODO: the next "if" code can be substituded with something like: # exec("db_record = OmVisitX{}{}(self.controller)".format(geometry_type[0].upper(), geometry_type[1:]))" if geometry_type == 'node': db_record = OmVisitXNode(self.controller) # remove all actual saved records related with visit_id where_clause = "visit_id = '{}'".format(self.visit_id.text()) db_record.delete(where_clause=where_clause, commit=self.autocommit) # do nothing if model is None or no element is present if not self.tbl_relation.model() or not self.tbl_relation.model( ).rowCount(): return # set the current db_record tyope to do insert of new records # all the new records belong to the same geom_type # TODO: the next "if" code can be substituded with something like: # exec("db_record = OmVisitX{}{}(self.controller)".format(geometry_type[0].upper(), geometry_type[1:]))" if self.geom_type == 'node': db_record = OmVisitXNode(self.controller) # for each showed element of a specific geom_type create an db entry column_name = self.geom_type + "_id" for row in range(self.tbl_relation.model().rowCount()): # get modelIndex to get data index = self.tbl_relation.model().index(row, 0) # set common fields db_record.id = db_record.max_pk() + 1 db_record.visit_id = int(self.visit_id.text()) # set value for column <geom_type>_id setattr(db_record, column_name, index.data()) # than save the showed records db_record.upsert(commit=self.autocommit) def manage_tab_changed(self, index): """ Do actions when tab is exit and entered. Actions depend on tab index """ # manage leaving tab # tab Visit if self.current_tab_index == self.tab_index('VisitTab'): self.manage_leave_visit_tab() # need to create the relation record that is done only # changing tab if self.locked_geom_type: self.update_relations() # tab Relation if self.current_tab_index == self.tab_index('RelationsTab'): self.update_relations() # manage arriving tab # tab Visit self.current_tab_index = index if index == self.tab_index('VisitTab'): pass # tab Relation if index == self.tab_index('RelationsTab'): pass # tab Event if index == self.tab_index('EventTab'): pass # self.entered_event_tab() def entered_event_tab(self): """ Manage actions when the Event tab is entered """ self.set_parameter_id_combo() def set_parameter_id_combo(self): """ Set parameter_id combo basing on current selections """ sql = ( f"SELECT id, descript" f" FROM om_visit_parameter" f" WHERE UPPER (parameter_type) = '{self.parameter_type_id.currentText().upper()}'" f" AND UPPER (feature_type) = '{self.feature_type.currentText().upper()}'" f" ORDER BY id") rows = self.controller.get_rows(sql, commit=self.autocommit) if rows: utils_giswater.set_item_data(self.dlg_add_visit.parameter_id, rows, 1) def config_relation_table(self, qtable): """ Set all actions related to the table, model and selectionModel. It's necessary a centralised call because base class can create a None model where all callbacks are lost ance can't be registered """ # configure model visibility table_name = "v_edit_" + self.geom_type self.set_configuration(qtable, table_name) def event_feature_type_selected(self): """ Manage selection change in feature_type combo box. THis means that have to set completer for feature_id QTextLine and setup model for features to select table. """ # 1) set the model linked to selecte features # 2) check if there are features related to the current visit # 3) if so, select them => would appear in the table associated to the model self.geom_type = self.feature_type.currentText().lower() viewname = "v_edit_" + self.geom_type self.set_completer_feature_id(self.dlg_add_visit.feature_id, self.geom_type, viewname) # set table model and completer # set a fake where expression to avoid to set model to None fake_filter = f'{self.geom_type}_id IN ("-1")' self.set_table_model(self.tbl_relation, self.geom_type, fake_filter) # set the callback to setup all events later # its not possible to setup listener in this moment beacouse set_table_model without # a valid expression parameter return a None model => no events can be triggered self.lazy_configuration(self.tbl_relation, self.config_relation_table) # check if there are features related to the current visit if not self.visit_id.text(): return table_name = 'om_visit_x_' + self.geom_type sql = f"SELECT {self.geom_type}_id FROM {table_name} WHERE visit_id = '{int(self.visit_id.text())}'" rows = self.controller.get_rows(sql, commit=self.autocommit) if not rows or not rows[0]: return ids = [x[0] for x in rows] # select list of related features # Set 'expr_filter' with features that are in the list expr_filter = f'"{self.geom_type}_id" IN ({",".join(ids)})' # Check expression (is_valid, expr) = self.check_expression(expr_filter) # @UnusedVariable if not is_valid: return # do selection allowing the tbl_relation to be linked to canvas selectionChanged self.disconnect_signal_selection_changed() self.connect_signal_selection_changed(self.tbl_relation) self.select_features_by_ids(self.geom_type, expr) self.disconnect_signal_selection_changed() def fill_combos(self): """ Fill combo boxes of the form """ # Visit tab # Fill ComboBox visitcat_id # save result in self.visitcat_ids to get id depending on selected combo sql = ( "SELECT id, name FROM om_visit_cat" # " WHERE active is true" " ORDER BY name") self.visitcat_ids = self.controller.get_rows(sql, commit=self.autocommit) if self.visitcat_ids: utils_giswater.set_item_data(self.dlg_add_visit.visitcat_id, self.visitcat_ids, 1) # now get default value to be show in visitcat_id sql = ( "SELECT value FROM config_param_user" " WHERE parameter = 'visitcat_vdefault' AND cur_user = current_user" ) row = self.controller.get_row(sql, commit=self.autocommit) if row: # if int then look for default row ans set it try: utils_giswater.set_combo_itemData( self.dlg_add_visit.visitcat_id, row[0], 0) for i in range(0, self.dlg_add_visit.visitcat_id.count()): elem = self.dlg_add_visit.visitcat_id.itemData(i) if str(row[0]) == str(elem[0]): utils_giswater.setWidgetText( self.dlg_add_visit, self.dlg_add_visit.visitcat_id, (elem[1])) except TypeError: pass except ValueError: pass # Relations tab rows = [['node']] utils_giswater.fillComboBox(self.dlg_add_visit, self.dlg_add_visit.feature_type, rows, allow_nulls=False) # Event tab # Fill ComboBox parameter_type_id sql = ("SELECT id FROM om_visit_parameter_type" " ORDER BY id") parameter_type_ids = self.controller.get_rows(sql, commit=self.autocommit) utils_giswater.fillComboBox(self.dlg_add_visit, self.dlg_add_visit.parameter_type_id, parameter_type_ids, allow_nulls=False) def set_completers(self, widget, table_name): """ Set autocompleters of the form """ # Adding auto-completion to a QLineEdit - visit_id self.completer = QCompleter() widget.setCompleter(self.completer) model = QStringListModel() sql = f"SELECT DISTINCT(id) FROM {table_name}" rows = self.controller.get_rows(sql, commit=self.autocommit) values = [] if rows: for row in rows: values.append(str(row[0])) model.setStringList(values) self.completer.setModel(model) def fill_table_visit(self, widget, table_name, filter_): """ Set a model with selected filter. Attach that model to selected table """ if self.schema_name not in table_name: table_name = self.schema_name + "." + table_name # Set model model = QSqlTableModel() model.setTable(table_name) model.setEditStrategy(QSqlTableModel.OnManualSubmit) model.setFilter(filter_) model.select() # Check for errors if model.lastError().isValid(): self.controller.show_warning(model.lastError().text()) # Attach model to table view widget.setModel(model) widget.show() def event_insert(self): """ Add and event basing on form associated to the selected parameter_id """ # check a parameter_id is selected (can be that no value is available) parameter_id = utils_giswater.get_item_data( self.dlg_add_visit, self.dlg_add_visit.parameter_id, 0) if not parameter_id: message = "You need to select a valid parameter id" self.controller.show_info_box(message) return # get form associated sql = (f"SELECT form_type FROM om_visit_parameter" f" WHERE id = '{parameter_id}'") row = self.controller.get_row(sql, commit=False) form_type = str(row[0]) if form_type == 'event_standard': self.dlg_event = EventStandardTm() self.load_settings(self.dlg_event) else: message = "Unrecognised form type" self.controller.show_info_box(message, parameter=form_type) return # because of multiple view disable add picture and view gallery self.dlg_event.btn_add_picture.setEnabled(False) self.dlg_event.btn_view_gallery.setEnabled(False) # set fixed values self.dlg_event.parameter_id.setText(parameter_id) self.dlg_event.setWindowFlags(Qt.WindowStaysOnTopHint) ret = self.dlg_event.exec_() # check return if not ret: # clicked cancel return # create an empty Event event = OmVisitEvent(self.controller) event.id = event.max_pk() + 1 event.parameter_id = parameter_id event.visit_id = int(self.visit_id.text()) for field_name in event.field_names(): if not hasattr(self.dlg_event, field_name): continue value = getattr(self.dlg_event, field_name).text() if value: setattr(event, field_name, value) # save new event event.upsert() # update Table self.tbl_event.model().select() self.manage_events_changed() def manage_events_changed(self): """ Action when at a Event model is changed. A) if some record is available => enable OK button of VisitDialog """ state = (self.tbl_event.model().rowCount() > 0) self.button_box.button(QDialogButtonBox.Ok).setEnabled(state) def event_update(self): """ Update selected event """ if not self.tbl_event.selectionModel().hasSelection(): message = "Any record selected" self.controller.show_info_box(message) return # Get selected rows # TODO: use tbl_event.model().fieldIndex(event.pk()) to be pk name independent # 0 is the column of the pk 0 'id' selected_list = self.tbl_event.selectionModel().selectedRows(0) if selected_list == 0: message = "Any record selected" self.controller.show_info_box(message) return elif len(selected_list) > 1: message = "More then one event selected. Select just one" self.controller.show_warning(message) return # fetch the record event = OmVisitEvent(self.controller) event.id = selected_list[0].data() if not event.fetch(commit=self.autocommit): return # get parameter_id code to select the widget useful to edit the event om_event_parameter = OmVisitParameter(self.controller) om_event_parameter.id = event.parameter_id if not om_event_parameter.fetch(commit=self.autocommit): return if om_event_parameter.form_type == 'event_standard': self.dlg_event_standard = EventStandardTm() self.load_settings(self.dlg_event_standard) # because of multiple view disable add picture and view gallery self.dlg_event_standard.btn_add_picture.setEnabled(False) self.dlg_event_standard.btn_view_gallery.setEnabled(False) # fill widget values if the values are present for field_name in event.field_names(): if not hasattr(self.dlg_event, field_name): continue value = getattr(event, field_name) if value: getattr(self.dlg_event, field_name).setText(str(value)) self.dlg_event_standard.setWindowFlags(Qt.WindowStaysOnTopHint) if self.dlg_event_standard.exec_(): # set record values basing on widget for field_name in event.field_names(): if not hasattr(self.dlg_event_standard, field_name): continue value = getattr(self.dlg_event_standard, field_name).text() if value: setattr(event, field_name, str(value)) # update the record event.upsert(commit=self.autocommit) # update Table self.tbl_event.model().select() self.tbl_event.setModel(self.tbl_event.model()) self.manage_events_changed() def event_delete(self): """ Delete a selected event """ if not self.tbl_event.selectionModel().hasSelection(): message = "Any record selected" self.controller.show_info_box(message) return # a fake event to get some ancyllary data event = OmVisitEvent(self.controller) # Get selected rows # TODO: use tbl_event.model().fieldIndex(event.pk()) to be pk name independent # 0 is the column of the pk 0 'id' selected_list = self.tbl_event.selectionModel().selectedRows(0) selected_id = [] for index in selected_list: selected_id.append(str(index.data())) list_id = ','.join(selected_id) # ask for deletion message = "Are you sure you want to delete these records?" title = "Delete records" answer = self.controller.ask_question(message, title, list_id) if not answer: return # do the action if not event.delete(pks=selected_id, commit=self.autocommit): message = "Error deleting records" self.controller.show_warning(message) return message = "Records deleted" self.controller.show_info(message) # update Table self.tbl_event.model().select() self.manage_events_changed() def set_configuration(self, qtable, table_name): """ Configuration of tables. Set visibility and width of columns """ if not qtable: return # Set width and alias of visible columns columns_to_delete = [] sql = (f"SELECT column_index, width, alias, status" f" FROM config_client_forms" f" WHERE table_id = '{table_name}'" f" ORDER BY column_index") rows = self.controller.get_rows(sql, log_info=False, commit=self.autocommit) if not rows: return for row in rows: if not row['status']: columns_to_delete.append(row['column_index'] - 1) else: width = row['width'] if width is None: width = 100 qtable.setColumnWidth(row['column_index'] - 1, width) qtable.model().setHeaderData(row['column_index'] - 1, Qt.Horizontal, row['alias']) # Set order qtable.model().setSort(0, Qt.AscendingOrder) qtable.model().select() # Delete columns for column in columns_to_delete: qtable.hideColumn(column)
class GwMincutManager(ParentAction): def __init__(self, mincut): """ Class constructor """ self.mincut = mincut self.canvas = mincut.canvas self.plugin_dir = mincut.plugin_dir self.controller = self.mincut.controller self.schema_name = self.controller.schema_name self.settings = self.mincut.settings self.api_parent = ApiParent(mincut.iface, self.settings, self.controller, self.plugin_dir) def mg_mincut_management(self): """ Button 27: Mincut management """ self.action = "mg_mincut_management" # Create the dialog and signals self.dlg_min_edit = MincutManagerUi() self.load_settings(self.dlg_min_edit) self.set_dates_from_to(self.dlg_min_edit.date_from, self.dlg_min_edit.date_to, 'om_mincut', 'forecast_start, exec_start', 'forecast_end, exec_end') self.dlg_min_edit.date_from.setEnabled(False) self.dlg_min_edit.date_to.setEnabled(False) self.set_icon(self.dlg_min_edit.btn_selector_mincut, "191") self.tbl_mincut_edit = self.dlg_min_edit.findChild( QTableView, "tbl_mincut_edit") self.txt_mincut_id = self.dlg_min_edit.findChild( QLineEdit, "txt_mincut_id") self.tbl_mincut_edit.setSelectionBehavior(QAbstractItemView.SelectRows) # Adding auto-completion to a QLineEdit self.completer = QCompleter() self.txt_mincut_id.setCompleter(self.completer) model = QStringListModel() sql = "SELECT DISTINCT(id) FROM om_mincut WHERE id > 0 " rows = self.controller.get_rows(sql) values = [] if rows: for row in rows: values.append(str(row[0])) model.setStringList(values) self.completer.setModel(model) self.txt_mincut_id.textChanged.connect( partial(self.filter_by_id, self.tbl_mincut_edit)) self.dlg_min_edit.date_from.dateChanged.connect( partial(self.filter_by_id, self.tbl_mincut_edit)) self.dlg_min_edit.date_to.dateChanged.connect( partial(self.filter_by_id, self.tbl_mincut_edit)) self.dlg_min_edit.cmb_expl.currentIndexChanged.connect( partial(self.filter_by_id, self.tbl_mincut_edit)) self.dlg_min_edit.spn_next_days.setRange(-9999, 9999) self.dlg_min_edit.btn_next_days.clicked.connect(self.filter_by_days) self.dlg_min_edit.spn_next_days.valueChanged.connect( self.filter_by_days) self.dlg_min_edit.btn_cancel_mincut.clicked.connect( self.set_state_cancel_mincut) self.dlg_min_edit.tbl_mincut_edit.doubleClicked.connect( self.open_mincut) self.dlg_min_edit.btn_cancel.clicked.connect( partial(self.close_dialog, self.dlg_min_edit)) self.dlg_min_edit.rejected.connect( partial(self.close_dialog, self.dlg_min_edit)) self.dlg_min_edit.btn_delete.clicked.connect( partial(self.delete_mincut_management, self.tbl_mincut_edit, "om_mincut", "id")) self.dlg_min_edit.btn_selector_mincut.clicked.connect( partial(self.mincut_selector, self.tbl_mincut_edit, 'id')) self.btn_notify = self.dlg_min_edit.findChild(QPushButton, "btn_notify") self.btn_notify.clicked.connect( partial(self.get_clients_codes, self.dlg_min_edit.tbl_mincut_edit)) self.set_icon(self.btn_notify, "307") try: row = self.controller.get_config('om_mincut_enable_alerts', 'value', 'config_param_system') if row: self.custom_action_sms = json.loads( row[0], object_pairs_hook=OrderedDict) self.btn_notify.setVisible( self.custom_action_sms['show_mincut_sms']) except KeyError: self.btn_notify.setVisible(False) self.populate_combos() self.dlg_min_edit.state_edit.activated.connect( partial(self.filter_by_id, self.tbl_mincut_edit)) # Set a model with selected filter. Attach that model to selected table self.fill_table_mincut_management(self.tbl_mincut_edit, self.schema_name + ".v_ui_mincut") self.set_table_columns(self.dlg_min_edit, self.tbl_mincut_edit, "v_ui_mincut") #self.mincut.set_table_columns(self.tbl_mincut_edit, "v_ui_mincut") # Open the dialog self.open_dialog(self.dlg_min_edit, dlg_name='mincut_manager') def get_clients_codes(self, qtable): selected_list = qtable.selectionModel().selectedRows() if len(selected_list) == 0: message = "Any record selected" self.controller.show_warning(message) return field_code = self.custom_action_sms['field_code'] inf_text = "Are you sure you want to send smd to this clients?" for i in range(0, len(selected_list)): row = selected_list[i].row() id_ = qtable.model().record(row).value(str('id')) inf_text += f"\n\nMincut: {id_}" sql = ( f"SELECT t3.{field_code}, t2.forecast_start, t2.forecast_end, anl_cause " f"FROM om_mincut_hydrometer AS t1 " f"JOIN ext_rtc_hydrometer AS t3 ON t1.hydrometer_id::bigint = t3.id::bigint " f"JOIN om_mincut AS t2 ON t1.result_id = t2.id " f"WHERE result_id = {id_}") rows = self.controller.get_rows(sql, log_sql=True) if not rows: inf_text += "\nClients: None(No messages will be sent)" continue inf_text += "\nClients: \n" for row in rows: inf_text += str(row[0]) + ", " inf_text = inf_text[:-2] inf_text += "\n" answer = self.controller.ask_question(str(inf_text)) if answer: self.call_sms_script(qtable) def call_sms_script(self, qtable): path = self.custom_action_sms['path_sms_script'] if path is None or not os.path.exists(path): self.controller.show_warning("File not found", parameter=path) return selected_list = qtable.selectionModel().selectedRows() field_code = self.custom_action_sms['field_code'] for i in range(0, len(selected_list)): row = selected_list[i].row() id_ = qtable.model().record(row).value(str('id')) sql = ( f"SELECT t3.{field_code}, t2.forecast_start, t2.forecast_end, anl_cause, notified " f"FROM om_mincut_hydrometer AS t1 " f"JOIN ext_rtc_hydrometer AS t3 ON t1.hydrometer_id::bigint = t3.id::bigint " f"JOIN om_mincut AS t2 ON t1.result_id = t2.id " f"WHERE result_id = {id_}") rows = self.controller.get_rows(sql, log_sql=True) if not rows: continue from_date = "" if rows[0][1] is not None: from_date = str(rows[0][1].strftime('%d/%m/%Y %H:%M')) to_date = "" if rows[0][2] is not None: to_date = str(rows[0][2].strftime('%d/%m/%Y %H:%M')) _cause = "" if rows[0][3] is not None: _cause = rows[0][3] list_clients = "" for row in rows: list_clients += str(row[0]) + ", " if len(list_clients) != 0: list_clients = list_clients[:-2] # Call script result = subprocess.call( [path, _cause, from_date, to_date, list_clients]) _date_sended = datetime.datetime.now().strftime('%d/%m/%Y %H:%M') sql = ("UPDATE " + self.schema_name + ".om_mincut ") if row[4] is None: sql += f"SET notified = ('[{{\"code\":\"{result[0]}\",\"date\":\"{_date_sended}\",\"avisats\":\"{result[1]}\",\"afectats\":\"{result[2]}\"}}]') " else: sql += f"SET notified= concat(replace(notified::text,']',','),'{{\"code\":\"{result[0]}\",\"date\":\"{_date_sended}\",\"avisats\":\"{result[1]}\",\"afectats\":\"{result[2]}\"}}]')::json " sql += f"WHERE id = '{id_}'" self.controller.execute_sql(sql) # Set a model with selected filter. Attach that model to selected table self.fill_table_mincut_management( self.tbl_mincut_edit, self.schema_name + ".v_ui_mincut") self.set_table_columns(self.dlg_min_edit, self.tbl_mincut_edit, "v_ui_mincut") def set_state_cancel_mincut(self): selected_list = self.tbl_mincut_edit.selectionModel().selectedRows() if len(selected_list) == 0: message = "Any record selected" self.controller.show_warning(message) return inf_text = "" list_id = "" for i in range(0, len(selected_list)): row = selected_list[i].row() id_ = self.tbl_mincut_edit.model().record(row).value("id") inf_text += f"{id_}, " list_id += f"'{id_}', " inf_text = inf_text[:-2] list_id = list_id[:-2] message = "Are you sure you want to cancel these mincuts?" title = "Cancel mincuts" answer = self.controller.ask_question(message, title, inf_text) if answer: sql = (f"UPDATE om_mincut SET mincut_state = 3 " f" WHERE id::text IN ({list_id})") self.controller.execute_sql(sql, log_sql=False) self.tbl_mincut_edit.model().select() def mincut_selector(self, qtable, field_id): """ Manage mincut selector """ model = qtable.model() selected_mincuts = [] for x in range(0, model.rowCount()): i = int(model.fieldIndex(field_id)) value = model.data(model.index(x, i)) selected_mincuts.append(value) if len(selected_mincuts) == 0: msg = "There are no visible mincuts in the table. Try a different filter or make one" self.controller.show_message(msg) return selector_values = f'"selector_mincut", "ids":{selected_mincuts}' self.dlg_selector = SelectorUi() self.load_settings(self.dlg_selector) current_tab = self.get_last_tab(self.dlg_selector, 'mincut') self.dlg_selector.btn_close.clicked.connect( partial(self.close_dialog, self.dlg_selector)) self.dlg_selector.rejected.connect( partial(self.save_settings, self.dlg_selector)) self.dlg_selector.rejected.connect( partial(self.save_current_tab, self.dlg_selector, self.dlg_selector.main_tab, 'mincut')) self.api_parent.get_selector(self.dlg_selector, selector_values, current_tab=current_tab) self.open_dialog(self.dlg_selector, dlg_name='selector', maximize_button=False) def populate_combos(self): # Fill ComboBox state sql = ("SELECT id, idval " "FROM om_typevalue WHERE typevalue = 'mincut_state' " "ORDER BY id") rows = self.controller.get_rows(sql, add_empty_row=True) qt_tools.set_item_data(self.dlg_min_edit.state_edit, rows, 1) # Fill ComboBox exploitation sql = "SELECT expl_id, name FROM exploitation WHERE expl_id > 0 ORDER BY name" rows = self.controller.get_rows(sql, add_empty_row=True) qt_tools.set_item_data(self.dlg_min_edit.cmb_expl, rows, 1) def open_mincut(self): """ Open mincut form with selected record of the table """ selected_list = self.tbl_mincut_edit.selectionModel().selectedRows() if len(selected_list) == 0: message = "Any record selected" self.controller.show_warning(message) return row = selected_list[0].row() # Get mincut_id from selected row result_mincut_id = self.tbl_mincut_edit.model().record(row).value("id") # Close this dialog and open selected mincut self.close_dialog(self.dlg_min_edit) self.mincut.is_new = False self.mincut.init_mincut_form() self.mincut.load_mincut(result_mincut_id) self.mincut.manage_docker() def filter_by_days(self): date_from = datetime.datetime.now() days_added = self.dlg_min_edit.spn_next_days.text() date_to = datetime.datetime.now() date_to += datetime.timedelta(days=int(days_added)) # If the date_to is less than the date_from, you have to exchange them or the interval will not work if date_to < date_from: aux = date_from date_from = date_to date_to = aux format_low = '%Y-%m-%d 00:00:00.000' format_high = '%Y-%m-%d 23:59:59.999' interval = f"'{date_from.strftime(format_low)}'::timestamp AND '{date_to.strftime(format_high)}'::timestamp" expr = f"(forecast_start BETWEEN {interval})" self.tbl_mincut_edit.model().setFilter(expr) self.tbl_mincut_edit.model().select() def filter_by_id(self, qtable): expr = "" id_ = qt_tools.getWidgetText(self.dlg_min_edit, self.dlg_min_edit.txt_mincut_id, False, False) state_id = qt_tools.get_item_data(self.dlg_min_edit, self.dlg_min_edit.state_edit, 0) state_text = qt_tools.get_item_data(self.dlg_min_edit, self.dlg_min_edit.state_edit, 1) expl = qt_tools.get_item_data(self.dlg_min_edit, self.dlg_min_edit.cmb_expl, 1) dates_filter = "" if state_id == '': self.dlg_min_edit.date_from.setEnabled(False) self.dlg_min_edit.date_to.setEnabled(False) else: self.dlg_min_edit.date_from.setEnabled(True) self.dlg_min_edit.date_to.setEnabled(True) # Get selected dates visit_start = self.dlg_min_edit.date_from.date() visit_end = self.dlg_min_edit.date_to.date() date_from = visit_start.toString('yyyyMMdd 00:00:00') date_to = visit_end.toString('yyyyMMdd 23:59:59') if date_from > date_to: message = "Selected date interval is not valid" self.controller.show_warning(message) return # Create interval dates format_low = 'yyyy-MM-dd 00:00:00.000' format_high = 'yyyy-MM-dd 23:59:59.999' interval = f"'{visit_start.toString(format_low)}'::timestamp AND '{visit_end.toString(format_high)}'::timestamp" if str(state_id) in ('0', '3'): qt_tools.setWidgetText(self.dlg_min_edit, self.dlg_min_edit.lbl_date_from, 'Date from: forecast_start') qt_tools.setWidgetText(self.dlg_min_edit, self.dlg_min_edit.lbl_date_to, 'Date to: forecast_end') dates_filter = f"AND (forecast_start BETWEEN {interval}) AND (forecast_end BETWEEN {interval})" elif str(state_id) in ('1', '2'): qt_tools.setWidgetText(self.dlg_min_edit, self.dlg_min_edit.lbl_date_from, 'Date from: exec_start') qt_tools.setWidgetText(self.dlg_min_edit, self.dlg_min_edit.lbl_date_to, 'Date to: exec_end') dates_filter = f"AND (exec_start BETWEEN {interval}) AND (exec_end BETWEEN {interval})" else: qt_tools.setWidgetText(self.dlg_min_edit, self.dlg_min_edit.lbl_date_from, 'Date from:') qt_tools.setWidgetText(self.dlg_min_edit, self.dlg_min_edit.lbl_date_to, 'Date to:') expr += f" (id::text ILIKE '%{id_}%'" expr += f" OR work_order::text ILIKE '%{id_}%')" expr += f" {dates_filter}" if state_text != '': expr += f" AND state::text ILIKE '%{state_text}%' " expr += f" AND (exploitation::text ILIKE '%{expl}%' OR exploitation IS null)" # Refresh model with selected filter qtable.model().setFilter(expr) qtable.model().select() def fill_table_mincut_management(self, widget, table_name): """ Set a model with selected filter. Attach that model to selected table """ if self.schema_name not in table_name: table_name = self.schema_name + "." + table_name # Set model model = QSqlTableModel() model.setTable(table_name) model.setEditStrategy(QSqlTableModel.OnManualSubmit) model.sort(0, 1) model.select() # Check for errors if model.lastError().isValid(): self.controller.show_warning(model.lastError().text()) # Attach model to table view widget.setModel(model) def delete_mincut_management(self, widget, table_name, column_id): """ Delete selected elements of the table (by id) """ # Get selected rows selected_list = widget.selectionModel().selectedRows() if len(selected_list) == 0: message = "Any record selected" self.controller.show_warning(message) return inf_text = "" list_id = "" for i in range(0, len(selected_list)): row = selected_list[i].row() id_ = widget.model().record(row).value(str(column_id)) inf_text += f"{id_}, " list_id += f"'{id_}', " inf_text = inf_text[:-2] list_id = list_id[:-2] message = "Are you sure you want to delete these mincuts?" title = "Delete mincut" answer = self.controller.ask_question(message, title, inf_text) if answer: sql = (f"DELETE FROM {table_name}" f" WHERE {column_id} IN ({list_id})") self.controller.execute_sql(sql) widget.model().select() layer = self.controller.get_layer_by_tablename('v_om_mincut_node') if layer is not None: layer.triggerRepaint() layer = self.controller.get_layer_by_tablename( 'v_om_mincut_connec') if layer is not None: layer.triggerRepaint() layer = self.controller.get_layer_by_tablename('v_om_mincut_arc') if layer is not None: layer.triggerRepaint() layer = self.controller.get_layer_by_tablename('v_om_mincut_valve') if layer is not None: layer.triggerRepaint() layer = self.controller.get_layer_by_tablename('v_om_mincut') if layer is not None: layer.triggerRepaint() layer = self.controller.get_layer_by_tablename( 'v_om_mincut_hydrometer') if layer is not None: layer.triggerRepaint()
class ParentManage(ParentAction, object): def __init__(self, iface, settings, controller, plugin_dir): """ Class to keep common functions of classes 'ManageDocument', 'ManageElement' and 'ManageVisit' of toolbar 'edit' """ super(ParentManage, self).__init__(iface, settings, controller, plugin_dir) self.x = "" self.y = "" self.canvas = self.iface.mapCanvas() self.plan_om = None self.previous_map_tool = None self.autocommit = True self.lazy_widget = None self.workcat_id_end = None self.xyCoordinates_conected = False self.remove_ids = True self.snapper_manager = None def reset_lists(self): """ Reset list of selected records """ self.ids = [] self.list_ids = {} self.list_ids['arc'] = [] self.list_ids['node'] = [] self.list_ids['connec'] = [] self.list_ids['gully'] = [] self.list_ids['element'] = [] def reset_layers(self): """ Reset list of layers """ self.layers = {} self.layers['arc'] = [] self.layers['node'] = [] self.layers['connec'] = [] self.layers['gully'] = [] self.layers['element'] = [] def reset_model(self, dialog, table_object, geom_type): """ Reset model of the widget """ table_relation = table_object + "_x_" + geom_type widget_name = "tbl_" + table_relation widget = utils_giswater.getWidget(dialog, widget_name) if widget: widget.setModel(None) def remove_selection(self, remove_groups=True): """ Remove all previous selections """ layer = self.controller.get_layer_by_tablename("v_edit_arc") if layer: layer.removeSelection() layer = self.controller.get_layer_by_tablename("v_edit_node") if layer: layer.removeSelection() layer = self.controller.get_layer_by_tablename("v_edit_connec") if layer: layer.removeSelection() layer = self.controller.get_layer_by_tablename("v_edit_element") if layer: layer.removeSelection() if self.project_type == 'ud': layer = self.controller.get_layer_by_tablename("v_edit_gully") if layer: layer.removeSelection() try: if remove_groups: for layer in self.layers['arc']: layer.removeSelection() for layer in self.layers['node']: layer.removeSelection() for layer in self.layers['connec']: layer.removeSelection() for layer in self.layers['gully']: layer.removeSelection() for layer in self.layers['element']: layer.removeSelection() except: pass self.canvas.refresh() def reset_widgets(self, dialog, table_object): """ Clear contents of input widgets """ if table_object == "doc": utils_giswater.setWidgetText(dialog, "doc_type", "") utils_giswater.setWidgetText(dialog, "observ", "") utils_giswater.setWidgetText(dialog, "path", "") elif table_object == "element": utils_giswater.setWidgetText(dialog, "elementcat_id", "") utils_giswater.setWidgetText(dialog, "state", "") utils_giswater.setWidgetText(dialog, "expl_id","") utils_giswater.setWidgetText(dialog, "ownercat_id", "") utils_giswater.setWidgetText(dialog, "location_type", "") utils_giswater.setWidgetText(dialog, "buildercat_id", "") utils_giswater.setWidgetText(dialog, "workcat_id", "") utils_giswater.setWidgetText(dialog, "workcat_id_end", "") utils_giswater.setWidgetText(dialog, "comment", "") utils_giswater.setWidgetText(dialog, "observ", "") utils_giswater.setWidgetText(dialog, "path", "") utils_giswater.setWidgetText(dialog, "rotation", "") utils_giswater.setWidgetText(dialog, "verified", "") utils_giswater.setWidgetText(dialog, dialog.num_elements, "") def fill_widgets(self, dialog, table_object, row): """ Fill input widgets with data int he @row """ if table_object == "doc": utils_giswater.setWidgetText(dialog, "doc_type", row["doc_type"]) utils_giswater.setWidgetText(dialog, "observ", row["observ"]) utils_giswater.setWidgetText(dialog, "path", row["path"]) elif table_object == "element": state = "" if row['state']: sql = (f"SELECT name FROM value_state" f" WHERE id = '{row['state']}'") row_aux = self.controller.get_row(sql, commit=self.autocommit) if row_aux: state = row_aux[0] expl_id = "" if row['expl_id']: sql = (f"SELECT name FROM exploitation" f" WHERE expl_id = '{row['expl_id']}'") row_aux = self.controller.get_row(sql, commit=self.autocommit) if row_aux: expl_id = row_aux[0] utils_giswater.setWidgetText(dialog, "code", row['code']) sql = (f"SELECT elementtype_id FROM cat_element" f" WHERE id = '{row['elementcat_id']}'") row_type = self.controller.get_row(sql) if row_type: utils_giswater.setWidgetText(dialog, "element_type", row_type[0]) utils_giswater.setWidgetText(dialog, "elementcat_id", row['elementcat_id']) utils_giswater.setWidgetText(dialog, "num_elements", row['num_elements']) utils_giswater.setWidgetText(dialog, "state", state) utils_giswater.setWidgetText(dialog, "expl_id", expl_id) utils_giswater.setWidgetText(dialog, "ownercat_id", row['ownercat_id']) utils_giswater.setWidgetText(dialog, "location_type", row['location_type']) utils_giswater.setWidgetText(dialog, "buildercat_id", row['buildercat_id']) utils_giswater.setWidgetText(dialog, "builtdate", row['builtdate']) utils_giswater.setWidgetText(dialog, "workcat_id", row['workcat_id']) utils_giswater.setWidgetText(dialog, "workcat_id_end", row['workcat_id_end']) utils_giswater.setWidgetText(dialog, "comment", row['comment']) utils_giswater.setWidgetText(dialog, "observ", row['observ']) utils_giswater.setWidgetText(dialog, "link", row['link']) utils_giswater.setWidgetText(dialog, "verified", row['verified']) utils_giswater.setWidgetText(dialog, "rotation", row['rotation']) if str(row['undelete']) == 'True': dialog.undelete.setChecked(True) def get_records_geom_type(self, dialog, table_object, geom_type): """ Get records of @geom_type associated to selected @table_object """ object_id = utils_giswater.getWidgetText(dialog, table_object + "_id") table_relation = table_object + "_x_" + geom_type widget_name = "tbl_" + table_relation exists = self.controller.check_table(table_relation) if not exists: self.controller.log_info(f"Not found: {table_relation}") return sql = (f"SELECT {geom_type}_id " f"FROM {table_relation} " f"WHERE {table_object}_id = '{object_id}'") rows = self.controller.get_rows(sql, commit=True, log_info=False) if rows: for row in rows: self.list_ids[geom_type].append(str(row[0])) self.ids.append(str(row[0])) expr_filter = self.get_expr_filter(geom_type) self.set_table_model(dialog, widget_name, geom_type, expr_filter) def exist_object(self, dialog, table_object): """ Check if selected object (document or element) already exists """ # Reset list of selected records self.reset_lists() field_object_id = "id" if table_object == "element": field_object_id = table_object + "_id" object_id = utils_giswater.getWidgetText(dialog, table_object + "_id") # Check if we already have data with selected object_id sql = (f"SELECT * " f" FROM {table_object}" f" WHERE {field_object_id} = '{object_id}'") row = self.controller.get_row(sql, log_info=False) # If object_id not found: Clear data if not row: self.reset_widgets(dialog, table_object) if table_object == 'element': self.set_combo(dialog, 'state', 'value_state', 'state_vdefault', field_name='name') self.set_combo(dialog, 'expl_id', 'exploitation', 'exploitation_vdefault', field_id='expl_id',field_name='name') self.set_calendars(dialog, 'builtdate', 'config_param_user', 'value', 'builtdate_vdefault') self.set_combo(dialog, 'workcat_id', 'cat_work', 'workcat_vdefault', field_id='id', field_name='id') if hasattr(self, 'single_tool_mode'): # some tools can work differently if standalone or integrated in # another tool if self.single_tool_mode: self.remove_selection(True) else: self.remove_selection(True) self.reset_model(dialog, table_object, "arc") self.reset_model(dialog, table_object, "node") self.reset_model(dialog, table_object, "connec") self.reset_model(dialog, table_object, "element") if self.project_type == 'ud': self.reset_model(dialog, table_object, "gully") return # Fill input widgets with data of the @row self.fill_widgets(dialog, table_object, row) # Check related 'arcs' self.get_records_geom_type(dialog, table_object, "arc") # Check related 'nodes' self.get_records_geom_type(dialog, table_object, "node") # Check related 'connecs' self.get_records_geom_type(dialog, table_object, "connec") # Check related 'elements' self.get_records_geom_type(dialog, table_object, "element") # Check related 'gullys' if self.project_type == 'ud': self.get_records_geom_type(dialog, table_object, "gully") def populate_combo(self, dialog, widget, table_name, field_name="id"): """ Executes query and fill combo box """ sql = (f"SELECT {field_name}" f" FROM {table_name}" f" ORDER BY {field_name}") rows = self.controller.get_rows(sql, commit=self.autocommit) utils_giswater.fillComboBox(dialog, widget, rows) if rows: utils_giswater.setCurrentIndex(dialog, widget, 0) def set_combo(self, dialog, widget, table_name, parameter, field_id='id', field_name='id'): """ Executes query and set combo box """ sql = (f"SELECT t1.{field_name} FROM {table_name} as t1" f" INNER JOIN config_param_user as t2 ON t1.{field_id}::text = t2.value::text" f" WHERE parameter = '{parameter}' AND cur_user = current_user") row = self.controller.get_row(sql) if row: utils_giswater.setWidgetText(dialog, widget, row[0]) def set_calendars(self, dialog, widget, table_name, value, parameter): """ Executes query and set QDateEdit """ sql = (f"SELECT {value} FROM {table_name}" f" WHERE parameter = '{parameter}' AND cur_user = current_user") row = self.controller.get_row(sql) if row: date = QDate.fromString(row[0], 'yyyy-MM-dd') else: date = QDate.currentDate() utils_giswater.setCalendarDate(dialog, widget, date) def add_point(self): """ Create the appropriate map tool and connect to the corresponding signal """ active_layer = self.iface.activeLayer() if active_layer is None: active_layer = self.controller.get_layer_by_tablename('version') self.iface.setActiveLayer(active_layer) # Vertex marker self.vertex_marker = QgsVertexMarker(self.canvas) self.vertex_marker.setColor(QColor(255, 100, 255)) self.vertex_marker.setIconSize(15) self.vertex_marker.setIconType(QgsVertexMarker.ICON_CROSS) self.vertex_marker.setPenWidth(3) # Snapper if self.snapper_manager is None: self.snapper_manager = SnappingConfigManager(self.iface) self.snapper = self.snapper_manager.get_snapper() if self.snapper_manager.controller is None: self.snapper_manager.set_controller(self.controller) self.emit_point = QgsMapToolEmitPoint(self.canvas) self.previous_map_tool = self.canvas.mapTool() self.canvas.setMapTool(self.emit_point) self.canvas.xyCoordinates.connect(self.mouse_move) self.xyCoordinates_conected = True self.emit_point.canvasClicked.connect(partial(self.get_xy)) def mouse_move(self, point): # Hide marker and get coordinates self.snapped_point = None self.vertex_marker.hide() event_point = self.snapper_manager.get_event_point(point=point) # Snapping result = self.snapper_manager.snap_to_background_layers(event_point) if self.snapper_manager.result_is_valid(): self.snapper_manager.add_marker(result, self.vertex_marker) else: self.vertex_marker.hide() def get_xy(self, point): """ Get coordinates of selected point """ if self.snapped_point: self.x = self.snapped_point.x() self.y = self.snapped_point.y() else: self.x = point.x() self.y = point.y() message = "Geometry has been added!" self.controller.show_info(message) self.emit_point.canvasClicked.disconnect() self.canvas.xyCoordinates.disconnect() self.xyCoordinates_conected = False self.iface.mapCanvas().refreshAllLayers() self.vertex_marker.hide() def get_values_from_form(self, dialog): self.enddate = utils_giswater.getCalendarDate(dialog, "enddate") self.workcat_id_end = utils_giswater.getWidgetText(dialog, "workcat_id_end") self.description = utils_giswater.getWidgetText(dialog, "descript") def tab_feature_changed(self, dialog, table_object): """ Set geom_type and layer depending selected tab @table_object = ['doc' | 'element' | 'cat_work'] """ self.get_values_from_form(dialog) tab_position = dialog.tab_feature.currentIndex() if tab_position == 0: self.geom_type = "arc" elif tab_position == 1: self.geom_type = "node" elif tab_position == 2: self.geom_type = "connec" elif tab_position == 3: self.geom_type = "element" elif tab_position == 4: self.geom_type = "gully" self.hide_generic_layers() widget_name = f"tbl_{table_object}_x_{self.geom_type}" viewname = f"v_edit_{self.geom_type}" self.widget = utils_giswater.getWidget(dialog, widget_name) # Adding auto-completion to a QLineEdit self.set_completer_feature_id(dialog.feature_id, self.geom_type, viewname) self.iface.actionPan().trigger() def set_completer_object(self, dialog, table_object): """ Set autocomplete of widget @table_object + "_id" getting id's from selected @table_object """ widget = utils_giswater.getWidget(dialog, table_object + "_id") if not widget: return # Set SQL field_object_id = "id" if table_object == "element": field_object_id = table_object + "_id" sql = (f"SELECT DISTINCT({field_object_id})" f" FROM {table_object}") rows = self.controller.get_rows(sql, commit=self.autocommit) if rows is None: return for i in range(0, len(rows)): aux = rows[i] rows[i] = str(aux[0]) # Set completer and model: add autocomplete in the widget self.completer = QCompleter() self.completer.setCaseSensitivity(Qt.CaseInsensitive) widget.setCompleter(self.completer) model = QStringListModel() model.setStringList(rows) self.completer.setModel(model) def set_completer_widget(self, tablename, widget, field_id): """ Set autocomplete of widget @table_object + "_id" getting id's from selected @table_object """ if not widget: return # Set SQL sql = (f"SELECT DISTINCT({field_id})" f" FROM {tablename}" f" ORDER BY {field_id}") row = self.controller.get_rows(sql, commit=True) for i in range(0, len(row)): aux = row[i] row[i] = str(aux[0]) # Set completer and model: add autocomplete in the widget self.completer = QCompleter() self.completer.setCaseSensitivity(Qt.CaseInsensitive) widget.setCompleter(self.completer) model = QStringListModel() model.setStringList(row) self.completer.setModel(model) def set_completer_feature_id(self, widget, geom_type, viewname): """ Set autocomplete of widget 'feature_id' getting id's from selected @viewname """ # Adding auto-completion to a QLineEdit self.completer = QCompleter() self.completer.setCaseSensitivity(Qt.CaseInsensitive) widget.setCompleter(self.completer) model = QStringListModel() sql = (f"SELECT {geom_type}_id" f" FROM {viewname}") row = self.controller.get_rows(sql, commit=self.autocommit) if row: for i in range(0, len(row)): aux = row[i] row[i] = str(aux[0]) model.setStringList(row) self.completer.setModel(model) def get_expr_filter(self, geom_type): """ Set an expression filter with the contents of the list. Set a model with selected filter. Attach that model to selected table """ list_ids = self.list_ids[geom_type] field_id = geom_type + "_id" if len(list_ids) == 0: return None # Set expression filter with features in the list expr_filter = field_id + " IN (" for i in range(len(list_ids)): expr_filter += f"'{list_ids[i]}', " expr_filter = expr_filter[:-2] + ")" # Check expression (is_valid, expr) = self.check_expression(expr_filter) if not is_valid: return None # Select features of layers applying @expr self.select_features_by_ids(geom_type, expr) return expr_filter def reload_table(self, dialog, table_object, geom_type, expr_filter): """ Reload @widget with contents of @tablename applying selected @expr_filter """ if type(table_object) is str: widget_name = f"tbl_{table_object}_x_{geom_type}" widget = utils_giswater.getWidget(dialog, widget_name) if not widget: message = "Widget not found" self.controller.log_info(message, parameter=widget_name) return None elif type(table_object) is QTableView: widget = table_object else: message = "Table_object is not a table name or QTableView" self.controller.log_info(message) return None expr = self.set_table_model(dialog, widget, geom_type, expr_filter) return expr def set_table_model(self, dialog, table_object, geom_type, expr_filter): """ Sets a TableModel to @widget_name attached to @table_name and filter @expr_filter """ expr = None if expr_filter: # Check expression (is_valid, expr) = self.check_expression(expr_filter) #@UnusedVariable if not is_valid: return expr # Set a model with selected filter expression table_name = "v_edit_" + geom_type if self.schema_name not in table_name: table_name = self.schema_name + "." + table_name # Set the model model = QSqlTableModel() model.setTable(table_name) model.setEditStrategy(QSqlTableModel.OnManualSubmit) model.select() if model.lastError().isValid(): self.controller.show_warning(model.lastError().text()) return expr # Attach model to selected widget if type(table_object) is str: widget = utils_giswater.getWidget(dialog, table_object) if not widget: message = "Widget not found" self.controller.log_info(message, parameter=table_object) return expr elif type(table_object) is QTableView: widget = table_object else: message = "Table_object is not a table name or QTableView" self.controller.log_info(message) return expr if expr_filter: widget.setModel(model) widget.model().setFilter(expr_filter) widget.model().select() else: widget.setModel(None) return expr def apply_lazy_init(self, widget): """Apply the init function related to the model. It's necessary a lazy init because model is changed everytime is loaded.""" if self.lazy_widget is None: return if widget != self.lazy_widget: return self.lazy_init_function(self.lazy_widget) def lazy_configuration(self, widget, init_function): """set the init_function where all necessary events are set. This is necessary to allow a lazy setup of the events because set_table_events can create a table with a None model loosing any event connection.""" # TODO: create a dictionary with key:widged.objectName value:initFuction # to allow multiple lazy initialization self.lazy_widget = widget self.lazy_init_function = init_function def select_features_by_ids(self, geom_type, expr): """ Select features of layers of group @geom_type applying @expr """ # Build a list of feature id's and select them for layer in self.layers[geom_type]: if expr is None: layer.removeSelection() else: it = layer.getFeatures(QgsFeatureRequest(expr)) id_list = [i.id() for i in it] if len(id_list) > 0: layer.selectByIds(id_list) else: layer.removeSelection() def delete_records(self, dialog, table_object, query=False): """ Delete selected elements of the table """ self.disconnect_signal_selection_changed() if type(table_object) is str: widget_name = f"tbl_{table_object}_x_{self.geom_type}" widget = utils_giswater.getWidget(dialog, widget_name) if not widget: message = "Widget not found" self.controller.show_warning(message, parameter=widget_name) return elif type(table_object) is QTableView: widget = table_object else: message = "Table_object is not a table name or QTableView" self.controller.log_info(message) return # Control when QTableView is void or has no model try: # Get selected rows selected_list = widget.selectionModel().selectedRows() except AttributeError as e: selected_list = [] if len(selected_list) == 0: message = "Any record selected" self.controller.show_info_box(message) return if query: full_list = widget.model() for x in range(0, full_list.rowCount()): self.ids.append(widget.model().record(x).value(f"{self.geom_type}_id")) else: self.ids = self.list_ids[self.geom_type] field_id = self.geom_type + "_id" del_id = [] inf_text = "" list_id = "" for i in range(0, len(selected_list)): row = selected_list[i].row() id_feature = widget.model().record(row).value(field_id) inf_text += f"{id_feature}, " list_id += f"'{id_feature}', " del_id.append(id_feature) inf_text = inf_text[:-2] list_id = list_id[:-2] message = "Are you sure you want to delete these records?" title = "Delete records" answer = self.controller.ask_question(message, title, inf_text) if answer: for el in del_id: self.ids.remove(el) else: return expr_filter = None expr = None if len(self.ids) > 0: # Set expression filter with features in the list expr_filter = f'"{field_id}" IN (' for i in range(len(self.ids)): expr_filter += f"'{self.ids[i]}', " expr_filter = expr_filter[:-2] + ")" # Check expression (is_valid, expr) = self.check_expression(expr_filter) #@UnusedVariable if not is_valid: return # Update model of the widget with selected expr_filter if query: self.delete_feature_at_plan(dialog, self.geom_type, list_id) self.reload_qtable(dialog, self.geom_type, self.plan_om) else: self.reload_table(dialog, table_object, self.geom_type, expr_filter) self.apply_lazy_init(table_object) # Select features with previous filter # Build a list of feature id's and select them self.select_features_by_ids(self.geom_type, expr) if query: self.remove_selection() # Update list self.list_ids[self.geom_type] = self.ids self.enable_feature_type(dialog) self.connect_signal_selection_changed(dialog, table_object) def manage_close(self, dialog, table_object, cur_active_layer=None): """ Close dialog and disconnect snapping """ if cur_active_layer: self.iface.setActiveLayer(cur_active_layer) if hasattr(self, 'single_tool_mode'): # some tools can work differently if standalone or integrated in # another tool if self.single_tool_mode: self.remove_selection(True) else: self.remove_selection(True) self.reset_model(dialog, table_object, "arc") self.reset_model(dialog, table_object, "node") self.reset_model(dialog, table_object, "connec") self.reset_model(dialog, table_object, "element") if self.project_type == 'ud': self.reset_model(dialog, table_object, "gully") self.close_dialog(dialog) self.hide_generic_layers() self.disconnect_snapping() self.disconnect_signal_selection_changed() def selection_init(self, dialog, table_object, query=False): """ Set canvas map tool to an instance of class 'MultipleSelection' """ multiple_selection = MultipleSelection(self.iface, self.controller, self.layers[self.geom_type], parent_manage=self, table_object=table_object, dialog=dialog) self.disconnect_signal_selection_changed() self.previous_map_tool = self.canvas.mapTool() self.canvas.setMapTool(multiple_selection) self.connect_signal_selection_changed(dialog, table_object, query) cursor = self.get_cursor_multiple_selection() self.canvas.setCursor(cursor) def selection_changed(self, dialog, table_object, geom_type, query=False): """ Slot function for signal 'canvas.selectionChanged' """ self.disconnect_signal_selection_changed() field_id = geom_type + "_id" if self.remove_ids: self.ids = [] # Iterate over all layers of the group for layer in self.layers[self.geom_type]: if layer.selectedFeatureCount() > 0: # Get selected features of the layer features = layer.selectedFeatures() for feature in features: # Append 'feature_id' into the list selected_id = feature.attribute(field_id) if selected_id not in self.ids: self.ids.append(selected_id) if geom_type == 'arc': self.list_ids['arc'] = self.ids elif geom_type == 'node': self.list_ids['node'] = self.ids elif geom_type == 'connec': self.list_ids['connec'] = self.ids elif geom_type == 'gully': self.list_ids['gully'] = self.ids elif geom_type == 'element': self.list_ids['element'] = self.ids expr_filter = None if len(self.ids) > 0: # Set 'expr_filter' with features that are in the list expr_filter = f'"{field_id}" IN (' for i in range(len(self.ids)): expr_filter += f"'{self.ids[i]}', " expr_filter = expr_filter[:-2] + ")" # Check expression (is_valid, expr) = self.check_expression(expr_filter) #@UnusedVariable if not is_valid: return self.select_features_by_ids(geom_type, expr) # Reload contents of table 'tbl_@table_object_x_@geom_type' if query: self.insert_feature_to_plan(dialog, self.geom_type) if self.plan_om == 'plan': self.remove_selection() self.reload_qtable(dialog, geom_type, self.plan_om) else: self.reload_table(dialog, table_object, self.geom_type, expr_filter) self.apply_lazy_init(table_object) # Remove selection in generic 'v_edit' layers if self.plan_om == 'plan': self.remove_selection(False) self.enable_feature_type(dialog) self.connect_signal_selection_changed(dialog, table_object) def delete_feature_at_plan(self, dialog, geom_type, list_id): """ Delete features_id to table plan_@geom_type_x_psector""" value = utils_giswater.getWidgetText(dialog, dialog.psector_id) sql = (f"DELETE FROM {self.plan_om}_psector_x_{geom_type} " f"WHERE {geom_type}_id IN ({list_id}) AND psector_id = '{value}'") self.controller.execute_sql(sql) def enable_feature_type(self, dialog): feature_type = dialog.findChild(QComboBox, 'feature_type') table = dialog.findChild(QTableView, 'tbl_relation') if feature_type is not None and table is not None: if len(self.ids) > 0: feature_type.setEnabled(False) else: feature_type.setEnabled(True) def insert_feature(self, dialog, table_object, query=False, remove_ids=True): """ Select feature with entered id. Set a model with selected filter. Attach that model to selected table """ self.disconnect_signal_selection_changed() # Clear list of ids if remove_ids: self.ids = [] field_id = self.geom_type + "_id" feature_id = utils_giswater.getWidgetText(dialog, "feature_id") if feature_id == 'null': message = "You need to enter a feature id" self.controller.show_info_box(message) return # Iterate over all layers of the group for layer in self.layers[self.geom_type]: if layer.selectedFeatureCount() > 0: # Get selected features of the layer features = layer.selectedFeatures() for feature in features: # Append 'feature_id' into the list selected_id = feature.attribute(field_id) if selected_id not in self.ids: self.ids.append(selected_id) if feature_id not in self.ids: # If feature id doesn't exist in list -> add self.ids.append(str(feature_id)) # Set expression filter with features in the list expr_filter = f'"{field_id}" IN (' for i in range(len(self.ids)): expr_filter += f"'{self.ids[i]}', " expr_filter = expr_filter[:-2] + ")" # Check expression (is_valid, expr) = self.check_expression(expr_filter) if not is_valid: return # Select features with previous filter # Build a list of feature id's and select them for layer in self.layers[self.geom_type]: it = layer.getFeatures(QgsFeatureRequest(expr)) id_list = [i.id() for i in it] if len(id_list) > 0: layer.selectByIds(id_list) # Reload contents of table 'tbl_???_x_@geom_type' if query: self.insert_feature_to_plan(dialog, self.geom_type) self.remove_selection() else: self.reload_table(dialog, table_object, self.geom_type, expr_filter) self.apply_lazy_init(table_object) # Update list self.list_ids[self.geom_type] = self.ids self.enable_feature_type(dialog) self.connect_signal_selection_changed(dialog, table_object) def insert_feature_to_plan(self, dialog, geom_type): """ Insert features_id to table plan_@geom_type_x_psector """ value = utils_giswater.getWidgetText(dialog, dialog.psector_id) for i in range(len(self.ids)): sql = (f"SELECT {geom_type}_id " f"FROM {self.plan_om}_psector_x_{geom_type} " f"WHERE {geom_type}_id = '{self.ids[i]}' AND psector_id = '{value}'") row = self.controller.get_row(sql) if not row: sql = (f"INSERT INTO {self.plan_om}_psector_x_{geom_type}" f"({geom_type}_id, psector_id) VALUES('{self.ids[i]}', '{value}')") self.controller.execute_sql(sql) self.reload_qtable(dialog, geom_type, self.plan_om) def reload_qtable(self, dialog, geom_type, plan_om): """ Reload QtableView """ value = utils_giswater.getWidgetText(dialog, dialog.psector_id) expr = f"psector_id = '{value}'" qtable = utils_giswater.getWidget(dialog, f'tbl_psector_x_{geom_type}') self.fill_table_by_expr(qtable, f"{plan_om}_psector_x_{geom_type}", expr) self.set_table_columns(dialog, qtable, f"{plan_om}_psector_x_{geom_type}") self.refresh_map_canvas() def fill_table_by_expr(self, qtable, table_name, expr): """ :param qtable: QTableView to show :param expr: expression to set model """ if self.schema_name not in table_name: table_name = self.schema_name + "." + table_name model = QSqlTableModel() model.setTable(table_name) model.setFilter(expr) model.setEditStrategy(QSqlTableModel.OnFieldChange) qtable.setEditTriggers(QTableView.DoubleClicked) model.select() qtable.setModel(model) qtable.show() # Check for errors if model.lastError().isValid(): self.controller.show_warning(model.lastError().text()) def disconnect_snapping(self): """ Select 'Pan' as current map tool and disconnect snapping """ try: self.iface.actionPan().trigger() self.canvas.xyCoordinates.disconnect() if self.emit_point: self.emit_point.canvasClicked.disconnect() except: pass def fill_table_object(self, widget, table_name, expr_filter=None): """ Set a model with selected filter. Attach that model to selected table """ if self.schema_name not in table_name: table_name = self.schema_name + "." + table_name # Set model model = QSqlTableModel() model.setTable(table_name) model.setEditStrategy(QSqlTableModel.OnManualSubmit) model.sort(0, 1) if expr_filter: model.setFilter(expr_filter) model.select() # Check for errors if model.lastError().isValid(): self.controller.show_warning(model.lastError().text()) # Attach model to table view widget.setModel(model) def filter_by_id(self, dialog, widget_table, widget_txt, table_object, field_object_id='id'): field_object_id = "id" if table_object == "element": field_object_id = table_object + "_id" object_id = utils_giswater.getWidgetText(dialog, widget_txt) if object_id != 'null': expr = f"{field_object_id}::text ILIKE '%{object_id}%'" # Refresh model with selected filter widget_table.model().setFilter(expr) widget_table.model().select() else: self.fill_table_object(widget_table, self.schema_name + "." + table_object) def delete_selected_object(self, widget, table_object): """ Delete selected objects of the table (by object_id) """ # Get selected rows selected_list = widget.selectionModel().selectedRows() if len(selected_list) == 0: message = "Any record selected" self.controller.show_warning(message) return inf_text = "" list_id = "" field_object_id = "id" if table_object == "element": field_object_id = table_object + "_id" elif "v_ui_om_visitman_x_" in table_object: field_object_id = "visit_id" for i in range(0, len(selected_list)): row = selected_list[i].row() id_ = widget.model().record(row).value(str(field_object_id)) inf_text += f"{id_}, " list_id += f"'{id_}', " inf_text = inf_text[:-2] list_id = list_id[:-2] message = "Are you sure you want to delete these records?" title = "Delete records" answer = self.controller.ask_question(message, title, inf_text) if answer: sql = (f"DELETE FROM {table_object} " f"WHERE {field_object_id} IN ({list_id})") self.controller.execute_sql(sql, commit=self.autocommit) widget.model().select() def open_selected_object(self, dialog, widget, table_object): """ Open object form with selected record of the table """ selected_list = widget.selectionModel().selectedRows() if len(selected_list) == 0: message = "Any record selected" self.controller.show_warning(message) return row = selected_list[0].row() # Get object_id from selected row field_object_id = "id" widget_id = table_object + "_id" if table_object == "element": field_object_id = table_object + "_id" if table_object == "v_ui_om_visit": widget_id = "visit_id" elif "v_ui_om_visitman_x_" in table_object: field_object_id = "visit_id" selected_object_id = widget.model().record(row).value(field_object_id) # Close this dialog and open selected object dialog.close() if table_object == "doc": self.manage_document() utils_giswater.setWidgetText(self.dlg_add_doc, widget_id, selected_object_id) elif table_object == "element": self.manage_element(new_element_id=False) utils_giswater.setWidgetText(self.dlg_add_element, widget_id, selected_object_id) elif table_object == "v_ui_om_visit": self.manage_visit(visit_id=selected_object_id) elif "v_ui_om_visitman_x_" in table_object: self.manage_visit(visit_id=selected_object_id) def set_selectionbehavior(self, dialog): # Get objects of type: QTableView widget_list = dialog.findChildren(QTableView) for widget in widget_list: widget.setSelectionBehavior(QAbstractItemView.SelectRows) def hide_generic_layers(self, visible=False): """ Hide generic layers """ layer = self.controller.get_layer_by_tablename("v_edit_arc") if layer: self.controller.set_layer_visible(layer) layer = self.controller.get_layer_by_tablename("v_edit_node") if layer: self.controller.set_layer_visible(layer) layer = self.controller.get_layer_by_tablename("v_edit_connec") if layer: self.controller.set_layer_visible(layer) layer = self.controller.get_layer_by_tablename("v_edit_element") if layer: self.controller.set_layer_visible(layer) if self.project_type == 'ud': layer = self.controller.get_layer_by_tablename("v_edit_gully") if layer: self.controller.set_layer_visible(layer) def connect_signal_selection_changed(self, dialog, table_object, query=False): """ Connect signal selectionChanged """ try: self.canvas.selectionChanged.connect(partial(self.selection_changed, dialog, table_object, self.geom_type, query)) except Exception: pass def disconnect_signal_selection_changed(self): """ Disconnect signal selectionChanged """ try: self.canvas.selectionChanged.disconnect() self.iface.actionPan().trigger() except Exception: pass def fill_widget_with_fields(self, dialog, data_object, field_names): """Fill the Widget with value get from data_object limited to the list of field_names.""" for field_name in field_names: value = getattr(data_object, field_name) if not hasattr(dialog, field_name): continue widget = getattr(dialog, field_name) if type(widget) == QDateEdit: widget.setDate(value if value else QDate.currentDate()) elif type(widget) == QDateTimeEdit: widget.setDateTime(value if value else QDateTime.currentDateTime()) if type(widget) in [QLineEdit, QTextEdit]: if value: widget.setText(value) else: widget.clear() if type(widget) in [QComboBox]: if not value: widget.setCurrentIndex(0) continue # look the value in item text index = widget.findText(str(value)) if index >= 0: widget.setCurrentIndex(index) continue # look the value in itemData index = widget.findData(value) if index >= 0: widget.setCurrentIndex(index) continue def set_model_to_table(self, widget, table_name, expr_filter): """ Set a model with selected filter. Attach that model to selected table """ if self.schema_name not in table_name: table_name = self.schema_name + "." + table_name # Set model model = QSqlTableModel(); model.setTable(table_name) model.setEditStrategy(QSqlTableModel.OnManualSubmit) model.setFilter(expr_filter) model.select() # Check for errors if model.lastError().isValid(): self.controller.show_warning(model.lastError().text()) # Attach model to table view if widget: widget.setModel(model) else: self.controller.log_info("set_model_to_table: widget not found")
class TmParentAction(object): def __init__(self, iface, settings, controller, plugin_dir): """ Class constructor """ # Initialize instance attributes self.tree_manage_version = "1.0" self.iface = iface self.canvas = self.iface.mapCanvas() self.settings = settings self.controller = controller self.plugin_dir = plugin_dir self.dao = self.controller.dao self.schema_name = self.controller.schema_name self.project_type = None self.file_gsw = None self.gsw_settings = None self.lazy_widget = None def set_controller(self, controller): """ Set controller class """ self.controller = controller self.schema_name = self.controller.schema_name def get_plugin_version(self): """ Get plugin version from metadata.txt file """ # Check if metadata file exists metadata_file = os.path.join(self.plugin_dir, 'metadata.txt') if not os.path.exists(metadata_file): message = "Metadata file not found" + metadata_file self.controller.show_warning(message, parameter=metadata_file) return None metadata = configparser.ConfigParser() metadata.read(metadata_file) plugin_version = metadata.get('general', 'version') if plugin_version is None: message = "Plugin version not found" self.controller.show_warning(message) return plugin_version def load_settings(self, dialog=None): """ Load QGIS settings related with dialog position and size """ if dialog is None: dialog = self.dlg try: screens = ctypes.windll.user32 screen_x = screens.GetSystemMetrics(78) screen_y = screens.GetSystemMetrics(79) x = self.controller.plugin_settings_value(dialog.objectName() + "_x") y = self.controller.plugin_settings_value(dialog.objectName() + "_y") width = self.controller.plugin_settings_value( dialog.objectName() + "_width", dialog.property('width')) height = self.controller.plugin_settings_value( dialog.objectName() + "_height", dialog.property('height')) if int(x) < 0 or int(y) < 0: dialog.resize(int(width), int(height)) else: if int(x) > screen_x: x = int(screen_x) - int(width) if int(y) > screen_y: y = int(screen_y) dialog.setGeometry(int(x), int(y), int(width), int(height)) except: pass def save_settings(self, dialog=None): """ Save QGIS settings related with dialog position and size """ if dialog is None: dialog = self.dlg self.controller.plugin_settings_set_value( dialog.objectName() + "_width", dialog.width()) self.controller.plugin_settings_set_value( dialog.objectName() + "_height", dialog.height()) self.controller.plugin_settings_set_value(dialog.objectName() + "_x", dialog.pos().x() + 8) self.controller.plugin_settings_set_value(dialog.objectName() + "_y", dialog.pos().y() + 31) def open_dialog(self, dlg=None, dlg_name=None, info=True, maximize_button=True, stay_on_top=True): """ Open dialog """ if dlg is None or type(dlg) is bool: dlg = self.dlg # Manage i18n of the dialog if dlg_name: self.controller.manage_translation(dlg_name, dlg) # Manage stay on top, maximize/minimize button and information button # if info is True maximize flag will be ignored # To enable maximize button you must set info to False flags = Qt.WindowCloseButtonHint if info: flags |= Qt.WindowSystemMenuHint | Qt.WindowContextHelpButtonHint else: if maximize_button: flags |= Qt.WindowMinMaxButtonsHint if stay_on_top: flags |= Qt.WindowStaysOnTopHint dlg.setWindowFlags(flags) # Open dialog if issubclass(type(dlg), GwDialog): dlg.open() elif issubclass(type(dlg), GwMainWindow): dlg.show() else: print(f"WARNING: dialog type {type(dlg)} is not handled!") dlg.show() def close_dialog(self, dlg=None): """ Close dialog """ try: self.save_settings(dlg) dlg.close() map_tool = self.canvas.mapTool() # If selected map tool is from the plugin, set 'Pan' as current one if map_tool.toolName() == '': self.iface.actionPan().trigger() except AttributeError: pass def hide_colums(self, widget, comuns_to_hide): for i in range(0, len(comuns_to_hide)): widget.hideColumn(comuns_to_hide[i]) def set_icon(self, widget, icon): """ Set @icon to selected @widget """ # Get icons folder icons_folder = os.path.join(self.plugin_dir, 'icons') icon_path = os.path.join(icons_folder, str(icon) + ".png") if os.path.exists(icon_path): widget.setIcon(QIcon(icon_path)) else: self.controller.log_info("File not found", parameter=icon_path) def check_expression(self, expr_filter, log_info=False): """ Check if expression filter @expr_filter is valid """ if log_info: self.controller.log_info(expr_filter) expr = QgsExpression(expr_filter) if expr.hasParserError(): message = "Expression Error" self.controller.log_warning(message, parameter=expr_filter) return False, expr return True, expr def set_table_columns(self, dialog, widget, table_name, project_type=None): """ Configuration of tables. Set visibility and width of columns """ widget = utils_giswater.getWidget(dialog, widget) if not widget: return # Set width and alias of visible columns columns_to_delete = [] sql = (f"SELECT column_index, width, alias, status" f" FROM config_client_forms" f" WHERE table_id = '{table_name}'") if project_type is not None: sql += f" AND project_type = '{project_type}' " sql += " ORDER BY column_index" rows = self.controller.get_rows(sql, log_info=False) if not rows: return for row in rows: if not row['status']: columns_to_delete.append(row['column_index'] - 1) else: width = row['width'] if width is not None: widget.setColumnWidth(row['column_index'] - 1, width) widget.model().setHeaderData(row['column_index'] - 1, Qt.Horizontal, row['alias']) widget.model().select() # Delete columns for column in columns_to_delete: widget.hideColumn(column) def set_completer_object(self, tablename, widget, field_search): """ Set autocomplete of widget @table_object + "_id" getting id's from selected @table_object """ if not widget: return # Set SQL sql = (f"SELECT DISTINCT({field_search})" f" FROM {tablename}" f" ORDER BY {field_search}") rows = self.controller.get_rows(sql) if rows is None: return for i in range(0, len(rows)): aux = rows[i] rows[i] = aux[0] # Set completer and model: add autocomplete in the widget self.completer = QCompleter() self.completer.setCaseSensitivity(Qt.CaseInsensitive) self.completer.setCompletionMode(0) widget.setCompleter(self.completer) model = QStringListModel() model.setStringList(rows) self.completer.setModel(model) def refresh_map_canvas(self, restore_cursor=False): """ Refresh all layers present in map canvas """ self.canvas.refreshAllLayers() for layer_refresh in self.canvas.layers(): layer_refresh.triggerRepaint() if restore_cursor: self.set_cursor_restore() def set_cursor_restore(self): """ Restore to previous cursors """ QApplication.restoreOverrideCursor() def get_cursor_multiple_selection(self): """ Set cursor for multiple selection """ path_folder = os.path.join(os.path.dirname(__file__), os.pardir) path_cursor = os.path.join(path_folder, 'icons', '201.png') if os.path.exists(path_cursor): cursor = QCursor(QPixmap(path_cursor)) else: cursor = QCursor(Qt.ArrowCursor) return cursor def fill_table(self, qtable, table_name, set_edit_triggers=QTableView.NoEditTriggers, expr_filter=None): """ Fill table @widget filtering query by @workcat_id Set a model with selected filter. Attach that model to selected table @setEditStrategy: 0: OnFieldChange 1: OnRowChange 2: OnManualSubmit """ expr = None if expr_filter: # Check expression (is_valid, expr) = self.check_expression(expr_filter) # @UnusedVariable if not is_valid: return expr # Set a model with selected filter expression if self.schema_name not in table_name: table_name = self.schema_name + "." + table_name # Set model model = QSqlTableModel() model.setTable(table_name) model.setEditStrategy(QSqlTableModel.OnManualSubmit) model.setSort(0, 0) model.select() # When change some field we need to refresh Qtableview and filter by psector_id qtable.setEditTriggers(set_edit_triggers) # Check for errors if model.lastError().isValid(): self.controller.show_warning(model.lastError().text()) # Attach model to table view if expr: qtable.setModel(model) qtable.model().setFilter(expr_filter) else: qtable.setModel(model) return expr def get_feature_by_id(self, layer, id, field_id): features = layer.getFeatures() for feature in features: if feature[field_id] == id: return feature return False
class GwGo2Epa: def __init__(self): """ Class to control toolbar 'go2epa' """ self.g2epa_opt = GwGo2EpaOptions() self.iterations = 0 self.controller = global_vars.controller self.project_type = self.controller.get_project_type() self.plugin_dir = global_vars.plugin_dir def go2epa(self): """ Button 23: Open form to set INP, RPT and project """ # Show form in docker? self.controller.init_docker('qgis_form_docker') # Create dialog self.dlg_go2epa = Go2EpaUI() load_settings(self.dlg_go2epa) self.load_user_values() if self.project_type in 'ws': self.dlg_go2epa.chk_export_subcatch.setVisible(False) # Set signals self.set_signals() if self.project_type == 'ws': self.dlg_go2epa.btn_hs_ds.setText("Dscenario Selector") tableleft = "cat_dscenario" tableright = "selector_inp_demand" field_id_left = "dscenario_id" field_id_right = "dscenario_id" self.dlg_go2epa.btn_hs_ds.clicked.connect( partial(self.sector_selection, tableleft, tableright, field_id_left, field_id_right, aql="")) elif self.project_type == 'ud': self.dlg_go2epa.btn_hs_ds.setText("Hydrology selector") self.dlg_go2epa.btn_hs_ds.clicked.connect( self.ud_hydrology_selector) # Check OS and enable/disable checkbox execute EPA software if sys.platform != "win32": qt_tools.setChecked(self.dlg_go2epa, self.dlg_go2epa.chk_exec, False) self.dlg_go2epa.chk_exec.setEnabled(False) self.dlg_go2epa.chk_exec.setText( 'Execute EPA software (Runs only on Windows)') self.set_completer_result(self.dlg_go2epa.txt_result_name, 'v_ui_rpt_cat_result', 'result_id') if self.controller.dlg_docker: self.controller.manage_translation('go2epa', self.dlg_go2epa) self.controller.dock_dialog(self.dlg_go2epa) self.dlg_go2epa.btn_cancel.clicked.disconnect() self.dlg_go2epa.btn_cancel.clicked.connect( self.controller.close_docker) else: open_dialog(self.dlg_go2epa, dlg_name='go2epa') def set_signals(self): self.dlg_go2epa.txt_result_name.textChanged.connect( partial(self.check_result_id)) self.dlg_go2epa.btn_file_inp.clicked.connect( self.go2epa_select_file_inp) self.dlg_go2epa.btn_file_rpt.clicked.connect( self.go2epa_select_file_rpt) self.dlg_go2epa.btn_accept.clicked.connect(self.go2epa_accept) self.dlg_go2epa.btn_cancel.clicked.connect( partial(close_dialog, self.dlg_go2epa)) self.dlg_go2epa.rejected.connect(partial(close_dialog, self.dlg_go2epa)) self.dlg_go2epa.btn_options.clicked.connect(self.epa_options) def check_inp_chk(self, file_inp): if file_inp is None: msg = "Select valid INP file" self.controller.show_warning(msg, parameter=str(file_inp)) return False def check_rpt(self): file_inp = qt_tools.getWidgetText(self.dlg_go2epa, self.dlg_go2epa.txt_file_inp) file_rpt = qt_tools.getWidgetText(self.dlg_go2epa, self.dlg_go2epa.txt_file_rpt) # Control execute epa software if qt_tools.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_exec): if self.check_inp_chk(file_inp) is False: return False if file_rpt is None: msg = "Select valid RPT file" self.controller.show_warning(msg, parameter=str(file_rpt)) return False if not qt_tools.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_export): if not os.path.exists(file_inp): msg = "File INP not found" self.controller.show_warning(msg, parameter=str(file_rpt)) return False def check_fields(self): file_inp = qt_tools.getWidgetText(self.dlg_go2epa, self.dlg_go2epa.txt_file_inp) file_rpt = qt_tools.getWidgetText(self.dlg_go2epa, self.dlg_go2epa.txt_file_rpt) result_name = qt_tools.getWidgetText(self.dlg_go2epa, self.dlg_go2epa.txt_result_name, False, False) # Control export INP if qt_tools.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_export): if self.check_inp_chk(file_inp) is False: return False # Control execute epa software if self.check_rpt() is False: return False # Control import result if qt_tools.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_import_result): if file_rpt is None: msg = "Select valid RPT file" self.controller.show_warning(msg, parameter=str(file_rpt)) return False if not qt_tools.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_exec): if not os.path.exists(file_rpt): msg = "File RPT not found" self.controller.show_warning(msg, parameter=str(file_rpt)) return False else: if self.check_rpt() is False: return False # Control result name if result_name == '': self.dlg_go2epa.txt_result_name.setStyleSheet( "border: 1px solid red") msg = "This parameter is mandatory. Please, set a value" self.controller.show_details(msg, title="Rpt fail", inf_text=None) return False sql = (f"SELECT result_id FROM rpt_cat_result " f"WHERE result_id = '{result_name}' LIMIT 1") row = self.controller.get_row(sql) if row: msg = "Result name already exists, do you want overwrite?" answer = self.controller.ask_question(msg, title="Alert") if not answer: return False return True def load_user_values(self): """ Load QGIS settings related with file_manager """ self.dlg_go2epa.txt_result_name.setMaxLength(16) self.result_name = get_parser_value('go2epa', 'go2epa_RESULT_NAME') self.dlg_go2epa.txt_result_name.setText(self.result_name) self.file_inp = get_parser_value('go2epa', 'go2epa_FILE_INP') self.dlg_go2epa.txt_file_inp.setText(self.file_inp) self.file_rpt = get_parser_value('go2epa', 'go2epa_FILE_RPT') self.dlg_go2epa.txt_file_rpt.setText(self.file_rpt) value = get_parser_value('go2epa', 'go2epa_chk_NETWORK_GEOM') qt_tools.setChecked(self.dlg_go2epa, self.dlg_go2epa.chk_only_check, value) value = get_parser_value('go2epa', 'go2epa_chk_INP') qt_tools.setChecked(self.dlg_go2epa, self.dlg_go2epa.chk_export, value) value = get_parser_value('go2epa', 'go2epa_chk_UD') qt_tools.setChecked(self.dlg_go2epa, self.dlg_go2epa.chk_export_subcatch, value) value = get_parser_value('go2epa', 'go2epa_chk_EPA') qt_tools.setChecked(self.dlg_go2epa, self.dlg_go2epa.chk_exec, value) value = get_parser_value('go2epa', 'go2epa_chk_RPT') qt_tools.setChecked(self.dlg_go2epa, self.dlg_go2epa.chk_import_result, value) def save_user_values(self): """ Save QGIS settings related with file_manager """ set_parser_value( 'go2epa', 'go2epa_RESULT_NAME', f"{qt_tools.getWidgetText(self.dlg_go2epa, 'txt_result_name', return_string_null=False)}" ) set_parser_value( 'go2epa', 'go2epa_FILE_INP', f"{qt_tools.getWidgetText(self.dlg_go2epa, 'txt_file_inp', return_string_null=False)}" ) set_parser_value( 'go2epa', 'go2epa_FILE_RPT', f"{qt_tools.getWidgetText(self.dlg_go2epa, 'txt_file_rpt', return_string_null=False)}" ) set_parser_value( 'go2epa', 'go2epa_chk_NETWORK_GEOM', f"{qt_tools.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_only_check)}" ) set_parser_value( 'go2epa', 'go2epa_chk_INP', f"{qt_tools.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_export)}" ) set_parser_value( 'go2epa', 'go2epa_chk_UD', f"{qt_tools.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_export_subcatch)}" ) set_parser_value( 'go2epa', 'go2epa_chk_EPA', f"{qt_tools.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_exec)}") set_parser_value( 'go2epa', 'go2epa_chk_RPT', f"{qt_tools.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_import_result)}" ) def sector_selection(self, tableleft, tableright, field_id_left, field_id_right, aql=""): """ Load the tables in the selection form """ dlg_psector_sel = Multirow_selector('dscenario') load_settings(dlg_psector_sel) dlg_psector_sel.btn_ok.clicked.connect(dlg_psector_sel.close) if tableleft == 'cat_dscenario': dlg_psector_sel.setWindowTitle(" Dscenario selector") qt_tools.setWidgetText( dlg_psector_sel, dlg_psector_sel.lbl_filter, self.controller.tr('Filter by: Dscenario name', context_name='labels')) qt_tools.setWidgetText( dlg_psector_sel, dlg_psector_sel.lbl_unselected, self.controller.tr('Unselected dscenarios', context_name='labels')) qt_tools.setWidgetText( dlg_psector_sel, dlg_psector_sel.lbl_selected, self.controller.tr('Selected dscenarios', context_name='labels')) multi_row_selector(dlg_psector_sel, tableleft, tableright, field_id_left, field_id_right, aql=aql) open_dialog(dlg_psector_sel) def epa_options(self): """ Open dialog api_epa_options.ui.ui """ self.g2epa_opt.go2epa_options() return def ud_hydrology_selector(self): """ Dialog hydrology_selector.ui """ self.dlg_hydrology_selector = HydrologySelector() load_settings(self.dlg_hydrology_selector) self.dlg_hydrology_selector.btn_accept.clicked.connect( self.save_hydrology) self.dlg_hydrology_selector.hydrology.currentIndexChanged.connect( self.update_labels) self.dlg_hydrology_selector.txt_name.textChanged.connect( partial(self.filter_cbx_by_text, "cat_hydrology", self.dlg_hydrology_selector.txt_name, self.dlg_hydrology_selector.hydrology)) sql = "SELECT DISTINCT(name), hydrology_id FROM cat_hydrology ORDER BY name" rows = self.controller.get_rows(sql) if not rows: message = "Any data found in table" self.controller.show_warning(message, parameter='cat_hydrology') return False qt_tools.set_item_data(self.dlg_hydrology_selector.hydrology, rows) sql = ( "SELECT DISTINCT(t1.name) FROM cat_hydrology AS t1 " "INNER JOIN selector_inp_hydrology AS t2 ON t1.hydrology_id = t2.hydrology_id " "WHERE t2.cur_user = current_user") row = self.controller.get_row(sql) if row: qt_tools.setWidgetText(self.dlg_hydrology_selector, self.dlg_hydrology_selector.hydrology, row[0]) else: qt_tools.setWidgetText(self.dlg_hydrology_selector, self.dlg_hydrology_selector.hydrology, 0) self.update_labels() open_dialog(self.dlg_hydrology_selector) def save_hydrology(self): hydrology_id = qt_tools.get_item_data( self.dlg_hydrology_selector, self.dlg_hydrology_selector.hydrology, 1) sql = ("SELECT cur_user FROM selector_inp_hydrology " "WHERE cur_user = current_user") row = self.controller.get_row(sql) if row: sql = (f"UPDATE selector_inp_hydrology " f"SET hydrology_id = {hydrology_id} " f"WHERE cur_user = current_user") else: sql = ( f"INSERT INTO selector_inp_hydrology (hydrology_id, cur_user) " f"VALUES('{hydrology_id}', current_user)") self.controller.execute_sql(sql) message = "Values has been update" self.controller.show_info(message) close_dialog(self.dlg_hydrology_selector) def update_labels(self): """ Show text in labels from SELECT """ sql = ( f"SELECT infiltration, text FROM cat_hydrology" f" WHERE name = '{self.dlg_hydrology_selector.hydrology.currentText()}'" ) row = self.controller.get_row(sql) if row is not None: qt_tools.setText(self.dlg_hydrology_selector, self.dlg_hydrology_selector.infiltration, row[0]) qt_tools.setText(self.dlg_hydrology_selector, self.dlg_hydrology_selector.descript, row[1]) def filter_cbx_by_text(self, tablename, widgettxt, widgetcbx): sql = (f"SELECT DISTINCT(name), hydrology_id FROM {tablename}" f" WHERE name LIKE '%{widgettxt.text()}%'" f" ORDER BY name ") rows = self.controller.get_rows(sql) if not rows: message = "Check the table 'cat_hydrology' " self.controller.show_warning(message) return False qt_tools.set_item_data(widgetcbx, rows) self.update_labels() def go2epa_select_file_inp(self): """ Select INP file """ self.file_inp = qt_tools.getWidgetText(self.dlg_go2epa, self.dlg_go2epa.txt_file_inp) # Set default value if necessary if self.file_inp is None or self.file_inp == '': self.file_inp = global_vars.plugin_dir # Get directory of that file folder_path = os.path.dirname(self.file_inp) if not os.path.exists(folder_path): folder_path = os.path.dirname(__file__) os.chdir(folder_path) message = self.controller.tr("Select INP file") self.file_inp, filter_ = QFileDialog.getSaveFileName( None, message, "", '*.inp') qt_tools.setWidgetText(self.dlg_go2epa, self.dlg_go2epa.txt_file_inp, self.file_inp) def go2epa_select_file_rpt(self): """ Select RPT file """ # Set default value if necessary if self.file_rpt is None or self.file_rpt == '': self.file_rpt = global_vars.plugin_dir # Get directory of that file folder_path = os.path.dirname(self.file_rpt) if not os.path.exists(folder_path): folder_path = os.path.dirname(__file__) os.chdir(folder_path) message = self.controller.tr("Select RPT file") self.file_rpt, filter_ = QFileDialog.getSaveFileName( None, message, "", '*.rpt') qt_tools.setWidgetText(self.dlg_go2epa, self.dlg_go2epa.txt_file_rpt, self.file_rpt) def go2epa_accept(self): """ Save INP, RPT and result name into GSW file """ # Save user values self.save_user_values() self.dlg_go2epa.txt_infolog.clear() self.dlg_go2epa.txt_file_rpt.setStyleSheet(None) status = self.check_fields() if status is False: return # Get widgets values self.result_name = qt_tools.getWidgetText( self.dlg_go2epa, self.dlg_go2epa.txt_result_name, False, False) self.net_geom = qt_tools.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_only_check) self.export_inp = qt_tools.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_export) self.export_subcatch = qt_tools.isChecked( self.dlg_go2epa, self.dlg_go2epa.chk_export_subcatch) self.file_inp = qt_tools.getWidgetText(self.dlg_go2epa, self.dlg_go2epa.txt_file_inp) self.exec_epa = qt_tools.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_exec) self.file_rpt = qt_tools.getWidgetText(self.dlg_go2epa, self.dlg_go2epa.txt_file_rpt) self.import_result = qt_tools.isChecked( self.dlg_go2epa, self.dlg_go2epa.chk_import_result) # Check for sector selector if self.export_inp: sql = "SELECT sector_id FROM selector_sector LIMIT 1" row = self.controller.get_row(sql) if row is None: msg = "You need to select some sector" self.controller.show_info_box(msg) return # Set background task 'Go2Epa' description = f"Go2Epa" self.task_go2epa = GwGo2EpaTask(description, self) QgsApplication.taskManager().addTask(self.task_go2epa) QgsApplication.taskManager().triggerTask(self.task_go2epa) def set_completer_result(self, widget, viewname, field_name): """ Set autocomplete of widget 'feature_id' getting id's from selected @viewname """ result_name = qt_tools.getWidgetText(self.dlg_go2epa, self.dlg_go2epa.txt_result_name) # Adding auto-completion to a QLineEdit self.completer = QCompleter() self.completer.setCaseSensitivity(Qt.CaseInsensitive) widget.setCompleter(self.completer) model = QStringListModel() sql = f"SELECT {field_name} FROM {viewname}" rows = self.controller.get_rows(sql) if rows: for i in range(0, len(rows)): aux = rows[i] rows[i] = str(aux[0]) model.setStringList(rows) self.completer.setModel(model) if result_name in rows: self.dlg_go2epa.chk_only_check.setEnabled(True) def check_result_id(self): """ Check if selected @result_id already exists """ result_id = qt_tools.getWidgetText(self.dlg_go2epa, self.dlg_go2epa.txt_result_name) sql = (f"SELECT result_id FROM v_ui_rpt_cat_result" f" WHERE result_id = '{result_id}'") row = self.controller.get_row(sql, log_info=False) if not row: self.dlg_go2epa.chk_only_check.setChecked(False) self.dlg_go2epa.chk_only_check.setEnabled(False) else: self.dlg_go2epa.chk_only_check.setEnabled(True) def go2epa_options_get_data(self, tablename, dialog): """ Get data from selected table """ sql = f"SELECT * FROM {tablename}" row = self.controller.get_row(sql) if not row: message = "Any data found in table" self.controller.show_warning(message, parameter=tablename) return None # Iterate over all columns and populate its corresponding widget columns = [] for i in range(0, len(row)): column_name = self.controller.dao.get_column_name(i) widget = dialog.findChild(QWidget, column_name) widget_type = qt_tools.getWidgetType(dialog, widget) if row[column_name] is not None: if widget_type is QCheckBox: qt_tools.setChecked(dialog, widget, row[column_name]) elif widget_type is QComboBox: qt_tools.set_combo_itemData(widget, row[column_name], 0) elif widget_type is QDateEdit: dateaux = row[column_name].replace('/', '-') date = QDate.fromString(dateaux, 'dd-MM-yyyy') qt_tools.setCalendarDate(dialog, widget, date) elif widget_type is QTimeEdit: timeparts = str(row[column_name]).split(':') if len(timeparts) < 3: timeparts.append("0") days = int(timeparts[0]) / 24 hours = int(timeparts[0]) % 24 minuts = int(timeparts[1]) seconds = int(timeparts[2]) time = QTime(hours, minuts, seconds) qt_tools.setTimeEdit(dialog, widget, time) qt_tools.setText(dialog, column_name + "_day", days) else: qt_tools.setWidgetText(dialog, widget, str(row[column_name])) columns.append(column_name) return columns def update_sql(self): usql = GwAdmin() usql.init_sql()
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")
class TmParentAction(object): def __init__(self, iface, settings, controller, plugin_dir): """ Class constructor """ # Initialize instance attributes self.tree_manage_version = "1.0" self.iface = iface self.canvas = self.iface.mapCanvas() self.settings = settings self.controller = controller self.plugin_dir = plugin_dir self.dao = self.controller.dao self.schema_name = self.controller.schema_name self.project_type = None self.file_gsw = None self.gsw_settings = None self.lazy_widget = None def set_controller(self, controller): """ Set controller class """ self.controller = controller self.schema_name = self.controller.schema_name def get_plugin_version(self): """ Get plugin version from metadata.txt file """ # Check if metadata file exists metadata_file = os.path.join(self.plugin_dir, 'metadata.txt') if not os.path.exists(metadata_file): message = "Metadata file not found" + metadata_file self.controller.show_warning(message, parameter=metadata_file) return None metadata = configparser.ConfigParser() metadata.read(metadata_file) plugin_version = metadata.get('general', 'version') if plugin_version is None: message = "Plugin version not found" self.controller.show_warning(message) return plugin_version def load_settings(self, dialog=None): """ Load QGIS settings related with dialog position and size """ if dialog is None: dialog = self.dlg try: screens = ctypes.windll.user32 screen_x = screens.GetSystemMetrics(78) screen_y = screens.GetSystemMetrics(79) x = self.controller.plugin_settings_value(dialog.objectName() + "_x") y = self.controller.plugin_settings_value(dialog.objectName() + "_y") width = self.controller.plugin_settings_value( dialog.objectName() + "_width", dialog.property('width')) height = self.controller.plugin_settings_value( dialog.objectName() + "_height", dialog.property('height')) if int(x) < 0 or int(y) < 0: dialog.resize(int(width), int(height)) else: if int(x) > screen_x: x = int(screen_x) - int(width) if int(y) > screen_y: y = int(screen_y) dialog.setGeometry(int(x), int(y), int(width), int(height)) except: pass def save_settings(self, dialog=None): """ Save QGIS settings related with dialog position and size """ if dialog is None: dialog = self.dlg self.controller.plugin_settings_set_value( dialog.objectName() + "_width", dialog.width()) self.controller.plugin_settings_set_value( dialog.objectName() + "_height", dialog.height()) self.controller.plugin_settings_set_value(dialog.objectName() + "_x", dialog.pos().x() + 8) self.controller.plugin_settings_set_value(dialog.objectName() + "_y", dialog.pos().y() + 31) def open_dialog(self, dlg=None, dlg_name=None, info=True, maximize_button=True, stay_on_top=True): """ Open dialog """ # Check database connection before opening dialog if not self.controller.check_db_connection(): return if dlg is None or type(dlg) is bool: dlg = self.dlg # Manage i18n of the dialog if dlg_name: self.controller.manage_translation(dlg_name, dlg) # Manage stay on top, maximize/minimize button and information button # if info is True maximize flag will be ignored # To enable maximize button you must set info to False flags = Qt.WindowCloseButtonHint if info: flags |= Qt.WindowSystemMenuHint | Qt.WindowContextHelpButtonHint else: if maximize_button: flags |= Qt.WindowMinMaxButtonsHint if stay_on_top: flags |= Qt.WindowStaysOnTopHint dlg.setWindowFlags(flags) # Open dialog if issubclass(type(dlg), GwDialog): dlg.open() elif issubclass(type(dlg), GwMainWindow): dlg.show() else: dlg.show() def close_dialog(self, dlg=None): """ Close dialog """ try: self.save_settings(dlg) dlg.close() map_tool = self.canvas.mapTool() # If selected map tool is from the plugin, set 'Pan' as current one if map_tool.toolName() == '': self.iface.actionPan().trigger() except AttributeError: pass def hide_colums(self, widget, comuns_to_hide): for i in range(0, len(comuns_to_hide)): widget.hideColumn(comuns_to_hide[i]) def set_icon(self, widget, icon): """ Set @icon to selected @widget """ # Get icons folder icons_folder = os.path.join(self.plugin_dir, 'icons') icon_path = os.path.join(icons_folder, str(icon) + ".png") if os.path.exists(icon_path): widget.setIcon(QIcon(icon_path)) else: self.controller.log_info("File not found", parameter=icon_path) def check_expression(self, expr_filter, log_info=False): """ Check if expression filter @expr_filter is valid """ if log_info: self.controller.log_info(expr_filter) expr = QgsExpression(expr_filter) if expr.hasParserError(): message = "Expression Error" self.controller.log_warning(message, parameter=expr_filter) return False, expr return True, expr def set_table_columns(self, dialog, widget, table_name, project_type=None): """ Configuration of tables. Set visibility and width of columns """ widget = utils_giswater.getWidget(dialog, widget) if not widget: return # Set width and alias of visible columns columns_to_delete = [] sql = (f"SELECT columnindex, width, alias, status" f" FROM config_form_tableview" f" WHERE tablename = '{table_name}'") if project_type is not None: sql += f" AND project_type = '{project_type}' " sql += " ORDER BY column_index" rows = self.controller.get_rows(sql, log_info=False) if not rows: return for row in rows: if not row['status']: columns_to_delete.append(row['columnindex'] - 1) else: width = row['width'] if width is not None: widget.setColumnWidth(row['columnindex'] - 1, width) widget.model().setHeaderData(row['columnindex'] - 1, Qt.Horizontal, row['alias']) widget.model().select() # Delete columns for column in columns_to_delete: widget.hideColumn(column) def set_completer_object(self, tablename, widget, field_search): """ Set autocomplete of widget @table_object + "_id" getting id's from selected @table_object """ if not widget: return # Set SQL sql = (f"SELECT DISTINCT({field_search})" f" FROM {tablename}" f" ORDER BY {field_search}") rows = self.controller.get_rows(sql) if rows is None: return for i in range(0, len(rows)): aux = rows[i] rows[i] = aux[0] # Set completer and model: add autocomplete in the widget self.completer = QCompleter() self.completer.setCaseSensitivity(Qt.CaseInsensitive) self.completer.setCompletionMode(0) widget.setCompleter(self.completer) model = QStringListModel() model.setStringList(rows) self.completer.setModel(model) def refresh_map_canvas(self, restore_cursor=False): """ Refresh all layers present in map canvas """ self.canvas.refreshAllLayers() for layer_refresh in self.canvas.layers(): layer_refresh.triggerRepaint() if restore_cursor: self.set_cursor_restore() def set_cursor_restore(self): """ Restore to previous cursors """ QApplication.restoreOverrideCursor() def get_cursor_multiple_selection(self): """ Set cursor for multiple selection """ path_folder = os.path.join(os.path.dirname(__file__), os.pardir) path_cursor = os.path.join(path_folder, 'icons', '201.png') if os.path.exists(path_cursor): cursor = QCursor(QPixmap(path_cursor)) else: cursor = QCursor(Qt.ArrowCursor) return cursor def fill_table(self, qtable, table_name, set_edit_triggers=QTableView.NoEditTriggers, expr_filter=None): """ Fill table @widget filtering query by @workcat_id Set a model with selected filter. Attach that model to selected table @setEditStrategy: 0: OnFieldChange 1: OnRowChange 2: OnManualSubmit """ expr = None if expr_filter: # Check expression (is_valid, expr) = self.check_expression(expr_filter) # @UnusedVariable if not is_valid: return expr # Set a model with selected filter expression if self.schema_name not in table_name: table_name = self.schema_name + "." + table_name # Set model model = QSqlTableModel() model.setTable(table_name) model.setEditStrategy(QSqlTableModel.OnManualSubmit) model.setSort(0, 0) model.select() # When change some field we need to refresh Qtableview and filter by psector_id qtable.setEditTriggers(set_edit_triggers) # Check for errors if model.lastError().isValid(): self.controller.show_warning(model.lastError().text()) # Attach model to table view if expr: qtable.setModel(model) qtable.model().setFilter(expr_filter) else: qtable.setModel(model) return expr def get_feature_by_id(self, layer, id, field_id): features = layer.getFeatures() for feature in features: if feature[field_id] == id: return feature return False def put_combobox(self, qtable, rows, combo_values, field, combo_pos, col_update): """ Set one column of a QtableView as QComboBox with values from database. :param qtable: QTableView to fill :param rows: List of items to set QComboBox (["..", "..."]) :param combo_values: List of items to populate QComboBox (["..", "..."]) :param field: Field to set QComboBox (String) :param combo_pos: Position of the column where we want to put the QComboBox (integer) :param col_update: Column to update into QTableView.Model() (integer) :return: """ self.controller.log_info(str()) for x, row in enumerate(rows): combo = QComboBox() combo.setSizeAdjustPolicy(2) # Populate QComboBox utils_giswater.set_item_data(combo, combo_values, 1) # Set QCombobox to wanted item utils_giswater.set_combo_itemData(combo, str(row[field]), 0) # Get index and put QComboBox into QTableView at index position idx = qtable.model().index(x, combo_pos) qtable.setIndexWidget(idx, combo) combo.currentIndexChanged.connect( partial(self.update_real_field, qtable, combo, x, combo_pos, col_update)) def update_real_field(self, qtable, combo, pos_x, combo_pos, col_update): """ Update values from QComboBox to QTableView :param qtable: QTableView Where update values :param combo: QComboBox from which we will take the value :param pos_x: Position of the row where we want to update value (integer) :param combo_pos: Position of the column where we want to put the QComboBox (integer) :param col_update: Column to update into QTableView.Model() (integer) :return: """ elem = combo.itemData(combo.currentIndex()) i = qtable.model().index(pos_x, combo_pos) qtable.model().setData(i, elem[0]) i = qtable.model().index(pos_x, col_update) qtable.model().setData(i, elem[0]) def create_body(self, form='', feature='', filter_fields='', extras=None): """ Create and return parameters as body to functions""" client = f'$${{"client":{{"device":4, "infoType":1, "lang":"ES"}}, ' form = '"form":{' + form + '}, ' feature = '"feature":{' + feature + '}, ' filter_fields = '"filterFields":{' + filter_fields + '}' page_info = '"pageInfo":{}' data = '"data":{' + filter_fields + ', ' + page_info if extras is not None: data += ', ' + extras data += f'}}}}$$' body = "" + client + form + feature + data return body def set_dates_from_to(self, widget_from, widget_to, table_name, field_from, field_to): sql = ("SELECT MIN(LEAST(" + field_from + ", " + field_to + "))," " MAX(GREATEST(" + field_from + ", " + field_to + "))" " FROM " + table_name + "") row = self.controller.get_row(sql, log_sql=False) current_date = QDate.currentDate() if row: if row[0]: widget_from.setDate(row[0]) else: widget_from.setDate(current_date) if row[1]: widget_to.setDate(row[1]) else: widget_to.setDate(current_date) def remove_selection(self): """ Remove selected features of all layers """ for layer in self.canvas.layers(): if type(layer) is QgsVectorLayer: layer.removeSelection() self.canvas.refresh() for a in self.iface.attributesToolBar().actions(): if a.objectName() == 'mActionDeselectAll': a.trigger() break
class geopunt4QgisDataCatalog(QDialog): def __init__(self, iface): QDialog.__init__(self, None) self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) self.iface = iface # initialize locale locale = QSettings().value("locale/userLocale", "en") if not locale: locale = 'en' else: locale = locale[0:2] localePath = os.path.join(os.path.dirname(__file__), 'i18n', 'geopunt4qgis_{}.qm'.format(locale)) if os.path.exists(localePath): self.translator = QTranslator() self.translator.load(localePath) QCoreApplication.installTranslator(self.translator) self._initGui() def _initGui(self): """setup the user interface""" self.ui = Ui_geopunt4QgisDataCatalogDlg() self.ui.setupUi(self) # get settings self.s = QSettings() self.loadSettings() self.gh = geometryHelper(self.iface) # setup a message bar self.bar = QgsMessageBar() self.bar.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Fixed) self.ui.verticalLayout.addWidget(self.bar) self.ui.buttonBox.addButton(QPushButton("Sluiten"), QDialogButtonBox.RejectRole) for btn in self.ui.buttonBox.buttons(): btn.setAutoDefault(0) # vars self.firstShow = True self.wms = None self.wfs = None self.dl = None self.zoek = '' self.bronnen = None self.model = QStandardItemModel(self) self.proxyModel = QSortFilterProxyModel(self) self.proxyModel.setSourceModel(self.model) self.ui.resultView.setModel(self.proxyModel) self.completer = QCompleter(self) self.completerModel = QStringListModel(self) self.ui.zoekTxt.setCompleter(self.completer) self.completer.setModel(self.completerModel) # eventhandlers self.ui.zoekBtn.clicked.connect(self.onZoekClicked) self.ui.addWMSbtn.clicked.connect(self.addWMS) self.ui.addWFSbtn.clicked.connect(self.addWFS) self.ui.DLbtn.clicked.connect(lambda: self.openUrl(self.dl)) self.ui.resultView.clicked.connect(self.resultViewClicked) self.ui.modelFilterCbx.currentIndexChanged.connect(self.modelFilterCbxIndexChanged) self.ui.filterWgt.setHidden(1) self.ui.buttonBox.helpRequested.connect(self.openHelp) self.finished.connect(self.clean) def loadSettings(self): self.timeout = int(self.s.value("geopunt4qgis/timeout", 15)) if settings().proxyUrl: self.proxy = settings().proxyUrl else: self.proxy = "" self.md = MDReader(self.timeout, self.proxy) def openHelp(self): webbrowser.open_new_tab("http://www.geopunt.be/voor-experts/geopunt-plug-ins/functionaliteiten/catalogus") def _setModel(self, records): self.model.clear() records = sorted(records, key=lambda k: k['title']) for rec in records: title = QStandardItem(rec['title']) # 0 wms = QStandardItem(rec['wms']) # 1 downloadLink = QStandardItem(rec['download']) # 2 id = QStandardItem(rec['uuid']) # 3 abstract = QStandardItem(rec['abstract']) # 4 wfs = QStandardItem(rec['wfs']) # 5 self.model.appendRow([title, wms, downloadLink, id, abstract, wfs]) # overwrite def show(self): QDialog.show(self) self.setWindowModality(0) metadataUrl = "https://metadata.geopunt.be" inet = internet_on(proxyUrl=self.proxy, timeout=self.timeout, testSite= metadataUrl) if not inet: msg = "Kan geen verbing maken met de metadata van Geopunt: {} \nMogelijke is deze site niet bereikbaar, dan zal deze tool ook niet werken.\nProbeer later opnieuw. Indien dit probleem zich blijft voordoen contacteer informatie Vlaanderen.".format(metadataUrl) QMessageBox.warning(self.iface.mainWindow(), "Waarschuwing: kan geen verbinding maken", msg) self.bar.pushMessage( QCoreApplication.translate("geopunt4QgisPoidialog","Waarschuwing"), msg, level=Qgis.Warning, duration=3) return if self.firstShow: self.ui.GDIThemaCbx.addItems([''] + self.md.list_GDI_theme()) self.ui.organisatiesCbx.addItems([''] + self.md.list_organisations()) keywords = sorted(self.md.list_suggestionKeyword()) self.completerModel.setStringList(keywords) self.bronnen = self.md.list_bronnen() self.ui.bronCbx.addItems([''] + [n[1] for n in self.bronnen]) self.ui.typeCbx.addItems([''] + [n[0] for n in self.md.dataTypes]) self.ui.INSPIREannexCbx.addItems([''] + self.md.inspireannex) self.ui.INSPIREserviceCbx.addItems([''] + self.md.inspireServiceTypes) self.ui.INSPIREthemaCbx.addItems([''] + self.md.list_inspire_theme()) self.firstShow = False # eventhandlers def resultViewClicked(self): if self.ui.resultView.selectedIndexes(): row = self.ui.resultView.selectedIndexes()[0].row() title = self.proxyModel.data(self.proxyModel.index(row, 0)) self.wms = self.proxyModel.data(self.proxyModel.index(row, 1)) self.dl = self.proxyModel.data(self.proxyModel.index(row, 2)) self.wfs = self.proxyModel.data(self.proxyModel.index(row, 5)) uuid = self.proxyModel.data(self.proxyModel.index(row, 3)) abstract = self.proxyModel.data(self.proxyModel.index(row, 4)) self.ui.descriptionText.setText( """<h3>%s</h3><div>%s</div><br/><div> <a href='https://metadata.geopunt.be/zoekdienst/apps/tabsearch/index.html?uuid=%s'> Ga naar fiche</a></div>""" % (title, abstract, uuid)) if self.wms: self.ui.addWMSbtn.setEnabled(1) else: self.ui.addWMSbtn.setEnabled(0) if self.wfs: self.ui.addWFSbtn.setEnabled(1) else: self.ui.addWFSbtn.setEnabled(0) if self.dl: self.ui.DLbtn.setEnabled(1) else: self.ui.DLbtn.setEnabled(0) def onZoekClicked(self): self.zoek = self.ui.zoekTxt.currentText() self.search() def modelFilterCbxIndexChanged(self): value = self.ui.modelFilterCbx.currentIndex() if value == 1: self.filterModel(1) elif value == 2: self.filterModel(5) elif value == 3: self.filterModel(2) else: self.filterModel() def filterModel(self, col=None): if col != None: self.proxyModel.setFilterKeyColumn(col) expr = QRegExp("?*", Qt.CaseInsensitive, QRegExp.Wildcard) self.proxyModel.setFilterRegExp(expr) else: self.proxyModel.setFilterRegExp(None) def search(self): try: if self.ui.filterBox.isChecked(): themekey = self.ui.GDIThemaCbx.currentText() orgName = self.ui.organisatiesCbx.currentText() dataTypes = [n[1] for n in self.md.dataTypes if n[0] == self.ui.typeCbx.currentText()] if dataTypes != []: dataType = dataTypes[0] else: dataType = '' siteIds = [n[0] for n in self.bronnen if n[1] == self.ui.bronCbx.currentText()] if siteIds != []: siteId = siteIds[0] else: siteId = '' inspiretheme = self.ui.INSPIREthemaCbx.currentText() inspireannex = self.ui.INSPIREannexCbx.currentText() inspireServiceType = self.ui.INSPIREserviceCbx.currentText() searchResult = MDdata(self.md.searchAll( self.zoek, themekey, orgName, dataType, siteId, inspiretheme, inspireannex, inspireServiceType)) else: searchResult = MDdata(self.md.searchAll(self.zoek)) except: self.bar.pushMessage("Error", str(sys.exc_info()[1]), level=Qgis.Critical, duration=3) return self.ui.countLbl.setText("Aantal gevonden: %s" % searchResult.count) self.ui.descriptionText.setText('') self._setModel(searchResult.records) if searchResult.count == 0: self.bar.pushMessage( QCoreApplication.translate("geopunt4QgisPoidialog", "Waarschuwing "), QCoreApplication.translate("geopunt4QgisPoidialog", "Er werden geen resultaten gevonde voor deze zoekopdracht"), duration=5) def openUrl(self, url): if url: webbrowser.open_new_tab(url.encode("utf-8")) def addWMS(self): if self.wms == None: return crs = self.gh.getGetMapCrs(self.iface).authid() if crs != 'EPSG:31370' or crs != 'EPSG:3857' or crs != 'EPSG:3043': crs = 'EPSG:31370' try: lyrs = getWmsLayerNames(self.wms, self.proxy) except: self.bar.pushMessage("Error", str(sys.exc_info()[1]), level=Qgis.Critical, duration=10) return if len(lyrs) == 0: self.bar.pushMessage("WMS", QCoreApplication.translate("geopunt4QgisDataCatalog", "Kan geen lagen vinden in: %s" % self.wms), level=Qgis.Warning, duration=10) return elif len(lyrs) == 1: layerTitle = lyrs[0][1] else: layerTitle, accept = QInputDialog.getItem(self, "WMS toevoegen", "Kies een laag om toe te voegen", [n[1] for n in lyrs], editable=0) if not accept: return layerName = [n[0] for n in lyrs if n[1] == layerTitle][0] style = [n[2] for n in lyrs if n[1] == layerTitle][0] if not style: style = "" url = self.wms.split('?')[0] if crs != 'EPSG:31370' or crs != 'EPSG:3857': crs = 'EPSG:31370' wmsUrl = "contextualWMSLegend=0&dpiMode=7&url=%s&layers=%s&format=image/png&styles=%s&crs=%s" % ( url, layerName, style, crs) try: rlayer = QgsRasterLayer(wmsUrl, layerTitle, 'wms') if rlayer.isValid(): QgsProject.instance().addMapLayer(rlayer) else: self.bar.pushMessage("Error", QCoreApplication.translate("geopunt4QgisDataCatalog", "Kan WMS niet laden"), level=Qgis.Critical, duration=10) except: self.bar.pushMessage("Error", str(sys.exc_info()[1]), level=Qgis.Critical, duration=10) return def addWFS(self): if self.wfs == None: return try: lyrs = getWFSLayerNames(self.wfs, self.proxy) except: self.bar.pushMessage("Error", str(sys.exc_info()[1]), level=Qgis.Critical, duration=10) return if len(lyrs) == 0: self.bar.pushMessage("WFS", QCoreApplication.translate("geopunt4QgisDataCatalog", "Kan geen lagen vinden in: %s" % self.wfs), level=Qgis.Warning, duration=10) return elif len(lyrs) == 1: layerTitle = lyrs[0][1] else: layerTitle, accept = QInputDialog.getItem(self, "WFS toevoegen", "Kies een laag om toe te voegen", [n[1] for n in lyrs], editable=0) if not accept: return layerName = [n[0] for n in lyrs if n[1] == layerTitle][0] crs = [n[2] for n in lyrs if n[1] == layerTitle][0] url = self.wfs.split('?')[0] wfsUri = makeWFSuri(url, layerName, crs ) try: vlayer = QgsVectorLayer(wfsUri, layerTitle, "WFS") QgsProject.instance().addMapLayer(vlayer) except: self.bar.pushMessage("Error", str(sys.exc_info()[1]), level=Qgis.Critical, duration=10) return def clean(self): self.model.clear() self.wms = None self.wfs = None self.dl = None self.ui.zoekTxt.setCurrentIndex(0) self.ui.descriptionText.setText('') self.ui.countLbl.setText("") self.ui.msgLbl.setText("") self.ui.DLbtn.setEnabled(0) self.ui.addWFSbtn.setEnabled(0) self.ui.addWMSbtn.setEnabled(0) self.ui.modelFilterCbx.setCurrentIndex(0)
class geopunt4QgisAdresDialog(QDialog): def __init__(self, iface): QDialog.__init__(self, None) self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) self.iface = iface # initialize locale locale = QSettings().value("locale/userLocale", "nl") if not locale: locale == 'nl' else: locale = locale[0:2] localePath = os.path.join(os.path.dirname(__file__), 'i18n', 'geopunt4qgis_{}.qm'.format(locale)) if os.path.exists(localePath): self.translator = QTranslator() self.translator.load(localePath) QCoreApplication.installTranslator(self.translator) self._initGui() def _initGui(self): """setup the user interface""" self.ui = Ui_geopunt4Qgis() self.ui.setupUi(self) #get settings self.s = QSettings() self.loadSettings() #setup geometryHelper object self.gh = geometryHelper(self.iface) #create graphicsLayer self.graphicsLayer = [] self.firstShow = True self.completer = QCompleter(self) self.completerModel = QStringListModel(self) self.ui.gemeenteBox.setCompleter(self.completer) self.completer.setModel(self.completerModel) self.completer.setCaseSensitivity(False) #setup a message bar self.bar = QgsMessageBar() self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) self.ui.verticalLayout.addWidget(self.bar) self.ui.buttonBox.addButton(QPushButton("Sluiten"), QDialogButtonBox.RejectRole) for btn in self.ui.buttonBox.buttons(): btn.setAutoDefault(0) #event handlers if self.adresSearchOnEnter: self.ui.zoekText.returnPressed.connect(self.onZoekActivated) else: self.ui.zoekText.textEdited.connect(self.onZoekActivated) self.ui.gemeenteBox.currentIndexChanged.connect(self.onZoekActivated) self.ui.resultLijst.itemDoubleClicked.connect(self.onItemActivated) self.ui.resultLijst.itemClicked.connect(self.onItemClick) self.ui.ZoomKnop.clicked.connect(self.onZoomKnopClick) self.ui.Add2mapKnop.clicked.connect(self.onAdd2mapKnopClick) self.ui.buttonBox.helpRequested.connect(self.openHelp) self.finished.connect(self.clean) def loadSettings(self): self.saveToFile = int(self.s.value("geopunt4qgis/adresSavetoFile", 1)) layerName = self.s.value("geopunt4qgis/adreslayerText", "") if layerName: self.layerName = layerName self.adresSearchOnEnter = int( self.s.value("geopunt4qgis/adresSearchOnEnter", 0)) self.timeout = int(self.s.value("geopunt4qgis/timeout", 15)) if settings().proxyUrl: self.proxy = settings().proxyUrl else: self.proxy = "" self.startDir = self.s.value("geopunt4qgis/startDir", os.path.expanduser("~")) self.gp = Adres(self.timeout, self.proxy) # overwrite def show(self): QDialog.show(self) self.setWindowModality(0) arUrl = "http://loc.api.geopunt.be/" inet = internet_on(proxyUrl=self.proxy, timeout=self.timeout, testSite=arUrl) if not inet: msg = "Kan geen verbing maken met de site van Geopunt: {} \nMogelijke is deze site niet bereikbaar, dan zal deze tool ook niet werken.\nProbeer later opnieuw. Indien dit probleem zich blijft voordoen contacteer informatie Vlaanderen.".format( arUrl) QMessageBox.warning(self.iface.mainWindow(), "Waarschuwing: kan geen verbinding maken", msg) self.bar.pushMessage(QCoreApplication.translate( "geopunt4QgisPoidialog", "Waarschuwing"), msg, level=Qgis.Warning, duration=3) return if self.firstShow: self.am = basisregisters.adresMatch(self.timeout, self.proxy) gemeenteNamen = [n["Naam"] for n in self.am.gemeenten()] self.ui.gemeenteBox.addItems(gemeenteNamen) self.completerModel.setStringList(gemeenteNamen) self.ui.gemeenteBox.setEditText( QCoreApplication.translate("geopunt4QgisAdresDialog", "gemeente")) self.ui.gemeenteBox.setStyleSheet('QComboBox {color: #808080}') self.ui.gemeenteBox.setFocus() self.firstShow = False def openHelp(self): webbrowser.open_new_tab( "http://www.geopunt.be/voor-experts/geopunt-plug-ins/functionaliteiten/zoek-een-adres" ) def onZoekActivated(self): self._clearGraphicsLayer() self.bar.clearWidgets() gemeente = self.ui.gemeenteBox.currentText() if gemeente != QCoreApplication.translate("geopunt4QgisAdresDialog", "gemeente"): self.ui.gemeenteBox.setStyleSheet('QComboBox {color: #000000}') txt = self.ui.zoekText.text() + ", " + gemeente suggesties = self.gp.fetchSuggestion(txt, 25) self.ui.resultLijst.clear() if type(suggesties) is list and len(suggesties) != 0: self.ui.resultLijst.addItems(suggesties) if len(suggesties) == 1: self.ui.resultLijst.setCurrentRow(0) def onItemActivated(self, item): txt = item.text() self._zoomLoc(txt) def onItemClick(self, item): txt = item.text() streetNr = txt.split(",")[:-1] self.ui.zoekText.setText(",".join(streetNr)) def onZoomKnopClick(self): item = self.ui.resultLijst.currentItem() if item: self._zoomLoc(item.text()) def onAdd2mapKnopClick(self): item = self.ui.resultLijst.currentItem() if item: self._addToMap(item.text()) def _clearGraphicsLayer(self): for graphic in self.graphicsLayer: self.iface.mapCanvas().scene().removeItem(graphic) self.graphicsLayer = [] def _zoomLoc(self, txt): self._clearGraphicsLayer() locations = self.gp.fetchLocation(txt) if type(locations) is list and len(locations): loc = locations[0] LowerLeftX = loc['BoundingBox']['LowerLeft']['X_Lambert72'] LowerLeftY = loc['BoundingBox']['LowerLeft']['Y_Lambert72'] UpperRightX = loc['BoundingBox']['UpperRight']['X_Lambert72'] UpperRightY = loc['BoundingBox']['UpperRight']['Y_Lambert72'] self.gh.zoomtoRec(QgsPointXY(LowerLeftX, LowerLeftY), QgsPointXY(UpperRightX, UpperRightY), 31370) xlb, ylb = loc["Location"]["X_Lambert72"], loc["Location"][ "Y_Lambert72"] x, y = self.gh.prjPtToMapCrs(QgsPointXY(xlb, ylb), 31370) m = QgsVertexMarker(self.iface.mapCanvas()) self.graphicsLayer.append(m) m.setCenter(QgsPointXY(x, y)) m.setColor(QColor(255, 255, 0)) m.setIconSize(1) m.setIconType(QgsVertexMarker.ICON_BOX) m.setPenWidth(9) elif type(locations) is str: self.bar.pushMessage(QCoreApplication.translate( "geopunt4QgisAdresDialog", "Waarschuwing"), locations, level=Qgis.Warning, duration=3) else: self.bar.pushMessage("Error", QCoreApplication.translate( "geopunt4QgisAdresDialog", "onbekende fout"), level=Qgis.Critical, duration=3) def _addToMap(self, txt): if not self.layernameValid(): return locations = self.gp.fetchLocation(txt) if type(locations) is list and len(locations): loc = locations[0] x, y = loc["Location"]["X_Lambert72"], loc["Location"][ "Y_Lambert72"] adres = loc["FormattedAddress"] LocationType = loc["LocationType"] pt = self.gh.prjPtToMapCrs(QgsPointXY(x, y), 31370) self.gh.save_adres_point(pt, adres, typeAddress=LocationType, layername=self.layerName, saveToFile=self.saveToFile, sender=self, startFolder=os.path.join( self.startDir, self.layerName)) def layernameValid(self): if not hasattr(self, 'layerName'): layerName, accept = QInputDialog.getText( None, QCoreApplication.translate("geopunt4Qgis", 'Laag toevoegen'), QCoreApplication.translate("geopunt4Qgis", 'Geef een naam voor de laag op:')) if accept == False: return False else: self.layerName = layerName return True def clean(self): self.bar.clearWidgets() self.ui.resultLijst.clear() self.ui.zoekText.setText("") self.ui.gemeenteBox.setEditText( QCoreApplication.translate("geopunt4QgisAdresDialog", "gemeente")) self.ui.gemeenteBox.setStyleSheet('QComboBox {color: #808080}') self._clearGraphicsLayer()
class TmParentManage(TmParentAction, object): def __init__(self, iface, settings, controller, plugin_dir): """ Class to keep common functions of classes 'ManageDocument', 'ManageElement' and 'ManageVisit' of toolbar 'edit' """ super(TmParentManage, self).__init__(iface, settings, controller, plugin_dir) self.x = "" self.y = "" self.canvas = self.iface.mapCanvas() self.plan_om = None self.previous_map_tool = None self.autocommit = True self.lazy_widget = None self.workcat_id_end = None def reset_lists(self): """ Reset list of selected records """ self.ids = [] self.list_ids = {} self.list_ids['node'] = [] def reset_layers(self): """ Reset list of layers """ self.layers = {} self.layers['node'] = [] self.visible_layers = [] def remove_selection(self): """ Remove all previous selections """ try: for layer in self.layers['node']: if layer in self.visible_layers: self.controller.set_layer_visible(layer, False) for layer in self.layers['node']: if layer in self.visible_layers: self.controller.set_layer_visible(layer, True) layer.removeSelection() except: pass self.canvas.refresh() self.canvas.setMapTool(self.previous_map_tool) def add_point(self): """ Create the appropriate map tool and connect to the corresponding signal """ self.emit_point = QgsMapToolEmitPoint(self.canvas) self.previous_map_tool = self.canvas.mapTool() self.canvas.setMapTool(self.emit_point) self.emit_point.canvasClicked.connect(partial(self.get_xy)) def get_xy(self, point): """ Get coordinates of selected point """ self.x = point.x() self.y = point.y() message = "Geometry has been added!" self.controller.show_info(message) self.emit_point.canvasClicked.disconnect() def set_completer_feature_id(self, widget, geom_type, viewname): """ Set autocomplete of widget 'feature_id'. Getting id's from selected @viewname """ # Adding auto-completion to a QLineEdit self.completer = QCompleter() self.completer.setCaseSensitivity(Qt.CaseInsensitive) widget.setCompleter(self.completer) model = QStringListModel() sql = (f"SELECT {geom_type}_id" f" FROM {viewname}") row = self.controller.get_rows(sql, commit=self.autocommit) if row: for i in range(0, len(row)): aux = row[i] row[i] = str(aux[0]) model.setStringList(row) self.completer.setModel(model) def set_table_model(self, qtable, geom_type, expr_filter): """ Sets a TableModel to @widget_name attached to @table_name and filter @expr_filter """ expr = None if expr_filter: # Check expression (is_valid, expr) = self.check_expression(expr_filter) # @UnusedVariable if not is_valid: return expr # Set a model with selected filter expression table_name = "v_edit_" + geom_type if self.schema_name not in table_name: table_name = self.schema_name + "." + table_name # Set the model model = QSqlTableModel() model.setTable(table_name) model.setEditStrategy(QSqlTableModel.OnManualSubmit) model.select() if model.lastError().isValid(): self.controller.show_warning(model.lastError().text()) return expr # Attach model to selected widget if type(qtable) is QTableView: widget = qtable else: message = "Table_object is not a table name or QTableView" self.controller.log_info(message) return expr if expr_filter: widget.setModel(model) widget.model().setFilter(expr_filter) widget.model().select() else: widget.setModel(None) return expr def apply_lazy_init(self, widget): """ Apply the init function related to the model. It's necessary a lazy init because model is changed everytime is loaded """ if self.lazy_widget is None: return if widget != self.lazy_widget: return self.lazy_init_function(self.lazy_widget) def lazy_configuration(self, widget, init_function): """ set the init_function where all necessary events are set. This is necessary to allow a lazy setup of the events because set_table_events can create a table with a None model loosing any event connection """ # TODO: create a dictionary with key:widged.objectName value:initFuction # to allow multiple lazy initialization self.lazy_widget = widget self.lazy_init_function = init_function def select_features_by_ids(self, geom_type, expr): """ Select features of layers of group @geom_type applying @expr """ # Build a list of feature id's and select them for layer in self.layers[geom_type]: if expr is None: layer.removeSelection() else: it = layer.getFeatures(QgsFeatureRequest(expr)) id_list = [i.id() for i in it] if len(id_list) > 0: layer.selectByIds(id_list) else: layer.removeSelection() def delete_records(self, dialog, table_object): """ Delete selected elements of the table """ self.disconnect_signal_selection_changed() if type(table_object) is str: widget_name = f"tbl_{table_object}_x_{self.geom_type}" widget = utils_giswater.getWidget(dialog, widget_name) if not widget: message = "Widget not found" self.controller.show_warning(message, parameter=widget_name) return elif type(table_object) is QTableView: widget = table_object else: message = "Table_object is not a table name or QTableView" self.controller.log_info(message) return # Get selected rows selected_list = widget.selectionModel().selectedRows() if len(selected_list) == 0: message = "Any record selected" self.controller.show_info_box(message) return self.ids = self.list_ids[self.geom_type] field_id = self.geom_type + "_id" del_id = [] inf_text = "" for i in range(0, len(selected_list)): row = selected_list[i].row() id_feature = widget.model().record(row).value(field_id) inf_text += f"{id_feature}, " del_id.append(id_feature) inf_text = inf_text[:-2] message = "Are you sure you want to delete these records?" title = "Delete records" answer = self.controller.ask_question(message, title, inf_text) if answer: for el in del_id: self.ids.remove(el) else: return expr_filter = None expr = None if len(self.ids) > 0: # Set expression filter with features in the list expr_filter = f'"{field_id}" IN (' for i in range(len(self.ids)): expr_filter += f"'{self.ids[i]}', " expr_filter = expr_filter[:-2] + ")" # Check expression (is_valid, expr) = self.check_expression(expr_filter) # @UnusedVariable if not is_valid: return # Update model of the widget with selected expr_filter self.reload_table(table_object, self.geom_type, expr_filter) self.apply_lazy_init(table_object) # Select features with previous filter # Build a list of feature id's and select them self.select_features_by_ids(self.geom_type, expr) # Update list self.list_ids[self.geom_type] = self.ids self.connect_signal_selection_changed(table_object) def selection_init(self, table_object): """ Set canvas map tool to an instance of class 'MultipleSelection' """ current_visible_layers = self.get_visible_layers() for layer in current_visible_layers: if layer not in self.visible_layers: self.visible_layers.append(layer) self.controller.log_info(str(self.visible_layers)) multiple_selection = TmMultipleSelection(self.iface, self.controller, self.layers[self.geom_type], parent_manage=self, table_object=table_object) self.disconnect_signal_selection_changed() self.previous_map_tool = self.canvas.mapTool() self.canvas.setMapTool(multiple_selection) self.connect_signal_selection_changed(table_object) cursor = self.get_cursor_multiple_selection() self.canvas.setCursor(cursor) def selection_changed(self, qtable, geom_type): """ Slot function for signal 'canvas.selectionChanged' """ self.disconnect_signal_selection_changed() field_id = geom_type + "_id" self.ids = [] # Iterate over all layers of the group for layer in self.layers[self.geom_type]: if layer.selectedFeatureCount( ) > 0 and self.controller.is_layer_visible(layer): # Get selected features of the layer features = layer.selectedFeatures() for feature in features: # Append 'feature_id' into the list selected_id = feature.attribute(field_id) if selected_id not in self.ids: self.ids.append(selected_id) if geom_type == 'node': self.list_ids['node'] = self.ids expr_filter = None if len(self.ids) > 0: # Set 'expr_filter' with features that are in the list expr_filter = f'"{field_id}" IN (' for i in range(len(self.ids)): expr_filter += f"'{self.ids[i]}', " expr_filter = expr_filter[:-2] + ")" # Check expression (is_valid, expr) = self.check_expression(expr_filter) # @UnusedVariable if not is_valid: return self.select_features_by_ids(geom_type, expr) # Reload contents of table 'tbl_@table_object_x_@geom_type' self.reload_table(qtable, self.geom_type, expr_filter) self.apply_lazy_init(qtable) # Remove selection in generic 'v_edit' layers #self.remove_selection(False) self.connect_signal_selection_changed(qtable) def insert_feature(self, widget, table_object): """ Select feature with entered id. Set a model with selected filter. Attach that model to selected table """ self.disconnect_signal_selection_changed() # Clear list of ids self.ids = [] field_id = self.geom_type + "_id" feature_id = widget.text() if feature_id == 'null': message = "You need to enter a feature id" self.controller.show_info_box(message) return # Iterate over all layers of the group for layer in self.layers[self.geom_type]: if layer.selectedFeatureCount() > 0: # Get selected features of the layer features = layer.selectedFeatures() for feature in features: # Append 'feature_id' into the list selected_id = feature.attribute(field_id) self.ids.append(selected_id) if feature_id not in self.ids: # If feature id doesn't exist in list -> add self.ids.append(str(feature_id)) # Set expression filter with features in the list expr_filter = f'"{field_id}" IN (' for i in range(len(self.ids)): expr_filter += f"'{self.ids[i]}', " expr_filter = expr_filter[:-2] + ")" # Check expression (is_valid, expr) = self.check_expression(expr_filter) if not is_valid: return # Select features with previous filter # Build a list of feature id's and select them for layer in self.layers[self.geom_type]: it = layer.getFeatures(QgsFeatureRequest(expr)) id_list = [i.id() for i in it] if len(id_list) > 0: layer.selectByIds(id_list) # Reload contents of table 'tbl_???_x_@geom_type' self.reload_table(table_object, self.geom_type, expr_filter) self.apply_lazy_init(table_object) # Update list self.list_ids[self.geom_type] = self.ids self.connect_signal_selection_changed(table_object) def disconnect_snapping(self): """ Select 'Pan' as current map tool and disconnect snapping """ try: self.iface.actionPan().trigger() self.canvas.xyCoordinates.disconnect() if self.emit_point: self.emit_point.canvasClicked.disconnect() except: pass def connect_signal_selection_changed(self, table_object): """ Connect signal selectionChanged """ try: self.canvas.selectionChanged.connect( partial(self.selection_changed, table_object, self.geom_type)) except Exception: pass def disconnect_signal_selection_changed(self): """ Disconnect signal selectionChanged """ try: self.canvas.selectionChanged.disconnect() except Exception: pass def fill_widget_with_fields(self, dialog, data_object, field_names): """ Fill the Widget with value get from data_object limited to the list of field_names. """ for field_name in field_names: value = getattr(data_object, field_name) if not hasattr(dialog, field_name): continue widget = getattr(dialog, field_name) if type(widget) in [QDateEdit, QDateTimeEdit]: widget.setDateTime(value if value else QDate.currentDate()) if type(widget) in [QLineEdit, QTextEdit]: if value: widget.setText(value) else: widget.clear() if type(widget) in [QComboBox]: if not value: widget.setCurrentIndex(0) continue # look the value in item text index = widget.findText(str(value)) if index >= 0: widget.setCurrentIndex(index) continue # look the value in itemData index = widget.findData(value) if index >= 0: widget.setCurrentIndex(index) continue def reload_table(self, qtable, geom_type, expr_filter): """ Reload @widget with contents of @tablename applying selected @expr_filter """ if type(qtable) is QTableView: widget = qtable else: message = "Table_object is not a table name or QTableView" self.controller.log_info(message) return None expr = self.set_table_model(widget, geom_type, expr_filter) return expr def get_visible_layers(self, return_as_list=True): """ Return list or string as {...} with all visible layer in TOC """ visible_layer = [] layers = self.controller.get_layers() if return_as_list: for layer in layers: if self.controller.is_layer_visible(layer): visible_layer.append(layer) return visible_layer for layer in layers: if self.controller.is_layer_visible(layer): visible_layer += f'"{layer.name()}", ' visible_layer = visible_layer[:-2] + "}" return visible_layer
class ReplaceFeatureMapTool(ParentMapTool): """ Button 44: User select one feature. Execute SQL function: 'gw_fct_feature_replace' """ def __init__(self, iface, settings, action, index_action): """ Class constructor """ super(ReplaceFeatureMapTool, self).__init__(iface, settings, action, index_action) self.current_date = QDate.currentDate().toString('yyyy-MM-dd') self.project_type = None self.geom_type = None self.geom_view = None self.cat_table = None self.feature_type_ws = None self.feature_type_ud = None def manage_dates(self, date_value): """ Manage dates """ date_result = None try: date_result = str(date_value) date_result = date_result.replace("-", "/") date_result = datetime.strptime(date_result, '%Y/%m/%d') except Exception as e: self.controller.log_warning(str(e)) finally: return date_result def init_replace_feature_form(self, feature): # Create the dialog and signals self.dlg_replace = FeatureReplace() self.load_settings(self.dlg_replace) sql = "SELECT id FROM cat_work ORDER BY id" rows = self.controller.get_rows(sql) if rows: utils_giswater.fillComboBox(self.dlg_replace, self.dlg_replace.workcat_id_end, rows) utils_giswater.set_autocompleter(self.dlg_replace.workcat_id_end) row = self.controller.get_config('edit_workcat_vdefault') if row: edit_workcat_vdefault = self.dlg_replace.workcat_id_end.findText( row[0]) self.dlg_replace.workcat_id_end.setCurrentIndex( edit_workcat_vdefault) row = self.controller.get_config('edit_enddate_vdefault') if row: self.enddate_aux = self.manage_dates(row[0]).date() else: work_id = utils_giswater.getWidgetText( self.dlg_replace, self.dlg_replace.workcat_id_end) sql = (f"SELECT builtdate FROM cat_work " f"WHERE id = '{work_id}'") row = self.controller.get_row(sql) current_date = self.manage_dates(self.current_date) if row and row[0]: builtdate = self.manage_dates(row[0]) if builtdate != 'null' and builtdate: self.enddate_aux = builtdate.date() else: self.enddate_aux = current_date.date() else: self.enddate_aux = current_date.date() self.dlg_replace.enddate.setDate(self.enddate_aux) # Get feature type from current feature feature_type = None if self.project_type == 'ws': feature_type = feature.attribute(self.feature_type_ws) elif self.project_type == 'ud': feature_type = feature.attribute(self.feature_type_ud) if self.geom_type in ('node', 'connec'): sql = f"SELECT DISTINCT(id) FROM {self.cat_table} ORDER BY id" rows = self.controller.get_rows(sql) utils_giswater.fillComboBox(self.dlg_replace, "featurecat_id", rows, allow_nulls=False) elif self.geom_type in ('gully'): sql = f"SELECT DISTINCT(id) FROM cat_grate ORDER BY id" rows = self.controller.get_rows(sql) utils_giswater.fillComboBox(self.dlg_replace, "featurecat_id", rows, allow_nulls=False) self.dlg_replace.feature_type.setText(feature_type) self.dlg_replace.feature_type_new.currentIndexChanged.connect( self.edit_change_elem_type_get_value) self.dlg_replace.btn_catalog.clicked.connect(partial( self.open_catalog)) self.dlg_replace.workcat_id_end.currentIndexChanged.connect( self.update_date) # Fill 1st combo boxes-new system node type sql = ( f"SELECT DISTINCT(id) FROM cat_feature WHERE lower(feature_type) = '{self.geom_type}' " f"AND active is True " f"ORDER BY id") rows = self.controller.get_rows(sql) utils_giswater.fillComboBox(self.dlg_replace, "feature_type_new", rows) self.dlg_replace.btn_new_workcat.clicked.connect( partial(self.new_workcat)) self.dlg_replace.btn_accept.clicked.connect( partial(self.get_values, self.dlg_replace)) self.dlg_replace.btn_cancel.clicked.connect( partial(self.close_dialog, self.dlg_replace)) self.dlg_replace.rejected.connect(self.cancel_map_tool) # Open dialog self.open_dialog(self.dlg_replace, maximize_button=False) def open_catalog(self): # Get feature_type feature_type = utils_giswater.getWidgetText( self.dlg_replace, self.dlg_replace.feature_type_new) if feature_type is 'null': msg = "New feature type is null. Please, select a valid value." self.controller.show_info_box(msg, "Info") return sql = f"SELECT lower(feature_type) FROM cat_feature WHERE id = '{feature_type}'" row = self.controller.get_row(sql) self.catalog = ApiCatalog(self.iface, self.settings, self.controller, self.plugin_dir) self.catalog.api_catalog(self.dlg_replace, 'featurecat_id', row[0], feature_type) def update_date(self): row = self.controller.get_config('edit_enddate_vdefault') if row: self.enddate_aux = self.manage_dates(row[0]).date() else: work_id = utils_giswater.getWidgetText( self.dlg_replace, self.dlg_replace.workcat_id_end) sql = (f"SELECT builtdate FROM cat_work " f"WHERE id = '{work_id}'") row = self.controller.get_row(sql) current_date = self.manage_dates(self.current_date) if row and row[0]: builtdate = self.manage_dates(row[0]) if builtdate != 'null' and builtdate: self.enddate_aux = builtdate.date() else: self.enddate_aux = current_date.date() else: self.enddate_aux = current_date.date() self.dlg_replace.enddate.setDate(self.enddate_aux) def new_workcat(self): self.dlg_new_workcat = InfoWorkcatUi() self.load_settings(self.dlg_new_workcat) utils_giswater.setCalendarDate(self.dlg_new_workcat, self.dlg_new_workcat.builtdate, None, True) table_object = "cat_work" self.set_completer_object(table_object, self.dlg_new_workcat.cat_work_id, 'id') # Set signals self.dlg_new_workcat.btn_accept.clicked.connect( partial(self.manage_new_workcat_accept, table_object)) self.dlg_new_workcat.btn_cancel.clicked.connect( partial(self.close_dialog, self.dlg_new_workcat)) # Open dialog self.open_dialog(self.dlg_new_workcat, dlg_name='info_workcat') def manage_new_workcat_accept(self, table_object): """ Insert table 'cat_work'. Add cat_work """ # Get values from dialog values = "" fields = "" cat_work_id = utils_giswater.getWidgetText( self.dlg_new_workcat, self.dlg_new_workcat.cat_work_id) if cat_work_id != "null": fields += 'id, ' values += ("'" + str(cat_work_id) + "', ") descript = utils_giswater.getWidgetText(self.dlg_new_workcat, "descript") if descript != "null": fields += 'descript, ' values += ("'" + str(descript) + "', ") link = utils_giswater.getWidgetText(self.dlg_new_workcat, "link") if link != "null": fields += 'link, ' values += ("'" + str(link) + "', ") workid_key_1 = utils_giswater.getWidgetText(self.dlg_new_workcat, "workid_key_1") if workid_key_1 != "null": fields += 'workid_key1, ' values += ("'" + str(workid_key_1) + "', ") workid_key_2 = utils_giswater.getWidgetText(self.dlg_new_workcat, "workid_key_2") if workid_key_2 != "null": fields += 'workid_key2, ' values += ("'" + str(workid_key_2) + "', ") builtdate = self.dlg_new_workcat.builtdate.dateTime().toString( 'yyyy-MM-dd') if builtdate != "null": fields += 'builtdate, ' values += ("'" + str(builtdate) + "', ") if values != "": fields = fields[:-2] values = values[:-2] if cat_work_id == 'null': msg = "Work_id field is empty" self.controller.show_info_box(msg, "Warning") else: # Check if this element already exists sql = (f"SELECT DISTINCT(id) " f"FROM {table_object} " f"WHERE id = '{cat_work_id}'") row = self.controller.get_row(sql, log_info=False) if row is None: sql = f"INSERT INTO cat_work ({fields}) VALUES ({values})" self.controller.execute_sql(sql, log_sql=True) sql = "SELECT id FROM cat_work ORDER BY id" rows = self.controller.get_rows(sql) if rows: utils_giswater.fillComboBox( self.dlg_replace, self.dlg_replace.workcat_id_end, rows) current_index = self.dlg_replace.workcat_id_end.findText( str(cat_work_id)) self.dlg_replace.workcat_id_end.setCurrentIndex( current_index) self.close_dialog(self.dlg_new_workcat) else: msg = "This Workcat is already exist" self.controller.show_info_box(msg, "Warning") def set_completer_object(self, tablename, widget, field_id): """ Set autocomplete of widget @table_object + "_id" getting id's from selected @table_object """ if not widget: return sql = (f"SELECT DISTINCT({field_id}) " f"FROM {tablename} " f"ORDER BY {field_id}") rows = self.controller.get_rows(sql) if rows is None: return for i in range(0, len(rows)): aux = rows[i] rows[i] = str(aux[0]) # Set completer and model: add autocomplete in the widget self.completer = QCompleter() self.completer.setCaseSensitivity(Qt.CaseInsensitive) widget.setCompleter(self.completer) model = QStringListModel() model.setStringList(rows) self.completer.setModel(model) def get_values(self, dialog): self.workcat_id_end_aux = utils_giswater.getWidgetText( dialog, dialog.workcat_id_end) self.enddate_aux = dialog.enddate.date().toString('yyyy-MM-dd') # Check null values if self.workcat_id_end_aux in (None, 'null'): message = "Mandatory field is missing. Please, set a value" self.controller.show_warning(message, parameter='Workcat_id') return feature_type_new = utils_giswater.getWidgetText( dialog, dialog.feature_type_new) featurecat_id = utils_giswater.getWidgetText(dialog, dialog.featurecat_id) # Ask question before executing message = "Are you sure you want to replace selected feature with a new one?" answer = self.controller.ask_question(message, "Replace feature") if answer: # Get function input parameters feature = f'"type":"{self.geom_type}"' extras = f'"old_feature_id":"{self.feature_id}"' extras += f', "workcat_id_end":"{self.workcat_id_end_aux}"' extras += f', "enddate":"{self.enddate_aux}"' extras += f', "keep_elements":"{utils_giswater.isChecked(dialog, "keep_elements")}"' body = self.create_body(feature=feature, extras=extras) # Execute SQL function and show result to the user function_name = "gw_fct_feature_replace" sql = f"SELECT {function_name}({body})::text" row = self.controller.get_row(sql, log_sql=True) if not row: message = "Error replacing feature" self.controller.show_warning(message) self.deactivate() self.set_action_pan() self.close_dialog(dialog, set_action_pan=False) return complet_result = [ json.loads(row[0], object_pairs_hook=OrderedDict) ] message = "Feature replaced successfully" self.controller.show_info(message) # Force user to manage with state = 1 features current_user = self.controller.get_project_user() sql = (f"DELETE FROM selector_state " f"WHERE state_id = 1 AND cur_user = '******';" f"\nINSERT INTO selector_state (state_id, cur_user) " f"VALUES (1, '{current_user}');") self.controller.execute_sql(sql) if feature_type_new != "null" and featurecat_id != "null": # Get id of new generated feature sql = (f"SELECT {self.geom_type}_id " f"FROM {self.geom_view} " f"ORDER BY {self.geom_type}_id::int4 DESC LIMIT 1") row = self.controller.get_row(sql) if row: if self.geom_type == 'connec': field_cat_id = "connecat_id" else: field_cat_id = self.geom_type + "cat_id" if self.geom_type != 'gully': sql = (f"UPDATE {self.geom_view} " f"SET {field_cat_id} = '{featurecat_id}' " f"WHERE {self.geom_type}_id = '{row[0]}'") self.controller.execute_sql(sql, log_sql=True) if self.project_type == 'ud': sql = ( f"UPDATE {self.geom_view} " f"SET {self.geom_type}_type = '{feature_type_new}' " f"WHERE {self.geom_type}_id = '{row[0]}'") self.controller.execute_sql(sql, log_sql=True) message = "Values has been updated" self.controller.show_info(message) # Fill tab 'Info log' if complet_result and complet_result[0]['status'] == "Accepted": self.populate_info_text(self.dlg_replace, complet_result[0]['body']['data']) # Refresh canvas self.refresh_map_canvas() self.controller.set_layer_index('v_edit_arc') self.controller.set_layer_index('v_edit_connec') self.controller.set_layer_index('v_edit_gully') self.controller.set_layer_index('v_edit_node') self.refresh_legend() # Deactivate map tool self.deactivate() self.set_action_pan() # Disable ok button at the end of process self.dlg_replace.btn_accept.setEnabled(False) """ QgsMapTools inherited event functions """ def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: self.cancel_map_tool() return def canvasMoveEvent(self, event): # Hide marker and clicked point self.vertex_marker.hide() event_point = self.snapper_manager.get_event_point(event) # Snapping layers 'v_edit_' result = self.snapper_manager.snap_to_background_layers(event_point) if self.snapper_manager.result_is_valid(): layer = self.snapper_manager.get_snapped_layer(result) tablename = self.controller.get_layer_source_table_name(layer) if tablename and 'v_edit' in tablename: self.snapper_manager.add_marker(result, self.vertex_marker) def canvasReleaseEvent(self, event): if event.button() == Qt.RightButton: self.cancel_map_tool() return event_point = self.snapper_manager.get_event_point(event) # Snapping result = self.snapper_manager.snap_to_background_layers(event_point) if not self.snapper_manager.result_is_valid(): return # Get snapped feature snapped_feat = self.snapper_manager.get_snapped_feature(result) if snapped_feat: layer = self.snapper_manager.get_snapped_layer(result) tablename = self.controller.get_layer_source_table_name(layer) if tablename and 'v_edit' in tablename: if tablename == 'v_edit_node': self.geom_type = 'node' elif tablename == 'v_edit_connec': self.geom_type = 'connec' elif tablename == 'v_edit_gully': self.geom_type = 'gully' self.geom_view = tablename self.cat_table = 'cat_' + self.geom_type self.feature_type_ws = self.geom_type + 'type_id' self.feature_type_ud = self.geom_type + '_type' self.feature_id = snapped_feat.attribute(self.geom_type + '_id') self.init_replace_feature_form(snapped_feat) def activate(self): # Set active and current layer self.layer_node = self.controller.get_layer_by_tablename("v_edit_node") self.iface.setActiveLayer(self.layer_node) self.current_layer = self.layer_node # Check button self.action().setChecked(True) # Set main snapping layers self.snapper_manager.set_snapping_layers() # Store user snapping configuration self.snapper_manager.store_snapping_options() # Disable snapping self.snapper_manager.enable_snapping() # Set snapping to 'node', 'connec' and 'gully' self.snapper_manager.snap_to_node() self.snapper_manager.snap_to_connec_gully() self.snapper_manager.set_snapping_mode() # Change cursor self.canvas.setCursor(self.cursor) self.project_type = self.controller.get_project_type() # Show help message when action is activated if self.show_help: message = "Select the feature by clicking on it and it will be replaced" self.controller.show_info(message) def deactivate(self): ParentMapTool.deactivate(self) def edit_change_elem_type_get_value(self, index): """ Just select item to 'real' combo 'featurecat_id' (that is hidden) """ if index == -1: return # Get selected value from 2nd combobox feature_type_new = utils_giswater.getWidgetText( self.dlg_replace, "feature_type_new") # When value is selected, enabled 3rd combo box if feature_type_new == 'null': return if self.project_type == 'ws': # Fill 3rd combo_box-catalog_id utils_giswater.setWidgetEnabled(self.dlg_replace, self.dlg_replace.featurecat_id, True) sql = (f"SELECT DISTINCT(id) " f"FROM {self.cat_table} " f"WHERE {self.feature_type_ws} = '{feature_type_new}'") rows = self.controller.get_rows(sql) utils_giswater.fillComboBox(self.dlg_replace, self.dlg_replace.featurecat_id, rows)
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)
class Go2Epa(ApiParent): def __init__(self, iface, settings, controller, plugin_dir): """ Class to control toolbar 'go2epa' """ ApiParent.__init__(self, iface, settings, controller, plugin_dir) self.g2epa_opt = Go2EpaOptions(iface, settings, controller, plugin_dir) self.iterations = 0 def set_project_type(self, project_type): self.project_type = project_type def go2epa(self): """ Button 23: Open form to set INP, RPT and project """ # Show form in docker? self.controller.init_docker('qgis_form_docker') # Create dialog self.dlg_go2epa = Go2EpaUI() self.load_settings(self.dlg_go2epa) self.load_user_values() if self.project_type in 'ws': self.dlg_go2epa.chk_export_subcatch.setVisible(False) # Set signals self.set_signals() if self.project_type == 'ws': self.dlg_go2epa.btn_hs_ds.setText("Dscenario Selector") tableleft = "cat_dscenario" tableright = "selector_inp_demand" field_id_left = "dscenario_id" field_id_right = "dscenario_id" self.dlg_go2epa.btn_hs_ds.clicked.connect( partial(self.sector_selection, tableleft, tableright, field_id_left, field_id_right, aql="")) elif self.project_type == 'ud': self.dlg_go2epa.btn_hs_ds.setText("Hydrology selector") self.dlg_go2epa.btn_hs_ds.clicked.connect( self.ud_hydrology_selector) # Check OS and enable/disable checkbox execute EPA software if sys.platform != "win32": utils_giswater.setChecked(self.dlg_go2epa, self.dlg_go2epa.chk_exec, False) self.dlg_go2epa.chk_exec.setEnabled(False) self.dlg_go2epa.chk_exec.setText( 'Execute EPA software (Runs only on Windows)') self.set_completer_result(self.dlg_go2epa.txt_result_name, 'v_ui_rpt_cat_result', 'result_id') if self.controller.dlg_docker: self.controller.manage_translation('go2epa', self.dlg_go2epa) self.controller.dock_dialog(self.dlg_go2epa) self.dlg_go2epa.btn_cancel.clicked.disconnect() self.dlg_go2epa.btn_cancel.clicked.connect( self.controller.close_docker) else: self.open_dialog(self.dlg_go2epa, dlg_name='go2epa') def set_signals(self): self.dlg_go2epa.txt_result_name.textChanged.connect( partial(self.check_result_id)) self.dlg_go2epa.btn_file_inp.clicked.connect( self.go2epa_select_file_inp) self.dlg_go2epa.btn_file_rpt.clicked.connect( self.go2epa_select_file_rpt) self.dlg_go2epa.btn_accept.clicked.connect(self.go2epa_accept) self.dlg_go2epa.btn_cancel.clicked.connect( partial(self.close_dialog, self.dlg_go2epa)) self.dlg_go2epa.rejected.connect( partial(self.close_dialog, self.dlg_go2epa)) self.dlg_go2epa.btn_options.clicked.connect(self.epa_options) def check_inp_chk(self, file_inp): if file_inp is None: msg = "Select valid INP file" self.controller.show_warning(msg, parameter=str(file_inp)) return False def check_rpt(self): file_inp = utils_giswater.getWidgetText(self.dlg_go2epa, self.dlg_go2epa.txt_file_inp) file_rpt = utils_giswater.getWidgetText(self.dlg_go2epa, self.dlg_go2epa.txt_file_rpt) # Control execute epa software if utils_giswater.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_exec): if self.check_inp_chk(file_inp) is False: return False if file_rpt is None: msg = "Select valid RPT file" self.controller.show_warning(msg, parameter=str(file_rpt)) return False if not utils_giswater.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_export): if not os.path.exists(file_inp): msg = "File INP not found" self.controller.show_warning(msg, parameter=str(file_rpt)) return False def check_fields(self): file_inp = utils_giswater.getWidgetText(self.dlg_go2epa, self.dlg_go2epa.txt_file_inp) file_rpt = utils_giswater.getWidgetText(self.dlg_go2epa, self.dlg_go2epa.txt_file_rpt) result_name = utils_giswater.getWidgetText( self.dlg_go2epa, self.dlg_go2epa.txt_result_name, False, False) # Check if at least one process is selected export_checked = utils_giswater.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_export) exec_checked = utils_giswater.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_exec) import_result_checked = utils_giswater.isChecked( self.dlg_go2epa, self.dlg_go2epa.chk_import_result) if not export_checked and not exec_checked and not import_result_checked: msg = "You need to select at least one process" self.controller.show_info_box(msg, title="Go2Epa") return False # Control export INP if utils_giswater.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_export): if self.check_inp_chk(file_inp) is False: return False # Control execute epa software if self.check_rpt() is False: return False # Control import result if utils_giswater.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_import_result): if file_rpt is None: msg = "Select valid RPT file" self.controller.show_warning(msg, parameter=str(file_rpt)) return False if not utils_giswater.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_exec): if not os.path.exists(file_rpt): msg = "File RPT not found" self.controller.show_warning(msg, parameter=str(file_rpt)) return False else: if self.check_rpt() is False: return False # Control result name if result_name == '': self.dlg_go2epa.txt_result_name.setStyleSheet( "border: 1px solid red") msg = "This parameter is mandatory. Please, set a value" self.controller.show_details(msg, title="Rpt fail", inf_text=None) return False sql = (f"SELECT result_id FROM rpt_cat_result " f"WHERE result_id = '{result_name}' LIMIT 1") row = self.controller.get_row(sql) if row: msg = "Result name already exists, do you want overwrite?" answer = self.controller.ask_question(msg, title="Alert") if not answer: return False return True def load_user_values(self): """ Load QGIS settings related with file_manager """ cur_user = self.controller.get_current_user() self.dlg_go2epa.txt_result_name.setMaxLength(16) self.result_name = self.controller.plugin_settings_value( 'go2epa_RESULT_NAME' + cur_user) self.dlg_go2epa.txt_result_name.setText(self.result_name) self.file_inp = self.controller.plugin_settings_value( 'go2epa_FILE_INP' + cur_user) self.dlg_go2epa.txt_file_inp.setText(self.file_inp) self.file_rpt = self.controller.plugin_settings_value( 'go2epa_FILE_RPT' + cur_user) self.dlg_go2epa.txt_file_rpt.setText(self.file_rpt) value = self.controller.plugin_settings_value( 'go2epa_chk_NETWORK_GEOM' + cur_user) if str(value) == 'true': utils_giswater.setChecked(self.dlg_go2epa, self.dlg_go2epa.chk_only_check, True) value = self.controller.plugin_settings_value('go2epa_chk_INP' + cur_user) if str(value) == 'true': utils_giswater.setChecked(self.dlg_go2epa, self.dlg_go2epa.chk_export, True) value = self.controller.plugin_settings_value('go2epa_chk_UD' + cur_user) if str(value) == 'true': utils_giswater.setChecked(self.dlg_go2epa, self.dlg_go2epa.chk_export_subcatch, True) value = self.controller.plugin_settings_value('go2epa_chk_EPA' + cur_user) if str(value) == 'true': utils_giswater.setChecked(self.dlg_go2epa, self.dlg_go2epa.chk_exec, True) value = self.controller.plugin_settings_value('go2epa_chk_RPT' + cur_user) if str(value) == 'true': utils_giswater.setChecked(self.dlg_go2epa, self.dlg_go2epa.chk_import_result, True) def save_user_values(self): """ Save QGIS settings related with file_manager """ cur_user = self.controller.get_current_user() self.controller.plugin_settings_set_value( 'go2epa_RESULT_NAME' + cur_user, utils_giswater.getWidgetText(self.dlg_go2epa, 'txt_result_name', return_string_null=False)) self.controller.plugin_settings_set_value( 'go2epa_FILE_INP' + cur_user, utils_giswater.getWidgetText(self.dlg_go2epa, 'txt_file_inp', return_string_null=False)) self.controller.plugin_settings_set_value( 'go2epa_FILE_RPT' + cur_user, utils_giswater.getWidgetText(self.dlg_go2epa, 'txt_file_rpt', return_string_null=False)) self.controller.plugin_settings_set_value( 'go2epa_chk_NETWORK_GEOM' + cur_user, utils_giswater.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_only_check)) self.controller.plugin_settings_set_value( 'go2epa_chk_INP' + cur_user, utils_giswater.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_export)) self.controller.plugin_settings_set_value( 'go2epa_chk_UD' + cur_user, utils_giswater.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_export_subcatch)) self.controller.plugin_settings_set_value( 'go2epa_chk_EPA' + cur_user, utils_giswater.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_exec)) self.controller.plugin_settings_set_value( 'go2epa_chk_RPT' + cur_user, utils_giswater.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_import_result)) def sector_selection(self, tableleft, tableright, field_id_left, field_id_right, aql=""): """ Load the tables in the selection form """ dlg_psector_sel = Multirow_selector('dscenario') self.load_settings(dlg_psector_sel) dlg_psector_sel.btn_ok.clicked.connect(dlg_psector_sel.close) if tableleft == 'cat_dscenario': dlg_psector_sel.setWindowTitle(" Dscenario selector") utils_giswater.setWidgetText( dlg_psector_sel, dlg_psector_sel.lbl_filter, self.controller.tr('Filter by: Dscenario name', context_name='labels')) utils_giswater.setWidgetText( dlg_psector_sel, dlg_psector_sel.lbl_unselected, self.controller.tr('Unselected dscenarios', context_name='labels')) utils_giswater.setWidgetText( dlg_psector_sel, dlg_psector_sel.lbl_selected, self.controller.tr('Selected dscenarios', context_name='labels')) self.multi_row_selector(dlg_psector_sel, tableleft, tableright, field_id_left, field_id_right, aql=aql) self.open_dialog(dlg_psector_sel) def epa_options(self): """ Open dialog api_epa_options.ui.ui """ self.g2epa_opt.go2epa_options() return def ud_hydrology_selector(self): """ Dialog hydrology_selector.ui """ self.dlg_hydrology_selector = HydrologySelector() self.load_settings(self.dlg_hydrology_selector) self.dlg_hydrology_selector.btn_accept.clicked.connect( self.save_hydrology) self.dlg_hydrology_selector.hydrology.currentIndexChanged.connect( self.update_labels) self.dlg_hydrology_selector.txt_name.textChanged.connect( partial(self.filter_cbx_by_text, "cat_hydrology", self.dlg_hydrology_selector.txt_name, self.dlg_hydrology_selector.hydrology)) sql = "SELECT DISTINCT(name), hydrology_id FROM cat_hydrology ORDER BY name" rows = self.controller.get_rows(sql) if not rows: message = "Any data found in table" self.controller.show_warning(message, parameter='cat_hydrology') return False utils_giswater.set_item_data(self.dlg_hydrology_selector.hydrology, rows) sql = ( "SELECT DISTINCT(t1.name) FROM cat_hydrology AS t1 " "INNER JOIN selector_inp_hydrology AS t2 ON t1.hydrology_id = t2.hydrology_id " "WHERE t2.cur_user = current_user") row = self.controller.get_row(sql) if row: utils_giswater.setWidgetText(self.dlg_hydrology_selector, self.dlg_hydrology_selector.hydrology, row[0]) else: utils_giswater.setWidgetText(self.dlg_hydrology_selector, self.dlg_hydrology_selector.hydrology, 0) self.update_labels() self.open_dialog(self.dlg_hydrology_selector) def save_hydrology(self): hydrology_id = utils_giswater.get_item_data( self.dlg_hydrology_selector, self.dlg_hydrology_selector.hydrology, 1) sql = ("SELECT cur_user FROM selector_inp_hydrology " "WHERE cur_user = current_user") row = self.controller.get_row(sql) if row: sql = (f"UPDATE selector_inp_hydrology " f"SET hydrology_id = {hydrology_id} " f"WHERE cur_user = current_user") else: sql = ( f"INSERT INTO selector_inp_hydrology (hydrology_id, cur_user) " f"VALUES('{hydrology_id}', current_user)") self.controller.execute_sql(sql) message = "Values has been update" self.controller.show_info(message) self.close_dialog(self.dlg_hydrology_selector) def update_labels(self): """ Show text in labels from SELECT """ sql = ( f"SELECT infiltration, text FROM cat_hydrology" f" WHERE name = '{self.dlg_hydrology_selector.hydrology.currentText()}'" ) row = self.controller.get_row(sql) if row is not None: utils_giswater.setText(self.dlg_hydrology_selector, self.dlg_hydrology_selector.infiltration, row[0]) utils_giswater.setText(self.dlg_hydrology_selector, self.dlg_hydrology_selector.descript, row[1]) def filter_cbx_by_text(self, tablename, widgettxt, widgetcbx): sql = (f"SELECT DISTINCT(name), hydrology_id FROM {tablename}" f" WHERE name LIKE '%{widgettxt.text()}%'" f" ORDER BY name ") rows = self.controller.get_rows(sql) if not rows: message = "Check the table 'cat_hydrology' " self.controller.show_warning(message) return False utils_giswater.set_item_data(widgetcbx, rows) self.update_labels() def go2epa_select_file_inp(self): """ Select INP file """ self.file_inp = utils_giswater.getWidgetText( self.dlg_go2epa, self.dlg_go2epa.txt_file_inp) # Set default value if necessary if self.file_inp is None or self.file_inp == '': self.file_inp = self.plugin_dir # Get directory of that file folder_path = os.path.dirname(self.file_inp) if not os.path.exists(folder_path): folder_path = os.path.dirname(__file__) os.chdir(folder_path) message = self.controller.tr("Select INP file") widget_is_checked = utils_giswater.isChecked( self.dlg_go2epa, self.dlg_go2epa.chk_export) if widget_is_checked: self.file_inp, filter_ = QFileDialog.getSaveFileName( None, message, "", '*.inp') else: self.file_inp, filter_ = QFileDialog.getOpenFileName( None, message, "", '*.inp') utils_giswater.setWidgetText(self.dlg_go2epa, self.dlg_go2epa.txt_file_inp, self.file_inp) def go2epa_select_file_rpt(self): """ Select RPT file """ # Set default value if necessary if self.file_rpt is None or self.file_rpt == '': self.file_rpt = self.plugin_dir # Get directory of that file folder_path = os.path.dirname(self.file_rpt) if not os.path.exists(folder_path): folder_path = os.path.dirname(__file__) os.chdir(folder_path) message = self.controller.tr("Select RPT file") widget_is_checked = utils_giswater.isChecked( self.dlg_go2epa, self.dlg_go2epa.chk_export) if widget_is_checked: self.file_rpt, filter_ = QFileDialog.getSaveFileName( None, message, "", '*.rpt') else: self.file_rpt, filter_ = QFileDialog.getOpenFileName( None, message, "", '*.rpt') utils_giswater.setWidgetText(self.dlg_go2epa, self.dlg_go2epa.txt_file_rpt, self.file_rpt) def go2epa_accept(self): """ Save INP, RPT and result name into GSW file """ # Save user values self.save_user_values() self.dlg_go2epa.txt_infolog.clear() self.dlg_go2epa.txt_file_rpt.setStyleSheet(None) status = self.check_fields() if status is False: return # Get widgets values self.result_name = utils_giswater.getWidgetText( self.dlg_go2epa, self.dlg_go2epa.txt_result_name, False, False) self.net_geom = utils_giswater.isChecked( self.dlg_go2epa, self.dlg_go2epa.chk_only_check) self.export_inp = utils_giswater.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_export) self.export_subcatch = utils_giswater.isChecked( self.dlg_go2epa, self.dlg_go2epa.chk_export_subcatch) self.file_inp = utils_giswater.getWidgetText( self.dlg_go2epa, self.dlg_go2epa.txt_file_inp) self.exec_epa = utils_giswater.isChecked(self.dlg_go2epa, self.dlg_go2epa.chk_exec) self.file_rpt = utils_giswater.getWidgetText( self.dlg_go2epa, self.dlg_go2epa.txt_file_rpt) self.import_result = utils_giswater.isChecked( self.dlg_go2epa, self.dlg_go2epa.chk_import_result) # Check for sector selector if self.export_inp: sql = "SELECT sector_id FROM selector_sector LIMIT 1" row = self.controller.get_row(sql) if row is None: msg = "You need to select some sector" self.controller.show_info_box(msg) return # Set background task 'Go2Epa' description = f"Go2Epa" self.task_go2epa = TaskGo2Epa(description, self.controller, self) QgsApplication.taskManager().addTask(self.task_go2epa) QgsApplication.taskManager().triggerTask(self.task_go2epa) def set_completer_result(self, widget, viewname, field_name): """ Set autocomplete of widget 'feature_id' getting id's from selected @viewname """ result_name = utils_giswater.getWidgetText( self.dlg_go2epa, self.dlg_go2epa.txt_result_name) # Adding auto-completion to a QLineEdit self.completer = QCompleter() self.completer.setCaseSensitivity(Qt.CaseInsensitive) widget.setCompleter(self.completer) model = QStringListModel() sql = f"SELECT {field_name} FROM {viewname}" rows = self.controller.get_rows(sql) if rows: for i in range(0, len(rows)): aux = rows[i] rows[i] = str(aux[0]) model.setStringList(rows) self.completer.setModel(model) if result_name in rows: self.dlg_go2epa.chk_only_check.setEnabled(True) def check_result_id(self): """ Check if selected @result_id already exists """ result_id = utils_giswater.getWidgetText( self.dlg_go2epa, self.dlg_go2epa.txt_result_name) sql = (f"SELECT result_id FROM v_ui_rpt_cat_result" f" WHERE result_id = '{result_id}'") row = self.controller.get_row(sql, log_info=False) if not row: self.dlg_go2epa.chk_only_check.setChecked(False) self.dlg_go2epa.chk_only_check.setEnabled(False) else: self.dlg_go2epa.chk_only_check.setEnabled(True) def check_data(self): """ Check data executing function 'gw_fct_pg2epa' """ sql = f"SELECT gw_fct_pg2epa('{self.project_name}', 'True');" row = self.controller.get_row(sql) if not row: return False if row[0] > 0: message = ("It is not possible to execute the epa model." "There are errors on your project. Review it!") sql_details = ( f"SELECT table_id, column_id, error_message" f" FROM audit_check_data" f" WHERE fid = 114 AND result_id = '{self.project_name}'") inf_text = "For more details execute query:\n" + sql_details title = "Execute epa model" self.controller.show_info_box(message, title, inf_text, parameter=row[0]) self.csv_audit_check_data("audit_check_data", "audit_check_data_log.csv") return False else: message = "Data is ok. You can try to generate the INP file" title = "Execute epa model" self.controller.show_info_box(message, title) return True def csv_audit_check_data(self, tablename, filename): # Get columns name in order of the table rows = self.controller.get_columns_list(tablename) if not rows: message = "Table not found" self.controller.show_warning(message, parameter=tablename) return columns = [] for i in range(0, len(rows)): column_name = rows[i] columns.append(str(column_name[0])) sql = (f"SELECT table_id, column_id, error_message" f" FROM {tablename}" f" WHERE fid = 114 AND result_id = '{self.project_name}'") rows = self.controller.get_rows(sql) if not rows: message = "No records found with selected 'result_id'" self.controller.show_warning(message, parameter=self.project_name) return all_rows = [] all_rows.append(columns) for i in rows: all_rows.append(i) path = self.controller.get_log_folder() + filename try: with open(path, "w") as output: writer = csv.writer(output, lineterminator='\n') writer.writerows(all_rows) message = "File created successfully" self.controller.show_info(message, parameter=path) except IOError: message = "File cannot be created. Check if it is already opened" self.controller.show_warning(message, parameter=path) def save_file_parameters(self): """ Save INP, RPT and result name into GSW file """ self.gsw_settings.setValue('FILE_INP', self.file_inp) self.gsw_settings.setValue('FILE_RPT', self.file_rpt) self.gsw_settings.setValue('RESULT_NAME', self.result_name) def go2epa_result_selector(self): """ Button 29: Epa result selector """ # Create the dialog and signals self.dlg_go2epa_result = Go2EpaSelectorUi() self.load_settings(self.dlg_go2epa_result) if self.project_type == 'ud': utils_giswater.remove_tab_by_tabName( self.dlg_go2epa_result.tabWidget, "tab_time") if self.project_type == 'ws': utils_giswater.remove_tab_by_tabName( self.dlg_go2epa_result.tabWidget, "tab_datetime") self.dlg_go2epa_result.btn_accept.clicked.connect( self.result_selector_accept) self.dlg_go2epa_result.btn_cancel.clicked.connect( partial(self.close_dialog, self.dlg_go2epa_result)) self.dlg_go2epa_result.rejected.connect( partial(self.close_dialog, self.dlg_go2epa_result)) # Set values from widgets of type QComboBox sql = ("SELECT DISTINCT(result_id), result_id " "FROM v_ui_rpt_cat_result ORDER BY result_id") rows = self.controller.get_rows(sql) utils_giswater.set_item_data( self.dlg_go2epa_result.rpt_selector_result_id, rows) rows = self.controller.get_rows(sql, add_empty_row=True) utils_giswater.set_item_data( self.dlg_go2epa_result.rpt_selector_compare_id, rows) if self.project_type == 'ws': sql = ("SELECT DISTINCT time, time FROM rpt_arc " "WHERE result_id ILIKE '%%' ORDER BY time") rows = self.controller.get_rows(sql, add_empty_row=True) utils_giswater.set_item_data( self.dlg_go2epa_result.cmb_time_to_show, rows) utils_giswater.set_item_data( self.dlg_go2epa_result.cmb_time_to_compare, rows) self.dlg_go2epa_result.rpt_selector_result_id.currentIndexChanged.connect( partial(self.populate_time, self.dlg_go2epa_result.rpt_selector_result_id, self.dlg_go2epa_result.cmb_time_to_show)) self.dlg_go2epa_result.rpt_selector_compare_id.currentIndexChanged.connect( partial(self.populate_time, self.dlg_go2epa_result.rpt_selector_compare_id, self.dlg_go2epa_result.cmb_time_to_compare)) elif self.project_type == 'ud': # Populate GroupBox Selector date result_id = utils_giswater.get_item_data( self.dlg_go2epa_result, self.dlg_go2epa_result.rpt_selector_result_id, 0) sql = (f"SELECT DISTINCT(resultdate), resultdate FROM rpt_arc " f"WHERE result_id = '{result_id}' " f"ORDER BY resultdate") rows = self.controller.get_rows(sql) if rows is not None: utils_giswater.set_item_data( self.dlg_go2epa_result.cmb_sel_date, rows) selector_date = utils_giswater.get_item_data( self.dlg_go2epa_result, self.dlg_go2epa_result.cmb_sel_date, 0) sql = (f"SELECT DISTINCT(resulttime), resulttime FROM rpt_arc " f"WHERE result_id = '{result_id}' " f"AND resultdate = '{selector_date}' " f"ORDER BY resulttime") rows = self.controller.get_rows(sql, add_empty_row=True) utils_giswater.set_item_data( self.dlg_go2epa_result.cmb_sel_time, rows) self.dlg_go2epa_result.rpt_selector_result_id.currentIndexChanged.connect( partial(self.populate_date_time, self.dlg_go2epa_result.cmb_sel_date)) self.dlg_go2epa_result.cmb_sel_date.currentIndexChanged.connect( partial(self.populate_time, self.dlg_go2epa_result.rpt_selector_result_id, self.dlg_go2epa_result.cmb_sel_time)) # Populate GroupBox Selector compare result_id_to_comp = utils_giswater.get_item_data( self.dlg_go2epa_result, self.dlg_go2epa_result.rpt_selector_result_id, 0) sql = (f"SELECT DISTINCT(resultdate), resultdate FROM rpt_arc " f"WHERE result_id = '{result_id_to_comp}' " f"ORDER BY resultdate ") rows = self.controller.get_rows(sql) if rows is not None: utils_giswater.set_item_data( self.dlg_go2epa_result.cmb_com_date, rows) selector_cmp_date = utils_giswater.get_item_data( self.dlg_go2epa_result, self.dlg_go2epa_result.cmb_com_date, 0) sql = (f"SELECT DISTINCT(resulttime), resulttime FROM rpt_arc " f"WHERE result_id = '{result_id_to_comp}' " f"AND resultdate = '{selector_cmp_date}' " f"ORDER BY resulttime") rows = self.controller.get_rows(sql, add_empty_row=True) utils_giswater.set_item_data( self.dlg_go2epa_result.cmb_com_time, rows) self.dlg_go2epa_result.rpt_selector_compare_id.currentIndexChanged.connect( partial(self.populate_date_time, self.dlg_go2epa_result.cmb_com_date)) self.dlg_go2epa_result.cmb_com_date.currentIndexChanged.connect( partial(self.populate_time, self.dlg_go2epa_result.rpt_selector_compare_id, self.dlg_go2epa_result.cmb_com_time)) # Get current data from tables 'rpt_selector_result' and 'rpt_selector_compare' sql = "SELECT result_id FROM selector_rpt_main" row = self.controller.get_row(sql) if row: utils_giswater.set_combo_itemData( self.dlg_go2epa_result.rpt_selector_result_id, row["result_id"], 0) sql = "SELECT result_id FROM selector_rpt_compare" row = self.controller.get_row(sql) if row: utils_giswater.set_combo_itemData( self.dlg_go2epa_result.rpt_selector_compare_id, row["result_id"], 0) # Open the dialog self.open_dialog(self.dlg_go2epa_result, dlg_name='go2epa_selector') def populate_date_time(self, combo_date): result_id = utils_giswater.get_item_data( self.dlg_go2epa_result, self.dlg_go2epa_result.rpt_selector_result_id, 0) sql = (f"SELECT DISTINCT(resultdate), resultdate FROM rpt_arc " f"WHERE result_id = '{result_id}' " f"ORDER BY resultdate") rows = self.controller.get_rows(sql) utils_giswater.set_item_data(combo_date, rows) def populate_time(self, combo_result, combo_time): """ Populate combo times """ result_id = utils_giswater.get_item_data(self.dlg_go2epa_result, combo_result) if self.project_type == 'ws': field = "time" else: field = "resulttime" sql = (f"SELECT DISTINCT {field}, {field} " f"FROM rpt_arc " f"WHERE result_id ILIKE '{result_id}' " f"ORDER BY {field};") rows = self.controller.get_rows(sql, add_empty_row=True) utils_giswater.set_item_data(combo_time, rows) def result_selector_accept(self): """ Update current values to the table """ # Set project user user = self.controller.get_project_user() # Delete previous values sql = ( f"DELETE FROM selector_rpt_main WHERE cur_user = '******';\n" f"DELETE FROM selector_rpt_compare WHERE cur_user = '******';\n") sql += ( f"DELETE FROM selector_rpt_main_tstep WHERE cur_user = '******';\n" f"DELETE FROM selector_rpt_compare_tstep WHERE cur_user = '******';\n" ) self.controller.execute_sql(sql) # Get new values from widgets of type QComboBox rpt_selector_result_id = utils_giswater.get_item_data( self.dlg_go2epa_result, self.dlg_go2epa_result.rpt_selector_result_id) rpt_selector_compare_id = utils_giswater.get_item_data( self.dlg_go2epa_result, self.dlg_go2epa_result.rpt_selector_compare_id) if rpt_selector_result_id not in (None, -1, ''): sql = (f"INSERT INTO selector_rpt_main (result_id, cur_user)" f" VALUES ('{rpt_selector_result_id}', '{user}');\n") self.controller.execute_sql(sql) if rpt_selector_compare_id not in (None, -1, ''): sql = (f"INSERT INTO selector_rpt_compare (result_id, cur_user)" f" VALUES ('{rpt_selector_compare_id}', '{user}');\n") self.controller.execute_sql(sql) if self.project_type == 'ws': time_to_show = utils_giswater.get_item_data( self.dlg_go2epa_result, self.dlg_go2epa_result.cmb_time_to_show) time_to_compare = utils_giswater.get_item_data( self.dlg_go2epa_result, self.dlg_go2epa_result.cmb_time_to_compare) if time_to_show not in (None, -1, ''): sql = ( f"INSERT INTO selector_rpt_main_tstep (timestep, cur_user)" f" VALUES ('{time_to_show}', '{user}');\n") self.controller.execute_sql(sql) if time_to_compare not in (None, -1, ''): sql = ( f"INSERT INTO selector_rpt_compare_tstep (timestep, cur_user)" f" VALUES ('{time_to_compare}', '{user}');\n") self.controller.execute_sql(sql) elif self.project_type == 'ud': date_to_show = utils_giswater.get_item_data( self.dlg_go2epa_result, self.dlg_go2epa_result.cmb_sel_date) time_to_show = utils_giswater.get_item_data( self.dlg_go2epa_result, self.dlg_go2epa_result.cmb_sel_time) date_to_compare = utils_giswater.get_item_data( self.dlg_go2epa_result, self.dlg_go2epa_result.cmb_com_date) time_to_compare = utils_giswater.get_item_data( self.dlg_go2epa_result, self.dlg_go2epa_result.cmb_com_time) if date_to_show not in (None, -1, ''): sql = ( f"INSERT INTO selector_rpt_main_tstep (resultdate, resulttime, cur_user)" f" VALUES ('{date_to_show}', '{time_to_show}', '{user}');\n" ) self.controller.execute_sql(sql) if date_to_compare not in (None, -1, ''): sql = ( f"INSERT INTO selector_rpt_compare_tstep (resultdate, resulttime, cur_user)" f" VALUES ('{date_to_compare}', '{time_to_compare}', '{user}');\n" ) self.controller.execute_sql(sql) # Show message to user message = "Values has been updated" self.controller.show_info(message) self.close_dialog(self.dlg_go2epa_result) def go2epa_options_get_data(self, tablename, dialog): """ Get data from selected table """ sql = f"SELECT * FROM {tablename}" row = self.controller.get_row(sql) if not row: message = "Any data found in table" self.controller.show_warning(message, parameter=tablename) return None # Iterate over all columns and populate its corresponding widget columns = [] for i in range(0, len(row)): column_name = self.dao.get_column_name(i) widget = dialog.findChild(QWidget, column_name) widget_type = utils_giswater.getWidgetType(dialog, widget) if row[column_name] is not None: if widget_type is QCheckBox: utils_giswater.setChecked(dialog, widget, row[column_name]) elif widget_type is QComboBox: utils_giswater.set_combo_itemData(widget, row[column_name], 0) elif widget_type is QDateEdit: dateaux = row[column_name].replace('/', '-') date = QDate.fromString(dateaux, 'dd-MM-yyyy') utils_giswater.setCalendarDate(dialog, widget, date) elif widget_type is QTimeEdit: timeparts = str(row[column_name]).split(':') if len(timeparts) < 3: timeparts.append("0") days = int(timeparts[0]) / 24 hours = int(timeparts[0]) % 24 minuts = int(timeparts[1]) seconds = int(timeparts[2]) time = QTime(hours, minuts, seconds) utils_giswater.setTimeEdit(dialog, widget, time) utils_giswater.setText(dialog, column_name + "_day", days) else: utils_giswater.setWidgetText(dialog, widget, str(row[column_name])) columns.append(column_name) return columns def go2epa_result_manager(self): """ Button 25: Epa result manager """ # Create the dialog self.dlg_manager = EpaManager() self.load_settings(self.dlg_manager) # Manage widgets reg_exp = QRegExp("^[A-Za-z0-9_]{1,16}$") self.dlg_manager.txt_result_id.setValidator(QRegExpValidator(reg_exp)) # Fill combo box and table view self.fill_combo_result_id() self.dlg_manager.tbl_rpt_cat_result.setSelectionBehavior( QAbstractItemView.SelectRows) self.fill_table(self.dlg_manager.tbl_rpt_cat_result, 'v_ui_rpt_cat_result') self.set_table_columns(self.dlg_manager, self.dlg_manager.tbl_rpt_cat_result, 'v_ui_rpt_cat_result') # Set signals self.dlg_manager.btn_delete.clicked.connect( partial(self.multi_rows_delete, self.dlg_manager.tbl_rpt_cat_result, 'rpt_cat_result', 'result_id')) self.dlg_manager.btn_close.clicked.connect( partial(self.close_dialog, self.dlg_manager)) self.dlg_manager.rejected.connect( partial(self.close_dialog, self.dlg_manager)) self.dlg_manager.txt_result_id.editTextChanged.connect( self.filter_by_result_id) # Open form self.open_dialog(self.dlg_manager, dlg_name='go2epa_manager') def fill_combo_result_id(self): sql = "SELECT result_id FROM v_ui_rpt_cat_result ORDER BY result_id" rows = self.controller.get_rows(sql) utils_giswater.fillComboBox(self.dlg_manager, self.dlg_manager.txt_result_id, rows) def filter_by_result_id(self): table = self.dlg_manager.tbl_rpt_cat_result widget_txt = self.dlg_manager.txt_result_id tablename = 'v_ui_rpt_cat_result' result_id = utils_giswater.getWidgetText(self.dlg_manager, widget_txt) if result_id != 'null': expr = f" result_id ILIKE '%{result_id}%'" # Refresh model with selected filter table.model().setFilter(expr) table.model().select() else: self.fill_table(table, tablename) def update_sql(self): usql = UpdateSQL(self.iface, self.settings, self.controller, self.plugin_dir) usql.init_sql()
class GwGo2EpaButton(GwAction): """ Button 23: Go2epa """ def __init__(self, icon_path, action_name, text, toolbar, action_group): super().__init__(icon_path, action_name, text, toolbar, action_group) self.project_type = global_vars.project_type self.epa_options_list = [] def clicked_event(self): self._open_go2epa() def check_result_id(self): """ Check if selected @result_id already exists """ self.dlg_go2epa.txt_result_name.setStyleSheet(None) # region private functions def _open_go2epa(self): self._go2epa() def _go2epa(self): """ Button 23: Open form to set INP, RPT and project """ # Show form in docker? tools_gw.init_docker('qgis_form_docker') # Create dialog self.dlg_go2epa = GwGo2EpaUI() tools_gw.load_settings(self.dlg_go2epa) self._load_user_values() if self.project_type in 'ws': self.dlg_go2epa.chk_export_subcatch.setVisible(False) # Set signals self._set_signals() self.dlg_go2epa.btn_cancel.setEnabled(False) # Disable tab log tools_gw.disable_tab_log(self.dlg_go2epa) # Set shortcut keys self.dlg_go2epa.key_escape.connect(partial(tools_gw.close_docker)) self.dlg_go2epa.btn_hs_ds.clicked.connect( partial(self._sector_selection)) # Check OS and enable/disable checkbox execute EPA software if sys.platform != "win32": tools_qt.set_checked(self.dlg_go2epa, self.dlg_go2epa.chk_exec, False) self.dlg_go2epa.chk_exec.setEnabled(False) self.dlg_go2epa.chk_exec.setText( 'Execute EPA software (Runs only on Windows)') self._set_completer_result(self.dlg_go2epa.txt_result_name, 'v_ui_rpt_cat_result', 'result_id') self.check_result_id() if global_vars.session_vars['dialog_docker']: tools_qt.manage_translation('go2epa', self.dlg_go2epa) tools_gw.docker_dialog(self.dlg_go2epa) self.dlg_go2epa.btn_close.clicked.disconnect() self.dlg_go2epa.btn_close.clicked.connect( partial(tools_gw.close_docker, option_name='position')) else: tools_gw.open_dialog(self.dlg_go2epa, dlg_name='go2epa') def _set_signals(self): self.dlg_go2epa.btn_cancel.clicked.connect(self._cancel_task) self.dlg_go2epa.txt_result_name.textChanged.connect( partial(self.check_result_id)) self.dlg_go2epa.btn_file_inp.clicked.connect( self._go2epa_select_file_inp) self.dlg_go2epa.btn_file_rpt.clicked.connect( self._go2epa_select_file_rpt) self.dlg_go2epa.btn_accept.clicked.connect(self._go2epa_accept) self.dlg_go2epa.btn_close.clicked.connect( partial(tools_gw.close_dialog, self.dlg_go2epa)) self.dlg_go2epa.rejected.connect( partial(tools_gw.close_dialog, self.dlg_go2epa)) self.dlg_go2epa.btn_options.clicked.connect(self._go2epa_options) self.dlg_go2epa.mainTab.currentChanged.connect( partial(self._manage_btn_accept)) def _manage_btn_accept(self, index): """ Disable btn_accept when on tab info log and/or if go2epa_task is active :param index: tab index (passed by signal) """ if index == 1: self.dlg_go2epa.btn_accept.setEnabled(False) else: # Disable if task is active, enabled otherwise if hasattr(self, 'go2epa_task') and self.go2epa_task is not None: try: if self.go2epa_task.isActive(): self.dlg_go2epa.btn_accept.setEnabled(False) return except RuntimeError: pass self.dlg_go2epa.btn_accept.setEnabled(True) def _check_inp_chk(self, file_inp): if file_inp is None: msg = "Select valid INP file" tools_qgis.show_warning(msg, parameter=str(file_inp)) return False return True def _check_rpt(self): file_inp = tools_qt.get_text(self.dlg_go2epa, self.dlg_go2epa.txt_file_inp) file_rpt = tools_qt.get_text(self.dlg_go2epa, self.dlg_go2epa.txt_file_rpt) # Control execute epa software if tools_qt.is_checked(self.dlg_go2epa, self.dlg_go2epa.chk_exec): if not self._check_inp_chk(file_inp): return False if file_rpt is None: msg = "Select valid RPT file" tools_qgis.show_warning(msg, parameter=str(file_rpt)) return False if not tools_qt.is_checked(self.dlg_go2epa, self.dlg_go2epa.chk_export): if not os.path.exists(file_inp): msg = "File INP not found" tools_qgis.show_warning(msg, parameter=str(file_inp)) return False return True def _check_fields(self): file_inp = tools_qt.get_text(self.dlg_go2epa, self.dlg_go2epa.txt_file_inp) file_rpt = tools_qt.get_text(self.dlg_go2epa, self.dlg_go2epa.txt_file_rpt) result_name = tools_qt.get_text(self.dlg_go2epa, self.dlg_go2epa.txt_result_name, False, False) # Check if at least one process is selected export_checked = tools_qt.is_checked(self.dlg_go2epa, self.dlg_go2epa.chk_export) exec_checked = tools_qt.is_checked(self.dlg_go2epa, self.dlg_go2epa.chk_exec) import_result_checked = tools_qt.is_checked( self.dlg_go2epa, self.dlg_go2epa.chk_import_result) if not export_checked and not exec_checked and not import_result_checked: msg = "You need to select at least one process" tools_qt.show_info_box(msg, title="Go2Epa") return False # Control export INP if export_checked: if not self._check_inp_chk(file_inp): return False # Control execute epa software if not self._check_rpt(): return False # Control import result if import_result_checked: if file_rpt is None: msg = "Select valid RPT file" tools_qgis.show_warning(msg, parameter=str(file_rpt)) return False if not tools_qt.is_checked(self.dlg_go2epa, self.dlg_go2epa.chk_exec): if not os.path.exists(file_rpt): msg = "File RPT not found" tools_qgis.show_warning(msg, parameter=str(file_rpt)) return False else: if not self._check_rpt(): return False # Control result name if result_name == '': self.dlg_go2epa.txt_result_name.setStyleSheet( "border: 1px solid red") msg = "This parameter is mandatory. Please, set a value" tools_qt.show_details(msg, title="Rpt fail", inf_text=None) return False self.dlg_go2epa.txt_result_name.setStyleSheet(None) sql = (f"SELECT result_id FROM rpt_cat_result " f"WHERE result_id = '{result_name}' LIMIT 1") row = tools_db.get_row(sql) if import_result_checked and not export_checked and not exec_checked: if not row: msg = "Result name not found. It's not possible to import RPT file into database" tools_qt.show_info_box(msg, "Import RPT file") return False else: if row: msg = "Result name already exists, do you want overwrite?" answer = tools_qt.show_question(msg, title="Alert") if not answer: return False return True def _load_user_values(self): """ Load QGIS settings related with file_manager """ self.dlg_go2epa.txt_result_name.setMaxLength(16) self.result_name = tools_gw.get_config_parser('btn_go2epa', 'go2epa_RESULT_NAME', "user", "session") self.dlg_go2epa.txt_result_name.setText(self.result_name) self.file_inp = tools_gw.get_config_parser('btn_go2epa', 'go2epa_FILE_INP', "user", "session") self.dlg_go2epa.txt_file_inp.setText(self.file_inp) self.file_rpt = tools_gw.get_config_parser('btn_go2epa', 'go2epa_FILE_RPT', "user", "session") self.dlg_go2epa.txt_file_rpt.setText(self.file_rpt) value = tools_gw.get_config_parser('btn_go2epa', 'go2epa_chk_INP', "user", "session") tools_qt.set_checked(self.dlg_go2epa, self.dlg_go2epa.chk_export, value) value = tools_gw.get_config_parser('btn_go2epa', 'go2epa_chk_UD', "user", "session") tools_qt.set_checked(self.dlg_go2epa, self.dlg_go2epa.chk_export_subcatch, value) value = tools_gw.get_config_parser('btn_go2epa', 'go2epa_chk_EPA', "user", "session") tools_qt.set_checked(self.dlg_go2epa, self.dlg_go2epa.chk_exec, value) value = tools_gw.get_config_parser('btn_go2epa', 'go2epa_chk_RPT', "user", "session") tools_qt.set_checked(self.dlg_go2epa, self.dlg_go2epa.chk_import_result, value) def _save_user_values(self): """ Save QGIS settings related with file_manager """ txt_result_name = f"{tools_qt.get_text(self.dlg_go2epa, 'txt_result_name', return_string_null=False)}" tools_gw.set_config_parser('btn_go2epa', 'go2epa_RESULT_NAME', f"{txt_result_name}") txt_file_inp = f"{tools_qt.get_text(self.dlg_go2epa, 'txt_file_inp', return_string_null=False)}" tools_gw.set_config_parser('btn_go2epa', 'go2epa_FILE_INP', f"{txt_file_inp}") txt_file_rpt = f"{tools_qt.get_text(self.dlg_go2epa, 'txt_file_rpt', return_string_null=False)}" tools_gw.set_config_parser('btn_go2epa', 'go2epa_FILE_RPT', f"{txt_file_rpt}") chk_export = f"{tools_qt.is_checked(self.dlg_go2epa, self.dlg_go2epa.chk_export)}" tools_gw.set_config_parser('btn_go2epa', 'go2epa_chk_INP', f"{chk_export}") chk_export_subcatch = f"{tools_qt.is_checked(self.dlg_go2epa, self.dlg_go2epa.chk_export_subcatch)}" tools_gw.set_config_parser('btn_go2epa', 'go2epa_chk_UD', f"{chk_export_subcatch}") chk_exec = f"{tools_qt.is_checked(self.dlg_go2epa, self.dlg_go2epa.chk_exec)}" tools_gw.set_config_parser('btn_go2epa', 'go2epa_chk_EPA', f"{chk_exec}") chk_import_result = f"{tools_qt.is_checked(self.dlg_go2epa, self.dlg_go2epa.chk_import_result)}" tools_gw.set_config_parser('btn_go2epa', 'go2epa_chk_RPT', f"{chk_import_result}") def _sector_selection(self): """ Load the tables in the selection form """ # Get class Selector from selector.py go2epa_selector = GwSelector() # Create the dialog dlg_selector = GwSelectorUi() tools_gw.load_settings(dlg_selector) # Create the common signals go2epa_selector.get_selector(dlg_selector, '"selector_basic"', current_tab='tab_dscenario') tools_gw.save_current_tab(dlg_selector, dlg_selector.main_tab, 'basic') # Open form if global_vars.session_vars['dialog_docker']: # Set signals when have docker form dlg_selector.btn_close.clicked.connect( partial(tools_gw.docker_dialog, self.dlg_go2epa)) dlg_selector.btn_close.clicked.connect( partial(self._manage_form_settings, 'restore')) # Save widgets settings from go2epa form self._manage_form_settings('save') # Open form tools_gw.docker_dialog(dlg_selector) else: # Set signals when have not docker form dlg_selector.btn_close.clicked.connect( partial(tools_gw.close_dialog, dlg_selector)) # Open form tools_gw.open_dialog(dlg_selector) def _manage_form_settings(self, action): if action == 'save': # Get widgets form values self.txt_result_name = tools_qt.get_text( self.dlg_go2epa, self.dlg_go2epa.txt_result_name) self.chk_export = self.dlg_go2epa.chk_export.isChecked() self.chk_export_subcatch = self.dlg_go2epa.chk_export_subcatch.isChecked( ) self.txt_file_inp = tools_qt.get_text(self.dlg_go2epa, self.dlg_go2epa.txt_file_inp) self.chk_exec = self.dlg_go2epa.chk_exec.isChecked() self.txt_file_rpt = tools_qt.get_text(self.dlg_go2epa, self.dlg_go2epa.txt_file_rpt) self.chk_import_result = self.dlg_go2epa.chk_import_result.isChecked( ) elif action == 'restore': # Set widgets form values if self.txt_result_name is not 'null': tools_qt.set_widget_text(self.dlg_go2epa, self.dlg_go2epa.txt_result_name, self.txt_result_name) if self.chk_export is not 'null': tools_qt.set_widget_text(self.dlg_go2epa, self.dlg_go2epa.chk_export, self.chk_export) if self.chk_export_subcatch is not 'null': tools_qt.set_widget_text(self.dlg_go2epa, self.dlg_go2epa.chk_export_subcatch, self.chk_export_subcatch) if self.txt_file_inp is not 'null': tools_qt.set_widget_text(self.dlg_go2epa, self.dlg_go2epa.txt_file_inp, self.txt_file_inp) if self.chk_exec is not 'null': tools_qt.set_widget_text(self.dlg_go2epa, self.dlg_go2epa.chk_exec, self.chk_exec) if self.txt_file_rpt is not 'null': tools_qt.set_widget_text(self.dlg_go2epa, self.dlg_go2epa.txt_file_rpt, self.txt_file_rpt) if self.chk_import_result is not 'null': tools_qt.set_widget_text(self.dlg_go2epa, self.dlg_go2epa.chk_import_result, self.chk_import_result) def _go2epa_select_file_inp(self): """ Select INP file """ self.file_inp = tools_qt.get_text(self.dlg_go2epa, self.dlg_go2epa.txt_file_inp) # Set default value if necessary if self.file_inp is None or self.file_inp == '': self.file_inp = global_vars.plugin_dir # Get directory of that file folder_path = os.path.dirname(self.file_inp) if not os.path.exists(folder_path): folder_path = os.path.dirname(__file__) os.chdir(folder_path) message = tools_qt.tr("Select INP file") widget_is_checked = tools_qt.is_checked(self.dlg_go2epa, self.dlg_go2epa.chk_export) if widget_is_checked: self.file_inp, filter_ = QFileDialog.getSaveFileName( None, message, "", '*.inp') else: self.file_inp, filter_ = QFileDialog.getOpenFileName( None, message, "", '*.inp') tools_qt.set_widget_text(self.dlg_go2epa, self.dlg_go2epa.txt_file_inp, self.file_inp) def _go2epa_select_file_rpt(self): """ Select RPT file """ # Set default value if necessary if self.file_rpt is None or self.file_rpt == '': self.file_rpt = global_vars.plugin_dir # Get directory of that file folder_path = os.path.dirname(self.file_rpt) if not os.path.exists(folder_path): folder_path = os.path.dirname(__file__) os.chdir(folder_path) message = tools_qt.tr("Select RPT file") widget_is_checked = tools_qt.is_checked(self.dlg_go2epa, self.dlg_go2epa.chk_export) if widget_is_checked: self.file_rpt, filter_ = QFileDialog.getSaveFileName( None, message, "", '*.rpt') else: self.file_rpt, filter_ = QFileDialog.getOpenFileName( None, message, "", '*.rpt') tools_qt.set_widget_text(self.dlg_go2epa, self.dlg_go2epa.txt_file_rpt, self.file_rpt) def _go2epa_accept(self): """ Save INP, RPT and result name""" # Manage if task is already running if hasattr(self, 'go2epa_task') and self.go2epa_task is not None: try: if self.go2epa_task.isActive(): message = "Go2Epa task is already active!" tools_qgis.show_warning(message) return except RuntimeError: pass # Save user values self._save_user_values() self.dlg_go2epa.txt_infolog.clear() self.dlg_go2epa.txt_file_rpt.setStyleSheet(None) status = self._check_fields() if status is False: return # Get widgets values self.result_name = tools_qt.get_text(self.dlg_go2epa, self.dlg_go2epa.txt_result_name, False, False) self.export_inp = tools_qt.is_checked(self.dlg_go2epa, self.dlg_go2epa.chk_export) self.export_subcatch = tools_qt.is_checked( self.dlg_go2epa, self.dlg_go2epa.chk_export_subcatch) self.file_inp = tools_qt.get_text(self.dlg_go2epa, self.dlg_go2epa.txt_file_inp) self.exec_epa = tools_qt.is_checked(self.dlg_go2epa, self.dlg_go2epa.chk_exec) self.file_rpt = tools_qt.get_text(self.dlg_go2epa, self.dlg_go2epa.txt_file_rpt) self.import_result = tools_qt.is_checked( self.dlg_go2epa, self.dlg_go2epa.chk_import_result) # Check for sector selector if self.export_inp: sql = "SELECT sector_id FROM selector_sector WHERE sector_id > 0 LIMIT 1" row = tools_db.get_row(sql) if row is None: msg = "You need to select some sector" tools_qt.show_info_box(msg) return self.dlg_go2epa.btn_accept.setEnabled(False) self.dlg_go2epa.btn_cancel.setEnabled(True) # Set background task 'Go2Epa' description = f"Go2Epa" self.go2epa_task = GwEpaFileManager(description, self) QgsApplication.taskManager().addTask(self.go2epa_task) QgsApplication.taskManager().triggerTask(self.go2epa_task) def _cancel_task(self): if hasattr(self, 'go2epa_task'): self.go2epa_task.cancel() def _set_completer_result(self, widget, viewname, field_name): """ Set autocomplete of widget 'feature_id' getting id's from selected @viewname """ # Adding auto-completion to a QLineEdit self.completer = QCompleter() self.completer.setCaseSensitivity(Qt.CaseInsensitive) widget.setCompleter(self.completer) model = QStringListModel() sql = f"SELECT {field_name} FROM {viewname}" rows = tools_db.get_rows(sql) if rows: for i in range(0, len(rows)): aux = rows[i] rows[i] = str(aux[0]) model.setStringList(rows) self.completer.setModel(model) def _go2epa_options(self): """ Button 23: Open form to set INP, RPT and project """ # Clear list self.epa_options_list = [] # Create dialog self.dlg_go2epa_options = GwGo2EpaOptionsUi() tools_gw.load_settings(self.dlg_go2epa_options) form = '"formName":"epaoptions"' body = tools_gw.create_body(form=form) json_result = tools_gw.execute_procedure('gw_fct_getconfig', body) if not json_result or json_result['status'] == 'Failed': return False tools_gw.build_dialog_options(self.dlg_go2epa_options, json_result['body']['form']['formTabs'], 0, self.epa_options_list) grbox_list = self.dlg_go2epa_options.findChildren(QGroupBox) for grbox in grbox_list: widget_list = grbox.findChildren(QWidget) if len(widget_list) == 0: grbox.setVisible(False) else: layout_list = grbox.findChildren(QGridLayout) for lyt in layout_list: spacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) lyt.addItem(spacer) # Event on change from combo parent self._get_event_combo_parent(json_result) self.dlg_go2epa_options.btn_accept.clicked.connect( partial(self._update_values, self.epa_options_list)) self.dlg_go2epa_options.btn_cancel.clicked.connect( partial(tools_gw.close_dialog, self.dlg_go2epa_options)) self.dlg_go2epa_options.rejected.connect( partial(tools_gw.close_dialog, self.dlg_go2epa_options)) tools_gw.open_dialog(self.dlg_go2epa_options, dlg_name='go2epa_options') def _update_values(self, _json): my_json = json.dumps(_json) form = '"formName":"epaoptions"' extras = f'"fields":{my_json}' body = tools_gw.create_body(form=form, extras=extras) json_result = tools_gw.execute_procedure('gw_fct_setconfig', body) if not json_result or json_result['status'] == 'Failed': return False tools_gw.manage_current_selections_docker(json_result) message = "Values has been updated" tools_qgis.show_info(message) # Close dialog tools_gw.close_dialog(self.dlg_go2epa_options) def _get_event_combo_parent(self, complet_result): for field in complet_result['body']['form']['formTabs'][0]["fields"]: if field['isparent']: widget = self.dlg_go2epa_options.findChild( QComboBox, field['widgetname']) if widget: widget.currentIndexChanged.connect( partial(self._fill_child, self.dlg_go2epa_options, widget)) def _fill_child(self, dialog, widget): combo_parent = widget.objectName() combo_id = tools_qt.get_combo_value(dialog, widget) # TODO cambiar por gw_fct_getchilds then unified with tools_gw.get_child if posible json_result = tools_gw.execute_procedure( 'gw_fct_getcombochilds', f"'epaoptions', '', '', '{combo_parent}', '{combo_id}', ''") if not json_result or json_result['status'] == 'Failed': return False for combo_child in json_result['fields']: if combo_child is not None: tools_gw.manage_combo_child(dialog, widget, combo_child)