예제 #1
0
    def testCancel(self):
        f = QgsFeedback()
        self.assertFalse(f.isCanceled())

        cancel_spy = QSignalSpy(f.canceled)

        f.cancel()
        self.assertTrue(f.isCanceled())
        self.assertEqual(len(cancel_spy), 1)
예제 #2
0
    def testProgress(self):
        f = QgsFeedback()
        self.assertEqual(f.progress(), 0.0)

        progress_spy = QSignalSpy(f.progressChanged)

        f.setProgress(25)
        self.assertEqual(f.progress(), 25.0)
        self.assertEqual(len(progress_spy), 1)
        self.assertEqual(progress_spy[0][0], 25.0)
예제 #3
0
    def testCancel(self):
        f = QgsFeedback()
        self.assertFalse(f.isCanceled())

        cancel_spy = QSignalSpy(f.canceled)

        f.cancel()
        self.assertTrue(f.isCanceled())
        self.assertEqual(len(cancel_spy), 1)
예제 #4
0
    def testProcessedCount(self):
        f = QgsFeedback()
        self.assertEqual(f.processedCount(), 0)

        processed_spy = QSignalSpy(f.processedCountChanged)

        f.setProcessedCount(25)
        self.assertEqual(f.processedCount(), 25)
        self.assertEqual(len(processed_spy), 1)
        self.assertEqual(processed_spy[0][0], 25)
예제 #5
0
    def testProgress(self):
        f = QgsFeedback()
        self.assertEqual(f.progress(), 0.0)

        progress_spy = QSignalSpy(f.progressChanged)

        f.setProgress(25)
        self.assertEqual(f.progress(), 25.0)
        self.assertEqual(len(progress_spy), 1)
        self.assertEqual(progress_spy[0][0], 25.0)
예제 #6
0
    def test_process_err(self):
        def std_out(ba):
            std_out.val += ba.data().decode('UTF-8')

        std_out.val = ''

        def std_err(ba):
            std_err.val += ba.data().decode('UTF-8')

        std_err.val = ''

        p = QgsBlockingProcess('ogrinfo', [])
        p.setStdOutHandler(std_out)
        p.setStdErrHandler(std_err)

        f = QgsFeedback()
        self.assertEqual(p.run(f), 1)
        self.assertIn('Usage', std_out.val)
        self.assertIn('FAILURE', std_err.val)
예제 #7
0
    def test_process_ok(self):
        def std_out(ba):
            std_out.val += ba.data().decode('UTF-8')

        std_out.val = ''

        def std_err(ba):
            std_err.val += ba.data().decode('UTF-8')

        std_err.val = ''

        p = QgsBlockingProcess('ogrinfo', ['--version'])
        p.setStdOutHandler(std_out)
        p.setStdErrHandler(std_err)

        f = QgsFeedback()
        self.assertEqual(p.run(f), 0)
        self.assertIn('GDAL', std_out.val)
        self.assertEqual(std_err.val, '')
예제 #8
0
    def testRunChecks(self):
        registry = QgsValidityCheckRegistry()
        res1 = QgsValidityCheckResult()
        res1.type = QgsValidityCheckResult.Warning
        res1.title = 'test'
        res1.detailedDescription = 'blah blah'

        c1 = TestCheck('c1', 'my check', 1, [res1])
        registry.addCheck(c1)

        res2 = QgsValidityCheckResult()
        res2.type = QgsValidityCheckResult.Critical
        res2.title = 'test2'
        res2.detailedDescription = 'blah blah2'
        c2 = TestCheck('c2', 'my check2', 2, [res2])
        registry.addCheck(c2)

        res3 = QgsValidityCheckResult()
        res3.type = QgsValidityCheckResult.Warning
        res3.title = 'test3'
        res3.detailedDescription = 'blah blah3'
        res4 = QgsValidityCheckResult()
        res4.type = QgsValidityCheckResult.Warning
        res4.title = 'test4'
        res4.detailedDescription = 'blah blah4'
        c3 = TestCheck('c3', 'my check3', 1, [res3, res4])
        registry.addCheck(c3)

        context = TestContext()
        feedback = QgsFeedback()
        self.assertFalse(registry.runChecks(0, context, feedback))

        self.assertEqual([r.type for r in registry.runChecks(1, context, feedback)],
                         [QgsValidityCheckResult.Warning, QgsValidityCheckResult.Warning,
                          QgsValidityCheckResult.Warning])
        self.assertEqual([r.title for r in registry.runChecks(1, context, feedback)], ['test', 'test3', 'test4'])
        self.assertEqual([r.detailedDescription for r in registry.runChecks(1, context, feedback)],
                         ['blah blah', 'blah blah3', 'blah blah4'])

        self.assertEqual([r.type for r in registry.runChecks(2, context, feedback)], [QgsValidityCheckResult.Critical])
        self.assertEqual([r.title for r in registry.runChecks(2, context, feedback)], ['test2'])
        self.assertEqual([r.detailedDescription for r in registry.runChecks(2, context, feedback)], ['blah blah2'])
