def createCsvVectorLayer(dataSourceHandler,
                             vectorLayerDescriptor,
                             qgsVectorLayer=None):
        ':type dataSourceHandler:GeoCsvDataSourceHandler'
        ':type vectorLayerDescriptor: CsvVectorLayerDescriptor'
        if not qgsVectorLayer:
            # create VectorLayer using memory provider
            _path = vectorLayerDescriptor.geometryType
            _path += '?index=yes'
            if vectorLayerDescriptor.crs:
                _path += "&crs=" + vectorLayerDescriptor.crs.toWkt()
            qgsVectorLayer = QgsVectorLayer(_path,
                                            vectorLayerDescriptor.layerName,
                                            "memory")
        else:
            # reset the memory layer
            qgsVectorLayer.dataProvider().deleteFeatures(
                qgsVectorLayer.allFeatureIds())
            qgsVectorLayer.dataProvider().deleteAttributes(
                qgsVectorLayer.dataProvider().fields().allAttributesList())

        # : :type dataProvider: QgsVectorDataProvider
        dataProvider = qgsVectorLayer.dataProvider()
        dataProvider.addAttributes(
            vectorLayerDescriptor.getAttributesAsQgsFields())
        qgsVectorLayer.updateFields()
        dataProvider.addFeatures(
            dataSourceHandler.createFeaturesFromCsv(vectorLayerDescriptor))
        qgsVectorLayer.updateExtents()
        csvVectorLayer = CsvVectorLayer(qgsVectorLayer, vectorLayerDescriptor)
        csvVectorLayer.updateGeoCsvPath(dataSourceHandler.getPathToCsvFile())
        return csvVectorLayer
Ejemplo n.º 2
0
 def loadLayer(self, view):
     uri = u'dbname=\'%s\' host=%s port=%s user=\'%s\' password=\'%s\' key=\'id\' table="%s"."%s" (geom) sql=' % ( self.getData()[0],
     self.getData()[1], self.getData()[2], self.getData()[3],
     self.getData()[4], self.getData()[5], view )
     layer = QgsVectorLayer(uri, view[len(view.split('_')[0])+1:], "postgres")
     if (self.data[-1] == 2) and (layer.allFeatureIds() != []):
         self.createValueMap(layer, view)
         return layer
     elif (self.data[-1] == 1):
         self.createValueMap(layer, view)
         return layer
     return False
Ejemplo n.º 3
0
 def loadLayer(self, view):
     uri = u'dbname=\'%s\' host=%s port=%s user=\'%s\' password=\'%s\' key=\'id\' table="%s"."%s" (geom) sql=' % (
         self.getData()[0], self.getData()[1], self.getData()[2],
         self.getData()[3], self.getData()[4], self.getData()[5], view)
     layer = QgsVectorLayer(uri, view[len(view.split('_')[0]) + 1:],
                            "postgres")
     if (self.data[-1] == 2) and (layer.allFeatureIds() != []):
         self.createValueMap(layer, view)
         return layer
     elif (self.data[-1] == 1):
         self.createValueMap(layer, view)
         return layer
     return False
def create_vectorlayer(_fields, data, geometries=None, geomtype='Point', crs=4326):
    """From GroupStats"""
    vlayer = QgsVectorLayer("{}?crs=epsg:{}".format(geomtype, str(crs)), "test", "memory")
    provider = vlayer.dataProvider()

    fields = QgsFields()
    for _field in _fields:
        fields.append(_field)

    provider.addAttributes(_fields)
    vlayer.updateFields()
    feats = []
    for f_idx, features_attributes in enumerate(data):
        feature = QgsFeature(fields)
        for idx, attr in enumerate(features_attributes):
            feature[_fields[idx].name()] = attr
        if geometries:
            feature.setGeometry(geometries[f_idx])
        else:
            feature.setGeometry(None)
        #print("Feature valid: " + str(feature.isValid()))
        feats.append(feature)
    provider.addFeatures(feats)
    vlayer.updateExtents()

    features = [f for f in vlayer.getFeatures('True') if f.id() in vlayer.allFeatureIds()]
    feature_ids = [feature.id() for feature in features]

    QgsProject.instance().addMapLayer(vlayer)
    hide_print = True
    if not hide_print:
        print("1. Valid vlayer '{}'".format(vlayer.isValid()))
        print("2. feature_ids: " + str(feature_ids))
        print("5. QgsVectorLayer.getFeature(): " + str([vlayer.getFeature(x).id() for x in feature_ids]))
        print("6. QgsVectorLayer.getFeature() type: " + str([str(type(vlayer.getFeature(x))) for x in feature_ids]))
        print("7. QgsVectorLayer.getFeatures(): " + str([x.id() for x in vlayer.getFeatures(feature_ids)]))
        print("8. QgsVectorLayer.featureCount(): " + str(vlayer.featureCount()))

    root = QgsProject.instance().layerTreeRoot()
    root.addLayer(vlayer)
    return vlayer
 def createCsvVectorLayer(dataSourceHandler, vectorLayerDescriptor, qgsVectorLayer=None):                
     ':type dataSourceHandler:GeoCsvDataSourceHandler'
     ':type vectorLayerDescriptor: CsvVectorLayerDescriptor'                     
     if not qgsVectorLayer:
         # create VectorLayer using memory provider
         _path = vectorLayerDescriptor.geometryType
         _path += '?index=yes'
         if vectorLayerDescriptor.crs:
             _path += "&crs=" + vectorLayerDescriptor.crs.toWkt()            
         qgsVectorLayer = QgsVectorLayer(_path, vectorLayerDescriptor.layerName, "memory")
     else:            
         # reset the memory layer 
         qgsVectorLayer.dataProvider().deleteFeatures(qgsVectorLayer.allFeatureIds())
         qgsVectorLayer.dataProvider().deleteAttributes(qgsVectorLayer.dataProvider().fields().allAttributesList())
                                 
     # : :type dataProvider: QgsVectorDataProvider                
     dataProvider = qgsVectorLayer.dataProvider() 
     dataProvider.addAttributes(vectorLayerDescriptor.getAttributesAsQgsFields())        
     qgsVectorLayer.updateFields()
     dataProvider.addFeatures(dataSourceHandler.createFeaturesFromCsv(vectorLayerDescriptor))                
     qgsVectorLayer.updateExtents()        
     csvVectorLayer = CsvVectorLayer(qgsVectorLayer, vectorLayerDescriptor)
     csvVectorLayer.updateGeoCsvPath(dataSourceHandler.getPathToCsvFile())                 
     return csvVectorLayer 
