def _buildSymbolWidget(self, spColumnName):
        """
        Build symbol widget based on geometry type.
        """
        geomType, srid = geometryType(self._dsName, spColumnName)
        if geomType == "":
            return None

        vlGeomConfig = "{0}?crs=epsg:{1!s}".format(geomType, srid)

        vl = QgsVectorLayer(vlGeomConfig, "stdm_proxy", "memory")

        if geomType == "POINT":
            symbolEditor = QgsSimpleMarkerSymbolLayerV2Widget(vl)

        elif geomType == "LINESTRING":
            symbolEditor = QgsSimpleLineSymbolLayerV2Widget.create(vl)

        elif geomType == "POLYGON":
            symbolEditor = SimpleFillSymbolLayerProxyWidget(vl)

        else:
            return None

        return (symbolEditor, geomType, srid)
 def _buildSymbolWidget(self,spColumnName):
     """
     Build symbol widget based on geometry type.
     """
     geomType,srid = geometryType(self._dsName,spColumnName)
     if geomType == "":
         return None
     
     vlGeomConfig = "{0}?crs=epsg:{1!s}".format(geomType,srid)
    
     vl = QgsVectorLayer(vlGeomConfig, "stdm_proxy", "memory")
     
     if geomType == "POINT":
         symbolEditor = QgsSimpleMarkerSymbolLayerV2Widget(vl)
         
     elif geomType == "LINESTRING":
         symbolEditor = QgsSimpleLineSymbolLayerV2Widget.create(vl)
         
     elif geomType == "POLYGON":
         symbolEditor = SimpleFillSymbolLayerProxyWidget(vl)
         
     else:
         return None
     
     return (symbolEditor,geomType,srid)
Example #3
0
    def _build_symbol_widget(self, sp_column_name):
        """
        Build symbol widget based on geometry type.
        """
        geom_type,srid = geometryType(self._ds_name, sp_column_name)

        if not geom_type:
            return None
        
        vlGeomConfig = "{0}?crs=epsg:{1!s}".format(geom_type, srid)
       
        vl = QgsVectorLayer(vlGeomConfig, "stdm_proxy", "memory")

        if geom_type == "POINT" or geom_type == "MULTIPOINT":
            symbol_editor = _SimpleMarkerSymbolLayerProxyWidget(vl)
            
        elif geom_type == "LINESTRING" or geom_type == "MULTILINESTRING":
            symbol_editor = _SimpleLineSymbolLayerProxyWidget(vl)
            
        elif geom_type == "POLYGON" or geom_type == "MULTIPOLYGON":
            symbol_editor = _SimpleFillSymbolLayerProxyWidget(vl)
            
        else:
            return None, "", -1
        
        return (symbol_editor,geom_type,srid)
