Exemple #1
0
    def testPoint(self):
        point = QgsReferencedPointXY(QgsPointXY(1.0, 2.0), QgsCoordinateReferenceSystem('epsg:3111'))
        self.assertEqual(point.x(), 1.0)
        self.assertEqual(point.y(), 2.0)
        self.assertEqual(point.crs().authid(), 'EPSG:3111')

        point.setCrs(QgsCoordinateReferenceSystem('epsg:28356'))
        self.assertEqual(point.crs().authid(), 'EPSG:28356')

        # in variant
        v = QVariant(QgsReferencedPointXY(QgsPointXY(3.0, 4.0), QgsCoordinateReferenceSystem('epsg:3111')))
        self.assertEqual(v.value().x(), 3.0)
        self.assertEqual(v.value().y(), 4.0)
        self.assertEqual(v.value().crs().authid(), 'EPSG:3111')

        # to QgsPointXY
        p = QgsPointXY(point)
        self.assertEqual(p.x(), 1.0)
        self.assertEqual(p.y(), 2.0)
    def refreshTable(self, part_num):
        # Clear coord's table
        if -1 < part_num < len(self.coords_matrix):
            model = self.twPoints.model()
            coordslist = self.coords_matrix[part_num][1]

            model.removeRows(0, model.rowCount())
            model.insertRows(0, len(self.coords_matrix[part_num][1]) + 1)

            model.blockSignals(True)
            for i in range(len(coordslist)):
                for j in range(model.columnCount()):
                    model.setData(model.createIndex(i, j),
                                  QVariant(str(coordslist[i][j])))
            model.blockSignals(False)
            model.dataChanged.emit(
                model.createIndex(0, 0),
                model.createIndex(model.rowCount() - 1,
                                  model.columnCount() - 1))
    def initAlgorithm(self, config):
        """
        Here we define the inputs and output of the algorithm, along
        with some other properties.
        """

        self.addParameter(
            QgsProcessingParameterVectorLayer(self.INPUT,
                                              self.tr('Point layer'),
                                              [QgsProcessing.TypeVectorPoint]))

        self.addParameter(
            QgsProcessingParameterEnum(self.INPUT_METHOD,
                                       self.tr('Interpolation method'), [
                                           'Thiessen', 'Voronoi', 'Delaunay',
                                           'Inverse distance weighting'
                                       ]))

        self.addParameter(
            QgsProcessingParameterField(
                self.FIELD,
                self.tr("Field to interpolate"),
                QVariant(),
                self.INPUT,
                type=QgsProcessingParameterField.Numeric))

        self.addParameter(
            QgsProcessingParameterNumber(
                self.INPUT_PIXEL, self.tr('Grid resolution (in meters)'),
                QgsProcessingParameterNumber.Double, 0.5))

        self.addParameter(
            QgsProcessingParameterNumber(self.INPUT_POWER,
                                         self.tr('IDW power (for IDW method)'),
                                         QgsProcessingParameterNumber.Integer,
                                         2))

        self.addParameter(
            QgsProcessingParameterRasterDestination(
                self.OUTPUT, self.tr('Interpolated raster')))
Exemple #4
0
 def initAlgorithm(self, config=None):
     self.addParameter(
         QgsProcessingParameterRasterLayer(self.INPUT_RASTER_A,
                                           self.tr("Input Raster A"), None,
                                           False))
     self.addParameter(
         QgsProcessingParameterRasterLayer(self.INPUT_RASTER_B,
                                           self.tr("Input Raster B"), None,
                                           False))
     self.addParameter(
         QgsProcessingParameterNumber(self.INPUT_DOUBLE,
                                      self.tr("Input Double"),
                                      QgsProcessingParameterNumber.Double,
                                      QVariant(1.0)))
     self.addParameter(
         QgsProcessingParameterRasterDestination(self.OUTPUT_RASTER_A,
                                                 self.tr("Output Raster A"),
                                                 None, False))
     self.addParameter(
         QgsProcessingParameterRasterDestination(self.OUTPUT_RASTER_B,
                                                 self.tr("Output Raster B"),
                                                 None, False))
    def testRectangle(self):
        rect = QgsReferencedRectangle(
            QgsRectangle(0.0, 1.0, 20.0, 10.0),
            QgsCoordinateReferenceSystem('epsg:3111'))
        self.assertEqual(rect.xMinimum(), 0.0)
        self.assertEqual(rect.yMinimum(), 1.0)
        self.assertEqual(rect.xMaximum(), 20.0)
        self.assertEqual(rect.yMaximum(), 10.0)
        self.assertEqual(rect.crs().authid(), 'EPSG:3111')

        rect.setCrs(QgsCoordinateReferenceSystem('epsg:28356'))
        self.assertEqual(rect.crs().authid(), 'EPSG:28356')

        # in variant
        v = QVariant(
            QgsReferencedRectangle(QgsRectangle(1.0, 2.0, 3.0, 4.0),
                                   QgsCoordinateReferenceSystem('epsg:3111')))
        self.assertEqual(v.value().xMinimum(), 1.0)
        self.assertEqual(v.value().yMinimum(), 2.0)
        self.assertEqual(v.value().xMaximum(), 3.0)
        self.assertEqual(v.value().yMaximum(), 4.0)
        self.assertEqual(v.value().crs().authid(), 'EPSG:3111')

        # to rectangle
        r = QgsRectangle(rect)
        self.assertEqual(r.xMinimum(), 0.0)
        self.assertEqual(r.yMinimum(), 1.0)
        self.assertEqual(r.xMaximum(), 20.0)
        self.assertEqual(r.yMaximum(), 10.0)

        # test that QgsReferencedRectangle IS a QgsRectangle
        r2 = QgsRectangle(5, 6, 30, 40)
        r2.combineExtentWith(rect)
        self.assertEqual(r2.xMinimum(), 0.0)
        self.assertEqual(r2.yMinimum(), 1.0)
        self.assertEqual(r2.xMaximum(), 30.0)
        self.assertEqual(r2.yMaximum(), 40.0)
Exemple #6
0
    def __init__(self, iface):
        # Save reference to the QGIS interface
        self.iface = iface
        # docked or dialog, defaults to dialog
        if isinstance(QSettings().value("locale/userLocale"), QVariant):
            self.docked = QSettings().value("/pdokservicesplugin/docked", QVariant(False)).toBool()
        else:
            self.docked = QSettings().value("/pdokservicesplugin/docked", False)
        # Create the dialog and keep reference
        if "True" == self.docked or "true" == self.docked or  True == self.docked:
            self.dlg = PdokServicesPluginDockWidget()
            self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dlg)
        else:
            self.dlg = PdokServicesPluginDialog(parent=self.iface.mainWindow())
        # initialize plugin directory
        self.plugin_dir = QFileInfo(QgsApplication.qgisUserDatabaseFilePath()).path() + "/python/plugins/pdokservicesplugin"
        # initialize locale
        localePath = ""
        if isinstance(QSettings().value("locale/userLocale"), QVariant):
            locale = QSettings().value("locale/userLocale").toString()[0:2]
        else:
            locale = QSettings().value("locale/userLocale")[0:2]

        if QFileInfo(self.plugin_dir).exists():
            localePath = self.plugin_dir + "/i18n/pdokservicesplugin_" + locale + ".qm"

        if QFileInfo(localePath).exists():
            self.translator = QTranslator()
            self.translator.load(localePath)
            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)
        self.currentLayer = None
        self.SETTINGS_SECTION = '/pdokservicesplugin/'
        self.pointer = None
        self.pdokgeocoder = PDOKGeoLocator(self.iface)
        self.geocoderSourceModel = None
    def test_representValueWithDefault(self):
        """
        Check representValue behaves correctly when used on a layer which define default values
        """

        dbname = os.path.join(tempfile.mkdtemp(), 'test.sqlite')
        con = spatialite_connect(dbname, isolation_level=None)
        cur = con.cursor()
        cur.execute("BEGIN")
        sql = """
        CREATE TABLE test_table_default_values (
            id integer primary key autoincrement,
            anumber INTEGER DEFAULT 123
        )
        """
        cur.execute(sql)
        cur.execute("COMMIT")
        con.close()

        vl = QgsVectorLayer(dbname + '|layername=test_table_default_values',
                            'test_table_default_values', 'ogr')
        self.assertTrue(vl.isValid())

        fieldFormatter = QgsFallbackFieldFormatter()

        QLocale.setDefault(QLocale('en'))

        self.assertEqual(
            fieldFormatter.representValue(vl, 1, {}, None,
                                          QVariant(QVariant.Int)), 'NULL')
        self.assertEqual(fieldFormatter.representValue(vl, 1, {}, None, 4),
                         '4')
        self.assertEqual(fieldFormatter.representValue(vl, 1, {}, None, "123"),
                         '123')
        # bad field index
        self.assertEqual(fieldFormatter.representValue(vl, 3, {}, None, 5), "")
            def addItem():
                if checkListFormValidity():
                    newListWidgetItem = QListWidgetItem()
                    data = {}
                    textList = []
                    for formItem in formItems:
                        if isinstance(formItem, QLineEdit):
                            data[formItem.objectName()] = formItem.text()
                            textList.append(formItem.text())
                        elif isinstance(formItem, QDateTimeEdit):
                            data[formItem.objectName()] = formItem.dateTime().date()
                            textList.append(
                                formItem.dateTime().toString("dd-MM-yyyy")
                                # formItem.dateTime().date().toString()
                            )
                        elif isinstance(formItem, QCheckBox):
                            data[formItem.objectName()] = formItem.isChecked()
                        elif isinstance(formItem, QComboBox):
                            data[formItem.objectName()] = formItem.currentIndex()

                    newListWidgetItem.setData(
                        Qt.UserRole,
                        QVariant(data)
                    )
                    newListWidgetItem.setText(" - ".join(textList))
                    listWidget.addItem(newListWidgetItem)
                    clearDataFromListWidget()   # czyszczenie
                else:
                    if name == 'mapaPodkladowa':
                        utils.showPopup("Wypełnij formularz mapy podkładowej",
                                        'Musisz zdefiniować wartości dla obowiązkowych pól:\n'
                                        '- referencja,\n'
                                        '- data')
                    else:
                        utils.showPopup("Wypełnij formularz",
                                        "Musisz wpisać wartość przed dodaniem")
Exemple #9
0
    def data(self, index, role):

        indexData = self.questdata[index.row()][index.column()]

        if not index.isValid():
            return QVariant()

        elif role == Qt.DisplayRole:

            col = index.column()
            # Specify formatters for columns with
            if col == 4:
                # Worksite formatter
                return self._wkformatter.setDisplay(indexData)
            elif col == 5:
                # Enumerator formatter
                return self._enumformatter.setDisplay(indexData)
            elif col == 6:
                return self._respformatter.setDisplay(indexData)
            else:
                return QVariant(indexData)

        # For columns representing foreign keys then we need to pass the integer value to the editor
        elif role == Qt.EditRole:
            return QVariant(indexData)

        elif role == Qt.BackgroundRole:
            if index.row() % 2 == 0:
                # Orange
                return QVariant(ALT_COLOR_EVEN)
            else:
                # Blue
                return QVariant(ALT_COLOR_ODD)

        else:
            return QVariant()
