コード例 #1
0
ファイル: test_qt_js.py プロジェクト: sxl47/learn
class JsEngine(QObject):
    def __init__(self):
        QObject.__init__(self)
        self.engine = QJSEngine()
        t = self.engine.newQObject(self)
        self.engine.globalObject().setProperty("app", t)

    @pyqtSlot(str)
    def exec_js(self, js):
        val = self.engine.evaluate(js)
        if not val.isNull() and not val.isUndefined():
            print("error:{0}".format(val.toString()))

    @pyqtSlot()
    def exec_js1(self):
        js = """
            var c = 123;
            """
        self.exec_js(js)

    @pyqtSlot(str, str)
    def log(self, p1, p2):
        print(p1, p2)
コード例 #2
0
class JsAlgorithm(QgsProcessingFeatureBasedAlgorithm):  # pylint: disable=too-many-public-methods
    """
    Javascript Algorithm
    """

    def __init__(self, description_file, script=None):
        super().__init__()

        self.script = script
        self.js_script = ''
        self.codec = None
        self.engine = None
        self.process_js_function = None
        self.json_exporter = None
        self.fields = None
        self._name = ''
        self._display_name = ''
        self._group = ''
        self.description_file = os.path.realpath(description_file) if description_file else None
        self.error = None
        self.commands = list()
        self.is_user_script = False
        if description_file:
            self.is_user_script = not description_file.startswith(JsUtils.builtin_scripts_folder())

        if self.script is not None:
            self.load_from_string()
        if self.description_file is not None:
            self.load_from_file()

    def createInstance(self):
        """
        Returns a new instance of this algorithm
        """
        if self.description_file is not None:
            return JsAlgorithm(self.description_file)

        return JsAlgorithm(description_file=None, script=self.script)

    def icon(self):
        """
        Returns the algorithm's icon
        """
        return GuiUtils.get_icon("providerJS.svg")

    def svgIconPath(self):
        """
        Returns a path to the algorithm's icon as a SVG file
        """
        return GuiUtils.get_icon_svg("providerJS.svg")

    def name(self):
        """
        Internal unique id for algorithm
        """
        return self._name

    def displayName(self):
        """
        User friendly display name
        """
        return self._display_name

    def shortDescription(self):
        """
        Returns the path to the script file, for use in toolbox tooltips
        """
        return self.description_file

    def group(self):
        """
        Returns the algorithm's group
        """
        return self._group

    def groupId(self):
        """
        Returns the algorithm's group ID
        """
        return self._group

    def load_from_string(self):
        """
        Load the algorithm from a string
        """
        lines = self.script.split('\n')
        self._name = 'unnamedalgorithm'
        self._display_name = self.tr('[Unnamed algorithm]')
        self.parse_script(iter(lines))

    def load_from_file(self):
        """
        Load the algorithm from a file
        """
        filename = os.path.basename(self.description_file)
        self._display_name = self._name
        self._name = filename[:filename.rfind('.')]
        self._display_name = self._name.replace('_', ' ')
        with open(self.description_file, 'r') as f:
            lines = [line.strip() for line in f]
        self.parse_script(iter(lines))

    def parse_script(self, lines):
        """
        Parse the lines from an JS script, initializing parameters and outputs as encountered
        """
        self.script = ''
        js_script_lines = list()
        self.error = None
        ender = 0
        line = next(lines).strip('\n').strip('\r')
        while ender < 10:
            if line.startswith('//#'):
                try:
                    self.process_metadata_line(line)
                except Exception:  # pylint: disable=broad-except
                    self.error = self.tr('This script has a syntax error.\n'
                                         'Problem with line: {0}').format(line)
            else:
                if line == '':
                    ender += 1
                else:
                    ender = 0
                js_script_lines.append(line)
            self.script += line + '\n'
            try:
                line = next(lines).strip('\n').strip('\r')
            except StopIteration:
                break
        self.js_script = '\n'.join(js_script_lines)

    def process_metadata_line(self, line):
        """
        Processes a "metadata" (##) line
        """
        line = line.replace('//#', '')

        # special commands
        #if line.lower().strip().startswith('dontuserasterpackage'):
        #    self.use_raster_package = False
        #    return

        value, type_ = self.split_tokens(line)
        if type_.lower().strip() == 'group':
            self._group = value
            return
        if type_.lower().strip() == 'name':
            self._name = self._display_name = value
            self._name = JsUtils.strip_special_characters(self._name.lower())
            return

        self.process_parameter_line(line)

    @staticmethod
    def split_tokens(line):
        """
        Attempts to split a line into tokens
        """
        tokens = line.split('=')
        return tokens[0], tokens[1]

    def process_parameter_line(self, line):
        """
        Processes a single script line representing a parameter
        """
        value, _ = self.split_tokens(line)
        description = JsUtils.create_descriptive_name(value)

        output = create_output_from_string(line)
        if output is not None:
            output.setName(value)
            output.setDescription(description)
            if issubclass(output.__class__, QgsProcessingOutputDefinition):
                self.addOutput(output)
            else:
                # destination type parameter
                self.addParameter(output)
        else:
            line = JsUtils.upgrade_parameter_line(line)
            param = getParameterFromString(line)
            if param is not None:
                self.addParameter(param)
            else:
                self.error = self.tr('This script has a syntax error.\n'
                                     'Problem with line: {0}').format(line)

    def outputFields(self, fields):
        self.fields = fields
        return self.fields

    def outputCrs(self, inputCrs):
        self.input_crs = inputCrs
        return QgsCoordinateReferenceSystem('EPSG:4326')

    def prepareAlgorithm(self, parameters, context, feedback):
        """
        Prepares the algorithm
        """
        self.engine = QJSEngine()
        js_feedback = self.engine.newQObject(feedback)
        QQmlEngine.setObjectOwnership(feedback, QQmlEngine.CppOwnership)
        self.engine.globalObject().setProperty("feedback", js_feedback)
        js = """
        function process(feature)
        {
          res = func(JSON.parse(feature))
          if ( res && res.stack && res.message )
            return res;
         return JSON.stringify(res);
        }
        """

        for param in self.parameterDefinitions():
            if param.isDestination():
                continue

            if param.name() not in parameters or parameters[param.name()] is None:
                js += '{}=None;\n'.format(param.name())
                continue

            if isinstance(param,
                            (QgsProcessingParameterField, QgsProcessingParameterString, QgsProcessingParameterFile)):
                value = self.parameterAsString(parameters, param.name(), context)
                js += '{}="{}";'.format(param.name(), value)
            elif isinstance(param, QgsProcessingParameterNumber):
                value = self.parameterAsDouble(parameters, param.name(), context)
                js += '{}={};'.format(param.name(), value)

        js += self.js_script
        result = self.engine.evaluate(js)

        user_func = self.engine.globalObject().property("func")
        if not user_func:
            raise QgsProcessingException('No \'func\' function detected in script')
        if not user_func.isCallable():
            raise QgsProcessingException('Object \'func\' is not a callable function')

        self.process_js_function = self.engine.globalObject().property("process")
        self.json_exporter = QgsJsonExporter()

        self.codec = QTextCodec.codecForName("System")

        return True

    def outputName(self):
        return 'Processed'

    def processFeature(self, feature, context, feedback):
        """
        Executes the algorithm
        """
        self.json_exporter.setSourceCrs(self.input_crs)
        geojson = self.json_exporter.exportFeature(feature)
        res = self.process_js_function.call([geojson])
        if not res:
            return []
        if res.isError():
            error = "Uncaught exception at line {}:{}".format(res.property("lineNumber").toInt(),
                                                            res.toString())
            raise QgsProcessingException(error)

        return QgsJsonUtils.stringToFeatureList(res.toString(), self.fields, self.codec)

    def shortHelpString(self):
        """
        Returns the algorithms helper string
        """
        if self.description_file is None:
            return ''

        help_file = self.description_file + '.help'
        print(help_file)
        if os.path.exists(help_file):
            with open(help_file) as f:
                descriptions = json.load(f)

            return QgsProcessingUtils.formatHelpMapAsHtml(descriptions, self)

        return ''

    def tr(self, string, context=''):
        """
        Translates a string
        """
        if context == '':
            context = 'JsAlgorithmProvider'
        return QCoreApplication.translate(context, string)