Ejemplo n.º 6
0
class BestPathFinder(object):

    RAW_FN_TEMPLATE = 'frd_raw_{}_num_{}.shp'
    SIMPLIFIED_FN_TEMPLATE = 'frd_simplified_{}_num_{}.shp'

    def __init__(self, dtm_layer, exclusion_areas_layer=None):

        self.dtm = {"layer": dtm_layer, "array": af.raster_2_array(dtm_layer)}
        self.converter = af.Converter(dtm_layer)

        self.exclusion_areas = {
            "layer":
            exclusion_areas_layer,
            "array":
            exclusion_areas_fn.create_exclusion_array(dtm_layer,
                                                      exclusion_areas_layer)
        }

        self.optimizer = a_star.DefaultConstraintsOptimizer(
            self.dtm["array"], self.converter.pixel_width)
        self.set_parameters({
            "semi_size": 5,
            "min_slope_pct": 0,
            "max_slope_pct": 10,
            "penalty_factor_xy": 50,
            "penalty_factor_z": 50
        })

    def _slope_label(self):
        return _slope_label(self.parameters["min_slope_pct"],
                            self.parameters["max_slope_pct"])

    def set_output_folder(self, output_folder):

        self.output_folder = output_folder

    def set_parameters(self, parameters):

        self.parameters = parameters

        self.optimizer.reset_config(parameters["min_slope_pct"] / 100.0,
                                    parameters["max_slope_pct"] / 100.0,
                                    parameters["semi_size"],
                                    parameters["penalty_factor_xy"],
                                    parameters["penalty_factor_z"],
                                    self.exclusion_areas["array"])

    def add_segment_to(self,
                       goal_coords,
                       max_dist_m=None,
                       iterative=False,
                       force=False):

        self.check_point(goal_coords)
        goal_index = self.converter.coord_to_index([goal_coords])
        self.optimizer.add_segment_to(goal_index[0], max_dist_m, iterative,
                                      force)
        self._update_output_layer()
        self._update_output_layer()

    def remove_last_segment(self):

        self.optimizer.remove_last_segment()

        self._update_output_layer()
        self._update_output_layer()

    def check_point(self, goal_coords):
        """Check for given points not inside exclusion areas and not out of
        dtm extent limits
        """
        if not self.dtm['layer'].extent().contains(
                QgsPoint(goal_coords[0], goal_coords[-1])):
            raise (ValueError(
                u"Error: ¡No se admiten puntos fuera de la extensión\n" +
                u" del Modelo Digital del Terreno!."))

        if self.exclusion_areas["layer"]:
            if self.optimizer._waypoints_index == []:
                for elem in self.exclusion_areas["layer"].dataProvider(
                ).getFeatures():
                    if elem.geometry().contains(
                            QgsPoint(goal_coords[0], goal_coords[-1])):
                        raise (ValueError(
                            u"Error: ¡No se admiten puntos dentro de" +
                            u" las áreas de exclusión!"))

    def _output_raw_filename(self):
        """Output the raw filename with last updated output index on set
            folder.
        """
        import glob
        file_mask = 'forest_road_lines_{}_num_{}.shp'  # due raw_points_layer is a memory layer
        key_for_glob = os.path.join(self.output_folder,
                                    file_mask.format(self._slope_label(), '*'))
        files_list = glob.glob(key_for_glob)
        raw_file_name = self.RAW_FN_TEMPLATE.format(self._slope_label(),
                                                    len(files_list) + 1)

        return os.path.join(self.output_folder, raw_file_name)

    def create_raw_output_layer(self):
        """creates the raw layer as point memory layer
        """
        fn = self._output_raw_filename()
        layer_name = os.path.splitext(os.path.split(fn)[-1])[0]

        self.raw_layer = QgsVectorLayer(
            'Point?crs={}'.format(self.dtm["layer"].crs().toWkt()), layer_name,
            'memory')

        self._update_output_layer()
        if profiler:
            profiler.toolrenderer.setSelectionMethod(2)

        return self.raw_layer

    def _update_output_layer(self):
        """Updates the output layer (raw)
        """
        if self.raw_layer is None or not self.raw_layer.isValid():
            return False
        raw_path_index = self.optimizer.waypoints_index()
        raw_path_height_profile, _, _ = \
                dtm_values_at_points(self.dtm["array"],
                                     raw_path_index,
                                     self.parameters["max_slope_pct"] / 100.0,
                                     self.converter.pixel_width)
        dp = self.raw_layer.dataProvider()
        dp.deleteFeatures(self.raw_layer.allFeatureIds())

        raw_path_coords = self.converter.index_to_coord(raw_path_index)

        features = []
        for point_coords in raw_path_coords:
            new_feature = QgsFeature()
            new_feature.setGeometry(
                QgsGeometry.fromPoint(QgsPoint(*point_coords)))
            features.append(new_feature)

        result, _ = dp.addFeatures(features)
        dp.updateExtents()
        self.raw_layer.triggerRepaint()

        return result

    def create_simplified_output_layer(self, polyline_threshold):
        """Create the simplified layer (LineString Layer)
        """
        raw_path_index = self.optimizer.waypoints_index()

        if polyline_threshold > 0 and len(raw_path_index) > 0:
            path_simplifier = polysimplify.VWSimplifier(raw_path_index)
            simp_path_index = path_simplifier.from_threshold(
                polyline_threshold)
        else:
            simp_path_index = raw_path_index
        """Recover the height profile and create the lines layer."""
        lines_height_data, lines_section_slope, lines_projected_cum_dist = \
                dtm_values_at_points(self.dtm["array"],
                                     simp_path_index,
                                     self.parameters["max_slope_pct"] / 100.0,
                                     self.converter.pixel_width)

        road_layer = af.line_layer_from_coords_array(
            self.converter.index_to_coord(simp_path_index), self.output_folder,
            self.dtm["layer"].crs(), self._slope_label(), lines_height_data,
            lines_section_slope, lines_projected_cum_dist)

        AttributeLayerSymbology(road_layer, "slope_p",
                                self.parameters["max_slope_pct"])
        return road_layer