예제 #9
0
    def _start_process(self):
        """Make some stuff before launching the process."""
        QApplication.setOverrideCursor(Qt.WaitCursor)

        self.dialog.feedback_process = QgsFeedback()

        if self.panel == Panels.QuickQuery:
            self.dialog.button_show_query.setDisabled(True)

        if self.panel == Panels.Query:
            self.dialog.button_generate_query.setDisabled(True)

        self.dialog.execute_buttons[self.panel].setCurrentIndex(1)
        if self.dialog.output_directories[self.panel]:
            self.dialog.output_directories[self.panel].setDisabled(True)
        self.dialog.progress_bar.setMinimum(0)
        self.dialog.progress_bar.setMaximum(0)
        self.dialog.progress_bar.setValue(0)
        self.dialog.progress_text.setText('')
        QApplication.processEvents()
예제 #10
0
    def testExecuteSqlCancel(self):
        """Test that feedback can cancel an executeSql query"""

        if hasattr(self, 'slowQuery'):

            md = QgsProviderRegistry.instance().providerMetadata(self.providerKey)
            conn = md.createConnection(self.uri, {})
            feedback = QgsFeedback()

            def _run(task):
                conn.executeSql(self.slowQuery, feedback=feedback)

            def _cancel():
                feedback.cancel()

            start = time.time()
            QtCore.QTimer.singleShot(500, _cancel)
            task = QgsTask.fromFunction('test long running query', _run)
            QgsApplication.taskManager().addTask(task)
            while task.status() not in [QgsTask.Complete, QgsTask.Terminated]:
                QgsApplication.processEvents()
            end = time.time()
            self.assertTrue(end - start < 1)
예제 #11
0
    def open_style(input_file):  # pylint: disable=too-many-locals,too-many-branches,too-many-statements
        """
        Opens a .style file
        """

        if not Extractor.is_mdb_tools_binary_available():
            bar = iface.messageBar()
            widget = bar.createMessage('SLYR', "MDB Tools utility not found")
            settings_button = QPushButton("Configure…", pressed=partial(open_settings, widget))
            widget.layout().addWidget(settings_button)
            bar.pushWidget(widget, Qgis.Critical)
            return True

        style = QgsStyle()
        style.createMemoryDatabase()

        symbol_names = set()

        def make_name_unique(name):
            """
            Ensures that the symbol name is unique (in a case insensitive way)
            """
            counter = 0
            candidate = name
            while candidate.lower() in symbol_names:
                # make name unique
                if counter == 0:
                    candidate += '_1'
                else:
                    candidate = candidate[:candidate.rfind('_') + 1] + str(counter)
                counter += 1
            symbol_names.add(candidate.lower())
            return candidate

        feedback = QgsFeedback()

        progress_dialog = QProgressDialog("Loading style database…", "Abort", 0, 100, None)
        progress_dialog.setWindowTitle("Loading Style")

        def progress_changed(progress):
            """
            Handles feedback to progress dialog bridge
            """
            progress_dialog.setValue(progress)
            iters = 0
            while QCoreApplication.hasPendingEvents() and iters < 100:
                QCoreApplication.processEvents()
                iters += 1

        feedback.progressChanged.connect(progress_changed)

        def cancel():
            """
            Slot to cancel the import
            """
            feedback.cancel()

        progress_dialog.canceled.connect(cancel)
        unreadable = []
        warnings = set()
        errors = set()

        types_to_extract = [Extractor.FILL_SYMBOLS, Extractor.LINE_SYMBOLS, Extractor.MARKER_SYMBOLS,
                            Extractor.COLOR_RAMPS,
                            Extractor.TEXT_SYMBOLS, Extractor.LABELS, Extractor.MAPLEX_LABELS, Extractor.AREA_PATCHES,
                            Extractor.LINE_PATCHES]

        type_percent = 100 / len(types_to_extract)

        for type_index, symbol_type in enumerate(types_to_extract):

            try:
                raw_symbols = Extractor.extract_styles(input_file, symbol_type)
            except MissingBinaryException:
                show_warning('MDB Tools utility not found', 'Convert style',
                             'The MDB tools "mdb-export" utility is required to convert .style databases. Please setup a path to the MDB tools utility in the SLYR options panel.',
                             level=Qgis.Critical)
                progress_dialog.deleteLater()
                return True

            if feedback.isCanceled():
                break

            for index, raw_symbol in enumerate(raw_symbols):
                feedback.setProgress(index / len(raw_symbols) * type_percent + type_percent * type_index)
                if feedback.isCanceled():
                    break
                name = raw_symbol[Extractor.NAME]
                tags = raw_symbol[Extractor.TAGS].split(';')

                if symbol_type in (
                        Extractor.AREA_PATCHES, Extractor.LINE_PATCHES, Extractor.TEXT_SYMBOLS, Extractor.MAPLEX_LABELS,
                        Extractor.LABELS):
                    if symbol_type == Extractor.AREA_PATCHES:
                        type_string = 'area patches'
                    elif symbol_type == Extractor.LINE_PATCHES:
                        type_string = 'line patches'
                    elif symbol_type == Extractor.TEXT_SYMBOLS:
                        type_string = 'text symbols'
                    elif symbol_type == Extractor.MAPLEX_LABELS:
                        type_string = 'maplex labels'
                    elif symbol_type == Extractor.LABELS:
                        type_string = 'labels'
                    else:
                        type_string = ''

                    unreadable.append('<b>{}</b>: {} conversion requires a licensed version of the SLYR plugin'.format(
                        html.escape(name), type_string))
                    continue

                unique_name = make_name_unique(name)

                handle = BytesIO(raw_symbol[Extractor.BLOB])
                stream = Stream(handle)
                stream.allow_shortcuts = False

                try:
                    symbol = stream.read_object()
                except UnreadableSymbolException as e:
                    e = 'Unreadable object: {}'.format(e)
                    unreadable.append('<b>{}</b>: {}'.format(html.escape(name), html.escape(str(e))))
                    continue
                except NotImplementedException as e:
                    unreadable.append('<b>{}</b>: {}'.format(html.escape(name), html.escape(str(e))))
                    continue
                except UnsupportedVersionException as e:
                    e = 'Unsupported version: {}'.format(e)
                    unreadable.append('<b>{}</b>: {}'.format(html.escape(name), html.escape(str(e))))
                    continue
                except UnknownClsidException as e:
                    unreadable.append('<b>{}</b>: {}'.format(html.escape(name), html.escape(str(e))))
                    continue
                except UnreadablePictureException as e:
                    unreadable.append('<b>{}</b>: {}'.format(html.escape(name), html.escape(str(e))))
                    continue

                context = Context()
                context.symbol_name = unique_name

                def unsupported_object_callback(msg, level=Context.WARNING):
                    if level == Context.WARNING:
                        warnings.add('<b>{}</b>: {}'.format(html.escape(unique_name), html.escape(msg)))
                    elif level == Context.CRITICAL:
                        errors.add('<b>{}</b>: {}'.format(html.escape(unique_name), html.escape(msg)))

                context.unsupported_object_callback = unsupported_object_callback
                # context.style_folder, _ = os.path.split(output_file)

                try:
                    qgis_symbol = SymbolConverter.Symbol_to_QgsSymbol(symbol, context)
                except NotImplementedException as e:
                    unreadable.append('<b>{}</b>: {}'.format(html.escape(name), html.escape(str(e))))
                    continue
                except UnreadablePictureException as e:
                    unreadable.append('<b>{}</b>: {}'.format(html.escape(name), html.escape(str(e))))
                    continue

                if isinstance(qgis_symbol, QgsSymbol):
                    # self.check_for_missing_fonts(qgis_symbol, feedback)
                    style.addSymbol(unique_name, qgis_symbol, True)
                elif isinstance(qgis_symbol, QgsColorRamp):
                    style.addColorRamp(unique_name, qgis_symbol, True)

                if tags:
                    if isinstance(qgis_symbol, QgsSymbol):
                        assert style.tagSymbol(QgsStyle.SymbolEntity, unique_name, tags)
                    elif isinstance(qgis_symbol, QgsColorRamp):
                        assert style.tagSymbol(QgsStyle.ColorrampEntity, unique_name, tags)
        progress_dialog.deleteLater()
        if feedback.isCanceled():
            return True

        if errors or unreadable or warnings:
            message = ''
            if unreadable:
                message = '<p>The following symbols could not be converted:</p>'
                message += '<ul>'
                for w in unreadable:
                    message += '<li>{}</li>'.format(w.replace('\n', '<br>'))
                message += '</ul>'

            if errors:
                message += '<p>The following errors were generated while converting symbols:</p>'
                message += '<ul>'
                for w in errors:
                    message += '<li>{}</li>'.format(w.replace('\n', '<br>'))
                message += '</ul>'

            if warnings:
                message += '<p>The following warnings were generated while converting symbols:</p>'
                message += '<ul>'
                for w in warnings:
                    message += '<li>{}</li>'.format(w.replace('\n', '<br>'))
                message += '</ul>'

            show_warning('style could not be completely converted', 'Convert style', message,
                         level=Qgis.Critical if (unreadable or errors) else Qgis.Warning)

        if Qgis.QGIS_VERSION_INT >= 30800:
            dlg = QgsStyleManagerDialog(style, readOnly=True)
            dlg.setFavoritesGroupVisible(False)
            dlg.setSmartGroupsVisible(False)
            fi = QFileInfo(input_file)
            dlg.setBaseStyleName(fi.baseName())
        else:
            dlg = QgsStyleManagerDialog(style)
        dlg.exec_()
        return True