Example #4
0
    def featToDb(self, targettable , columnmatch, append, parentdialog,
                 geomColumn=None, geomCode=-1, translator_manager=ValueTranslatorManager()):
        """
        Performs the data import from the source layer to the STDM database.
        :param targettable: Destination table name
        :param columnmatch: Dictionary containing source columns as keys and target columns as the values.
        :param append: True to append, false to overwrite by deleting previous records
        :param parentdialog: A reference to the calling dialog.
        :param translator_manager: Instance of 'stdm.data.importexport.ValueTranslatorManager'
        containing value translators defined for the destination table columns.
        :type translator_manager: ValueTranslatorManager
        """
        #Delete existing rows in the target table if user has chosen to overwrite
        if not append:
            delete_table_data(targettable)

        """
        #Debug logging
        logging.basicConfig(level=logging.DEBUG,
                            format='%(asctime)s %(levelname)s %(message)s',
                            filename='stdm.log',
                            filemode='w')        
        """
        #Container for mapping column names to their corresponding values
        column_value_mapping = {}
        
        lyr = self.getLayer()
        lyr.ResetReading()
        feat_defn = lyr.GetLayerDefn()
        numFeat = lyr.GetFeatureCount() 
          
        #Configure progress dialog
        init_val = 0
        progress = QProgressDialog("", "&Cancel", init_val, numFeat,
                                   parentdialog)
        progress.setWindowModality(Qt.WindowModal)    
        lblMsgTemp = "Importing {0} of {1} to STDM..."  
           
        for feat in lyr:
            column_count = 0
            progress.setValue(init_val)
            progressMsg = lblMsgTemp.format((init_val + 1), numFeat)
            progress.setLabelText(progressMsg)
            
            if progress.wasCanceled():
                break
            
            for f in range(feat_defn.GetFieldCount()):
                field_defn = feat_defn.GetFieldDefn(f) 
                field_name = field_defn.GetNameRef()  
                
                #Append value only if it has been defined by the user                         
                if field_name in columnmatch:
                    dest_column = columnmatch[field_name]

                    field_value = feat.GetField(f)

                    '''
                    Check if there is a value translator defined for the specified destination column.
                    '''
                    value_translator = translator_manager.translator(dest_column)

                    if not value_translator is None:
                        source_col_names = value_translator.source_column_names()

                        field_value_mappings = self._map_column_values(feat, feat_defn,
                                                                       source_col_names)
                        field_value = value_translator.referencing_column_value(field_value_mappings)

                    if not isinstance(field_value, IgnoreType):
                            column_value_mapping[dest_column] = field_value

                    column_count += 1

                    #Create mapped table only once
                    if self._mapped_class is None:
                        #Execute only once, when all fields have been iterated
                        if column_count == len(columnmatch):
                            #Add geometry column to the mapping 
                            if geomColumn is not None:                                                                                                                    
                                column_value_mapping[geomColumn] = None
                                
                                #Use geometry column SRID in the target table
                                self._geomType,self._targetGeomColSRID = geometryType(targettable,
                                                                                      geomColumn)

                            mapped_class = self._get_mapped_class(targettable)

                            if mapped_class is None:
                                msg = QApplication.translate("OGRReader",
                                                             "Something happened that caused the database table " \
                                      "not to be mapped to the corresponding model class. Please try again.")

                                raise RuntimeError(msg)
                                
                            self._mapped_class = mapped_class
                                                       
            #Only insert geometry if it has been defined by the user
            if geomColumn is not None:
                geom = feat.GetGeometryRef()
                
                if geom is not None:
                    #Get geometry in WKT/WKB format
                    geomWkb = geom.ExportToWkt()
                    column_value_mapping[geomColumn] = "SRID={0!s};{1}".format(self._targetGeomColSRID,geomWkb)
                    
                    #Check if the geometry types match
                    layerGeomType = geom.GetGeometryName()
                    
                    if layerGeomType.lower() != self._geomType.lower():
                        raise TypeError("The geometries of the source and destination columns do not match.\n" \
                                        "Source Geometry Type: {0}, Destination Geometry Type: {1}".format(layerGeomType,
                                                                                                           self._geomType))
                        return
    
            #logging.debug()
            
            try:               
                #Insert the record
                self._insertRow(column_value_mapping)

            except:
                progress.close()
                raise
            
            init_val+=1
            
        progress.setValue(numFeat)
