Beispiel #1
0
    def _geom_icon(self, table, column):
        # Get column type and apply the appropriate icon
        geometry_typ = unicode(geometryType(table, column)[0])

        icon = None

        if geometry_typ == 'POLYGON':
            icon = QIcon(
                ':/plugins/stdm/images/icons/layer_polygon.png'
            )

        elif geometry_typ == 'LINESTRING':
            icon = QIcon(
                ':/plugins/stdm/images/icons/layer_line.png'
            )

        elif geometry_typ == 'POINT':
            icon = QIcon(
                ':/plugins/stdm/images/icons/layer_point.png'
            )

        else:
            icon = QIcon(
                ':/plugins/stdm/images/icons/table.png'
            )

        return icon
Beispiel #2
0
    def _geom_icon(self, table, column):
        # Get column type and apply the appropriate icon
        geometry_typ = unicode(geometryType(table, column)[0])

        icon = None

        if geometry_typ == 'POLYGON':
            icon = QIcon(
                ':/plugins/stdm/images/icons/layer_polygon.png'
            )

        elif geometry_typ == 'LINESTRING':
            icon = QIcon(
                ':/plugins/stdm/images/icons/layer_line.png'
            )

        elif geometry_typ == 'POINT':
            icon = QIcon(
                ':/plugins/stdm/images/icons/layer_point.png'
            )
        elif geometry_typ == 'MULTIPOLYGON':
            icon = QIcon(
                ':/plugins/stdm/images/icons/layer_polygon.png'
            )
        elif geometry_typ == 'MULTILINESTRING':
            icon = QIcon(
                ':/plugins/stdm/images/icons/layer_line.png'
            )
        else:
            icon = QIcon(
                ':/plugins/stdm/images/icons/table.png'
            )

        return icon
Beispiel #3
0
    def _build_symbol_widget(self, sp_field_mapping):
        """
        Build symbol widget based on geometry type.
        """
        if isinstance(sp_field_mapping, (str, unicode)):
            sp_column_name = sp_field_mapping
            sym_layer = None
        else:
            sp_column_name = sp_field_mapping.spatialField()
            sym_layer = sp_field_mapping.symbolLayer()

        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,
                symbol_layer=sym_layer
            )
            
        elif geom_type == "LINESTRING" or geom_type == "MULTILINESTRING":
            symbol_editor = _SimpleLineSymbolLayerProxyWidget(
                vl,
                symbol_layer=sym_layer
            )
            
        elif geom_type == "POLYGON" or geom_type == "MULTIPOLYGON":
            symbol_editor = _SimpleFillSymbolLayerProxyWidget(
                vl,
                symbol_layer=sym_layer
            )
            
        else:
            return None, '', -1
        
        return symbol_editor, geom_type, srid
Beispiel #4
0
    def _build_symbol_widget(self, sp_field_mapping):
        """
        Build symbol widget based on geometry type.
        """
        if isinstance(sp_field_mapping, str):
            sp_column_name = sp_field_mapping
            sym_layer = None
        else:
            sp_column_name = sp_field_mapping.spatialField()
            sym_layer = sp_field_mapping.symbolLayer()

        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,
                symbol_layer=sym_layer
            )

        elif geom_type == "LINESTRING" or geom_type == "MULTILINESTRING":
            symbol_editor = _SimpleLineSymbolLayerProxyWidget(
                vl,
                symbol_layer=sym_layer
            )

        elif geom_type == "POLYGON" or geom_type == "MULTIPOLYGON":
            symbol_editor = _SimpleFillSymbolLayerProxyWidget(
                vl,
                symbol_layer=sym_layer
            )

        else:
            return None, '', -1

        return symbol_editor, geom_type, srid
Beispiel #5
0
    def _geom_icon(self, table, column):
        # Get column type and apply the appropriate icon
        geometry_typ = str(geometryType(table, column)[0])

        icon = None

        if geometry_typ == 'POLYGON':
            icon = GuiUtils.get_icon('layer_polygon.png')

        elif geometry_typ == 'LINESTRING':
            icon = GuiUtils.get_icon('layer_line.png')

        elif geometry_typ == 'POINT':
            icon = GuiUtils.get_icon('layer_point.png')
        elif geometry_typ == 'MULTIPOLYGON':
            icon = GuiUtils.get_icon('layer_polygon.png')
        elif geometry_typ == 'MULTILINESTRING':
            icon = GuiUtils.get_icon('layer_line.png')
        else:
            icon = GuiUtils.get_icon('table.png')

        return icon