예제 #12
0
def processing(options, f, progressBar, progressMessage):
    '''
    Select trees which are on the contour of the forest and isolated trees.
    '''
    # Export Grid contour and isolated to crowns values
    forestSelectedPath = options['dst'] + 'tif/' + f + \
        '_forest_selected.tif'
    crownsPath = options['dst'] + 'shp/' + f + '_crowns.shp'
    # crownsStatsPath = options['dst'] + 'shp/' + f + '_crowns_stats.shp'
    outputDir = options["dst"]
    fileTxt = open(outputDir + "/log.txt", "a")
    fileTxt.write("gridstatisticsforpolygons started\n")
    fileTxt.close()

    crowns = QgsVectorLayer(crownsPath, "crowns", "ogr")
    inputStatRaster = QgsRasterLayer(forestSelectedPath, "forestSelected")
    z_stat = QgsZonalStatistics(crowns, inputStatRaster, '_', 1,
                                QgsZonalStatistics.Max)

    result_z_stat = z_stat.calculateStatistics(QgsFeedback())

    outputDir = options["dst"]
    fileTxt = open(outputDir + "/log.txt", "a")
    fileTxt.write("gridstatisticsforpolygons passed\n")
    fileTxt.close()
    # crowns = QgsVectorLayer(crownsStatsPath, 'Crowns stats', 'ogr')
    crowns.selectByExpression('"_max"=1.0')
    selected_array = crowns.getValues("N", True)
    crowns.invertSelection()
    unselected_array = crowns.getValues("N", True)
    unselected_crowns_ids = crowns.getValues("$id", True)
    unselected_top_ids = crowns.getValues('"N" - 1', True)
    crowns.dataProvider().deleteFeatures(unselected_crowns_ids[0])

    treetopsPath = options['dst'] + 'shp/' + f + '_treetops.shp'
    treetops = QgsVectorLayer(treetopsPath, 'Tree tops', 'ogr')

    treetops.dataProvider().deleteFeatures(unselected_top_ids[0])

    treetopsSelectedPath = options['dst'] + 'shp/' + f + \
        '_treetops_selected.shp'
    crownsSelectedPath = options['dst'] + 'shp/' + f + '_crowns_selected.shp'
    treetopsTrianglesPath = options['dst'] + 'shp/' + f + \
        '_treetops_triangles.shp'

    outputDir = options["dst"]
    fileTxt = open(outputDir + "/log.txt", "a")
    fileTxt.write("advancedpythonfieldcalculator started\n")
    fileTxt.close()

    treetops.dataProvider().addAttributes([QgsField('N', QVariant.Int)])
    treetops.updateFields()
    treetops.startEditing()
    for treetop in treetops.getFeatures():
        treetops.changeAttributeValue(treetop.id(),
                                      treetop.fieldNameIndex('N'),
                                      treetop.id())
    treetops.commitChanges()

    outputDir = options["dst"]
    fileTxt = open(outputDir + "/log.txt", "a")
    fileTxt.write("joinattributesbylocation started\n")
    fileTxt.close()

    # Adapted from https://github.com/qgis/QGIS-Processing
    # TODO: replace by native QGIS c++ algo when available...

    crowns.dataProvider().addAttributes([QgsField('tid', QVariant.Int)])
    crowns.updateFields()
    crowns.startEditing()
    fcount = crowns.featureCount()
    counter = 0
    for crown in crowns.getFeatures():
        counter += 1
        progressBar.setValue(100 + int(counter * (600 / fcount)))
        progressMessage.setText('Joining crown ' + str(counter) + '/' +
                                str(fcount))
        request = QgsFeatureRequest()
        request.setFilterRect(crown.geometry().boundingBox())
        dp = treetops.dataProvider()
        for r in dp.getFeatures(request):
            if crown.geometry().intersects(r.geometry()):
                crowns.changeAttributeValue(crown.id(),
                                            crown.fieldNameIndex('tid'),
                                            r.id())
    crowns.commitChanges()

    fileTxt = open(outputDir + "/log.txt", "a")
    fileTxt.write("delaunaytriangulation started\n")
    fileTxt.close()

    # delaunay triangulation Adapted from official Python plugin
    # TODO: replace by native QGIS c++ algo when available...

    fields = QgsFields()
    fields.append(QgsField('POINTA', QVariant.Double, '', 24, 15))
    fields.append(QgsField('POINTB', QVariant.Double, '', 24, 15))
    fields.append(QgsField('POINTC', QVariant.Double, '', 24, 15))
    crs = QgsCoordinateReferenceSystem('EPSG:2056')
    triangleFile = QgsVectorFileWriter(treetopsTrianglesPath, 'utf-8', fields,
                                       QgsWkbTypes.Polygon, crs,
                                       'ESRI Shapefile')

    pts = []
    ptDict = {}
    ptNdx = -1
    c = voronoi.Context()
    features = treetops.getFeatures()
    total = 100.0 / treetops.featureCount() if treetops.featureCount() else 0
    progressMessage.setText('Starting triangulation...')
    for current, inFeat in enumerate(features):
        geom = QgsGeometry(inFeat.geometry())
        if geom.isNull():
            continue
        if geom.isMultipart():
            points = geom.asMultiPoint()
        else:
            points = [geom.asPoint()]
        for n, point in enumerate(points):
            x = point.x()
            y = point.y()
            pts.append((x, y))
            ptNdx += 1
            ptDict[ptNdx] = (inFeat.id(), n)
    progressMessage.setText('Triangulation step 1 ok')

    if len(pts) < 3:
        raise QgsProcessingException(
            'Input file should contain at least 3 points. Choose '
            'another file and try again.')

    uniqueSet = set(item for item in pts)
    ids = [pts.index(item) for item in uniqueSet]
    sl = voronoi.SiteList([voronoi.Site(*i) for i in uniqueSet])
    c.triangulate = True
    voronoi.voronoi(sl, c)
    triangles = c.triangles
    feat = QgsFeature()

    total = 100.0 / len(triangles) if triangles else 1
    for current, triangle in enumerate(triangles):

        indices = list(triangle)
        indices.append(indices[0])
        polygon = []

        attrs = []
        step = 0
        for index in indices:
            fid, n = ptDict[ids[index]]
            request = QgsFeatureRequest().setFilterFid(fid)
            inFeat = next(treetops.getFeatures(request))
            geom = QgsGeometry(inFeat.geometry())
            point = QgsPoint(geom.asPoint())

            polygon.append(point)
            if step <= 3:
                attrs.append(ids[index])
            step += 1

        linestring = QgsLineString(polygon)
        poly = QgsPolygon()
        poly.setExteriorRing(linestring)
        feat.setAttributes(attrs)
        geometry = QgsGeometry().fromWkt(poly.asWkt())
        feat.setGeometry(geometry)
        triangleFile.addFeature(feat)
    progressMessage.setText('Triangulation terminated')

    #  Remove triangles with perimeter higher than threshold
    triangles = QgsVectorLayer(treetopsTrianglesPath, 'triangles', 'ogr')
    maxPeri = str(options['MaxTrianglePerimeter'])
    triangles.selectByExpression('$perimeter > ' + maxPeri)
    triangles_to_delete_ids = triangles.getValues("$id", True)
    triangles.dataProvider().deleteFeatures(triangles_to_delete_ids[0])

    outputDir = options["dst"]
    fileTxt = open(outputDir + "/log.txt", "a")
    fileTxt.write("treeSelector passed\n")
    fileTxt.close()
    progressMessage.setText('Starting convexhull computing...')
