def testMainAnnotationLayerRendered(self): """ test that main annotation layer is rendered above all other layers """ canvas = QgsMapCanvas() canvas.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) canvas.setFrameStyle(0) canvas.resize(600, 400) self.assertEqual(canvas.width(), 600) self.assertEqual(canvas.height(), 400) layer = QgsVectorLayer("Polygon?crs=epsg:4326&field=fldtxt:string", "layer", "memory") sym3 = QgsFillSymbol.createSimple({'color': '#b200b2'}) layer.renderer().setSymbol(sym3) canvas.setLayers([layer]) canvas.setExtent(QgsRectangle(10, 30, 20, 35)) canvas.show() # need to wait until first redraw can occur (note that we first need to wait till drawing starts!) while not canvas.isDrawing(): app.processEvents() canvas.waitWhileRendering() self.assertTrue( self.canvasImageCheck('empty_canvas', 'empty_canvas', canvas)) # add polygon to layer f = QgsFeature() f.setGeometry(QgsGeometry.fromRect(QgsRectangle(5, 25, 25, 45))) self.assertTrue(layer.dataProvider().addFeatures([f])) # refresh canvas canvas.refresh() canvas.waitWhileRendering() # no annotation yet... self.assertFalse( self.canvasImageCheck('main_annotation_layer', 'main_annotation_layer', canvas, expect_fail=True)) annotation_layer = QgsProject.instance().mainAnnotationLayer() annotation_layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) annotation_geom = QgsGeometry.fromRect(QgsRectangle(12, 30, 18, 33)) annotation = QgsAnnotationPolygonItem( annotation_geom.constGet().clone()) sym3 = QgsFillSymbol.createSimple({ 'color': '#ff0000', 'outline_style': 'no' }) annotation.setSymbol(sym3) annotation_layer.addItem(annotation) # refresh canvas canvas.refresh() canvas.waitWhileRendering() # annotation must be rendered over other layers self.assertTrue( self.canvasImageCheck('main_annotation_layer', 'main_annotation_layer', canvas)) annotation_layer.clear()
def testLockedScale(self): """Test zoom/pan/center operations when scale lock is on""" c = QgsMapCanvas() dpr = c.mapSettings().devicePixelRatio() self.assertEqual(c.size().width(), 640) self.assertEqual(c.size().height(), 480) c.setExtent(QgsRectangle(5, 45, 9, 47)) self.assertEqual(round(c.scale() / 100000), 13 * dpr) c.zoomScale(2500000) c.setScaleLocked(True) self.assertEqual(round(c.magnificationFactor(), 1), 1) # Test setExtent c.setExtent(QgsRectangle(6, 45.5, 8, 46), True) self.assertEqual(round(c.scale()), 2500000) self.assertEqual(c.center().x(), 7.0) self.assertEqual(c.center().y(), 45.75) self.assertEqual(round(c.magnificationFactor()), 4 / dpr) # Test setCenter c.setCenter(QgsPointXY(6, 46)) self.assertEqual(c.center().x(), 6) self.assertEqual(c.center().y(), 46) self.assertEqual(round(c.scale()), 2500000) # Test zoom c.zoomByFactor(0.5, QgsPointXY(6.5, 46.5), False) self.assertEqual(c.center().x(), 6.5) self.assertEqual(c.center().y(), 46.5) self.assertTrue(c.magnificationFactor() > 7 / dpr) self.assertEqual(round(c.scale()), 2500000) # Test zoom with center # default zoom factor is 2, x and y are pixel coordinates, default size is 640x480 c.zoomWithCenter(300, 200, True) self.assertEqual(round(c.center().x(), 1), 6.5) self.assertEqual(round(c.center().y(), 1), 46.6) self.assertEqual(round(c.scale()), 2500000) self.assertTrue(c.magnificationFactor() > (14 / dpr) and c.magnificationFactor() < (16 / dpr)) # out ... c.zoomWithCenter(300, 200, False) self.assertEqual(round(c.center().x(), 1), 6.5) self.assertEqual(round(c.center().y(), 1), 46.6) self.assertEqual(round(c.scale()), 2500000) self.assertTrue(c.magnificationFactor() > 7 / dpr) # Test setExtent with different ratio c2 = QgsMapCanvas() c2.setExtent(QgsRectangle(5, 45, 9, 47)) c2.zoomScale(2500000) c2.setScaleLocked(True) c2.setExtent(QgsRectangle(3, 45, 11, 45.5), True) self.assertEqual(round(c2.scale()), 2500000) self.assertEqual(c2.center().x(), 7.0) self.assertEqual(c2.center().y(), 45.25) self.assertAlmostEqual(c2.magnificationFactor(), 1 / dpr, 0) # Restore original c2.setExtent(QgsRectangle(5, 45, 9, 47), True) self.assertEqual(round(c2.scale()), 2500000) self.assertEqual(c2.center().x(), 7.0) self.assertEqual(c2.center().y(), 46.0) self.assertAlmostEqual(c2.magnificationFactor(), 2 / dpr, 0) c2.setExtent(QgsRectangle(7, 46, 11, 46.5), True) self.assertEqual(round(c2.scale()), 2500000) self.assertEqual(c2.center().x(), 9.0) self.assertEqual(c2.center().y(), 46.25) self.assertAlmostEqual(c2.magnificationFactor(), 2 / dpr, 0) c2.setExtent(QgsRectangle(7, 46, 9, 46.5), True) self.assertEqual(round(c2.scale()), 2500000) self.assertEqual(c2.center().x(), 8.0) self.assertEqual(c2.center().y(), 46.25) self.assertAlmostEqual(c2.magnificationFactor(), 4 / dpr, 0)
def __init__(self, app): """ constructor - initialize UI elements - connect UI elements to callback """ super(WidgetResult, self).__init__() self.ui = Ui_widgetResult() self.ui.setupUi(self) # create canvas self.canvas = QgsMapCanvas(self.ui.widget_map) self.canvas.setGeometry( 0, # x self.ui.widget_map_menu_l.x() + self.ui.widget_map_menu_l.height(), # y self.ui.widget_map.width() - 2 * UI_PADDING, # width self.ui.widget_map.width() - 2 * UI_PADDING # height ) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.mapRenderer().setProjectionsEnabled(True) self.canvas.mapRenderer().setDestinationCrs( QgsCoordinateReferenceSystem( 4326, QgsCoordinateReferenceSystem.PostgisCrsId)) self.canvas.zoomNextStatusChanged.connect(self.checkRendering) self.canvas.xyCoordinates.connect(self.currentLocation) self.registry = QgsMapLayerRegistry.instance() self.map_layers = [None] * len(self.LAYER_NAMES) self.map_layer_renderer = [None] * len(self.LAYER_NAMES) for idx, str_style in enumerate(self.LAYER_STYLES): rdoc = QDomDocument("renderer") rdoc.setContent(str_style) self.map_layer_renderer[idx] = QgsFeatureRendererV2.load( rdoc.firstChild().toElement()) # populate export list self.ui.cb_export_format.clear() for export_format in self.EXPORT_FORMATS.keys(): self.ui.cb_export_format.addItem(export_format) # style object required for QgsRendererV2PropertiesDialog self.style = QgsStyleV2() # create the map tools self.toolPan = QgsMapToolPan(self.canvas) self.toolZoomIn = QgsMapToolZoom(self.canvas, False) # false = in self.toolZoomOut = QgsMapToolZoom(self.canvas, True) # true = out self.toolInfo = QgsMapToolEmitPoint(self.canvas) self.toolInfo.canvasClicked.connect(self.showInfo) self.canvas.setMapTool(self.toolPan) # additional self.dlgResultDetail = DialogResult() self.dlgResultDetail.setModal(True) # set link to application main controller self.app = app # reset project self._project = None # default export setting self.export_format = ExportTypes.Shapefile # connect slots (ui event) self.ui.btn_zoom_full.clicked.connect(self.mapZoomFull) self.ui.btn_zoom_in.clicked.connect(self.mapZoomIn) self.ui.btn_zoom_out.clicked.connect(self.mapZoomOut) self.ui.btn_stop.clicked.connect(self.stopRendering) self.ui.btn_zoom_layer.clicked.connect(self.mapZoomLayer) self.ui.btn_pan.clicked.connect(self.mapPan) self.ui.btn_theme.clicked.connect(self.mapEditTheme) self.ui.btn_info.clicked.connect(self.mapIdentify) self.ui.btn_zoom_to_feature.clicked.connect(self.searchFeature) self.ui.cb_export_format.currentIndexChanged[str].connect( self.exportFormatChanged) self.ui.btn_export.clicked.connect(self.exportData) self.ui.btn_export_select_path.clicked.connect(self.selectExportFile)
def test_geocode(self): geocoder = TestGeocoder() canvas = QgsMapCanvas() filter = QgsGeocoderLocatorFilter('testgeocoder', 'my geocoder', 'pref', geocoder, canvas) self.assertEqual(filter.name(), 'testgeocoder') self.assertEqual(filter.displayName(), 'my geocoder') self.assertEqual(filter.prefix(), 'pref') self.assertEqual(filter.geocoder(), geocoder) spy = QSignalSpy(filter.resultFetched) context = QgsLocatorContext() feedback = QgsFeedback() # no results filter.fetchResults('cvxbcvb', context, feedback) self.assertEqual(len(spy), 0) # one result filter.fetchResults('a', context, feedback) self.assertEqual(len(spy), 1) res = spy[-1][0] self.assertEqual(res.displayString, 'res 1') # some sip weirdness here -- if we directly access the QgsLocatorResult object here then we get segfaults! # so instead convert back to QgsGeocoderResult. This makes the test more robust anyway... geocode_result = filter.locatorResultToGeocoderResult(res) self.assertEqual(geocode_result.identifier(), 'res 1') self.assertEqual(geocode_result.geometry().asWkt(), 'Point (1 2)') self.assertEqual(geocode_result.crs().authid(), 'EPSG:4326') self.assertEqual(geocode_result.additionalAttributes(), { 'b': 123, 'c': 'xyz' }) self.assertTrue(geocode_result.viewport().isNull()) self.assertFalse(geocode_result.description()) self.assertFalse(geocode_result.group()) # two possible results filter.fetchResults('b', context, feedback) self.assertEqual(len(spy), 3) res1 = spy[-2][0] res2 = spy[-1][0] self.assertEqual(res1.displayString, 'res 1') geocode_result = filter.locatorResultToGeocoderResult(res1) self.assertEqual(geocode_result.identifier(), 'res 1') self.assertEqual(geocode_result.geometry().asWkt(), 'Point (11 12)') self.assertEqual(geocode_result.crs().authid(), 'EPSG:4326') self.assertEqual(geocode_result.additionalAttributes(), { 'b': 123, 'c': 'xyz' }) self.assertTrue(geocode_result.viewport().isNull()) self.assertEqual(geocode_result.description(), 'desc') self.assertEqual(geocode_result.group(), 'group') self.assertEqual(res2.displayString, 'res 2') geocode_result = filter.locatorResultToGeocoderResult(res2) self.assertEqual(geocode_result.identifier(), 'res 2') self.assertEqual(geocode_result.geometry().asWkt(), 'Point (13 14)') self.assertEqual(geocode_result.crs().authid(), 'EPSG:3857') self.assertEqual(geocode_result.additionalAttributes(), {'d': 456}) self.assertEqual(geocode_result.viewport(), QgsRectangle(1, 2, 3, 4)) self.assertFalse(geocode_result.description()) self.assertFalse(geocode_result.group())
def testMasterLayerOrder(self): """ test master layer order""" prj = QgsProject.instance() prj.clear() layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") layer3 = QgsVectorLayer("Point?field=fldtxt:string", "layer3", "memory") prj.addMapLayers([layer, layer2, layer3]) prj.layerTreeRoot().setHasCustomLayerOrder(True) prj.layerTreeRoot().setCustomLayerOrder([layer2, layer]) self.assertEqual(prj.mapThemeCollection().masterLayerOrder(), [layer2, layer]) prj.layerTreeRoot().setCustomLayerOrder([layer, layer2, layer3]) # make some themes... theme1 = QgsMapThemeCollection.MapThemeRecord() theme1.setLayerRecords([ QgsMapThemeCollection.MapThemeLayerRecord(layer3), QgsMapThemeCollection.MapThemeLayerRecord(layer) ]) theme2 = QgsMapThemeCollection.MapThemeRecord() theme2.setLayerRecords([ QgsMapThemeCollection.MapThemeLayerRecord(layer3), QgsMapThemeCollection.MapThemeLayerRecord(layer2), QgsMapThemeCollection.MapThemeLayerRecord(layer) ]) theme3 = QgsMapThemeCollection.MapThemeRecord() theme3.setLayerRecords([ QgsMapThemeCollection.MapThemeLayerRecord(layer2), QgsMapThemeCollection.MapThemeLayerRecord(layer) ]) prj.mapThemeCollection().insert('theme1', theme1) prj.mapThemeCollection().insert('theme2', theme2) prj.mapThemeCollection().insert('theme3', theme3) #order of layers in theme should respect master order self.assertEqual( prj.mapThemeCollection().mapThemeVisibleLayers('theme1'), [layer, layer3]) self.assertEqual( prj.mapThemeCollection().mapThemeVisibleLayers('theme2'), [layer, layer2, layer3]) self.assertEqual( prj.mapThemeCollection().mapThemeVisibleLayers('theme3'), [layer, layer2]) # also check ids! self.assertEqual( prj.mapThemeCollection().mapThemeVisibleLayerIds('theme1'), [layer.id(), layer3.id()]) self.assertEqual( prj.mapThemeCollection().mapThemeVisibleLayerIds('theme2'), [layer.id(), layer2.id(), layer3.id()]) self.assertEqual( prj.mapThemeCollection().mapThemeVisibleLayerIds('theme3'), [layer.id(), layer2.id()]) # reset master order prj.layerTreeRoot().setCustomLayerOrder([layer2, layer3, layer]) self.assertEqual( prj.mapThemeCollection().mapThemeVisibleLayers('theme1'), [layer3, layer]) self.assertEqual( prj.mapThemeCollection().mapThemeVisibleLayers('theme2'), [layer2, layer3, layer]) self.assertEqual( prj.mapThemeCollection().mapThemeVisibleLayers('theme3'), [layer2, layer]) self.assertEqual( prj.mapThemeCollection().mapThemeVisibleLayerIds('theme1'), [layer3.id(), layer.id()]) self.assertEqual( prj.mapThemeCollection().mapThemeVisibleLayerIds('theme2'), [layer2.id(), layer3.id(), layer.id()]) self.assertEqual( prj.mapThemeCollection().mapThemeVisibleLayerIds('theme3'), [layer2.id(), layer.id()]) # check that layers include those hidden in the layer tree canvas = QgsMapCanvas() bridge = QgsLayerTreeMapCanvasBridge(prj.layerTreeRoot(), canvas) root = prj.layerTreeRoot() layer_node = root.findLayer(layer2.id()) layer_node.setItemVisibilityChecked(False) app.processEvents() prj.layerTreeRoot().setHasCustomLayerOrder(False) self.assertEqual(prj.mapThemeCollection().masterLayerOrder(), [layer, layer2, layer3]) self.assertEqual( prj.mapThemeCollection().mapThemeVisibleLayers('theme1'), [layer, layer3]) self.assertEqual( prj.mapThemeCollection().mapThemeVisibleLayers('theme2'), [layer, layer2, layer3]) self.assertEqual( prj.mapThemeCollection().mapThemeVisibleLayers('theme3'), [layer, layer2]) self.assertEqual( prj.mapThemeCollection().mapThemeVisibleLayerIds('theme1'), [layer.id(), layer3.id()]) self.assertEqual( prj.mapThemeCollection().mapThemeVisibleLayerIds('theme2'), [layer.id(), layer2.id(), layer3.id()]) self.assertEqual( prj.mapThemeCollection().mapThemeVisibleLayerIds('theme3'), [layer.id(), layer2.id()])
def get_qgis_app(): """ Start one QGIS application to test against. :returns: Handle to QGIS app, canvas, iface and parent. If there are any errors the tuple members will be returned as None. :rtype: (QgsApplication, CANVAS, IFACE, PARENT) If QGIS is already running the handle to that app will be returned. """ global QGIS_APP, PARENT, IFACE, CANVAS # pylint: disable=W0603 if iface: from qgis.core import QgsApplication QGIS_APP = QgsApplication CANVAS = iface.mapCanvas() PARENT = iface.mainWindow() IFACE = iface return QGIS_APP, CANVAS, IFACE, PARENT try: from qgis.core import QgsApplication from qgis.gui import QgsMapCanvas # pylint: disable=no-name-in-module # noinspection PyPackageRequirements from PyQt4 import QtGui, QtCore # pylint: disable=W0621 # noinspection PyPackageRequirements from PyQt4.QtCore import QCoreApplication, QSettings from safe.test.qgis_interface import QgisInterface except ImportError: return None, None, None, None if QGIS_APP is None: gui_flag = True # All test will run qgis in gui mode # AG: For testing purposes, we use our own configuration file instead # of using the QGIS apps conf of the host # noinspection PyCallByClass,PyArgumentList QCoreApplication.setOrganizationName('QGIS') # noinspection PyCallByClass,PyArgumentList QCoreApplication.setOrganizationDomain('qgis.org') # noinspection PyCallByClass,PyArgumentList QCoreApplication.setApplicationName('QGIS2InaSAFETesting') # noinspection PyPep8Naming if 'argv' in dir(sys): QGIS_APP = QgsApplication(sys.argv, gui_flag) else: QGIS_APP = QgsApplication([], gui_flag) # Make sure QGIS_PREFIX_PATH is set in your env if needed! QGIS_APP.initQgis() s = QGIS_APP.showSettings() LOGGER.debug(s) # Save some settings settings = QSettings() settings.setValue('locale/overrideFlag', True) settings.setValue('locale/userLocale', 'en_US') # We disabled message bars for now for extent selector as # we don't have a main window to show them in TS - version 3.2 settings.setValue('inasafe/show_extent_confirmations', False) settings.setValue('inasafe/show_extent_warnings', False) settings.setValue('inasafe/showRubberBands', True) settings.setValue('inasafe/analysis_extents_mode', HAZARD_EXPOSURE) if PARENT is None: # noinspection PyPep8Naming PARENT = QtGui.QWidget() if CANVAS is None: # noinspection PyPep8Naming CANVAS = QgsMapCanvas(PARENT) CANVAS.resize(QtCore.QSize(400, 400)) if IFACE is None: # QgisInterface is a stub implementation of the QGIS plugin interface # noinspection PyPep8Naming IFACE = QgisInterface(CANVAS) return QGIS_APP, CANVAS, IFACE, PARENT
def __sp_index_factory(layer): index = QgsSpatialIndex() for ft in layer.getFeatures(): index.insertFeature(ft) return index if __name__ == '__main__' or __name__ == '__console__': """ <init/> """ app = QApplication([]) QgsApplication.setPrefixPath(r'C:\Program Files\QGIS 2.18\apps\qgis', True) QgsApplication.initQgis() canvas = QgsMapCanvas() iface = QgisInterface(canvas) """ </init> """ """ main """ print('Starts populate grid...') start_time = datetime.now() property_map = { 'COD_CLASSE': { 'type': 'number', 'alias': 'codigo',
def test_temporal_animation(self): """ Test temporal animation logic """ canvas = QgsMapCanvas() self.assertEqual(canvas.mapSettings().frameRate(), -1) self.assertEqual(canvas.mapSettings().currentFrame(), -1) controller = QgsTemporalController() canvas.setTemporalController(controller) controller.updateTemporalRange.emit( QgsDateTimeRange(QDateTime(QDate(2020, 1, 2), QTime(1, 2, 3)), QDateTime(QDate(2020, 1, 4), QTime(1, 2, 3)))) # should be no change self.assertEqual(canvas.mapSettings().frameRate(), -1) self.assertEqual(canvas.mapSettings().currentFrame(), -1) temporal_no = QgsTemporalNavigationObject() temporal_no.setTemporalExtents( QgsDateTimeRange(QDateTime(QDate(2020, 1, 2), QTime(1, 2, 3)), QDateTime(QDate(2020, 1, 4), QTime(1, 2, 3)))) temporal_no.setFrameDuration(QgsInterval(0, 0, 0, 0, 1, 0, 0)) canvas.setTemporalController(temporal_no) controller.updateTemporalRange.emit( QgsDateTimeRange(QDateTime(QDate(2020, 1, 2), QTime(1, 2, 3)), QDateTime(QDate(2020, 1, 4), QTime(1, 2, 3)))) # should be no change self.assertEqual(canvas.mapSettings().frameRate(), -1) self.assertEqual(canvas.mapSettings().currentFrame(), -1) temporal_no.setFramesPerSecond(30) temporal_no.pause() temporal_no.setCurrentFrameNumber(6) canvas.refresh() # should be no change - temporal controller is not in animation mode self.assertEqual(canvas.mapSettings().frameRate(), -1) self.assertEqual(canvas.mapSettings().currentFrame(), -1) temporal_no.setNavigationMode(QgsTemporalNavigationObject.Animated) self.assertEqual(canvas.mapSettings().frameRate(), 30) self.assertEqual(canvas.mapSettings().currentFrame(), 6) temporal_no.setCurrentFrameNumber(7) self.assertEqual(canvas.mapSettings().frameRate(), 30) self.assertEqual(canvas.mapSettings().currentFrame(), 6) # switch off animation mode temporal_no.setNavigationMode(QgsTemporalNavigationObject.FixedRange) self.assertEqual(canvas.mapSettings().frameRate(), -1) self.assertEqual(canvas.mapSettings().currentFrame(), -1) temporal_no.setNavigationMode(QgsTemporalNavigationObject.Animated) self.assertEqual(canvas.mapSettings().frameRate(), 30) self.assertEqual(canvas.mapSettings().currentFrame(), 7) temporal_no.setNavigationMode( QgsTemporalNavigationObject.NavigationOff) self.assertEqual(canvas.mapSettings().frameRate(), -1) self.assertEqual(canvas.mapSettings().currentFrame(), -1)
def update_summary_sheet(self): ''' Creates a summary sheet with thumbnail, layer metadata and online view link ''' #create a layer snapshot and upload it to google drive mapbox_style = self.service_sheet.sheet_cell('settings!A5') if not mapbox_style: print "migrating mapbox style" self.service_sheet.set_style_mapbox(self.layer_style_to_json(self.lyr)) if not self.dirty: return canvas = QgsMapCanvas() canvas.resize(QSize(300,300)) canvas.setCanvasColor(Qt.white) canvas.setExtent(self.lyr.extent()) canvas.setLayerSet([QgsMapCanvasLayer(self.lyr)]) canvas.refresh() canvas.update() settings = canvas.mapSettings() settings.setLayers([self.lyr.id()]) job = QgsMapRendererParallelJob(settings) job.start() job.waitForFinished() image = job.renderedImage() tmp_path = os.path.join(self.parent.plugin_dir,self.service_sheet.name+".png") image.save(tmp_path,"PNG") image_istances = self.service_drive.list_files(mimeTypeFilter='image/png',filename=self.service_sheet.name+".png") for imagename, image_props in image_istances.iteritems(): print imagename, image_props['id'] self.service_drive.delete_file(image_props['id']) result = self.service_drive.upload_image(tmp_path) print "UPLOADED", result self.service_drive.add_permission(result['id'],'anyone','reader') webLink = 'https://drive.google.com/uc?export=view&id='+result['id'] os.remove(tmp_path) print 'result',result,webLink #update layer metadata summary_id = self.service_sheet.add_sheet('summary', no_grid=True) self.service_sheet.erase_cells('summary') metadata = self.get_layer_metadata() range = 'summary!A1:B8' update_body = { "range": range, "values": metadata, } print "update", self.service_sheet.service.spreadsheets().values().update(spreadsheetId=self.spreadsheet_id,range=range, body=update_body, valueInputOption='USER_ENTERED').execute() #merge cells to visualize snapshot and aaply image snapshot request_body = { 'requests': [{ 'mergeCells': { "range": { "sheetId": summary_id, "startRowIndex": 9, "endRowIndex": 32, "startColumnIndex": 0, "endColumnIndex": 9, }, "mergeType": 'MERGE_ALL' } }] } print "merge", self.service_sheet.service.spreadsheets().batchUpdate(spreadsheetId=self.spreadsheet_id, body=request_body).execute() print "image", self.service_sheet.set_sheet_cell('summary!A10','=IMAGE("%s",3)' % webLink) permissions = self.service_drive.file_property(self.spreadsheet_id,'permissions') for permission in permissions: if permission['type'] == 'anyone': public = True break else: public = False if public: range = 'summary!A9:B9' update_body = { "range": range, "values": [['public link', "https://enricofer.github.io/GooGIS2CSV/converter.html?spreadsheet_id="+self.spreadsheet_id]] } print "update_public_link", self.service_sheet.service.spreadsheets().values().update(spreadsheetId=self.spreadsheet_id,range=range, body=update_body, valueInputOption='USER_ENTERED').execute() #hide worksheets except summary sheets = self.service_sheet.get_sheets() #self.service_sheet.toggle_sheet('summary', sheets['summary'], hidden=None) for sheet_name,sheet_id in sheets.iteritems(): if not sheet_name == 'summary': print sheet_name, sheet_id self.service_sheet.toggle_sheet(sheet_name, sheet_id, hidden=True)
from qgis.core.contextmanagers import qgisapp gui = True with qgisapp(guienabled=gui) as app: from moduls.QvApp import QvApp from qgis.gui import QgsMapCanvas from moduls.QvLlegenda import QvLlegenda from moduls.QvAtributs import QvAtributs from moduls.QvMapForms import QvFormNovaMapificacio app = QvApp() canv = QgsMapCanvas() canv.setWindowTitle('Canvas') canv.show() atrib = QvAtributs(canv) leyenda = QvLlegenda(canv, atrib) leyenda.project.read('mapesOffline/qVista default map.qgs') leyenda.setWindowTitle('Llegenda') leyenda.show() # z = QvMapificacio('U:/QUOTA/Comu_imi/Becaris/CarrecsAnsi100.csv') # z = QvMapificacio('CarrecsUTF8.csv') z = QvMapificacio('C:/temp/qVista/dades/Terrasses.csv') if z.msgError != '':
def get_qgis_app(cleanup=True): """ Start one QGIS application to test against. :returns: Handle to QGIS app, canvas, iface and parent. If there are any errors the tuple members will be returned as None. :rtype: (QgsApplication, CANVAS, IFACE, PARENT) If QGIS is already running the handle to that app will be returned. """ global QGIS_APP, PARENT, IFACE, CANVAS # pylint: disable=W0603 if iface: from qgis.core import QgsApplication QGIS_APP = QgsApplication CANVAS = iface.mapCanvas() PARENT = iface.mainWindow() IFACE = iface return QGIS_APP, CANVAS, IFACE, PARENT from qgis.core import QgsApplication from qgis.gui import QgsMapCanvas from qgis.PyQt.QtCore import QSize from qgis.PyQt.QtWidgets import QWidget from .qgis_interface import QgisInterface global QGISAPP # pylint: disable=global-variable-undefined try: QGISAPP except NameError: myGuiFlag = True # All test will run qgis in gui mode # In python3 we need to convert to a bytes object (or should # QgsApplication accept a QString instead of const char* ?) try: argvb = list(map(os.fsencode, sys.argv)) except AttributeError: argvb = sys.argv # Note: QGIS_PREFIX_PATH is evaluated in QgsApplication - # no need to mess with it here. QGISAPP = QgsApplication(argvb, myGuiFlag) QGISAPP.initQgis() s = QGISAPP.showSettings() LOGGER.debug(s) def debug_log_message(message, tag, level): """ Prints a debug message to a log :param message: message to print :param tag: log tag :param level: log message level (severity) :return: """ print('{}({}): {}'.format(tag, level, message)) QgsApplication.instance().messageLog().messageReceived.connect( debug_log_message) if cleanup: import atexit @atexit.register def exitQgis(): # pylint: disable=unused-variable """ Gracefully closes the QgsApplication instance """ try: QGISAPP.exitQgis() # pylint: disable=used-before-assignment QGISAPP = None # pylint: disable=redefined-outer-name except NameError: pass if PARENT is None: # noinspection PyPep8Naming PARENT = QWidget() if CANVAS is None: # noinspection PyPep8Naming CANVAS = QgsMapCanvas(PARENT) CANVAS.resize(QSize(400, 400)) if IFACE is None: # QgisInterface is a stub implementation of the QGIS plugin interface # noinspection PyPep8Naming IFACE = QgisInterface(CANVAS) return QGISAPP, CANVAS, IFACE, PARENT
def __init__(self, app, mapLayers, mapLayersCategory): QMainWindow.__init__(self) self.app = app self.mapLayers = mapLayers self.mapLayersCategory = mapLayersCategory self.resize(shared.windowWidth, shared.windowHeight) self.setWindowTitle(shared.progName + ": " + shared.progVer) # Set up the map canvas self.canvas = QgsMapCanvas() self.setCentralWidget(self.canvas) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.setCachingEnabled(True) #self.canvas.setMapUpdateInterval(1000) self.canvas.setParallelRenderingEnabled(True) self.canvas.enableMapTileRendering(True) self.canvas.setLayers(self.mapLayers) self.canvas.setExtent(shared.extentRect) self.canvas.setMagnificationFactor(shared.windowMagnification) #mapSet = self.canvas.mapSettings() #print(mapSet.flags()) # Create some actions #self.actionExit = QAction(QIcon('exit.png'), '&Exit', self) self.actionExit = QAction("&Exit", self) self.actionExit.setShortcut("Ctrl+Q") self.actionExit.setStatusTip("Exit " + shared.progName) self.actionZoomIn = QAction("Zoom in", self) self.actionZoomIn.setCheckable(True) #self.actionExit.setShortcut("Ctrl++") self.actionZoomIn.setStatusTip("Show more detail") self.actionZoomOut = QAction("Zoom out", self) self.actionZoomOut.setCheckable(True) #self.actionExit.setShortcut("Ctrl+-") self.actionZoomOut.setStatusTip("Show less detail") self.actionPan = QAction("Pan", self) self.actionPan.setCheckable(True) self.actionPan.setStatusTip("Move the map laterally") self.actionChangeBackground = QAction("Change background", self) self.actionChangeBackground.setStatusTip( "Change the raster background") if not shared.haveRasterBackground: self.actionChangeBackground.setEnabled(False) self.actionCoords = QAction("Show coordinates", self) self.actionCoords.setCheckable(True) self.actionCoords.setStatusTip("Click to show coordinates") self.actionRun = QAction("Simulate", self) self.actionRun.setStatusTip("Route flow") # Connect the actions self.actionExit.triggered.connect(app.quit) self.actionZoomIn.triggered.connect(self.zoomIn) self.actionZoomOut.triggered.connect(self.zoomOut) self.actionPan.triggered.connect(self.pan) self.actionChangeBackground.triggered.connect(self.changeBackground) self.actionCoords.triggered.connect(self.showCoords) self.actionRun.triggered.connect(self.doRun) # Create a menu bar and add menus self.menubar = self.menuBar() self.fileMenu = self.menubar.addMenu("&File") self.fileMenu.addAction(self.actionExit) self.editMenu = self.menubar.addMenu("&Edit") #self.editMenu.addAction(self.actionExit) self.viewMenu = self.menubar.addMenu("&View") self.viewMenu.addAction(self.actionZoomIn) self.viewMenu.addAction(self.actionZoomOut) self.viewMenu.addAction(self.actionPan) self.viewMenu.addAction(self.actionChangeBackground) self.viewMenu.addAction(self.actionCoords) self.runMenu = self.menubar.addMenu("&Run") self.runMenu.addAction(self.actionRun) # Create a tool bar and add some actions self.toolbar = self.addToolBar("Default") self.toolbar.setFloatable(True) self.toolbar.addAction(self.actionRun) self.toolbar.addAction(self.actionZoomIn) self.toolbar.addAction(self.actionZoomOut) self.toolbar.addAction(self.actionPan) self.toolbar.addAction(self.actionCoords) # Create some map tools self.toolPan = QgsMapToolPan(self.canvas) self.toolPan.setAction(self.actionPan) self.toolZoomIn = QgsMapToolZoom(self.canvas, False) # False = in self.toolZoomIn.setAction(self.actionZoomIn) self.toolZoomOut = QgsMapToolZoom(self.canvas, True) # True = out self.toolZoomOut.setAction(self.actionZoomOut) self.toolCoords = PointTool(self.canvas) self.toolCoords.setAction(self.actionCoords) # Put into panning mode self.pan() # Add a status bar self.statusBar = QStatusBar(self.canvas) self.setStatusBar(self.statusBar) # And put a progress indicator on the status bar self.statusBar.progress = QProgressBar(self) self.statusBar.progress.setRange(0, 100) self.statusBar.progress.setMaximumWidth(500) self.statusBar.progress.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.statusBar.addPermanentWidget(self.statusBar.progress) self.myThread = None return
def get_qgis_app(requested_locale='en_US', qsetting=''): """ Start one QGIS application to test against. :param locale: The locale we want the qgis to launch with. :type locale: str :param qsetting: String to specify the QSettings. By default, use empty string. :type qsetting: str :returns: Handle to QGIS app, canvas, iface and parent. If there are any errors the tuple members will be returned as None. :rtype: (QgsApplication, CANVAS, IFACE, PARENT) If QGIS is already running the handle to that app will be returned. """ global QGIS_APP, PARENT, IFACE, CANVAS # pylint: disable=W0603 from qgis.PyQt.QtCore import QSettings if qsetting: settings = QSettings(qsetting) else: settings = QSettings() default_user_directory = setting('defaultUserDirectory') current_locale = general_setting('locale/userLocale', default='en_US', qsettings=settings) locale_match = current_locale == requested_locale if iface and locale_match: from qgis.core import QgsApplication QGIS_APP = QgsApplication CANVAS = iface.mapCanvas() PARENT = iface.mainWindow() IFACE = iface try: from qgis.core import QgsApplication from qgis.gui import QgsMapCanvas # pylint: disable=no-name-in-module # noinspection PyPackageRequirements from qgis.PyQt import QtWidgets, QtCore # pylint: disable=W0621 # noinspection PyPackageRequirements from qgis.PyQt.QtCore import QCoreApplication, QSettings from safe.test.qgis_interface import QgisInterface except ImportError: return None, None, None, None if qsetting: settings = QSettings(qsetting) else: settings = QSettings() if not QGIS_APP: gui_flag = True # All test will run qgis in gui mode # AG: For testing purposes, we use our own configuration file # instead of using the QGIS apps conf of the host # noinspection PyCallByClass,PyArgumentList QCoreApplication.setOrganizationName('QGIS') # noinspection PyCallByClass,PyArgumentList QCoreApplication.setOrganizationDomain('qgis.org') # noinspection PyCallByClass,PyArgumentList QCoreApplication.setApplicationName('QGIS2InaSAFETesting') # We disabled message bars for now for extent selector as # we don't have a main window to show them in TS - version 3.2 set_setting('show_extent_warnings', False, settings) set_setting('showRubberBands', True, settings) set_setting('show_extent_confirmations', False, settings) set_setting('analysis_extents_mode', HAZARD_EXPOSURE, settings) if default_user_directory: set_setting('defaultUserDirectory', default_user_directory, settings) # noinspection PyPep8Naming if 'argv' in dir(sys): QGIS_APP = QgsApplication([p.encode('utf-8') for p in sys.argv], gui_flag) else: QGIS_APP = QgsApplication([], gui_flag) # Make sure QGIS_PREFIX_PATH is set in your env if needed! QGIS_APP.initQgis() # Initialize processing processing.Processing.initialize() s = QGIS_APP.showSettings() LOGGER.debug(s) if not locale_match: """Setup internationalisation for the plugin.""" # Save some settings set_general_setting('locale/overrideFlag', True, settings) set_general_setting('locale/userLocale', requested_locale, settings) locale_name = str(requested_locale).split('_')[0] # Also set the system locale to the user overridden local # so that the inasafe library functions gettext will work # .. see:: :py:func:`common.utilities` os.environ['LANG'] = str(locale_name) inasafe_translation_path = os.path.join( safe_dir('i18n'), 'inasafe_' + str(locale_name) + '.qm') if os.path.exists(inasafe_translation_path): if isinstance(QGIS_APP, sip.wrappertype): translator = QTranslator() else: translator = QTranslator(QGIS_APP) result = translator.load(inasafe_translation_path) if not result: message = 'Failed to load translation for %s' % locale_name raise Exception(message) # noinspection PyTypeChecker,PyCallByClass QCoreApplication.installTranslator(translator) # at the end, reload InaSAFE modules so it will get translated too reload_inasafe_modules() if PARENT is None: # noinspection PyPep8Naming PARENT = QtWidgets.QWidget() if CANVAS is None: # noinspection PyPep8Naming CANVAS = QgsMapCanvas(PARENT) CANVAS.resize(QtCore.QSize(400, 400)) if IFACE is None: # QgisInterface is a stub implementation of the QGIS plugin interface # noinspection PyPep8Naming IFACE = QgisInterface(CANVAS) return QGIS_APP, CANVAS, IFACE, PARENT
def test_rendered_items(self): canvas = QgsMapCanvas() canvas.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) canvas.setFrameStyle(0) canvas.resize(600, 400) canvas.setCachingEnabled(True) self.assertEqual(canvas.width(), 600) self.assertEqual(canvas.height(), 400) layer = QgsAnnotationLayer( 'test', QgsAnnotationLayer.LayerOptions( QgsProject.instance().transformContext())) self.assertTrue(layer.isValid()) layer2 = QgsAnnotationLayer( 'test', QgsAnnotationLayer.LayerOptions( QgsProject.instance().transformContext())) self.assertTrue(layer2.isValid()) item = QgsAnnotationPolygonItem( QgsPolygon( QgsLineString([ QgsPoint(11.5, 13), QgsPoint(12, 13), QgsPoint(12, 13.5), QgsPoint(11.5, 13) ]))) item.setSymbol( QgsFillSymbol.createSimple({ 'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2' })) item.setZIndex(1) i1_id = layer.addItem(item) item = QgsAnnotationLineItem( QgsLineString( [QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)])) item.setZIndex(2) i2_id = layer.addItem(item) item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) item.setZIndex(3) i3_id = layer2.addItem(item) layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) layer2.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) canvas.setLayers([layer, layer2]) canvas.setExtent(QgsRectangle(10, 10, 18, 18)) canvas.show() # need to wait until first redraw can occur (note that we first need to wait till drawing starts!) while not canvas.isDrawing(): app.processEvents() canvas.waitWhileRendering() results = canvas.renderedItemResults() self.assertCountEqual([i.itemId() for i in results.renderedItems()], [i1_id, i2_id, i3_id]) # turn off a layer -- the other layer will be rendered direct from the cached version canvas.setLayers([layer2]) while not canvas.isDrawing(): app.processEvents() canvas.waitWhileRendering() results = canvas.renderedItemResults() # only layer2 items should be present in results -- but these MUST be present while layer2 is visible in the canvas, # even though the most recent canvas redraw used a cached version of layer2 and didn't actually have to redraw the layer self.assertEqual([i.itemId() for i in results.renderedItems()], [i3_id]) # turn layer 1 back on canvas.setLayers([layer, layer2]) while not canvas.isDrawing(): app.processEvents() canvas.waitWhileRendering() results = canvas.renderedItemResults() # both layer1 and layer2 items should be present in results -- even though NEITHER of these layers were re-rendered, # and instead we used precached renders of both layers self.assertCountEqual([i.itemId() for i in results.renderedItems()], [i1_id, i2_id, i3_id])
from PyQt4.QtCore import QPoint from PyQt4.QtGui import QColor #from PyQt4.QtTest import QTest from qgis.core import (QgsProviderRegistry, QgsVectorLayer, QgsRasterLayer, QgsMapLayerRegistry, QgsCoordinateReferenceSystem, QgsPoint, QgsRectangle, QgsFeature) from qgis.gui import QgsMapCanvas, QgsMapCanvasLayer from qgisinterface import QgisInterface from utilities_test import globalQgis from bucketfill import BucketFill # Get QGis app handle QGISAPP = globalQgis() # Set form to test against PARENT = QtGui.QWidget() CANVAS = QgsMapCanvas(PARENT) CANVAS.resize(QtCore.QSize(400, 400)) CANVAS.refresh() # QgisInterface is a stub implementation of the QGIS plugin interface IFACE = QgisInterface(CANVAS) GUI_CONTEXT_FLAG = False GEOCRS = 4326 # constant for EPSG:GEOCRS Geographic CRS id GOOGLECRS = 900913 # constant for EPSG:GOOGLECRS Google Mercator id TEST_BOX = (106.773659284, -6.13591899755, 106.776649984, -6.1329282975) def loadLayers(): """ Helper function to load layers into the dialog. """
def test_rendered_item_results_remove_outdated(self): """ Test that outdated results are removed from rendered item result caches """ canvas = QgsMapCanvas() canvas.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) canvas.setFrameStyle(0) canvas.resize(600, 400) canvas.setCachingEnabled(True) self.assertEqual(canvas.width(), 600) self.assertEqual(canvas.height(), 400) layer = QgsAnnotationLayer( 'test', QgsAnnotationLayer.LayerOptions( QgsProject.instance().transformContext())) self.assertTrue(layer.isValid()) layer2 = QgsAnnotationLayer( 'test', QgsAnnotationLayer.LayerOptions( QgsProject.instance().transformContext())) self.assertTrue(layer2.isValid()) item = QgsAnnotationPolygonItem( QgsPolygon( QgsLineString([ QgsPoint(11.5, 13), QgsPoint(12, 13), QgsPoint(12, 13.5), QgsPoint(11.5, 13) ]))) item.setSymbol( QgsFillSymbol.createSimple({ 'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2' })) item.setZIndex(1) i1_id = layer.addItem(item) item = QgsAnnotationLineItem( QgsLineString( [QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)])) item.setZIndex(2) i2_id = layer.addItem(item) item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) item.setZIndex(3) i3_id = layer2.addItem(item) layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) layer2.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) canvas.setLayers([layer, layer2]) canvas.setExtent(QgsRectangle(10, 10, 18, 18)) canvas.show() # need to wait until first redraw can occur (note that we first need to wait till drawing starts!) while not canvas.isDrawing(): app.processEvents() canvas.waitWhileRendering() results = canvas.renderedItemResults() self.assertCountEqual([i.itemId() for i in results.renderedItems()], [i1_id, i2_id, i3_id]) # now try modifying an annotation in the layer -- it will redraw, and we don't want to reuse any previously # cached rendered item results for this layer! item = QgsAnnotationPolygonItem( QgsPolygon( QgsLineString([ QgsPoint(11.5, 13), QgsPoint(12.5, 13), QgsPoint(12.5, 13.5), QgsPoint(11.5, 13) ]))) item.setZIndex(1) layer.replaceItem(i1_id, item) while not canvas.isDrawing(): app.processEvents() canvas.waitWhileRendering() item = QgsAnnotationMarkerItem(QgsPoint(17, 18)) item.setZIndex(3) layer2.replaceItem(i3_id, item) while not canvas.isDrawing(): app.processEvents() canvas.waitWhileRendering() results = canvas.renderedItemResults() items_in_bounds = results.renderedAnnotationItemsInBounds( QgsRectangle(10, 10, 15, 15)) self.assertCountEqual([i.itemId() for i in items_in_bounds], [i1_id, i2_id]) items_in_bounds = results.renderedAnnotationItemsInBounds( QgsRectangle(15, 15, 20, 20)) self.assertCountEqual([i.itemId() for i in items_in_bounds], [i3_id])
def print_layout(project, layout_name, feature_filter: str = None, scales=None, scale=None, **kwargs): """Generate a PDF for an atlas or a report. :param project: The QGIS project. :type project: QgsProject :param layout_name: Name of the layout of the atlas or report. :type layout_name: basestring :param feature_filter: QGIS Expression to use to select the feature. It can return many features, a multiple pages PDF will be returned. This is required to print atlas, not report :type feature_filter: basestring :param scale: A scale to force in the atlas context. Default to None. :type scale: int :param scales: A list of predefined list of scales to force in the atlas context. Default to None. :type scales: list :return: Path to the PDF. :rtype: basestring """ canvas = QgsMapCanvas() bridge = QgsLayerTreeMapCanvasBridge(project.layerTreeRoot(), canvas) bridge.setCanvasLayers() manager = project.layoutManager() master_layout = manager.layoutByName(layout_name) settings = QgsLayoutExporter.PdfExportSettings() atlas = None atlas_layout = None report_layout = None logger = Logger() if not master_layout: raise AtlasPrintException('Layout `{}` not found'.format(layout_name)) if master_layout.layoutType() == QgsMasterLayoutInterface.PrintLayout: for _print_layout in manager.printLayouts(): if _print_layout.name() == layout_name: atlas_layout = _print_layout break atlas = atlas_layout.atlas() if not atlas.enabled(): raise AtlasPrintException('The layout is not enabled for an atlas') layer = atlas.coverageLayer() if feature_filter is None: raise AtlasPrintException( 'EXP_FILTER is mandatory to print an atlas layout') feature_filter = optimize_expression(layer, feature_filter) expression = QgsExpression(feature_filter) if expression.hasParserError(): raise AtlasPrintException( 'Expression is invalid, parser error: {}'.format( expression.parserErrorString())) context = QgsExpressionContext() context.appendScope(QgsExpressionContextUtils.globalScope()) context.appendScope(QgsExpressionContextUtils.projectScope(project)) context.appendScope( QgsExpressionContextUtils.layoutScope(atlas_layout)) context.appendScope(QgsExpressionContextUtils.atlasScope(atlas)) context.appendScope(QgsExpressionContextUtils.layerScope(layer)) expression.prepare(context) if expression.hasEvalError(): raise AtlasPrintException( 'Expression is invalid, eval error: {}'.format( expression.evalErrorString())) atlas.setFilterFeatures(True) atlas.setFilterExpression(feature_filter) if scale: atlas_layout.referenceMap().setAtlasScalingMode( QgsLayoutItemMap.Fixed) atlas_layout.referenceMap().setScale(scale) if scales: atlas_layout.referenceMap().setAtlasScalingMode( QgsLayoutItemMap.Predefined) if Qgis.QGIS_VERSION_INT >= 30900: settings.predefinedMapScales = scales else: atlas_layout.reportContext().setPredefinedScales(scales) if not scales and atlas_layout.referenceMap().atlasScalingMode( ) == QgsLayoutItemMap.Predefined: if Qgis.QGIS_VERSION_INT >= 30900: use_project = project.useProjectScales() map_scales = project.mapScales() else: map_scales = project_scales(project) use_project = len(map_scales) == 0 if not use_project or len(map_scales) == 0: logger.info( 'Map scales not found in project, fetching predefined map scales in global config' ) map_scales = global_scales() if Qgis.QGIS_VERSION_INT >= 30900: settings.predefinedMapScales = map_scales else: atlas_layout.reportContext().setPredefinedScales(map_scales) elif master_layout.layoutType() == QgsMasterLayoutInterface.Report: report_layout = master_layout else: raise AtlasPrintException('The layout is not supported by the plugin') for key, value in kwargs.items(): found = False if atlas_layout: item = atlas_layout.itemById(key.lower()) if isinstance(item, QgsLayoutItemLabel): item.setText(value) found = True logger.info( 'Additional parameters: {} found in layout {}, value {}'.format( key, found, value)) export_path = os.path.join( tempfile.gettempdir(), '{}_{}.pdf'.format(clean_string(layout_name), uuid4())) result, error = QgsLayoutExporter.exportToPdf(atlas or report_layout, export_path, settings) if result != QgsLayoutExporter.Success: raise Exception('Export not generated in QGIS exporter {} : {}'.format( export_path, error)) if not os.path.isfile(export_path): raise Exception( 'Export OK from QGIS, but file not found on the file system : {}'. format(export_path)) return export_path
def testRefreshOnTimer(self): """ test that map canvas refreshes with auto refreshing layers """ canvas = QgsMapCanvas() canvas.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) canvas.setFrameStyle(0) canvas.resize(600, 400) self.assertEqual(canvas.width(), 600) self.assertEqual(canvas.height(), 400) layer = QgsVectorLayer("Polygon?crs=epsg:4326&field=fldtxt:string", "layer", "memory") canvas.setLayers([layer]) canvas.setExtent(QgsRectangle(10, 30, 20, 35)) canvas.show() # need to wait until first redraw can occur (note that we first need to wait till drawing starts!) while not canvas.isDrawing(): app.processEvents() canvas.waitWhileRendering() self.assertTrue( self.canvasImageCheck('empty_canvas', 'empty_canvas', canvas)) # add polygon to layer f = QgsFeature() f.setGeometry(QgsGeometry.fromRect(QgsRectangle(5, 25, 25, 45))) self.assertTrue(layer.dataProvider().addFeatures([f])) # set auto refresh on layer layer.setAutoRefreshInterval(100) layer.setAutoRefreshEnabled(True) timeout = time.time() + 1 # expect canvas to auto refresh... while not canvas.isDrawing(): app.processEvents() self.assertTrue(time.time() < timeout) while canvas.isDrawing(): app.processEvents() self.assertTrue(time.time() < timeout) # add a polygon to layer f = QgsFeature() f.setGeometry(QgsGeometry.fromRect(QgsRectangle(5, 25, 25, 45))) self.assertTrue(layer.dataProvider().addFeatures([f])) # wait for canvas auto refresh while not canvas.isDrawing(): app.processEvents() self.assertTrue(time.time() < timeout) while canvas.isDrawing(): app.processEvents() self.assertTrue(time.time() < timeout) # now canvas should look different... self.assertFalse( self.canvasImageCheck('empty_canvas', 'empty_canvas', canvas, expect_fail=True)) # switch off auto refresh layer.setAutoRefreshEnabled(False) timeout = time.time() + 0.5 while time.time() < timeout: # messy, but only way to check that canvas redraw doesn't occur self.assertFalse(canvas.isDrawing())
def test_custom_widgets(self): """ This test checks if the apply method of customized QgsMapLayerConfigWidgets will be called """ class MyWidget(QgsMapLayerConfigWidget): """ A custom QgsMapLayerConfigWidget """ COUNT = 0 def __init__(self, layer: QgsMapLayer, canvas: QgsMapCanvas, parent: QWidget = None): super().__init__(layer, canvas, parent=parent) def apply(self) -> None: MyWidget.COUNT += 1 class MyFactory(QgsMapLayerConfigWidgetFactory): """ A custom QgsMapLayerConfigWidgetFactory """ COUNT = 0 def __init__(self, title: str, icon: QIcon): super(MyFactory, self).__init__(title, icon) def supportsLayer(self, layer): return True def supportLayerPropertiesDialog(self): return True def createWidget( self, layer: QgsMapLayer, canvas: QgsMapCanvas, dockWidget: bool = ..., parent: typing.Optional[QWidget] = ... ) -> QgsMapLayerConfigWidget: MyFactory.COUNT += 1 w = MyWidget(layer, canvas, parent=parent) return w myFactory = MyFactory('Dummy Factory', QIcon()) myCanvas = QgsMapCanvas() myPath = pathlib.Path( unitTestDataPath('raster')) / 'band1_float32_noct_epsg4326.tif' myRasterLayer = QgsRasterLayer(myPath.as_posix(), myPath.name) assert myRasterLayer.isValid(), f'Raster not loaded {myPath}' dialog = QgsRasterLayerProperties(myRasterLayer, myCanvas) dialog.addPropertiesPageFactory(myFactory) dialog.show() # this should trigger dialog.accept() self.assertEqual( MyFactory.COUNT, 1, msg='Custom QgsMapLayerConfigWidget::createWidget(...) not called') self.assertEqual( MyWidget.COUNT, 1, msg='Custom QgsMapLayerConfigWidget::apply() not called')
def testMapTheme(self): canvas = QgsMapCanvas() canvas.setDestinationCrs(QgsCoordinateReferenceSystem(4326)) canvas.setFrameStyle(0) canvas.resize(600, 400) self.assertEqual(canvas.width(), 600) self.assertEqual(canvas.height(), 400) layer = QgsVectorLayer("Polygon?crs=epsg:4326&field=fldtxt:string", "layer", "memory") # add a polygon to layer f = QgsFeature() f.setGeometry(QgsGeometry.fromRect(QgsRectangle(5, 25, 25, 45))) self.assertTrue(layer.dataProvider().addFeatures([f])) # create a style sym1 = QgsFillSymbol.createSimple({'color': '#ffb200'}) renderer = QgsSingleSymbolRenderer(sym1) layer.setRenderer(renderer) canvas.setLayers([layer]) canvas.setExtent(QgsRectangle(10, 30, 20, 35)) canvas.show() # need to wait until first redraw can occur (note that we first need to wait till drawing starts!) while not canvas.isDrawing(): app.processEvents() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme1', 'theme1', canvas)) # add some styles layer.styleManager().addStyleFromLayer('style1') sym2 = QgsFillSymbol.createSimple({'color': '#00b2ff'}) renderer2 = QgsSingleSymbolRenderer(sym2) layer.setRenderer(renderer2) layer.styleManager().addStyleFromLayer('style2') canvas.refresh() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme2', 'theme2', canvas)) layer.styleManager().setCurrentStyle('style1') canvas.refresh() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme1', 'theme1', canvas)) # OK, so all good with setting/rendering map styles # try setting canvas to a particular theme # make some themes... theme1 = QgsMapThemeCollection.MapThemeRecord() record1 = QgsMapThemeCollection.MapThemeLayerRecord(layer) record1.currentStyle = 'style1' record1.usingCurrentStyle = True theme1.setLayerRecords([record1]) theme2 = QgsMapThemeCollection.MapThemeRecord() record2 = QgsMapThemeCollection.MapThemeLayerRecord(layer) record2.currentStyle = 'style2' record2.usingCurrentStyle = True theme2.setLayerRecords([record2]) QgsProject.instance().mapThemeCollection().insert('theme1', theme1) QgsProject.instance().mapThemeCollection().insert('theme2', theme2) canvas.setTheme('theme2') canvas.refresh() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme2', 'theme2', canvas)) canvas.setTheme('theme1') canvas.refresh() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme1', 'theme1', canvas)) # add another layer layer2 = QgsVectorLayer("Polygon?crs=epsg:4326&field=fldtxt:string", "layer2", "memory") f = QgsFeature() f.setGeometry(QgsGeometry.fromRect(QgsRectangle(5, 25, 25, 45))) self.assertTrue(layer2.dataProvider().addFeatures([f])) # create a style sym1 = QgsFillSymbol.createSimple({'color': '#b2ff00'}) renderer = QgsSingleSymbolRenderer(sym1) layer2.setRenderer(renderer) # rerender canvas - should NOT show new layer canvas.refresh() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme1', 'theme1', canvas)) # test again - this time refresh all layers canvas.refreshAllLayers() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme1', 'theme1', canvas)) # add layer 2 to theme1 record3 = QgsMapThemeCollection.MapThemeLayerRecord(layer2) theme1.setLayerRecords([record3]) QgsProject.instance().mapThemeCollection().update('theme1', theme1) canvas.refresh() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme3', 'theme3', canvas)) # change the appearance of an active style layer2.styleManager().addStyleFromLayer('original') layer2.styleManager().addStyleFromLayer('style4') record3.currentStyle = 'style4' record3.usingCurrentStyle = True theme1.setLayerRecords([record3]) QgsProject.instance().mapThemeCollection().update('theme1', theme1) canvas.refresh() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme3', 'theme3', canvas)) layer2.styleManager().setCurrentStyle('style4') sym3 = QgsFillSymbol.createSimple({'color': '#b200b2'}) layer2.renderer().setSymbol(sym3) canvas.refresh() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme4', 'theme4', canvas)) # try setting layers while a theme is in place canvas.setLayers([layer]) canvas.refresh() # should be no change... setLayers should be ignored if canvas is following a theme! canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme4', 'theme4', canvas)) # setLayerStyleOverrides while theme is in place canvas.setLayerStyleOverrides({layer2.id(): 'original'}) # should be no change... setLayerStyleOverrides should be ignored if canvas is following a theme! canvas.refresh() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme4', 'theme4', canvas)) # clear theme canvas.setTheme('') canvas.refresh() canvas.waitWhileRendering() # should be different - we should now render project layers self.assertFalse(self.canvasImageCheck('theme4', 'theme4', canvas))
def setupUi(self, MainWindow): self.actionPan = QAction("Pan", MainWindow) self.actionPan.setShortcut("Ctrl+1") self.actionPan.setCheckable(True) self.actionQuit = QAction("Quit", MainWindow) self.actionQuit.setShortcut(QKeySequence.Quit) self.actionZoomIn = QAction("Zoom In", MainWindow) self.actionZoomIn.setShortcut(QKeySequence.ZoomIn) self.actionZoomOut = QAction("Zoom Out", MainWindow) self.actionZoomOut.setShortcut(QKeySequence.ZoomOut) self.actionEdit = QAction("Edit Mode", MainWindow) self.actionEdit.setShortcut("Ctrl+2") self.actionEdit.setCheckable(True) self.actionAddFlowPath = QAction("Add FlowPath", MainWindow) self.actionAddFlowPath.setShortcut("Ctrl+A") self.actionAddFlowPath.setCheckable(True) self.actionEditFlowPath = QAction("Edit FlowPath", MainWindow) self.actionEditFlowPath.setShortcut("Ctrl+E") self.actionEditFlowPath.setCheckable(True) self.actionDeleteFlowPath = QAction("Delete FlowPath", MainWindow) self.actionDeleteFlowPath.setShortcut("Ctrl+D") self.actionDeleteFlowPath.setCheckable(True) MainWindow.setObjectName("MainWindow") MainWindow.resize(986, 620) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout_3 = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout_3.setObjectName("gridLayout_3") self.verticalLayout_4 = QtWidgets.QVBoxLayout() self.verticalLayout_4.setObjectName("verticalLayout_4") self.gridLayout_2 = QtWidgets.QGridLayout() self.gridLayout_2.setSizeConstraint(QtWidgets.QLayout.SetFixedSize) self.gridLayout_2.setObjectName("gridLayout_2") self.QgsMapCanvas = QgsMapCanvas(self.centralwidget) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(3) sizePolicy.setVerticalStretch(3) sizePolicy.setHeightForWidth( self.QgsMapCanvas.sizePolicy().hasHeightForWidth()) self.QgsMapCanvas.setSizePolicy(sizePolicy) self.QgsMapCanvas.setObjectName("QgsMapCanvas") self.gridLayout_2.addWidget(self.QgsMapCanvas, 0, 2, 1, 1) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem1) self.gridLayout_2.addLayout(self.horizontalLayout, 3, 2, 1, 1) self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.toolButton = QtWidgets.QToolButton(self.centralwidget) self.toolButton.setText("Zoom In") self.toolButton.setDefaultAction(self.actionZoomIn) self.toolButton.setObjectName("toolButton") self.horizontalLayout_2.addWidget(self.toolButton) self.toolButton_4 = QtWidgets.QToolButton(self.centralwidget) self.toolButton_4.setText("Zoom Out") self.toolButton_4.setDefaultAction(self.actionZoomOut) self.toolButton_4.setObjectName("toolButton_4") self.horizontalLayout_2.addWidget(self.toolButton_4) self.toolButton_3 = QtWidgets.QToolButton(self.centralwidget) self.toolButton_3.setText("Pan") self.toolButton_3.setDefaultAction(self.actionPan) self.toolButton_3.setObjectName("toolButton_3") self.horizontalLayout_2.addWidget(self.toolButton_3) self.toolButton_2 = QtWidgets.QToolButton(self.centralwidget) self.toolButton_2.setText("Edit") self.toolButton_2.setDefaultAction(self.actionEdit) self.toolButton_2.setObjectName("toolButton_2") self.horizontalLayout_2.addWidget(self.toolButton_2) self.toolButton_5 = QtWidgets.QToolButton(self.centralwidget) self.toolButton_5.setText("Add FlowPath") self.toolButton_5.setDefaultAction(self.actionAddFlowPath) self.toolButton_5.setObjectName("toolButton_5") self.horizontalLayout_2.addWidget(self.toolButton_5) self.toolButton_6 = QtWidgets.QToolButton(self.centralwidget) self.toolButton_6.setText("Edit FlowPath") self.toolButton_6.setDefaultAction(self.actionEditFlowPath) self.toolButton_6.setObjectName("toolButton_6") self.horizontalLayout_2.addWidget(self.toolButton_6) self.toolButton_7 = QtWidgets.QToolButton(self.centralwidget) self.toolButton_7.setText("Delete FlowPath") self.toolButton_7.setDefaultAction(self.actionDeleteFlowPath) self.toolButton_7.setObjectName("toolButton_7") self.horizontalLayout_2.addWidget(self.toolButton_7) spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_2.addItem(spacerItem2) self.label_2 = QtWidgets.QLabel() font = QtGui.QFont() font.setPointSize(8) self.label_2.setFont(font) self.label_2.setAlignment(QtCore.Qt.AlignVCenter) self.label_2.setText( "© <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors" ) self.label_2.setOpenExternalLinks(True) self.label_2.setObjectName("label_2") self.horizontalLayout_2.addWidget(self.label_2) self.gridLayout_2.addLayout(self.horizontalLayout_2, 1, 2, 1, 1) self.verticalLayout_2 = QtWidgets.QVBoxLayout() self.verticalLayout_2.setObjectName("verticalLayout_2") spacerItem4 = QtWidgets.QSpacerItem( 20, 200, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.MinimumExpanding) self.verticalLayout_2.addItem(spacerItem4) spacerItem5 = QtWidgets.QSpacerItem(20, 150, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred) self.verticalLayout_2.addItem(spacerItem5) self.gridLayout_2.addLayout(self.verticalLayout_2, 0, 0, 1, 1) self.verticalLayout_4.addLayout(self.gridLayout_2) self.gridLayout_3.addLayout(self.verticalLayout_4, 0, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 986, 21)) self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(self.menubar) self.menuFile.setObjectName("menuFile") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.actionLoad_File = QtWidgets.QAction(MainWindow) self.actionLoad_File.setObjectName("actionLoad_File") self.actionPrint = QtWidgets.QAction(MainWindow) self.actionPrint.setObjectName("actionPrint") self.actionDeleteLayer = QtWidgets.QAction(MainWindow) self.actionDeleteLayer.setObjectName("actionDeleteLayer") self.menuFile.addAction(self.actionDeleteLayer) self.menuFile.addAction(self.actionLoad_File) self.menuFile.addAction(self.actionPrint) self.menubar.addAction(self.menuFile.menuAction()) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow)