[processing] move script provider stuff into provider directory

This commit is contained in:
Alexander Bruy 2018-01-29 15:50:16 +02:00
parent 6841c52210
commit 862b1139fa
9 changed files with 64 additions and 303 deletions

View File

@ -37,5 +37,5 @@ class ContextAction:
def tr(self, string, context=''):
if context == '':
context = 'ContextAction'
context = self.__class__.__name__
return QCoreApplication.translate(context, string)

View File

@ -1,208 +0,0 @@
# -*- coding: utf-8 -*-
"""
***************************************************************************
ScriptEdit.py
---------------------
Date : April 2013
Copyright : (C) 2013 by Alexander Bruy
Email : alexander dot bruy at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
__author__ = 'Alexander Bruy'
__date__ = 'April 2013'
__copyright__ = '(C) 2013, Alexander Bruy'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import os
from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtGui import QFont, QColor, QKeySequence
from qgis.PyQt.QtWidgets import QShortcut
from qgis.core import QgsApplication, QgsSettings
from qgis.PyQt.Qsci import QsciScintilla, QsciLexerPython, QsciAPIs
class ScriptEdit(QsciScintilla):
LEXER_PYTHON = 0
LEXER_R = 1
def __init__(self, parent=None):
QsciScintilla.__init__(self, parent)
self.lexer = None
self.api = None
self.lexerType = -1
self.setCommonOptions()
self.initShortcuts()
def setCommonOptions(self):
# Enable non-ASCII characters
self.setUtf8(True)
# Default font
font = QFont()
font.setFamily('Courier')
font.setFixedPitch(True)
font.setPointSize(20)
self.setFont(font)
self.setMarginsFont(font)
self.initLexer()
self.setBraceMatching(QsciScintilla.SloppyBraceMatch)
self.setWrapMode(QsciScintilla.WrapWord)
self.setWrapVisualFlags(QsciScintilla.WrapFlagByText,
QsciScintilla.WrapFlagNone, 4)
self.setSelectionForegroundColor(QColor('#2e3436'))
self.setSelectionBackgroundColor(QColor('#babdb6'))
# Show line numbers
self.setMarginWidth(1, '000')
self.setMarginLineNumbers(1, True)
self.setMarginsForegroundColor(QColor('#2e3436'))
self.setMarginsBackgroundColor(QColor('#babdb6'))
# Highlight current line
self.setCaretLineVisible(True)
self.setCaretLineBackgroundColor(QColor('#d3d7cf'))
# Folding
self.setFolding(QsciScintilla.BoxedTreeFoldStyle)
self.setFoldMarginColors(QColor('#d3d7cf'), QColor('#d3d7cf'))
# Mark column 80 with vertical line
self.setEdgeMode(QsciScintilla.EdgeLine)
self.setEdgeColumn(80)
self.setEdgeColor(QColor('#eeeeec'))
# Indentation
self.setAutoIndent(True)
self.setIndentationsUseTabs(False)
self.setIndentationWidth(4)
self.setTabIndents(True)
self.setBackspaceUnindents(True)
self.setTabWidth(4)
# Autocomletion
self.setAutoCompletionThreshold(2)
self.setAutoCompletionSource(QsciScintilla.AcsAPIs)
self.setFonts(10)
def setFonts(self, size):
# Load font from Python console settings
settings = QgsSettings()
fontName = settings.value('pythonConsole/fontfamilytext', 'Monospace')
fontSize = int(settings.value('pythonConsole/fontsize', size))
self.defaultFont = QFont(fontName)
self.defaultFont.setFixedPitch(True)
self.defaultFont.setPointSize(fontSize)
self.defaultFont.setStyleHint(QFont.TypeWriter)
self.defaultFont.setStretch(QFont.SemiCondensed)
self.defaultFont.setLetterSpacing(QFont.PercentageSpacing, 87.0)
self.defaultFont.setBold(False)
self.boldFont = QFont(self.defaultFont)
self.boldFont.setBold(True)
self.italicFont = QFont(self.defaultFont)
self.italicFont.setItalic(True)
self.setFont(self.defaultFont)
self.setMarginsFont(self.defaultFont)
def initShortcuts(self):
(ctrl, shift) = (self.SCMOD_CTRL << 16, self.SCMOD_SHIFT << 16)
# Disable some shortcuts
self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('D') + ctrl)
self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl)
self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('L') + ctrl +
shift)
self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord('T') + ctrl)
# self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Z") + ctrl)
# self.SendScintilla(QsciScintilla.SCI_CLEARCMDKEY, ord("Y") + ctrl)
# Use Ctrl+Space for autocompletion
self.shortcutAutocomplete = QShortcut(QKeySequence(Qt.CTRL +
Qt.Key_Space), self)
self.shortcutAutocomplete.setContext(Qt.WidgetShortcut)
self.shortcutAutocomplete.activated.connect(self.autoComplete)
def autoComplete(self):
self.autoCompleteFromAll()
def setLexerType(self, lexerType):
self.lexerType = lexerType
self.initLexer()
def initLexer(self):
if self.lexerType == self.LEXER_PYTHON:
self.lexer = QsciLexerPython()
colorDefault = QColor('#2e3436')
colorComment = QColor('#c00')
colorCommentBlock = QColor('#3465a4')
colorNumber = QColor('#4e9a06')
colorType = QColor('#4e9a06')
colorKeyword = QColor('#204a87')
colorString = QColor('#ce5c00')
self.lexer.setDefaultFont(self.defaultFont)
self.lexer.setDefaultColor(colorDefault)
self.lexer.setColor(colorComment, 1)
self.lexer.setColor(colorNumber, 2)
self.lexer.setColor(colorString, 3)
self.lexer.setColor(colorString, 4)
self.lexer.setColor(colorKeyword, 5)
self.lexer.setColor(colorString, 6)
self.lexer.setColor(colorString, 7)
self.lexer.setColor(colorType, 8)
self.lexer.setColor(colorCommentBlock, 12)
self.lexer.setColor(colorString, 15)
self.lexer.setFont(self.italicFont, 1)
self.lexer.setFont(self.boldFont, 5)
self.lexer.setFont(self.boldFont, 8)
self.lexer.setFont(self.italicFont, 12)
self.api = QsciAPIs(self.lexer)
settings = QgsSettings()
useDefaultAPI = bool(settings.value('pythonConsole/preloadAPI',
True))
if useDefaultAPI:
# Load QGIS API shipped with Python console
self.api.loadPrepared(
os.path.join(QgsApplication.pkgDataPath(),
'python', 'qsci_apis', 'pyqgis.pap'))
else:
# Load user-defined API files
apiPaths = settings.value('pythonConsole/userAPI', [])
for path in apiPaths:
self.api.load(path)
self.api.prepare()
self.lexer.setAPIs(self.api)
self.setLexer(self.lexer)

View File

@ -32,8 +32,9 @@ from qgis.PyQt.QtCore import QFileInfo
from qgis.core import QgsApplication, QgsSettings
from processing.script.ScriptAlgorithm import ScriptAlgorithm
from processing.gui.ToolboxAction import ToolboxAction
from processing.script.ScriptAlgorithm import ScriptAlgorithm
from processing.script.WrongScriptException import WrongScriptException
from processing.script.ScriptUtils import ScriptUtils
@ -53,8 +54,9 @@ class AddScriptFromFileAction(ToolboxAction):
settings = QgsSettings()
lastDir = settings.value('Processing/lastScriptsDir', '')
filenames, selected_filter = QFileDialog.getOpenFileNames(self.toolbox,
self.tr('Script files', 'AddScriptFromFileAction'), lastDir,
self.tr('Script files (*.py *.PY)', 'AddScriptFromFileAction'))
self.tr('Script files'),
lastDir,
self.tr('Script files (*.py *.PY)'))
if filenames:
validAlgs = 0
wrongAlgs = []
@ -73,6 +75,6 @@ class AddScriptFromFileAction(ToolboxAction):
QgsApplication.processingRegistry().providerById('script').refreshAlgorithms()
if wrongAlgs:
QMessageBox.warning(self.toolbox,
self.tr('Error reading scripts', 'AddScriptFromFileAction'),
self.tr('The following files do not contain a valid script:\n-', 'AddScriptFromFileAction') +
"\n-".join(wrongAlgs))
self.tr('Error reading scripts'),
self.tr('The following files do not contain a valid script:\n') +
"\n- ".join(wrongAlgs))

View File

@ -30,27 +30,20 @@ import os
from qgis.core import QgsApplication
from processing.gui.ToolboxAction import ToolboxAction
from processing.gui.ScriptEditorDialog import ScriptEditorDialog
from processing.script.ScriptEditorDialog import ScriptEditorDialog
pluginPath = os.path.split(os.path.dirname(__file__))[0]
class CreateNewScriptAction(ToolboxAction):
SCRIPT_PYTHON = 0
def __init__(self, actionName, scriptType):
def __init__(self, actionName):
self.name, self.i18n_name = self.trAction(actionName)
self.group, self.i18n_group = self.trAction('Tools')
self.scriptType = scriptType
def getIcon(self):
if self.scriptType == self.SCRIPT_PYTHON:
return QgsApplication.getThemeIcon("/processingScript.svg")
return QgsApplication.getThemeIcon("/processingScript.svg")
def execute(self):
dlg = None
if self.scriptType == self.SCRIPT_PYTHON:
dlg = ScriptEditorDialog(ScriptEditorDialog.SCRIPT_PYTHON, None)
dlg = ScriptEditorDialog(None)
dlg.show()

View File

@ -37,25 +37,18 @@ from processing.script.ScriptAlgorithm import ScriptAlgorithm
class DeleteScriptAction(ContextAction):
SCRIPT_PYTHON = 0
def __init__(self, scriptType):
self.name = self.tr('Delete script', 'DeleteScriptAction')
self.scriptType = scriptType
def __init__(self):
self.name = self.tr('Delete script')
def isEnabled(self):
if self.scriptType == self.SCRIPT_PYTHON:
return isinstance(self.itemData, ScriptAlgorithm) and self.itemData.allowEdit
return isinstance(self.itemData, ScriptAlgorithm) and self.itemData.allowEdit
def execute(self):
reply = QMessageBox.question(None,
self.tr('Confirmation', 'DeleteScriptAction'),
self.tr('Are you sure you want to delete this script?',
'DeleteScriptAction'),
self.tr('Confirmation'),
self.tr('Are you sure you want to delete this script?'),
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No)
if reply == QMessageBox.Yes:
os.remove(self.itemData.descriptionFile)
if self.scriptType == self.SCRIPT_PYTHON:
QgsApplication.processingRegistry().providerById('script').refreshAlgorithms()
QgsApplication.processingRegistry().providerById('script').refreshAlgorithms()

View File

@ -26,22 +26,18 @@ __copyright__ = '(C) 2012, Victor Olaya'
__revision__ = '$Format:%H$'
from processing.gui.ContextAction import ContextAction
from processing.gui.ScriptEditorDialog import ScriptEditorDialog
from processing.script.ScriptEditorDialog import ScriptEditorDialog
from processing.script.ScriptAlgorithm import ScriptAlgorithm
class EditScriptAction(ContextAction):
SCRIPT_PYTHON = 0
def __init__(self, scriptType):
self.name = self.tr('Edit script', 'EditScriptAction')
self.scriptType = scriptType
def __init__(self):
self.name = self.tr('Edit script')
def isEnabled(self):
if self.scriptType == ScriptEditorDialog.SCRIPT_PYTHON:
return isinstance(self.itemData, ScriptAlgorithm) and self.itemData.allowEdit
return isinstance(self.itemData, ScriptAlgorithm) and self.itemData.allowEdit
def execute(self):
dlg = ScriptEditorDialog(self.scriptType, self.itemData)
dlg = ScriptEditorDialog(self.itemData)
dlg.show()

View File

@ -31,14 +31,15 @@ from qgis.core import (QgsApplication,
QgsProcessingProvider)
from processing.core.ProcessingConfig import ProcessingConfig, Setting
from processing.gui.EditScriptAction import EditScriptAction
from processing.gui.DeleteScriptAction import DeleteScriptAction
from processing.gui.CreateNewScriptAction import CreateNewScriptAction
from processing.script.ScriptUtils import ScriptUtils
from processing.script.AddScriptFromFileAction import AddScriptFromFileAction
from processing.gui.ProviderActions import (ProviderActions,
ProviderContextMenuActions)
from processing.script.AddScriptFromFileAction import AddScriptFromFileAction
from processing.script.CreateNewScriptAction import CreateNewScriptAction
from processing.script.DeleteScriptAction import DeleteScriptAction
from processing.script.EditScriptAction import EditScriptAction
from processing.script.CreateScriptCollectionPluginAction import CreateScriptCollectionPluginAction
from processing.script.ScriptUtils import ScriptUtils
pluginPath = os.path.split(os.path.dirname(__file__))[0]
@ -49,13 +50,11 @@ class ScriptAlgorithmProvider(QgsProcessingProvider):
super().__init__()
self.algs = []
self.folder_algorithms = []
self.actions = [CreateNewScriptAction('Create new script',
CreateNewScriptAction.SCRIPT_PYTHON),
self.actions = [CreateNewScriptAction('Create new script'),
AddScriptFromFileAction(),
CreateScriptCollectionPluginAction()]
self.contextMenuActions = \
[EditScriptAction(EditScriptAction.SCRIPT_PYTHON),
DeleteScriptAction(DeleteScriptAction.SCRIPT_PYTHON)]
self.contextMenuActions = [EditScriptAction(),
DeleteScriptAction()]
def load(self):
ProcessingConfig.settingIcons[self.name()] = self.icon()

View File

@ -42,6 +42,7 @@ from qgis.utils import iface, OverrideCursor
from processing.gui.AlgorithmDialog import AlgorithmDialog
from processing.gui.HelpEditionDialog import HelpEditionDialog
from processing.script.ScriptAlgorithm import ScriptAlgorithm
from processing.script.ScriptUtils import ScriptUtils
@ -51,12 +52,9 @@ WIDGET, BASE = uic.loadUiType(
class ScriptEditorDialog(BASE, WIDGET):
SCRIPT_PYTHON = 0
hasChanged = False
def __init__(self, algType, alg):
def __init__(self, alg):
super(ScriptEditorDialog, self).__init__(None)
self.setupUi(self)
@ -120,25 +118,23 @@ class ScriptEditorDialog(BASE, WIDGET):
self.lastSearch = None
self.alg = alg
self.algType = algType
self.snippets = {}
if self.algType == self.SCRIPT_PYTHON:
path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "script", "snippets.py")
with codecs.open(path, 'r', encoding='utf-8') as f:
lines = f.readlines()
snippetlines = []
name = None
for line in lines:
if line.startswith("##"):
if snippetlines:
self.snippets[name] = "".join(snippetlines)
name = line[2:]
snippetlines = []
else:
snippetlines.append(line)
if snippetlines:
self.snippets[name] = "".join(snippetlines)
path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "script", "snippets.py")
with codecs.open(path, 'r', encoding='utf-8') as f:
lines = f.readlines()
snippetlines = []
name = None
for line in lines:
if line.startswith("##"):
if snippetlines:
self.snippets[name] = "".join(snippetlines)
name = line[2:]
snippetlines = []
else:
snippetlines.append(line)
if snippetlines:
self.snippets[name] = "".join(snippetlines)
#if self.snippets:
# self.btnSnippets.setVisible(False)
@ -154,8 +150,6 @@ class ScriptEditorDialog(BASE, WIDGET):
self.setHasChanged(False)
self.editor.setLexerType(self.algType)
#def showSnippets(self, evt):
# popupmenu = QMenu()
# for name, snippet in list(self.snippets.items()):
@ -181,13 +175,11 @@ class ScriptEditorDialog(BASE, WIDGET):
def updateProviders(self):
if self.update:
if self.algType == self.SCRIPT_PYTHON:
QgsApplication.processingRegistry().providerById('script').refreshAlgorithms()
QgsApplication.processingRegistry().providerById('script').refreshAlgorithms()
def editHelp(self):
if self.alg is None:
if self.algType == self.SCRIPT_PYTHON:
alg = ScriptAlgorithm(None, self.editor.text())
alg = ScriptAlgorithm(None, self.editor.text())
else:
alg = self.alg
@ -205,10 +197,8 @@ class ScriptEditorDialog(BASE, WIDGET):
if ret == QMessageBox.No:
return
if self.algType == self.SCRIPT_PYTHON:
scriptDir = ScriptUtils.scriptsFolders()[0]
filterName = self.tr('Python scripts (*.py)')
scriptDir = ScriptUtils.scriptsFolders()[0]
filterName = self.tr('Python scripts (*.py)')
self.filename, fileFilter = QFileDialog.getOpenFileName(
self, self.tr('Open script'), scriptDir, filterName)
@ -232,16 +222,13 @@ class ScriptEditorDialog(BASE, WIDGET):
def saveScript(self, saveAs):
if self.filename is None or saveAs:
if self.algType == self.SCRIPT_PYTHON:
scriptDir = ScriptUtils.scriptsFolders()[0]
filterName = self.tr('Python scripts (*.py)')
scriptDir = ScriptUtils.scriptsFolders()[0]
filterName = self.tr('Python scripts (*.py)')
self.filename, fileFilter = QFileDialog.getSaveFileName(
self, self.tr('Save script'), scriptDir, filterName)
if self.filename:
if self.algType == self.SCRIPT_PYTHON and \
not self.filename.lower().endswith('.py'):
if not self.filename.lower().endswith('.py'):
self.filename += '.py'
text = self.editor.text()
@ -273,9 +260,8 @@ class ScriptEditorDialog(BASE, WIDGET):
self.actionSaveScript.setEnabled(hasChanged)
def runAlgorithm(self):
if self.algType == self.SCRIPT_PYTHON:
alg = ScriptAlgorithm(None, script=self.editor.text())
alg.setProvider(QgsApplication.processingRegistry().providerById('script'))
alg = ScriptAlgorithm(None, script=self.editor.text())
alg.setProvider(QgsApplication.processingRegistry().providerById('script'))
dlg = alg.createCustomParametersWidget(self)
if not dlg:

View File

@ -16,7 +16,7 @@
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="ScriptEdit" name="editor"/>
<widget class="QgsCodeEditorPython" name="editor"/>
</item>
<item row="1" column="0">
<widget class="QWidget" name="searchWidget" native="true">
@ -257,9 +257,9 @@
</widget>
<customwidgets>
<customwidget>
<class>ScriptEdit</class>
<class>QgsCodeEditorPython</class>
<extends>QTextEdit</extends>
<header>processing.gui.ScriptEdit</header>
<header>qgis.gui</header>
</customwidget>
</customwidgets>
<resources/>