예제 #13
0
    def test_process_env(self):
        """
        Test that process inherits system environment correctly
        """
        temp_folder = tempfile.mkdtemp()

        script_file = os.path.join(temp_folder, 'process_env.sh')
        with open(script_file, 'wt') as f:
            f.write('echo $my_var')

        os.chmod(script_file, 0o775)

        def std_out(ba):
            std_out.val += ba.data().decode('UTF-8')

        std_out.val = ''

        def std_err(ba):
            std_err.val += ba.data().decode('UTF-8')

        std_err.val = ''

        # environment variable not set:
        p = QgsBlockingProcess('sh', [script_file])
        p.setStdOutHandler(std_out)
        p.setStdErrHandler(std_err)

        f = QgsFeedback()
        self.assertEqual(p.run(f), 0)
        self.assertEqual(p.exitStatus(), QProcess.NormalExit)
        self.assertFalse(std_out.val.strip())
        self.assertFalse(std_err.val.strip())

        # set environment variable
        os.environ['my_var'] = 'my test variable'
        std_out.val = ''
        std_err.val = ''
        p = QgsBlockingProcess('sh', [script_file])
        p.setStdOutHandler(std_out)
        p.setStdErrHandler(std_err)

        f = QgsFeedback()
        self.assertEqual(p.run(f), 0)
        self.assertEqual(p.exitStatus(), QProcess.NormalExit)
        self.assertEqual(std_out.val.strip(), 'my test variable')
        self.assertFalse(std_err.val.strip())

        # test python changing path

        script_file = os.path.join(temp_folder, 'process_env_path.sh')
        with open(script_file, 'wt') as f:
            f.write('echo $PATH')

        prev_path_val = os.getenv('PATH')
        new_path = "{}{}{}".format('/my_test/folder', os.pathsep,
                                   prev_path_val)
        os.environ['PATH'] = new_path

        std_out.val = ''
        std_err.val = ''
        p = QgsBlockingProcess('sh', [script_file])
        p.setStdOutHandler(std_out)
        p.setStdErrHandler(std_err)

        f = QgsFeedback()
        self.assertEqual(p.run(f), 0)
        self.assertEqual(p.exitStatus(), QProcess.NormalExit)
        self.assertEqual(std_out.val.strip(), new_path)
        self.assertFalse(std_err.val.strip())