Ejemplo n.º 7
0
class SpatialPreview(QTabWidget, Ui_frmPropertyPreview):
    """
    Widget for previewing spatial unit on either local map or web source.
    """
    def __init__(self, parent=None, iface=None):
        QTabWidget.__init__(self, parent)
        self.setupUi(self)

        self._notif_bar = None
        self._ol_loaded = False
        self._overlay_layer = None
        self.sel_highlight = None
        self.memory_layer = None
        self._db_session = STDMDb.instance().session

        self.set_iface(iface)

        #Web config
        self._web_spatial_loader = WebSpatialLoader(self.spatial_web_view, self)

        #Connect signals
        self._web_spatial_loader.loadError.connect(self.on_spatial_browser_error)
        self._web_spatial_loader.loadProgress.connect(self.on_spatial_browser_loading)
        self._web_spatial_loader.loadFinished.connect(self.on_spatial_browser_finished)
        self._web_spatial_loader.zoomChanged.connect(self.on_map_zoom_level_changed)
        self.rbGMaps.toggled.connect(self.on_load_GMaps)
        self.rbOSM.toggled.connect(self.on_load_OSM)
        self.zoomSlider.sliderReleased.connect(self.on_zoom_changed)
        self.btnResetMap.clicked.connect(self.on_reset_web_map)
        self.btnSync.clicked.connect(self.on_sync_extents)
        QgsMapLayerRegistry.instance().layersWillBeRemoved.connect(self._on_overlay_to_be_removed)

    def set_iface(self, iface):
        self._iface = iface
        self.local_map.set_iface(iface)

    def set_notification_bar(self, notif_bar):
        """
        Set notification widget.
        :param notif_bar: Notification widget.
        """
        self._notif_bar = notif_bar

    def notification_bar(self):
        """
        :return: Currently configured notification bar.
        """
        return self._notif_bar

    def _insert_notification(self, msg, level, clear_first = True):
        if self._notif_bar is None:
            return

        if clear_first:
            self._notif_bar.clear()

        self._notif_bar.insertNotification(msg, level)

    def iface(self):
        return self._iface

    def _setDefaults(self):
        """
        Set default settings
        """
        self.set_canvas_background_color(self.canvasBgColor)

    def set_canvas_background_color(self,color):
        """
        Set the background color of the map canvas
        """
        self.localMap.setCanvasColor(color)
        self.canvasBgColor = color

    def refresh_canvas_layers(self, process_events=False):
        """
        Reload map layers in the viewer canvas.
        """
        self.local_map.refresh_layers()

    def load_web_map(self):
        """
        Loads the web map into the view using canvas extents if there
        are existing layers in the map canvas.
        """
        if not self._ol_loaded:
            self._web_spatial_loader.load()

    def _create_vector_layer(self, geom_type, prj_code):
        """
        Creates/resets the internal vector layer that will be used to draw
        the spatial unit overlays.
        :param geom_type: Geometry type
        :type geom_type: str
        :param prj_code: EPSG code
        :type prj_code: int
        """
        self._overlay_layer = QgsVectorLayer(
            u"{0}?crs=epsg:{1!s}&field=lbname:string(20)&index=yes".format(geom_type,
                                                                      prj_code),
            "view_str_spatial_unit",
            "memory")

    def draw_spatial_unit(self, spatial_unit, model):
        """
        Draw geometry of the given model in the respective local and web views.
        :param model: Source model whose geometry will be drawn.
        :type model: object
        :param clear_existing: Clears any existing features prior to adding the
        new features.
        :type clear_existing: bool
        """
        if model is None:
            msg = QApplication.translate("SpatialPreview",
                                         "Data model is empty, the spatial "
                                         "unit cannot be rendered.")
            QMessageBox.critical(self,
                                 QApplication.translate(
                                    "SpatialPreview",
                                    "Spatial Unit Preview"),
                                 msg)

            return

        table_name = spatial_unit.name
        if not pg_table_exists(table_name):
            msg = QApplication.translate("SpatialPreview",
                                         "The spatial unit data source could "
                                         "not be retrieved, the feature cannot "
                                         "be rendered.")
            QMessageBox.critical(
                self,
                QApplication.translate(
                    "SpatialPreview",
                    "Spatial Unit Preview"),
                msg
            )

            return

        sp_unit_manager = SpatialUnitManagerDockWidget(self.iface())
        spatial_cols = sp_unit_manager.geom_columns(spatial_unit)

        geom, geom_col = None, ""
        sc_obj = None
        for sc in spatial_cols:

            db_geom = getattr(model, sc.name)
            #Use the first non-empty geometry
            # value in the collection
            if not db_geom is None:
                sc_obj = sc
                geom_col = sc.name
                geom = db_geom
        QApplication.processEvents()

        lyr = sp_unit_manager.geom_col_layer_name(
            table_name, sc_obj
        )

        sp_unit_manager.add_layer_by_name(lyr)

        if geom is not None:

            self.highlight_spatial_unit(
                spatial_unit, geom, self.local_map.canvas
            )
            self._web_spatial_loader.add_overlay(
                model, geom_col
            )

    def clear_sel_highlight(self):
        """
        Removes sel_highlight from the canvas.
        :return:
        """
        if self.sel_highlight is not None:
            self.sel_highlight = None

    def get_layer_source(self, layer):
        """
        Get the layer table name if the source is from the database.
        :param layer: The layer for which the source is checked
        :type QGIS vectorlayer
        :return: String or None
        """
        source = layer.source()
        vals = dict(re.findall('(\S+)="?(.*?)"? ', source))
        try:
            table = vals['table'].split('.')
            table_name = table[1].strip('"')
            return table_name
        except KeyError:
            return None

    def spatial_unit_layer(self, spatial_unit, active_layer):
        """
        Check whether the layer is parcel layer or not.
        :param active_layer: The layer to be checked
        :type QGIS vectorlayer
        :return: Boolean
        """
        if self.active_layer_check():
            layers = self.iface().legendInterface().layers()

            for layer in layers:
                layer_source = self.get_layer_source(layer)
                if layer_source == spatial_unit.name:
                    self.iface().setActiveLayer(layer)
                    return True

            not_sp_msg = QApplication.translate(
                'SpatialPreview',
                'You have selected a non-spatial_unit layer. '
                'Please select a spatial unit layer to preview.'
            )
            QMessageBox.information(
                self._iface.mainWindow(),
                "Error",
                not_sp_msg
            )


    def active_layer_check(self):
        """
        Check if there is active layer and if not, displays
        a message box to select a parcel layer.
        :return:
        """
        active_layer = self._iface.activeLayer()
        if active_layer is None:
            no_layer_msg = QApplication.translate(
                'SpatialPreview',
                'Please add a spatial unit layer '
                'to preview the spatial unit.'
            )
            QMessageBox.critical(
                self._iface.mainWindow(),
                "Error",
                no_layer_msg
            )
            return False
        else:
            return True

    def _add_geom_to_map(self, geom):

        if self._overlay_layer is None:
            return

        geom_func = geom.ST_AsText()
        geom_wkt = self._db_session.scalar(geom_func)

        dp = self._overlay_layer.dataProvider()

        feat = QgsFeature()
        qgis_geom = QgsGeometry.fromWkt(geom_wkt)
        feat.setGeometry(g)
        dp.addFeatures([feat])

        self._overlay_layer.updateExtents()

        return qgis_geom.boundingBox()

    def highlight_spatial_unit(
            self, spatial_unit, geom, map_canvas
    ):
        layer = self._iface.activeLayer()
        map_canvas.setExtent(layer.extent())
        map_canvas.refresh()

        if self.spatial_unit_layer(spatial_unit, layer):

            self.clear_sel_highlight()

            qgis_geom = qgsgeometry_from_wkbelement(geom)

            self.sel_highlight = QgsHighlight(
                map_canvas, qgis_geom, layer
            )
            rgba = selection_color()
            self.sel_highlight.setFillColor(rgba)

            self.sel_highlight.setWidth(3)
            self.sel_highlight.show()

            extent = qgis_geom.boundingBox()
            extent.scale(1.5)
            map_canvas.setExtent(extent)
            map_canvas.refresh()
        else:
            return


    def remove_preview_layer(self, layer, name):
        """
        Removes the preview layer from legend.
        :param layer: The preview polygon layer to be removed.
        :param name: The name of the layer to be removed.
        :return: None
        """
        if layer is not None:
            for lyr in QgsMapLayerRegistry.instance().mapLayers().values():
                if lyr.name() == name:
                    id = lyr.id()
                    QgsMapLayerRegistry.instance().removeMapLayer(id)


    def delete_local_features(self, feature_ids=[]):
        """
        Removes features in the local map overlay.
        """
        del_status = False

        if not self._overlay_layer is None:
            if len(feature_ids) == 0:
                feature_ids = self._overlay_layer.allFeatureIds()

            del_status = self._overlay_layer.dataProvider().deleteFeatures(feature_ids)

        return del_status

    def remove_layer(self):
        """
        Removes both the local and web layers.
        """
        if not self._overlay_layer is None:
            QgsProject.instance().layerTreeRoot().removeLayer(self._overlay_layer)

            #Clear web overlays
            self._web_spatial_loader.removeOverlay()

            self._overlay_layer = None

    def _on_overlay_to_be_removed(self, layers_ids):
        """
        Resets the local layer variable and removes the web overlay.
        """
        if not self._overlay_layer is None:
            if self._overlay_layer.id() in layers_ids:
                self.remove_layer()

    def on_spatial_browser_error(self, err):
        """
        Slot raised when an error occurs when loading items in the property browser
        """
        self._insert_notification(err, ERROR)

    def on_spatial_browser_loading(self, progress):
        """
        Slot raised when the property browser is loading.
        Displays the progress of the page loading as a percentage.
        """
        if progress <= 0 or progress >= 100:
            self.lblInfo.setText("")
            self.lblInfo.setVisible(False)

        else:
            self.lblInfo.setVisible(True)
            self.lblInfo.setText("Loading...%d%%)"%(progress))

    def on_spatial_browser_finished(self, status):
        """
        Slot raised when the property browser finishes loading the content
        """
        if status:
            if len(self.local_map.canvas_layers()) > 0:# and not self._ol_loaded:
                self.on_sync_extents()

            self._ol_loaded = True
            #self._overlay_spatial_unit()

        else:
            msg = QApplication.translate("SpatialPreview",
                                         "Error: Spatial unit cannot be loaded.")
            self._insert_notification(msg, ERROR)

    def on_zoom_changed(self):
        """
        Slot raised when the zoom value in the slider changes.
        This is only raised once the user releases the slider with the mouse.
        """
        zoom = self.zoomSlider.value()
        self._web_spatial_loader.zoom_to_level(zoom)

    def on_load_GMaps(self, state):
        """
        Slot raised when a user clicks to set Google Maps Satellite
        as the base layer
        """
        if state:
            self._web_spatial_loader.setBaseLayer(GMAP_SATELLITE)

    def on_load_OSM(self, state):
        """
        Slot raised when a user clicks to set OSM as the base layer
        """
        if state:
            self._web_spatial_loader.setBaseLayer(OSM)

    def on_map_zoom_level_changed(self, level):
        """
        Slot which is raised when the zoom level of the map changes.
        """
        self.zoomSlider.setValue(level)

    def on_reset_web_map(self):
        """
        Slot raised when the user clicks to reset the property
        location in the map.
        """
        self._web_spatial_loader.zoom_to_extents()

    def on_sync_extents(self):
        """
        Slot raised to synchronize the webview extents with those of the
        local map canvas.
        """
        if len(self.local_map.canvas_layers()) > 0:# and self._ol_loaded:
            curr_extent = self.map_extents()
            self._web_spatial_loader.zoom_to_map_extents(curr_extent)

    def map_extents(self):
        """
        :returns: Current extents of the local map.
        :rtype: QgsRectangle
        """
        return self.local_map.extent()

    def canvas_zoom_to_extent(self, extent):
        self.local_map.canvas.setExtent(extent)
