def test_field_editability_depends_on_feature(self): """ Test QgsVectorLayerUtils.fieldEditabilityDependsOnFeature """ layer = createLayerWithOnePoint() # not joined fields, so answer should be False self.assertFalse( QgsVectorLayerUtils.fieldEditabilityDependsOnFeature(layer, 0)) self.assertFalse( QgsVectorLayerUtils.fieldEditabilityDependsOnFeature(layer, 1)) # joined field layer2 = QgsVectorLayer( "Point?field=fldtxt2:string&field=fldint:integer", "addfeat", "memory") join_info = QgsVectorLayerJoinInfo() join_info.setJoinLayer(layer2) join_info.setJoinFieldName('fldint') join_info.setTargetFieldName('fldint') join_info.setUsingMemoryCache(True) layer.addJoin(join_info) layer.updateFields() self.assertEqual([f.name() for f in layer.fields()], ['fldtxt', 'fldint', 'addfeat_fldtxt2']) self.assertFalse( QgsVectorLayerUtils.fieldEditabilityDependsOnFeature(layer, 0)) self.assertFalse( QgsVectorLayerUtils.fieldEditabilityDependsOnFeature(layer, 1)) # join layer is not editable => regardless of the feature, the field will always be read-only self.assertFalse( QgsVectorLayerUtils.fieldEditabilityDependsOnFeature(layer, 2)) # make join editable layer.removeJoin(layer2.id()) join_info.setEditable(True) join_info.setUpsertOnEdit(True) layer.addJoin(join_info) layer.updateFields() self.assertEqual([f.name() for f in layer.fields()], ['fldtxt', 'fldint', 'addfeat_fldtxt2']) # has upsert on edit => regardless of feature, we can create the join target to make the field editable self.assertFalse( QgsVectorLayerUtils.fieldEditabilityDependsOnFeature(layer, 2)) layer.removeJoin(layer2.id()) join_info.setEditable(True) join_info.setUpsertOnEdit(False) layer.addJoin(join_info) layer.updateFields() self.assertEqual([f.name() for f in layer.fields()], ['fldtxt', 'fldint', 'addfeat_fldtxt2']) # No upsert on edit => depending on feature, we either can edit the field or not, depending on whether # the join target feature already exists or not self.assertTrue( QgsVectorLayerUtils.fieldEditabilityDependsOnFeature(layer, 2))
def buildJoin(self, originalLyr, originalLyrFieldName, joinnedLyr, joinLyrFieldName): """ Builds a join bewteen lyr and joinnedLyr. :param originalLyr: QgsVectorLayer original layer; :param originalLyrFieldName: (str) name of the field; :param joinnedLyr: QgsVectorLayer lyr to be joinned to originalLayer; :param joinLyrFieldName: (str) name of the join field name (usually primary key of joinnedLyr) """ joinObject = QgsVectorLayerJoinInfo() joinObject.setJoinFieldName(joinLyrFieldName) joinObject.setTargetFieldName(originalLyrFieldName) joinObject.setJoinLayer(joinnedLyr) joinObject.setJoinFieldNamesSubset() joinObject.upsertOnEdit(True) #set to enable edit on original lyr joinObject.setCascadedDelete(True) joinObject.setDynamicFormEnabled(True) joinObject.setEditable(True) joinObject.setUsingMemoryCache(True) originalLyr.addJoin(joinObject)
def joinTables(self): d, f = self.lyrPair() for k, v in d.items(): target = QgsProject.instance().mapLayer(k) layerToJoin = QgsProject.instance().mapLayer(v) fieldToJoin = QgsProject.instance() symb = QgsVectorLayerJoinInfo() symb.setJoinFieldName('id_feature') symb.setTargetFieldName('id') symb.setJoinLayerId(layerToJoin.id()) symb.setUsingMemoryCache(True) symb.setEditable(True) symb.setDynamicFormEnabled(True) symb.setUpsertOnEdit(True) symb.setPrefix('') symb.setJoinFieldNamesSubset([ 'ocultar', 'legenda', 'tamanhotxt', 'justtxt', 'orient_txt', 'orient_simb', 'offset_txt', 'offset_simb', 'prioridade', 'offset_txt_x', 'offset_txt_y' ]) symb.setJoinLayer(layerToJoin) target.addJoin(symb)
def joinTables(self): d, f = self.lyrPair() for k, v in d.items(): target = QgsProject.instance().mapLayer(k) layerToJoin = QgsProject.instance().mapLayer(v) """ # tests for previous joined layers - under research i = QgsProject.instance().mapLayers().values() for layer in i: fh_lyr = layer joinsInfo = fh_lyr.vectorJoins() if joinsInfo != 0: QMessageBox.critical(iface.mainWindow(), "Error", "Previously Joins already exists! Please remove joins and try again.") break # ask for remove previous joins. use removeJoinTables() else: """ # target.removeJoin(layerToJoin.id()) fieldToJoin = QgsProject.instance() symb = QgsVectorLayerJoinInfo() symb.setJoinFieldName('id_feature') symb.setTargetFieldName('id') symb.setJoinLayerId(layerToJoin.id()) symb.setUsingMemoryCache(True) symb.setEditable(True) symb.setDynamicFormEnabled(True) symb.setUpsertOnEdit(True) symb.setPrefix('') symb.setJoinFieldNamesSubset([ 'ocultar', 'legenda', 'tamanhotxt', 'justtxt', 'orient_txt', 'orient_simb', 'offset_txt', 'offset_simb', 'prioridade', 'offset_txt_x', 'offset_txt_y' ]) symb.setJoinLayer(layerToJoin) target.addJoin(symb) layerToJoin.startEditing() target.triggerRepaint()
def processAlgorithm(self, parameters, context, feedback): t_file = self.parameterAsVectorLayer( parameters, self.FILE_TABLE, context ) t_troncon = self.parameterAsVectorLayer( parameters, self.SEGMENTS_TABLE, context ) t_obs = self.parameterAsVectorLayer( parameters, self.OBSERVATIONS_TABLE, context ) t_regard = self.parameterAsVectorLayer( parameters, self.MANHOLES_TABLE, context ) g_regard = self.parameterAsVectorLayer( parameters, self.GEOM_MANHOLES, context ) g_troncon = self.parameterAsVectorLayer( parameters, self.GEOM_SEGMENT, context ) g_obs = self.parameterAsVectorLayer( parameters, self.GEOM_OBSERVATION, context ) v_regard = self.parameterAsVectorLayer( parameters, self.VIEW_MANHOLES_GEOLOCALIZED, context ) # define variables variables = context.project().customVariables() variables['itv_rerau_t_file'] = t_file.id() variables['itv_rerau_t_troncon'] = t_troncon.id() variables['itv_rerau_t_obs'] = t_obs.id() variables['itv_rerau_t_regard'] = t_regard.id() variables['itv_rerau_g_regard'] = g_regard.id() variables['itv_rerau_g_troncon'] = g_troncon.id() variables['itv_rerau_g_obs'] = g_obs.id() context.project().setCustomVariables(variables) # define relations relations = [ { 'id': 'fk_obs_id_file', 'name': tr('Link File - Observation'), 'referencingLayer': t_obs.id(), 'referencingField': 'id_file', 'referencedLayer': t_file.id(), 'referencedField': 'id' }, { 'id': 'fk_regard_id_file', 'name': tr('Link File - Manhole'), 'referencingLayer': t_regard.id(), 'referencingField': 'id_file', 'referencedLayer': t_file.id(), 'referencedField': 'id' }, { 'id': 'fk_troncon_id_file', 'name': tr('Link File - Pipe segment'), 'referencingLayer': t_troncon.id(), 'referencingField': 'id_file', 'referencedLayer': t_file.id(), 'referencedField': 'id' }, { 'id': 'fk_obs_id_troncon', 'name': tr('Link Pipe segment - Observation'), 'referencingLayer': t_obs.id(), 'referencingField': 'id_troncon', 'referencedLayer': t_troncon.id(), 'referencedField': 'id' }, { 'id': 'fk_regard_id_geom_regard', 'name': tr('Link Manhole inspection - Reference'), 'referencingLayer': t_regard.id(), 'referencingField': 'id_geom_regard', 'referencedLayer': g_regard.id(), 'referencedField': 'id' }, { 'id': 'fk_troncon_id_geom_trononc', 'name': tr('Link Pipe segment inspection - Reference'), 'referencingLayer': t_troncon.id(), 'referencingField': 'id_geom_troncon', 'referencedLayer': g_troncon.id(), 'referencedField': 'id' } ] relation_manager = context.project().relationManager() for rel_def in relations: feedback.pushInfo( 'Link: {}'.format(rel_def['name']) ) rel = QgsRelation() rel.setId(rel_def['id']) rel.setName(rel_def['name']) rel.setReferencingLayer(rel_def['referencingLayer']) rel.setReferencedLayer(rel_def['referencedLayer']) rel.addFieldPair( rel_def['referencingField'], rel_def['referencedField'] ) rel.setStrength(QgsRelation.Association) relation_manager.addRelation(rel) feedback.pushInfo( 'Count relations {}'.format( len(relation_manager.relations()) ) ) joins = [ { 'layer': t_obs, 'targetField': 'id_troncon', 'joinLayer': t_troncon, 'joinField': 'id', 'fieldNamesSubset': ['ack'] }, { 'layer': g_obs, 'targetField': 'id', 'joinLayer': t_obs, 'joinField': 'id', 'fieldNamesSubset': [] } ] for j_def in joins: layer = j_def['layer'] join = QgsVectorLayerJoinInfo() join.setJoinFieldName(j_def['joinField']) join.setJoinLayerId(j_def['joinLayer'].id()) join.setTargetFieldName(j_def['targetField']) if j_def['fieldNamesSubset']: join.setJoinFieldNamesSubset(j_def['fieldNamesSubset']) join.setUsingMemoryCache(False) join.setPrefix('') join.setEditable(False) join.setCascadedDelete(False) join.setJoinLayer(j_def['joinLayer']) layer.addJoin(join) layer.updateFields() # load styles styles = [ { 'layer': t_file, 'namedStyles': [ { 'file': 'itv_file_fields.qml', 'type': QgsMapLayer.Fields }, { 'file': 'itv_file_actions.qml', 'type': QgsMapLayer.Actions } ] }, { 'layer': t_troncon, 'namedStyles': [ { 'file': 'itv_troncon_fields.qml', 'type': QgsMapLayer.Fields }, { 'file': 'itv_troncon_table.qml', 'type': QgsMapLayer.AttributeTable } ] }, { 'layer': t_obs, 'namedStyles': [ { 'file': 'itv_obs_fields.qml', 'type': QgsMapLayer.Fields }, { 'file': 'itv_obs_table.qml', 'type': QgsMapLayer.AttributeTable } ] }, { 'layer': t_regard, 'namedStyles': [ { 'file': 'itv_regard_fields.qml', 'type': QgsMapLayer.Fields }, { 'file': 'itv_regard_forms.qml', 'type': QgsMapLayer.Forms }, { 'file': 'itv_regard_table.qml', 'type': QgsMapLayer.AttributeTable } ] }, { 'layer': g_regard, 'namedStyles': [ { 'file': 'itv_geom_regard_fields.qml', 'type': QgsMapLayer.Fields }, { 'file': 'itv_geom_regard_symbology.qml', 'type': QgsMapLayer.Symbology } ] }, { 'layer': g_troncon, 'namedStyles': [ { 'file': 'itv_geom_troncon_fields.qml', 'type': QgsMapLayer.Fields }, { 'file': 'itv_geom_troncon_symbology.qml', 'type': QgsMapLayer.Symbology }, { 'file': 'itv_geom_troncon_actions.qml', 'type': QgsMapLayer.Actions } ] }, { 'layer': g_obs, 'namedStyles': [ { 'file': 'itv_geom_obs_fields.qml', 'type': QgsMapLayer.Fields }, { 'file': 'itv_geom_obs_symbology.qml', 'type': QgsMapLayer.Symbology } ] }, { 'layer': v_regard, 'namedStyles': [ { 'file': 'itv_view_regard_fields.qml', 'type': QgsMapLayer.Fields }, { 'file': 'itv_view_regard_symbology.qml', 'type': QgsMapLayer.Symbology }, { 'file': 'itv_view_regard_labeling.qml', 'type': QgsMapLayer.Labeling } ] } ] for style in styles: layer = style['layer'] for n_style in style['namedStyles']: layer.loadNamedStyle( resources_path('styles', n_style['file']), categories=n_style['type'] ) # layer.saveStyleToDatabase('style', 'default style', True, '') layer.triggerRepaint() # Creation de la symbologie g_obs g_obs_rules = ( 'BAA', 'BAB', 'BAC', 'BAD', 'BAE', 'BAF', 'BAG', 'BAH', 'BAI', 'BAJ', 'BAK', 'BAL', 'BAM', 'BAN', 'BAO', 'BAP', 'BBA', 'BBB', 'BBC', 'BBD', 'BBE', 'BBF', 'BBG', 'BBH', 'BCA', 'BCB', 'BCC', 'BDA', 'BDB', 'BDC', 'BDD', 'BDE', 'BDF', 'BDG' ) g_obs_rule_descs = { 'BAA': 'Déformation', 'BAB': 'Fissure', 'BAC': 'Rupture/Effondrement', 'BAD': 'Elt maçonnerie', 'BAE': 'Mortier manquant', 'BAF': 'Dégradation de surface', 'BAG': 'Branchement pénétrant', 'BAH': 'Raccordement défectueux', 'BAI': 'Joint étanchéité apparent', 'BAJ': 'Déplacement d\'assemblage', 'BAK': 'Défaut de révêtement', 'BAL': 'Réparation défectueuse', 'BAM': 'Défaut soudure', 'BAN': 'Conduite poreuse', 'BAO': 'Sol visible', 'BAP': 'Trou visible', 'BBA': 'Racines', 'BBB': 'Dépots Adhérents', 'BBC': 'Dépôts', 'BBD': 'Entrée de terre', 'BBE': 'Autres obstacles', 'BBF': 'Infiltration', 'BBG': 'Exfiltration', 'BBH': 'Vermine', 'BCA': 'Raccordement', 'BCB': 'Réparation', 'BCC': 'Courbure de collecteur', 'BDA': 'Photographie générale', 'BDB': 'Remarque générale', 'BDC': 'Inspection abandonnée', 'BDD': 'Niveau d\'eau', 'BDE': 'Ecoulement dans une canlisation entrante', 'BDF': 'Atmosphère canalisation', 'BDG': 'Perte de visibilité' } g_obs_rootrule = QgsRuleBasedRenderer.Rule(None) rendering_pass_idx = len(g_obs_rules) for rule in g_obs_rules: # get svg path svg_path = resources_path('styles', 'img_obs', rule + '.svg') # create svg symbol layer svg_symbol_layer = QgsSvgMarkerSymbolLayer(svg_path) svg_symbol_layer.setRenderingPass(rendering_pass_idx) # create white square symbol layer for the backend simple_symbol_layer = QgsSimpleMarkerSymbolLayer( shape=QgsSimpleMarkerSymbolLayerBase.Circle, size=svg_symbol_layer.size(), color=QColor('white'), strokeColor=QColor('white') ) simple_symbol_layer.setRenderingPass(rendering_pass_idx) # create marker svg_marker = QgsMarkerSymbol() # set the backend symbol layer svg_marker.changeSymbolLayer(0, simple_symbol_layer) # add svg symbol layer svg_marker.appendSymbolLayer(svg_symbol_layer) # create rule svg_rule = QgsRuleBasedRenderer.Rule( svg_marker, 0, 10000, QgsExpression.createFieldEqualityExpression('a', rule), rule ) if rule in g_obs_rule_descs: svg_rule.setLabel(g_obs_rule_descs[rule]) svg_rule.setDescription('{}: {}'.format( rule, g_obs_rule_descs[rule] )) # add rule g_obs_rootrule.appendChild(svg_rule) rendering_pass_idx -= 1 g_obs_rootrule.appendChild( QgsRuleBasedRenderer.Rule( QgsMarkerSymbol.createSimple( { 'name': 'circle', 'color': '#0000b2', 'outline_color': '#0000b2', 'size': '1' } ), 0, 10000, 'ELSE', 'Autres' ) ) g_obs.setRenderer(QgsRuleBasedRenderer(g_obs_rootrule)) feedback.pushInfo('Project has been setup') return {}
def test_field_is_read_only(self): """ Test fieldIsReadOnly """ layer = createLayerWithOnePoint() # layer is not editable => all fields are read only self.assertTrue(QgsVectorLayerUtils.fieldIsReadOnly(layer, 0)) self.assertTrue(QgsVectorLayerUtils.fieldIsReadOnly(layer, 1)) layer.startEditing() self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 0)) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 1)) field = QgsField('test', QVariant.String) layer.addAttribute(field) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 0)) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 1)) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 2)) # simulate read-only field from provider field = QgsField('test2', QVariant.String) field.setReadOnly(True) layer.addAttribute(field) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 0)) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 1)) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 2)) self.assertTrue(QgsVectorLayerUtils.fieldIsReadOnly(layer, 3)) layer.rollBack() layer.startEditing() # edit form config specifies read only form_config = layer.editFormConfig() form_config.setReadOnly(1, True) layer.setEditFormConfig(form_config) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 0)) self.assertTrue(QgsVectorLayerUtils.fieldIsReadOnly(layer, 1)) form_config.setReadOnly(1, False) layer.setEditFormConfig(form_config) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 0)) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 1)) # joined field layer2 = QgsVectorLayer( "Point?field=fldtxt2:string&field=fldint:integer", "addfeat", "memory") join_info = QgsVectorLayerJoinInfo() join_info.setJoinLayer(layer2) join_info.setJoinFieldName('fldint') join_info.setTargetFieldName('fldint') join_info.setUsingMemoryCache(True) layer.addJoin(join_info) layer.updateFields() self.assertEqual([f.name() for f in layer.fields()], ['fldtxt', 'fldint', 'addfeat_fldtxt2']) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 0)) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 1)) # join layer is not editable self.assertTrue(QgsVectorLayerUtils.fieldIsReadOnly(layer, 2)) # make join editable layer.removeJoin(layer2.id()) join_info.setEditable(True) layer.addJoin(join_info) layer.updateFields() self.assertEqual([f.name() for f in layer.fields()], ['fldtxt', 'fldint', 'addfeat_fldtxt2']) # should still be read only -- the join layer itself is not editable self.assertTrue(QgsVectorLayerUtils.fieldIsReadOnly(layer, 2)) layer2.startEditing() self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 2)) # but now we set a property on the join layer which blocks editing for the feature... form_config = layer2.editFormConfig() form_config.setReadOnly(0, True) layer2.setEditFormConfig(form_config) # should now be read only -- the joined layer edit form config prohibits edits self.assertTrue(QgsVectorLayerUtils.fieldIsReadOnly(layer, 2))
def testJoinedFieldIsEditableRole(self): layer = QgsVectorLayer("Point?field=id_a:integer", "addfeat", "memory") layer2 = QgsVectorLayer("Point?field=id_b:integer&field=value_b", "addfeat", "memory") QgsProject.instance().addMapLayers([layer, layer2]) # editable join join_info = QgsVectorLayerJoinInfo() join_info.setTargetFieldName("id_a") join_info.setJoinLayer(layer2) join_info.setJoinFieldName("id_b") join_info.setPrefix("B_") join_info.setEditable(True) join_info.setUpsertOnEdit(True) layer.addJoin(join_info) m = QgsFieldModel() m.setLayer(layer) self.assertIsNone( m.data(m.indexFromName('id_a'), QgsFieldModel.JoinedFieldIsEditable)) self.assertTrue( m.data(m.indexFromName('B_value_b'), QgsFieldModel.JoinedFieldIsEditable)) self.assertIsNone( m.data(m.indexFromName('an expression'), QgsFieldModel.JoinedFieldIsEditable)) self.assertIsNone( m.data(m.indexFromName(None), QgsFieldModel.JoinedFieldIsEditable)) m.setAllowExpression(True) m.setExpression('an expression') self.assertIsNone( m.data(m.indexFromName('an expression'), QgsFieldModel.JoinedFieldIsEditable)) m.setAllowEmptyFieldName(True) self.assertIsNone( m.data(m.indexFromName(None), QgsFieldModel.JoinedFieldIsEditable)) proxy_m = QgsFieldProxyModel() proxy_m.setFilters(QgsFieldProxyModel.AllTypes | QgsFieldProxyModel.HideReadOnly) proxy_m.sourceFieldModel().setLayer(layer) self.assertEqual(proxy_m.rowCount(), 2) self.assertEqual(proxy_m.data(proxy_m.index(0, 0)), 'id_a') self.assertEqual(proxy_m.data(proxy_m.index(1, 0)), 'B_value_b') # not editable join layer3 = QgsVectorLayer("Point?field=id_a:integer", "addfeat", "memory") QgsProject.instance().addMapLayers([layer3]) join_info = QgsVectorLayerJoinInfo() join_info.setTargetFieldName("id_a") join_info.setJoinLayer(layer2) join_info.setJoinFieldName("id_b") join_info.setPrefix("B_") join_info.setEditable(False) layer3.addJoin(join_info) m = QgsFieldModel() m.setLayer(layer3) self.assertIsNone( m.data(m.indexFromName('id_a'), QgsFieldModel.JoinedFieldIsEditable)) self.assertFalse( m.data(m.indexFromName('B_value_b'), QgsFieldModel.JoinedFieldIsEditable)) self.assertIsNone( m.data(m.indexFromName('an expression'), QgsFieldModel.JoinedFieldIsEditable)) self.assertIsNone( m.data(m.indexFromName(None), QgsFieldModel.JoinedFieldIsEditable)) m.setAllowExpression(True) m.setExpression('an expression') self.assertIsNone( m.data(m.indexFromName('an expression'), QgsFieldModel.JoinedFieldIsEditable)) m.setAllowEmptyFieldName(True) self.assertIsNone( m.data(m.indexFromName(None), QgsFieldModel.JoinedFieldIsEditable)) proxy_m = QgsFieldProxyModel() proxy_m.sourceFieldModel().setLayer(layer3) proxy_m.setFilters(QgsFieldProxyModel.AllTypes | QgsFieldProxyModel.HideReadOnly) self.assertEqual(proxy_m.rowCount(), 1) self.assertEqual(proxy_m.data(proxy_m.index(0, 0)), 'id_a')