Beispiel #6
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

            #Set file name value formatter
            self._file_name_value_formatter = EntityValueFormatter(
                name=data_source)

            #Register field names to be used for file naming
            self._file_name_value_formatter.register_columns(dataFields)

            #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)
                ref_layer = None
                #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
                            '''
                            self.map_registry.addMapLayer(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.id())
                            self._hide_layer(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)

                    # Replace unsupported characters in Windows file naming
                    docFileName = docFileName.replace('/', '_').replace \
                        ('\\', '_').replace(':', '_').strip('*?"<>|')

                    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)

            return True, "Success"

        return False, "Document composition could not be generated"
Beispiel #7
0
    def featToDb(self,
                 targettable,
                 columnmatch,
                 append,
                 parentdialog,
                 geomColumn=None,
                 geomCode=-1,
                 translator_manager=None):
        """
        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
        """
        # Check current profile
        if self._current_profile is None:
            msg = QApplication.translate(
                'OGRReader',
                'The current profile could not be determined.\nPlease set it '
                'in the Options dialog or Configuration Wizard.')
            raise ConfigurationException(msg)

        if translator_manager is None:
            translator_manager = ValueTranslatorManager()

        # Delete existing rows in the target table if user has chosen to overwrite
        if not append:
            delete_table_data(targettable)

        # Container for mapping column names to their corresponding values

        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..."

        # Set entity for use in translators
        destination_entity = self._data_source_entity(targettable)

        for feat in lyr:
            column_value_mapping = {}
            column_count = 0
            progress.setValue(init_val)
            progressMsg = lblMsgTemp.format((init_val + 1), numFeat)
            progress.setLabelText(progressMsg)

            if progress.wasCanceled():
                break

            # Reset source document manager for new records
            if destination_entity.supports_documents:
                if not self._source_doc_manager is None:
                    self._source_doc_manager.reset()

            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)

                    # Create mapped class only once
                    if self._mapped_cls is None:
                        mapped_cls, mapped_doc_cls = self._get_mapped_class(
                            targettable)

                        if mapped_cls is None:
                            msg = QApplication.translate(
                                "OGRReader",
                                "Something happened that caused the "
                                "database table not to be mapped to the "
                                "corresponding model class. Please contact"
                                " your system administrator.")

                            raise RuntimeError(msg)

                        self._mapped_cls = mapped_cls
                        self._mapped_doc_cls = mapped_doc_cls

                        # Create source document manager if the entity supports them
                        if destination_entity.supports_documents:
                            self._source_doc_manager = SourceDocumentManager(
                                destination_entity.supporting_doc,
                                self._mapped_doc_cls)

                        if geomColumn is not None:
                            # Use geometry column SRID in the target table
                            self._geomType, self._targetGeomColSRID = \
                                geometryType(targettable, geomColumn)
                    '''
                    Check if there is a value translator defined for the
                    specified destination column.
                    '''
                    value_translator = translator_manager.translator(
                        dest_column)

                    if value_translator is not None:
                        # Set destination table entity
                        value_translator.entity = destination_entity

                        source_col_names = value_translator.source_column_names(
                        )
                        field_value_mappings = self._map_column_values(
                            feat, feat_defn, source_col_names)
                        # Set source document manager if required
                        if value_translator.requires_source_document_manager:
                            value_translator.source_document_manager = self._source_doc_manager

                        field_value = value_translator.referencing_column_value(
                            field_value_mappings)

                    if not isinstance(field_value, IgnoreType):
                        # Check column type and rename if multiple select for
                        # SQLAlchemy compatibility
                        col_obj = destination_entity.column(dest_column)
                        if col_obj.TYPE_INFO == 'MULTIPLE_SELECT':
                            lk_name = col_obj.value_list.name
                            dest_column = '{0}_collection'.format(lk_name)

                        column_value_mapping[dest_column] = field_value

                    # Set supporting documents
                    if destination_entity.supports_documents:
                        column_value_mapping['documents'] = \
                            self._source_doc_manager.model_objects()

                    column_count += 1

            # Only insert geometry if it has been defined by the user
            if geomColumn is not None:
                geom = feat.GetGeometryRef()
                if geom is not None:
                    # Check if the geometry types match
                    layerGeomType = geom.GetGeometryName()

                    # Convert polygon to multipolygon if the destination table is multi-polygon.
                    geom_wkb, geom_type = self.auto_fix_geom_type(
                        geom, layerGeomType, self._geomType)
                    column_value_mapping[geomColumn] = "SRID={0!s};{1}".format(
                        self._targetGeomColSRID, geom_wkb)

                    if geom_type.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(
                                geom_type,
                                self._geomType))

            try:
                # Insert the record
                self._insertRow(targettable, column_value_mapping)

            except:
                progress.close()
                raise

            init_val += 1

        progress.setValue(numFeat)
Beispiel #8
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(u"{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.")
        dest_crs = None
        #Create layer
        if geom != "":
            pgGeomType, srid = geometryType(table, geom)
            geomType = wkbTypes[pgGeomType]
            dest_crs = ogr.osr.SpatialReference()
            dest_crs.ImportFromEPSG(srid)

        else:
            geomType = ogr.wkbNone
        layer_name = self.getLayerName()

        lyr = self._ds.CreateLayer(layer_name, dest_crs, geomType)

        if lyr is None:
            raise Exception("Layer creation failed")

        #Create fields
        for c in columns:

            field_defn = self.createField(table, c)

            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 = QApplication.translate('OGRWriter',
                                            'Writing {0} of {1} to file...')

        entity = current_profile().entity_by_name(table)
        #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:

                    if isinstance(r[i], decimal.Decimal):

                        value = int(r[i])
                        feat.setField(i, value)

                    elif self.is_date(r[i]):
                        date = datetime.datetime.strptime(r[i],
                                                          "%Y-%m-%d").date()
                        feat.setField(i, date)
                    else:
                        feat.SetField(i, r[i])

            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)
Beispiel #9
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.")
        dest_crs = None
        #Create layer
        if geom != "":
            pgGeomType, srid = geometryType(table, geom)
            geomType = wkbTypes[pgGeomType]
            dest_crs = ogr.osr.SpatialReference()
            dest_crs.ImportFromEPSG(srid)

        else:
            geomType = ogr.wkbNone

        lyr = self._ds.CreateLayer(self.getLayerName(), dest_crs, 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]

                    fieldValue = str(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)
Beispiel #10
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

            #Set file name value formatter
            self._file_name_value_formatter = EntityValueFormatter(
                name=data_source
            )

            #Register field names to be used for file naming
            self._file_name_value_formatter.register_columns(dataFields)

            #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)

            # Create QR code configuration collection object
            qrc_config_collection = QRCodeConfigurationCollection.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_settings)
                composition.loadFromTemplate(templateDoc)
                ref_layer = None
                #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())

                # Set use fixed scale to false i.e. relative zoom
                use_fixed_scale = False

                # 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)

                            zoom_type = spfm.zoom_type
                            # Only scale the extents if zoom type is relative
                            if zoom_type == 'RELATIVE':
                                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
                            '''
                            self.map_registry.addMapLayer(ref_layer)
                            self._iface.mapCanvas().setExtent(bbox)

                            # Set scale if type is FIXED
                            if zoom_type == 'FIXED':
                                self._iface.mapCanvas().zoomScale(spfm.zoomLevel())
                                use_fixed_scale = True

                            self._iface.mapCanvas().refresh()
                            # Add layer to map memory layer list
                            self._map_memory_layers.append(ref_layer.id())
                            self._hide_layer(ref_layer)
                        '''
                        Use root layer tree to get the correct ordering of layers
                        in the legend
                        '''
                        self._refresh_map_item(map_item, use_fixed_scale)

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

                # Extract QR code information in order to generate QR codes
                self._generate_qr_codes(composition, qrc_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)

                    # Replace unsupported characters in Windows file naming
                    docFileName = docFileName.replace('/', '_').replace \
                        ('\\', '_').replace(':', '_').strip('*?"<>|')


                    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)

            return True, "Success"

        return False, "Document composition could not be generated"
Beispiel #11
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(u"{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.")
        dest_crs = None
        #Create layer
        if geom != "":
            pgGeomType,srid = geometryType(table,geom)
            geomType = wkbTypes[pgGeomType]
            try:
                dest_crs = ogr.osr.SpatialReference()
            except AttributeError:
                dest_crs = osr.SpatialReference()
            dest_crs.ImportFromEPSG(srid)

        else:
            geomType=ogr.wkbNone
        layer_name = self.getLayerName()

        lyr = self._ds.CreateLayer(layer_name, dest_crs, geomType)
        
        if lyr is None:
            raise Exception("Layer creation failed")

        #Create fields
        for c in columns:

            field_defn = self.createField(table, c)

            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 = QApplication.translate(
            'OGRWriter', 'Writing {0} of {1} to file...')

        entity = current_profile().entity_by_name(table)
        #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:
                    field_value = r[i]
                    field_value = unicode(field_value).encode('utf-8')
                    feat.SetField(i,field_value)
                    
            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)