Example #5
0
 def featToDb(self,targettable,columnmatch,append,parentdialog,geomColumn=None,geomCode=-1):
     '''
     Performs the data import from the source layer to the STDM database.
     :param targettable: Destination table name
     :param columnmatch: Dictionary containing source columns as keys and target columns as the values
     :param append: True to append, false to overwrite by deleting previous records
     :param parentdialog: A reference to the calling dialog
     ''' 
     #Delete existing rows if user has chosen to overwrite
     if not append:
         delete_table_data(targettable)
         
     """
     #Debug logging
     logging.basicConfig(level=logging.DEBUG,
                         format='%(asctime)s %(levelname)s %(message)s',
                         filename='stdm.log',
                         filemode='w')        
     """
           
     #Container for mapping column names to their corresponding values
     columnValueMapping = {}
     
     lyr = self.getLayer()
     lyr.ResetReading()
     feat_defn = lyr.GetLayerDefn()
     numFeat = lyr.GetFeatureCount() 
       
     #Configure progress dialog
     initVal = 0 
     progress = QProgressDialog("","&Cancel",initVal,numFeat,parentdialog)
     progress.setWindowModality(Qt.WindowModal)    
     lblMsgTemp = "Importing {0} of {1} to STDM..."  
        
     for feat in lyr: 
         progress.setValue(initVal) 
         progressMsg = lblMsgTemp.format(str(initVal+1),str(numFeat))
         progress.setLabelText(progressMsg)
         
         if progress.wasCanceled():
             break
         
         for f in range(feat_defn.GetFieldCount()):
             field_defn = feat_defn.GetFieldDefn(f) 
             field_name = field_defn.GetNameRef()  
             
             #Append value only if it has been defined by the user                         
             if field_name in columnmatch:
                 fieldValue = feat.GetField(f)  
                 columnValueMapping[columnmatch[field_name]] = fieldValue
                 
                 #Create mapped table only once
                 if self._mappedClass == None:
                     
                     #Execute only once, when all fields have been iterated
                     if len(columnValueMapping.keys()) == len(columnmatch):                             
                         #Add geometry column to the mapping 
                         if geomColumn is not None:                                                                                                                    
                             columnValueMapping[geomColumn] = None 
                             
                             #Use geometry column SRID in the target table
                             self._geomType,self._targetGeomColSRID = geometryType(targettable,geomColumn)
                         
                         try:
                             primaryMapper = class_mapper(_ReflectedModel) 
                             
                         except (sqlalchemy.orm.exc.UnmappedClassError,sqlalchemy.exc.ArgumentError):     
                             #Reflect table and map it to '_ReflectedModel' class only once                                                                        
                             mapper(_ReflectedModel,self._mapTable(targettable))
                             
                         self._mappedClass = _ReflectedModel
                                                    
         #Only insert geometry if it has been defined by the user
         if geomColumn is not None:
             geom = feat.GetGeometryRef()
             
             if geom is not None:
                 #Get geometry in WKT/WKB format
                 geomWkb = geom.ExportToWkt()
                 columnValueMapping[geomColumn] = "SRID={0!s};{1}".format(self._targetGeomColSRID,geomWkb)
                 
                 #Check if the geometry types match
                 layerGeomType = geom.GetGeometryName()
                 
                 if layerGeomType.lower() != self._geomType.lower():
                     raise TypeError("The geometries of the source and destination columns do not match.\n" \
                                     "Source Geometry Type: {0}, Destination Geometry Type: {1}".format(layerGeomType,
                                                                                                        self._geomType))
                     return
 
         #logging.debug()
         
         try:               
             #Insert the record
             self._insertRow(columnValueMapping)
         except:
             progress.close()
             raise
         
         initVal+=1
         
     progress.setValue(numFeat)
Example #6
0
    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())
Example #7
0
    def db2Feat(self,parent,table,results,columns,geom=""):
        #Execute the export process
        #Create driver
        drv = ogr.GetDriverByName(self.getDriverName())        
        if drv is None:
            raise Exception("{0} driver not available.".format(self.getDriverName()))
        
        #Create data source
        self._ds = drv.CreateDataSource(self._targetFile)
        if self._ds is None:
            raise Exception("Creation of output file failed.")
        
        #Create layer
        if geom != "":
            pgGeomType,srid = geometryType(table,geom)
            geomType = wkbTypes[pgGeomType]
            
        else:
            geomType=ogr.wkbNone
            
        lyr = self._ds.CreateLayer(self.getLayerName(),None,geomType)
        
        if lyr is None:
            raise Exception("Layer creation failed")
        
        #Create fields
        for c in columns:
            #SQLAlchemy string values are in unicode so decoding is required in order to use in OGR
            encodedFieldName = c.encode('utf-8')
            field_defn = self.createField(table,encodedFieldName)
            if lyr.CreateField(field_defn) != 0:
                raise Exception("Creating %s field failed"%(c))
            
        #Add Geometry column to list for referencing in the result set
        if geom != "":
            columns.append(geom) 
            
        featGeom=None  
             
        #Configure progress dialog
        initVal=0 
        numFeat = results.rowcount
        progress = QProgressDialog("","&Cancel",initVal,numFeat,parent)        
        progress.setWindowModality(Qt.WindowModal)    
        lblMsgTemp = "Writing {0} of {1} to file..." 
         
        #Iterate the result set        
        for r in results:
            #Progress dialog 
            progress.setValue(initVal) 
            progressMsg = lblMsgTemp.format(str(initVal+1),str(numFeat))
            progress.setLabelText(progressMsg)
            
            if progress.wasCanceled():
                break  
            
            #Create OGR Feature
            feat = ogr.Feature(lyr.GetLayerDefn())    
                    
            for i in range(len(columns)):
                colName = columns[i]   
                             
                #Check if its the geometry column in the iteration
                if colName==geom: 
                    if r[i] is not None:                                                                               
                        featGeom=ogr.CreateGeometryFromWkt(r[i])
                    else:
                        featGeom=ogr.CreateGeometryFromWkt("")
                        
                    feat.SetGeometry(featGeom)
                    
                else:
                    fieldValue = r[i]  
                    if isinstance(fieldValue,unicode):
                        fieldValue = fieldValue.encode('utf-8')
                        
                    feat.SetField(i,fieldValue)
                          
            if lyr.CreateFeature(feat) != 0:
                progress.close()
                raise Exception("Failed to create feature in %s"%(self._targetFile))
            
            if featGeom is not None:                
                featGeom.Destroy()
                
            feat.Destroy()
            initVal+=1
            
        progress.setValue(numFeat)
                
  
        
            

        
        
