def fill_table_planned_month(self, qtable, txt_filter, tableright, expression=None, set_edit_triggers=QTableView.NoEditTriggers): """ Set a model with selected filter and attach it to selected table @setEditStrategy: 0: OnFieldChange, 1: OnRowChange, 2: OnManualSubmit """ if self.schema_name not in tableright: tableright = f"{self.schema_name}.{tableright}" # Set model model = QSqlTableModel() model.setTable(tableright) model.setEditStrategy(QSqlTableModel.OnManualSubmit) model.setSort(2, 0) model.select() qtable.setEditTriggers(set_edit_triggers) # Check for errors if model.lastError().isValid(): self.controller.show_warning(model.lastError().text()) # Create expresion expr = (f" mu_name ILIKE '%{txt_filter.text()}%' " f" AND campaign_id = '{self.planned_camp_id}' ") if expression is not None: expr += expression qtable.setModel(model) qtable.model().setFilter(expr)
def workcat_fill_table(self, widget, table_name, set_edit_triggers=QTableView.NoEditTriggers, expr=None): """ Fill table @widget filtering query by @workcat_id Set a model with selected filter. Attach that model to selected table @setEditStrategy: 0: OnFieldChange 1: OnRowChange 2: OnManualSubmit """ if self.schema_name not in table_name: table_name = self.schema_name + "." + table_name # Set model model = QSqlTableModel() model.setTable(table_name) model.setEditStrategy(QSqlTableModel.OnFieldChange) model.setSort(0, 0) model.select() widget.setEditTriggers(set_edit_triggers) # Check for errors if model.lastError().isValid(): self.controller.show_warning(model.lastError().text()) # Attach model to table view if expr: widget.setModel(model) widget.model().setFilter(expr) else: widget.setModel(model)
def fill_table_prices(self, qtable, table_view, new_camp, set_edit_triggers=QTableView.NoEditTriggers): """ Set a model with selected filter and attach it to selected table @setEditStrategy: 0: OnFieldChange, 1: OnRowChange, 2: OnManualSubmit """ if self.schema_name not in table_view: table_view = self.schema_name + "." + table_view # Set model model = QSqlTableModel() model.setTable(table_view) model.setEditStrategy(QSqlTableModel.OnFieldChange) model.setSort(2, 0) model.select() qtable.setEditTriggers(set_edit_triggers) # Check for errors if model.lastError().isValid(): self.controller.show_warning(model.lastError().text()) return # Attach model to table view expr = f"campaign_id = '{new_camp}'" qtable.setModel(model) qtable.model().setFilter(expr)
def fill_table(qtable, table_name, expr_filter=None, edit_strategy=QSqlTableModel.OnManualSubmit, sort_order=Qt.AscendingOrder): """ Set a model with selected filter. Attach that model to selected table :param qtable: tableview where set the model (QTableView) :param table_name: database table name or view name (String) :param expr_filter: expression to filter the model (String) :param edit_strategy: (QSqlTableModel.OnFieldChange, QSqlTableModel.OnManualSubmit, QSqlTableModel.OnRowChange) :param sort_order: can be 0 or 1 (Qt.AscendingOrder or Qt.AscendingOrder) :return: """ if global_vars.schema_name and global_vars.schema_name not in table_name: table_name = f"{global_vars.schema_name}.{table_name}" # Set model model = QSqlTableModel(db=global_vars.qgis_db_credentials) model.setTable(table_name) model.setEditStrategy(edit_strategy) model.setSort(0, sort_order) if expr_filter is not None: model.setFilter(expr_filter) model.select() # Check for errors if model.lastError().isValid(): tools_log.log_warning(f"fill_table: {model.lastError().text()}") # Attach model to tableview qtable.setModel(model)
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 fill_table(widget, table_name, set_edit_strategy=QSqlTableModel.OnManualSubmit, expr_filter=None): """ Set a model with selected filter. Attach that model to selected table """ if global_vars.schema_name not in table_name: table_name = global_vars.schema_name + "." + table_name # Set model model = QSqlTableModel() model.setTable(table_name) model.setEditStrategy(set_edit_strategy) model.setSort(0, 0) model.select() # Check for errors if model.lastError().isValid(): global_vars.controller.show_warning(model.lastError().text()) # Attach model to table view widget.setModel(model) if expr_filter: widget.model().setFilter(expr_filter)
def fill_table(self, dialog, table_view, set_edit_triggers=QTableView.NoEditTriggers, update=False): """ Set a model with selected filter and attach it to selected table @setEditStrategy: 0: OnFieldChange, 1: OnRowChange, 2: OnManualSubmit """ if self.schema_name not in table_view: table_view = self.schema_name + "." + table_view # Set model model = QSqlTableModel() model.setTable(table_view) model.setEditStrategy(QSqlTableModel.OnManualSubmit) model.setSort(2, 0) model.select() dialog.selected_rows.setEditTriggers(set_edit_triggers) # Check for errors if model.lastError().isValid(): self.controller.show_warning(model.lastError().text()) # Create expresion expr = f" mu_name ILIKE '%{dialog.txt_selected_filter.text()}%'" if self.selected_camp is not None: expr += f" AND campaign_id = '{self.campaign_id}'" if update: expr += f" OR campaign_id = '{self.selected_camp}'" # Attach model to table or view dialog.selected_rows.setModel(model) dialog.selected_rows.model().setFilter(expr) # Set year to plan to all rows in list for x in range(0, model.rowCount()): i = int(dialog.selected_rows.model().fieldIndex('campaign_id')) index = dialog.selected_rows.model().index(x, i) model.setData(index, self.campaign_id) self.calculate_total_price(dialog, self.campaign_id)
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 ParentAction(object): def __init__(self, iface, settings, controller, plugin_dir): """ Class constructor """ # Initialize instance attributes self.iface = iface self.canvas = self.iface.mapCanvas() self.settings = settings self.controller = controller self.plugin_dir = plugin_dir self.dao = self.controller.dao self.schema_name = self.controller.schema_name self.project_type = None self.plugin_version = self.get_plugin_version() self.add_layer = AddLayer(iface, settings, controller, plugin_dir) self.user_current_layer = None self.rubber_point = None self.rubber_polygon = None def init_rubber(self): try: self.rubber_point = QgsRubberBand(self.canvas, 0) self.rubber_point.setColor(Qt.yellow) self.rubber_point.setIconSize(10) self.rubber_polygon = QgsRubberBand(self.canvas, 2) self.rubber_polygon.setColor(Qt.darkRed) self.rubber_polygon.setIconSize(20) except: pass def set_controller(self, controller): """ Set controller class """ self.controller = controller self.schema_name = self.controller.schema_name def open_web_browser(self, dialog, widget=None): """ Display url using the default browser """ if widget is not None: url = utils_giswater.getWidgetText(dialog, widget) if url == 'null': url = 'http://www.giswater.org' else: url = 'http://www.giswater.org' webbrowser.open(url) def get_plugin_version(self): """ Get plugin version from metadata.txt file """ # Check if metadata file exists metadata_file = os.path.join(self.plugin_dir, 'metadata.txt') if not os.path.exists(metadata_file): message = "Metadata file not found" self.controller.show_warning(message, parameter=metadata_file) return None metadata = configparser.ConfigParser() metadata.read(metadata_file) plugin_version = metadata.get('general', 'version') if plugin_version is None: message = "Plugin version not found" self.controller.show_warning(message) return plugin_version def get_file_dialog(self, dialog, widget): """ Get file dialog """ # Check if selected file exists. Set default value if necessary file_path = utils_giswater.getWidgetText(dialog, widget) if file_path is None or file_path == 'null' or not os.path.exists(str(file_path)): folder_path = self.plugin_dir else: folder_path = os.path.dirname(file_path) # Open dialog to select file os.chdir(folder_path) file_dialog = QFileDialog() file_dialog.setFileMode(QFileDialog.AnyFile) message = "Select file" files_path, filter_ = file_dialog.getOpenFileNames(parent=None, caption=self.controller.tr(message)) file_text = "" for file in files_path: file_text += f"{file}\n\n" if files_path: utils_giswater.setWidgetText(dialog, widget, str(file_text)) return files_path def get_folder_dialog(self, dialog, widget): """ Get folder dialog """ # Check if selected folder exists. Set default value if necessary folder_path = utils_giswater.getWidgetText(dialog, widget) if folder_path is None or folder_path == 'null' or not os.path.exists(folder_path): folder_path = os.path.expanduser("~") # Open dialog to select folder os.chdir(folder_path) file_dialog = QFileDialog() file_dialog.setFileMode(QFileDialog.Directory) message = "Select folder" folder_path = file_dialog.getExistingDirectory( parent=None, caption=self.controller.tr(message), directory=folder_path) if folder_path: utils_giswater.setWidgetText(dialog, widget, str(folder_path)) def load_settings(self, dialog=None): """ Load QGIS settings related with dialog position and size """ if dialog is None: dialog = self.dlg try: x = self.controller.plugin_settings_value(dialog.objectName() + "_x") y = self.controller.plugin_settings_value(dialog.objectName() + "_y") width = self.controller.plugin_settings_value(dialog.objectName() + "_width", dialog.property('width')) height = self.controller.plugin_settings_value(dialog.objectName() + "_height", dialog.property('height')) v_screens = ctypes.windll.user32 screen_x = v_screens.GetSystemMetrics(78) # Width of virtual screen screen_y = v_screens.GetSystemMetrics(79) # Height of virtual screen monitors = v_screens.GetSystemMetrics(80) # Will return an integer of the num of display monitors present. if (int(x) < 0 and monitors == 1) or (int(y) < 0 and monitors == 1): dialog.resize(int(width), int(height)) else: if int(x) > screen_x: x = int(screen_x) - int(width) if int(y) > screen_y: y = int(screen_y) dialog.setGeometry(int(x), int(y), int(width), int(height)) except: pass def save_settings(self, dialog=None): """ Save QGIS settings related with dialog position and size """ if dialog is None: dialog = self.dlg self.controller.plugin_settings_set_value(dialog.objectName() + "_width", dialog.property('width')) self.controller.plugin_settings_set_value(dialog.objectName() + "_height", dialog.property('height')) self.controller.plugin_settings_set_value(dialog.objectName() + "_x", dialog.pos().x() + 8) self.controller.plugin_settings_set_value(dialog.objectName() + "_y", dialog.pos().y() + 31) def get_last_tab(self, dialog, selector_name): """ Get the name of the last tab used by the user from QSettings() :param dialog: QDialog :param selector_name: Name of the selector (String) :return: Name of the last tab used by the user (string) """ tab_name = self.controller.plugin_settings_value(f"{dialog.objectName()}_{selector_name}") return tab_name def save_current_tab(self, dialog, tab_widget, selector_name): """ Save the name of current tab used by the user into QSettings() :param dialog: QDialog :param tab_widget: QTabWidget :param selector_name: Name of the selector (String) """ index = tab_widget.currentIndex() tab = tab_widget.widget(index) if tab: tab_name = tab.objectName() dlg_name = dialog.objectName() self.controller.plugin_settings_set_value(f"{dlg_name}_{selector_name}", tab_name) def open_dialog(self, dlg=None, dlg_name=None, info=True, maximize_button=True, stay_on_top=True, title=None): """ Open dialog """ # Check database connection before opening dialog if not self.controller.check_db_connection(): return if dlg is None or type(dlg) is bool: dlg = self.dlg # Set window title if title is not None: dlg.setWindowTitle(title) else: if dlg_name: self.controller.manage_translation(dlg_name, dlg) # Manage stay on top, maximize/minimize button and information button # if info is True maximize flag will be ignored # To enable maximize button you must set info to False flags = Qt.WindowCloseButtonHint if info: flags |= Qt.WindowSystemMenuHint | Qt.WindowContextHelpButtonHint else: if maximize_button: flags |= Qt.WindowMinMaxButtonsHint if stay_on_top: flags |= Qt.WindowStaysOnTopHint dlg.setWindowFlags(flags) # Open dialog if issubclass(type(dlg), GwDialog): dlg.open() elif issubclass(type(dlg), GwMainWindow): dlg.show() else: dlg.show() def close_dialog(self, dlg=None): """ Close dialog """ if dlg is None or type(dlg) is bool: dlg = self.dlg try: self.save_settings(dlg) dlg.close() map_tool = self.canvas.mapTool() # If selected map tool is from the plugin, set 'Pan' as current one if map_tool.toolName() == '': self.iface.actionPan().trigger() except AttributeError: pass except Exception as e: self.controller.log_info(type(e).__name__) def multi_row_selector(self, dialog, tableleft, tableright, field_id_left, field_id_right, name='name', hide_left=[0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30], hide_right=[1, 2, 3], aql=""): """ :param dialog: :param tableleft: Table to consult and load on the left side :param tableright: Table to consult and load on the right side :param field_id_left: ID field of the left table :param field_id_right: ID field of the right table :param name: field name (used in add_lot.py) :param hide_left: Columns to hide from the left table :param hide_right: Columns to hide from the right table :param aql: (add query left) Query added to the left side (used in basic.py def basic_exploitation_selector()) :return: """ # fill QTableView all_rows tbl_all_rows = dialog.findChild(QTableView, "all_rows") tbl_all_rows.setSelectionBehavior(QAbstractItemView.SelectRows) schema_name = self.schema_name.replace('"', '') query_left = f"SELECT * FROM {schema_name}.{tableleft} WHERE {name} NOT IN " query_left += f"(SELECT {schema_name}.{tableleft}.{name} FROM {schema_name}.{tableleft}" query_left += f" RIGHT JOIN {schema_name}.{tableright} ON {tableleft}.{field_id_left} = {tableright}.{field_id_right}" query_left += f" WHERE cur_user = current_user)" query_left += f" AND {field_id_left} > -1" query_left += aql self.fill_table_by_query(tbl_all_rows, query_left + f" ORDER BY {name};") self.hide_colums(tbl_all_rows, hide_left) tbl_all_rows.setColumnWidth(1, 200) # fill QTableView selected_rows tbl_selected_rows = dialog.findChild(QTableView, "selected_rows") tbl_selected_rows.setSelectionBehavior(QAbstractItemView.SelectRows) query_right = f"SELECT {tableleft}.{name}, cur_user, {tableleft}.{field_id_left}, {tableright}.{field_id_right}" query_right += f" FROM {schema_name}.{tableleft}" query_right += f" JOIN {schema_name}.{tableright} ON {tableleft}.{field_id_left} = {tableright}.{field_id_right}" query_right += " WHERE cur_user = current_user" self.fill_table_by_query(tbl_selected_rows, query_right + f" ORDER BY {name};") self.hide_colums(tbl_selected_rows, hide_right) tbl_selected_rows.setColumnWidth(0, 200) # Button select dialog.btn_select.clicked.connect(partial(self.multi_rows_selector, tbl_all_rows, tbl_selected_rows, field_id_left, tableright, field_id_right, query_left, query_right, field_id_right)) # Button unselect query_delete = f"DELETE FROM {schema_name}.{tableright}" query_delete += f" WHERE current_user = cur_user AND {tableright}.{field_id_right}=" dialog.btn_unselect.clicked.connect(partial(self.unselector, tbl_all_rows, tbl_selected_rows, query_delete, query_left, query_right, field_id_right)) # QLineEdit dialog.txt_name.textChanged.connect(partial(self.query_like_widget_text, dialog, dialog.txt_name, tbl_all_rows, tableleft, tableright, field_id_right, field_id_left, name, aql)) # Order control tbl_all_rows.horizontalHeader().sectionClicked.connect(partial(self.order_by_column, tbl_all_rows, query_left)) tbl_selected_rows.horizontalHeader().sectionClicked.connect( partial(self.order_by_column, tbl_selected_rows, query_right)) def order_by_column(self, qtable, query, idx): """ :param qtable: QTableView widget :param query: Query for populate QsqlQueryModel :param idx: The index of the clicked column :return: """ oder_by = {0: "ASC", 1: "DESC"} sort_order = qtable.horizontalHeader().sortIndicatorOrder() col_to_sort = qtable.model().headerData(idx, Qt.Horizontal) query += f" ORDER BY {col_to_sort} {oder_by[sort_order]}" self.fill_table_by_query(qtable, query) self.refresh_map_canvas() def hide_colums(self, widget, comuns_to_hide): for i in range(0, len(comuns_to_hide)): widget.hideColumn(comuns_to_hide[i]) def unselector(self, qtable_left, qtable_right, query_delete, query_left, query_right, field_id_right): selected_list = qtable_right.selectionModel().selectedRows() if len(selected_list) == 0: message = "Any record selected" self.controller.show_warning(message) return expl_id = [] for i in range(0, len(selected_list)): row = selected_list[i].row() id_ = str(qtable_right.model().record(row).value(field_id_right)) expl_id.append(id_) for i in range(0, len(expl_id)): self.controller.execute_sql(query_delete + str(expl_id[i])) # Refresh oder_by = {0: "ASC", 1: "DESC"} sort_order = qtable_left.horizontalHeader().sortIndicatorOrder() idx = qtable_left.horizontalHeader().sortIndicatorSection() col_to_sort = qtable_left.model().headerData(idx, Qt.Horizontal) query_left += f" ORDER BY {col_to_sort} {oder_by[sort_order]}" self.fill_table_by_query(qtable_left, query_left) sort_order = qtable_right.horizontalHeader().sortIndicatorOrder() idx = qtable_right.horizontalHeader().sortIndicatorSection() col_to_sort = qtable_right.model().headerData(idx, Qt.Horizontal) query_right += f" ORDER BY {col_to_sort} {oder_by[sort_order]}" self.fill_table_by_query(qtable_right, query_right) self.refresh_map_canvas() def multi_rows_selector(self, qtable_left, qtable_right, id_ori, tablename_des, id_des, query_left, query_right, field_id): """ :param qtable_left: QTableView origin :param qtable_right: QTableView destini :param id_ori: Refers to the id of the source table :param tablename_des: table destini :param id_des: Refers to the id of the target table, on which the query will be made :param query_right: :param query_left: :param field_id: """ selected_list = qtable_left.selectionModel().selectedRows() if len(selected_list) == 0: message = "Any record selected" self.controller.show_warning(message) return expl_id = [] curuser_list = [] for i in range(0, len(selected_list)): row = selected_list[i].row() id_ = qtable_left.model().record(row).value(id_ori) expl_id.append(id_) curuser = qtable_left.model().record(row).value("cur_user") curuser_list.append(curuser) for i in range(0, len(expl_id)): # Check if expl_id already exists in expl_selector sql = (f"SELECT DISTINCT({id_des}, cur_user)" f" FROM {tablename_des}" f" WHERE {id_des} = '{expl_id[i]}' AND cur_user = current_user") row = self.controller.get_row(sql) if row: # if exist - show warning message = "Id already selected" self.controller.show_info_box(message, "Info", parameter=str(expl_id[i])) else: sql = (f"INSERT INTO {tablename_des} ({field_id}, cur_user) " f" VALUES ({expl_id[i]}, current_user)") self.controller.execute_sql(sql) # Refresh oder_by = {0: "ASC", 1: "DESC"} sort_order = qtable_left.horizontalHeader().sortIndicatorOrder() idx = qtable_left.horizontalHeader().sortIndicatorSection() col_to_sort = qtable_left.model().headerData(idx, Qt.Horizontal) query_left += f" ORDER BY {col_to_sort} {oder_by[sort_order]}" self.fill_table_by_query(qtable_right, query_right) sort_order = qtable_right.horizontalHeader().sortIndicatorOrder() idx = qtable_right.horizontalHeader().sortIndicatorSection() col_to_sort = qtable_right.model().headerData(idx, Qt.Horizontal) query_right += f" ORDER BY {col_to_sort} {oder_by[sort_order]}" self.fill_table_by_query(qtable_left, query_left) self.refresh_map_canvas() def fill_table(self, widget, table_name, set_edit_strategy=QSqlTableModel.OnManualSubmit, expr_filter=None): """ Set a model with selected filter. Attach that model to selected table """ if self.schema_name not in table_name: table_name = self.schema_name + "." + table_name # Set model self.model = QSqlTableModel() self.model.setTable(table_name) self.model.setEditStrategy(set_edit_strategy) self.model.setSort(0, 0) self.model.select() # Check for errors if self.model.lastError().isValid(): self.controller.show_warning(self.model.lastError().text()) # Attach model to table view widget.setModel(self.model) if expr_filter: widget.model().setFilter(expr_filter) def fill_table_by_query(self, qtable, query): """ :param qtable: QTableView to show :param query: query to set model """ model = QSqlQueryModel() model.setQuery(query) qtable.setModel(model) qtable.show() # Check for errors if model.lastError().isValid(): self.controller.show_warning(model.lastError().text()) def query_like_widget_text(self, dialog, text_line, qtable, tableleft, tableright, field_id_r, field_id_l, name='name', aql=''): """ Fill the QTableView by filtering through the QLineEdit""" schema_name = self.schema_name.replace('"', '') query = utils_giswater.getWidgetText(dialog, text_line, return_string_null=False).lower() sql = (f"SELECT * FROM {schema_name}.{tableleft} WHERE {name} NOT IN " f"(SELECT {tableleft}.{name} FROM {schema_name}.{tableleft}" f" RIGHT JOIN {schema_name}.{tableright}" f" ON {tableleft}.{field_id_l} = {tableright}.{field_id_r}" f" WHERE cur_user = current_user) AND LOWER({name}::text) LIKE '%{query}%'" f" AND {field_id_l} > -1") sql += aql self.fill_table_by_query(qtable, sql) def set_icon(self, widget, icon): """ Set @icon to selected @widget """ # Get icons folder icons_folder = os.path.join(self.plugin_dir, 'icons') icon_path = os.path.join(icons_folder, str(icon) + ".png") if os.path.exists(icon_path): widget.setIcon(QIcon(icon_path)) else: self.controller.log_info("File not found", parameter=icon_path) def check_expression(self, expr_filter, log_info=False): """ Check if expression filter @expr_filter is valid """ if log_info: self.controller.log_info(expr_filter) expr = QgsExpression(expr_filter) if expr.hasParserError(): message = "Expression Error" self.controller.log_warning(message, parameter=expr_filter) return False, expr return True, expr def refresh_map_canvas(self, restore_cursor=False): """ Refresh all layers present in map canvas """ self.canvas.refreshAllLayers() for layer_refresh in self.canvas.layers(): layer_refresh.triggerRepaint() if restore_cursor: self.set_cursor_restore() def set_cursor_wait(self): """ Change cursor to 'WaitCursor' """ QApplication.setOverrideCursor(Qt.WaitCursor) def set_cursor_restore(self): """ Restore to previous cursors """ QApplication.restoreOverrideCursor() def get_cursor_multiple_selection(self): """ Set cursor for multiple selection """ path_folder = os.path.join(os.path.dirname(__file__), os.pardir) path_cursor = os.path.join(path_folder, 'icons', '201.png') if os.path.exists(path_cursor): cursor = QCursor(QPixmap(path_cursor)) else: cursor = QCursor(Qt.ArrowCursor) return cursor def set_table_columns(self, dialog, widget, table_name, sort_order=0, isQStandardItemModel=False): """ Configuration of tables. Set visibility and width of columns """ widget = utils_giswater.getWidget(dialog, widget) if not widget: return # Set width and alias of visible columns columns_to_delete = [] sql = (f"SELECT columnindex, width, alias, status" f" FROM config_form_tableview" f" WHERE tablename = '{table_name}'" f" ORDER BY columnindex") rows = self.controller.get_rows(sql, log_info=False) if not rows: return for row in rows: if not row['status']: columns_to_delete.append(row['columnindex'] - 1) else: width = row['width'] if width is None: width = 100 widget.setColumnWidth(row['columnindex'] - 1, width) widget.model().setHeaderData(row['columnindex'] - 1, Qt.Horizontal, row['alias']) # Set order if isQStandardItemModel: widget.model().sort(sort_order, Qt.AscendingOrder) else: widget.model().setSort(sort_order, Qt.AscendingOrder) widget.model().select() # Delete columns for column in columns_to_delete: widget.hideColumn(column) return widget def connect_signal_selection_changed(self, option): """ Connect signal selectionChanged """ try: if option == "mincut_connec": self.canvas.selectionChanged.connect(partial(self.snapping_selection_connec)) elif option == "mincut_hydro": self.canvas.selectionChanged.connect(partial(self.snapping_selection_hydro)) except Exception: pass def disconnect_signal_selection_changed(self): """ Disconnect signal selectionChanged """ try: self.canvas.selectionChanged.disconnect() except Exception: pass finally: self.iface.actionPan().trigger() def set_label_current_psector(self, dialog): sql = ("SELECT t1.name FROM plan_psector AS t1 " " INNER JOIN config_param_user AS t2 ON t1.psector_id::text = t2.value " " WHERE t2.parameter='plan_psector_vdefault' AND cur_user = current_user") row = self.controller.get_row(sql) if not row: return utils_giswater.setWidgetText(dialog, 'lbl_vdefault_psector', row[0]) def multi_rows_delete(self, widget, table_name, column_id): """ Delete selected elements of the table :param QTableView widget: origin :param table_name: table origin :param column_id: Refers to the id of the source table """ # Get selected rows selected_list = widget.selectionModel().selectedRows() if len(selected_list) == 0: message = "Any record selected" self.controller.show_warning(message) return inf_text = "" list_id = "" for i in range(0, len(selected_list)): row = selected_list[i].row() id_ = widget.model().record(row).value(str(column_id)) inf_text += f"{id_}, " list_id += f"'{id_}', " inf_text = inf_text[:-2] list_id = list_id[:-2] message = "Are you sure you want to delete these records?" title = "Delete records" answer = self.controller.ask_question(message, title, inf_text) if answer: sql = f"DELETE FROM {table_name}" sql += f" WHERE {column_id} IN ({list_id})" self.controller.execute_sql(sql) widget.model().select() def select_features_by_expr(self, layer, expr): """ Select features of @layer applying @expr """ if not layer: return if expr is None: layer.removeSelection() else: it = layer.getFeatures(QgsFeatureRequest(expr)) # Build a list of feature id's from the previous result and select them id_list = [i.id() for i in it] if len(id_list) > 0: layer.selectByIds(id_list) else: layer.removeSelection() def hide_void_groupbox(self, dialog): """ Hide empty groupbox """ grb_list = {} grbox_list = dialog.findChildren(QGroupBox) for grbox in grbox_list: widget_list = grbox.findChildren(QWidget) if len(widget_list) == 0: grb_list[grbox.objectName()] = 0 grbox.setVisible(False) return grb_list def zoom_to_selected_features(self, layer, geom_type=None, zoom=None): """ Zoom to selected features of the @layer with @geom_type """ if not layer: return self.iface.setActiveLayer(layer) self.iface.actionZoomToSelected().trigger() if geom_type: # Set scale = scale_zoom if geom_type in ('node', 'connec', 'gully'): scale = self.scale_zoom # Set scale = max(current_scale, scale_zoom) elif geom_type == 'arc': scale = self.iface.mapCanvas().scale() if int(scale) < int(self.scale_zoom): scale = self.scale_zoom else: scale = 5000 if zoom is not None: scale = zoom self.iface.mapCanvas().zoomScale(float(scale)) def make_list_for_completer(self, sql): """ Prepare a list with the necessary items for the completer :param sql: Query to be executed, where will we get the list of items (string) :return list_items: List with the result of the query executed (List) ["item1","item2","..."] """ rows = self.controller.get_rows(sql) list_items = [] if rows: for row in rows: list_items.append(str(row[0])) return list_items def set_completer_lineedit(self, qlineedit, list_items): """ Set a completer into a QLineEdit :param qlineedit: Object where to set the completer (QLineEdit) :param list_items: List of items to set into the completer (List)["item1","item2","..."] """ completer = QCompleter() completer.setCaseSensitivity(Qt.CaseInsensitive) completer.setMaxVisibleItems(10) completer.setCompletionMode(0) completer.setFilterMode(Qt.MatchContains) completer.popup().setStyleSheet("color: black;") qlineedit.setCompleter(completer) model = QStringListModel() model.setStringList(list_items) completer.setModel(model) def get_max_rectangle_from_coords(self, list_coord): """ Returns the minimum rectangle(x1, y1, x2, y2) of a series of coordinates :type list_coord: list of coors in format ['x1 y1', 'x2 y2',....,'x99 y99'] """ coords = list_coord.group(1) polygon = coords.split(',') x, y = polygon[0].split(' ') min_x = x # start with something much higher than expected min min_y = y max_x = x # start with something much lower than expected max max_y = y for i in range(0, len(polygon)): x, y = polygon[i].split(' ') if x < min_x: min_x = x if x > max_x: max_x = x if y < min_y: min_y = y if y > max_y: max_y = y return max_x, max_y, min_x, min_y def zoom_to_rectangle(self, x1, y1, x2, y2, margin=5): rect = QgsRectangle(float(x1) - margin, float(y1) - margin, float(x2) + margin, float(y2) + margin) self.canvas.setExtent(rect) self.canvas.refresh() def create_action(self, action_name, action_group, icon_num=None, text=None): """ Creates a new action with selected parameters """ icon = None icon_folder = self.plugin_dir + '/icons/' icon_path = icon_folder + icon_num + '.png' if os.path.exists(icon_path): icon = QIcon(icon_path) if icon is None: action = QAction(text, action_group) else: action = QAction(icon, text, action_group) action.setObjectName(action_name) return action def set_wait_cursor(self): QApplication.instance().setOverrideCursor(Qt.WaitCursor) def set_arrow_cursor(self): QApplication.instance().setOverrideCursor(Qt.ArrowCursor) def delete_layer_from_toc(self, layer_name): """ Delete layer from toc if exist """ layer = None for lyr in list(QgsProject.instance().mapLayers().values()): if lyr.name() == layer_name: layer = lyr break if layer is not None: # Remove layer QgsProject.instance().removeMapLayer(layer) # Remove group if is void root = QgsProject.instance().layerTreeRoot() group = root.findGroup('GW Temporal Layers') if group: layers = group.findLayers() if not layers: root.removeChildNode(group) self.delete_layer_from_toc(layer_name) def create_body(self, form='', feature='', filter_fields='', extras=None): """ Create and return parameters as body to functions""" client = f'$${{"client":{{"device":4, "infoType":1, "lang":"ES"}}, ' form = f'"form":{{{form}}}, ' feature = f'"feature":{{{feature}}}, ' filter_fields = f'"filterFields":{{{filter_fields}}}' page_info = f'"pageInfo":{{}}' data = f'"data":{{{filter_fields}, {page_info}' if extras is not None: data += ', ' + extras data += f'}}}}$$' body = "" + client + form + feature + data return body def get_composers_list(self): layour_manager = QgsProject.instance().layoutManager().layouts() active_composers = [layout for layout in layour_manager] return active_composers def get_composer_index(self, name): index = 0 composers = self.get_composers_list() for comp_view in composers: composer_name = comp_view.name() if composer_name == name: break index += 1 return index def set_restriction(self, dialog, widget_to_ignore, restriction): """ Set all widget enabled(False) or readOnly(True) except those on the tuple :param dialog: :param widget_to_ignore: tuple = ('widgetname1', 'widgetname2', 'widgetname3', ...) :param restriction: roles that do not have access. tuple = ('role1', 'role1', 'role1', ...) :return: """ role = self.controller.get_restriction() if role in restriction: widget_list = dialog.findChildren(QWidget) for widget in widget_list: if widget.objectName() in widget_to_ignore: continue # Set editable/readonly if type(widget) in (QLineEdit, QDoubleSpinBox, QTextEdit): widget.setReadOnly(True) widget.setStyleSheet("QWidget {background: rgb(242, 242, 242);color: rgb(100, 100, 100)}") elif type(widget) in (QComboBox, QCheckBox, QTableView, QPushButton): widget.setEnabled(False) def set_dates_from_to(self, widget_from, widget_to, table_name, field_from, field_to): sql = (f"SELECT MIN(LEAST({field_from}, {field_to}))," f" MAX(GREATEST({field_from}, {field_to}))" f" FROM {table_name}") row = self.controller.get_row(sql, log_sql=False) current_date = QDate.currentDate() if row: if row[0]: widget_from.setDate(row[0]) else: widget_from.setDate(current_date) if row[1]: widget_to.setDate(row[1]) else: widget_to.setDate(current_date) def get_values_from_catalog(self, table_name, typevalue, order_by='id'): sql = (f"SELECT id, idval" f" FROM {table_name}" f" WHERE typevalue = '{typevalue}'" f" ORDER BY {order_by}") rows = self.controller.get_rows(sql) return rows def integer_validator(self, value, widget, btn_accept): """ Check if the value is an integer or not. This function is called in def set_datatype_validator(self, value, widget, btn) widget = getattr(self, f"{widget.property('datatype')}_validator")( value, widget, btn) """ if value is None or bool(re.search("^\d*$", value)): widget.setStyleSheet(None) btn_accept.setEnabled(True) else: widget.setStyleSheet("border: 1px solid red") btn_accept.setEnabled(False) def double_validator(self, value, widget, btn_accept): """ Check if the value is double or not. This function is called in def set_datatype_validator(self, value, widget, btn) widget = getattr(self, f"{widget.property('datatype')}_validator")( value, widget, btn) """ if value is None or bool(re.search("^\d*$", value)) or bool(re.search("^\d+\.\d+$", value)): widget.setStyleSheet(None) btn_accept.setEnabled(True) else: widget.setStyleSheet("border: 1px solid red") btn_accept.setEnabled(False) def load_qml(self, layer, qml_path): """ Apply QML style located in @qml_path in @layer """ if layer is None: return False if not os.path.exists(qml_path): self.controller.log_warning("File not found", parameter=qml_path) return False if not qml_path.endswith(".qml"): self.controller.log_warning("File extension not valid", parameter=qml_path) return False layer.loadNamedStyle(qml_path) layer.triggerRepaint() return True def open_file_path(self, filter_="All (*.*)"): """ Open QFileDialog """ msg = self.controller.tr("Select DXF file") path, filter_ = QFileDialog.getOpenFileName(None, msg, "", filter_) return path, filter_ def show_exceptions_msg(self, title, msg=""): cat_exception = {'KeyError': 'Key on returned json from ddbb is missed.'} self.dlg_info = DialogTextUi() self.dlg_info.btn_accept.setVisible(False) self.dlg_info.btn_close.clicked.connect(partial(self.close_dialog, self.dlg_info)) self.dlg_info.setWindowTitle(title) utils_giswater.setWidgetText(self.dlg_info, self.dlg_info.txt_infolog, msg) self.open_dialog(self.dlg_info, dlg_name='dialog_text', title=title) def put_combobox(self, qtable, rows, field, widget_pos, combo_values): """ Set one column of a QtableView as QComboBox with values from database. :param qtable: QTableView to fill :param rows: List of items to set QComboBox (["..", "..."]) :param field: Field to set QComboBox (String) :param widget_pos: Position of the column where we want to put the QComboBox (integer) :param combo_values: List of items to populate QComboBox (["..", "..."]) :return: """ for x in range(0, len(rows)): combo = QComboBox() row = rows[x] # Populate QComboBox utils_giswater.set_item_data(combo, combo_values, 1) # Set QCombobox to wanted item utils_giswater.set_combo_itemData(combo, str(row[field]), 1) # Get index and put QComboBox into QTableView at index position idx = qtable.model().index(x, widget_pos) qtable.setIndexWidget(idx, combo) combo.currentIndexChanged.connect(partial(self.update_status, combo, qtable, x, widget_pos)) def update_status(self, combo, qtable, pos_x, widget_pos): """ Update values from QComboBox to QTableView :param combo: QComboBox from which we will take the value :param qtable: QTableView Where update values :param pos_x: Position of the row where we want to update value (integer) :param widget_pos:Position of the widget where we want to update value (integer) :return: """ elem = combo.itemData(combo.currentIndex()) i = qtable.model().index(pos_x, widget_pos) qtable.model().setData(i, elem[0]) i = qtable.model().index(pos_x, widget_pos + 1) qtable.model().setData(i, elem[1]) def get_feature_by_id(self, layer, id_, field_id): expr = "" + str(field_id) + "= '" + str(id_) + "'" features = layer.getFeatures(QgsFeatureRequest().setFilterExpression(expr)) for feature in features: if str(feature[field_id]) == str(id_): return feature return False def document_insert(self, dialog, tablename, field, field_value): """ Insert a document related to the current visit :param dialog: (QDialog ) :param tablename: Name of the table to make the queries (string) :param field: Field of the table to make the where clause (string) :param field_value: Value to compare in the clause where (string) """ doc_id = dialog.doc_id.text() if not doc_id: message = "You need to insert doc_id" self.controller.show_warning(message) return # Check if document already exist sql = (f"SELECT doc_id" f" FROM {tablename}" f" WHERE doc_id = '{doc_id}' AND {field} = '{field_value}'") row = self.controller.get_row(sql) if row: msg = "Document already exist" self.controller.show_warning(msg) return # Insert into new table sql = (f"INSERT INTO {tablename} (doc_id, {field})" f" VALUES ('{doc_id}', '{field_value}')") status = self.controller.execute_sql(sql) if status: message = "Document inserted successfully" self.controller.show_info(message) dialog.tbl_document.model().select() def document_open(self, qtable): """ Open selected document """ # Get selected rows field_index = qtable.model().fieldIndex('path') selected_list = qtable.selectionModel().selectedRows(field_index) if not selected_list: message = "Any record selected" self.controller.show_info_box(message) return elif len(selected_list) > 1: message = "More then one document selected. Select just one document." self.controller.show_warning(message) return path = selected_list[0].data() # Check if file exist if os.path.exists(path): # Open the document if sys.platform == "win32": os.startfile(path) else: opener = "open" if sys.platform == "darwin" else "xdg-open" subprocess.call([opener, path]) else: webbrowser.open(path) def document_delete(self, qtable, tablename): """ Delete record from selected rows in tbl_document """ # Get selected rows. 0 is the column of the pk 0 'id' selected_list = qtable.selectionModel().selectedRows(0) if len(selected_list) == 0: message = "Any record selected" self.controller.show_info_box(message) return selected_id = [] for index in selected_list: doc_id = index.data() selected_id.append(str(doc_id)) message = "Are you sure you want to delete these records?" title = "Delete records" answer = self.controller.ask_question(message, title, ','.join(selected_id)) if answer: sql = (f"DELETE FROM {tablename}" f" WHERE id IN ({','.join(selected_id)})") status = self.controller.execute_sql(sql) if not status: message = "Error deleting data" self.controller.show_warning(message) return else: message = "Document deleted" self.controller.show_info(message) qtable.model().select() def get_all_actions(self): actions_list = self.iface.mainWindow().findChildren(QAction) for action in actions_list: self.controller.log_info(str(action.objectName())) action.triggered.connect(partial(self.show_action_name, action)) def show_action_name(self, action): self.controller.log_info(str(action.objectName())) def get_points(self, list_coord=None): """ Return list of QgsPoints taken from geometry :type list_coord: list of coors in format ['x1 y1', 'x2 y2',....,'x99 y99'] """ coords = list_coord.group(1) polygon = coords.split(',') points = [] for i in range(0, len(polygon)): x, y = polygon[i].split(' ') point = QgsPointXY(float(x), float(y)) points.append(point) return points def hilight_feature_by_id(self, qtable, layer_name, field_id, width, index): """ Based on the received index and field_id, the id of the received field_id is searched within the table and is painted in red on the canvas """ self.resetRubberbands() layer = self.controller.get_layer_by_tablename(layer_name) if not layer: return row = index.row() column_index = utils_giswater.get_col_index_by_col_name(qtable, field_id) _id = index.sibling(row, column_index).data() feature = self.get_feature_by_id(layer, _id, field_id) try: geometry = feature.geometry() self.rubber_polygon.setToGeometry(geometry, None) self.rubber_polygon.setColor(QColor(255, 0, 0, 100)) self.rubber_polygon.setWidth(width) self.rubber_polygon.show() except AttributeError: pass def draw_polyline(self, points, color=QColor(255, 0, 0, 100), width=5, duration_time=None): """ Draw 'line' over canvas following list of points :param duration_time: integer milliseconds ex: 3000 for 3 seconds """ if self.rubber_polygon is None: self.init_rubber() rb = self.rubber_polygon polyline = QgsGeometry.fromPolylineXY(points) rb.setToGeometry(polyline, None) rb.setColor(color) rb.setWidth(width) rb.show() # wait to simulate a flashing effect if duration_time is not None: QTimer.singleShot(duration_time, self.resetRubberbands) return rb def resetRubberbands(self): if self.rubber_polygon is None: self.init_rubber() self.rubber_point.reset(0) self.rubber_polygon.reset(2) def restore_user_layer(self): if self.user_current_layer: self.iface.setActiveLayer(self.user_current_layer) else: layer = self.controller.get_layer_by_tablename('v_edit_node') if layer: self.iface.setActiveLayer(layer) def set_style_mapzones(self): extras = f'"mapzones":""' body = self.create_body(extras=extras) json_return = self.controller.get_json('gw_fct_getstylemapzones', body) if not json_return: return False for mapzone in json_return['body']['data']['mapzones']: # Loop for each mapzone returned on json lyr = self.controller.get_layer_by_tablename(mapzone['layer']) categories = [] status = mapzone['status'] if status == 'Disable': pass if lyr: # Loop for each id returned on json for id in mapzone['values']: # initialize the default symbol for this geometry type symbol = QgsSymbol.defaultSymbol(lyr.geometryType()) symbol.setOpacity(float(mapzone['opacity'])) # Setting simp R = random.randint(0, 255) G = random.randint(0, 255) B = random.randint(0, 255) if status == 'Stylesheet': try: R = id['stylesheet']['color'][0] G = id['stylesheet']['color'][1] B = id['stylesheet']['color'][2] except TypeError: R = random.randint(0, 255) G = random.randint(0, 255) B = random.randint(0, 255) elif status == 'Random': R = random.randint(0, 255) G = random.randint(0, 255) B = random.randint(0, 255) # Setting sytle layer_style = {'color': '{}, {}, {}'.format(int(R), int(G), int(B))} symbol_layer = QgsSimpleFillSymbolLayer.create(layer_style) if symbol_layer is not None: symbol.changeSymbolLayer(0, symbol_layer) category = QgsRendererCategory(id['id'], symbol, str(id['id'])) categories.append(category) # apply symbol to layer renderer if 'idname' in mapzone: lyr.setRenderer(QgsCategorizedSymbolRenderer(mapzone['idname'], categories)) # repaint layer lyr.triggerRepaint()
class hsrrProcessorDockWidget(QDockWidget, FORM_CLASS): closingPlugin = pyqtSignal() def __init__(self, parent=None): super(hsrrProcessorDockWidget, self).__init__(parent) self.setupUi(self) self.connect_button.clicked.connect(self.connect) self.dd = hsrr_processor_dd.hsrr_dd(self) self.prepare_database_button.clicked.connect(self.prepare_database) self.rw = routes_widget(self, self.dd, 'hsrr.routes', self.readings_box, self.network_box, self.run_fieldbox, self.f_line_fieldbox, self.sec_fieldbox) self.rw_placeholder.addWidget(self.rw) #self.tabs.insertTab(2,self.rw,'Fitting') self.upload_csv_button.clicked.connect(self.upload_runs_dialog) self.upload_folder_button.clicked.connect(self.upload_folder_dialog) self.open_help_button.clicked.connect(self.open_help) self.init_run_menu() self.init_requested_menu() self.rw.refit.connect(lambda: print('refit')) def connect(self): if self.dd.exec_(): if self.dd.connected: self.database_label.setText('Connected to %s' % (self.dd.db.databaseName())) self.connect_run_info() self.connect_coverage() self.refresh_run_info() else: self.database_label.setText('Not Connected') def coverage_show_all(self): self.requested_model.setFilter('') self.requested_model.select() def coverage_show_missing(self): self.requested_model.setFilter("coverage=0") self.requested_model.select() #opens help/index.html in default browser def open_help(self): help_path = os.path.join(os.path.dirname(__file__), 'help', 'index.html') help_path = 'file:///' + os.path.abspath(help_path) QDesktopServices.openUrl(QUrl(help_path)) def connect_run_info(self): self.run_info_model = QSqlTableModel(db=self.dd.db) self.run_info_model.setTable('hsrr.run_info') self.run_info_model.setSort(self.run_info_model.fieldIndex("run"), Qt.AscendingOrder) self.run_info_model.setEditStrategy(QSqlTableModel.OnFieldChange) self.run_info_view.setModel(self.run_info_model) def check_connected(self): if self.dd.con: return True else: iface.messageBar().pushMessage( 'fitting tool: Not connected to database') return False def upload_runs(self, runs): for f in runs: r = self.dd.upload_run_csv(f) if r == True: self.upload_log.appendPlainText('sucessfully uploaded %s' % (f)) else: self.upload_log.appendPlainText('error uploading %s:%s' % (f, str(r))) self.update() self.refresh_run_info() def upload_runs_dialog(self): if self.check_connected(): files = file_dialogs.load_files_dialog('.xls', 'upload spreadsheets') if files: for f in files: self.upload_runs(files) def upload_folder_dialog(self): folder = file_dialogs.load_directory_dialog( '.xls', 'upload all .xls in directory') if folder: self.upload_runs(file_dialogs.filter_files(folder, '.xls')) def closeEvent(self, event): self.dd.disconnect() self.closingPlugin.emit() event.accept() def after_refit(self): self.coverage_model.select() def connect_coverage(self): # self.requested_model = QSqlTableModel(db=self.dd.db) self.requested_model = betterTableModel(db=self.dd.db) self.requested_model.setEditStrategy(QSqlTableModel.OnFieldChange) self.requested_model.setTable('hsrr.requested') self.requested_model.setEditable(False) #set all cols uneditable self.requested_model.setColEditable( self.requested_model.fieldIndex("note"), True) #make note col editable self.requested_model.setSort(self.requested_model.fieldIndex("sec"), Qt.AscendingOrder) self.requested_view.setModel(self.requested_model) self.requested_view.setColumnHidden( self.requested_model.fieldIndex("pk"), True) #hide pk column self.show_all_button.clicked.connect(self.coverage_show_all) self.show_missing_button.clicked.connect(self.coverage_show_missing) self.rw.refit.connect(self.requested_model.select) if self.show_missing_button.isChecked(): self.coverage_show_missing() else: self.coverage_show_all() self.requested_view.resizeColumnsToContents() def prepare_database(self): if self.check_connected(): msgBox = QMessageBox() msgBox.setText( "DON'T USE THIS PARTWAY THROUGH THE JOB! because this will erase any data in tables used by this plugin." ) msgBox.setInformativeText("Continue?") msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No) msgBox.setDefaultButton(QMessageBox.No) i = msgBox.exec_() if i == QMessageBox.Yes: self.dd.setup_database() iface.messageBar().pushMessage( 'fitting tool: prepared database') #drop selected run of run_info table def drop_run(self): r = self.run_box.currentText() self.dd.sql("delete from run_info where run='{run}'", {'run': r}) self.rw.get_runs() #for requested view def init_run_menu(self): self.run_info_menu = QMenu() act = self.run_info_menu.addAction('drop run') act.triggered.connect(lambda: self.dd.drop_runs([ str(i.data()) for i in self.run_info_view.selectionModel().selectedRows(0) ])) # selectedRows(0) returns column 0 (sec) act.triggered.connect( self.refresh_run_info) # selectedRows(0) returns column 0 (sec) self.run_info_view.setContextMenuPolicy(Qt.CustomContextMenu) self.run_info_view.customContextMenuRequested.connect( self.show_run_info_menu) #for requested view def init_requested_menu(self): self.requested_menu = QMenu() act = self.requested_menu.addAction('zoom to section') act.triggered.connect(lambda: self.select_on_network([ i.data() for i in self.requested_view.selectionModel().selectedRows() ])) self.requested_view.setContextMenuPolicy(Qt.CustomContextMenu) self.requested_view.customContextMenuRequested.connect( self.show_requested_menu) def show_run_info_menu(self, pt): self.run_info_menu.exec_(self.mapToGlobal(pt)) def show_requested_menu(self, pt): self.requested_menu.exec_(self.mapToGlobal(pt)) def refresh_run_info(self): self.run_info_model.select() self.rw.refresh_runs() #select sec on network def select_on_network(self, sects): # inds=self.requested_view.selectionModel().selectedRows()#indexes of column 0 have_network = self.network_box.currentLayer( ) and self.sec_fieldbox.currentField() if have_network: select_sections(sects, self.network_box.currentLayer(), self.sec_fieldbox.currentField(), zoom=True) else: iface.messageBar().pushMessage( 'fitting tool:network layer§ion field not set')
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 grip_testerDockWidget(QDockWidget, FORM_CLASS): closingPlugin = pyqtSignal() def __init__(self, parent=None): super(grip_testerDockWidget, self).__init__(parent) self.setupUi(self) self.connect_button.clicked.connect(self.connect) self.dd = grip_tester_dd.grip_dd(self) self.s10_button.clicked.connect(self.set_s10) self.zm3_button.clicked.connect(self.set_zm3) self.upload_button.clicked.connect(self.upload_run) self.to_hmd_button.clicked.connect(self.download_hmd) self.prepare_database_button.clicked.connect(self.prepare_database) self.search_hmds_button.clicked.connect(self.search_hmds) self.rw = routes_widget(self, self.dd, 'gtest.routes', self.readings_box, self.network_box, self.run_fieldbox, self.f_line_fieldbox, self.sec_fieldbox) self.rw_placeholder.addWidget(self.rw) #self.tabs.insertTab(2,self.rw,'Fitting') self.upload_csv_button.clicked.connect(self.upload_run_csvs) self.init_requested_menu() self.init_missing_menu() self.init_run_menu() self.open_help_button.clicked.connect(self.open_help) self.copy_lengths_button.clicked.connect( lambda: copy_functions.copy_all(self.lengths_view)) self.copy_missing_button.clicked.connect( lambda: copy_functions.copy_all(self.missing_view)) self.copy_benchmarks_button.clicked.connect( lambda: copy_functions.copy_all(self.benchmarks_view)) self.upload_folder_button.clicked.connect(self.upload_folder) def connect(self): if self.dd.exec_(): if self.dd.connected: self.database_label.setText('Connected to %s' % (self.dd.db.databaseName())) self.dd.sql('set search_path to gtest,public;') self.connect_coverage() self.connect_lengths() self.connect_missing() self.connect_benchmarks() self.rw.refresh_runs() self.connect_run_info() self.tabs.currentChanged.connect(self.refresh_coverage) self.coverage_toolbox.currentChanged.connect( self.refresh_coverage) self.requested_model.dataChanged.connect( lambda: self.missing_model.setQuery(self.missing_model. query())) else: self.database_label.setText('Not Connected') #opens help/index.html in default browser def open_help(self): help_path = os.path.join(os.path.dirname(__file__), 'help', 'index.html') help_path = 'file:///' + os.path.abspath(help_path) QDesktopServices.openUrl(QUrl(help_path)) def connect_run_info(self): self.run_info_model = QSqlTableModel(db=self.dd.db) self.run_info_model.setTable('gtest.run_info') self.run_info_model.setSort(self.run_info_model.fieldIndex("run"), Qt.AscendingOrder) self.run_info_model.setEditStrategy(QSqlTableModel.OnFieldChange) self.run_info_view.setModel(self.run_info_model) self.run_info_model.select() def connect_coverage(self): # self.requested_model = QSqlTableModel(db=self.dd.db) self.requested_model = betterTableModel(db=self.dd.db) self.requested_model.setEditStrategy(QSqlTableModel.OnFieldChange) self.requested_model.setTable('gtest.requested') self.requested_model.setEditable(False) #set all cols uneditable self.requested_model.setColEditable( self.requested_model.fieldIndex("note"), True) #make note col editable self.requested_model.setSort(self.requested_model.fieldIndex("sec"), Qt.AscendingOrder) self.requested_view.setModel(self.requested_model) self.requested_view.setColumnHidden( self.requested_model.fieldIndex("pk"), True) #hide pk column self.requested_view.setColumnHidden( self.requested_model.fieldIndex("coverage"), True) #hide coverage column #self.show_all_button.clicked.connect(self.coverage_show_all) #self.show_missing_button.clicked.connect(self.coverage_show_missing) self.show_missing_button.clicked.connect(self.filter_requested) self.show_all_button.clicked.connect(self.filter_requested) self.partly_missing_button.clicked.connect(self.filter_requested) self.filter_requested() self.requested_view.resizeColumnsToContents() def filter_requested(self): if self.show_missing_button.isChecked(): self.requested_model.setFilter("cardinality(hmds)=0") if self.show_all_button.isChecked(): self.requested_model.setFilter('') if self.partly_missing_button.isChecked(): self.requested_model.setFilter( 'cardinality(hmds)>0 and (select count (sec) from gtest.resized where gtest.resized.sec=gtest.requested.sec and gtest.resized.reversed=gtest.requested.reversed and sfc is null)>1' ) self.requested_model.select() def connect_benchmarks(self): self.benchmarks_model = QSqlQueryModel() self.benchmarks_model.setQuery( "select early,mid,late,com from gtest.benchmarks_view order by sec,xsp,s_ch", self.dd.db) self.benchmarks_view.setModel(self.benchmarks_model) self.benchmarks_view.resizeColumnsToContents() def refresh_coverage(self): self.requested_model.select() self.missing_model.setQuery(self.missing_model.query()) self.lengths_model.setQuery(self.lengths_model.query()) self.benchmarks_model.setQuery(self.benchmarks_model.query()) def connect_missing(self): self.missing_model = QSqlQueryModel() self.missing_model.setQuery("select * from gtest.missing_view", self.dd.db) self.missing_view.setModel(self.missing_model) self.missing_view.resizeColumnsToContents() def connect_lengths(self): self.lengths_model = QSqlQueryModel() self.lengths_model.setQuery("select * from gtest.lengths", self.dd.db) self.lengths_view.setModel(self.lengths_model) self.lengths_view.resizeColumnsToContents() #make_copyable(self.lengths_view) def check_connected(self): if self.dd.con: return True else: iface.messageBar().pushMessage( 'fitting tool: Not connected to database') return False def upload_run_csvs(self): if self.check_connected(): files = file_dialogs.load_files_dialog('.csv', 'upload csv') if files: for f in files: #r=self.dd.upload_run_csv(f) r = self.dd.upload_run(f) if r == True: self.upload_log.appendPlainText( 'sucessfully uploaded %s' % (f)) else: self.upload_log.appendPlainText( 'error uploading %s:%s' % (f, str(r))) # self.upload_log.repaint() self.update() #processEvents() self.run_info_model.select() self.rw.refresh_runs() def upload_folder(self): folder = file_dialogs.load_directory_dialog( '.csv', 'upload all .csv in directory') if folder: self.dd.upload_runs(file_dialogs.filter_files(folder, '.csv')) def closeEvent(self, event): self.dd.disconnect() self.closingPlugin.emit() event.accept() def upload_run(self): if self.check_connected(): if self.run_number.text() == '': iface.messageBar().pushMessage( 'fitting tool: run number not set') else: self.dd.sql( "insert into run_info select '{run}',to_date('{date}','dd-mm-yyyy') where not exists (select run from run_info where run='{run}')", { 'run': self.run_number.text(), 'date': str(self.survey_date.date().day()) + '-' + str(self.survey_date.date().month()) + '-' + str(self.survey_date.date().year()) }) if self.s10.text() != '': try: upload_s10(self.run_number.text(), self.s10.text(), db_to_con(self.dd.db)) iface.messageBar().pushMessage( 'fitting tool: uploaded s10:' + str(self.s10.text())) except Exception as e: iface.messageBar().pushMessage( 'fitting tool: error uploading s10:' + self.s10.text() + ': ' + str(e)) if self.zm3.text() != '': try: #zm3,con upload_zm3(self.run_number.text(), self.zm3.text(), db_to_con(self.dd.db)) iface.messageBar().pushMessage( 'fitting tool: uploaded zm3:' + self.zm3.text()) except Exception as e: iface.messageBar().pushMessage( 'fitting tool: error uploading zm3:' + self.zm3.text() + ': ' + str(e)) self.rw.refresh_runs() def set_s10(self): s = file_dialogs.load_file_dialog('.s10', 'load .s10') if s: self.s10.setText(s) def set_zm3(self): s = file_dialogs.load_file_dialog('.zm3', 'load .zm3') if s: self.zm3.setText(s) def download_hmd(self): if self.check_connected(): s = file_dialogs.save_file_dialog('.hmd') print(s) if s: if self.include_snode_box.isChecked(): to_hmd_snode(s, self.forward_box.isChecked(), self.reversed_box.isChecked(), self.dd.db) else: to_hmd(s, self.forward_box.isChecked(), self.reversed_box.isChecked(), self.dd.db) iface.messageBar().pushMessage('fitting tool: saved:' + s) def prepare_database(self): if self.check_connected(): msgBox = QMessageBox() msgBox.setText( "DON'T USE THIS PARTWAY THROUGH THE JOB! because this will erase any data in tables used by this plugin." ) msgBox.setInformativeText("Continue?") msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No) msgBox.setDefaultButton(QMessageBox.No) i = msgBox.exec_() if i == QMessageBox.Yes: self.dd.setup_database() iface.messageBar().pushMessage( 'fitting tool: prepared database') #drop selected run of run_info table def drop_run(self): r = self.run_box.currentText() self.dd.sql("delete from run_info where run='{run}'", {'run': r}) self.rw.get_runs() def search_hmds(self): hmds = file_dialogs.load_files_dialog(ext='.hmd', caption='search hmds') if hmds and self.check_connected(): self.dd.search_hmds(hmds, reset=True) iface.messageBar().pushMessage('fitting tool:searched hmds: ' + ','.join(hmds)) self.missing_model.setQuery( "select * from missing_view") #refresh missing_model self.lengths_model.setQuery("select * from lengths") self.requested_model.select() #for requested view def init_requested_menu(self): self.requested_menu = QMenu() requested_zoom_act = self.requested_menu.addAction('zoom to section') requested_zoom_act.triggered.connect(lambda: self.select_on_network([ i.data() for i in self.requested_view.selectionModel().selectedRows() ])) copy_all_requested_act = self.requested_menu.addAction( 'copy all rows to clipboard') copy_all_requested_act.triggered.connect( lambda: copy_functions.copy_all(self.requested_view)) self.requested_view.setContextMenuPolicy(Qt.CustomContextMenu) self.requested_view.customContextMenuRequested.connect( self.show_requested_menu) #for missing_view def init_missing_menu(self): self.missing_menu = QMenu() act = self.missing_menu.addAction('zoom to section') act.triggered.connect(lambda: self.select_on_network([ i.data() for i in self.missing_view.selectionModel().selectedRows(1) ])) # selectedRows(1) returns column 1 (sec) self.missing_view.setContextMenuPolicy(Qt.CustomContextMenu) self.missing_view.customContextMenuRequested.connect( self.show_missing_menu) #for run_info_view def init_run_menu(self): self.run_info_menu = QMenu() act = self.run_info_menu.addAction('drop run') act.triggered.connect(lambda: self.dd.drop_runs([ str(i.data()) for i in self.run_info_view.selectionModel().selectedRows(0) ])) # selectedRows(0) returns column 0 (run) act.triggered.connect( self.refresh_runs) # selectedRows(0) returns column 0 (sec) self.run_info_view.setContextMenuPolicy(Qt.CustomContextMenu) self.run_info_view.customContextMenuRequested.connect( self.show_run_info_menu) def show_requested_menu(self, pt): self.requested_menu.exec_(self.mapToGlobal(pt)) def show_missing_menu(self, pt): self.missing_menu.exec_(self.mapToGlobal(pt)) def show_run_info_menu(self, pt): self.run_info_menu.exec_(self.mapToGlobal(pt)) def refresh_runs(self): self.rw.get_runs() self.run_info_model.select() #select sec on network def select_on_network(self, sects): # inds=self.requested_view.selectionModel().selectedRows()#indexes of column 0 have_network = self.network_box.currentLayer( ) and self.sec_fieldbox.currentField() if have_network: select_sections(sects, self.network_box.currentLayer(), self.sec_fieldbox.currentField(), zoom=True) else: iface.messageBar().pushMessage( 'fitting tool:network layer§ion field not set')