Exemple #10
0
    def initAlgorithm(self, config=None):
        self.units = [self.tr("Pixels"),
                      self.tr("Georeferenced units")]

        self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
                                                              self.tr('Input layer')))
        self.addParameter(QgsProcessingParameterField(self.FIELD,
                                                      self.tr('Field to use for a burn-in value'),
                                                      None,
                                                      self.INPUT,
                                                      QgsProcessingParameterField.Numeric,
                                                      optional=True))
        self.addParameter(QgsProcessingParameterNumber(self.BURN,
                                                       self.tr('A fixed value to burn'),
                                                       type=QgsProcessingParameterNumber.Double,
                                                       defaultValue=0.0,
                                                       optional=True))
        self.addParameter(QgsProcessingParameterBoolean(self.USE_Z,
                                                        self.tr('Burn value extracted from the "Z" values of the feature'),
                                                        defaultValue=False,
                                                        optional=True))
        self.addParameter(QgsProcessingParameterEnum(self.UNITS,
                                                     self.tr('Output raster size units'),
                                                     self.units))
        self.addParameter(QgsProcessingParameterNumber(self.WIDTH,
                                                       self.tr('Width/Horizontal resolution'),
                                                       type=QgsProcessingParameterNumber.Double,
                                                       minValue=0.0,
                                                       defaultValue=0.0))
        self.addParameter(QgsProcessingParameterNumber(self.HEIGHT,
                                                       self.tr('Height/Vertical resolution'),
                                                       type=QgsProcessingParameterNumber.Double,
                                                       minValue=0.0,
                                                       defaultValue=0.0))
        self.addParameter(QgsProcessingParameterExtent(self.EXTENT,
                                                       self.tr('Output extent'),
                                                       optional=True))
        nodataParam = QgsProcessingParameterNumber(self.NODATA,
                                                   self.tr('Assign a specified nodata value to output bands'),
                                                   type=QgsProcessingParameterNumber.Double,
                                                   optional=True)
        nodataParam.setGuiDefaultValueOverride(QVariant(QVariant.Double))
        self.addParameter(nodataParam)

        options_param = QgsProcessingParameterString(self.OPTIONS,
                                                     self.tr('Additional creation options'),
                                                     defaultValue='',
                                                     optional=True)
        options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
        options_param.setMetadata({
            'widget_wrapper': {
                'class': 'processing.algs.gdal.ui.RasterOptionsWidget.RasterOptionsWidgetWrapper'}})
        self.addParameter(options_param)

        dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE,
                                                    self.tr('Output data type'),
                                                    self.TYPES,
                                                    allowMultiple=False,
                                                    defaultValue=5)
        dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
        self.addParameter(dataType_param)

        init_param = QgsProcessingParameterNumber(self.INIT,
                                                  self.tr('Pre-initialize the output image with value'),
                                                  type=QgsProcessingParameterNumber.Double,
                                                  optional=True)
        init_param.setFlags(init_param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
        self.addParameter(init_param)

        invert_param = QgsProcessingParameterBoolean(self.INVERT,
                                                     self.tr('Invert rasterization'),
                                                     defaultValue=False)
        invert_param.setFlags(invert_param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
        self.addParameter(invert_param)

        extra_param = QgsProcessingParameterString(self.EXTRA,
                                                   self.tr('Additional command-line parameters'),
                                                   defaultValue=None,
                                                   optional=True)
        extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
        self.addParameter(extra_param)

        self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
                                                                  self.tr('Rasterized')))
