def create_layout_from_template(template_filename): layout = QgsPrintLayout(QgsProject().instance()) document = QDomDocument() with open(os.path.join('data', 'general', template_filename)) as template_file: template_content = template_file.read() document.setContent(template_content) layout.loadFromTemplate(document, QgsReadWriteContext()) return layout
def export_view(self): """ Export current view to PDF """ # Load template from file s = QSettings() f = s.value("cadastre/composerTemplateFile", '', type=str) if not os.path.exists(f): f = os.path.join(str(Path(__file__).resolve().parent), 'composers', 'paysage_a4.qpt') s.setValue("cadastre/composerTemplateFile", f) QApplication.setOverrideCursor(Qt.WaitCursor) template_content = None with open(f, 'rt', encoding="utf-8") as ff: template_content = ff.read() if not template_content: return d = QDomDocument() d.setContent(template_content) c = QgsPrintLayout(QgsProject.instance()) c.loadFromTemplate(d, QgsReadWriteContext()) # Set scale and extent cm = c.referenceMap() canvas = self.iface.mapCanvas() extent = canvas.extent() scale = canvas.scale() if extent: cm.zoomToExtent(extent) if scale: cm.setScale(scale) # Export tempDir = s.value("cadastre/tempDir", '%s' % tempfile.gettempdir(), type=str) self.targetDir = tempfile.mkdtemp('', 'cad_export_', tempDir) temp = int(time() * 100) temppath = os.path.join(tempDir, 'export_cadastre_%s.pdf' % temp) exporter = QgsLayoutExporter(c) exportersettings = QgsLayoutExporter.PdfExportSettings() exportersettings.dpi = 300 exportersettings.forceVectorOutput = True exportersettings.rasterizeWholeImage = False # rasterizeWholeImage = false exporter.exportToPdf(temppath, exportersettings) QApplication.restoreOverrideCursor() if os.path.exists(temppath): CadastreCommon.openFile(temppath)
def layoutLoader(self, template_source, layout_name, title_text): """ Generate the layout """ from qgis.core import (QgsProject, QgsPrintLayout, QgsReadWriteContext) from qgis.utils import iface from PyQt5.QtXml import QDomDocument #template_source = '/home/user/Document/Template.qpt' #layout_name = 'NewLayout' #title_text = 'New Title' # Create objects lm = layout manager, l = print layout lm = QgsProject.instance().layoutManager() l = QgsPrintLayout(QgsProject.instance()) l.initializeDefaults() # Load template file and load it into the layout (l) template_file = open(template_source, 'r+', encoding='utf-8') template_content = template_file.read() template_file.close() document = QDomDocument() document.setContent(template_content) context = QgsReadWriteContext() l.loadFromTemplate(document, context) # Give the layout a name (must be unique) l.setName(layout_name) # Get current canvas extent and apply that to all maps (items) in layout # Replace any text "{{title}}" in any layout label with the dialog Title text canvas = iface.mapCanvas() for item in l.items(): if item.type() == 65639: # Map item.zoomToExtent(canvas.extent()) if item.type() == 65641: # Label item.setText(item.text().replace('{{title}}', title_text)) # Add layout to layout manager l.refresh() lm.addLayout(l) # Open and show the layout in designer try: iface.openLayoutDesigner(l) except: oopsBox = QMessageBox() oopsBox.setIcon(QMessageBox.Warning) oopsBox.setText( self. tr('Ooops. Something went wrong. Trying to open the generated layout ({}) returned errors.' .format(l.name()))) oopsBox.setWindowTitle(self.tr('Layout Loader')) oopsBox.exec_()
def export_view(self): ''' Export current view to PDF ''' # Load template from file s = QSettings() f = s.value("cadastre/composerTemplateFile", '', type=str) if not os.path.exists(f): f = os.path.join(str(Path(__file__).resolve().parent), 'composers', 'paysage_a4.qpt') s.setValue("cadastre/composerTemplateFile", f) QApplication.setOverrideCursor(Qt.WaitCursor) template_content = None with open(f, 'rt', encoding="utf-8") as ff: template_content = ff.read() if not template_content: return d = QDomDocument() d.setContent(template_content) c = QgsPrintLayout(QgsProject.instance()) c.loadFromTemplate(d, QgsReadWriteContext() ) # Set scale and extent cm=c.referenceMap() canvas = self.iface.mapCanvas() extent = canvas.extent() scale = canvas.scale() if extent: cm.zoomToExtent(extent) if scale: cm.setScale(scale) # Export tempDir = s.value("cadastre/tempDir", '%s' % tempfile.gettempdir(), type=str) self.targetDir = tempfile.mkdtemp('', 'cad_export_', tempDir) temp = int(time()*100) temppath = os.path.join(tempDir, 'export_cadastre_%s.pdf' % temp) exporter = QgsLayoutExporter(c) exportersettings = QgsLayoutExporter.PdfExportSettings() exportersettings.dpi = 300 exportersettings.forceVectorOutput = True exportersettings.rasterizeWholeImage = False #rasterizeWholeImage = false exporter.exportToPdf(temppath, exportersettings ) QApplication.restoreOverrideCursor() if os.path.exists(temppath): cadastre_common.openFile(temppath)
def getPrintLayoutFromQptPath(self, path, newValue): ''' Returns a QgsPrintLayout from a template indicated by path. Also sets the composition variable 'variableNames' to newvalue ''' # Load template from file layout = QgsPrintLayout(QgsProject.instance()) # self.updateQptVariables(layout, newValue) # layout.initializeDefaults() with open(path) as template: templateContent = template.read() doc = QDomDocument() doc.setContent(templateContent) # adding to existing items #items, ok = layout.loadFromTemplate(doc, QgsReadWriteContext(), False) layout.loadFromTemplate(doc, QgsReadWriteContext()) self.updateQptVariables(layout, str(newValue)) return layout
class ProductExporter(object): def __init__(self): self.layout = QgsPrintLayout(QgsProject.instance()) def populateTemplate(self, templateXMLContent): templateDomDoc = QDomDocument() templateDomDoc.setContent(templateXMLContent) #TODO: Adicionar um parser para o XML para substituir # informações pertinentes, como por exemplo, id da # camada de atlas. self.layout.loadFromTemplate(templateDomDoc, QgsReadWriteContext()) def export(self, parameterDict): pass def exportPdf(self, outputPath, feedback=None): exporter = QgsLayoutExporter(self.layout) result, error = exporter.exportToPdfs( self.layout.atlas(), outputPath, settings=QgsLayoutExporter.PdfExportSettings(), feedback=feedback) return result, error def exportTiff(self): pass def generateProductionStepsHTML(self, parameterDict): """ Para gerar a tabela de etapas de produção. Nos parâmetros deve vir a ordem de supressão caso seja necessário. """ pass def exportPopulatedQPT(self, parameterDict): """ easter egg """ pass
def get_print_layout(self): template_path = self.getTemplateFilePath() if not os.path.isfile(template_path): msg = 'The requested template {} is not currently available.'.format( template_path) QMessageBox.critical(self.iface.mainWindow(), 'Template Not Found', msg) return # Create a new print layout with name equal to the project title project = QgsProject.instance() layout_manager = project.layoutManager() user_layout_title = self.ui.titleLineEdit.text() layout_title = user_layout_title if user_layout_title else "unnamed" existing_print_layout = layout_manager.layoutByName( layout_title) if layout_title else None if existing_print_layout: layout_manager.removeLayout(existing_print_layout) print_layout = QgsPrintLayout(project) # Load the template file try: tree = ET.parse(template_path) doc = QDomDocument() doc.setContent(ET.tostring(tree.getroot())) except IOError: # problem reading xml template msg = 'The requested template {} could not be read.'.format( template_path) QMessageBox.critical(self.iface.mainWindow(), 'Failed to Read Template', msg) return except: # Unexpected problem msg = 'An unexpected error occurred while reading {}:\n\n{}'.format( template_path, traceback.format_exc()) QMessageBox.critical(self.iface.mainWindow(), 'Failed to Read Template', msg) return if not print_layout.loadFromTemplate(doc, QgsReadWriteContext(), True): msg = 'loadFromTemplate returned False.' QMessageBox.critical(self.iface.mainWindow(), 'Failed to Read Template', msg) return print_layout.setName(layout_title) return print_layout
def open_template(layout: QgsPrintLayout, fp: str): '''Load items from template into layout''' logging.info(f'opening template: {fp}') doc = QDomDocument() context = QgsReadWriteContext() # read template with open(fp, 'rt', encoding='utf-8') as f: content = f.read() # set content and load items from template doc.setContent(content) _, ok = layout.loadFromTemplate(doc, context) if not ok: raise baseException(f'failed to load QGS template: {fp}', baseException.ERR_CODE_LEVEL)
def open_in_composer(self): """Open in layout designer a given MapReport instance. .. versionadded: 4.3.0 """ impact_layer = self.impact_function.analysis_impacted report_path = dirname(impact_layer.source()) impact_report = self.impact_function.impact_report custom_map_report_metadata = impact_report.metadata custom_map_report_product = ( custom_map_report_metadata.component_by_tags( [final_product_tag, pdf_product_tag])) for template_path in self.retrieve_paths( custom_map_report_product, report_path=report_path, suffix='.qpt'): layout = QgsPrintLayout(QgsProject.instance()) with open(template_path) as template_file: template_content = template_file.read() document = QtXml.QDomDocument() document.setContent(template_content) # load layout object rwcontext = QgsReadWriteContext() load_status = layout.loadFromTemplate(document, rwcontext) if not load_status: # noinspection PyCallByClass,PyTypeChecker QtWidgets.QMessageBox.warning( self, tr('InaSAFE'), tr('Error loading template: %s') % template_path) return QgsProject.instance().layoutManager().addLayout(layout) self.iface.openLayoutDesigner(layout)
def get_print_layout(self): template_path = self.getTemplateFilePath() if not os.path.isfile(template_path): msg = 'The requested template {} is not currently available.'.format(template_path) QMessageBox.critical(self.iface.mainWindow(), 'Template Not Found', msg) return # Create a new print layout with name equal to the project title project = QgsProject.instance() layout_manager = project.layoutManager() existing_print_layout = layout_manager.layoutByName(self.ui.titleLineEdit.text()) if existing_print_layout: layout_manager.removeLayout(existing_print_layout) print_layout = QgsPrintLayout(project) print_layout.setName(self.ui.titleLineEdit.text()) layout_manager.addLayout(print_layout) # Load the template file try: tree = ET.parse(template_path) doc = QDomDocument() doc.setContent(ET.tostring(tree.getroot())) except IOError: # problem reading xml template msg = 'The requested template {} could not be read.'.format(template_path) QMessageBox.critical(self.iface.mainWindow(), 'Failed to Read Template', msg) return except: # Unexpected problem msg = 'An unexpected error occurred while reading {}:\n\n{}'.format(template_path, traceback.format_exc()) QMessageBox.critical(self.iface.mainWindow(), 'Failed to Read Template', msg) return if not print_layout.loadFromTemplate(doc, QgsReadWriteContext(), True): msg = 'loadFromTemplate returned False.' QMessageBox.critical(self.iface.mainWindow(), 'Failed to Read Template', msg) return return print_layout
def createLayout(self): print(u'createLayout()') templateFile = self.createLayoutDialog.comboBoxTemplate.currentText() templateQpt = os.path.join(self.dataPath, templateFile) layoutName = self.createLayoutDialog.lineEditName.text() project = QgsProject.instance() layoutManager = project.layoutManager() oldLayout = layoutManager.layoutByName(layoutName) if oldLayout is not None: print(u'removing: {}'.format(oldLayout)) layoutManager.removeLayout(oldLayout) # create new layout layout = QgsPrintLayout(project) # load layout template fl = QFile(templateQpt) doc = QDomDocument() doc.setContent(fl) layout.loadFromTemplate(doc, QgsReadWriteContext()) # set name layout.setName(layoutName) # set map properties map = self.getItemById(layout, u'RC_map') if map is not None: #print(map.crs().description()) map.zoomToExtent(self.iface.mapCanvas().extent()) # set default label values for configurationItem in simsLayoutConfiguration: label = self.getItemById(layout, configurationItem['code']) if label is not None and isinstance(label, QgsLayoutItemLabel): if configurationItem['default'] is not None: label.setText(configurationItem['default']) # set overview map map = self.getItemById(layout, u'RC_overview') if map is not None: worldLayer = self.addWorldLayer() map.setFollowVisibilityPreset(False) map.setKeepLayerSet(True) map.setLayers([worldLayer]) overviewCrs = QgsCoordinateReferenceSystem("EPSG:54030") map.setCrs(overviewCrs) extent = worldLayer.extent() layerCrs = worldLayer.sourceCrs() if not layerCrs == overviewCrs: transform = QgsCoordinateTransform(layerCrs, overviewCrs, QgsProject.instance()) extent = transform.transformBoundingBox(extent) map.zoomToExtent(extent) root = QgsProject.instance().layerTreeRoot() rl = root.findLayer(worldLayer.id()) rl.setItemVisibilityChecked(False) # set disclamer languageChoice = self.createLayoutDialog.comboBoxLanguage.currentText() label = self.getItemById(layout, u'RC_disclaimer') if label is not None: label.setText(simsDisclamers[languageChoice]) label = self.getItemById(layout, u'RC_logotext') if label is not None: label.setText(simsLogoTexts[languageChoice]) # set title label = self.getItemById(layout, u'RC_title') if label is not None: label.setText(self.createLayoutDialog.lineEditName.text()) # set Copyright # possibly dynamically: [%'© SIMS ' || year(now())%] ''' label = self.getItemById(layout, u'COPYRIGHT') if label is not None: print(label) label.setText(u'© SIMS {0}'.format(datetime.now().year)) # set filename label = self.getItemById(layout, u'FILENAME') if label is not None: print(label) filename = QgsProject.instance().fileName() if filename == u'': filename = u'filename unknown, project not saved' label.setText(filename) ''' # set NS logo picture = self.getItemById(layout, u'RC_logo1') if picture is not None: logoChoice = self.createLayoutDialog.comboBoxNsLogo.currentText() logoSvg = os.path.join(self.dataPath, u'logos', logoChoice) picture.setPicturePath(logoSvg) # set IFRC logo picture = self.getItemById(layout, u'RC_logo2') if picture is not None: logo = simsIfrcLogos[languageChoice] logoSvg = os.path.join(self.dataPath, u'img', logo) picture.setPicturePath(logoSvg) # set date label = self.getItemById(layout, u'RC_date') if label is not None: now = datetime.now() month = simsMonths[languageChoice][now.month] label.setText(now.strftime('%d {} %Y').format(month)) # set North Arrow picture = self.getItemById(layout, u'RC_northarrow') if picture is not None: logoSvg = os.path.join(QgsApplication.pkgDataPath(), u'svg', u'arrows', u'NorthArrow_02.svg') picture.setPicturePath(logoSvg) # clear default label values # add to project and open designer window layoutManager.addLayout(layout) designer = self.iface.openLayoutDesigner(layout)
class run(QObject): def __init__(self, id, gtotool, config, debug): super(run, self).__init__() try: self.debug = debug self.gtotool=gtotool self.gtomain = gtotool.gtomain self.info =gtotool.info self.metadata = self.gtomain.metadata templatedir = self.metadata.dirPrintLayouts self.iface = self.gtomain.iface #tool data template = config.get('template',None) activetool= config.get('active_tool',None) scale = config.get('scale',0) #init templatefile = None layoutname =config.get('layoutname', None) if template and layoutname is None: layoutname= os.path.splitext(template)[0]#default layoutname for template if self.debug:self.info.log("layoutname:",layoutname) prj = QgsProject.instance() projectLayoutManager = prj.layoutManager()#QgsLayoutManager self.layout = None if template is not None: templatefile = os.path.join(templatedir , template) if debug: self.info.log("template:",templatefile) if os.path.isfile(templatefile): f= open(templatefile, 'r') templateContent = f.read() f.close() doc=QDomDocument() doc.setContent(templateContent) pr = QgsPathResolver(templatefile) rwc = QgsReadWriteContext() rwc.setPathResolver(pr) self.layout = QgsPrintLayout(prj) self.layout.loadFromTemplate(doc,rwc) self.layout.setName(layoutname) projectLayoutManager.addLayout(self.layout) self.layout = projectLayoutManager.layoutByName(layoutname) if self.debug: self.info.log(type(self.layout)) if self.debug and self.layout:self.info.log("found layout:",self.layout.name()) if self.layout: result = self.iface.openLayoutDesigner(self.layout)#QgsLayoutDesignerInterface self.layoutview = result.view()#QgsLayoutView currenttool = self.layoutview.tool()#QgsLayoutViewTool if self.debug: self.info.log(currenttool.toolName()) if activetool: tool = QgsLayoutViewToolMoveItemContent(self.layoutview) self.layoutview.setTool(tool) #itemMap = QgsLayoutItemMap(self.layout) referencemap = self.layout.referenceMap() referencemap.zoomToExtent(self.iface.mapCanvas().extent()) if scale < 0: referencemap.setScale(self.iface.mapCanvas().scale()) elif scale > 0: referencemap.setScale(scale) referencemap.refresh() if activetool: menu = result.editMenu() for a in menu.actions(): if a.objectName() == activetool: if self.debug: self.info.log("set active tool:",activetool) a.trigger() break self.result = True else: self.result="Layout <%s> not found!" % layoutname except Exception as e: self.info.err(e)
def print_atlas(project_path, composer_name, predefined_scales, feature_filter, page_name_expression=None): if not feature_filter: QgsMessageLog.logMessage("atlasprint: NO feature_filter provided !", 'atlasprint', Qgis.Critical) return None # Get composer from project # in QGIS 2, we can't get composers without iface # so we reading project xml and extract composer # TODO Since QGIS 3.0, we should be able to use project layoutManager() # noinspection PyPep8Naming 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: for elem in tree.findall('.//Layout[@name="%s"]' % composer_name): composer_xml = ET.tostring( elem, encoding='utf8', method='xml' ) if not composer_xml: QgsMessageLog.logMessage("atlasprint: Composer XML not parsed !", 'atlasprint', Qgis.Critical) return None document = QDomDocument() document.setContent(composer_xml) # Get canvas, map setting & instantiate composition canvas = QgsMapCanvas() project = QgsProject() project.read(project_path) bridge = QgsLayerTreeMapCanvasBridge( project.layerTreeRoot(), canvas ) bridge.setCanvasLayers() layout = QgsPrintLayout(project) # Load content from XML layout.loadFromTemplate( document, QgsReadWriteContext(), ) atlas = layout.atlas() atlas.setEnabled(True) atlas_map = layout.referenceMap() atlas_map.setAtlasDriven(True) atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Predefined) layout.reportContext().setPredefinedScales(predefined_scales) 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) coverage_layer = atlas.coverageLayer() # Filter by FID as QGIS cannot compile expressions with $id or other $ vars # which leads to bad performance for big dataset use_fid = None if '$id' in feature_filter: import re ids = list(map(int, re.findall(r'\d+', feature_filter))) if len(ids) > 0: use_fid = ids[0] if use_fid: qReq = QgsFeatureRequest().setFilterFid(use_fid) else: qReq = QgsFeatureRequest().setFilterExpression(feature_filter) # Change feature_filter in order to improve performance pks = coverage_layer.dataProvider().pkAttributeIndexes() if use_fid and len(pks) == 1: pk = coverage_layer.dataProvider().fields()[pks[0]].name() feature_filter = '"%s" IN (%s)' % (pk, use_fid) QgsMessageLog.logMessage("atlasprint: feature_filter changed into: %s" % feature_filter, 'atlasprint', Qgis.Info) qReq = QgsFeatureRequest().setFilterExpression(feature_filter) atlas.setFilterFeatures(True) atlas.setFilterExpression(feature_filter) uid = uuid4() i = 0 # We use a single page for now. atlas.beginRender() atlas.seekTo(i) # setup settings settings = QgsLayoutExporter.PdfExportSettings() export_path = os.path.join( tempfile.gettempdir(), '%s_%s.pdf' % (atlas.nameForPage(i), uid) ) exporter = QgsLayoutExporter(layout) result = exporter.exportToPdf(export_path, settings) atlas.endRender() if result != QgsLayoutExporter.Success: QgsMessageLog.logMessage("atlasprint: export not generated %s" % export_path, 'atlasprint', Qgis.Critical) return None if not os.path.isfile(export_path): QgsMessageLog.logMessage("atlasprint: export not generated %s" % export_path, 'atlasprint', Qgis.Critical) return None QgsMessageLog.logMessage("atlasprint: path generated %s" % export_path, 'atlasprint', Qgis.Success) return export_path
class ScangisAtlas: def __init__(self, iface): self.iface = iface self.virtualLayerName = u'deelnemers_atlas' self.layoutName = u'Scangis Atlas' #print(__file__) self.pluginDir = os.path.dirname(__file__) #print(self.pluginDir) self.templateFile = os.path.join(self.pluginDir, u'data', u'a4.qpt') self.scangisStyle = os.path.join(self.pluginDir, u'data', u'pakketten_atlas_alz.qml') #print(self.templateFile) def initGui(self): self.action = QAction(u'Scangis Atlas', self.iface.mainWindow()) self.action.triggered.connect(self.run) self.iface.addToolBarIcon(self.action) def unload(self): self.iface.removeToolBarIcon(self.action) del self.action def run(self): project = QgsProject.instance() # set qml scangisLayer = self.iface.activeLayer() #print(scangisLayer.name()) scangisLayer.loadNamedStyle(self.scangisStyle) # delete existing deelnemers virtual layer oldLayers = project.mapLayersByName(self.virtualLayerName) for oldLayer in oldLayers: project.removeMapLayer(oldLayer.id()) # create new virtual layer query = u'?query=SELECT min(ID) AS ID, DEELN_NAAM, st_union(geometry) AS geometry FROM "{}" GROUP BY DEELN_NAAM'.format( scangisLayer.name()) virtualLayer = QgsVectorLayer(query, self.virtualLayerName, "virtual") project.addMapLayer(virtualLayer) ltr = QgsProject.instance().layerTreeRoot() rootLayer = ltr.findLayer(virtualLayer.id()) rootLayer.setItemVisibilityChecked(False) self.iface.mapCanvas().refreshAllLayers() # delete existing atlas layout layoutManager = project.layoutManager() #print(layoutManager) #print(layoutManager.layouts()) oldLayout = layoutManager.layoutByName(self.layoutName) if oldLayout is not None: layoutManager.removeLayout(oldLayout) # create new layout self.atlasLayout = QgsPrintLayout(project) # load layout template fl = QFile(self.templateFile) doc = QDomDocument() doc.setContent(fl) rw_context = QgsReadWriteContext() rw_context.setPathResolver(project.pathResolver()) self.atlasLayout.loadFromTemplate(doc, rw_context) # set name self.atlasLayout.setName(self.layoutName) # add to project layoutManager.addLayout(self.atlasLayout) # turn on atlas atl = self.atlasLayout.atlas() atl.setEnabled(True) atl.setCoverageLayer(virtualLayer) atl.setHideCoverage(True) itemId = u'map1' item = self.getLayoutItem(itemId, QgsLayoutItemMap) item.setAtlasDriven(True) # set title itemId = u'label_title' item = self.getLayoutItem(itemId, QgsLayoutItemLabel) #item.setText(u'[% attribute(@atlas_feature, \'DEELN_NAAM\') %]') item.setText(u'[% "DEELN_NAAM" %]') # set source info itemId = u'label_source' item = self.getLayoutItem(itemId, QgsLayoutItemLabel) exp = u"[% format_date(now(), 'dd-MM-yyyy (hh:mm:ss)') || '\\n' || 'pagina ' || @atlas_featurenumber || '/' || @atlas_totalfeatures %]" item.setText(exp) item.setHAlign(2) # right item.setVAlign(64) # bottom # set legend filter itemId = u'legend1' item = self.getLayoutItem(itemId, QgsLayoutItemLegend) #print(item) item.setLegendFilterByMapEnabled(True) #QMessageBox.information(None, u'Scangis Atlas', u'Atlas finished! :)') designer = self.iface.openLayoutDesigner(self.atlasLayout) # new in qgis 3.3 if qgis.utils.Qgis.QGIS_VERSION_INT >= 30300: designer.setAtlasPreviewEnabled(True) def getLayoutItem(self, itemId, itemType): item = self.atlasLayout.itemById(itemId) if item is None: #print(u'Layout does not contain item: \'{0}\''.format(itemId)) return None if not type(item) == u'qgis._core.{0}'.format(itemType.__name__): item = sip.cast(item, itemType) return item
def _load_print_layout(self, layer_name, prod_id, dt=None): window_title = "Print" # will be checked with a found composer title """ Avoid creating a new PrintComposer again and again here. Otherwise more and more composers will be added to the list - even with the same name. """ project = QgsProject.instance() # From it, you can get the current layoutManager instance and deduce the layouts layout_manager = project.layoutManager() layout = layout_manager.layoutByName(window_title) if not layout: self.out("no composer found; creating one...") # Load the template into the composer # QGIS 2: #active_composer = self.iface.createNewComposer(window_title) #createNewComposer() #active_composer = QgsComposition(QgsProject.instance()) #layout = QgsLayout(project) layout = QgsPrintLayout(project) layout.initializeDefaults() # initializes default settings for blank print layout canvas q_xmldoc = self._create_qdocument_from_print_template_content() # load layout from template and add to Layout Manager #layout.composition().loadFromTemplate(q_xmldoc) # QGIS 2 layout.loadFromTemplate(q_xmldoc, QgsReadWriteContext()) layout.setName(window_title) layout_manager.addLayout(layout) # Update Logo: #logo_item = layout.getComposerItemById('logo') # QGIS 2 logo_item = layout.itemById('logo') #self.out(">>> logo_item: '{}'".format(logo_item)) # gibt nur die Objekt-ID aus logo_image = self._model.logo_path self.out("Logo: {}".format(logo_image)) if logo_image.exists(): logo_item.setPicturePath(str(logo_image)) else: self.out(" ERROR: logo '{}' not found!".format(logo_image), False) # if """ Hier versuche ich ein für die Überschrift mit einer ID ('headline') versehenes QgsLabel aus dem Template ausfindig zu machen. Ich mache das hier sehr kompliziert, es gibt bestimmt einen einfacheren Weg. Folgendes hat NICHT funktioniert: map_item = active_composer.getComposerItemById('headline') print(active_composer.items()) liefert: [<PyQt4.QtGui.QGraphicsRectItem object at 0x124c60e8>, <qgis._core.QgsComposerLabel object at 0x124c65a8>, ... ] """ ''' other possibility: for item in list(layout.items()): #if type(item) != QgsComposerLabel: ''' # QgsComposerLabel: composer_label = layout.itemById('headline') # a QgsComposerLabel was provided with the ID 'headline' in the template # -> None if not found if composer_label: title = self._model.title(prod_id, dt) subtitle = "" if prod_id != 'RW': subtitle = "\n{}-Produkt (Basis: RW)".format(prod_id) composer_label.setText(title + subtitle) else: # A note that the template needs to be revised: self.out("no element with id 'headline' found!", False) legend = layout.itemById('legend') if not legend: self.out("legend couldn't created!", False) return # # Layer für die Legende ausfindig machen # # You would just need to make sure your layer has a name you can distinguish from others. Instead of: # Vorherige Version: #active_raster_layer = self.iface.activeLayer() # do: l_layer = project.mapLayersByName(layer_name) if not l_layer: self.out("legend: no layer found with name '{}'!".format(layer_name), False) return active_raster_layer = l_layer[0] #print("Legend active_raster_layer id:", active_raster_layer.id()) # ok #print("Legend active_raster_layer name:", active_raster_layer.name()) # ok #legend.model().setLayerSet([layer.id() for layer in layers]) #legend.model().setLayerSet([active_raster_layer.id()]) # bringt nichts # DAS ist es! Dies fügt zumindest erstmal das interessierende Rasterlayer hinzu: #legend.modelV2().rootGroup().addLayer(active_raster_layer) #legend.updateLegend() #for layout in layout_manager.printLayouts(): # iterate layouts ''' would be ok, if we want to create a new legend -> then legend appears at the upper left corner legend = QgsLayoutItemLegend(layout) #legend.setTitle('Legend') legend.setAutoUpdateModel(False) group = legend.model().rootGroup() group.clear() group.addLayer(active_raster_layer) layout.addItem(legend) legend.adjustBoxSize() #legend.refresh() # avoids adding all other layers ''' # uses existing legend object (see above), so we preserve it's layout position: legend.setAutoUpdateModel(False) group = legend.model().rootGroup() group.clear() group.addLayer(active_raster_layer) legend.adjustBoxSize() """ By default the newly created composer items have zero position (top left corner of the page) and zero size. The position and size are always measured in millimeters. # set label 1cm from the top and 2cm from the left of the page composerLabel.setItemPosition(20, 10) # set both label’s position and size (width 10cm, height 3cm) composerLabel.setItemPosition(20, 10, 100, 30) A frame is drawn around each item by default. How to remove the frame: composerLabel.setFrame(False) """ #print(active_composer.rect().width(), active_composer.rect().height()) # 1054 911 #print(self.iface.mapCanvas().size().width(), self.iface.mapCanvas().size().height()) # 1517 535 # "Leinwandgröße": habe keine vernünftigen Werte oben ermittelt (vielleicht Pixel; ich brauche mm). # selbst, mittels Mauszeiger ermittelt: width = 210 height = 297 # Rand neben der Legende (mm): dw = 10 dh = 14 """
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 qgis_composition_context = impact_report.qgis_composition_context # load composition object layout = QgsPrintLayout(QgsProject.instance()) # 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() # Replace for k, v in context.substitution_map.items(): template_content = template_content.replace('[{}]'.format(k), v) document.setContent(template_content) rwcontext = QgsReadWriteContext() load_status = layout.loadFromTemplate( document, rwcontext) 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 = layout_item(layout, item_id, QgsLayoutItemPicture) 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') html_element = layout_item(layout, item_id, QgsLayoutItemHtml) if html_element: if mode == 'text': text = html_el.get('text') text = text if text else '' html_element.setContentMode(QgsLayoutItemHtml.ManualHtml) html_element.setHtml(text) html_element.loadHtml() elif mode == 'url': url = html_el.get('url') html_element.setContentMode(QgsLayoutItemHtml.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, QgsProject.instance()) # 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 = layout_item(layout, item_id, QgsLayoutItemMap) for index, layer in enumerate(layers): # we need to check whether the layer is registered or not registered_layer = ( QgsProject.instance().mapLayer(layer.id())) if registered_layer: if not registered_layer == layer: layers[index] = registered_layer else: QgsProject.instance().addMapLayer(layer) """:type: qgis.core.QgsLayoutItemMap""" 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 for l in layers if isinstance(l, QgsMapLayer)] composer_map.setLayers(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.invalidateCache() 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 = layout_item(layout, item_id, QgsLayoutItemLegend) """:type: qgis.core.QgsLayoutItemLegend""" 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.model().rootGroup() for layer in layers: # we need to check whether the layer is registered or not registered_layer = ( QgsProject.instance().mapLayer(layer.id())) if registered_layer: if not registered_layer == layer: layer = registered_layer else: QgsProject.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, QgsLegendStyle.Hidden) legend.adjustBoxSize() legend.updateFilterByMap(False) # 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, layout, each_format, component) component_output.append(result_path) elif each_format == template_format: result_path = create_qgis_template_output( each_path, layout) component_output.append(result_path) elif isinstance(output_format, dict): component_output = {} for key, each_format in list(output_format.items()): each_path = component_output_path[key] if each_format in doc_format: result_path = create_qgis_pdf_output( impact_report, each_path, layout, each_format, component) component_output[key] = result_path elif each_format == template_format: result_path = create_qgis_template_output( each_path, layout) 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, layout, output_format, component) component_output = result_path elif output_format == template_format: result_path = create_qgis_template_output( component_output_path, layout) component_output = result_path component.output = component_output return component.output
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", "'{0}' data source does not exist in the database." "\nPlease contact your database " "administrator.".format(composerDS.name())) return False, msg #Set file name value formatter self._file_name_value_formatter = EntityValueFormatter( name=data_source ) #Register field names to be used for file naming self._file_name_value_formatter.register_columns(dataFields) #TODO: Need to automatically register custom configuration collections #Photo config collection ph_config_collection = PhotoConfigurationCollection.create(templateDoc) #Table configuration collection table_config_collection = TableConfigurationCollection.create(templateDoc) #Create chart configuration collection object chart_config_collection = ChartConfigurationCollection.create(templateDoc) # Create QR code configuration collection object qrc_config_collection = QRCodeConfigurationCollection.create(templateDoc) #Load the layers required by the table composer items self._table_mem_layers = load_table_layers(table_config_collection) entityFieldName = self.format_entity_field_name(composerDS.name(), data_source) #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 = QgsPrintLayout(self._map_settings) composition.loadFromTemplate(templateDoc) ref_layer = None #Set value of composer items based on the corresponding db values for composerId in composerDS.dataFieldMappings().reverse: #Use composer item id since the uuid is stripped off composerItem = composition.getComposerItemById(composerId) if not composerItem is None: fieldName = composerDS.dataFieldName(composerId) fieldValue = getattr(rec,fieldName) self._composeritem_value_handler(composerItem, fieldValue) # Extract photo information self._extract_photo_info(composition, ph_config_collection, rec) # Set table item values based on configuration information self._set_table_data(composition, table_config_collection, rec) # Refresh non-custom map composer items self._refresh_composer_maps(composition, list(spatialFieldsConfig.spatialFieldsMapping().keys())) # Set use fixed scale to false i.e. relative zoom use_fixed_scale = False # Create memory layers for spatial features and add them to the map for mapId,spfmList in spatialFieldsConfig.spatialFieldsMapping().items(): map_item = composition.getComposerItemById(mapId) if not map_item is None: # Clear any previous map memory layer # self.clear_temporary_map_layers() for spfm in spfmList: #Use the value of the label field to name the layer lbl_field = spfm.labelField() spatial_field = spfm.spatialField() if not spatial_field: continue if lbl_field: if hasattr(rec, spfm.labelField()): layerName = getattr(rec, spfm.labelField()) else: layerName = self._random_feature_layer_name(spatial_field) else: layerName = self._random_feature_layer_name(spatial_field) #Extract the geometry using geoalchemy spatial capabilities geom_value = getattr(rec, spatial_field) if geom_value is None: continue geom_func = geom_value.ST_AsText() geomWKT = self._dbSession.scalar(geom_func) #Get geometry type geom_type, srid = geometryType(composerDS.name(), spatial_field) #Create reference layer with feature ref_layer = self._build_vector_layer(layerName, geom_type, srid) if ref_layer is None or not ref_layer.isValid(): continue # Add feature bbox = self._add_feature_to_layer(ref_layer, geomWKT) zoom_type = spfm.zoom_type # Only scale the extents if zoom type is relative if zoom_type == 'RELATIVE': bbox.scale(spfm.zoomLevel()) #Workaround for zooming to single point extent if ref_layer.wkbType() == QgsWkbTypes.Point: canvas_extent = self._iface.mapCanvas().fullExtent() cnt_pnt = bbox.center() canvas_extent.scale(1.0/32, cnt_pnt) bbox = canvas_extent #Style layer based on the spatial field mapping symbol layer symbol_layer = spfm.symbolLayer() if not symbol_layer is None: ref_layer.rendererV2().symbols()[0].changeSymbolLayer(0,spfm.symbolLayer()) ''' Add layer to map and ensure its always added at the top ''' self.map_registry.addMapLayer(ref_layer) self._iface.mapCanvas().setExtent(bbox) # Set scale if type is FIXED if zoom_type == 'FIXED': self._iface.mapCanvas().zoomScale(spfm.zoomLevel()) use_fixed_scale = True self._iface.mapCanvas().refresh() # Add layer to map memory layer list self._map_memory_layers.append(ref_layer.id()) self._hide_layer(ref_layer) ''' Use root layer tree to get the correct ordering of layers in the legend ''' self._refresh_map_item(map_item, use_fixed_scale) # Extract chart information and generate chart self._generate_charts(composition, chart_config_collection, rec) # Extract QR code information in order to generate QR codes self._generate_qr_codes(composition, qrc_config_collection,rec) #Build output path and generate composition if not filePath is None and len(dataFields) == 0: self._write_output(composition, outputMode, filePath) elif filePath is None and len(dataFields) > 0: entityFieldName = 'id' 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 = "{0}/{1}".format(outputDir, docFileName) self._write_output(composition, outputMode, absDocPath) return True, "Success" return False, "Document composition could not be generated"
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 qgis_composition_context = impact_report.qgis_composition_context # load composition object layout = QgsPrintLayout(QgsProject.instance()) # 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() # Replace for k, v in context.substitution_map.items(): template_content = template_content.replace('[{}]'.format(k), v) document.setContent(template_content) rwcontext = QgsReadWriteContext() load_status = layout.loadFromTemplate( document, rwcontext) 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 = layout_item(layout, item_id, QgsLayoutItemPicture) 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') html_element = layout_item(layout, item_id, QgsLayoutItemHtml) if html_element: if mode == 'text': text = html_el.get('text') text = text if text else '' html_element.setContentMode(QgsLayoutItemHtml.ManualHtml) html_element.setHtml(text) html_element.loadHtml() elif mode == 'url': url = html_el.get('url') html_element.setContentMode(QgsLayoutItemHtml.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, QgsProject.instance()) # 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 = layout_item(layout, item_id, QgsLayoutItemMap) for index, _layer in enumerate(layers): # we need to check whether the layer is registered or not registered_layer = ( QgsProject.instance().mapLayer(_layer.id())) if registered_layer: if not registered_layer == _layer: layers[index] = registered_layer else: QgsProject.instance().addMapLayer(_layer) """:type: qgis.core.QgsLayoutItemMap""" 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 = [_layer for _layer in layers if isinstance( _layer, QgsMapLayer)] composer_map.setLayers(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 layer in layer_set: layer_extent = coord_transform.transform(layer.extent()) if layer.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 layer in layer_set: # combine extent if different layer is provided. layer_extent = coord_transform.transform(layer.extent()) extent.combineExtentWith(layer_extent) if layer.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.invalidateCache() 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 = layout_item(layout, item_id, QgsLayoutItemLegend) """:type: qgis.core.QgsLayoutItemLegend""" 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.model().rootGroup() for _layer in layers: # we need to check whether the layer is registered or not registered_layer = ( QgsProject.instance().mapLayer(_layer.id())) if registered_layer: if not registered_layer == _layer: _layer = registered_layer else: QgsProject.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, QgsLegendStyle.Hidden) legend.adjustBoxSize() legend.updateFilterByMap(False) # 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, layout, each_format, component) component_output.append(result_path) elif each_format == template_format: result_path = create_qgis_template_output( each_path, layout) component_output.append(result_path) elif isinstance(output_format, dict): component_output = {} for key, each_format in list(output_format.items()): each_path = component_output_path[key] if each_format in doc_format: result_path = create_qgis_pdf_output( impact_report, each_path, layout, each_format, component) component_output[key] = result_path elif each_format == template_format: result_path = create_qgis_template_output( each_path, layout) 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, layout, output_format, component) component_output = result_path elif output_format == template_format: result_path = create_qgis_template_output( component_output_path, layout) component_output = result_path component.output = component_output return component.output