Ejemplo n.º 8
0
 def addPolygonsToMap(self, polygons):
     if not QgsProject.instance().mapLayersByName(
             'Location Lab - catchments'):
         vl = QgsVectorLayer('Polygon?crs=EPSG:4326',
                             'Location Lab - catchments', 'memory')
         pr = vl.dataProvider()
         vl.startEditing()
         pr.addAttributes([
             QgsField('id', QVariant.Int),
             QgsField(self.tr('provider'), QVariant.String),
             QgsField(self.tr('mode'), QVariant.String),
             QgsField(self.tr('value'), QVariant.Int),
             QgsField(self.tr('units'), QVariant.String),
             QgsField(self.tr('lat'), QVariant.Double),
             QgsField(self.tr('lon'), QVariant.Double),
             QgsField('params', QVariant.String)
         ])
         vl.commitChanges()
         QgsProject.instance().addMapLayer(vl)
     vl = QgsProject.instance().mapLayersByName(
         'Location Lab - catchments')[0]
     pr = vl.dataProvider()
     next_id = len(vl.allFeatureIds()) + 1
     id_field = self.fieldsComboBox.currentField()
     if id_field:
         layer = self.layerComboBox.currentLayer()
         new_ids = [
             feature.attribute(id_field)
             for feature in list(layer.getFeatures())
         ]
     for index, p in enumerate(polygons):
         feature = QgsFeature()
         points = []
         if p['source'] == 'HERE' or p['source'] == 'OpenRouteService':
             coordinates = [c.split(',') for c in p['coordinates']]
             for xy in coordinates:
                 points.append(QgsPointXY(float(xy[1]), float(xy[0])))
         feature = QgsFeature()
         feature.setGeometry(QgsGeometry.fromPolygonXY([points]))
         lat, lon = p['coords'].split(',')
         for key in ['key', 'url', 'coordinates',
                     'start']:  #unnecessary params
             if key in p.keys():
                 p.pop(key)
         feature.setAttributes([
             next_id if not id_field else new_ids[index],
             self.providersComboBox.currentText(),
             self.modesComboBox.currentText().lower(),
             self.valueSpinBox.value(),
             self.unitsComboBox.currentText(),
             float(lat),
             float(lon),
             str(p)
         ])
         pr.addFeatures([feature])
         next_id += 1
     vl.updateExtents()
     self.iface.mapCanvas().setExtent(
         QgsCoordinateTransform(
             vl.crs(),
             self.iface.mapCanvas().mapSettings().destinationCrs(),
             QgsProject().instance()).transform(vl.extent()))
     self.iface.mapCanvas().refresh()
Ejemplo n.º 9
0
class SpatialPreview(QTabWidget, Ui_frmPropertyPreview):
    """
    Widget for previewing spatial unit on either local map or web source.
    """
    def __init__(self, parent=None, iface=None):
        QTabWidget.__init__(self, parent)
        self.setupUi(self)

        self._notif_bar = None
        self._ol_loaded = False
        self._overlay_layer = None
        self.sel_highlight = None
        self.memory_layer = None
        self._db_session = STDMDb.instance().session

        self.set_iface(iface)

        #Web config
        self._web_spatial_loader = WebSpatialLoader(self.spatial_web_view,
                                                    self)

        #Connect signals
        self._web_spatial_loader.loadError.connect(
            self.on_spatial_browser_error)
        self._web_spatial_loader.loadProgress.connect(
            self.on_spatial_browser_loading)
        self._web_spatial_loader.loadFinished.connect(
            self.on_spatial_browser_finished)
        self._web_spatial_loader.zoomChanged.connect(
            self.on_map_zoom_level_changed)
        self.rbGMaps.toggled.connect(self.on_load_GMaps)
        self.rbOSM.toggled.connect(self.on_load_OSM)
        self.zoomSlider.sliderReleased.connect(self.on_zoom_changed)
        self.btnResetMap.clicked.connect(self.on_reset_web_map)
        self.btnSync.clicked.connect(self.on_sync_extents)
        QgsMapLayerRegistry.instance().layersWillBeRemoved.connect(
            self._on_overlay_to_be_removed)

    def set_iface(self, iface):
        self._iface = iface
        self.local_map.set_iface(iface)

    def set_notification_bar(self, notif_bar):
        """
        Set notification widget.
        :param notif_bar: Notification widget.
        """
        self._notif_bar = notif_bar

    def notification_bar(self):
        """
        :return: Currently configured notification bar.
        """
        return self._notif_bar

    def _insert_notification(self, msg, level, clear_first=True):
        if self._notif_bar is None:
            return

        if clear_first:
            self._notif_bar.clear()

        self._notif_bar.insertNotification(msg, level)

    def iface(self):
        return self._iface

    def _setDefaults(self):
        """
        Set default settings
        """
        self.set_canvas_background_color(self.canvasBgColor)

    def set_canvas_background_color(self, color):
        """
        Set the background color of the map canvas
        """
        self.localMap.setCanvasColor(color)
        self.canvasBgColor = color

    def refresh_canvas_layers(self, process_events=False):
        """
        Reload map layers in the viewer canvas.
        """
        self.local_map.refresh_layers()

    def load_web_map(self):
        """
        Loads the web map into the view using canvas extents if there
        are existing layers in the map canvas.
        """
        if not self._ol_loaded:
            self._web_spatial_loader.load()

    def _create_vector_layer(self, geom_type, prj_code):
        """
        Creates/resets the internal vector layer that will be used to draw
        the spatial unit overlays.
        :param geom_type: Geometry type
        :type geom_type: str
        :param prj_code: EPSG code
        :type prj_code: int
        """
        self._overlay_layer = QgsVectorLayer(
            u"{0}?crs=epsg:{1!s}&field=lbname:string(20)&index=yes".format(
                geom_type, prj_code), "view_str_spatial_unit", "memory")

    def draw_spatial_unit(self, spatial_unit, model):
        """
        Draw geometry of the given model in the respective local and web views.
        :param model: Source model whose geometry will be drawn.
        :type model: object
        :param clear_existing: Clears any existing features prior to adding the
        new features.
        :type clear_existing: bool
        """
        if model is None:
            msg = QApplication.translate(
                "SpatialPreview", "Data model is empty, the spatial "
                "unit cannot be rendered.")
            QMessageBox.critical(
                self,
                QApplication.translate("SpatialPreview",
                                       "Spatial Unit Preview"), msg)

            return

        table_name = spatial_unit.name
        if not pg_table_exists(table_name):
            msg = QApplication.translate(
                "SpatialPreview", "The spatial unit data source could "
                "not be retrieved, the feature cannot "
                "be rendered.")
            QMessageBox.critical(
                self,
                QApplication.translate("SpatialPreview",
                                       "Spatial Unit Preview"), msg)

            return

        sp_unit_manager = SpatialUnitManagerDockWidget(self.iface())
        spatial_cols = sp_unit_manager.geom_columns(spatial_unit)

        geom, geom_col = None, ""
        sc_obj = None
        for sc in spatial_cols:

            db_geom = getattr(model, sc.name)
            #Use the first non-empty geometry
            # value in the collection
            if not db_geom is None:
                sc_obj = sc
                geom_col = sc.name
                geom = db_geom
        QApplication.processEvents()

        lyr = sp_unit_manager.geom_col_layer_name(table_name, sc_obj)

        sp_unit_manager.add_layer_by_name(lyr)

        if geom is not None:

            self.highlight_spatial_unit(spatial_unit, geom,
                                        self.local_map.canvas)
            self._web_spatial_loader.add_overlay(model, geom_col)

    def clear_sel_highlight(self):
        """
        Removes sel_highlight from the canvas.
        :return:
        """
        if self.sel_highlight is not None:
            self.sel_highlight = None

    def get_layer_source(self, layer):
        """
        Get the layer table name if the source is from the database.
        :param layer: The layer for which the source is checked
        :type QGIS vectorlayer
        :return: String or None
        """
        source = layer.source()
        vals = dict(re.findall('(\S+)="?(.*?)"? ', source))
        try:
            table = vals['table'].split('.')
            table_name = table[1].strip('"')
            return table_name
        except KeyError:
            return None

    def spatial_unit_layer(self, spatial_unit, active_layer):
        """
        Check whether the layer is parcel layer or not.
        :param active_layer: The layer to be checked
        :type QGIS vectorlayer
        :return: Boolean
        """
        if self.active_layer_check():
            layers = self.iface().legendInterface().layers()

            for layer in layers:
                layer_source = self.get_layer_source(layer)
                if layer_source == spatial_unit.name:
                    self.iface().setActiveLayer(layer)
                    return True

            not_sp_msg = QApplication.translate(
                'SpatialPreview',
                'You have selected a non-spatial_unit layer. '
                'Please select a spatial unit layer to preview.')
            QMessageBox.information(self._iface.mainWindow(), "Error",
                                    not_sp_msg)

    def active_layer_check(self):
        """
        Check if there is active layer and if not, displays
        a message box to select a parcel layer.
        :return:
        """
        active_layer = self._iface.activeLayer()
        if active_layer is None:
            no_layer_msg = QApplication.translate(
                'SpatialPreview', 'Please add a spatial unit layer '
                'to preview the spatial unit.')
            QMessageBox.critical(self._iface.mainWindow(), "Error",
                                 no_layer_msg)
            return False
        else:
            return True

    def _add_geom_to_map(self, geom):

        if self._overlay_layer is None:
            return

        geom_func = geom.ST_AsText()
        geom_wkt = self._db_session.scalar(geom_func)

        dp = self._overlay_layer.dataProvider()

        feat = QgsFeature()
        qgis_geom = QgsGeometry.fromWkt(geom_wkt)
        feat.setGeometry(g)
        dp.addFeatures([feat])

        self._overlay_layer.updateExtents()

        return qgis_geom.boundingBox()

    def highlight_spatial_unit(self, spatial_unit, geom, map_canvas):
        layer = self._iface.activeLayer()
        map_canvas.setExtent(layer.extent())
        map_canvas.refresh()

        if self.spatial_unit_layer(spatial_unit, layer):

            self.clear_sel_highlight()

            qgis_geom = qgsgeometry_from_wkbelement(geom)

            self.sel_highlight = QgsHighlight(map_canvas, qgis_geom, layer)
            rgba = selection_color()
            self.sel_highlight.setFillColor(rgba)

            self.sel_highlight.setWidth(3)
            self.sel_highlight.show()

            extent = qgis_geom.boundingBox()
            extent.scale(1.5)
            map_canvas.setExtent(extent)
            map_canvas.refresh()
        else:
            return

    def remove_preview_layer(self, layer, name):
        """
        Removes the preview layer from legend.
        :param layer: The preview polygon layer to be removed.
        :param name: The name of the layer to be removed.
        :return: None
        """
        if layer is not None:
            for lyr in QgsMapLayerRegistry.instance().mapLayers().values():
                if lyr.name() == name:
                    id = lyr.id()
                    QgsMapLayerRegistry.instance().removeMapLayer(id)

    def delete_local_features(self, feature_ids=[]):
        """
        Removes features in the local map overlay.
        """
        del_status = False

        if not self._overlay_layer is None:
            if len(feature_ids) == 0:
                feature_ids = self._overlay_layer.allFeatureIds()

            del_status = self._overlay_layer.dataProvider().deleteFeatures(
                feature_ids)

        return del_status

    def remove_layer(self):
        """
        Removes both the local and web layers.
        """
        if not self._overlay_layer is None:
            QgsProject.instance().layerTreeRoot().removeLayer(
                self._overlay_layer)

            #Clear web overlays
            self._web_spatial_loader.removeOverlay()

            self._overlay_layer = None

    def _on_overlay_to_be_removed(self, layers_ids):
        """
        Resets the local layer variable and removes the web overlay.
        """
        if not self._overlay_layer is None:
            if self._overlay_layer.id() in layers_ids:
                self.remove_layer()

    def on_spatial_browser_error(self, err):
        """
        Slot raised when an error occurs when loading items in the property browser
        """
        self._insert_notification(err, ERROR)

    def on_spatial_browser_loading(self, progress):
        """
        Slot raised when the property browser is loading.
        Displays the progress of the page loading as a percentage.
        """
        if progress <= 0 or progress >= 100:
            self.lblInfo.setText("")
            self.lblInfo.setVisible(False)

        else:
            self.lblInfo.setVisible(True)
            self.lblInfo.setText("Loading...%d%%)" % (progress))

    def on_spatial_browser_finished(self, status):
        """
        Slot raised when the property browser finishes loading the content
        """
        if status:
            if len(self.local_map.canvas_layers()
                   ) > 0:  # and not self._ol_loaded:
                self.on_sync_extents()

            self._ol_loaded = True
            #self._overlay_spatial_unit()

        else:
            msg = QApplication.translate(
                "SpatialPreview", "Error: Spatial unit cannot be loaded.")
            self._insert_notification(msg, ERROR)

    def on_zoom_changed(self):
        """
        Slot raised when the zoom value in the slider changes.
        This is only raised once the user releases the slider with the mouse.
        """
        zoom = self.zoomSlider.value()
        self._web_spatial_loader.zoom_to_level(zoom)

    def on_load_GMaps(self, state):
        """
        Slot raised when a user clicks to set Google Maps Satellite
        as the base layer
        """
        if state:
            self._web_spatial_loader.setBaseLayer(GMAP_SATELLITE)

    def on_load_OSM(self, state):
        """
        Slot raised when a user clicks to set OSM as the base layer
        """
        if state:
            self._web_spatial_loader.setBaseLayer(OSM)

    def on_map_zoom_level_changed(self, level):
        """
        Slot which is raised when the zoom level of the map changes.
        """
        self.zoomSlider.setValue(level)

    def on_reset_web_map(self):
        """
        Slot raised when the user clicks to reset the property
        location in the map.
        """
        self._web_spatial_loader.zoom_to_extents()

    def on_sync_extents(self):
        """
        Slot raised to synchronize the webview extents with those of the
        local map canvas.
        """
        if len(self.local_map.canvas_layers()) > 0:  # and self._ol_loaded:
            curr_extent = self.map_extents()
            self._web_spatial_loader.zoom_to_map_extents(curr_extent)

    def map_extents(self):
        """
        :returns: Current extents of the local map.
        :rtype: QgsRectangle
        """
        return self.local_map.extent()

    def canvas_zoom_to_extent(self, extent):
        self.local_map.canvas.setExtent(extent)