def set_qt_property(qobj, **kw):
    for k, v in kw.items():
        qobj.setProperty(str(k), QVariant(v))
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsLayer(parameters, self.INPUT, context)
        base_url = self.parameterAsString(parameters, self.BASE_URL, context)

        campus_code = self.parameterAsString(parameters, self.CAMPUS_CODE,
                                             context)

        search_key = self.parameterAsString(parameters, self.SEARCH_KEY,
                                            context)

        update = self.parameterAsString(parameters, self.UPDATE, context)

        # parameters
        base_url = base_url.strip()
        campus_code = campus_code.strip().lower()
        search_key = search_key.strip()

        if source is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUT))

        # extract required data
        _extractor = DataExtractor(feedback, base_url)
        filtered_meeting_rooms_data = _extractor.get_meeting_rooms_data(
            campus_code)
        filtered_toilets_data = _extractor.get_toilets_data(campus_code)
        filtered_employee_data = _extractor.get_employees_data(campus_code)
        mr_equipment_data = _extractor.get_meeting_rooms_equipment_data(
            campus_code)
        filtered_timetable_data = _extractor.get_timetable_data(campus_code)
        filtered_mr_usage_data = _extractor.get_meeting_room_usage_data(
            campus_code)

        # layer handlers
        layer = source
        features = layer.getFeatures()
        layer_provider = layer.dataProvider()

        # create layer manager
        layerManager = LayerManager(feedback)

        # clean + add attributes
        layerManager.add_attributes(layer, layer_provider)

        # get indexes of all attributes
        attr_indexes = layerManager.get_indexes_of_attributes(layer_provider)

        #### ---- Creating grouped data ----- #####
        feedback.pushInfo('Merging data for getting supply')
        tr_data = filtered_toilets_data.groupby(
            by=['Campus Code', 'Building Code', 'Building Name'],
            as_index=False).agg({
                'Room Code': pd.Series.nunique,
                'Room Capacity': sum
            })
        tr_data = tr_data.rename(columns={
            "Room Code": "TR_COUNT",
            "Room Capacity": "TR_CAP"
        })

        mr_data = filtered_meeting_rooms_data.groupby(
            by=['Campus Code', 'Building Code', 'Building Name'],
            as_index=False).agg({
                'Room Code': pd.Series.nunique,
                'Room Capacity': sum
            })
        mr_data = mr_data.rename(columns={
            "Room Code": "MR_COUNT",
            "Room Capacity": "MR_CAP"
        })

        feedback.pushInfo('Merging data for getting demand')
        student_data = filtered_timetable_data.groupby(
            by=['Campus Code', 'Building Code', 'Building Name'],
            as_index=False).agg({'Planned Size': sum})
        student_data = student_data.rename(
            columns={'Planned Size': 'STU_COUNT'})

        emp_data = filtered_employee_data.groupby(
            by=['Campus Code', 'Building Code', 'Building Name'],
            as_index=False).agg({'Employee Sequential ID': pd.Series.nunique})
        emp_data = emp_data.rename(
            columns={'Employee Sequential ID': 'EMP_COUNT'})

        cols = ['Campus Code', 'Building Code', 'Building Name']
        aggs = {'Equipment Code': pd.Series.nunique}
        names = {'Equipment Code': 'EQP_CNT'}
        mr_av_data = mr_equipment_data.groupby(by=cols,
                                               as_index=False).agg(aggs)
        mr_av_data = mr_av_data.rename(columns=names)

        ## New version - worked
        excellent_filtered_mr_data = filtered_meeting_rooms_data[
            filtered_meeting_rooms_data['Room Condition 2018'] == 'Excellent']
        verygood_filtered_mr_data = filtered_meeting_rooms_data[
            filtered_meeting_rooms_data['Room Condition 2018'] == 'Very Good']
        good_filtered_mr_data = filtered_meeting_rooms_data[
            filtered_meeting_rooms_data['Room Condition 2018'] == 'Good']
        cols = ['Campus Code', 'Building Code', 'Building Name']
        aggs = {'Room Code': pd.Series.nunique, 'Room Capacity': sum}
        names = {"Room Code": "EX_MR_CNT", "Room Capacity": "EX_MR_CAP"}
        excellent_mr_data = excellent_filtered_mr_data.groupby(
            by=cols, as_index=False).agg(aggs)
        excellent_mr_data = excellent_mr_data.rename(columns=names)
        names = {"Room Code": "VG_MR_CNT", "Room Capacity": "VG_MR_CAP"}
        verygood_mr_data = verygood_filtered_mr_data.groupby(
            by=cols, as_index=False).agg(aggs)
        verygood_mr_data = verygood_mr_data.rename(columns=names)
        names = {"Room Code": "G_MR_CNT", "Room Capacity": "G_MR_CAP"}
        good_mr_data = good_filtered_mr_data.groupby(by=cols,
                                                     as_index=False).agg(aggs)
        good_mr_data = good_mr_data.rename(columns=names)

        cols = ['Campus Code', 'Building Code', 'Building Name']
        names = {"Room Area m²": "AG_MR_SZ"}
        mr_data_area = filtered_meeting_rooms_data.groupby(
            by=cols, as_index=False)['Room Area m²'].mean()
        mr_data_area = mr_data_area.rename(columns=names)

        cols = ['Campus Code', 'Building Code', 'Building Name_x']
        names = {"Meetings": "TOTAL_M"}
        mr_usage = filtered_mr_usage_data.groupby(
            by=cols, as_index=False)["Meetings"].sum()
        mr_usage = mr_usage.rename(columns=names)

        ## New version TR - worked
        excellent_filtered_tr_data = filtered_toilets_data[
            filtered_toilets_data['Room Condition 2018'] == 'Excellent']
        verygood_filtered_tr_data = filtered_toilets_data[
            filtered_toilets_data['Room Condition 2018'] == 'Very Good']
        good_filtered_tr_data = filtered_toilets_data[
            filtered_toilets_data['Room Condition 2018'] == 'Good']
        cols = ['Campus Code', 'Building Code', 'Building Name']
        aggs = {'Room Code': pd.Series.nunique, 'Room Capacity': sum}
        names = {"Room Code": "EX_TR_CNT", "Room Capacity": "EX_TR_CAP"}
        excellent_tr_data = excellent_filtered_tr_data.groupby(
            by=cols, as_index=False).agg(aggs)
        excellent_tr_data = excellent_tr_data.rename(columns=names)
        names = {"Room Code": "VG_TR_CNT", "Room Capacity": "VG_TR_CAP"}
        verygood_tr_data = verygood_filtered_tr_data.groupby(
            by=cols, as_index=False).agg(aggs)
        verygood_tr_data = verygood_tr_data.rename(columns=names)
        names = {"Room Code": "G_TR_CNT", "Room Capacity": "G_TR_CAP"}
        good_tr_data = good_filtered_tr_data.groupby(by=cols,
                                                     as_index=False).agg(aggs)
        good_tr_data = good_tr_data.rename(columns=names)

        cols = ['Campus Code', 'Building Code', 'Building Name']
        names = {"Room Area m²": "AG_TR_SZ"}
        tr_data_area = filtered_toilets_data.groupby(
            by=cols, as_index=False)['Room Area m²'].mean()
        tr_data_area = tr_data_area.rename(columns=names)

        cols = ['Campus Code', 'Building Code', 'Building Name']
        names = {"Class Duration In Minutes": "AG_CL_DS"}
        cl_timetable = filtered_timetable_data.groupby(
            by=cols, as_index=False)["Class Duration In Minutes"].mean()
        cl_timetable = cl_timetable.rename(columns=names)

        ###### ---------------------------------- ######

        # create sink for new output layer
        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, layer.fields(),
                                               layer.wkbType(),
                                               layer.sourceCrs())
        feedback.pushInfo('CRS is {}'.format(layer.sourceCrs().authid()))
        if sink is None:
            raise QgsProcessingException(
                self.invalidSinkError(parameters, self.OUTPUT))

        total = 100.0 / layer.featureCount() if layer.featureCount() else 0

        features = layer.getFeatures()
        _features = DataFeatures(feedback)

        # feature update logic
        for current, feature in enumerate(features):
            if feedback.isCanceled():
                break
            id = feature.id()

            # update calculated fields
            supply = _features.get_data_for_key(mr_data, feature[search_key],
                                                'MR_CAP')
            demand = _features.get_data_for_key(emp_data, feature[search_key],
                                                'EMP_COUNT')

            toilet_supply = _features.get_data_for_key(tr_data,
                                                       feature[search_key],
                                                       'TR_CAP')
            toilet_demand = _features.get_data_for_key(student_data,
                                                       feature[search_key],
                                                       'STU_COUNT')

            if supply and demand:
                weight = float(supply / demand)
            else:
                weight = QVariant()
            if toilet_supply and toilet_demand:
                tr_weight = float(toilet_supply / toilet_demand)
            else:
                tr_weight = QVariant()

            feature['MR_WEIGHTS'] = weight
            feature['TR_WEIGHTS'] = tr_weight

            # update data fields
            mr_count = _features.get_data_for_key(mr_data, feature[search_key],
                                                  'MR_COUNT')
            if mr_count:
                feature['MR_CNT'] = int(mr_count)
            else:
                feature['MR_CNT'] = QVariant()

            if supply:
                feature['MR_CAP'] = int(supply)
            else:
                feature['MR_CAP'] = QVariant()

            tr_count = _features.get_data_for_key(tr_data, feature[search_key],
                                                  'TR_COUNT')
            if tr_count:
                feature['TR_CNT'] = int(tr_count)
            else:
                feature['TR_CNT'] = QVariant()

            if toilet_supply:
                feature['TR_CAP'] = int(toilet_supply)
            else:
                feature['TR_CAP'] = QVariant()

            if demand:
                feature['EMP_CNT'] = int(demand)
            else:
                feature['EMP_CNT'] = QVariant()

            eqp_count = _features.get_data_for_key(mr_av_data,
                                                   feature[search_key],
                                                   'EQP_CNT')
            if eqp_count:
                feature['EQP_CNT'] = int(eqp_count)
            else:
                feature['EQP_CNT'] = QVariant()

            if toilet_demand:
                feature['STU_CNT'] = int(toilet_demand)
            else:
                feature['STU_CNT'] = QVariant()

            ex_mr_cap = _features.get_data_for_key(excellent_mr_data,
                                                   feature[search_key],
                                                   'EX_MR_CAP')
            if ex_mr_cap:
                feature['EX_MR_CAP'] = int(ex_mr_cap)
            else:
                feature['EX_MR_CAP'] = QVariant()

            vg_mr_cap = _features.get_data_for_key(verygood_mr_data,
                                                   feature[search_key],
                                                   'VG_MR_CAP')
            if vg_mr_cap:
                feature['VG_MR_CAP'] = int(vg_mr_cap)
            else:
                feature['VG_MR_CAP'] = QVariant()

            g_mr_cap = _features.get_data_for_key(good_mr_data,
                                                  feature[search_key],
                                                  'G_MR_CAP')
            if g_mr_cap:
                feature['G_MR_CAP'] = int(g_mr_cap)
            else:
                feature['G_MR_CAP'] = QVariant()

            avg_mr_area = _features.get_data_for_key(mr_data_area,
                                                     feature[search_key],
                                                     'AG_MR_SZ')
            if avg_mr_area:
                feature['AG_MR_SZ'] = float(avg_mr_area)
            else:
                feature['AG_MR_SZ'] = QVariant()

            total_m = _features.get_data_for_key(mr_usage, feature[search_key],
                                                 'TOTAL_M')
            if total_m:
                feature['TOTAL_M'] = int(total_m)
            else:
                feature['TOTAL_M'] = QVariant()

            ex_tr_cap = _features.get_data_for_key(excellent_tr_data,
                                                   feature[search_key],
                                                   'EX_TR_CAP')
            if ex_tr_cap:
                feature['EX_TR_CAP'] = int(ex_tr_cap)
            else:
                feature['EX_TR_CAP'] = QVariant()

            vg_tr_cap = _features.get_data_for_key(verygood_tr_data,
                                                   feature[search_key],
                                                   'VG_TR_CAP')
            if vg_mr_cap:
                feature['VG_TR_CAP'] = int(vg_tr_cap)
            else:
                feature['VG_TR_CAP'] = QVariant()

            g_tr_cap = _features.get_data_for_key(good_tr_data,
                                                  feature[search_key],
                                                  'G_TR_CAP')
            if g_tr_cap:
                feature['G_TR_CAP'] = int(g_tr_cap)
            else:
                feature['G_TR_CAP'] = QVariant()

            avg_tr_area = _features.get_data_for_key(tr_data_area,
                                                     feature[search_key],
                                                     'AG_TR_SZ')
            if avg_tr_area:
                feature['AG_TR_SZ'] = float(avg_tr_area)
            else:
                feature['AG_TR_SZ'] = QVariant()

            ag_cl_ds = _features.get_data_for_key(cl_timetable,
                                                  feature[search_key],
                                                  'AG_CL_DS')
            if ag_cl_ds:
                feature['AG_CL_DS'] = float(ag_cl_ds)
            else:
                feature['AG_CL_DS'] = QVariant()

            # connect index with attributes
            attr_value = {
                attr_indexes['MR_WEIGHTS']: feature['MR_WEIGHTS'],
                attr_indexes['TR_WEIGHTS']: feature['TR_WEIGHTS'],
                attr_indexes['MR_CNT']: feature['MR_CNT'],
                attr_indexes['MR_CAP']: feature['MR_CAP'],
                attr_indexes['TR_CNT']: feature['TR_CNT'],
                attr_indexes['TR_CAP']: feature['TR_CAP'],
                attr_indexes['EMP_CNT']: feature['EMP_CNT'],
                attr_indexes['EQP_CNT']: feature['EQP_CNT'],
                attr_indexes['STU_CNT']: feature['STU_CNT'],
                attr_indexes['EX_MR_CAP']: feature['EX_MR_CAP'],
                attr_indexes['VG_MR_CAP']: feature['VG_MR_CAP'],
                attr_indexes['G_MR_CAP']: feature['G_MR_CAP'],
                attr_indexes['AG_MR_SZ']: feature['AG_MR_SZ'],
                attr_indexes['TOTAL_M']: feature['TOTAL_M'],
                attr_indexes['EX_TR_CAP']: feature['EX_TR_CAP'],
                attr_indexes['VG_TR_CAP']: feature['VG_TR_CAP'],
                attr_indexes['G_TR_CAP']: feature['G_TR_CAP'],
                attr_indexes['AG_TR_SZ']: feature['AG_TR_SZ'],
                attr_indexes['AG_CL_DS']: feature['AG_CL_DS']
            }
            layer_provider.changeAttributeValues({id: attr_value})
            if (update == "false"):
                sink.addFeature(feature, QgsFeatureSink.FastInsert)
            feedback.setProgress(int(current * total))

        if (update == "true"):
            feedback.pushInfo("-----")
            feedback.pushInfo("STOPPING SCRIPT TO AVOID CREATING NEW LAYER")
            feedback.pushInfo("-----")
            raise Exception("--- IGNORE THIS ---")
        else:
            attribute_indexes = list(attr_indexes.values())
            layer_provider.deleteAttributes(attribute_indexes)
            layer.updateFields()
            layer.commitChanges()

        return {self.OUTPUT: dest_id}
Exemple #13
0
 def to_float(self, value):
     if value == "NULL":
         return QVariant()
     return value
Exemple #14
0
    def name_callback(self, key, target, year):
        """
        A callback to manage when key is "name"
        """
        # get the index name, that should be the value of display_name in
        # indexs_metadata table
        index_name = target[key]
        self.feedback.pushInfo("Managing index: {}".format(index_name))

        # get the metadata associated to the diplay name
        index_metadata = self.getIndexMetadata(index_name)
        index_table_name = index_metadata['index_table_name']
        index_classes = index_metadata['classes'] # would be similar to: [{"low": 0,"high": 15,"value": "Bajo","color": "dark-red"},...]
        index_metric_column = index_metadata['metric_column'] # the column name inside index_table_name where to get the value
        index_hiperlinks = index_metadata.setdefault('hyperlinks', '<some hiperlinks>')


        # look for layer into the project having the name as:
        # index_name or index_table_name
        index_layer = QgsProject.instance().mapLayersByName(index_name)
        if len(index_layer) == 0:
            index_layer = QgsProject.instance().mapLayersByName(index_table_name)
        if (len(index_layer) == 0) or not index_layer[0].isValid():
            raise QgsProcessingException(self.tr('Index layer: "{}" or "{}" not loaded into project or invalid, load all index tables before!').format(index_name, index_table_name))
        index_layer = index_layer[0]

        # get the index value to the specified year
        expression = '"{}" = {}'.format(YEAR_COLUMN, year) # TODO: year column should be configurable
        request = QgsFeatureRequest()
        request.setFilterExpression(expression)
        features = index_layer.getFeatures(request)
        features = [f for f in features]
        if len(features) != 1:
            self.feedback.reportError(self.tr('Skipped! Found: {} features instead of only 1 with expression: "{}" for layer: "{}"').format(len(features), request.filterExpression().dump(), index_layer.name()))
            # then do nothing to the target
            return
        
        # convert index_classes json in dictionary
        try:
            index_classes = json.loads(index_classes)
        except Exception as ex:
            raise QgsProcessingException(self.tr('Configured index: "{}" classes are malformed: {}').format(index_name, str(ex)))

        # add the value to the target
        feature = features[0]
        percentage = feature.attribute(index_metric_column)
        if percentage == QVariant(): # manage if value in DB is NULL
            percentage = None
        target['percentage'] = percentage

        # basing of index_classes set evaluation string and related color representation
        # btw set before value to undefined in case the value is outside the intervals
        target['value'] = None if isinstance(target['percentage'], int) else target['percentage']
        target['color'] = 'black'
        if target['percentage'] is not None:
            for color_class in index_classes["classes"]:
                if (isinstance(target['percentage'], str) and
                    target['percentage'] == color_class["value"]):
                        target['color'] = color_class["color"]
                if (not isinstance(target['percentage'], str) and
                    target['percentage'] >= color_class["low"] and
                    target['percentage'] < color_class["high"]):
                        target['value'] = self.tr(color_class["value"])
                        target['color'] = color_class["color"]
        
        # add all hiperlinks
        target.setdefault('hiperlinks', [])
        for i, hyperlink in enumerate(index_hiperlinks.split(',')):
            target['hiperlinks'].append(hyperlink)
    def test_create_nulls_and_defaults(self):
        """Test bug #21304 when pasting features from another layer and default values are not honored"""

        vl = createLayerWithOnePoint()
        vl.setDefaultValueDefinition(1, QgsDefaultValue('300'))

        features_data = []
        context = vl.createExpressionContext()
        features_data.append(QgsVectorLayerUtils.QgsFeatureData(QgsGeometry.fromWkt('Point (7 44)'), {0: 'test_1', 1: None}))
        features_data.append(QgsVectorLayerUtils.QgsFeatureData(QgsGeometry.fromWkt('Point (7 45)'), {0: 'test_2', 1: QVariant()}))
        features_data.append(QgsVectorLayerUtils.QgsFeatureData(QgsGeometry.fromWkt('Point (7 46)'), {0: 'test_3', 1: QVariant(QVariant.Int)}))
        features_data.append(QgsVectorLayerUtils.QgsFeatureData(QgsGeometry.fromWkt('Point (7 46)'), {0: 'test_4'}))
        features = QgsVectorLayerUtils.createFeatures(vl, features_data, context)

        for f in features:
            self.assertEqual(f.attributes()[1], 300, f.id())

        vl = createLayerWithOnePoint()
        vl.setDefaultValueDefinition(0, QgsDefaultValue("'my_default'"))

        features_data = []
        context = vl.createExpressionContext()
        features_data.append(QgsVectorLayerUtils.QgsFeatureData(QgsGeometry.fromWkt('Point (7 44)'), {0: None}))
        features_data.append(QgsVectorLayerUtils.QgsFeatureData(QgsGeometry.fromWkt('Point (7 45)'), {0: QVariant()}))
        features_data.append(QgsVectorLayerUtils.QgsFeatureData(QgsGeometry.fromWkt('Point (7 46)'), {0: QVariant(QVariant.String)}))
        features_data.append(QgsVectorLayerUtils.QgsFeatureData(QgsGeometry.fromWkt('Point (7 46)'), {}))
        features = QgsVectorLayerUtils.createFeatures(vl, features_data, context)

        for f in features:
            self.assertEqual(f.attributes()[0], 'my_default', f.id())