Example #8
0
    def run(self, *args, **kwargs):
        """
        :param templatePath: The file path to the user-defined template.
        :param entityFieldName: The name of the column for the specified entity which
        must exist in the data source view or table.
        :param entityFieldValue: The value for filtering the records in the data source
        view or table.
        :param outputMode: Whether the output composition should be an image or PDF.
        :param filePath: The output file where the composition will be written to. Applies
        to single mode output generation.
        :param dataFields: List containing the field names whose values will be used to name the files.
        This is used in multiple mode configuration.
        :param fileExtension: The output file format. Used in multiple mode configuration.
        :param data_source: Name of the data source table or view whose
        row values will be used to name output files if the options has been
        specified by the user.
        """
        templatePath = args[0]
        entityFieldName = args[1]
        entityFieldValue = args[2]
        outputMode = args[3]
        filePath = kwargs.get("filePath", None)
        dataFields = kwargs.get("dataFields", [])
        fileExtension = kwargs.get("fileExtension", "")
        data_source = kwargs.get("data_source", "")
        
        templateFile = QFile(templatePath)
        
        if not templateFile.open(QIODevice.ReadOnly):
            return False, QApplication.translate("DocumentGenerator",
                                            "Cannot read template file.")

        templateDoc = QDomDocument()
        
        if templateDoc.setContent(templateFile):
            composerDS = ComposerDataSource.create(templateDoc)
            spatialFieldsConfig = SpatialFieldsConfiguration.create(templateDoc)
            composerDS.setSpatialFieldsConfig(spatialFieldsConfig)

            #Check if data source exists and return if it doesn't
            if not self.data_source_exists(composerDS):
                msg = QApplication.translate("DocumentGenerator",
                                             u"'{0}' data source does not exist in the database."
                                             u"\nPlease contact your database "
                                             u"administrator.".format(composerDS.name()))
                return False, msg

            #TODO: Need to automatically register custom configuration collections
            #Photo config collection
            ph_config_collection = PhotoConfigurationCollection.create(templateDoc)

            #Table configuration collection
            table_config_collection = TableConfigurationCollection.create(templateDoc)

            #Create chart configuration collection object
            chart_config_collection = ChartConfigurationCollection.create(templateDoc)

            #Load the layers required by the table composer items
            self._table_mem_layers = load_table_layers(table_config_collection)
            
            #Execute query
            dsTable,records = self._exec_query(composerDS.name(), entityFieldName, entityFieldValue)

            if records is None or len(records) == 0:
                return False, QApplication.translate("DocumentGenerator",
                                                    "No matching records in the database")
            
            """
            Iterate through records where a single file output will be generated for each matching record.
            """
            for rec in records:
                composition = QgsComposition(self._map_renderer)
                composition.loadFromTemplate(templateDoc)
                
                #Set value of composer items based on the corresponding db values
                for composerId in composerDS.dataFieldMappings().reverse:
                    #Use composer item id since the uuid is stripped off
                    composerItem = composition.getComposerItemById(composerId)
                    
                    if not composerItem is None:
                        fieldName = composerDS.dataFieldName(composerId)
                        fieldValue = getattr(rec,fieldName)
                        self._composeritem_value_handler(composerItem, fieldValue)

                #Extract photo information
                self._extract_photo_info(composition, ph_config_collection, rec)

                #Set table item values based on configuration information
                self._set_table_data(composition, table_config_collection, rec)

                #Refresh non-custom map composer items
                self._refresh_composer_maps(composition,
                                            spatialFieldsConfig.spatialFieldsMapping().keys())
                            
                #Create memory layers for spatial features and add them to the map
                for mapId,spfmList in spatialFieldsConfig.spatialFieldsMapping().iteritems():
                    map_item = composition.getComposerItemById(mapId)
                    
                    if not map_item is None:
                        #Clear any previous map memory layer
                        self.clear_temporary_map_layers()
                        
                        for spfm in spfmList:
                            #Use the value of the label field to name the layer
                            lbl_field = spfm.labelField()
                            spatial_field = spfm.spatialField()

                            if not spatial_field:
                                continue

                            if lbl_field:
                                if hasattr(rec, spfm.labelField()):
                                    layerName = getattr(rec, spfm.labelField())

                                else:
                                    layerName = self._random_feature_layer_name(spatial_field)
                            else:
                                layerName = self._random_feature_layer_name(spatial_field)
                            
                            #Extract the geometry using geoalchemy spatial capabilities
                            geom_value = getattr(rec, spatial_field)
                            if geom_value is None:
                                continue

                            geom_func = geom_value.ST_AsText()
                            geomWKT = self._dbSession.scalar(geom_func)

                            #Get geometry type
                            geom_type, srid = geometryType(composerDS.name(),
                                                          spatial_field)
                            
                            #Create reference layer with feature
                            ref_layer = self._build_vector_layer(layerName, geom_type, srid)

                            if ref_layer is None or not ref_layer.isValid():
                                continue
                            
                            #Add feature
                            bbox = self._add_feature_to_layer(ref_layer, geomWKT)
                            bbox.scale(spfm.zoomLevel())

                            #Workaround for zooming to single point extent
                            if ref_layer.wkbType() == QGis.WKBPoint:
                                canvas_extent = self._iface.mapCanvas().fullExtent()
                                cnt_pnt = bbox.center()
                                canvas_extent.scale(1.0/32, cnt_pnt)
                                bbox = canvas_extent

                            #Style layer based on the spatial field mapping symbol layer
                            symbol_layer = spfm.symbolLayer()
                            if not symbol_layer is None:
                                ref_layer.rendererV2().symbols()[0].changeSymbolLayer(0,spfm.symbolLayer())

                            '''
                            Add layer to map and ensure its always added at the top
                            '''
                            QgsMapLayerRegistry.instance().addMapLayer(ref_layer, False)
                            QgsProject.instance().layerTreeRoot().insertLayer(0, ref_layer)
                            self._iface.mapCanvas().setExtent(bbox)
                            self._iface.mapCanvas().refresh()

                            #Add layer to map memory layer list
                            self._map_memory_layers.append(ref_layer)

                        '''
                        Use root layer tree to get the correct ordering of layers
                        in the legend
                        '''
                        self._refresh_map_item(map_item)

                #Extract chart information and generate chart
                self._generate_charts(composition, chart_config_collection, rec)

                #Build output path and generate composition
                if not filePath is None and len(dataFields) == 0:
                    self._write_output(composition, outputMode, filePath)
                    
                elif filePath is None and len(dataFields) > 0:
                    docFileName = self._build_file_name(data_source, entityFieldName,
                                                      entityFieldValue, dataFields, fileExtension)

                    if not docFileName:
                        return (False, QApplication.translate("DocumentGenerator",
                                    "File name could not be generated from the data fields."))
                        
                    outputDir = self._composer_output_path()
                    if outputDir is None:
                        return (False, QApplication.translate("DocumentGenerator",
                            "System could not read the location of the output directory in the registry."))
                    
                    qDir = QDir()
                    if not qDir.exists(outputDir):
                        return (False, QApplication.translate("DocumentGenerator",
                                "Output directory does not exist"))
                    
                    absDocPath = u"{0}/{1}".format(outputDir, docFileName)
                    self._write_output(composition, outputMode, absDocPath)
            
            #Clear temporary layers
            self.clear_temporary_layers()
            
            return True, "Success"
        
        return False, "Document composition could not be generated"