Ejemplo n.º 10
0
class SpatialPreview(QTabWidget, Ui_frmPropertyPreview):
    """
    Widget for previewing spatial unit on either local map or web source.
    """
    def __init__(self, parent=None, iface=None):
        QTabWidget.__init__(self, parent)
        self.setupUi(self)

        self._notif_bar = None
        self._ol_loaded = False
        self._overlay_layer = None

        self._db_session = STDMDb.instance().session

        self.set_iface(iface)

        #Web config
        self._web_spatial_loader = WebSpatialLoader(self.spatial_web_view, self)

        #Connect signals
        self._web_spatial_loader.loadError.connect(self.on_spatial_browser_error)
        self._web_spatial_loader.loadProgress.connect(self.on_spatial_browser_loading)
        self._web_spatial_loader.loadFinished.connect(self.on_spatial_browser_finished)
        self._web_spatial_loader.zoomChanged.connect(self.on_map_zoom_level_changed)
        self.rbGMaps.toggled.connect(self.on_load_GMaps)
        self.rbOSM.toggled.connect(self.on_load_OSM)
        self.zoomSlider.sliderReleased.connect(self.on_zoom_changed)
        self.btnResetMap.clicked.connect(self.on_reset_web_map)
        self.btnSync.clicked.connect(self.on_sync_extents)
        QgsMapLayerRegistry.instance().layersWillBeRemoved.connect(self._on_overlay_to_be_removed)

    def set_iface(self, iface):
        self._iface = iface
        self.local_map.set_iface(iface)

    def set_notification_bar(self, notif_bar):
        """
        Set notification widget.
        :param notif_bar: Notification widget.
        """
        self._notif_bar = notif_bar

    def notification_bar(self):
        """
        :return: Currently configured notification bar.
        """
        return self._notif_bar

    def _insert_notification(self, msg, level, clear_first = True):
        if self._notif_bar is None:
            return

        if clear_first:
            self._notif_bar.clear()

        self._notif_bar.insertNotification(msg, level)

    def iface(self):
        return self._iface

    def _setDefaults(self):
        """
        Set default settings
        """
        self.set_canvas_background_color(self.canvasBgColor)

    def set_canvas_background_color(self,color):
        """
        Set the background color of the map canvas
        """
        self.localMap.setCanvasColor(color)
        self.canvasBgColor = color

    def refresh_canvas_layers(self, process_events=False):
        """
        Reload map layers in the viewer canvas.
        """
        self.local_map.refresh_layers()

    def load_web_map(self):
        """
        Loads the web map into the view using canvas extents if there
        are existing layers in the map canvas.
        """
        if not self._ol_loaded:
            self._web_spatial_loader.load()

    def _create_vector_layer(self, geom_type, prj_code):
        """
        Creates/resets the internal vector layer that will be used to draw
        the spatial unit overlays.
        :param geom_type: Geometry type
        :type geom_type: str
        :param prj_code: EPSG code
        :type prj_code: int
        """
        self._overlay_layer = QgsVectorLayer(
            u"{0}?crs=epsg:{1!s}&field=lbname:string(20)&index=yes".format(geom_type,
                                                                      prj_code),
            "view_str_spatial_unit",
            "memory")

    def draw_spatial_unit(self, model, clear_existing=True):
        """
        Draw geometry of the given model in the respective local and web views.
        :param model: Source model whose geometry will be drawn.
        :type model: object
        :param clear_existing: Clears any existing features prior to adding the
        new features.
        :type clear_existing: bool
        """
        if model is None:
            msg = QApplication.translate("SpatialPreview",
                                         "Data model is empty, the spatial "
                                         "unit cannot be rendered.")
            QMessageBox.critical(self, QApplication.translate("SpatialPreview",
                                                              "Spatial Unit Preview"),
                                 msg)

            return

        table_name = model.__class__.__name__.replace(' ', '_').lower()
        if not pg_table_exists(table_name):
            msg = QApplication.translate("SpatialPreview",
                                         "The spatial unit data source could "
                                         "not be retrieved, the feature cannot "
                                         "be rendered.")
            QMessageBox.critical(self, QApplication.translate("SpatialPreview",
                                                              "Spatial Unit Preview"),
                                 msg)

            return

        spatial_cols = table_column_names(table_name, True)

        geom, geom_col = None, ""

        for sc in spatial_cols:
            geom = getattr(model, sc)

            #Use the first non-empty geometry value in the collection
            if not geom is None:
                geom_col = sc

        if geom is None:
            msg = QApplication.translate("SpatialPreview",
                                         "The selected spatial unit does not "
                                         "contain a valid geometry.")
            QMessageBox.critical(self, QApplication.translate("SpatialPreview",
                                                              "Spatial Unit Preview"),
                                 msg)

            return

        geom_type, epsg_code = geometryType(table_name, geom_col)

        if self._overlay_layer is None:
            self._create_vector_layer(geom_type, epsg_code)

            #Add layer to map
            QgsMapLayerRegistry.instance().addMapLayer(self._overlay_layer,
                                                       False)
            #Ensure it is always added on top
            QgsProject.instance().layerTreeRoot().insertLayer(0, self._overlay_layer)

        if clear_existing:
            self.delete_local_features()

        feat, extent = self._add_geom_to_map(geom)

        #Add spatial unit to web viewer
        self._web_spatial_loader.add_overlay(model, geom_col)

        #Increase bounding box by 50%, so that layer slightly zoomed out
        extent.scale(1.5)

        #Select feature. Hack for forcing a selection by using inversion
        self._overlay_layer.invertSelection()

        self._iface.mapCanvas().setExtent(extent)
        self._iface.mapCanvas().refresh()
        self.refresh_canvas_layers()

        #Need to force event so that layer is shown
        QCoreApplication.sendEvent(self.local_map, QShowEvent())

    def _add_geom_to_map(self, geom):
        if self._overlay_layer is None:
            return

        geom_func = geom.ST_AsText()
        geom_wkt = self._db_session.scalar(geom_func)

        dp = self._overlay_layer.dataProvider()

        feat = QgsFeature()
        g = QgsGeometry.fromWkt(geom_wkt)
        feat.setGeometry(g)
        dp.addFeatures([feat])

        self._overlay_layer.updateExtents()

        return feat, g.boundingBox()

    def delete_local_features(self, feature_ids=[]):
        """
        Removes features in the local map overlay.
        """
        del_status = False

        if not self._overlay_layer is None:
            if len(feature_ids) == 0:
                feature_ids = self._overlay_layer.allFeatureIds()

            del_status = self._overlay_layer.dataProvider().deleteFeatures(feature_ids)

        return del_status

    def remove_layer(self):
        """
        Removes both the local and web layers.
        """
        if not self._overlay_layer is None:
            QgsProject.instance().layerTreeRoot().removeLayer(self._overlay_layer)

            #Clear web overlays
            self._web_spatial_loader.removeOverlay()

            self._overlay_layer = None

    def _on_overlay_to_be_removed(self, layers_ids):
        """
        Resets the local layer variable and removes the web overlay.
        """
        if not self._overlay_layer is None:
            if self._overlay_layer.id() in layers_ids:
                self.remove_layer()

    def on_spatial_browser_error(self, err):
        """
        Slot raised when an error occurs when loading items in the property browser
        """
        self._insert_notification(err, ERROR)

    def on_spatial_browser_loading(self, progress):
        """
        Slot raised when the property browser is loading.
        Displays the progress of the page loading as a percentage.
        """
        if progress <= 0 or progress >= 100:
            self.lblInfo.setText("")
            self.lblInfo.setVisible(False)

        else:
            self.lblInfo.setVisible(True)
            self.lblInfo.setText("Loading...%d%%)"%(progress))

    def on_spatial_browser_finished(self, status):
        """
        Slot raised when the property browser finishes loading the content
        """
        if status:
            if len(self.local_map.canvas_layers()) > 0 and not self._ol_loaded:
                self.on_sync_extents()

            self._ol_loaded = True
            #self._overlay_spatial_unit()

        else:
            msg = QApplication.translate("SpatialPreview",
                                         "Error: Spatial unit cannot be loaded.")
            self._insert_notification(msg, ERROR)

    def on_zoom_changed(self):
        """
        Slot raised when the zoom value in the slider changes.
        This is only raised once the user releases the slider with the mouse.
        """
        zoom = self.zoomSlider.value()
        self._web_spatial_loader.zoom_to_level(zoom)

    def on_load_GMaps(self, state):
        """
        Slot raised when a user clicks to set Google Maps Satellite
        as the base layer
        """
        if state:
            self._web_spatial_loader.setBaseLayer(GMAP_SATELLITE)

    def on_load_OSM(self, state):
        """
        Slot raised when a user clicks to set OSM as the base layer
        """
        if state:
            self._web_spatial_loader.setBaseLayer(OSM)

    def on_map_zoom_level_changed(self, level):
        """
        Slot which is raised when the zoom level of the map changes.
        """
        self.zoomSlider.setValue(level)

    def on_reset_web_map(self):
        """
        Slot raised when the user clicks to reset the property
        location in the map.
        """
        self._web_spatial_loader.zoom_to_extents()

    def on_sync_extents(self):
        """
        Slot raised to synchronize the webview extents with those of the
        local map canvas.
        """
        if len(self.local_map.canvas_layers()) > 0 and self._ol_loaded:
            curr_extent = self.map_extents()
            self._web_spatial_loader.zoom_to_map_extents(curr_extent)

    def map_extents(self):
        """
        :returns: Current extents of the local map.
        :rtype: QgsRectangle
        """
        return self.local_map.extent()

    def canvas_zoom_to_extent(self, extent):
        self.local_map.canvas.setExtent(extent)