Exemple #16
0
    def upload_files(self, layer, field_index, features):
        """
        Upload given features' source files to remote server and return a dict
        formatted as changeAttributeValues expects to update 'datos' attribute
        to a remote location.
        """
        if not QSettings().value(
                'Asistente-LADM_COL/sources/document_repository', False, bool):
            self.message_with_duration_emitted.emit(
                QCoreApplication.translate(
                    "SourceHandler",
                    "The source files were not uploaded to the document repository because you have that option unchecked. You can still upload the source files later using the 'Upload Pending Source Files' menu."
                ), Qgis.Info, 10)
            return dict()

        # Test if we have Internet connection and a valid service
        dlg = self.qgis_utils.get_settings_dialog()
        res, msg = dlg.is_source_service_valid()

        if not res:
            msg['text'] = QCoreApplication.translate(
                "SourceHandler",
                "No file could be uploaded to the document repository. You can do it later from the 'Upload Pending Source Files' menu. Reason: {}"
            ).format(msg['text'])
            self.message_with_duration_emitted.emit(
                msg['text'], Qgis.Info,
                20)  # The data is still saved, so always show Info msg
            return dict()

        file_features = [
            feature for feature in features if not feature[field_index] == NULL
            and os.path.isfile(feature[field_index])
        ]
        total = len(features)
        not_found = total - len(file_features)

        upload_dialog = UploadProgressDialog(len(file_features), not_found)
        upload_dialog.show()
        count = 0
        upload_errors = 0
        new_values = dict()

        for feature in file_features:
            data_url = feature[field_index]
            file_name = os.path.basename(data_url)

            nam = QNetworkAccessManager()
            #reply.downloadProgress.connect(upload_dialog.update_current_progress)

            multiPart = QHttpMultiPart(QHttpMultiPart.FormDataType)
            textPart = QHttpPart()
            textPart.setHeader(QNetworkRequest.ContentDispositionHeader,
                               QVariant("form-data; name=\"driver\""))
            textPart.setBody(QByteArray().append('Local'))

            filePart = QHttpPart()
            filePart.setHeader(
                QNetworkRequest.ContentDispositionHeader,
                QVariant("form-data; name=\"file\"; filename=\"{}\"".format(
                    file_name)))
            file = QFile(data_url)
            file.open(QIODevice.ReadOnly)

            filePart.setBodyDevice(file)
            file.setParent(
                multiPart
            )  # we cannot delete the file now, so delete it with the multiPart

            multiPart.append(filePart)
            multiPart.append(textPart)

            service_url = '/'.join([
                QSettings().value(
                    'Asistente-LADM_COL/sources/service_endpoint',
                    DEFAULT_ENDPOINT_SOURCE_SERVICE),
                SOURCE_SERVICE_UPLOAD_SUFFIX
            ])
            request = QNetworkRequest(QUrl(service_url))
            reply = nam.post(request, multiPart)
            #reply.uploadProgress.connect(upload_dialog.update_current_progress)
            reply.error.connect(self.error_returned)
            multiPart.setParent(reply)

            # We'll block execution until we get response from the server
            loop = QEventLoop()
            reply.finished.connect(loop.quit)
            loop.exec_()

            response = reply.readAll()
            data = QTextStream(response, QIODevice.ReadOnly)
            content = data.readAll()

            if content is None:
                self.log.logMessage(
                    "There was an error uploading file '{}'".format(data_url),
                    PLUGIN_NAME, Qgis.Critical)
                upload_errors += 1
                continue

            try:
                response = json.loads(content)
            except json.decoder.JSONDecodeError:
                self.log.logMessage(
                    "Couldn't parse JSON response from server for file '{}'!!!"
                    .format(data_url), PLUGIN_NAME, Qgis.Critical)
                upload_errors += 1
                continue

            if 'error' in response:
                self.log.logMessage(
                    "STATUS: {}. ERROR: {} MESSAGE: {} FILE: {}".format(
                        response['status'], response['error'],
                        response['message'], data_url), PLUGIN_NAME,
                    Qgis.Critical)
                upload_errors += 1
                continue

            reply.deleteLater()

            if 'url' not in response:
                self.log.logMessage(
                    "'url' attribute not found in JSON response for file '{}'!"
                    .format(data_url), PLUGIN_NAME, Qgis.Critical)
                upload_errors += 1
                continue

            url = self.get_file_url(response['url'])
            new_values[feature.id()] = {field_index: url}

            count += 1
            upload_dialog.update_total_progress(count)

        if not_found > 0:
            self.message_with_duration_emitted.emit(
                QCoreApplication.translate(
                    "SourceHandler",
                    "{} out of {} records {} not uploaded to the document repository because {} file path is NULL or it couldn't be found in the local disk!"
                ).format(
                    not_found, total,
                    QCoreApplication.translate("SourceHandler", "was")
                    if not_found == 1 else QCoreApplication.translate(
                        "SourceHandler", "were"),
                    QCoreApplication.translate("SourceHandler", "its")
                    if not_found == 1 else QCoreApplication.translate(
                        "SourceHandler", "their")), Qgis.Info, 0)
        if len(new_values):
            self.message_with_duration_emitted.emit(
                QCoreApplication.translate(
                    "SourceHandler",
                    "{} out of {} files {} uploaded to the document repository and {} remote location stored in the database!"
                ).format(
                    len(new_values), total,
                    QCoreApplication.translate("SourceHandler", "was")
                    if len(new_values) == 1 else QCoreApplication.translate(
                        "SourceHandler", "were"),
                    QCoreApplication.translate("SourceHandler", "its")
                    if len(new_values) == 1 else QCoreApplication.translate(
                        "SourceHandler", "their")), Qgis.Info, 0)
        if upload_errors:
            self.message_with_duration_emitted.emit(
                QCoreApplication.translate(
                    "SourceHandler",
                    "{} out of {} files could not be uploaded to the document repository because of upload errors! See log for details."
                ).format(upload_errors, total), Qgis.Info, 0)

        return new_values
Exemple #17
0
        def addItem():
            if checkValidity():  # jeżeli pola są wypełnione
                newItem = QListWidgetItem()
                data = {}
                textList = []
                for input in inputs:
                    if isinstance(input, QLineEdit):
                        data[input.objectName()] = input.text()
                        textList.append(input.text())
                    if isinstance(input, QComboBox):
                        data[input.objectName()] = input.currentText()
                        textList.append(input.currentText())
                    if isinstance(input, QDateTimeEdit):
                        data[input.objectName()] = input.dateTime()
                        textList.append(
                            input.dateTime().toString("dd-MM-yyyy"))

                if elementId == 'e22':
                    input2 = utils.getWidgetByName(layout=self,
                                                   searchObjectType=QComboBox,
                                                   name='e23_cmbbx')
                    data[input2.objectName()] = input2.currentText()
                    textList.append(input2.currentText())
                if elementId == 'e18':
                    input2 = utils.getWidgetByName(layout=self,
                                                   searchObjectType=QComboBox,
                                                   name='e19_cmbbx')
                    data[input2.objectName()] = input2.currentText()
                    textList.append(input2.currentText())
                if elementId == 'e24':
                    input2 = utils.getWidgetByName(layout=self,
                                                   searchObjectType=QLineEdit,
                                                   name='e25_lineEdit')
                    data[input2.objectName()] = input2.text()
                    textList.append(input2.text())
                if elementId == 'e9':
                    input2 = utils.getWidgetByName(layout=self,
                                                   searchObjectType=QLineEdit,
                                                   name='e10_lineEdit')
                    data[input2.objectName()] = input2.text()
                    input2 = utils.getWidgetByName(
                        layout=self,
                        searchObjectType=QDateTimeEdit,
                        name='e10_dateTimeEdit')
                    data[input2.objectName()] = input2.dateTime()
                    input2 = utils.getWidgetByName(layout=self,
                                                   searchObjectType=QComboBox,
                                                   name='e10_cmbbx')
                    data[input2.objectName()] = input2.currentText()
                    data['xlink'] = None

                currentDatas = [
                    listWidget.item(i).data(Qt.UserRole)
                    for i in range(listWidget.count())
                ]
                if data in currentDatas:
                    utils.showPopup(
                        "Próba ponownego wpisania istniejącej wartości",
                        'Wprowadzana wartość już znajduje się na liście!')
                    return

                newItem.setData(Qt.UserRole, QVariant(data))
                newItem.setText(" - ".join(textList))
                listWidget.addItem(newItem)
                clearDataFromListWidget()  # czyszczenie
            else:
                utils.showPopup(
                    "Wypełnij formularz mapy podkładowej",
                    'Musisz zdefiniować poprawne wartości dla wszystkich wymaganych pól przed dodaniem do listy'
                )
Exemple #18
0
 def headerData(self, col, orientation, role):
     if orientation == Qt.Horizontal and role == Qt.DisplayRole:
         return QVariant(self.headerdata[col])
     return QVariant()