class ExportTask(ScenarioBaseTask):
    """
    A background task for exporting electorates, meshblock assignments
    """

    GN = 'GN'
    GS = 'GS'
    M = 'M'

    def __init__(self, task_name: str, dest_file: str,
                 electorate_registry: LinzElectoralDistrictRegistry,
                 meshblock_layer: QgsVectorLayer,
                 meshblock_number_field_name: str,
                 scenario_registry: ScenarioRegistry, scenario,
                 user_log_layer: QgsVectorLayer):
        """
        Constructor for ExportTask
        :param task_name: user-visible, translated name for task
        :param dest_file: destination filename
        :param electorate_registry: electorate registry
        :param meshblock_layer: meshblock layer
        :param meshblock_number_field_name: name of meshblock number field
        :param scenario_registry: scenario registry
        :param scenario: target scenario id to switch to
        :param user_log_layer: user log layer
        """
        self.electorate_registry = electorate_registry
        super().__init__(
            task_name=task_name,
            electorate_layer=self.electorate_registry.source_layer,
            meshblock_layer=meshblock_layer,
            meshblock_number_field_name=meshblock_number_field_name,
            scenario_registry=scenario_registry,
            scenario=scenario,
            task=None)
        self.dest_file = dest_file
        self.message = None
        self.user_log_layer = user_log_layer

        self.feedback = QgsFeedback()

    def cancel(self):
        """
        Cancels the export
        """
        super().cancel()
        self.feedback.cancel()

    def run(self):  # pylint: disable=missing-docstring,too-many-locals,too-many-return-statements,too-many-branches,too-many-statements
        try:
            electorate_geometries, electorate_attributes = self.calculate_new_electorates(
            )
        except CanceledException:
            return False

        # we also need a dictionary of meshblock number to all electorate types
        meshblock_electorates = {}

        electorate_features = []

        for electorate_feature_id, attributes in electorate_attributes.items():
            if self.isCanceled():
                return False

            electorate_code = attributes[self.ELECTORATE_CODE]
            geometry = electorate_geometries[electorate_feature_id]

            meshblocks = attributes[self.MESHBLOCKS]
            electorate_type = attributes[self.ELECTORATE_TYPE]
            name = attributes[self.ELECTORATE_NAME]

            for m in meshblocks:
                meshblock_number = m[self.meshblock_number_idx]
                if meshblock_number not in meshblock_electorates:
                    meshblock_electorates[meshblock_number] = {}
                meshblock_electorates[meshblock_number][
                    electorate_type] = electorate_code

                if self.isCanceled():
                    return False

            electorate_feature = QgsFeature()
            electorate_feature.setGeometry(geometry)
            electorate_feature.setAttributes(
                [electorate_type, electorate_code, name])
            electorate_features.append(electorate_feature)

        electorate_layer = QgsVectorLayer(
            "Polygon?crs=EPSG:2193&field=type:string(2)&field=code:string&field=name:string",
            "source", "memory")
        if not electorate_layer.dataProvider().addFeatures(
                electorate_features):
            return False

        if self.isCanceled():
            return False

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = 'GPKG'
        options.layerName = 'electorates'
        options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteFile
        options.feedback = self.feedback
        error, self.message = QgsVectorFileWriter.writeAsVectorFormat(
            electorate_layer, self.dest_file, options)
        if error:
            return False
        if self.isCanceled():
            return False

        layer = QgsVectorLayer(
            "NoGeometry?field=meshblock_number:int&field=gn_code:string&field=gs_code:string&field=m_code:string",
            "source", "memory")
        meshblock_features = []
        for meshblock_number, electorates in meshblock_electorates.items():
            f = QgsFeature()
            gn = electorates[self.GN] if self.GN in electorates else NULL
            gs = electorates[self.GS] if self.GS in electorates else NULL
            m = electorates[self.M] if self.M in electorates else NULL
            f.setAttributes([meshblock_number, gn, gs, m])
            meshblock_features.append(f)
            if self.isCanceled():
                return False

        layer.dataProvider().addFeatures(meshblock_features)
        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = 'GPKG'
        options.layerName = 'meshblocks'
        options.feedback = self.feedback
        options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer

        error, self.message = QgsVectorFileWriter.writeAsVectorFormat(
            layer, self.dest_file, options)
        if error:
            return False
        if self.isCanceled():
            return False

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = 'GPKG'
        options.layerName = 'user_log'
        options.feedback = self.feedback
        options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer

        error, self.message = QgsVectorFileWriter.writeAsVectorFormat(
            self.user_log_layer, self.dest_file, options)
        if error:
            return False

        return True