Ejemplo n.º 11
0
class AutoFieldsTests( unittest.TestCase ):

    @classmethod
    def setUpClass( self ):
        self.msg = MessageManager( 'debug', None ) 
        self.msg.show( "Info! SetUp started", 'info', True )
        #Initialize QGIS app
        app = QgsApplication([], True)
        QgsApplication.setPrefixPath("/usr", True)
        QgsApplication.initQgis()
        
        #Configure QSettings (organization and application name)
        self.settings = QSettings("GeoTux", "QGIS-Plugin-Test") 

        #Load layer, add field f1, and add layer to Registry
        baseDir = os.path.dirname( os.path.realpath( __file__ ) )
        self.layerPath = os.path.join( baseDir, 'test_data', 'test_points.shp' )
        self.layer = QgsVectorLayer( self.layerPath, 'puntos', 'ogr' )   
        self.layer.dataProvider().addAttributes([QgsField('f1', QVariant.Double)])
        self.layer.updateFields()
        QgsMapLayerRegistry.instance().addMapLayer( self.layer )  
        
        #Instantiate AutoFieldManager
        self.autoFieldManager = AutoFieldManager( self.msg, None, '/AutoFieldsTest', 'GeoTux', 'QGIS-Plugin-Test' )
        
            
    def readStoredSettings( self, layer, fieldName ):
        """ Helper function to get a dictionary of stored QSettings for an AutoField """
        dictTmpProperties = {}
        autoFieldId = self.autoFieldManager.buildAutoFieldId( layer, fieldName )
        self.settings.beginGroup('/AutoFieldsTest/data/' + autoFieldId)
        dictTmpProperties['layer'] = self.settings.value( "layer", "", type=str )
        dictTmpProperties['field'] = self.settings.value( "field", u"", type=unicode )
        dictTmpProperties['expression'] = self.settings.value( "expression", u"", type=unicode )
        dictTmpProperties['layer2'] = self.settings.value( "layer2", "", type=str )
        dictTmpProperties['field2'] = self.settings.value( "field2", "", type=str )            
        dictTmpProperties['enabled'] = self.settings.value( "enabled", False, type=bool )
        self.settings.endGroup()
                
        return dictTmpProperties

    def test01CreateEnabledAutoField( self ):
        """ QSettings should be properly stored, AutoField should be enabled """
        self.msg.show( "Info! Test 1 started", 'info', True )

        self.autoFieldManager.createAutoField(
            layer=self.layer, 
            fieldName=u'f1', 
            expression=u'$x'
        )

        dictTmpProperties = self.readStoredSettings( self.layer, u'f1' )      
        dictExpectedProperties = {
            'layer':self.layerPath,
            'field':u'f1',
            'expression':u'$x',
            'layer2':"",
            'field2':"",
            'enabled':True
        }
        
        self.assertEqual( dictTmpProperties, dictExpectedProperties )
        
        
    def test02AvoidTwoAutoFieldsOnSameField( self ):
        """ AutoField should not be created if another one already exists on the same field."""
        self.msg.show( "Info! Test 2 started", 'info', True )

        res = self.autoFieldManager.createAutoField(
            layer=self.layer, 
            fieldName=u'f1', 
            expression=u'$y'
        )
        
        self.assertFalse( res )
        
        
    def test03EditAutoFieldLayer( self ):
        """ AutoField value should be updated if a feature is added.
            Note: It cannot handle the case when writing directly to the provider,
              as QGIS doesn't have a SIGNAL for that.
              self.layer.dataProvider().addFeatures( [ tmpFeature ] )        
         """
        self.msg.show( "Info! Test 3 started", 'info', True )

        tmpFeature = QgsFeature( self.layer.pendingFields() )
        tmpFeature.setGeometry( QgsGeometry.fromPoint( QgsPoint(-74.4, 4.5) ) )

        # Either 1:
        self.layer.startEditing()
        self.layer.addFeature( tmpFeature )
        self.layer.commitChanges()
        
        # Or 2:
        #with edit( self.layer ):
        #    self.layer.addFeature( tmpFeature )
            
        addedFeature = self.layer.getFeatures().next()
        self.assertEquals( addedFeature['f1'], -74.4 )


    def test04ChangeAttributeValue( self ):
        """ AutoField value should be updated if another AutoField value is changed """
        self.msg.show( "Info! Test 4 started", 'info', True )

        self.autoFieldManager.createAutoField(
            layer=self.layer, 
            fieldName=u'modified', 
            expression=u'\'now: \' + to_string("f1")'
        )

        self.layer.startEditing()
        self.layer.changeAttributeValue( 0, self.layer.fieldNameIndex( u'id' ), 1 )
        self.layer.commitChanges()
            
        feature = self.layer.getFeatures().next()
        self.assertEquals( feature['modified'], 'now: -74.4' )

    
    def test05FieldRemovedThenDisableAutoField( self ):
        """ AutoField should be disabled if its base field is removed """
        self.msg.show( "Info! Test 5 started", 'info', True )

        fieldIndex = self.layer.fieldNameIndex( u'f1' )
        self.layer.startEditing()
        self.layer.deleteAttribute( fieldIndex )
        self.layer.commitChanges()
        dictTmpProperties = self.readStoredSettings( self.layer, u'f1' )    
        
        self.assertFalse( dictTmpProperties['enabled'] )        
            

    def test06MissingFieldAddedThenEnableAutoField( self ):
        """ AutoField should be enabled if missing field is added """
        self.msg.show( "Info! Test 6 started", 'info', True )    

        self.layer.startEditing()
        self.layer.addAttribute( QgsField( 'f1', QVariant.Double, len=10, prec=2 ) )
        self.layer.commitChanges()
        
        dictTmpProperties = self.readStoredSettings( self.layer, u'f1' )    
        
        self.assertTrue( dictTmpProperties['enabled'] )   

        
    def test07LayerRemovedThenDisableAutoField( self ):
        """ AutoField should be disabled if its base layer is removed """
        self.msg.show( "Info! Test 7 started", 'info', True )

        QgsMapLayerRegistry.instance().removeMapLayer( self.layer.id() )

        # removeMapLayer deletes the underlying object, so create it again
        self.layer = QgsVectorLayer( self.layerPath, 'puntos', 'ogr' )   
        dictTmpProperties = self.readStoredSettings( self.layer, u'f1' )    
        
        self.assertFalse( dictTmpProperties['enabled'] )
        
     
    def test08MissingLayerAddedThenEnableAutoField( self ):
        """ AutoField should be enabled if missing layer is added """
        self.msg.show( "Info! Test 8 started", 'info', True )

        # test07 deletes the layer object, so create it again
        self.layer = QgsVectorLayer( self.layerPath, 'puntos', 'ogr' )
        QgsMapLayerRegistry.instance().addMapLayer( self.layer )  
        dictTmpProperties = self.readStoredSettings( self.layer, u'f1' )    
        
        self.assertTrue( dictTmpProperties['enabled'] )
           
        
    def test09RemoveAutoField( self ):
        """ QSettings should be deleted for the removed AutoField """
        self.msg.show( "Info! Test 9 started", 'info', True )

        # test07 deletes the layer object, so create it again
        self.layer = QgsVectorLayer( self.layerPath, 'puntos', 'ogr' )
        autoFieldId = self.autoFieldManager.buildAutoFieldId( self.layer, u'f1')
        self.autoFieldManager.removeAutoField( autoFieldId )
        dictTmpProperties = self.readStoredSettings( self.layer, u'f1' ) 
        
        self.assertEqual( dictTmpProperties, {'layer':"",'field':"",'expression':"",'layer2':"",'field2':"",'enabled':False} )
        

    @classmethod    
    def tearDownClass( self ):   
        self.msg.show( "Info! TearDown started", 'info', True )
    
        # test07 deletes the layer object, so create it again
        self.layer = QgsVectorLayer( self.layerPath, 'puntos', 'ogr' )

        #Remove AutoField modified
        autoFieldId = self.autoFieldManager.buildAutoFieldId( self.layer, u'modified' )
        self.autoFieldManager.removeAutoField( autoFieldId )

        #Delete field f1
        fieldIndex = self.layer.fieldNameIndex('f1')
        self.layer.dataProvider().deleteAttributes( [fieldIndex] )
        self.layer.updateFields()
        
        #Delete features from test layer
        fIds = self.layer.allFeatureIds()
        self.layer.dataProvider().deleteFeatures( fIds )
        
        #Remove layer from Registry
        QgsMapLayerRegistry.instance().removeMapLayer( self.layer.id() )
        self.msg.show( "Info! TearDown finished", 'info', True )

        QgsApplication.exitQgis()
 def addPolygonsToMap(self, polygons):
     if not QgsMapLayerRegistry.instance().mapLayersByName('Location Lab - catchments'):
         vl = QgsVectorLayer('Polygon?crs=EPSG:4326', 'Location Lab - catchments', 'memory')
         pr = vl.dataProvider()
         vl.startEditing()
         pr.addAttributes(
             [
                 QgsField('id', QVariant.Int),
                 QgsField('provider', QVariant.String),
                 QgsField('mode', QVariant.String),
                 QgsField('value', QVariant.Int),
                 QgsField('units', QVariant.String),
                 QgsField('lat', QVariant.Double),
                 QgsField('lon', QVariant.Double),
                 QgsField('params', QVariant.String)
             ]
         )
         vl.commitChanges()
         QgsMapLayerRegistry.instance().addMapLayer(vl)
     vl = QgsMapLayerRegistry.instance().mapLayersByName('Location Lab - catchments')[0]
     pr = vl.dataProvider()
     next_id = len(vl.allFeatureIds()) + 1
     for p in polygons:
         feature = QgsFeature()
         points = []
         if p['source'] == 'Skobbler':
             coordinates_x = [c for c in p['coordinates'][8::2]]
             coordinates_y = [c for c in p['coordinates'][9::2]]
             for x, y in zip(coordinates_x, coordinates_y):
                 points.append(QgsPoint(x, y))
         elif p['source'] == 'HERE':
             coordinates = [c.split(',') for c in p['coordinates']]
             for xy in coordinates:
                 points.append(QgsPoint(float(xy[1]), float(xy[0])))
         feature = QgsFeature()
         feature.setGeometry(QgsGeometry.fromPolygon([points]))
         lat, lon = p['start'].split(',')
         for key in ['key', 'url', 'coordinates', 'start']: #unnecessary params
             p.pop(key)
         feature.setAttributes([
             next_id,
             self.providersComboBox.currentText(),
             self.modesComboBox.currentText().lower(),
             self.valueSpinBox.value(),
             self.unitsComboBox.currentText(),
             float(lat),
             float(lon),
             str(p)
         ])
         pr.addFeatures([feature])
         next_id += 1
     vl.updateExtents()
     self.iface.mapCanvas().setExtent(
         QgsCoordinateTransform(
             vl.crs(),
             self.iface.
             mapCanvas().
             mapRenderer().
             destinationCrs()).
         transform(vl.extent()))
     self.iface.mapCanvas().refresh()