Пример #1
0
    def testResizeWithMapContent(self):
        """Test test legend resizes to match map content"""

        point_path = os.path.join(TEST_DATA_DIR, 'points.shp')
        point_layer = QgsVectorLayer(point_path, 'points', 'ogr')
        QgsProject.instance().addMapLayers([point_layer])

        s = QgsMapSettings()
        s.setLayers([point_layer])
        s.setCrsTransformEnabled(False)
        composition = QgsComposition(QgsProject.instance())
        composition.setPaperSize(297, 210)

        composer_map = QgsComposerMap(composition, 20, 20, 80, 80)
        composer_map.setFrameEnabled(True)
        composer_map.setLayers([point_layer])
        composition.addComposerMap(composer_map)
        composer_map.setNewExtent(point_layer.extent())

        legend = QgsComposerLegend(composition)
        legend.setSceneRect(QRectF(120, 20, 80, 80))
        legend.setFrameEnabled(True)
        legend.setFrameOutlineWidth(2)
        legend.setBackgroundColor(QColor(200, 200, 200))
        legend.setTitle('')
        legend.setLegendFilterByMapEnabled(True)
        composition.addComposerLegend(legend)
        legend.setComposerMap(composer_map)

        composer_map.setNewExtent(QgsRectangle(-102.51, 41.16, -102.36, 41.30))

        checker = QgsCompositionChecker('composer_legend_size_content',
                                        composition)
        checker.setControlPathPrefix("composer_legend")
        result, message = checker.testComposition()
        self.assertTrue(result, message)

        QgsProject.instance().removeMapLayers([point_layer.id()])
Пример #2
0
    def testInitialSizeSymbolMapUnits(self):
        """Test initial size of legend with a symbol size in map units"""

        point_path = os.path.join(TEST_DATA_DIR, 'points.shp')
        point_layer = QgsVectorLayer(point_path, 'points', 'ogr')
        QgsProject.instance().addMapLayers([point_layer])

        marker_symbol = QgsMarkerSymbol.createSimple({'color': '#ff0000', 'outline_style': 'no', 'size': '5', 'size_unit': 'MapUnit'})

        point_layer.setRenderer(QgsSingleSymbolRenderer(marker_symbol))

        s = QgsMapSettings()
        s.setLayers([point_layer])
        composition = QgsComposition(QgsProject.instance())
        composition.setPaperSize(297, 210)

        composer_map = QgsComposerMap(composition, 20, 20, 80, 80)
        composer_map.setFrameEnabled(True)
        composer_map.setLayers([point_layer])
        composition.addComposerMap(composer_map)
        composer_map.setNewExtent(point_layer.extent())

        legend = QgsComposerLegend(composition)
        legend.setSceneRect(QRectF(120, 20, 80, 80))
        legend.setFrameEnabled(True)
        legend.setFrameStrokeWidth(2)
        legend.setBackgroundColor(QColor(200, 200, 200))
        legend.setTitle('')
        composition.addComposerLegend(legend)
        legend.setComposerMap(composer_map)

        checker = QgsCompositionChecker(
            'composer_legend_mapunits', composition)
        checker.setControlPathPrefix("composer_legend")
        result, message = checker.testComposition()
        self.assertTrue(result, message)

        QgsProject.instance().removeMapLayers([point_layer.id()])
Пример #3
0
    def testDuplicateComposition(self):
        """
        Test duplicating compositions
        """
        project = QgsProject()
        manager = QgsLayoutManager(project)
        doc = QDomDocument("testdoc")
        self.assertFalse(manager.duplicateComposition('not in manager', 'dest'))

        composition = QgsComposition(project)
        composition.setName('test composition')
        composition.setPaperSize(100, 200)
        manager.addComposition(composition)
        # duplicate name
        self.assertFalse(manager.duplicateComposition('test composition', 'test composition'))

        result = manager.duplicateComposition('test composition', 'dupe composition')
        self.assertTrue(result)
        # make sure result in stored in manager
        self.assertEqual(result, manager.compositionByName('dupe composition'))
        self.assertEqual(result.name(), 'dupe composition')
        self.assertEqual(result.paperHeight(), 200)
        self.assertEqual(result.paperWidth(), 100)
Пример #4
0
    def __init__(self, methodName):
        """Run once on class initialization."""
        unittest.TestCase.__init__(self, methodName)
        myPath = os.path.join(TEST_DATA_DIR, 'rgb256x256.png')
        rasterFileInfo = QFileInfo(myPath)
        mRasterLayer = QgsRasterLayer(rasterFileInfo.filePath(),
                                      rasterFileInfo.completeBaseName())
        rasterRenderer = QgsMultiBandColorRenderer(mRasterLayer.dataProvider(),
                                                   1, 2, 3)
        mRasterLayer.setRenderer(rasterRenderer)
        #pipe = mRasterLayer.pipe()
        #assert pipe.set(rasterRenderer), 'Cannot set pipe renderer'
        QgsMapLayerRegistry.instance().addMapLayers([mRasterLayer])

        # create composition with composer map
        self.mMapSettings = QgsMapSettings()
        self.mMapSettings.setLayers([mRasterLayer.id()])
        self.mMapSettings.setCrsTransformEnabled(False)
        self.mComposition = QgsComposition(self.mMapSettings)
        self.mComposition.setPaperSize(297, 210)
        self.mComposerMap = QgsComposerMap(self.mComposition, 20, 20, 200, 100)
        self.mComposerMap.setFrameEnabled(True)
        self.mComposition.addComposerMap(self.mComposerMap)
    def createComposition(self):
        '''
        Create a composition
        '''
        # Create composition
        c = QgsComposition(self.mInstance)

        # Set main properties
        c.setPaperSize(self.pageWidth, self.pageHeight)
        c.setPrintResolution(self.printResolution)
        c.setSnapGridOffsetX(3.5)
        c.setSnapGridOffsetY(0)
        c.setSnapGridResolution(2.5)

        # Set page number
        self.getPageNumberNeeded()
        c.setNumPages(self.numPages)

        # Set plot style if map added
        if self.etype == 'parcelle':
            c.setPlotStyle(QgsComposition.Print)

        self.currentComposition = c