예제 #15
0
파일: dialog.py 프로젝트: Gustry/QuickOSM
    def __init__(self, iface=None, parent=None):
        """Constructor."""
        QDialog.__init__(self, parent)
        self.setupUi(self)
        self._iface = iface

        self.query_menu_index = 2
        self.preset_menu_index = 0

        # Table mapping

        # Explaining quickly, these letters are referring to the panel
        # in the UI:
        # mp : Map preset
        # qq : Quick Query
        # q : Query
        # f : file
        self.external_panels = {
            Panels.MapPreset: MapPresetPanel(self),
            Panels.QuickQuery: QuickQueryPanel(self),
            Panels.Query: QueryPanel(self),
            Panels.File: OsmFilePanel(self),
            Panels.Configuration: ConfigurationPanel(self),
        }
        self.places_edits = {
            Panels.MapPreset: self.line_place_mp,
            Panels.QuickQuery: self.line_place_qq,
            Panels.Query: self.line_place_q,
        }
        self.query_type_buttons = {
            Panels.MapPreset: self.combo_query_type_mp,
            Panels.QuickQuery: self.combo_query_type_qq,
            Panels.Query: self.combo_query_type_q,
        }
        self.layers_buttons = {
            Panels.MapPreset: self.combo_extent_layer_mp,
            Panels.QuickQuery: self.combo_extent_layer_qq,
            Panels.Query: self.combo_extent_layer_q,
        }
        self.selection_features = {
            Panels.MapPreset: self.checkbox_selection_mp,
            Panels.QuickQuery: self.checkbox_selection_qq,
            Panels.Query: self.checkbox_selection_q,
        }
        self.run_buttons = {
            Panels.MapPreset: self.button_run_query_mp,
            Panels.QuickQuery: self.button_run_query_qq,
            Panels.Query: self.button_run_query_q,
            Panels.File: self.button_run_file,
        }
        self.cancel_buttons = {
            Panels.MapPreset: self.button_cancel_query_mp,
            Panels.QuickQuery: self.button_cancel_query_qq,
            Panels.Query: self.button_cancel_query_q,
            Panels.File: self.button_cancel_file,
        }
        self.execute_buttons = {
            Panels.MapPreset: self.stacked_execute_query_mp,
            Panels.QuickQuery: self.stacked_execute_query_qq,
            Panels.Query: self.stacked_execute_query_q,
            Panels.File: self.stacked_execute_file,
        }
        self.output_buttons = {
            Panels.MapPreset: [],
            Panels.QuickQuery: [
                self.checkbox_points_qq, self.checkbox_lines_qq,
                self.checkbox_multilinestrings_qq,
                self.checkbox_multipolygons_qq
            ],
            Panels.Query: [
                self.checkbox_points_q,
                self.checkbox_lines_q,
                self.checkbox_multilinestrings_q,
                self.checkbox_multipolygons_q,
            ],
            Panels.File: [
                self.checkbox_points_f,
                self.checkbox_lines_f,
                self.checkbox_multilinestrings_f,
                self.checkbox_multipolygons_f,
            ]
        }
        self.output_directories = {
            Panels.MapPreset: None,
            Panels.QuickQuery: self.output_directory_qq,
            Panels.Query: self.output_directory_q,
            Panels.File: self.output_directory_f
        }
        self.output_format = {
            Panels.MapPreset: None,
            Panels.QuickQuery: self.combo_format_qq,
            Panels.Query: self.combo_format_q,
            Panels.File: self.combo_format_f
        }
        self.prefix_edits = {
            Panels.MapPreset: None,
            Panels.QuickQuery: self.line_file_prefix_qq,
            Panels.Query: self.line_file_prefix_q,
            Panels.File: self.line_file_prefix_file,
        }
        self.advanced_panels = {
            Panels.MapPreset: None,
            Panels.QuickQuery: self.advanced_qq,
            Panels.Query: self.advanced_q,
        }
        self.query_language = {
            Panels.MapPreset: None,
            Panels.QuickQuery: QueryLanguage.OQL,
            Panels.Query: QueryLanguage.OQL,
        }
        self.action_oql_qq = QAction('OQL')
        self.action_oql_q = QAction('OQL')
        self.action_oql = {
            Panels.QuickQuery: self.action_oql_qq,
            Panels.Query: self.action_oql_q,
        }
        self.action_xml_qq = QAction('XML')
        self.action_xml_q = QAction('XML')
        self.action_xml = {
            Panels.QuickQuery: self.action_xml_qq,
            Panels.Query: self.action_xml_q,
        }

        icon = QIcon(resources_path('icons', 'QuickOSM.svg'))
        self.reload_action = QAction(icon,
                                     tr("Reload the query in a new file"),
                                     self.iface)
        actions = Actions(self)
        reloader = partial(actions.pre_run_reload)
        self.reload_action.triggered.connect(reloader)
        self.iface.addCustomActionForLayerType(self.reload_action, "",
                                               QgsMapLayer.VectorLayer, False)

        self.feedback_process = QgsFeedback()

        item = self.menu_widget.item(0)
        item.setIcon(QIcon(resources_path('icons', 'map_tools.svg')))
        item = self.menu_widget.item(1)
        item.setIcon(QIcon(resources_path('icons', 'quick.png')))
        item = self.menu_widget.item(2)
        item.setIcon(QIcon(resources_path('icons', 'edit.png')))
        item = self.menu_widget.item(3)
        item.setIcon(QIcon(resources_path('icons', 'open.png')))
        item = self.menu_widget.item(4)
        item.setIcon(QIcon(resources_path('icons', 'general.svg')))
        item = self.menu_widget.item(5)
        item.setIcon(QIcon(resources_path('icons', 'info.png')))
        self.label_gnu.setPixmap(QPixmap(resources_path('icons', 'gnu.png')))

        # Set minimum width for the menu
        self.menu_widget.setMinimumWidth(
            self.menu_widget.sizeHintForColumn(0) + 10)

        self.progress_text.setText('')

        self.menu_widget.currentRowChanged['int'].connect(
            self.stacked_panels_widget.setCurrentIndex)

        for panel in self.external_panels.values():
            panel.setup_panel()
        self.menu_widget.setCurrentRow(1)