Exemple #19
0
def feature_validator(feature, layer):
    """Validate a QGIS feature by checking QGIS fields constraints

    The logic here is to:
    - if geometry is not None check if geometry type matches the layer type
    - loop through the fields and check for constraints:
        - NOT NULL, skip the next check if this fails
        - UNIQUE (only if not NULL)
        - EXPRESSION (QgsExpression configured in the form), always evaluated,
          even in case of NULLs

    Note: only hard constraints are checked!

    :param feature: QGIS feature
    :type feature: QgsFeature
    :param layer: QGIS layer
    :type layer: QgsVectorLayer
    :return: a dictionary of errors for each field + geometry
    :rtype: dict
    """

    errors = dict()
    geometry = feature.geometry()

    data_provider = layer.dataProvider()

    def _has_default_value(field_index, field):
        return (
            # Provider level
            data_provider.defaultValueClause(field_index)
            or data_provider.defaultValue(field_index)
            or field.defaultValueDefinition().isValid())

    # Check geometry type
    if not geometry.isNull() and geometry.wkbType() != layer.wkbType():
        if not (geometry.wkbType() == QgsWkbTypes.Point25D
                and layer.wkbType() == QgsWkbTypes.PointZ
                or geometry.wkbType() == QgsWkbTypes.Polygon25D
                and layer.wkbType() == QgsWkbTypes.PolygonZ
                or geometry.wkbType() == QgsWkbTypes.LineString25D
                and layer.wkbType() == QgsWkbTypes.LineStringZ
                or geometry.wkbType() == QgsWkbTypes.MultiPoint25D
                and layer.wkbType() == QgsWkbTypes.MultiPointZ
                or geometry.wkbType() == QgsWkbTypes.MultiPolygon25D
                and layer.wkbType() == QgsWkbTypes.MultiPolygonZ
                or geometry.wkbType() == QgsWkbTypes.MultiLineString25D
                and layer.wkbType() == QgsWkbTypes.MultiLineStringZ):

            errors['geometry'] = _(
                'Feature geometry type %s does not match layer type: %s') % (
                    QgsWkbTypes.displayString(geometry.wkbType()),
                    QgsWkbTypes.displayString(layer.wkbType()))

    def _set_error(field_name, error):
        if not field_name in errors:
            errors[field_name] = []
        errors[field_name].append(error)

    # Check fields "hard" constraints
    for field_index in range(layer.fields().count()):

        field = layer.fields().field(field_index)

        # check if fields is a join field:
        if layer.fields().fieldOrigin(field_index) == QgsFields.OriginJoin:
            continue

        # Check not null first, if it fails skip other tests (unique and expression)
        value = feature.attribute(field.name())
        # If there is a default value we assume it's not NULL (we cannot really know at this point
        # what will be the result of the default value clause evaluation, it might even be provider-side
        if (value is None or value
                == QVariant()) and not _has_default_value(field_index, field):
            not_null = (field.constraints().constraintOrigin(
                QgsFieldConstraints.ConstraintNotNull) !=
                        QgsFieldConstraints.ConstraintOriginNotSet
                        and field.constraints().constraintStrength(
                            QgsFieldConstraints.ConstraintNotNull)
                        == QgsFieldConstraints.ConstraintStrengthHard)
            if not_null:
                _set_error(field.name(), _('Field value must be NOT NULL'))
                continue

        value = feature.attribute(field_index)

        # Skip if NULL, not sure if we want to continue in this case but it seems pointless
        # to check for unique or type compatibility on NULLs
        if value is not None and value != QVariant():

            if not QVariant(value).convert(field.type()):
                _set_error(
                    field.name(),
                    _('Field value \'%s\' cannot be converted to %s') %
                    (value, QVariant.typeToName(field.type())))

            unique = (field.constraints().constraintOrigin(
                QgsFieldConstraints.ConstraintUnique) !=
                      QgsFieldConstraints.ConstraintOriginNotSet
                      and field.constraints().constraintStrength(
                          QgsFieldConstraints.ConstraintUnique)
                      == QgsFieldConstraints.ConstraintStrengthHard)

            if unique:
                # Search for features, excluding self if it's an update
                request = QgsFeatureRequest()
                request.setNoAttributes()
                request.setFlags(QgsFeatureRequest.NoGeometry)
                request.setLimit(2)
                if field.isNumeric():
                    request.setFilterExpression(
                        '"%s" = %s' %
                        (field.name().replace('"', '\\"'), value))
                elif field.type() == QVariant.String:
                    request.setFilterExpression(
                        '"%s" = \'%s\'' % (field.name().replace(
                            '"', '\\"'), value.replace("'", "\\'")))
                elif field.type() == QVariant.Date:
                    request.setFilterExpression(
                        'to_date("%s") = \'%s\'' % (field.name().replace(
                            '"', '\\"'), value.toString(Qt.ISODate)))
                elif field.type() == QVariant.DateTime:
                    request.setFilterExpression(
                        'to_datetime("{field_name}") = \'{date_time_string}\' OR to_datetime("{field_name}") = \'{date_time_string}.000\''
                        .format(field_name=field.name().replace('"', '\\"'),
                                date_time_string=value.toString(Qt.ISODate)))
                elif field.type(
                ) == QVariant.Bool:  # This does not make any sense, but still
                    request.setFilterExpression(
                        '"%s" = %s' % (field.name().replace(
                            '"', '\\"'), 'true' if value else 'false'))
                else:  # All the other formats: let's convert to string and hope for the best
                    request.setFilterExpression(
                        '"%s" = \'%s\'' %
                        (field.name().replace('"', '\\"'), value.toString()))

                # Exclude same feature by id
                found = [
                    f.id() for f in layer.getFeatures(request)
                    if f.id() != feature.id()
                ]
                if len(found) > 0:
                    _set_error(field.name(), _('Field value must be UNIQUE'))

        # Check for expressions, even in case of NULL because expressions may want to check for combined
        # conditions on multiple fields
        expression = (field.constraints().constraintOrigin(
            QgsFieldConstraints.ConstraintExpression) !=
                      QgsFieldConstraints.ConstraintOriginNotSet
                      and field.constraints().constraintStrength(
                          QgsFieldConstraints.ConstraintExpression)
                      == QgsFieldConstraints.ConstraintStrengthHard)
        if expression:
            constraints = field.constraints()
            expression = constraints.constraintExpression()
            description = constraints.constraintDescription()
            value = feature.attribute(field_index)
            exp = QgsExpression(expression)
            context = QgsExpressionContextUtils.createFeatureBasedContext(
                feature, layer.fields())
            context.appendScopes(
                QgsExpressionContextUtils.globalProjectLayerScopes(layer))
            if not bool(exp.evaluate(context)):
                if not description:
                    description = _('Expression check violation')
                _set_error(field.name(),
                           _("%s Expression: %s") % (description, expression))

    return errors
Exemple #20
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.TRACKS, context)
        axis = self.parameterAsSource(parameters, self.AXIS, context)
        self.name_field = self.parameterAsString(parameters, self.NAME_FIELD, context)
        self.axis = next(axis.getFeatures())
        self.name_field_index = source.fields().indexFromName(self.name_field)

        (sink, dest_id) = self.parameterAsSink(
            parameters,
            self.OUTPUT,
            context,
            PreCourlisFileLine.base_fields(),
            QgsWkbTypes.LineString,
            source.sourceCrs(),
        )
        if sink is None:
            raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))

        total = 100.0 / source.featureCount() if source.featureCount() else 0
        features = source.getFeatures()

        for current, feature in enumerate(features):
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                break

            intersection = feature.geometry().intersection(self.axis.geometry())
            assert not intersection.isNull()

            abs_long = self.axis.geometry().lineLocatePoint(intersection)

            # Take only the first parts (QgsMultiLineString => QgsLineString)
            axis_line = next(self.axis.geometry().constParts()).clone()
            track_line = next(feature.geometry().constParts()).clone()

            intersection_point = intersection.constGet()
            track_angle = qgslinestring_angle(track_line, intersection_point) * (
                180 / math.pi
            )
            axis_angle = qgslinestring_angle(axis_line, intersection_point) * (
                180 / math.pi
            )
            d_angle = (track_angle - axis_angle) % 360

            out = QgsFeature()
            out.setAttributes(
                [
                    # sec_id
                    None,
                    # sec_name
                    feature.attribute(self.name_field_index)
                    if self.name_field
                    else None,
                    # abs_long
                    abs_long,
                    # axis_x
                    intersection_point.x(),
                    # axis_y
                    intersection_point.y(),
                    # layers
                    "",
                    # p_id
                    QVariant(),
                    # topo_bat
                    "B",
                    # abs_lat
                    QVariant(),
                    # zfond
                    QVariant(),
                ]
            )
            if d_angle < 180:
                out.setGeometry(QgsGeometry(track_line.reversed()))
            else:
                out.setGeometry(QgsGeometry(feature.geometry()))

            # Add a feature in the sink
            sink.addFeature(out, QgsFeatureSink.FastInsert)

            # Update the progress bar
            feedback.setProgress(int(current * total))

        return {self.OUTPUT: dest_id}