Пример #6
0
    def testGridNorth(self):
        """Test syncing picture to grid north"""

        mapSettings = QgsMapSettings()
        composition = QgsComposition(mapSettings)

        composerMap = QgsComposerMap(composition)
        composerMap.setNewExtent(QgsRectangle(0, -256, 256, 0))
        composition.addComposerMap(composerMap)

        composerPicture = QgsComposerPicture(composition)
        composition.addComposerPicture(composerPicture)

        composerPicture.setRotationMap(composerMap.id())
        self.assertTrue(composerPicture.rotationMap() >= 0)

        composerPicture.setNorthMode(QgsComposerPicture.GridNorth)
        composerMap.setMapRotation(45)
        self.assertEqual(composerPicture.pictureRotation(), 45)

        # add an offset
        composerPicture.setNorthOffset(-10)
        self.assertEqual(composerPicture.pictureRotation(), 35)
    def testCase(self):
        TEST_DATA_DIR = unitTestDataPath()
        vectorFileInfo = QFileInfo( TEST_DATA_DIR + "/france_parts.shp")
        mVectorLayer = QgsVectorLayer( vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr" )

        QgsMapLayerRegistry.instance().addMapLayers( [mVectorLayer] )

        # create composition with composer map
        mMapRenderer = QgsMapRenderer()
        layerStringList = []
        layerStringList.append( mVectorLayer.id() )
        mMapRenderer.setLayerSet( layerStringList )
        mMapRenderer.setProjectionsEnabled( False )

        mComposition = QgsComposition( mMapRenderer )
        mComposition.setPaperSize( 297, 210 )

        mLabel = QgsComposerLabel( mComposition )
        mComposition.addComposerLabel( mLabel )

        self.evaluation_test( mComposition, mLabel )
        self.feature_evaluation_test( mComposition, mLabel, mVectorLayer )
        self.page_evaluation_test( mComposition, mLabel, mVectorLayer )
Пример #8
0
    def load_composition(self):
        """ Creates the composition object (which is needed for creating the file) from the template file.
            
            :returns: the composition object
            :rtype: QgsComposition
        """
        template_path = get_plugin_path() + self.templates[
            self.dockwidget.comboBox_template.currentText()]
        template_file = open(template_path, "r")
        content = template_file.read()
        template_file.close()

        # the method from QgsComposition for loading the template needs to be a QDomDocument
        document = QDomDocument()
        document.setContent(content)

        # composition = QgsComposition(iface.mapCanvas().mapSettings()) does not work
        #TODO: is deprecated but works ...fix in new version https://hub.qgis.org/issues/11077
        composition = QgsComposition(iface.mapCanvas().mapRenderer())
        if not composition.loadFromTemplate(document):
            iface.messageBar().pushMessage("Error while loading template!")
            return

        # set map
        map_item = composition.getComposerItemById("map")
        map_item.setMapCanvas(iface.mapCanvas())
        map_item.zoomToExtent(iface.mapCanvas().extent())

        # set legend
        try:
            legend_item = composition.getComposerItemById("legend")
            legend_item.updateLegend()
        except AttributeError:  # in case first template was selected
            pass

        composition.refreshItems()
        return composition
Пример #9
0
def make_pdf():
    canvas = QgsMapCanvas()
    # Load our project
    QgsProject.instance().read(QFileInfo(project_path))
    bridge = QgsLayerTreeMapCanvasBridge(QgsProject.instance().layerTreeRoot(),
                                         canvas)
    bridge.setCanvasLayers()
    if canvas.layerCount() < 1:
        print 'No layers loaded from this project, exiting.'
        return
    print canvas.mapSettings().extent().toString()
    template_file = file(template_path)
    template_content = template_file.read()
    template_file.close()
    document = QDomDocument()
    document.setContent(template_content)
    composition = QgsComposition(canvas.mapSettings())
    # You can use this to replace any string like this [key]
    # in the template with a new value. e.g. to replace
    # [date] pass a map like this {'date': '1 Jan 2012'}
    substitution_map = {
        'DATE_TIME_START': TIME_START,
        'DATE_TIME_END': TIME_STOP
    }
    composition.loadFromTemplate(document, substitution_map)
    # You must set the id in the template
    map_item = composition.getComposerItemById('map')
    map_item.setMapCanvas(canvas)
    map_item.zoomToExtent(canvas.extent())
    # You must set the id in the template
    legend_item = composition.getComposerItemById('legend')
    legend_item.updateLegend()
    composition.refreshItems()
    composition.exportAsPDF('/home/web/reports/pdf/%s/%s.pdf' %
                            (TIME_SLICE, LABEL))
    QgsProject.instance().clear()
Пример #10
0
    def testTrueNorth(self):
        """Test syncing picture to true north"""

        mapSettings = QgsMapSettings()
        mapSettings.setDestinationCrs(
            QgsCoordinateReferenceSystem.fromEpsgId(3575))
        composition = QgsComposition(mapSettings)

        composerMap = QgsComposerMap(composition)
        composerMap.setNewExtent(
            QgsRectangle(-2126029.962, -2200807.749, -119078.102, -757031.156))
        composition.addComposerMap(composerMap)

        composerPicture = QgsComposerPicture(composition)
        composition.addComposerPicture(composerPicture)

        composerPicture.setRotationMap(composerMap.id())
        self.assertTrue(composerPicture.rotationMap() >= 0)

        composerPicture.setNorthMode(QgsComposerPicture.TrueNorth)
        self.assertAlmostEqual(composerPicture.pictureRotation(), 37.20, 1)

        # shift map
        composerMap.setNewExtent(
            QgsRectangle(2120672.293, -3056394.691, 2481640.226, -2796718.780))
        self.assertAlmostEqual(composerPicture.pictureRotation(), -38.18, 1)

        # rotate map
        composerMap.setMapRotation(45)
        self.assertAlmostEqual(composerPicture.pictureRotation(), -38.18 + 45,
                               1)

        # add an offset
        composerPicture.setNorthOffset(-10)
        self.assertAlmostEqual(composerPicture.pictureRotation(), -38.18 + 35,
                               1)
Пример #11
0
# coding: utf-8
from qgis.core import QgsComposition
from qgis.gui import QgsComposerRuler
from qgis.utils import iface

composer_ruler = QgsComposerRuler(QgsComposerRuler.Vertical)
composition = QgsComposition(iface.mapCanvas().mapSettings())
composer_ruler.setComposition(composition)

composer_ruler.show()
Пример #12
0
app = QgsApplication(sys.argv, True)
QgsApplication.setPrefixPath("/usr", True)
QgsApplication.initQgis()

project_path = 'report_maps.qgs'
template_path = 'owner_occupancy.qpt'

canvas = QgsMapCanvas()
canvas.resize(QSize(1450, 850))
#start = time.time()
QgsProject.instance().read(QFileInfo(project_path))
#end = time.time()
root = QgsProject.instance().layerTreeRoot()
bridge = QgsLayerTreeMapCanvasBridge(root, canvas)
bridge.setCanvasLayers()
registry = QgsMapLayerRegistry.instance()

template_file = file(template_path)
template_content = template_file.read()
template_file.close()
document = QDomDocument()
document.setContent(template_content)
map_settings = canvas.mapSettings()
composition = QgsComposition(map_settings)
#start = time.time()
composition.loadFromTemplate(document)
#end = time.time()

#create list of all layers currently in the map
map_layers = [lyr for lyr in registry.mapLayers() if root.findLayer(lyr)]
Пример #13
0
    def generate_report(self):
        # Generate pdf report from impact/hazard
        LOGGER.info('Generating report')
        if not self.impact_exists:
            # Cannot generate report when no impact layer present
            LOGGER.info('Cannot Generate report when no impact present.')
            return

        project_instance = QgsProject.instance()
        project_instance.setFileName(self.project_path)
        project_instance.read()

        # get layer registry
        layer_registry = QgsMapLayerRegistry.instance()
        layer_registry.removeAllMapLayers()

        # Set up the map renderer that will be assigned to the composition
        map_renderer = CANVAS.mapRenderer()

        # Enable on the fly CRS transformations
        map_renderer.setProjectionsEnabled(True)

        default_crs = map_renderer.destinationCrs()
        crs = QgsCoordinateReferenceSystem('EPSG:4326')
        map_renderer.setDestinationCrs(crs)

        # add place name layer
        layer_registry.addMapLayer(self.cities_layer, False)

        # add airport layer
        layer_registry.addMapLayer(self.airport_layer, False)

        # add volcano layer
        layer_registry.addMapLayer(self.volcano_layer, False)

        # add impact layer
        hazard_layer = read_qgis_layer(self.hazard_path,
                                       self.tr('People Affected'))
        layer_registry.addMapLayer(hazard_layer, False)

        # add basemap layer
        layer_registry.addMapLayer(self.highlight_base_layer, False)

        # add basemap layer
        layer_registry.addMapLayer(self.overview_layer, False)

        CANVAS.setExtent(hazard_layer.extent())
        CANVAS.refresh()

        template_path = self.ash_fixtures_dir('realtime-ash.qpt')

        with open(template_path) as f:
            template_content = f.read()

        document = QDomDocument()
        document.setContent(template_content)

        # Now set up the composition
        # map_settings = QgsMapSettings()
        # composition = QgsComposition(map_settings)
        composition = QgsComposition(map_renderer)

        subtitution_map = self.event_dict()
        LOGGER.debug(subtitution_map)

        # load composition object from template
        result = composition.loadFromTemplate(document, subtitution_map)
        if not result:
            LOGGER.exception('Error loading template %s with keywords\n %s',
                             template_path, subtitution_map)
            raise MapComposerError

        # get main map canvas on the composition and set extent
        map_impact = composition.getComposerItemById('map-impact')
        if map_impact:
            map_impact.zoomToExtent(hazard_layer.extent())
            map_impact.renderModeUpdateCachedImage()
        else:
            LOGGER.exception('Map canvas could not be found in template %s',
                             template_path)
            raise MapComposerError

        # get overview map canvas on the composition and set extent
        map_overall = composition.getComposerItemById('map-overall')
        if map_overall:
            map_overall.setLayerSet([self.overview_layer.id()])
            # this is indonesia extent
            indonesia_extent = QgsRectangle(94.0927980005593554,
                                            -15.6629591962689343,
                                            142.0261493318861312,
                                            10.7379406374101816)
            map_overall.zoomToExtent(indonesia_extent)
            map_overall.renderModeUpdateCachedImage()
        else:
            LOGGER.exception('Map canvas could not be found in template %s',
                             template_path)
            raise MapComposerError

        # setup impact table
        self.render_population_table()
        self.render_nearby_table()
        self.render_landcover_table()

        impact_table = composition.getComposerItemById('table-impact')
        if impact_table is None:
            message = 'table-impact composer item could not be found'
            LOGGER.exception(message)
            raise MapComposerError(message)
        impacts_html = composition.getComposerHtmlByItem(impact_table)
        if impacts_html is None:
            message = 'Impacts QgsComposerHtml could not be found'
            LOGGER.exception(message)
            raise MapComposerError(message)
        impacts_html.setUrl(QUrl(self.population_html_path))

        # setup nearby table
        nearby_table = composition.getComposerItemById('table-nearby')
        if nearby_table is None:
            message = 'table-nearby composer item could not be found'
            LOGGER.exception(message)
            raise MapComposerError(message)
        nearby_html = composition.getComposerHtmlByItem(nearby_table)
        if nearby_html is None:
            message = 'Nearby QgsComposerHtml could not be found'
            LOGGER.exception(message)
            raise MapComposerError(message)
        nearby_html.setUrl(QUrl(self.nearby_html_path))

        # setup landcover table
        landcover_table = composition.getComposerItemById('table-landcover')
        if landcover_table is None:
            message = 'table-landcover composer item could not be found'
            LOGGER.exception(message)
            raise MapComposerError(message)
        landcover_html = composition.getComposerHtmlByItem(landcover_table)
        if landcover_html is None:
            message = 'Landcover QgsComposerHtml could not be found'
            LOGGER.exception(message)
            raise MapComposerError(message)
        landcover_html.setUrl(QUrl(self.landcover_html_path))

        # setup logos
        logos_id = ['logo-bnpb', 'logo-geologi']
        for logo_id in logos_id:
            logo_picture = composition.getComposerItemById(logo_id)
            if logo_picture is None:
                message = '%s composer item could not be found' % logo_id
                LOGGER.exception(message)
                raise MapComposerError(message)
            pic_path = os.path.basename(logo_picture.picturePath())
            pic_path = os.path.join('logo', pic_path)
            logo_picture.setPicturePath(self.ash_fixtures_dir(pic_path))

        # save a pdf
        composition.exportAsPDF(self.map_report_path)

        project_instance.write(QFileInfo(self.project_path))

        layer_registry.removeAllMapLayers()
        map_renderer.setDestinationCrs(default_crs)
        map_renderer.setProjectionsEnabled(False)
        LOGGER.info('Report generation completed.')
Пример #14
0
dpi = 200

canvas = QgsMapCanvas()
# Load our project
QgsProject.instance().read(QFileInfo(project_path))
bridge = QgsLayerTreeMapCanvasBridge(QgsProject.instance().layerTreeRoot(),
                                     canvas)
bridge.setCanvasLayers()

template_file = file(template_path)
template_content = template_file.read()
template_file.close()
document = QDomDocument()
document.setContent(template_content)
ms = canvas.mapSettings()
composition = QgsComposition(ms)
composition.loadFromTemplate(document, {})
# You must set the id in the template
#map_item = composition.getComposerItemById('map')
map_item = composition.getComposerMapById(1)
#map_item.setMapCanvas(canvas)
#map_item.zoomToExtent(canvas.extent())
# You must set the id in the template
#legend_item = composition.getComposerItemById('legend')
#legend_item.updateLegend()
composition.refreshItems()

dpmm = dpi / 25.4
#width = int(dpmm * composition.paperWidth())
width = int(1400)
print(width)
Пример #15
0
    def print_atlas(self,
                    project_path,
                    composer_name,
                    predefined_scales,
                    feature_filter=None,
                    page_name_expression=None):

        # Get composer from project
        # in QGIS 2, canno get composers without iface
        # so we reading project xml and extract composer
        # in QGIS 3.0, we will use  project layoutManager()
        from xml.etree import ElementTree as ET
        composer_xml = None
        with open(project_path, 'r') as f:
            tree = ET.parse(f)
            for elem in tree.findall('.//Composer[@title="%s"]' %
                                     composer_name):
                composer_xml = ET.tostring(elem, encoding='utf8', method='xml')

        if not composer_xml:
            return

        document = QDomDocument()
        document.setContent(composer_xml)

        # Get canvas, map setting & instantiate composition
        canvas = QgsMapCanvas()
        QgsProject.instance().read(QFileInfo(project_path))
        bridge = QgsLayerTreeMapCanvasBridge(
            QgsProject.instance().layerTreeRoot(), canvas)
        bridge.setCanvasLayers()
        ms = canvas.mapSettings()
        composition = QgsComposition(ms)

        # Load content from XML
        substitution_map = {}
        composition.loadFromTemplate(document, substitution_map)

        # Get atlas for this composition
        atlas = composition.atlasComposition()
        atlas.setEnabled(True)
        atlas_map = composition.getComposerMapById(0)
        atlas_map.setAtlasScalingMode(QgsComposerMap.Predefined)

        # get project scales
        atlas.setPredefinedScales(predefined_scales)
        atlas.setComposerMap(atlas_map)

        #on definit le filtre
        if feature_filter:
            atlas.setFilterFeatures(True)
            atlas.setFeatureFilter(feature_filter)
        if page_name_expression:
            atlas.setPageNameExpression(page_name_expression)

        # Set atlas mode
        composition.setAtlasMode(QgsComposition.ExportAtlas)

        # Generate atlas
        atlas.beginRender()
        uid = uuid4()
        for i in range(0, atlas.numFeatures()):
            atlas.prepareForFeature(i)
            export_path = os.path.join(
                tempfile.gettempdir(),
                '%s_%s.pdf' % (atlas.nameForPage(i), uid))
            exported = composition.exportAsPDF(export_path)
            if not exported or not os.path.isfile(export_path):
                return None
            break

        atlas.endRender()

        return export_path
Пример #16
0
def qgis_composer_html_renderer(impact_report, component):
    """HTML to PDF renderer using QGIS Composer.

    Render using qgis composer for a given impact_report data and component
    context for html input.

    :param impact_report: ImpactReport contains data about the report that is
        going to be generated.
    :type impact_report: safe.report.impact_report.ImpactReport

    :param component: Contains the component metadata and context for
        rendering the output.
    :type component:
        safe.report.report_metadata.QgisComposerComponentsMetadata

    :return: Whatever type of output the component should be.

    .. versionadded:: 4.0
    """
    context = component.context
    """:type: safe.report.extractors.composer.QGISComposerContext"""
    qgis_composition_context = impact_report.qgis_composition_context

    # load composition object
    composition = QgsComposition(qgis_composition_context.map_settings)

    if not context.html_frame_elements:
        # if no html frame elements at all, do not generate empty report.
        component.output = ''
        return component.output

    # Add HTML Frame
    for html_el in context.html_frame_elements:
        mode = html_el.get('mode')
        html_element = QgsComposerHtml(composition, False)
        """:type: qgis.core.QgsComposerHtml"""
        margin_left = html_el.get('margin_left', 10)
        margin_top = html_el.get('margin_top', 10)
        width = html_el.get('width', component.page_width - 2 * margin_left)
        height = html_el.get('height', component.page_height - 2 * margin_top)

        html_frame = QgsComposerFrame(
            composition,
            html_element,
            margin_left,
            margin_top,
            width,
            height)
        html_element.addFrame(html_frame)

        if html_element:
            if mode == 'text':
                text = html_el.get('text')
                text = text if text else ''
                html_element.setContentMode(QgsComposerHtml.ManualHtml)
                html_element.setResizeMode(
                    QgsComposerHtml.RepeatUntilFinished)
                html_element.setHtml(text)
                html_element.loadHtml()
            elif mode == 'url':
                url = html_el.get('url')
                html_element.setContentMode(QgsComposerHtml.Url)
                html_element.setResizeMode(
                    QgsComposerHtml.RepeatUntilFinished)
                qurl = QUrl.fromLocalFile(url)
                html_element.setUrl(qurl)

    # Attempt on removing blank page. Notes: We assume that the blank page
    # will always appears in the last x page(s), not in the middle.

    index = composition.numPages()
    number_of_pages_to_be_removed = 0
    while composition.pageIsEmpty(index):
        number_of_pages_to_be_removed += 1
        index -= 1

    composition.setNumPages(
        composition.numPages() - number_of_pages_to_be_removed)

    # process to output

    # in case output folder not specified
    if impact_report.output_folder is None:
        impact_report.output_folder = mkdtemp(dir=temp_dir())
    component_output_path = impact_report.component_absolute_output_path(
        component.key)
    component_output = None

    output_format = component.output_format

    doc_format = QgisComposerComponentsMetadata.OutputFormat.DOC_OUTPUT
    template_format = QgisComposerComponentsMetadata.OutputFormat.QPT
    if isinstance(output_format, list):
        component_output = []
        for i in range(len(output_format)):
            each_format = output_format[i]
            each_path = component_output_path[i]

            if each_format in doc_format:
                result_path = create_qgis_pdf_output(
                    impact_report,
                    each_path,
                    composition,
                    each_format,
                    component)
                component_output.append(result_path)
            elif each_format == template_format:
                result_path = create_qgis_template_output(
                    each_path, composition)
                component_output.append(result_path)
    elif isinstance(output_format, dict):
        component_output = {}
        for key, each_format in output_format.iteritems():
            each_path = component_output_path[key]

            if each_format in doc_format:
                result_path = create_qgis_pdf_output(
                    impact_report,
                    each_path,
                    composition,
                    each_format,
                    component)
                component_output[key] = result_path
            elif each_format == template_format:
                result_path = create_qgis_template_output(
                    each_path, composition)
                component_output[key] = result_path
    elif (output_format in
            QgisComposerComponentsMetadata.OutputFormat.SUPPORTED_OUTPUT):
        component_output = None

        if output_format in doc_format:
            result_path = create_qgis_pdf_output(
                impact_report,
                component_output_path,
                composition,
                output_format,
                component)
            component_output = result_path
        elif output_format == template_format:
            result_path = create_qgis_template_output(
                component_output_path, composition)
            component_output = result_path

    component.output = component_output

    return component.output
    def testCase(self):
        self.TEST_DATA_DIR = unitTestDataPath()
        tmppath = tempfile.mkdtemp()
        for file in glob.glob(
                os.path.join(self.TEST_DATA_DIR, 'france_parts.*')):
            shutil.copy(os.path.join(self.TEST_DATA_DIR, file), tmppath)
        vectorFileInfo = QFileInfo(tmppath + "/france_parts.shp")
        mVectorLayer = QgsVectorLayer(vectorFileInfo.filePath(),
                                      vectorFileInfo.completeBaseName(), "ogr")

        QgsMapLayerRegistry.instance().addMapLayers([mVectorLayer])

        # create composition with composer map
        self.mapSettings = QgsMapSettings()
        layerStringList = []
        layerStringList.append(mVectorLayer.id())
        self.mapSettings.setLayers(layerStringList)
        self.mapSettings.setCrsTransformEnabled(True)
        self.mapSettings.setMapUnits(QGis.Meters)

        # select epsg:2154
        crs = QgsCoordinateReferenceSystem()
        crs.createFromSrid(2154)
        self.mapSettings.setDestinationCrs(crs)

        self.mComposition = QgsComposition(self.mapSettings)
        self.mComposition.setPaperSize(297, 210)

        # fix the renderer, fill with green
        props = {"color": "0,127,0"}
        fillSymbol = QgsFillSymbolV2.createSimple(props)
        renderer = QgsSingleSymbolRendererV2(fillSymbol)
        mVectorLayer.setRendererV2(renderer)

        # the atlas map
        self.mAtlasMap = QgsComposerMap(self.mComposition, 20, 20, 130, 130)
        self.mAtlasMap.setFrameEnabled(True)
        self.mComposition.addComposerMap(self.mAtlasMap)

        # the atlas
        self.mAtlas = self.mComposition.atlasComposition()
        self.mAtlas.setCoverageLayer(mVectorLayer)
        self.mAtlas.setEnabled(True)
        self.mComposition.setAtlasMode(QgsComposition.ExportAtlas)

        # an overview
        mOverview = QgsComposerMap(self.mComposition, 180, 20, 50, 50)
        mOverview.setFrameEnabled(True)
        mOverview.setOverviewFrameMap(self.mAtlasMap.id())
        self.mComposition.addComposerMap(mOverview)
        nextent = QgsRectangle(49670.718, 6415139.086, 699672.519, 7065140.887)
        mOverview.setNewExtent(nextent)

        # set the fill symbol of the overview map
        props2 = {"color": "127,0,0,127"}
        fillSymbol2 = QgsFillSymbolV2.createSimple(props2)
        mOverview.setOverviewFrameMapSymbol(fillSymbol2)

        # header label
        self.mLabel1 = QgsComposerLabel(self.mComposition)
        self.mComposition.addComposerLabel(self.mLabel1)
        self.mLabel1.setText("[% \"NAME_1\" %] area")
        self.mLabel1.setFont(QgsFontUtils.getStandardTestFont())
        self.mLabel1.adjustSizeToText()
        self.mLabel1.setSceneRect(QRectF(150, 5, 60, 15))

        qWarning(
            "header label font: %s exactMatch:%s" %
            (self.mLabel1.font().toString(), self.mLabel1.font().exactMatch()))

        # feature number label
        self.mLabel2 = QgsComposerLabel(self.mComposition)
        self.mComposition.addComposerLabel(self.mLabel2)
        self.mLabel2.setText("# [%$feature || ' / ' || $numfeatures%]")
        self.mLabel2.setFont(QgsFontUtils.getStandardTestFont())
        self.mLabel2.adjustSizeToText()
        self.mLabel2.setSceneRect(QRectF(150, 200, 60, 15))

        qWarning(
            "feature number label font: %s exactMatch:%s" %
            (self.mLabel2.font().toString(), self.mLabel2.font().exactMatch()))

        self.filename_test()
        self.autoscale_render_test()
        self.autoscale_render_test_old_api()
        self.fixedscale_render_test()
        self.predefinedscales_render_test()
        self.hidden_render_test()
        self.legend_test()

        shutil.rmtree(tmppath, True)
Пример #18
0
 def setUp(self):
     """Run before each test."""
     self.mapSettings = QgsMapSettings()
     self.mComposition = QgsComposition(self.mapSettings)
     self.mComposition.setPaperSize(297, 210) #A4 landscape
Пример #19
0
    def exportToPdf(self, print_context, targetFile=None):
        self.iface.mapCanvas().setDestinationCrs(
            self.settings_instance.projection.crs())
        myComposition = QgsComposition(self.iface.mapCanvas().mapSettings())
        template = self.env.get_template(print_context['template'])

        custom_qpt = template.render(CONTEXT=print_context)
        myDocument = QDomDocument()
        myDocument.setContent(custom_qpt)
        myComposition.loadFromTemplate(myDocument)

        suggestedFile = os.path.join(
            self.settings_instance.projectFolderPath.text(),
            print_context['title'] + ".pdf")
        if not targetFile:
            targetFile = QFileDialog.getSaveFileName(
                None, "Export " + print_context['job'], suggestedFile, "*.pdf")
            interactive = True
            if not targetFile:
                return
        else:
            interactive = None

        outputDir = tempfile.gettempdir()

        with open(os.path.join(targetFile + '.qpt'), "wb") as qpt_file:
            qpt_file.write(custom_qpt)

        if print_context['type'] == 'report':
            myComposition.exportAsPDF(targetFile)

        elif print_context['type'] == 'map':
            print myComposition.getComposerMapById(0)
            print myComposition.getComposerItemById('5')

            for composer_map in myComposition.composerMapItems():
                print composer_map, composer_map.id()

            fdtm_extent = None
            for layer in [
                    self.settings_instance.EPpLayer,
                    self.settings_instance.EApLayer,
                    self.settings_instance.WRLayer,
                    self.settings_instance.WDSLayer
            ]:
                if layer.featureCount() > 0:
                    if fdtm_extent:
                        fdtm_extent.combineExtentWith(layer.extent())
                    else:
                        fdtm_extent = layer.extent()
            fdtm_extent.scale(1.1)
            composer_map.zoomToExtent(fdtm_extent)
            composer_map.updateItem()
            myComposition.refreshItems()

            myComposition.exportAsPDF(targetFile)

        elif print_context['type'] == 'mapppp':
            print print_context
            myComposition = QgsComposition(
                self.iface.mapCanvas().mapSettings())
            myComposition.setPlotStyle(QgsComposition.Print)
            myComposition.setPaperSize(297, 210)
            composer_map = QgsComposerMap(myComposition, 10, 10, 190, 190)
            fdtm_extent = self.settings_instance.EPpLayer.extent()
            for layer in [
                    self.settings_instance.EApLayer,
                    self.settings_instance.WRLayer,
                    self.settings_instance.WDSLayer
            ]:
                fdtm_extent.combineExtentWith(layer.extent())
            composer_map.zoomToExtent(fdtm_extent)
            composer_map.updateItem()
            myComposition.addItem(composer_map)

            table = QgsComposerAttributeTable(myComposition)
            table.setItemPosition(205, 170)
            table.setVectorLayer(QgsMapLayerRegistry.instance().mapLayer(
                print_context['id']))
            table.setMaximumNumberOfFeatures(20)
            table.setFilterFeatures(True)
            col1 = QgsComposerTableColumn()
            col1.setAttribute('types')
            col1.setHeading("types")
            col2 = QgsComposerTableColumn()
            col2.setAttribute('project units')
            col2.setHeading("project units")
            col3 = QgsComposerTableColumn()
            col3.setAttribute('Areas')
            col3.setHeading("Areas")
            col4 = QgsComposerTableColumn()
            col4.setAttribute('Lengths')
            col4.setHeading("Lengths")
            col5 = QgsComposerTableColumn()
            col5.setAttribute('Cost')
            col5.setHeading("Cost")
            table.setColumns([col1, col2, col3, col4, col5])
            myComposition.addItem(table)

            myComposition.exportAsPDF(targetFile)

        elif print_context['type'] == 'atlas':

            myComposition.setAtlasMode(QgsComposition.ExportAtlas)
            for composer_map in myComposition.composerMapItems():
                print composer_map, composer_map.id()

            atlas = myComposition.atlasComposition()
            atlas.setComposerMap(composer_map)  #DEPRECATED
            atlas.setPredefinedScales(self.PREDEFINED_SCALES)
            composer_map.setAtlasDriven(True)
            composer_map.setAtlasScalingMode(QgsComposerMap.Predefined)

            atlas.beginRender()
            rendered_pdf = []
            progress = progressBar(self, "exporting " + print_context['job'],
                                   atlas.numFeatures())
            for i in range(0, atlas.numFeatures()):
                atlas.prepareForFeature(i)
                current_filename = atlas.currentFilename()
                file_name = '_'.join(current_filename.split())
                file_path = '%s.pdf' % file_name
                path = os.path.join(outputDir, file_path)
                myComposition.exportAsPDF(path)
                rendered_pdf.append(path)
                progress.setStep(i)
            progress.stop(print_context['job'] + "exported to " + targetFile)
            atlas.endRender()

            merge_pdfs(rendered_pdf, targetFile)

        if interactive:
            open_file(targetFile)

        return targetFile
    def export_all_features(self):
        pdf_painter = None
        """Export map to pdf atlas style (one page per feature)"""
        if VRP_DEBUG is True: QgsMessageLog.logMessage(u'exporting map', DLG_CAPTION)
        try:

            result = self.__delete_pdf()
            if not result is None:
                return result

            ids = []
            exp = QgsExpression(self.feature_filter)
            if exp.hasParserError():
                raise Exception(exp.parserErrorString())
            exp.prepare(self.coverage_layer.pendingFields())
            for feature in self.coverage_layer.getFeatures():
                value = exp.evaluate(feature)
                if exp.hasEvalError():
                    raise ValueError(exp.evalErrorString())
                if bool(value):
                    if VRP_DEBUG is True: QgsMessageLog.logMessage(u'export map, feature id:{0}'.format(feature.id()), DLG_CAPTION)
                    ids.append(feature.id())
            self.coverage_layer.select(ids)
            bbox = self.coverage_layer.boundingBoxOfSelected()
            self.canvas.zoomToSelected(self.coverage_layer)
            if VRP_DEBUG is True: QgsMessageLog.logMessage(u'bbox:{0}'.format(bbox.toString()), DLG_CAPTION)

            #self.map_renderer.setExtent(bbox)
            #self.map_renderer.updateScale()

            #read plotlayout
            composition = QgsComposition(self.map_renderer)
            self.composition = composition
            composition.setPlotStyle(QgsComposition.Print)
            error, xml_doc = self.__read_template()
            if not error is None:
                return error
            if composition.loadFromTemplate(xml_doc) is False:
                return u'Konnte Template nicht laden!\n{0}'.format(self.template_qpt)

            #read textinfo layout
            self.comp_textinfo = QgsComposition(self.map_renderer)
            self.comp_textinfo.setPlotStyle(QgsComposition.Print)
            error, xml_doc = self.__read_template(True)
            if not error is None:
                return error
            if self.comp_textinfo.loadFromTemplate(xml_doc) is False:
                return u'Konnte Template nicht laden!\n{0}'.format(self.settings.textinfo_layout())


            new_ext = bbox
            if QGis.QGIS_VERSION_INT > 20200:
                compmaps = self.__get_items(QgsComposerMap)
                if len(compmaps) < 1:
                    return u'Kein Kartenfenster im Layout vorhanden!'
                compmap = compmaps[0]
            else:
                if len(composition.composerMapItems()) < 1:
                    return u'Kein Kartenfenster im Layout vorhanden!'
                compmap = composition.composerMapItems()[0]

            self.composermap = compmap
            #self.composermap.setPreviewMode(QgsComposerMap.Render)
            #self.composermap.setPreviewMode(QgsComposerMap.Rectangle)
            #taken from QgsComposerMap::setNewAtlasFeatureExtent (not yet available in QGIS 2.0)
            #http://www.qgis.org/api/qgscomposermap_8cpp_source.html#l00610
            old_ratio = compmap.rect().width() / compmap.rect().height()
            new_ratio = new_ext.width() / new_ext.height()
            if old_ratio < new_ratio:
                new_height = new_ext.width() / old_ratio
                delta_height = new_height - new_ext.height()
                new_ext.setYMinimum( bbox.yMinimum() - delta_height / 2)
                new_ext.setYMaximum(bbox.yMaximum() + delta_height / 2)
            else:
                new_width = old_ratio * new_ext.height()
                delta_width = new_width - new_ext.width()
                new_ext.setXMinimum(bbox.xMinimum() - delta_width / 2)
                new_ext.setXMaximum(bbox.xMaximum() + delta_width / 2)

            if VRP_DEBUG is True: QgsMessageLog.logMessage(u'bbox old:{0}'.format(compmap.extent().toString()), DLG_CAPTION)
            compmap.setNewExtent(new_ext)
            if VRP_DEBUG is True: QgsMessageLog.logMessage(u'bbox new:{0}'.format(compmap.extent().toString()), DLG_CAPTION)
            #round up to next 1000
            compmap.setNewScale(math.ceil((compmap.scale()/1000.0)) * 1000.0)
            if VRP_DEBUG is True: QgsMessageLog.logMessage(u'bbox new (after scale):{0}'.format(compmap.extent().toString()), DLG_CAPTION)

            #add ORTHO after new extent -> performance
            if not self.ortho is None:
                self.ortho_lyr = self.__add_raster_layer(self.ortho, self.lyrname_ortho)
                self.__reorder_layers()

            self.comp_leg = self.__get_items(QgsComposerLegend)
            self.comp_lbl = self.__get_items(QgsComposerLabel)


            self.__update_composer_items(self.settings.dkm_gemeinde(self.gem_name)['lyrnamegstk'])

            if VRP_DEBUG is True:
                QgsMessageLog.logMessage(u'paperWidth:{0} paperHeight:{1}'.format(composition.paperWidth(), composition.paperHeight()), DLG_CAPTION)

            printer = QPrinter()
            printer.setOutputFormat(QPrinter.PdfFormat)
            printer.setOutputFileName(self.pdf_map)
            printer.setPaperSize(QSizeF(composition.paperWidth(), composition.paperHeight()), QPrinter.Millimeter)
            printer.setFullPage(True)
            printer.setColorMode(QPrinter.Color)
            printer.setResolution(composition.printResolution())

            pdf_painter = QPainter(printer)
            paper_rect_pixel = printer.pageRect(QPrinter.DevicePixel)
            paper_rect_mm = printer.pageRect(QPrinter.Millimeter)
            QgsPaintEngineHack.fixEngineFlags(printer.paintEngine())
            #DKM only
            if len(self.themen) < 1:
                composition.render(pdf_painter, paper_rect_pixel, paper_rect_mm)
            else:
                self.statistics = OrderedDict()
                try:
                    pass
                    #lyr = QgsVectorLayer('/home/bergw/VoGIS-Raumplanung-Daten/Geodaten/Raumplanung/Flaechenwidmung/Dornbirn/Flaechenwidmungsplan/fwp_flaeche.shp', 'flaeiw', 'ogr')
                    #lyr.loadNamedStyle('/home/bergw/VoGIS-Raumplanung-Daten/Geodaten/Raumplanung/Flaechenwidmung/Vorarlberg/Flaechenwidmungsplan/fwp_flaeche.qml')
                    #QgsMapLayerRegistry.instance().addMapLayer(lyr)
                except:
                    QgsMessageLog.logMessage('new lyr:{0}'.format(sys.exc_info()[0]), DLG_CAPTION)
                #QgsMapLayerRegistry.instance().addMapLayer(lyr)
                cntr = 0
                for thema, sub_themen in self.themen.iteritems():
                    if VRP_DEBUG is True: QgsMessageLog.logMessage('drucke Thema:{0}'.format(thema.name), DLG_CAPTION)
                    if sub_themen is None:
                        layers = self.__add_layers(thema)
                        self.__calculate_statistics(thema, thema, layers)
                        #no qml -> not visible -> means no map
                        if self.__at_least_one_visible(layers) is True:
                            if cntr > 0:
                                printer.newPage()
                            self.__reorder_layers()
                            self.__update_composer_items(thema.name, layers=layers)
                            composition.renderPage(pdf_painter, 0)
                            QgsMapLayerRegistry.instance().removeMapLayers([lyr.id() for lyr in layers])
                            cntr += 1
                        else:
                            QgsMapLayerRegistry.instance().removeMapLayers([lyr.id() for lyr in layers])
                    if not sub_themen is None:
                        for sub_thema in sub_themen:
                            if VRP_DEBUG is True: QgsMessageLog.logMessage(u'drucke SubThema:{0}'.format(sub_thema.name), DLG_CAPTION)
                            layers = self.__add_layers(sub_thema)
                            self.__calculate_statistics(thema, sub_thema, layers)
                            #no qml -> not visible -> means no map
                            if self.__at_least_one_visible(layers) is True:
                                if cntr > 0:
                                    printer.newPage()
                                self.__reorder_layers()
                                self.__update_composer_items(thema.name, subthema=sub_thema.name, layers=layers)
                                composition.renderPage(pdf_painter, 0)
                                QgsMapLayerRegistry.instance().removeMapLayers([lyr.id() for lyr in layers])
                                cntr += 1
                            else:
                                QgsMapLayerRegistry.instance().removeMapLayers([lyr.id() for lyr in layers])
            #output statistics
            if len(self.statistics) > 0:
                printer.setPaperSize(QSizeF(210, 297), QPrinter.Millimeter)
                tabelle = self.__get_item_byid(self.comp_textinfo, 'TABELLE')
                if tabelle is None:
                    self.iface.messageBar().pushMessage(u'Layout (Textinfo): Kein Textelement mit ID "TABELLE" vorhanden.', QgsMessageBar.CRITICAL)
                else:
                    try:
                        str_flaechen = ''
                        idx = 0
                        for gnr, stats in self.statistics.iteritems():
                            comma = ', ' if idx > 0 else ''
                            str_flaechen += u'{0}{1} ({2:.2f}m²)'.format(comma, gnr, stats[0].flaeche)
                            idx += 1
                        lbls = self.__get_items(QgsComposerLabel, self.comp_textinfo)
                        self.__update_composer_items('', labels=lbls, gnrflaeche=str_flaechen)
                        html = tabelle.text()
                        html += u'<table>'
                        #gnrcnt = 0
                        for gnr, stats in self.statistics.iteritems():
                            #if gnrcnt > 0:
                            #    html += u'<tr class="abstand"><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>'
                            html += u'<tr><th class="gnr"></th><th class="gnr">{0}</th><th class="gnr"></th></tr>'.format(gnr)
                            #html += u'<tr class="abstand"><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>'
                            curr_thema = ''
                            for stat in stats:
                                if stat.thema != curr_thema:
                                    html += u'<tr><th class="thema"></th><th class="thema">{0}</th><th class="thema"></th></tr>'.format(stat.thema)
                                curr_thema = stat.thema
                                for thema, subthema in stat.subthemen.iteritems():
                                    for quelle in subthema:
                                        html += u'<tr><td class="col1">{0}</td>'.format(quelle.name)
                                        attr_val = ''
                                        attr_area = ''
                                        for text, area in quelle.txt_area.iteritems():
                                            attr_val += u'{0}<br />'.format(text)
                                            attr_area += u'{0:.2f}m² <br />'.format(area)
                                        html += u'<td class="col2">{0}</td><td class="col3">{1}</td></tr>'.format(attr_val, attr_area)
                            #gnrcnt += 1
                        html += u'</table>'
                        tabelle.setText(html)
                        printer.newPage()
                        self.comp_textinfo.renderPage(pdf_painter, 0)
                    except:
                        msg = 'Statistikausgabe:\n\n{0}'.format(traceback.format_exc())
                        QgsMessageLog.logMessage(msg, DLG_CAPTION)
                        self.iface.messageBar().pushMessage(msg, QgsMessageBar.CRITICAL)
        except:
            msg = 'export pdf (catch all):\n\n{0}'.format(traceback.format_exc())
            QgsMessageLog.logMessage(msg, DLG_CAPTION)
            self.iface.messageBar().pushMessage(msg.replace(u'\n', u''), QgsMessageBar.CRITICAL)
            return msg
        finally:
            #end pdf
            if not pdf_painter is None:
                pdf_painter.end()
        return None
Пример #21
0
    def generate_report(self):
        # Generate pdf report from impact/hazard
        if not self.impact_exists:
            # Cannot generate report when no impact layer present
            return

        project_path = os.path.join(self.report_path,
                                    'project-%s.qgs' % self.locale)
        project_instance = QgsProject.instance()
        project_instance.setFileName(project_path)
        project_instance.read()

        # Set up the map renderer that will be assigned to the composition
        map_renderer = CANVAS.mapRenderer()
        # Set the labelling engine for the canvas
        labelling_engine = QgsPalLabeling()
        map_renderer.setLabelingEngine(labelling_engine)

        # Enable on the fly CRS transformations
        map_renderer.setProjectionsEnabled(True)

        default_crs = map_renderer.destinationCrs()
        crs = QgsCoordinateReferenceSystem('EPSG:4326')
        map_renderer.setDestinationCrs(crs)

        # get layer registry
        layer_registry = QgsMapLayerRegistry.instance()
        layer_registry.removeAllMapLayers()
        # add impact layer
        population_affected_layer = read_qgis_layer(
            self.population_aggregate_path, self.tr('People Affected'))
        layer_registry.addMapLayer(population_affected_layer, True)
        # add boundary mask
        boundary_mask = read_qgis_layer(
            self.flood_fixtures_dir('boundary-mask.shp'))
        layer_registry.addMapLayer(boundary_mask, False)
        # add hazard layer
        hazard_layer = read_qgis_layer(self.hazard_path,
                                       self.tr('Flood Depth (cm)'))
        layer_registry.addMapLayer(hazard_layer, True)
        # add boundary layer
        boundary_layer = read_qgis_layer(
            self.flood_fixtures_dir('boundary-5.shp'))
        layer_registry.addMapLayer(boundary_layer, False)
        CANVAS.setExtent(boundary_layer.extent())
        CANVAS.refresh()
        # add basemap layer
        # this code uses OpenlayersPlugin
        base_map = QgsRasterLayer(self.flood_fixtures_dir('jakarta.jpg'))
        layer_registry.addMapLayer(base_map, False)
        CANVAS.refresh()

        template_path = self.flood_fixtures_dir('realtime-flood.qpt')

        with open(template_path) as f:
            template_content = f.read()

        document = QDomDocument()
        document.setContent(template_content)

        # set destination CRS to Jakarta CRS
        # EPSG:32748
        # This allows us to use the scalebar in meter unit scale
        crs = QgsCoordinateReferenceSystem('EPSG:32748')
        map_renderer.setDestinationCrs(crs)

        # Now set up the composition
        composition = QgsComposition(map_renderer)

        subtitution_map = self.event_dict()
        LOGGER.debug(subtitution_map)

        # load composition object from template
        result = composition.loadFromTemplate(document, subtitution_map)
        if not result:
            LOGGER.exception('Error loading template %s with keywords\n %s',
                             template_path, subtitution_map)
            raise MapComposerError

        # get main map canvas on the composition and set extent
        map_canvas = composition.getComposerItemById('map-canvas')
        if map_canvas:
            map_canvas.setNewExtent(map_canvas.currentMapExtent())
            map_canvas.renderModeUpdateCachedImage()
        else:
            LOGGER.exception('Map canvas could not be found in template %s',
                             template_path)
            raise MapComposerError

        # get map legend on the composition
        map_legend = composition.getComposerItemById('map-legend')
        if map_legend:
            # show only legend for Flood Depth
            # ''.star
            # showed_legend = [layer_id for layer_id in map_renderer.layerSet()
            #                  if layer_id.startswith('Flood_Depth')]
            # LOGGER.info(showed_legend)
            # LOGGER.info(map_renderer.layerSet())
            # LOGGER.info(hazard_layer.id())

            # map_legend.model().setLayerSet(showed_legend)
            # map_legend.modelV2().clear()
            # print dir(map_legend.modelV2())
            # map_legend.setLegendFilterByMapEnabled(True)

            map_legend.model().setLayerSet(
                [hazard_layer.id(),
                 population_affected_layer.id()])

        else:
            LOGGER.exception('Map legend could not be found in template %s',
                             template_path)
            raise MapComposerError

        content_analysis = composition.getComposerItemById(
            'content-analysis-result')
        if not content_analysis:
            message = 'Content analysis composer item could not be found'
            LOGGER.exception(message)
            raise MapComposerError(message)
        content_analysis_html = content_analysis.multiFrame()
        if content_analysis_html:
            # set url to generated html
            analysis_html_path = self.generate_analysis_result_html()
            # We're using manual HTML to avoid memory leak and segfault
            # happened when using Url Mode
            content_analysis_html.setContentMode(QgsComposerHtml.ManualHtml)
            with open(analysis_html_path) as f:
                content_analysis_html.setHtml(f.read())
                content_analysis_html.loadHtml()
        else:
            message = 'Content analysis HTML not found in template'
            LOGGER.exception(message)
            raise MapComposerError(message)

        # save a pdf
        composition.exportAsPDF(self.map_report_path)

        project_instance.write(QFileInfo(project_path))

        layer_registry.removeAllMapLayers()
        map_renderer.setDestinationCrs(default_crs)
        map_renderer.setProjectionsEnabled(False)
Пример #22
0
    def load_template(self, renderer):
        """Load composer template for merged report.

        Validate it as well. The template needs to have:
        1. QgsComposerMap with id 'impact-map' for merged impact map.
        2. QgsComposerPicture with id 'safe-logo' for InaSAFE logo.
        3. QgsComposerLabel with id 'summary-report' for a summary of two
        impacts.
        4. QgsComposerLabel with id 'aggregation-area' to indicate the area
        of aggregation.
        5. QgsComposerScaleBar with id 'map-scale' for impact map scale.
        6. QgsComposerLegend with id 'map-legend' for impact map legend.
        7. QgsComposerPicture with id 'organisation-logo' for organisation
        logo.
        8. QgsComposerLegend with id 'impact-legend' for map legend.
        9. QgsComposerHTML with id 'merged-report-table' for the merged report.

        :param renderer: Map renderer
        :type renderer: QgsMapRenderer

        """
        # Create Composition
        composition = QgsComposition(renderer)

        template_file = QtCore.QFile(self.template_path)
        template_file.open(QtCore.QIODevice.ReadOnly | QtCore.QIODevice.Text)
        template_content = template_file.readAll()
        template_file.close()

        # Create a dom document containing template content
        document = QtXml.QDomDocument()
        document.setContent(template_content)

        # Prepare Map Substitution
        impact_title = '%s and %s' % (self.first_impact['map_title'],
                                      self.second_impact['map_title'])
        substitution_map = {
            'impact-title': impact_title,
            'hazard-title': self.first_impact['hazard_title'],
            'disclaimer': self.disclaimer
        }

        # Load template
        load_status = composition.loadFromTemplate(document, substitution_map)
        if not load_status:
            raise ReportCreationError(
                self.tr('Error loading template %s') % self.template_path)

        # Validate all needed composer components
        component_ids = [
            'impact-map', 'safe-logo', 'summary-report', 'aggregation-area',
            'map-scale', 'map-legend', 'organisation-logo',
            'merged-report-table'
        ]
        for component_id in component_ids:
            component = composition.getComposerItemById(component_id)
            if component is None:
                raise ReportCreationError(
                    self.tr('Component %s could not be found' % component_id))

        # Set InaSAFE logo
        safe_logo = composition.getComposerItemById('safe-logo')
        safe_logo.setPictureFile(self.safe_logo_path)

        # set organisation logo
        org_logo = composition.getComposerItemById('organisation-logo')
        org_logo.setPictureFile(self.organisation_logo_path)

        # Set Map Legend
        legend = composition.getComposerItemById('map-legend')
        legend.updateLegend()

        return composition
Пример #23
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 dbmodel: In order to name the files using the custom column mapping, a callable
        sqlalchemy data model must be specified.
        """
        #Unpack arguments
        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", "")
        dataModel = kwargs.get("dbmodel", None)

        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)

            #Execute query
            dsTable, records = self._execQuery(composerDS.name(),
                                               entityFieldName,
                                               entityFieldValue)

            if records == None:
                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._mapRenderer)
                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 composerItem != None:
                        fieldName = composerDS.dataFieldName(composerId)
                        fieldValue = getattr(rec, fieldName)
                        self._composerItemValueHandler(composerItem,
                                                       fieldValue)

                #Create memory layers for spatial features and add them to the map
                for mapId, spfmList in spatialFieldsConfig.spatialFieldsMapping(
                ).iteritems():
                    mapItem = composition.getComposerItemById(mapId)

                    if mapItem != None:
                        #Clear any previous memory layer
                        self.clearTemporaryLayers()

                        for spfm in spfmList:
                            #Use the value of the label field to name the layer
                            layerName = getattr(rec, spfm.labelField())

                            #Extract the geometry using geoalchemy spatial capabilities
                            geomFunc = getattr(
                                rec, spfm.spatialField()).ST_AsText()
                            geomWKT = self._dbSession.scalar(geomFunc)

                            #Create reference layer with feature
                            refLayer = self._buildVectorLayer(layerName)

                            #Add feature
                            bbox = self._addFeatureToLayer(refLayer, geomWKT)
                            bbox.scale(spfm.zoomLevel())

                            #Add layer to map
                            QgsMapLayerRegistry.instance().addMapLayer(
                                refLayer)
                            self._iface.mapCanvas().setExtent(bbox)
                            self._iface.mapCanvas().refresh()

                            #mapItem.storeCurrentLayerSet()
                            #mapItem.updateCachedImage()

                            #Add layer to memory layer list
                            self._memoryLayers.append(refLayer)

                        mapItem.setNewExtent(self._mapRenderer.extent())

                #Build output path and generate composition
                if filePath != None and len(dataFields) == 0:
                    self._writeOutput(composition, outputMode, filePath)

                elif filePath == None and len(dataFields) > 0:
                    docFileName = self._buildFileName(dataModel,
                                                      entityFieldName,
                                                      entityFieldValue,
                                                      dataFields,
                                                      fileExtension)
                    if docFileName == "":
                        return (
                            False,
                            QApplication.translate(
                                "DocumentGenerator",
                                "File name could not be generated from the data fields."
                            ))

                    outputDir = self._composerOutputPath()
                    if outputDir == 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 = unicode(outputDir) + "/" + docFileName
                    self._writeOutput(composition, outputMode, absDocPath)

            #Clear temporary layers
            self.clearTemporaryLayers()

            return (True, "Success")

        return (False, "Composition could not be generated")
Пример #24
0
def qgis_composer_renderer(impact_report, component):
    """Default Map Report Renderer using QGIS Composer.

    Render using qgis composer for a given impact_report data and component
    context.

    :param impact_report: ImpactReport contains data about the report that is
        going to be generated.
    :type impact_report: safe.report.impact_report.ImpactReport

    :param component: Contains the component metadata and context for
        rendering the output.
    :type component:
        safe.report.report_metadata.QgisComposerComponentsMetadata

    :return: Whatever type of output the component should be.

    .. versionadded:: 4.0
    """
    context = component.context
    """:type: safe.report.extractors.composer.QGISComposerContext"""
    qgis_composition_context = impact_report.qgis_composition_context

    # load composition object
    composition = QgsComposition(qgis_composition_context.map_settings)

    # load template
    main_template_folder = impact_report.metadata.template_folder

    # we do this condition in case custom template was found
    if component.template.startswith('../qgis-composer-templates/'):
        template_path = os.path.join(main_template_folder, component.template)
    else:
        template_path = component.template

    with open(template_path) as template_file:
        template_content = template_file.read()

    document = QtXml.QDomDocument()
    document.setContent(template_content)

    load_status = composition.loadFromTemplate(
        document, context.substitution_map)

    if not load_status:
        raise TemplateLoadingError(
            tr('Error loading template: %s') % template_path)

    # replace image path
    for img in context.image_elements:
        item_id = img.get('id')
        path = img.get('path')
        image = composition_item(composition, item_id, QgsComposerPicture)
        """:type: qgis.core.QgsComposerPicture"""
        if image and path:
            image.setPicturePath(path)

    # replace html frame
    for html_el in context.html_frame_elements:
        item_id = html_el.get('id')
        mode = html_el.get('mode')
        composer_item = composition.getComposerItemById(item_id)
        try:
            html_element = composition.getComposerHtmlByItem(composer_item)
        except:
            pass
        """:type: qgis.core.QgsComposerHtml"""
        if html_element:
            if mode == 'text':
                text = html_el.get('text')
                text = text if text else ''
                html_element.setContentMode(QgsComposerHtml.ManualHtml)
                html_element.setHtml(text)
                html_element.loadHtml()
            elif mode == 'url':
                url = html_el.get('url')
                html_element.setContentMode(QgsComposerHtml.Url)
                qurl = QUrl.fromLocalFile(url)
                html_element.setUrl(qurl)

    original_crs = impact_report.impact_function.crs
    destination_crs = qgis_composition_context.map_settings.destinationCrs()
    coord_transform = QgsCoordinateTransform(original_crs, destination_crs)

    # resize map extent
    for map_el in context.map_elements:
        item_id = map_el.get('id')
        split_count = map_el.get('grid_split_count')
        layers = [
            layer for layer in map_el.get('layers') if isinstance(
                layer, QgsMapLayer)
        ]
        map_extent_option = map_el.get('extent')
        composer_map = composition_item(composition, item_id, QgsComposerMap)

        for index, layer in enumerate(layers):
            # we need to check whether the layer is registered or not
            registered_layer = (
                QgsMapLayerRegistry.instance().mapLayer(layer.id()))
            if registered_layer:
                if not registered_layer == layer:
                    layers[index] = registered_layer
            else:
                QgsMapLayerRegistry.instance().addMapLayer(layer)

        """:type: qgis.core.QgsComposerMap"""
        if composer_map:

            # Search for specified map extent in the template.
            min_x = composer_map.extent().xMinimum() if (
                impact_report.use_template_extent) else None
            min_y = composer_map.extent().yMinimum() if (
                impact_report.use_template_extent) else None
            max_x = composer_map.extent().xMaximum() if (
                impact_report.use_template_extent) else None
            max_y = composer_map.extent().yMaximum() if (
                impact_report.use_template_extent) else None

            composer_map.setKeepLayerSet(True)
            layer_set = [l.id() for l in layers if isinstance(l, QgsMapLayer)]
            composer_map.setLayerSet(layer_set)
            map_overview_extent = None
            if map_extent_option and isinstance(
                    map_extent_option, QgsRectangle):
                # use provided map extent
                extent = coord_transform.transform(map_extent_option)
                for l in [layer for layer in layers if
                          isinstance(layer, QgsMapLayer)]:
                    layer_extent = coord_transform.transform(l.extent())
                    if l.name() == map_overview['id']:
                        map_overview_extent = layer_extent
            else:
                # if map extent not provided, try to calculate extent
                # from list of given layers. Combine it so all layers were
                # shown properly
                extent = QgsRectangle()
                extent.setMinimal()
                for l in [layer for layer in layers if
                          isinstance(layer, QgsMapLayer)]:
                    # combine extent if different layer is provided.
                    layer_extent = coord_transform.transform(l.extent())
                    extent.combineExtentWith(layer_extent)
                    if l.name() == map_overview['id']:
                        map_overview_extent = layer_extent

            width = extent.width()
            height = extent.height()
            longest_width = width if width > height else height
            half_length = longest_width / 2
            margin = half_length / 5
            center = extent.center()
            min_x = min_x or (center.x() - half_length - margin)
            max_x = max_x or (center.x() + half_length + margin)
            min_y = min_y or (center.y() - half_length - margin)
            max_y = max_y or (center.y() + half_length + margin)

            # noinspection PyCallingNonCallable
            square_extent = QgsRectangle(min_x, min_y, max_x, max_y)

            if component.key == 'population-infographic' and (
                    map_overview_extent):
                square_extent = map_overview_extent

            composer_map.zoomToExtent(square_extent)
            composer_map.renderModeUpdateCachedImage()

            actual_extent = composer_map.extent()

            # calculate intervals for grid
            x_interval = actual_extent.width() / split_count
            composer_map.grid().setIntervalX(x_interval)
            y_interval = actual_extent.height() / split_count
            composer_map.grid().setIntervalY(y_interval)

    # calculate legend element
    for leg_el in context.map_legends:
        item_id = leg_el.get('id')
        title = leg_el.get('title')
        layers = [
            layer for layer in leg_el.get('layers') if isinstance(
                layer, QgsMapLayer)
        ]
        symbol_count = leg_el.get('symbol_count')
        column_count = leg_el.get('column_count')

        legend = composition_item(composition, item_id, QgsComposerLegend)
        """:type: qgis.core.QgsComposerLegend"""
        if legend:
            # set column count
            if column_count:
                legend.setColumnCount(column_count)
            elif symbol_count <= 7:
                legend.setColumnCount(1)
            else:
                legend.setColumnCount(symbol_count / 7 + 1)

            # set legend title
            if title is not None and not impact_report.legend_layers:
                legend.setTitle(title)

            # set legend
            root_group = legend.modelV2().rootGroup()
            for layer in layers:
                # we need to check whether the layer is registered or not
                registered_layer = (
                    QgsMapLayerRegistry.instance().mapLayer(layer.id()))
                if registered_layer:
                    if not registered_layer == layer:
                        layer = registered_layer
                else:
                    QgsMapLayerRegistry.instance().addMapLayer(layer)
                # used for customizations
                tree_layer = root_group.addLayer(layer)
                if impact_report.legend_layers or (
                        not impact_report.multi_exposure_impact_function):
                    QgsLegendRenderer.setNodeLegendStyle(
                        tree_layer, QgsComposerLegendStyle.Hidden)
            legend.synchronizeWithModel()

    # process to output

    # in case output folder not specified
    if impact_report.output_folder is None:
        impact_report.output_folder = mkdtemp(dir=temp_dir())

    output_format = component.output_format
    component_output_path = impact_report.component_absolute_output_path(
        component.key)
    component_output = None

    doc_format = QgisComposerComponentsMetadata.OutputFormat.DOC_OUTPUT
    template_format = QgisComposerComponentsMetadata.OutputFormat.QPT
    if isinstance(output_format, list):
        component_output = []
        for i in range(len(output_format)):
            each_format = output_format[i]
            each_path = component_output_path[i]

            if each_format in doc_format:
                result_path = create_qgis_pdf_output(
                    impact_report,
                    each_path,
                    composition,
                    each_format,
                    component)
                component_output.append(result_path)
            elif each_format == template_format:
                result_path = create_qgis_template_output(
                    each_path, composition)
                component_output.append(result_path)
    elif isinstance(output_format, dict):
        component_output = {}
        for key, each_format in output_format.iteritems():
            each_path = component_output_path[key]

            if each_format in doc_format:
                result_path = create_qgis_pdf_output(
                    impact_report,
                    each_path,
                    composition,
                    each_format,
                    component)
                component_output[key] = result_path
            elif each_format == template_format:
                result_path = create_qgis_template_output(
                    each_path, composition)
                component_output[key] = result_path
    elif (output_format in
            QgisComposerComponentsMetadata.OutputFormat.SUPPORTED_OUTPUT):
        component_output = None

        if output_format in doc_format:
            result_path = create_qgis_pdf_output(
                impact_report,
                component_output_path,
                composition,
                output_format,
                component)
            component_output = result_path
        elif output_format == template_format:
            result_path = create_qgis_template_output(
                component_output_path, composition)
            component_output = result_path

    component.output = component_output

    return component.output
Пример #25
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"
Пример #26
0
    def print_impact_table(self, output_path):
        """Pint summary from impact layer to PDF.

        ..note:: The order of the report:
            1. Summary table
            2. Aggregation table
            3. Attribution table

        :param output_path: Output path.
        :type output_path: str

        :return: Path to generated pdf file.
        :rtype: str

        :raises: None
        """
        keywords = self._keyword_io.read_keywords(self.layer)

        if output_path is None:
            output_path = unique_filename(suffix='.pdf', dir=temp_dir())

        try:
            impact_template = get_report_template(self.layer.source())
            summary_table = impact_template.generate_html_report()
        except:
            summary_table = keywords.get('impact_summary', None)
        full_table = keywords.get('impact_table', None)
        aggregation_table = keywords.get('postprocessing_report', None)
        attribution_table = impact_attribution(keywords)

        # (AG) We will not use impact_table as most of the IF use that as:
        # impact_table = impact_summary + some information intended to be
        # shown on screen (see FloodOsmBuilding)
        # Unless the impact_summary is None, we will use impact_table as the
        # alternative
        html = m.Brand().to_html()
        html += m.Heading(tr('Analysis Results'), **INFO_STYLE).to_html()
        if summary_table is None:
            html += full_table
        else:
            html += summary_table

        if aggregation_table is not None:
            html += aggregation_table

        if attribution_table is not None:
            html += attribution_table.to_html()

        html = html_header() + html + html_footer()

        # Print HTML using composition
        # For QGIS < 2.4 compatibility
        # QgsMapSettings is added in 2.4
        if qgis_version() < 20400:
            map_settings = QgsMapRenderer()
        else:
            map_settings = QgsMapSettings()

        # A4 Portrait
        # TODO: Will break when we try to use larger print layouts TS
        paper_width = 210
        paper_height = 297

        # noinspection PyCallingNonCallable
        composition = QgsComposition(map_settings)
        # noinspection PyUnresolvedReferences
        composition.setPlotStyle(QgsComposition.Print)
        composition.setPaperSize(paper_width, paper_height)
        composition.setPrintResolution(300)

        # Add HTML Frame
        # noinspection PyCallingNonCallable
        html_item = QgsComposerHtml(composition, False)
        margin_left = 10
        margin_top = 10

        # noinspection PyCallingNonCallable
        html_frame = QgsComposerFrame(
            composition,
            html_item,
            margin_left,
            margin_top,
            paper_width - 2 * margin_left,
            paper_height - 2 * margin_top)
        html_item.addFrame(html_frame)

        # Set HTML
        # From QGIS 2.6, we can set composer HTML with manual HTML
        if qgis_version() < 20600:
            html_path = unique_filename(
                prefix='report', suffix='.html', dir=temp_dir())
            html_to_file(html, file_path=html_path)
            html_url = QUrl.fromLocalFile(html_path)
            html_item.setUrl(html_url)
        else:
            # noinspection PyUnresolvedReferences
            html_item.setContentMode(QgsComposerHtml.ManualHtml)
            # noinspection PyUnresolvedReferences
            html_item.setResizeMode(QgsComposerHtml.RepeatUntilFinished)
            html_item.setHtml(html)
            # RMN: This line below breaks in InaSAFE Headless after one
            # successful call. This is because the function is not
            # thread safe. Can't do anything about this, so avoid calling this
            # function in multithreaded way.
            html_item.loadHtml()

        composition.exportAsPDF(output_path)
        return output_path
Пример #27
0
 def setUp(self):
     """Run before each test."""
     self.iface = get_iface()
     self.mapSettings = QgsMapSettings()
     self.mComposition = QgsComposition(QgsProject.instance())
     self.mComposition.setPaperSize(297, 210)  # A4 landscape
Пример #28
0
    def composer(self, setData, flag=True):
        paperWidth = setData["Width"]
        paperHeight = setData["Height"]
        mapRenderer = define._canvas.mapRenderer()
        #         comp = None
        comp = QgsComposition(mapRenderer)
        comp.setPlotStyle(QgsComposition.Print)

        comp.setPaperSize(paperWidth, paperHeight)
        # rectangleAll = QgsComposerShape(comp)
        # rectangleAll.setItemPosition(3, 3, paperWidth - 3, paperHeight - 3)
        # rectangleAll.setShapeType(1)
        # comp.addItem(rectangleAll)

        self.txt1 = QgsComposerLabel(comp)
        self.txt1.setItemPosition(20, 20)
        self.txt1.setFrameEnabled(False)
        font = QFont("Arial", 10)
        self.txt1.setFont(font)
        self.txt1.setText(setData["TextData"][0])
        self.txt1.adjustSizeToText()
        comp.addItem(self.txt1)

        self.txt2 = QgsComposerLabel(comp)
        self.txt2.setItemPosition(int(paperWidth / 2) + 10, 20)
        self.txt2.setFrameEnabled(False)
        font = QFont("Arial", 10)
        self.txt2.setFont(font)
        self.txt2.setText(setData["TextData"][1])
        self.txt2.adjustSizeToText()
        comp.addItem(self.txt2)

        self.txt3 = QgsComposerLabel(comp)
        self.txt3.setItemPosition(paperWidth - 40, 20)
        self.txt3.setFrameEnabled(False)
        font = QFont("Arial", 10)
        self.txt3.setFont(font)
        self.txt3.setText(setData["TextData"][2])
        self.txt3.adjustSizeToText()
        comp.addItem(self.txt3)

        w = int((paperWidth - 40) / 4)

        self.txt4 = QgsComposerLabel(comp)
        self.txt4.setItemPosition(20, 35)
        self.txt4.setFrameEnabled(False)
        font = QFont("Arial", 10)
        self.txt4.setFont(font)
        self.txt4.setText(setData["TextData"][3])
        self.txt4.adjustSizeToText()
        comp.addItem(self.txt4)

        self.txt5 = QgsComposerLabel(comp)
        self.txt5.setItemPosition(20 + w, 35)
        self.txt5.setFrameEnabled(False)
        font = QFont("Arial", 10)
        self.txt5.setFont(font)
        self.txt5.setText(setData["TextData"][4])
        self.txt5.adjustSizeToText()
        comp.addItem(self.txt5)

        self.txt6 = QgsComposerLabel(comp)
        self.txt6.setItemPosition(20 + w * 2, 35)
        self.txt6.setFrameEnabled(False)
        font = QFont("Arial", 10)
        self.txt6.setFont(font)
        self.txt6.setText(setData["TextData"][5])
        self.txt6.adjustSizeToText()
        comp.addItem(self.txt6)

        self.txt7 = QgsComposerLabel(comp)
        self.txt7.setItemPosition(20 + w * 3, 35)
        self.txt7.setFrameEnabled(False)
        font = QFont("Arial", 10)
        self.txt7.setFont(font)
        self.txt7.setText(setData["TextData"][6])
        self.txt7.adjustSizeToText()
        comp.addItem(self.txt7)

        # if flag:
        x, y = 20, 45
        composerMap = QgsComposerMap(comp, x, y, paperWidth - 40, 150)
        #         composerMap.setPreviewMode(QgsComposerMap.Render)
        #         composerMap.setGridEnabled(False)

        #rect = composerMap.currentMapExtent ()
        renderer = composerMap.mapRenderer()
        newExtent = renderer.extent()

        #Make sure the width/height ratio is the same as in current composer map extent.
        #This is to keep the map item frame and the page layout fixed
        currentMapExtent = composerMap.currentMapExtent()
        currentWidthHeightRatio = currentMapExtent.width(
        ) / currentMapExtent.height()
        newWidthHeightRatio = newExtent.width() / newExtent.height()

        if currentWidthHeightRatio < newWidthHeightRatio:
            #enlarge height of new extent, ensuring the map center stays the same
            newHeight = newExtent.width() / currentWidthHeightRatio
            deltaHeight = newHeight - newExtent.height()
            newExtent.setYMinimum(newExtent.yMinimum() - deltaHeight / 2)
            newExtent.setYMaximum(newExtent.yMaximum() + deltaHeight / 2)

        else:
            #enlarge width of new extent, ensuring the map center stays the same
            newWidth = currentWidthHeightRatio * newExtent.height()
            deltaWidth = newWidth - newExtent.width()
            newExtent.setXMinimum(newExtent.xMinimum() - deltaWidth / 2)
            newExtent.setXMaximum(newExtent.xMaximum() + deltaWidth / 2)

        composerMap.beginCommand("Map extent changed")
        composerMap.setNewExtent(newExtent)
        composerMap.endCommand()
        # composerMap.setNewScale(3500)

        composerMap.setFrameEnabled(True)
        composerMap.setFrameOutlineWidth(1.0)
        composerMap.setPreviewMode(QgsComposerMap.Render)
        composerMap.updateCachedImage()

        composerMap.setGridEnabled(True)
        composerMap.setGridPenColor(QColor(255, 255, 255, 0))
        composerMap.setGridPenWidth(0.0)
        #composerMap.setGridStyle(QgsComposerMap.FrameAnnotationsOnly)
        composerMap.setGridIntervalX(1.0)
        composerMap.setGridIntervalY(1.0)
        #         mySymbol1 = composerMap.gridLineSymbol ()
        #         mySymbol1.setAlpha(0)
        #composerMap.setGridLineSymbol(mySymbol1)
        composerMap.setShowGridAnnotation(True)
        composerMap.setGridAnnotationFormat(1)
        composerMap.setGridAnnotationPrecision(0)
        composerMap.setGridAnnotationDirection(1, 0)
        composerMap.setGridAnnotationDirection(1, 1)

        comp.addItem(composerMap)

        w = int((paperWidth - 40) / 3)

        self.txt8 = QgsComposerLabel(comp)
        self.txt8.setItemPosition(20, 225)
        self.txt8.setFrameEnabled(False)
        font = QFont("Arial", 10)
        self.txt8.setFont(font)
        self.txt8.setText(setData["TextData"][7])
        self.txt8.adjustSizeToText()
        comp.addItem(self.txt8)

        self.txt9 = QgsComposerLabel(comp)
        self.txt9.setItemPosition(20 + w, 225)
        self.txt9.setFrameEnabled(False)
        font = QFont("Arial", 10)
        self.txt9.setFont(font)
        self.txt9.setText(setData["TextData"][8])
        self.txt9.adjustSizeToText()
        comp.addItem(self.txt9)

        self.txt10 = QgsComposerLabel(comp)
        self.txt10.setItemPosition(20 + w * 2, 225)
        self.txt10.setFrameEnabled(False)
        font = QFont("Arial", 10)
        self.txt10.setFont(font)
        self.txt10.setText(setData["TextData"][9])
        self.txt10.adjustSizeToText()
        comp.addItem(self.txt10)

        # profileRect = QgsComposerPicture(comp)
        # profileRect.setItemPosition(20, 200, paperWidth - 40, 50)
        # comp.addItem(profileRect)

        self.txt11 = QgsComposerLabel(comp)
        self.txt11.setItemPosition(20, paperHeight - 30)
        self.txt11.setFrameEnabled(False)
        font = QFont("Arial", 10)
        self.txt11.setFont(font)
        self.txt11.setText(setData["TextData"][10])
        self.txt11.adjustSizeToText()
        comp.addItem(self.txt11)

        self.txt12 = QgsComposerLabel(comp)
        self.txt12.setItemPosition(20 + w, paperHeight - 30)
        self.txt12.setFrameEnabled(False)
        font = QFont("Arial", 10)
        self.txt12.setFont(font)
        self.txt12.setText(setData["TextData"][11])
        self.txt12.adjustSizeToText()
        comp.addItem(self.txt12)

        self.txt13 = QgsComposerLabel(comp)
        self.txt13.setItemPosition(20 + w * 2, paperHeight - 30)
        self.txt13.setFrameEnabled(False)
        font = QFont("Arial", 10)
        self.txt13.setFont(font)
        self.txt13.setText(setData["TextData"][12])
        self.txt13.adjustSizeToText()
        comp.addItem(self.txt13)

        # gpw = QGraphicsProxyWidget()
        self.tblView = QTableView()
        tableHeight = None
        tableWidth = None
        if self.tableChangedValue == None:
            self.tblView.setFixedWidth(paperWidth - 40)
            tableHeight = 50
            tableWidth = paperWidth - 40
            self.tblView.setFixedHeight(tableHeight)
        else:
            self.tblView.setFixedWidth(self.tableChangedValue["Width"])
            self.tblView.setFixedHeight(self.tableChangedValue["Height"])
            tableHeight = self.tableChangedValue["Height"]
            tableWidth = self.tableChangedValue["Width"]
        self.tblView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.tblView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        hHeder = self.tblView.horizontalHeader()
        hHeder.setVisible(False)
        vHeder = self.tblView.verticalHeader()
        vHeder.setVisible(False)

        # if flag:
        self.stdModel = QStandardItemModel()
        self.data.__setitem__("TableWidth", tableWidth)
        self.data.__setitem__("TableHeight", tableHeight)
        self.setTableView(self.tblView, self.stdModel, self.data)

        self.calcALT()
        self.calcTimeRate()

        self.gpw = QGraphicsProxyWidget()
        self.gpw.setWidget(self.tblView)
        # gpw.setWidget(tblView)
        if self.tableChangedValue == None:
            self.gpw.setPos(20, 210)
            font = QFont()
            font.setPixelSize(2)
            self.gpw.setFont(font)
        else:
            self.gpw.setPos(self.tableChangedValue["X"],
                            self.tableChangedValue["Y"])
            font = QFont()
            font.setPixelSize(self.tableChangedValue["FontSize"])
            self.gpw.setFont(font)

        # tblView.setFrameRect(QRect(20, 210, paperWidth - 40, 50))
        comp.addItem(self.gpw)

        self.connect(self.stdModel, SIGNAL("itemChanged(QStandardItem *)"),
                     self.stdModel_itemChanged)
        return comp
Пример #29
0
 def setUp(self):
     """Run before each test."""
     self.mComposition = QgsComposition(None)
     self.mComposition.setPaperSize(297, 210) #A4 landscape
    def print_atlas(self,
                    project_path,
                    composer_name,
                    predefined_scales,
                    feature_filter=None,
                    page_name_expression=None):

        if not feature_filter:
            QgsMessageLog.logMessage(
                "atlasprint: NO feature_filter provided !")
            return None

        # Get composer from project
        # in QGIS 2, canno get composers without iface
        # so we reading project xml and extract composer
        # in QGIS 3.0, we will use  project layoutManager()
        from xml.etree import ElementTree as ET
        composer_xml = None
        with open(project_path, 'r') as f:
            tree = ET.parse(f)
            for elem in tree.findall('.//Composer[@title="%s"]' %
                                     composer_name):
                composer_xml = ET.tostring(elem, encoding='utf8', method='xml')

        if not composer_xml:
            QgsMessageLog.logMessage("atlasprint: Composer XML not parsed !")
            return None

        document = QDomDocument()
        document.setContent(composer_xml)

        # Get canvas, map setting & instantiate composition
        canvas = QgsMapCanvas()
        QgsProject.instance().read(QFileInfo(project_path))
        bridge = QgsLayerTreeMapCanvasBridge(
            QgsProject.instance().layerTreeRoot(), canvas)
        bridge.setCanvasLayers()
        ms = canvas.mapSettings()
        composition = QgsComposition(ms)

        # Load content from XML
        substitution_map = {}
        composition.loadFromTemplate(document, substitution_map)

        # Get atlas for this composition
        atlas = composition.atlasComposition()
        atlas.setEnabled(True)

        atlas_map = composition.getComposerMapById(0)
        atlas_map.setAtlasScalingMode(QgsComposerMap.Predefined)

        # get project scales
        atlas.setPredefinedScales(predefined_scales)
        atlas_map.setAtlasDriven(True)
        #atlas.setComposerMap(atlas_map)

        if page_name_expression:
            atlas.setPageNameExpression(page_name_expression)

        # Filter feature here to avoid QGIS looping through every feature when doing : composition.setAtlasMode(QgsComposition.ExportAtlas)
        coverageLayer = atlas.coverageLayer()

        # Filter by FID as QGIS cannot compile expressions with $id or other $ vars
        # which leads to bad perfs for big datasets
        useFid = None
        if '$id' in feature_filter:
            import re
            ids = map(int, re.findall(r'\d+', feature_filter))
            if len(ids) > 0:
                useFid = ids[0]
        if useFid:
            qReq = QgsFeatureRequest().setFilterFid(useFid)
        else:
            qReq = QgsFeatureRequest().setFilterExpression(feature_filter)

        # Change feature_filter in order to improve perfs
        pks = coverageLayer.dataProvider().pkAttributeIndexes()
        if useFid and len(pks) == 1:
            pk = coverageLayer.dataProvider().fields()[pks[0]].name()
            feature_filter = '"%s" IN (%s)' % (pk, useFid)
            QgsMessageLog.logMessage(
                "atlasprint: feature_filter changed into: %s" % feature_filter)
            qReq = QgsFeatureRequest().setFilterExpression(feature_filter)
        atlas.setFilterFeatures(True)
        atlas.setFeatureFilter(feature_filter)
        uid = uuid4()
        i = 0

        # Set Atlas mode
        composition.setAtlasMode(QgsComposition.ExportAtlas)
        atlas.beginRender()

        for feat in coverageLayer.getFeatures(qReq):
            atlas.prepareForFeature(feat)
            export_path = os.path.join(
                tempfile.gettempdir(),
                '%s_%s.pdf' % (atlas.nameForPage(i), uid))
            exported = composition.exportAsPDF(export_path)
            if not exported or not os.path.isfile(export_path):
                QgsMessageLog.logMessage(
                    "atlasprint: An error occured while exporting the atlas !")
                return None

            break

        atlas.endRender()

        if os.path.isfile(export_path):
            QgsMessageLog.logMessage("atlasprint: path generated %s" %
                                     export_path)
        return export_path