예제 #16
0
    def exportCompo(self, cView, folder, title, extension):
        """Function that sets how to export files.
        Returns a file
        :param cView: The print layout to export
        :param folder: The folder in which to store the output file
        :param title: The print layout name
        :param extension: The file extension to use for the output
        :return: A file representing the layout in the selected format
        """

        #self.msgWMSWarning(cView)

        myAtlas = cView.atlas()

        #Let's use custom export properties if there are
        exportSettings = self.overrideExportSettings(cView, extension)

        # Do the export process
        exporter = QgsLayoutExporter(cView)

        if myAtlas.enabled():
            feedback = QgsFeedback()

            # if single file export is required (only compatible with pdf, yet)
            # singleFile can be true and None in that case
            if cView.customProperty(
                    'singleFile') is not False and extension == '.pdf':
                result, error = exporter.exportToPdf(
                    myAtlas, os.path.join(folder, title + '.pdf'),
                    exportSettings, feedback)

            else:  #If instead multiple files will be output

                # Check if there's a valid expression for filenames,
                # and otherwise inform that a default one will be used and set it using the layout name.
                # replacement in the GUI is failing at the moment
                # if len(myAtlas.filenameExpression()) == 0:
                #     self.iface.messageBar().pushMessage(
                #         self.tr(u'Empty filename expression'),
                #         self.tr(u'The print layout "{}" has an empty output filename expression. {}_@atlas_pagename is used as default.').format(title, title),
                #         level = Qgis.Warning
                #         )
                #     myAtlas.setFilenameExpression(u"'{}_'||@atlas_pagename".format(title))

                current_fileName = myAtlas.filenameExpression()

                #export atlas to multiple pdfs
                if extension == '.pdf':
                    result, error = exporter.exportToPdfs(
                        myAtlas, os.path.join(folder, current_fileName),
                        exportSettings, feedback)

                # export atlas to svg format
                elif extension == '.svg':
                    result, error = exporter.exportToSvg(
                        myAtlas, os.path.join(folder, current_fileName),
                        exportSettings, feedback)

                # export atlas to image format
                else:
                    result, error = exporter.exportToImage(
                        myAtlas, os.path.join(folder, current_fileName),
                        extension, exportSettings, feedback)

            myAtlas.endRender()

        # if the composition has no atlas
        else:
            if extension == '.pdf':
                result = exporter.exportToPdf(
                    os.path.join(folder, title + '.pdf'), exportSettings)

            elif extension == '.svg':
                result = exporter.exportToSvg(
                    os.path.join(folder, title + '.svg'), exportSettings)

            else:
                result = exporter.exportToImage(
                    os.path.join(folder, title + extension), exportSettings)

        return result == QgsLayoutExporter.Success