Exemple #21
0
    def run(self, hiddenDialog=False):

        # enable possible remote pycharm debugging
        #import pydevd
        #pydevd.settrace('localhost', port=5678, stdoutToServer=True, stderrToServer=True)

        # last viewed/selected tab
        if QSettings().contains("/pdokservicesplugin/currenttab"):
            if Qgis.QGIS_VERSION_INT < 10900:
                # qgis <= 1.8
                self.dlg.tabs.widget(QSettings().value(
                    "/pdokservicesplugin/currenttab").toInt()[0])
            else:
                self.dlg.tabs.widget(
                    int(QSettings().value("/pdokservicesplugin/currenttab")))

        if self.servicesLoaded == False:
            pdokjson = os.path.join(os.path.dirname(__file__), ".",
                                    "pdok.json")
            f = open(pdokjson, 'r', encoding='utf-8')
            self.pdok = json.load(f)
            f.close()

            self.proxyModel = QSortFilterProxyModel()
            self.sourceModel = QStandardItemModel()
            self.proxyModel.setSourceModel(self.sourceModel)
            # filter == search on itemFilter column:
            self.proxyModel.setFilterKeyColumn(3)
            self.dlg.servicesView.setModel(self.proxyModel)
            self.dlg.servicesView.setEditTriggers(
                QAbstractItemView.NoEditTriggers)

            self.geocoderProxyModel = QSortFilterProxyModel()
            self.geocoderSourceModel = QStandardItemModel()

            self.geocoderProxyModel.setSourceModel(self.geocoderSourceModel)
            self.geocoderProxyModel.setFilterKeyColumn(0)
            self.dlg.geocoderResultView.setModel(self.geocoderProxyModel)
            self.dlg.geocoderResultView.setEditTriggers(
                QAbstractItemView.NoEditTriggers)

            #{"services":[
            #   {"naam":"WMS NHI","url":"http://geodata.nationaalgeoregister.nl/nhi/ows","layers":["dmlinks","dmnodes"],"type":"wms"},
            #   {"naam":"WMS NHI","url":"http://geodata.nationaalgeoregister.nl/nhi/ows","layers":["dmlinks","dmnodes"],"type":"wms"}
            # ]}
            #
            for service in self.pdok["services"]:
                # service[layer] was an array
                if isinstance(service["layers"], str) or isinstance(
                        service["layers"], str):
                    self.addSourceRow(service)

            self.dlg.layerSearch.textChanged.connect(self.filterLayers)
            self.dlg.layerSearch.setPlaceholderText(
                "woord uit laagnaam, type of service ")
            self.dlg.servicesView.selectionModel().selectionChanged.connect(
                self.showService)
            self.dlg.servicesView.doubleClicked.connect(self.loadService)
            # actually I want to load a service when doubleclicked on header
            # but as I cannot get this to work, let's disable clicking it then
            self.dlg.servicesView.verticalHeader().setSectionsClickable(False)
            self.dlg.servicesView.horizontalHeader().setSectionsClickable(
                False)

            #self.dlg.geocoderResultView.doubleClicked.connect(self.zoomToAddress)
            self.dlg.geocoderResultView.selectionModel(
            ).selectionChanged.connect(self.zoomToAddress)

            # hide itemFilter column:
            self.dlg.servicesView.hideColumn(3)
            self.servicesLoaded = True

        self.sourceModel.setHeaderData(2, Qt.Horizontal, "Service")
        self.sourceModel.setHeaderData(1, Qt.Horizontal, "Type")
        self.sourceModel.setHeaderData(0, Qt.Horizontal, "Laagnaam [style]")
        self.sourceModel.horizontalHeaderItem(2).setTextAlignment(Qt.AlignLeft)
        self.sourceModel.horizontalHeaderItem(1).setTextAlignment(Qt.AlignLeft)
        self.sourceModel.horizontalHeaderItem(0).setTextAlignment(Qt.AlignLeft)
        #self.dlg.servicesView.verticalHeader().hide()
        #self.dlg.servicesView.resizeColumnsToContents()
        self.dlg.servicesView.setColumnWidth(
            0, 300)  # set name to 300px (there are some huge layernames)
        self.dlg.servicesView.horizontalHeader().setStretchLastSection(True)
        # show the dialog ?
        if not hiddenDialog:
            self.dlg.show()
        # Run the dialog event loop
        #result = self.dlg.exec_()
        if Qgis.QGIS_VERSION_INT < 10900:
            # qgis <= 1.8
            QSettings().setValue("/pdokservicesplugin/currenttab",
                                 QVariant(self.dlg.tabs.currentIndex()))
        else:
            QSettings().setValue("/pdokservicesplugin/currenttab",
                                 self.dlg.tabs.currentIndex())
        self.removePointer()
Exemple #22
0
def getStringValue(settings, key, value):
    ''' returns key and its corresponding value. example: ("interval",30). '''
    if isSIPv2():
        return settings.value(key, value, type=str)
    else:
        return settings.value(key, QVariant(value)).toString()
Exemple #23
0
def getBoolValue(settings, key, value):
    ''' returns True if settings exist otherwise False. '''
    if isSIPv2():
        return settings.value(key, value, type=bool)
    else:
        return settings.value(key, QVariant(value)).toBool()
Exemple #24
0
    def test_make_features_compatible_attributes(self):
        """Test corner cases for attributes"""

        # Test feature with attributes
        fields = QgsFields()
        fields.append(QgsField('int_f', QVariant.Int))
        fields.append(QgsField('str_f', QVariant.String))
        f1 = QgsFeature(fields)
        f1['int_f'] = 1
        f1['str_f'] = 'str'
        f1.setGeometry(QgsGeometry.fromWkt('Point(9 45)'))
        f2 = f1
        QgsVectorLayerUtils.matchAttributesToFields(f2, fields)
        self.assertEqual(f1.attributes(), f2.attributes())
        self.assertTrue(f1.geometry().asWkt(), f2.geometry().asWkt())

        # Test pad with 0 with fields
        f1.setAttributes([])
        QgsVectorLayerUtils.matchAttributesToFields(f1, fields)
        self.assertEqual(len(f1.attributes()), 2)
        self.assertEqual(f1.attributes()[0], QVariant())
        self.assertEqual(f1.attributes()[1], QVariant())

        # Test pad with 0 without fields
        f1 = QgsFeature()
        QgsVectorLayerUtils.matchAttributesToFields(f1, fields)
        self.assertEqual(len(f1.attributes()), 2)
        self.assertEqual(f1.attributes()[0], QVariant())
        self.assertEqual(f1.attributes()[1], QVariant())

        # Test drop extra attrs
        f1 = QgsFeature(fields)
        f1.setAttributes([1, 'foo', 'extra'])
        QgsVectorLayerUtils.matchAttributesToFields(f1, fields)
        self.assertEqual(len(f1.attributes()), 2)
        self.assertEqual(f1.attributes()[0], 1)
        self.assertEqual(f1.attributes()[1], 'foo')

        # Rearranged fields
        fields2 = QgsFields()
        fields2.append(QgsField('str_f', QVariant.String))
        fields2.append(QgsField('int_f', QVariant.Int))
        f1 = QgsFeature(fields2)
        f1.setAttributes([1, 'foo', 'extra'])
        QgsVectorLayerUtils.matchAttributesToFields(f1, fields)
        self.assertEqual(len(f1.attributes()), 2)
        self.assertEqual(f1.attributes()[0], 'foo')
        self.assertEqual(f1.attributes()[1], 1)

        # mixed
        fields2.append(QgsField('extra', QVariant.String))
        fields.append(QgsField('extra2', QVariant.Int))
        f1.setFields(fields2)
        f1.setAttributes([1, 'foo', 'blah'])
        QgsVectorLayerUtils.matchAttributesToFields(f1, fields)
        self.assertEqual(len(f1.attributes()), 3)
        self.assertEqual(f1.attributes()[0], 'foo')
        self.assertEqual(f1.attributes()[1], 1)
        self.assertEqual(f1.attributes()[2], QVariant())

        fields.append(QgsField('extra', QVariant.Int))
        f1.setAttributes([1, 'foo', 'blah'])
        QgsVectorLayerUtils.matchAttributesToFields(f1, fields)
        self.assertEqual(len(f1.attributes()), 4)
        self.assertEqual(f1.attributes()[0], 1)
        self.assertEqual(f1.attributes()[1], 'foo')
        self.assertEqual(f1.attributes()[2], 'blah')
        self.assertEqual(f1.attributes()[3], QVariant())

        # case insensitive
        fields2.append(QgsField('extra3', QVariant.String))
        fields.append(QgsField('EXTRA3', QVariant.Int))
        f1.setFields(fields2)
        f1.setAttributes([1, 'foo', 'blah', 'blergh'])
        QgsVectorLayerUtils.matchAttributesToFields(f1, fields)
        self.assertEqual(len(f1.attributes()), 5)
        self.assertEqual(f1.attributes()[0], 'foo')
        self.assertEqual(f1.attributes()[1], 1)
        self.assertEqual(f1.attributes()[2], QVariant())
        self.assertEqual(f1.attributes()[3], 'blah')
        self.assertEqual(f1.attributes()[4], 'blergh')
    def checkCellValue(self, item: QTableWidgetItem):
        if item is None:
            return CellValue.ValueNone

        return self.checkValue(QVariant(item.text()))
