def setUpClass(cls): """Run before all tests""" cls.dbconn = 'dbname=\'qgis_test\'' if 'QGIS_PGTEST_DB' in os.environ: cls.dbconn = os.environ['QGIS_PGTEST_DB'] # Create test layers cls.vl = QgsVectorLayer(cls.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=', 'test', 'postgres') assert cls.vl.isValid() cls.provider = cls.vl.dataProvider() cls.poly_vl = QgsVectorLayer(cls.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=', 'test', 'postgres') assert cls.poly_vl.isValid() cls.poly_provider = cls.poly_vl.dataProvider() QgsEditorWidgetRegistry.instance().initEditors()
def setUpClass(cls): """ Setup the involved layers and relations for a n:m relation :return: """ QgsEditorWidgetRegistry.initEditors() cls.dbconn = "service='qgis_test'" if "QGIS_PGTEST_DB" in os.environ: cls.dbconn = os.environ["QGIS_PGTEST_DB"] # Create test layer cls.vl_b = QgsVectorLayer( cls.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."books" sql=', "books", "postgres" ) cls.vl_a = QgsVectorLayer( cls.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."authors" sql=', "authors", "postgres" ) cls.vl_link = QgsVectorLayer( cls.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."books_authors" sql=', "books_authors", "postgres", ) QgsProject.instance().addMapLayer(cls.vl_b) QgsProject.instance().addMapLayer(cls.vl_a) QgsProject.instance().addMapLayer(cls.vl_link) cls.relMgr = QgsProject.instance().relationManager() cls.rel_a = QgsRelation() cls.rel_a.setReferencingLayer(cls.vl_link.id()) cls.rel_a.setReferencedLayer(cls.vl_a.id()) cls.rel_a.addFieldPair("fk_author", "pk") cls.rel_a.setRelationId("rel_a") assert cls.rel_a.isValid() cls.relMgr.addRelation(cls.rel_a) cls.rel_b = QgsRelation() cls.rel_b.setReferencingLayer(cls.vl_link.id()) cls.rel_b.setReferencedLayer(cls.vl_b.id()) cls.rel_b.addFieldPair("fk_book", "pk") cls.rel_b.setRelationId("rel_b") assert cls.rel_b.isValid() cls.relMgr.addRelation(cls.rel_b) # Our mock QgsVectorLayerTools, that allow injecting data where user input is expected cls.vltools = VlTools() assert cls.vl_a.isValid() assert cls.vl_b.isValid() assert cls.vl_link.isValid()
def __init__(self, iface): self.iface = iface try: from .tests import testerplugin from qgistester.tests import addTestModule addTestModule(testerplugin, 'MIL-STD-2525') except: pass self._rendererMetadata = MilStd2525RendererMetadata() self._widgetWrapperFactory = SIDCWidgetWrapperFactory() QgsRendererV2Registry.instance().addRenderer(self._rendererMetadata) QgsEditorWidgetRegistry.instance().registerWidget('SIDC code editor', self._widgetWrapperFactory)
def test_ValueMap_representValue(self): layer = QgsVectorLayer("none?field=number1:integer&field=number2:double&field=text1:string&field=number3:integer&field=number4:double&field=text2:string", "layer", "memory") assert layer.isValid() QgsMapLayerRegistry.instance().addMapLayer(layer) f = QgsFeature() f.setAttributes([2, 2.5, 'NULL', None, None, None]) assert layer.dataProvider().addFeatures([f]) reg = QgsEditorWidgetRegistry.instance() factory = reg.factory("ValueMap") self.assertIsNotNone(factory) # Tests with different value types occurring in the value map config = {'two': '2', 'twoandhalf': '2.5', 'NULL text': 'NULL', 'nothing': self.VALUEMAP_NULL_TEXT} self.assertEqual(factory.representValue(layer, 0, config, None, 2), 'two') self.assertEqual(factory.representValue(layer, 1, config, None, 2.5), 'twoandhalf') self.assertEqual(factory.representValue(layer, 2, config, None, 'NULL'), 'NULL text') # Tests with null values of different types, if value map contains null self.assertEqual(factory.representValue(layer, 3, config, None, None), 'nothing') self.assertEqual(factory.representValue(layer, 4, config, None, None), 'nothing') self.assertEqual(factory.representValue(layer, 5, config, None, None), 'nothing') # Tests with fallback display for different value types config = {} self.assertEqual(factory.representValue(layer, 0, config, None, 2), '(2)') self.assertEqual(factory.representValue(layer, 1, config, None, 2.5), '(2.50000)') self.assertEqual(factory.representValue(layer, 2, config, None, 'NULL'), '(NULL)') # Tests with fallback display for null in different types of fields self.assertEqual(factory.representValue(layer, 3, config, None, None), '(NULL)') self.assertEqual(factory.representValue(layer, 4, config, None, None), '(NULL)') self.assertEqual(factory.representValue(layer, 5, config, None, None), '(NULL)') QgsMapLayerRegistry.instance().removeAllMapLayers()
def handleValueRelations(self, new_layer, ref_native_col_num, ref_foreign_col_num, selected_layer): """ Create a ValueRelation widget from the field numbers for the selected layer """ fields = new_layer.fields() foreign_column = fields[ref_foreign_col_num - 1].name() fields = selected_layer.fields() native_column = fields[ref_native_col_num - 1].name() if native_column and foreign_column: column_index = ref_native_col_num - 1 new_layer_id = new_layer.id() widget_type = QgsEditorWidgetRegistry().findBest( selected_layer, column_index.displayName()) selected_layer.setEditorWidgetSetup(column_index, widget_type) selected_layer.editFormConfig().setWidgetConfig( column_index, { 'Layer': new_layer_id, 'Key': foreign_column, 'Value': foreign_column, "AllowMulti": False, "AllowNull": False, "OrderByValue": True }) # Repeat the entire process for the layer which was just added self.identifyRelations(new_layer) self.alterForm(new_layer)
def setReferencingFeature(self, feature=QgsFeature()): self.deactivateMapTool() self.referencingFeature = QgsFeature(feature) self.deleteWrapper() # disable relation reference widget if no referencing feature self.referencedFeatureLayout.setEnabled(feature.isValid()) # set line edit if not self.relation.isValid() or not feature.isValid(): self.referencingFeatureLineEdit.clear() return self.referencingFeatureLineEdit.setText("%s" % feature.id()) fieldIdx = self.referencingFieldIndex() widgetConfig = self.relation.referencingLayer().editorWidgetV2Config(fieldIdx) self.relationWidgetWrapper = QgsEditorWidgetRegistry.instance().create("RelationReference", self.relation.referencingLayer(), fieldIdx, widgetConfig, self.relationReferenceWidget, self, self.editorContext) self.relationWidgetWrapper.setEnabled(self.relation.referencingLayer().isEditable()) self.relationWidgetWrapper.setValue(feature[fieldIdx]) self.relationWidgetWrapper.valueChanged.connect(self.foreignKeyChanged) # override field definition to allow map identification self.relationReferenceWidget.setAllowMapIdentification(True) self.relationReferenceWidget.setEmbedForm(False) # update drawn link self.highlightReferencingFeature() self.drawLink()
def setReferencingFeature(self, feature=QgsFeature()): self.deactivateMapTool() self.referencingFeature = QgsFeature(feature) self.deleteWrapper() # disable relation reference widget if no referencing feature self.referencedFeatureLayout.setEnabled(feature.isValid()) # set line edit if not self.relation.isValid() or not feature.isValid(): self.referencingFeatureLineEdit.clear() return self.referencingFeatureLineEdit.setText("%s" % feature.id()) fieldIdx = self.referencingFieldIndex() widgetConfig = self.relation.referencingLayer().editorWidgetV2Config( fieldIdx) self.relationWidgetWrapper = QgsEditorWidgetRegistry.instance().create( "RelationReference", self.relation.referencingLayer(), fieldIdx, widgetConfig, self.relationReferenceWidget, self, self.editorContext) self.relationWidgetWrapper.setEnabled( self.relation.referencingLayer().isEditable()) self.relationWidgetWrapper.setValue(feature[fieldIdx]) self.relationWidgetWrapper.valueChanged.connect(self.foreignKeyChanged) # override field definition to allow map identification self.relationReferenceWidget.setAllowMapIdentification(True) self.relationReferenceWidget.setEmbedForm(False) # update drawn link self.highlightReferencingFeature() self.drawLink()
def testStringWithMaxLen(self): """ tests that text edit wrappers correctly handle string fields with a maximum length """ layer = QgsVectorLayer("none?field=fldint:integer", "layer", "memory") assert layer.isValid() layer.dataProvider().addAttributes([QgsField('max', QVariant.String, 'string', 10), QgsField('nomax', QVariant.String, 'string', 0)]) layer.updateFields() QgsMapLayerRegistry.instance().addMapLayer(layer) reg = QgsEditorWidgetRegistry.instance() config = {'IsMultiline': 'True'} # first test for field without character limit editor = QTextEdit() editor.setPlainText('this_is_a_long_string') w = reg.create('TextEdit', layer, 2, config, editor, None) self.assertEqual(w.value(), 'this_is_a_long_string') # next test for field with character limit editor = QTextEdit() editor.setPlainText('this_is_a_long_string') w = reg.create('TextEdit', layer, 1, config, editor, None) self.assertEqual(w.value(), 'this_is_a_') QgsMapLayerRegistry.instance().removeAllMapLayers()
def setUpClass(cls): """ Setup the involved layers and relations for a n:m relation :return: """ QgsEditorWidgetRegistry.initEditors() cls.dbconn = u'dbname=\'qgis_test\' host=localhost port=5432 user=\'postgres\' password=\'postgres\'' if 'QGIS_PGTEST_DB' in os.environ: cls.dbconn = os.environ['QGIS_PGTEST_DB'] # Create test layer cls.vl_b = QgsVectorLayer(cls.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."books" sql=', 'test', 'postgres') cls.vl_a = QgsVectorLayer(cls.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."authors" sql=', 'test', 'postgres') cls.vl_link = QgsVectorLayer(cls.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."books_authors" sql=', 'test', 'postgres') QgsMapLayerRegistry.instance().addMapLayer(cls.vl_b) QgsMapLayerRegistry.instance().addMapLayer(cls.vl_a) QgsMapLayerRegistry.instance().addMapLayer(cls.vl_link) relMgr = QgsProject.instance().relationManager() cls.rel_a = QgsRelation() cls.rel_a.setReferencingLayer(cls.vl_link.id()) cls.rel_a.setReferencedLayer(cls.vl_a.id()) cls.rel_a.addFieldPair('fk_author', 'pk') cls.rel_a.setRelationId('rel_a') assert(cls.rel_a.isValid()) relMgr.addRelation(cls.rel_a) cls.rel_b = QgsRelation() cls.rel_b.setReferencingLayer(cls.vl_link.id()) cls.rel_b.setReferencedLayer(cls.vl_b.id()) cls.rel_b.addFieldPair('fk_book', 'pk') cls.rel_b.setRelationId('rel_b') assert(cls.rel_b.isValid()) relMgr.addRelation(cls.rel_b) # Our mock QgsVectorLayerTools, that allow injecting data where user input is expected cls.vltools = VlTools() assert(cls.vl_a.isValid()) assert(cls.vl_b.isValid()) assert(cls.vl_link.isValid())
def testEditorWidgetTypes(self): """Test that editor widget types can be fetched from the qgis_editor_widget_styles table""" vl = QgsVectorLayer('%s table="qgis_test"."widget_styles" sql=' % (self.dbconn), "widget_styles", "postgres") self.assertTrue(vl.isValid()) fields = vl.dataProvider().fields() setup1 = fields.field("fld1").editorWidgetSetup() self.assertFalse(setup1.isNull()) self.assertEqual(setup1.type(), "FooEdit") self.assertEqual(setup1.config(), {"param1": "value1", "param2": "2"}) best1 = QgsEditorWidgetRegistry.instance().findBest(vl, "fld1") self.assertEqual(best1.type(), "FooEdit") self.assertEqual(best1.config(), setup1.config()) self.assertTrue(fields.field("fld2").editorWidgetSetup().isNull()) best2 = QgsEditorWidgetRegistry.instance().findBest(vl, "fld2") self.assertEqual(best2.type(), "TextEdit")
def setUpClass(cls): """Run before all tests""" cls.dbconn = 'dbname=\'qgis_test\'' if 'QGIS_PGTEST_DB' in os.environ: cls.dbconn = os.environ['QGIS_PGTEST_DB'] # Create test layers cls.vl = QgsVectorLayer( cls.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=', 'test', 'postgres') assert cls.vl.isValid() cls.provider = cls.vl.dataProvider() cls.poly_vl = QgsVectorLayer( cls.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=', 'test', 'postgres') assert cls.poly_vl.isValid() cls.poly_provider = cls.poly_vl.dataProvider() QgsEditorWidgetRegistry.instance().initEditors() cls.con = psycopg2.connect(cls.dbconn)
def __createRangeWidget(self, allownull=False): """ create a range widget """ reg = QgsEditorWidgetRegistry.instance() configWdg = reg.createConfigWidget('Range', self.layer, 1, None) config = configWdg.config() # if null shall be allowed if allownull: config["AllowNull"] = allownull rangewidget = reg.create('Range', self.layer, 1, config, None, None) return rangewidget
def setUpClass(cls): """Run before all tests""" cls.dbconn = "dbname='qgis_test'" if "QGIS_PGTEST_DB" in os.environ: cls.dbconn = os.environ["QGIS_PGTEST_DB"] # Create test layers cls.vl = QgsVectorLayer( cls.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."someData" (geom) sql=', "test", "postgres", ) assert cls.vl.isValid() cls.provider = cls.vl.dataProvider() cls.poly_vl = QgsVectorLayer( cls.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=', "test", "postgres", ) assert cls.poly_vl.isValid() cls.poly_provider = cls.poly_vl.dataProvider() QgsEditorWidgetRegistry.instance().initEditors() cls.con = psycopg2.connect(cls.dbconn)
def __createRangeWidget(self, allownull=False): """ create a range widget """ reg = QgsEditorWidgetRegistry.instance() configWdg = reg.createConfigWidget('Range', self.layer, 1, None) config = configWdg.config() # if null shall be allowed if allownull == True: config["AllowNull"] = allownull rangewidget = reg.create('Range', self.layer, 1, config, None, None) return rangewidget
def test_ValueMap_set_get(self): layer = QgsVectorLayer("none?field=number:integer", "layer", "memory") assert layer.isValid() QgsMapLayerRegistry.instance().addMapLayer(layer) reg = QgsEditorWidgetRegistry.instance() configWdg = reg.createConfigWidget('ValueMap', layer, 0, None) config = {'two': '2', 'twoandhalf': '2.5', 'NULL text': 'NULL', 'nothing': self.VALUEMAP_NULL_TEXT} # Set a configuration containing values and NULL and check if it # is returned intact. configWdg.setConfig(config) self.assertEqual(configWdg.config(), config) QgsMapLayerRegistry.instance().removeAllMapLayers()
def doAttributeTest(self, idx, expected): reg = QgsEditorWidgetRegistry.instance() configWdg = reg.createConfigWidget('TextEdit', self.layer, idx, None) config = configWdg.config() editwidget = reg.create('TextEdit', self.layer, idx, config, None, None) editwidget.setValue('value') assert editwidget.value() == expected[0] editwidget.setValue(123) assert editwidget.value() == expected[1] editwidget.setValue(None) assert editwidget.value() == expected[2] editwidget.setValue(NULL) assert editwidget.value() == expected[3]
def test_ValueRelation_representValue(self): first_layer = QgsVectorLayer("none?field=foreign_key:integer", "first_layer", "memory") assert first_layer.isValid() second_layer = QgsVectorLayer("none?field=pkid:integer&field=decoded:string", "second_layer", "memory") assert second_layer.isValid() QgsMapLayerRegistry.instance().addMapLayer(second_layer) f = QgsFeature() f.setAttributes([123]) assert first_layer.dataProvider().addFeatures([f]) f = QgsFeature() f.setAttributes([123, 'decoded_val']) assert second_layer.dataProvider().addFeatures([f]) reg = QgsEditorWidgetRegistry.instance() factory = reg.factory("ValueRelation") self.assertIsNotNone(factory) # Everything valid config = {'Layer': second_layer.id(), 'Key': 'pkid', 'Value': 'decoded'} self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), 'decoded_val') # Code not find match in foreign layer config = {'Layer': second_layer.id(), 'Key': 'pkid', 'Value': 'decoded'} self.assertEqual(factory.representValue(first_layer, 0, config, None, '456'), '(456)') # Missing Layer config = {'Key': 'pkid', 'Value': 'decoded'} self.assertEqual(factory.representValue(first_layer, 0, config, None, '456'), '(456)') # Invalid Layer config = {'Layer': 'invalid', 'Key': 'pkid', 'Value': 'decoded'} self.assertEqual(factory.representValue(first_layer, 0, config, None, '456'), '(456)') # Invalid Key config = {'Layer': second_layer.id(), 'Key': 'invalid', 'Value': 'decoded'} self.assertEqual(factory.representValue(first_layer, 0, config, None, '456'), '(456)') # Invalid Value config = {'Layer': second_layer.id(), 'Key': 'pkid', 'Value': 'invalid'} self.assertEqual(factory.representValue(first_layer, 0, config, None, '456'), '(456)') QgsMapLayerRegistry.instance().removeMapLayer(second_layer.id())
def __init__(self, iface, data, data_path=""): QDialog.__init__(self) self.setupUi(self) self.settings = MySettings() self.data = data self.currentProjectId = None self.channelNameEdit.setFocus() self.cancel = False self.data_path_line_edit.setText(data_path) self.pdf_path_widget.setDefaultRoot(data_path) self.cannotImportLabel.hide() self.progressBar.setTextVisible(True) self.progressBar.hide() self.cancelButton.hide() self.pdf_path_widget.setDefaultRoot(data_path) self.relationWidgetWrapper = None maintenance_layer = QgsMapLayerRegistry.instance().mapLayer(self.settings.value("maintenance_layer")) if maintenance_layer is not None: field_idx = maintenance_layer.fieldNameIndex('fk_operating_company') widget_config = maintenance_layer.editorWidgetV2Config(field_idx) editor_context = QgsAttributeEditorContext() editor_context.setVectorLayerTools(iface.vectorLayerTools()) self.relationWidgetWrapper = QgsEditorWidgetRegistry.instance().create("ValueRelation", maintenance_layer, field_idx, widget_config, self.operatingCompanyComboBox, self, editor_context) self.sectionWidget.finish_init(iface, self.data) for p_id, project in self.data.items(): self.projectCombo.addItem(project['Name'], p_id) self.channelNameEdit.setText('')
def represent_value(values, feature, parent): """ Returns a fields representation using the layer widget configuration <h4>Syntax</h4> <p>represent_value(<i>value</i>, <i>layername</i>, <i>fieldname</i>)</p> <h4>Arguments</h4> <p><i> value</i> → value of a field. This value will be represented. <p><i> layername</i> → a string. Must be the either the layer id or the layer name of the layer on which this feature is located.</p> <p><i> fieldname</i> → a string. Must be a field name on the layer.</p> <h4>Example</h4> <p><pre>represent_value("type", 'type', 'houses')</pre></p> """ value=values[0] field_name=values[1] layer_name=values[2] layers = QgsMapLayerRegistry.instance().mapLayers() try: layer = layers[layer_name] except KeyError: try: layer = [l for l in layers.iteritems() if l[1].name() == layer_name][0][1] except IndexError: parent.setEvalErrorString(u'No layer with id or name {} found'.format(layer_name)) return False field_index = layer.fields().fieldNameIndex(field_name) if field_index < 0: parent.setEvalErrorString(u'Field with name {} not found on layer'.format(field_name, layer_name)) return False widget_type = layer.editFormConfig().widgetType(field_index) widget_config = layer.editFormConfig().widgetConfig(field_index) widget_factory = QgsEditorWidgetRegistry.instance().factory(widget_type) return widget_factory.representValue(layer, field_index, widget_config, None, value)
def _populate_widget_factories(self): """ We use the widget factories for proper representation of string values for different field types. This is preferred to writing custom value formatters based on the data type. """ if not self._vector_layer.isValid(): return fields = self._vector_layer.dataProvider().fields() for i in range(fields.count()): field_name = fields.at(i).name() widget_type = self._vector_layer.editFormConfig().widgetType(i) widget_factory = QgsEditorWidgetRegistry.instance().factory( widget_type) if widget_factory: self._col_widget_factories[field_name] = widget_factory widget_config = self._vector_layer.editFormConfig().\ widgetConfig(i) self._col_widget_config[field_name] = widget_config self._layer_col_idx[field_name] = i cache = widget_factory.createCache(self._vector_layer, i, widget_config) self._col_cache[field_name] = cache
import qgis # NOQA from qgis.gui import (QgsSearchWidgetWrapper, QgsAttributeFormEditorWidget, QgsSearchWidgetToolButton, QgsDefaultSearchWidgetWrapper, QgsAttributeForm, QgsEditorWidgetRegistry ) from qgis.core import (QgsVectorLayer) from qgis.PyQt.QtWidgets import QWidget, QDateTimeEdit from qgis.PyQt.QtCore import QDateTime, QDate, QTime from qgis.testing import start_app, unittest start_app() QgsEditorWidgetRegistry.instance().initEditors() class PyQgsAttributeFormEditorWidget(unittest.TestCase): def testCurrentFilterExpression(self): """ Test creating an expression using the widget""" layer = QgsVectorLayer("Point?field=fldint:integer", "test", "memory") parent = QWidget() w = QgsDefaultSearchWidgetWrapper(layer, 0, parent) af = QgsAttributeFormEditorWidget(None, None) af.setSearchWidgetWrapper(w) # test that filter combines both current value in search widget wrapper and flags from search tool button w.lineEdit().setText('5.5')
def setUpClass(cls): QgsEditorWidgetRegistry.initEditors()
def test_RelationReference_representValue(self): first_layer = QgsVectorLayer("none?field=foreign_key:integer", "first_layer", "memory") assert first_layer.isValid() second_layer = QgsVectorLayer("none?field=pkid:integer&field=decoded:string", "second_layer", "memory") assert second_layer.isValid() QgsMapLayerRegistry.instance().addMapLayers([first_layer, second_layer]) f = QgsFeature() f.setAttributes([123]) assert first_layer.dataProvider().addFeatures([f]) f = QgsFeature() f.setAttributes([123, 'decoded_val']) assert second_layer.dataProvider().addFeatures([f]) relMgr = QgsProject.instance().relationManager() reg = QgsEditorWidgetRegistry.instance() factory = reg.factory("RelationReference") self.assertIsNotNone(factory) rel = QgsRelation() rel.setRelationId('rel1') rel.setRelationName('Relation Number One') rel.setReferencingLayer(first_layer.id()) rel.setReferencedLayer(second_layer.id()) rel.addFieldPair('foreign_key', 'pkid') assert(rel.isValid()) relMgr.addRelation(rel) # Everything valid config = {'Relation': rel.id()} second_layer.setDisplayExpression('decoded') self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), 'decoded_val') # Code not find match in foreign layer config = {'Relation': rel.id()} second_layer.setDisplayExpression('decoded') self.assertEqual(factory.representValue(first_layer, 0, config, None, '456'), '456') # Invalid relation id config = {'Relation': 'invalid'} second_layer.setDisplayExpression('decoded') self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), '123') # No display expression config = {'Relation': rel.id()} second_layer.setDisplayExpression(None) self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), '123') # Invalid display expression config = {'Relation': rel.id()} second_layer.setDisplayExpression('invalid +') self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), '123') # Missing relation config = {} second_layer.setDisplayExpression('decoded') self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), '123') # Inconsistent layer provided to representValue() config = {'Relation': rel.id()} second_layer.setDisplayExpression('decoded') self.assertEqual(factory.representValue(second_layer, 0, config, None, '123'), '123') # Inconsistent idx provided to representValue() config = {'Relation': rel.id()} second_layer.setDisplayExpression('decoded') self.assertEqual(factory.representValue(first_layer, 1, config, None, '123'), '123') # Invalid relation rel = QgsRelation() rel.setRelationId('rel2') rel.setRelationName('Relation Number Two') rel.setReferencingLayer(first_layer.id()) rel.addFieldPair('foreign_key', 'pkid') self.assertFalse(rel.isValid()) relMgr.addRelation(rel) config = {'Relation': rel.id()} second_layer.setDisplayExpression('decoded') self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), '123') QgsMapLayerRegistry.instance().removeAllMapLayers()
# coding: utf-8 from qgis.gui import QgsEditorWidgetRegistry from qgis.utils import iface editor_widget_registry_instance = QgsEditorWidgetRegistry.instance() # List available widgets in Text edition in tab Fields of a vector layer print editor_widget_registry_instance.factories() # Return a list of QgsEditorWidgetFactory print editor_widget_registry_instance.factories().keys() # Get QgsEditorWidgetFactory print editor_widget_registry_instance.factory(u'Range') print editor_widget_registry_instance.factory(u'RelationReference') layer = iface.activeLayer() editFormConfig = layer.editFormConfig() # QgsEditFormConfig idx = layer.dataProvider().fieldNameIndex('ADM0_A3') widgetType = editFormConfig.widgetType(idx) widgetConfig = editFormConfig.widgetConfig(idx) wrapper = QgsEditorWidgetRegistry.instance().create( widgetType, layer, idx, widgetConfig, None, None) # QgsEditorWidgetWrapper widget = wrapper.widget() """ Classes below inherit from QgsEditorWidgetFactory and are the one really used. They are casted QgsCheckboxWidgetFactory QgsClassificationWidgetWrapperFactory QgsColorWidgetFactory
if self.mLabel is not None: self.mLineEdit.setText(fileName) class SimpleFilenameWidgetWrapperConfig(QgsEditorConfigWidget): def __init__(self, layer, idx, parent): QgsEditorConfigWidget.__init__(self, layer, idx, parent) self.setLayout(QHBoxLayout()) self.ruleEdit = QLabel(self) self.ruleEdit.setText(QCoreApplication.translate('SimpleFilenameWidgetWrapperConfig','A filename without extension editor widget.')) self.layout().addWidget(self.ruleEdit) def config(self): return {} def setConfig(self, config): pass class SimpleFilenameWidgetWrapperFactory(QgsEditorWidgetFactory): def __init__(self): QgsEditorWidgetFactory.__init__(self, QCoreApplication.translate('SimpleFilenameWidgetWrapperFactory','Simple Filename')) def create(self, layer, fieldIdx, editor, parent): return SimpleFilenameWidgetWrapper(layer, fieldIdx, editor, parent) def configWidget(self, layer, idx, parent): return SimpleFilenameWidgetWrapperConfig(layer, idx, parent) myFactory = SimpleFilenameWidgetWrapperFactory() QgsEditorWidgetRegistry.instance().registerWidget('SimpleFilename', myFactory)
def setConfig(self, config): self.conf = config class PreciseRangeWidgetWrapperFactory(QgsEditorWidgetFactory): def __init__(self): QgsEditorWidgetFactory.__init__(self, QCoreApplication.translate('PreciseRangeWidgetWrapperFactory','Precise Range')) def create(self, layer, fieldIdx, editor, parent): return PreciseRangeWidgetWrapper(layer, fieldIdx, editor, parent) def configWidget(self, layer, idx, parent): return PreciseRangeWidgetWrapperConfig(layer, idx, parent) def writeConfig( self, config, elem, doc, layer, idx ): elem.setAttribute('Min', config['Min']) elem.setAttribute('Max', config['Max']) elem.setAttribute('Step', config['Step']) elem.setAttribute('AllowNull', config['AllowNull']) def readConfig(self, elem, layer, idx): config = dict() config['Min'] = elem.attribute('Min') config['Max'] = elem.attribute('Max') config['Step'] = elem.attribute('Step') config['AllowNull'] = elem.attribute('AllowNull') return config myFactory = PreciseRangeWidgetWrapperFactory() QgsEditorWidgetRegistry.instance().registerWidget('PreciseRange', myFactory)
class STDMFieldWidget(): # Instantiate the singleton QgsEditorWidgetRegistry widgetRegistry = QgsEditorWidgetRegistry.instance() def __init__(self): self.entity = None self.widget_mapping = {} self.layer = None self.feature_models = OrderedDict() self.removed_feature_models = OrderedDict() self.current_feature = None self.editor = None def init_form(self, table, spatial_column, curr_layer): """ Initialize required methods and slots to be used in form initialization. :param table: The table name of the layer :type table: String :param spatial_column: The spatial column name of the layer :type spatial_column: String :param curr_layer: The current layer of form. :type curr_layer: QgsVectorLayer :return: None :rtype: NoneTYpe """ try: # init form self.set_entity(table) self.set_widget_mapping() self.register_factory() self.set_widget_type(curr_layer) curr_layer.editFormConfig().setSuppress(1) try: curr_layer.featureAdded.connect( lambda feature_id: self.load_stdm_form( feature_id, spatial_column)) except Exception: pass curr_layer.featureDeleted.connect(self.on_feature_deleted) curr_layer.beforeCommitChanges.connect(self.on_digitizing_saved) except Exception as ex: LOGGER.debug(ex) def set_entity(self, source): """ Sets the layer entity of the layer based on a table name. :param source: Table name that acts as a layer source. :type source: String :return: None :rtype: NoneType """ curr_profile = current_profile() self.entity = curr_profile.entity_by_name(source) def _set_widget_type(self, layer, column, widget_type_id): """ Sets the widget type for each field into QGIS form configuration. :param layer: The layer to which the widget type is set. :type layer: QgsVectorLayer :param column: STDM column object :type column: Object :param widget_type_id: The widget type id which could be the default QGIS or the custom STDM widget id which is based on column.TYPE_INFO. :type widget_type_id: String :return: None :rtype:NoneType """ idx = layer.fieldNameIndex(column.name) # Set Alias/ Display names for the column names layer.addAttributeAlias(idx, column.header()) try: layer.editFormConfig().setWidgetType(idx, widget_type_id) except Exception: layer.setEditorWidgetV2(idx, widget_type_id) def set_widget_mapping(self): """ Maps each column to QGIS or STDM editor widgets. :return: None :rtype:NoneType """ self.widget_mapping.clear() for c in self.entity.columns.values(): if c.TYPE_INFO == 'SERIAL': self.widget_mapping[c] = ['Hidden', None] elif c.TYPE_INFO == 'GEOMETRY': self.widget_mapping[c] = ['TextEdit', None] else: stdm = QApplication.translate('STDMFieldWidget', u'STDM') self.widget_mapping[c] = [ u'stdm_{}'.format(c.TYPE_INFO.lower()), u'{} {}'.format(stdm, c.display_name()) ] def register_factory(self): """ Registers each widget type to a QGIS widget factory registry. :return: None :rtype: NoneType """ # The destructor has no effects. It is QGIS bug. # So restarting QGIS is required to destroy # registered stdm widgets. for widget_id_name in self.widget_mapping.values(): # add and register stdm widget type only if not widget_id_name[1] is None: widget_name = widget_id_name[1] if widget_id_name[0] not in \ self.widgetRegistry.factories().keys(): widget_factory = QGISFieldWidgetFactory(widget_name) self.widgetRegistry.registerWidget(widget_id_name[0], widget_factory) def set_widget_type(self, layer): """ Sets widget type for each fields in a layer. :param layer: The layer to which the widget type is set. :type layer: QgsVectorLayer :return: None :rtype: NoneType """ self.layer = layer for col, widget_id_name in \ self.widget_mapping.iteritems(): self._set_widget_type(layer, col, widget_id_name[0]) def load_stdm_form(self, feature_id, spatial_column): """ Loads STDM Form and collects the model added into the form so that it is saved later. :param feature_id: the ID of a feature that is last added :type feature_id: Integer :param spatial_column: The spatial column name of the layer :type spatial_column: String :return: None :rtype:NoneType """ srid = None self.current_feature = feature_id # If the digitizing save button is clicked, # the featureAdded signal is called but the # feature ids value is over 0. Return to prevent # the dialog from popping up for every feature. if feature_id > 0: return # if the feature is already in the OrderedDict don't # show the form as the model of the feature is # already populated by the form if feature_id in self.feature_models.keys(): return # If the feature is removed by the undo button, don't # load the form for it but add it # back to feature_models and don't show the form. # This happens when redo button(add feature back) is # clicked after an undo button(remove feature) if feature_id in self.removed_feature_models.keys(): self.feature_models[feature_id] = \ self.removed_feature_models[feature_id] return # If the feature is not valid, geom_wkt will be None # So don't launch form for invalid feature and delete feature geom_wkt = self.get_wkt(feature_id) if geom_wkt is None: title = QApplication.translate('STDMFieldWidget', u'Spatial Entity Form Error', None, QCoreApplication.UnicodeUTF8) msg = QApplication.translate( 'STDMFieldWidget', u'The feature you have added is invalid. \n' 'To fix this issue, check if the feature ' 'is digitized correctly. \n' 'Make sure you have added a base layer to digitize on.', None, QCoreApplication.UnicodeUTF8) # Message: Spatial column information # could not be found QMessageBox.critical(iface.mainWindow(), title, msg) return # init form self.editor = EntityEditorDialog(self.entity, None, parent=iface.mainWindow(), manage_documents=True, collect_model=True) self.model = self.editor.model() self.editor.addedModel.connect(self.on_form_saved) # get srid with EPSG text full_srid = self.layer.crs().authid().split(':') if len(full_srid) > 0: # Only extract the number srid = full_srid[1] if not geom_wkt is None: # add geometry into the model setattr(self.model, spatial_column, 'SRID={};{}'.format(srid, geom_wkt)) # open editor result = self.editor.exec_() if result < 1: self.removed_feature_models[feature_id] = None self.layer.deleteFeature(feature_id) def get_wkt(self, feature_id): """ Gets feature geometry in Well-Known Text format and returns it. :param feature_id: Feature id :type feature_id: Integer :return: Well-Known Text format of a geometry :rtype: WKT """ geom_wkt = None fid = feature_id request = QgsFeatureRequest() request.setFilterFid(fid) features = self.layer.getFeatures(request) # get the wkt of the geometry for feature in features: geometry = feature.geometry() if geometry.isGeosValid(): geom_wkt = feature.geometry().exportToWkt() return geom_wkt def on_form_saved(self, model): """ A slot raised when the save button is clicked in spatial unit form. It adds the feature model in feature_models ordered dictionary to be saved later. :param model: The model holding feature geometry and attributes obtained from the form :type model: SQLAlchemy Model :return: None :rtype: NoneType """ if not model is None: self.feature_models[self.current_feature] = model if self.editor.is_valid: self.editor.accept() def on_feature_deleted(self, feature_id): """ A slot raised when a feature is deleted in QGIS map canvas via the undo button. It deletes the associated model of the feature. :param feature_id: The id that is removed. :type feature_id: Integer :return: None :rtype: NoneType """ if feature_id in self.feature_models.keys(): self.removed_feature_models[feature_id] = \ self.feature_models[feature_id] del self.feature_models[feature_id] def on_digitizing_saved(self): """ A slot raised when the save button is clicked on Digitizing Toolbar of QGIS. It saves feature models created by the digitizer and STDM form to the Database. :return: None :rtype: NoneType """ ent_model = entity_model(self.entity) entity_obj = ent_model() entity_obj.saveMany(self.feature_models.values()) # Save child models if self.editor is not None: self.editor.save_children() # undo each feature created so that qgis # don't try to save the same feature again. # It will also clear all the models from # self.feature_models as on_feature_deleted # is raised when a feature is removed. for i in range(len(self.feature_models)): self.layer.undoStack().undo()
self.ruleEdit = QLabel(self) self.ruleEdit.setText( QCoreApplication.translate( 'SimpleFilenameWidgetWrapperConfig', 'A filename without extension editor widget.')) self.layout().addWidget(self.ruleEdit) def config(self): return {} def setConfig(self, config): pass class SimpleFilenameWidgetWrapperFactory(QgsEditorWidgetFactory): def __init__(self): QgsEditorWidgetFactory.__init__( self, QCoreApplication.translate('SimpleFilenameWidgetWrapperFactory', 'Simple Filename')) def create(self, layer, fieldIdx, editor, parent): return SimpleFilenameWidgetWrapper(layer, fieldIdx, editor, parent) def configWidget(self, layer, idx, parent): return SimpleFilenameWidgetWrapperConfig(layer, idx, parent) myFactory = SimpleFilenameWidgetWrapperFactory() QgsEditorWidgetRegistry.instance().registerWidget('SimpleFilename', myFactory)
class PreciseRangeWidgetWrapperFactory(QgsEditorWidgetFactory): def __init__(self): QgsEditorWidgetFactory.__init__( self, QCoreApplication.translate('PreciseRangeWidgetWrapperFactory', 'Precise Range')) def create(self, layer, fieldIdx, editor, parent): return PreciseRangeWidgetWrapper(layer, fieldIdx, editor, parent) def configWidget(self, layer, idx, parent): return PreciseRangeWidgetWrapperConfig(layer, idx, parent) def writeConfig(self, config, elem, doc, layer, idx): elem.setAttribute('Min', config['Min']) elem.setAttribute('Max', config['Max']) elem.setAttribute('Step', config['Step']) elem.setAttribute('AllowNull', config['AllowNull']) def readConfig(self, elem, layer, idx): config = dict() config['Min'] = elem.attribute('Min') config['Max'] = elem.attribute('Max') config['Step'] = elem.attribute('Step') config['AllowNull'] = elem.attribute('AllowNull') return config myFactory = PreciseRangeWidgetWrapperFactory() QgsEditorWidgetRegistry.instance().registerWidget('PreciseRange', myFactory)