예제 #17
0
    def test_geocode(self):
        geocoder = TestGeocoder()
        canvas = QgsMapCanvas()
        filter = QgsGeocoderLocatorFilter('testgeocoder', 'my geocoder',
                                          'pref', geocoder, canvas,
                                          QgsRectangle(-1, -1, 1, 1))

        self.assertEqual(filter.name(), 'testgeocoder')
        self.assertEqual(filter.displayName(), 'my geocoder')
        self.assertEqual(filter.prefix(), 'pref')
        self.assertEqual(filter.geocoder(), geocoder)
        self.assertEqual(filter.boundingBox(), QgsRectangle(-1, -1, 1, 1))

        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())
예제 #18
0
파일: process.py 프로젝트: Gustry/QuickOSM
def open_file(dialog: QDialog = None,
              osm_file: str = None,
              output_geom_types: list = None,
              white_list_column: dict = None,
              key: Union[str, List[str]] = None,
              layer_name: str = "OsmFile",
              config_outputs: dict = None,
              output_dir: str = None,
              output_format: Format = None,
              final_query: str = None,
              prefix_file: str = None,
              subset: bool = False,
              subset_query: str = None,
              feedback: QgsFeedback = None) -> int:
    """
    Open an osm file.

    Memory layer if no output directory is set, or Geojson in the output
    directory.

    :param final_query: The query where the file comes from. Might be empty if
    it's a local OSM file.
    :type final_query: basestring
    """

    if output_geom_types is None:
        output_geom_types = OSM_LAYERS
    # Legacy, waiting to remove the OsmParser for QGIS >= 3.6
    # Change in osm_file_dialog.py L131 too
    output_geom_legacy = [geom.value.lower() for geom in output_geom_types]
    if not white_list_column:
        white_list_column = None

    LOGGER.info('The OSM file is: {}'.format(osm_file))
    if feedback:
        if feedback.isCanceled():
            return None

    # Parsing the file
    osm_parser = OsmParser(osm_file=osm_file,
                           layers=output_geom_legacy,
                           output_format=output_format,
                           output_dir=output_dir,
                           prefix_file=prefix_file,
                           layer_name=layer_name,
                           key=key,
                           white_list_column=white_list_column,
                           subset=subset,
                           subset_query=subset_query,
                           feedback=feedback)

    if dialog:
        osm_parser.signalText.connect(dialog.set_progress_text)
        osm_parser.signalPercentage.connect(dialog.set_progress_percentage)

    start_time = time.time()
    layers = osm_parser.processing_parse()
    elapsed_time = time.time() - start_time
    parser_time = time.strftime("%Hh %Mm %Ss", time.gmtime(elapsed_time))
    LOGGER.info('The OSM parser took: {}'.format(parser_time))

    if feedback:
        if feedback.isCanceled():
            return None

    # Finishing the process with an output format or memory layer
    num_layers = 0

    for i, (layer, item) in enumerate(layers.items()):
        if dialog:
            dialog.set_progress_percentage(i / len(layers) * 100)
        QApplication.processEvents()
        if item['featureCount'] and (LayerType(layer.capitalize())
                                     in output_geom_types):

            final_layer_name = layer_name
            # If configOutputs is not None (from My Queries)
            if config_outputs:
                if config_outputs[layer]['namelayer']:
                    final_layer_name = config_outputs[layer]['namelayer']

            new_layer = item['vector_layer']
            new_layer.setName(final_layer_name)

            # Try to set styling if defined
            if config_outputs and config_outputs[layer]['style']:
                new_layer.loadNamedStyle(config_outputs[layer]['style'])
            else:
                if "colour" in item['tags']:
                    index = item['tags'].index('colour')
                    colors = new_layer.uniqueValues(index)
                    categories = []
                    for value in colors:
                        if str(value) == 'None':
                            value = ''
                        if layer in ['lines', 'multilinestrings']:
                            symbol = QgsSymbol.defaultSymbol(
                                QgsWkbTypes.LineGeometry)
                        elif layer == "points":
                            symbol = QgsSymbol.defaultSymbol(
                                QgsWkbTypes.PointGeometry)
                        elif layer == "multipolygons":
                            symbol = QgsSymbol.defaultSymbol(
                                QgsWkbTypes.PolygonGeometry)
                        symbol.setColor(QColor(value))
                        category = QgsRendererCategory(str(value), symbol,
                                                       str(value))
                        categories.append(category)

                    renderer = QgsCategorizedSymbolRenderer(
                        "colour", categories)
                    new_layer.setRenderer(renderer)

            # Add action about OpenStreetMap
            actions.add_actions(new_layer, item['tags'])

            QgsProject.instance().addMapLayer(new_layer)

            if final_query:
                QgsExpressionContextUtils.setLayerVariable(
                    new_layer, 'quickosm_query', final_query)
                actions.add_relaunch_action(new_layer, final_layer_name)
                if dialog:
                    dialog.iface.addCustomActionForLayer(
                        dialog.reload_action, new_layer)

            metadata = QgsLayerMetadata()
            metadata.setRights([tr("© OpenStreetMap contributors")])
            metadata.setLicenses(['https://openstreetmap.org/copyright'])
            new_layer.setMetadata(metadata)
            num_layers += 1

    return num_layers