Exemple #26
0
    def test_convert_compatible(self):
        """Test convertCompatible"""

        vl = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer', 'test',
                            'memory')

        # Valid values
        self.assertTrue(vl.fields()[0].convertCompatible(123.0))
        self.assertTrue(vl.fields()[0].convertCompatible(123))
        # Check NULL/invalid
        self.assertIsNone(vl.fields()[0].convertCompatible(None))
        self.assertEqual(
            vl.fields()[0].convertCompatible(QVariant(QVariant.Int)), NULL)
        # Not valid
        with self.assertRaises(ValueError) as cm:
            vl.fields()[0].convertCompatible('QGIS Rocks!')
        self.assertEqual(
            str(cm.exception),
            'Value could not be converted to field type int: Value "QGIS Rocks!" is not a number'
        )

        with self.assertRaises(ValueError) as cm:
            self.assertFalse(vl.fields()[0].convertCompatible(
                QDate(2020, 6, 30)))
        self.assertEqual(
            str(cm.exception),
            'Value could not be converted to field type int: Could not convert value "2020-06-30" to target type'
        )

        # Not valid: overflow
        with self.assertRaises(ValueError) as cm:
            self.assertFalse(vl.fields()[0].convertCompatible(2147483647 + 1))
        self.assertEqual(
            str(cm.exception),
            'Value could not be converted to field type int: Value "2147483648" is too large for integer field'
        )
        # Valid: narrow cast with loss of precision (!)
        self.assertTrue(vl.fields()[0].convertCompatible(123.123))

        vl = QgsVectorLayer('Point?crs=epsg:4326&field=date:date', 'test',
                            'memory')
        self.assertTrue(vl.fields()[0].convertCompatible(QDate(2020, 6, 30)))
        # Not valid
        with self.assertRaises(ValueError) as cm:
            self.assertFalse(vl.fields()[0].convertCompatible('QGIS Rocks!'))
        self.assertEqual(
            str(cm.exception),
            'Value could not be converted to field type QDate: Could not convert value "QGIS Rocks!" to target type'
        )
        with self.assertRaises(ValueError) as cm:
            self.assertFalse(vl.fields()[0].convertCompatible(123))
        self.assertEqual(
            str(cm.exception),
            'Value could not be converted to field type QDate: Could not convert value "123" to target type'
        )

        # Strings can store almost anything
        vl = QgsVectorLayer('Point?crs=epsg:4326&field=text:string(30)',
                            'test', 'memory')
        self.assertTrue(vl.fields()[0].convertCompatible(QDate(2020, 6, 30)))
        self.assertTrue(vl.fields()[0].convertCompatible('QGIS Rocks!'))
        self.assertTrue(vl.fields()[0].convertCompatible(123))
        self.assertTrue(vl.fields()[0].convertCompatible(123.456))
        # string overflow
        self.assertEqual(vl.fields()[0].length(), 30)
        with self.assertRaises(ValueError) as cm:
            self.assertTrue(vl.fields()[0].convertCompatible('x' * 31))
        self.assertEqual(
            str(cm.exception),
            'Value could not be converted to field type QString: String of length 31 exceeds maximum field length (30)'
        )

        vl = QgsVectorLayer('Point?crs=epsg:4326&field=double:double', 'test',
                            'memory')

        # Valid values
        self.assertTrue(vl.fields()[0].convertCompatible(123.0))
        self.assertTrue(vl.fields()[0].convertCompatible(123))
        # Check NULL/invalid
        self.assertIsNone(vl.fields()[0].convertCompatible(None))
        self.assertEqual(vl.fields()[0].convertCompatible(NULL), NULL)
        self.assertTrue(vl.fields()[0].convertCompatible(QVariant.Double))
        # Not valid
        with self.assertRaises(ValueError) as cm:
            self.assertFalse(vl.fields()[0].convertCompatible('QGIS Rocks!'))
        self.assertEqual(
            str(cm.exception),
            'Value could not be converted to field type double: Could not convert value "QGIS Rocks!" to target type'
        )
        with self.assertRaises(ValueError) as cm:
            self.assertFalse(vl.fields()[0].convertCompatible(
                QDate(2020, 6, 30)))
        self.assertEqual(
            str(cm.exception),
            'Value could not be converted to field type double: Could not convert value "2020-06-30" to target type'
        )
    def testModel(self):
        """Test the mapping model"""

        model = QgsFieldMappingModel(self.source_fields, self.destination_fields)
        self.assertEqual(model.rowCount(QModelIndex()), 3)
        self.assertIsNone(model.data(model.index(9999, 0), Qt.DisplayRole))
        # We now have this default mapping:
        # source exp        | destination fld
        # -------------------------------------------
        # source_field2     | destination_field1
        # source_field1     | destination_field2
        # NOT SET (NULL)    | destination_field3
        self.assertEqual(model.data(model.index(0, 0), Qt.DisplayRole), '"source_field2"')
        self.assertEqual(model.data(model.index(0, 1), Qt.DisplayRole), 'destination_field1')
        self.assertEqual(model.data(model.index(0, 3), Qt.DisplayRole), 10)
        self.assertEqual(model.data(model.index(0, 4), Qt.DisplayRole), 8)

        self.assertEqual(model.data(model.index(1, 0), Qt.DisplayRole), '"source_field1"')
        self.assertEqual(model.data(model.index(1, 1), Qt.DisplayRole), 'destination_field2')

        self.assertEqual(model.data(model.index(2, 0), Qt.DisplayRole), QVariant())
        self.assertEqual(model.data(model.index(2, 1), Qt.DisplayRole), 'destination_field3')

        # Test expression scope
        ctx = model.contextGenerator().createExpressionContext()
        self.assertTrue('source_field1' in ctx.fields().names())

        # Test add fields
        model.appendField(QgsField('destination_field4', QVariant.String))
        self.assertEqual(model.rowCount(QModelIndex()), 4)
        self.assertEqual(model.data(model.index(3, 1), Qt.DisplayRole), 'destination_field4')

        # Test remove field
        model.removeField(model.index(3, 0))
        self.assertEqual(model.rowCount(QModelIndex()), 3)
        self.assertEqual(model.data(model.index(2, 1), Qt.DisplayRole), 'destination_field3')

        # Test edit fields
        mapping = model.mapping()
        self.assertEqual(mapping[0].field.name(), 'destination_field1')
        self.assertEqual(mapping[1].field.name(), 'destination_field2')
        self.assertEqual(mapping[2].field.name(), 'destination_field3')
        self.assertEqual(mapping[0].originalName, 'destination_field1')
        self.assertEqual(mapping[1].originalName, 'destination_field2')
        self.assertEqual(mapping[2].originalName, 'destination_field3')

        # Test move up or down
        self.assertFalse(model.moveUp(model.index(0, 0)))
        self.assertFalse(model.moveUp(model.index(100, 0)))
        self.assertFalse(model.moveDown(model.index(2, 0)))
        self.assertFalse(model.moveDown(model.index(100, 0)))

        self.assertTrue(model.moveDown(model.index(0, 0)))
        mapping = model.mapping()
        self.assertEqual(mapping[1].field.name(), 'destination_field1')
        self.assertEqual(mapping[0].field.name(), 'destination_field2')
        self.assertEqual(mapping[2].field.name(), 'destination_field3')
        self.assertEqual(mapping[1].originalName, 'destination_field1')
        self.assertEqual(mapping[0].originalName, 'destination_field2')
        self.assertEqual(mapping[2].originalName, 'destination_field3')

        self.assertTrue(model.moveUp(model.index(1, 0)))
        mapping = model.mapping()
        self.assertEqual(mapping[0].field.name(), 'destination_field1')
        self.assertEqual(mapping[1].field.name(), 'destination_field2')
        self.assertEqual(mapping[2].field.name(), 'destination_field3')
        self.assertEqual(mapping[0].originalName, 'destination_field1')
        self.assertEqual(mapping[1].originalName, 'destination_field2')
        self.assertEqual(mapping[2].originalName, 'destination_field3')

        self.assertTrue(model.moveUp(model.index(2, 0)))
        mapping = model.mapping()
        self.assertEqual(mapping[0].field.name(), 'destination_field1')
        self.assertEqual(mapping[2].field.name(), 'destination_field2')
        self.assertEqual(mapping[1].field.name(), 'destination_field3')
        self.assertEqual(mapping[0].originalName, 'destination_field1')
        self.assertEqual(mapping[2].originalName, 'destination_field2')
        self.assertEqual(mapping[1].originalName, 'destination_field3')
Exemple #28
0
        def _test(layer, is_gpkg=False):

            # Skip fid and precision tests
            offset = 1 if is_gpkg else 0

            fieldFormatter = QgsFallbackFieldFormatter()

            QLocale.setDefault(QLocale('en'))

            # Precision is ignored for integers and longlongs
            self.assertEqual(fieldFormatter.representValue(layer, 0 + offset, {}, None, '123'), '123')
            self.assertEqual(fieldFormatter.representValue(layer, 0 + offset, {}, None, '123000'), '123,000')
            self.assertEqual(fieldFormatter.representValue(layer, 0 + offset, {}, None, '9999999'), '9,999,999')
            self.assertEqual(fieldFormatter.representValue(layer, 0 + offset, {}, None, None), 'NULL')
            self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, '123'), '123')
            self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, '123000'), '123,000')
            self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, '9999999'), '9,999,999')
            self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, None), 'NULL')

            self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, None), 'NULL')

            if not is_gpkg:
                self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '123'), '123.00000')
            else:
                self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '123'), '123')

            self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, None), 'NULL')

            if not is_gpkg:
                self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '123000'), '123,000.00000')
            else:
                self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '123000'), '123,000')

            self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '0'), '0')
            self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '0.127'), '0.127')
            self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '1.27e-1'), '0.127')

            if not is_gpkg:
                self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '-123'), '-123.00000')
            else:
                self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '-123'), '-123')

            self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '-0.127'), '-0.127')
            self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '-1.27e-1'), '-0.127')

            # Check with Italian locale
            QLocale.setDefault(QLocale('it'))

            self.assertEqual(fieldFormatter.representValue(layer, 0 + offset, {}, None, '9999999'),
                             '9.999.999')  # scientific notation for integers!
            self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, '123'), '123')
            self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, '123000'), '123.000')
            self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, '9999999'), '9.999.999')
            self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, None), 'NULL')

            self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, None), 'NULL')

            if not is_gpkg:
                self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '123000'), '123.000,00000')
            else:
                self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '123000'), '123.000')

            self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '0'), '0')

            if not is_gpkg:
                self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '123'), '123,00000')
            else:
                self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '123'), '123')

            self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '0.127'), '0,127')
            self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '1.27e-1'), '0,127')

            if not is_gpkg:
                self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '-123'), '-123,00000')
            else:
                self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '-123'), '-123')

            self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '-0.127'), '-0,127')
            self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '-1.27e-1'), '-0,127')

            # Check with custom locale without thousand separator

            custom = QLocale('en')
            custom.setNumberOptions(QLocale.OmitGroupSeparator)
            QLocale.setDefault(custom)

            self.assertEqual(fieldFormatter.representValue(layer, 0 + offset, {}, None, '9999999'),
                             '9999999')  # scientific notation for integers!
            self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, '123'), '123')
            self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, '9999999'), '9999999')

            if not is_gpkg:
                self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '123000'), '123000.00000')
            else:
                self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, '123000'), '123000')

            # Check string
            self.assertEqual(fieldFormatter.representValue(layer, 3 + offset, {}, None, '123'), '123')
            self.assertEqual(fieldFormatter.representValue(layer, 3 + offset, {}, None, 'a string'), 'a string')
            self.assertEqual(fieldFormatter.representValue(layer, 3 + offset, {}, None, ''), '')
            self.assertEqual(fieldFormatter.representValue(layer, 3 + offset, {}, None, None), 'NULL')

            # Check NULLs (this is what happens in real life inside QGIS)
            self.assertEqual(fieldFormatter.representValue(layer, 0 + offset, {}, None, QVariant(QVariant.String)),
                             'NULL')
            self.assertEqual(fieldFormatter.representValue(layer, 1 + offset, {}, None, QVariant(QVariant.String)),
                             'NULL')
            self.assertEqual(fieldFormatter.representValue(layer, 2 + offset, {}, None, QVariant(QVariant.String)),
                             'NULL')
            self.assertEqual(fieldFormatter.representValue(layer, 3 + offset, {}, None, QVariant(QVariant.String)),
                             'NULL')
    def addLinkBetweenSourceFeatureAndSelectedTargetFeature(
            self, tableWidgetSourceTargetMatchesRowIndex,
            sourceDataFeatureInfo):
        selectedFeatures = self.selectedTargetLayer.selectedFeatures()

        if len(selectedFeatures) == 0:
            self.iface.messageBar().pushMessage(
                '' + userFriendlyTableName +
                ' karttatasolla ei ole valittua kaavakohdetta, joten linkkiä lähtöaineistoon ei voida listätä',
                Qgis.Info,
                duration=20)
        if len(selectedFeatures) > 1:
            self.iface.messageBar().pushMessage(
                '' + userFriendlyTableName +
                ' karttatasolla on useita valittuja kaavakohteita, joten linkkiä lähtöaineistoon ei voida listätä',
                Qgis.Info,
                duration=20)
        else:
            # lisää tarvittaessa uusi lähdeaineistorivi tietokantaan,
            # lisää relaatio kaavakohteen ja lähdeaineistorivin välille ja
            # päivitä käyttöliittymän tauluun "Näytä yhdistetty kohde"-infopainike

            selectedFeatureID = selectedFeatures[0]["id"]

            apiIndex = self.dialogAddSourceDataLinks.comboBoxChooseSourceDataAPI.currentIndex(
            ) - 1
            sourceName = sourceDataFeatureInfo["nimi"]
            sourceReferenceAPIName = self.apis[apiIndex]["name"]
            #QgsMessageLog.logMessage('addLinkBetweenSourceFeatureAndSelectedTargetFeature, field.name(): ' + str(field.name()) + ', name: ' + name, 'Yleiskaava-työkalu', Qgis.Info)
            sourceDescription = ""
            for field in sourceDataFeatureInfo["feature"].fields():
                fieldName = field.name()
                fieldTypeName = self.yleiskaavaUtils.getStringTypeForFeatureField(
                    field)
                if fieldTypeName != "uuid" and fieldTypeName != "Bool":
                    value = sourceDataFeatureInfo["feature"][fieldName]
                    if value is not None:
                        sourceDescription += fieldName.lower() + ": "
                        if (fieldTypeName == "Date"
                                or fieldTypeName == "DateTime"
                            ) and not QVariant(value).isNull():
                            sourceDescription += QDateTime(
                                QVariant(value).value()).toString("dd.MM.yyyy")
                        else:
                            sourceDescription += str(value)

                        sourceDescription += "; "
            if sourceDescription != "":
                sourceDescription = sourceDescription[:-2]
            sourceLinkType = self.apis[apiIndex]["linkitys_tyyppi"]
            sourceLinkData = sourceDataFeatureInfo["linkki_data"]

            sourceData = {
                "nimi": sourceName,
                "lahde": sourceReferenceAPIName,
                "kuvaus": sourceDescription,
                "linkitys_tyyppi": sourceLinkType,
                "linkki_data": sourceLinkData
            }

            success = self.yleiskaavaDatabase.createSourceDataFeatureAndRelationToSpatialFeature(
                sourceData, self.selectedTargetLayer, selectedFeatureID)

            if success:
                self.iface.messageBar().pushMessage('Lähdelinkki lisätty',
                                                    Qgis.Info,
                                                    duration=20)
                # päivitä käyttöliittymän tauluun "Näytä yhdistetty kohde"-infopainike
                linkedFeatureWidget = QPushButton()
                linkedFeatureWidget.setText("Näytä yhdistetty kohde")
                linkedFeatureWidget.clicked.connect(
                    partial(self.showLinkedFeature, self.selectedTargetLayer,
                            selectedFeatures[0]["id"]))
                self.dialogAddSourceDataLinks.tableWidgetSourceTargetMatches.setCellWidget(
                    tableWidgetSourceTargetMatchesRowIndex,
                    AddSourceDataLinks.LINKED_FEATURE_INDEX,
                    linkedFeatureWidget)
                self.yleiskaavaUtils.refreshTargetLayersInProject()
            else:
                self.iface.messageBar().pushMessage(
                    'Lähdelinkin lisääminen epäonnistui',
                    Qgis.Critical,
                    duration=0)
    def updateTheme(self):
        # Päivitä teema ja siihen liitetyt kaavakohteet ja huomio asetukset, sekä mahd. useat teemat kohteella
        # Tarkista, onko teeman lomaketiedoissa eroa ja jos ei, niin ilmoita käyttäjälle.
        # Lisää teema sellaisille kaavakohteille, joilla sitä ei vielä ole, mutta käyttäjä on ko. kaavakohteen valinnut / valitsee
        # Anna käyttäjän valita kaavakohteet, joille teema päivitetään.
        # Varmista, että käyttäjä ei voi vahingossa päivittää jo aiemmin valitsemiaan kaavaobjekteja.
        # Varmista jotenkin, että käyttäjän valitsemat kohteet päivitetään vaikka niillä olisi eri teema kuin muutettava teema / rajoita valintamahdollisuus kohteisiin, joilla muutettavan teeman relaatio
        # Ilmoita käyttäjälle, että valitse kohteet, tms., jos ei ole valinnut.
        # Varmista, että self.currentTheme != None jo vaikka käyttäjä ei ole valinnut dialogista kohteita / lisää ensimmäiseksi vaihtoehdoksi comboboxiin "Valitse teema"
        # Huomioi, "Poista kaavakohteilta vanhat teemat"-asetuksen pois päältä olo, kun käyttäjä vain päivittää kohteilla jo olevaa teemaa -> ei siis tehdä duplikaattirelaatiota
        # näytä käyttöliittymässä yleiskaavan id, nimi, nro
        if self.currentTheme != None:
            themeID = self.currentTheme["id"]
            themeName = self.dialogUpdateThemeOfGroup.lineEditThemeName.text()
            themeDescription = self.dialogUpdateThemeOfGroup.plainTextEditThemeDescription.toPlainText(
            )

            if not self.equalsThemeAndFormTexts(themeName, themeDescription):
                # self.yleiskaavaDatabase.reconnectToDB()

                success = self.yleiskaavaDatabase.updateTheme(
                    themeID, themeName, themeDescription)

                if success:
                    self.currentTheme["alpha_sort_key"] = themeName
                    self.currentTheme["nimi"] = QVariant(themeName)
                    self.currentTheme["kuvaus"] = QVariant(themeDescription)
                    # self.currentTheme["id_yleiskaava"] = QVariant(themeDescription)

                    self.iface.messageBar().pushMessage('Teema päivitetty',
                                                        Qgis.Info,
                                                        duration=30)
            elif not self.dialogUpdateThemeOfGroup.checkBoxUpdatePolygonFeatures.isChecked(
            ) and not self.dialogUpdateThemeOfGroup.checkBoxUpdateSupplementaryPolygonFeatures.isChecked(
            ) and not self.dialogUpdateThemeOfGroup.checkBoxUpdateLineFeatures.isChecked(
            ) and not self.dialogUpdateThemeOfGroup.checkBoxUpdatePointFeatures.isChecked(
            ):
                self.iface.messageBar().pushMessage(
                    'Teemaan ei ole tehty muutoksia eikä päivitettäviä kaavakohteita ole valittu. Ei tehdä päivityksiä',
                    Qgis.Info,
                    duration=30)

            if self.dialogUpdateThemeOfGroup.checkBoxUpdatePolygonFeatures.isChecked(
            ):
                if not self.hasUserSelectedPolygonFeaturesForUpdate:
                    self.iface.messageBar().pushMessage(
                        'Et ole valinnut päivitettäviä aluevarauksia; aluevarauksia ei päivitetty',
                        Qgis.Warning,
                        duration=0)
                else:
                    self.progressDialog = QProgressDialog(
                        "Päivitetään aluevarausten teemoja...", "Keskeytä", 0,
                        100)
                    self.progressDialog.setWindowFlags(
                        Qt.WindowMinimizeButtonHint
                        | Qt.WindowMaximizeButtonHint
                        | Qt.WindowStaysOnTopHint)
                    self.updateSpatialFeatures("alue")
            if self.dialogUpdateThemeOfGroup.checkBoxUpdateSupplementaryPolygonFeatures.isChecked(
            ):
                if not self.hasUserSelectedSuplementaryPolygonFeaturesForUpdate:
                    self.iface.messageBar().pushMessage(
                        'Et ole valinnut päivitettäviä täydentäviä aluekohteita; täydentäviä aluekohteita ei päivitetty',
                        Qgis.Warning,
                        duration=0)
                else:
                    self.progressDialog = QProgressDialog(
                        "Päivitetään täydentävien aluekohteiden teemoja...",
                        "Keskeytä", 0, 100)
                    self.progressDialog.setWindowFlags(
                        Qt.WindowMinimizeButtonHint
                        | Qt.WindowMaximizeButtonHint
                        | Qt.WindowStaysOnTopHint)
                    self.updateSpatialFeatures("alue_taydentava")
            if self.dialogUpdateThemeOfGroup.checkBoxUpdateLineFeatures.isChecked(
            ):
                if not self.hasUserSelectedLineFeaturesForUpdate:
                    self.iface.messageBar().pushMessage(
                        'Et ole valinnut päivitettäviä viivamaisia kohteita; viivamaisia ei päivitetty',
                        Qgis.Warning,
                        duration=0)
                else:
                    self.progressDialog = QProgressDialog(
                        "Päivitetään viivamaisten kohteiden teemoja...",
                        "Keskeytä", 0, 100)
                    self.progressDialog.setWindowFlags(
                        Qt.WindowMinimizeButtonHint
                        | Qt.WindowMaximizeButtonHint
                        | Qt.WindowStaysOnTopHint)
                    self.updateSpatialFeatures("viiva")
            if self.dialogUpdateThemeOfGroup.checkBoxUpdatePointFeatures.isChecked(
            ):
                if not self.hasUserSelectedPointFeaturesForUpdate:
                    self.iface.messageBar().pushMessage(
                        'Et ole valinnut päivitettäviä pistemäisiä kohteita; pistemäisiä kohteita ei päivitetty',
                        Qgis.Warning,
                        duration=0)
                else:
                    self.progressDialog = QProgressDialog(
                        "Päivitetään pistemäisten kohteiden teemoja...",
                        "Keskeytä", 0, 100)
                    self.progressDialog.setWindowFlags(
                        Qt.WindowMinimizeButtonHint
                        | Qt.WindowMaximizeButtonHint
                        | Qt.WindowStaysOnTopHint)
                    self.updateSpatialFeatures("piste")

            if self.shouldHide:
                self.dialogUpdateThemeOfGroup.hide()

            # else:
            #     self.iface.messageBar().pushMessage("Kaavakohteita ei päivitetty", Qgis.Critical)

        elif self.dialogUpdateThemeOfGroup.checkBoxRemoveOldThemesFromSpatialFeatures.isChecked(
        ):
            # ainoastaan poistetaan vanha(t) teema(t) valituilta kohteilta
            if self.dialogUpdateThemeOfGroup.checkBoxUpdatePolygonFeatures.isChecked(
            ):
                if not self.hasUserSelectedPolygonFeaturesForUpdate:
                    self.iface.messageBar().pushMessage(
                        'Et ole valinnut päivitettäviä aluevarauksia; aluevarauksia ei päivitetty',
                        Qgis.Warning,
                        duration=0)
                else:
                    success = self.removeThemesFromSpatialFeatures("alue")
                    if success:
                        self.iface.messageBar().pushMessage(
                            'Aluvarausten teemat poistettu',
                            Qgis.Info,
                            duration=30)
            if self.dialogUpdateThemeOfGroup.checkBoxUpdateSupplementaryPolygonFeatures.isChecked(
            ):
                if not self.hasUserSelectedSuplementaryPolygonFeaturesForUpdate:
                    self.iface.messageBar().pushMessage(
                        'Et ole valinnut päivitettäviä täydentäviä aluekohteita; täydentäviä aluekohteita ei päivitetty',
                        Qgis.Warning,
                        duration=0)
                else:
                    success = self.removeThemesFromSpatialFeatures(
                        "alue_taydentava")
                    if success:
                        self.iface.messageBar().pushMessage(
                            'Täydentävien aluekohteiden teemat poistettu',
                            Qgis.Info,
                            duration=30)
            if self.dialogUpdateThemeOfGroup.checkBoxUpdateLineFeatures.isChecked(
            ):
                if not self.hasUserSelectedLineFeaturesForUpdate:
                    self.iface.messageBar().pushMessage(
                        'Et ole valinnut päivitettäviä viivamaisia kohteita; viivamaisia ei päivitetty',
                        Qgis.Warning,
                        duration=0)
                else:
                    success = self.removeThemesFromSpatialFeatures("viiva")
                    if success:
                        self.iface.messageBar().pushMessage(
                            'Viivamaisten kohteiden teemat poistettu',
                            Qgis.Info,
                            duration=30)
            if self.dialogUpdateThemeOfGroup.checkBoxUpdatePointFeatures.isChecked(
            ):
                if not self.hasUserSelectedPointFeaturesForUpdate:
                    self.iface.messageBar().pushMessage(
                        'Et ole valinnut päivitettäviä pistemäisiä kohteita; pistemäisiä kohteita ei päivitetty',
                        Qgis.Warning,
                        duration=0)
                else:
                    success = self.removeThemesFromSpatialFeatures("piste")
                    if success:
                        self.iface.messageBar().pushMessage(
                            'Pistemäisten kohteiden teemat poistettu',
                            Qgis.Info,
                            duration=30)

            if self.shouldHide:
                self.dialogUpdateThemeOfGroup.hide()
            self.finishUpdate()
        else:
            self.iface.messageBar().pushMessage('Valitse teema',
                                                Qgis.Info,
                                                duration=30)