mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
[processing] support multiple scripts/models folders (fix #10476)
This commit is contained in:
parent
d17094611b
commit
d16f04bf3a
@ -62,8 +62,8 @@ class RAlgorithmProvider(AlgorithmProvider):
|
||||
AlgorithmProvider.initializeSettings(self)
|
||||
ProcessingConfig.addSetting(Setting(
|
||||
self.getDescription(), RUtils.RSCRIPTS_FOLDER,
|
||||
self.tr('R Scripts folder'), RUtils.RScriptsFolder(),
|
||||
valuetype=Setting.FOLDER))
|
||||
self.tr('R Scripts folder'), RUtils.defaultRScriptsFolder(),
|
||||
valuetype=Setting.MULTIPLE_FOLDERS))
|
||||
if isWindows():
|
||||
ProcessingConfig.addSetting(Setting(
|
||||
self.getDescription(),
|
||||
@ -95,8 +95,11 @@ class RAlgorithmProvider(AlgorithmProvider):
|
||||
return 'r'
|
||||
|
||||
def _loadAlgorithms(self):
|
||||
folder = RUtils.RScriptsFolder()
|
||||
self.loadFromFolder(folder)
|
||||
folders = RUtils.RScriptsFolders()
|
||||
self.algs = []
|
||||
for f in folders:
|
||||
self.loadFromFolder(f)
|
||||
|
||||
folder = os.path.join(os.path.dirname(__file__), 'scripts')
|
||||
self.loadFromFolder(folder)
|
||||
|
||||
|
@ -84,18 +84,19 @@ class RUtils:
|
||||
return os.path.abspath(unicode(folder))
|
||||
|
||||
@staticmethod
|
||||
def RScriptsFolder():
|
||||
folder = ProcessingConfig.getSetting(RUtils.RSCRIPTS_FOLDER)
|
||||
if folder is None:
|
||||
folder = unicode(os.path.join(userFolder(), 'rscripts'))
|
||||
try:
|
||||
mkdir(folder)
|
||||
except:
|
||||
folder = unicode(os.path.join(userFolder(), 'rscripts'))
|
||||
mkdir(folder)
|
||||
|
||||
def defaultRScriptsFolder():
|
||||
folder = unicode(os.path.join(userFolder(), 'rscripts'))
|
||||
mkdir(folder)
|
||||
return os.path.abspath(folder)
|
||||
|
||||
@staticmethod
|
||||
def RScriptsFolders():
|
||||
folder = ProcessingConfig.getSetting(RUtils.RSCRIPTS_FOLDER)
|
||||
if folder is not None:
|
||||
return folder.split(';')
|
||||
else:
|
||||
return [RUtils.defaultRScriptsFolder()]
|
||||
|
||||
@staticmethod
|
||||
def createRScriptFromRCommands(commands):
|
||||
scriptfile = open(RUtils.getRScriptFilename(), 'w')
|
||||
|
@ -228,6 +228,7 @@ class Setting:
|
||||
SELECTION = 3
|
||||
FLOAT = 4
|
||||
INT = 5
|
||||
MULTIPLE_FOLDERS = 6
|
||||
|
||||
def __init__(self, group, name, description, default, hidden=False, valuetype=None,
|
||||
validator=None, options=None):
|
||||
@ -264,6 +265,13 @@ class Setting:
|
||||
if v and not os.path.exists(v):
|
||||
raise ValueError(self.tr('Specified path does not exist:\n%s') % unicode(v))
|
||||
validator = checkFileOrFolder
|
||||
elif valuetype == self.MULTIPLE_FOLDERS:
|
||||
def checkMultipleFolders(v):
|
||||
folders = v.split(';')
|
||||
for f in folders:
|
||||
if f and not os.path.exists(f):
|
||||
raise ValueError(self.tr('Specified path does not exist:\n%s') % unicode(f))
|
||||
validator = checkMultipleFolders
|
||||
else:
|
||||
def validator(x):
|
||||
return True
|
||||
|
@ -54,6 +54,7 @@ from processing.core.ProcessingConfig import (ProcessingConfig,
|
||||
settingsWatcher,
|
||||
Setting)
|
||||
from processing.core.Processing import Processing
|
||||
from processing.gui.DirectorySelectorDialog import DirectorySelectorDialog
|
||||
from processing.gui.menus import updateMenus
|
||||
from processing.gui.menus import menusSettingsGroup
|
||||
|
||||
@ -284,12 +285,7 @@ class SettingDelegate(QStyledItemDelegate):
|
||||
def __init__(self, parent=None):
|
||||
QStyledItemDelegate.__init__(self, parent)
|
||||
|
||||
def createEditor(
|
||||
self,
|
||||
parent,
|
||||
options,
|
||||
index,
|
||||
):
|
||||
def createEditor(self, parent, options, index):
|
||||
setting = index.model().data(index, Qt.UserRole)
|
||||
if setting.valuetype == Setting.FOLDER:
|
||||
return FileDirectorySelector(parent)
|
||||
@ -299,6 +295,8 @@ class SettingDelegate(QStyledItemDelegate):
|
||||
combo = QComboBox(parent)
|
||||
combo.addItems(setting.options)
|
||||
return combo
|
||||
elif setting.valuetype == Setting.MULTIPLE_FOLDERS:
|
||||
return MultipleDirectorySelector(parent)
|
||||
else:
|
||||
value = self.convertValue(index.model().data(index, Qt.EditRole))
|
||||
if isinstance(value, (int, long)):
|
||||
@ -398,3 +396,44 @@ class FileDirectorySelector(QWidget):
|
||||
|
||||
def setText(self, value):
|
||||
self.lineEdit.setText(value)
|
||||
|
||||
|
||||
class MultipleDirectorySelector(QWidget):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QWidget.__init__(self, parent)
|
||||
|
||||
# create gui
|
||||
self.btnSelect = QToolButton()
|
||||
self.btnSelect.setText(self.tr('...'))
|
||||
self.lineEdit = QLineEdit()
|
||||
self.hbl = QHBoxLayout()
|
||||
self.hbl.setMargin(0)
|
||||
self.hbl.setSpacing(0)
|
||||
self.hbl.addWidget(self.lineEdit)
|
||||
self.hbl.addWidget(self.btnSelect)
|
||||
|
||||
self.setLayout(self.hbl)
|
||||
|
||||
self.canFocusOut = False
|
||||
|
||||
self.setFocusPolicy(Qt.StrongFocus)
|
||||
self.btnSelect.clicked.connect(self.select)
|
||||
|
||||
def select(self):
|
||||
text = self.lineEdit.text()
|
||||
if text != '':
|
||||
items = text.split(';')
|
||||
|
||||
dlg = DirectorySelectorDialog(None, items)
|
||||
if dlg.exec_():
|
||||
text = dlg.value()
|
||||
self.lineEdit.setText(text)
|
||||
|
||||
self.canFocusOut = True
|
||||
|
||||
def text(self):
|
||||
return self.lineEdit.text()
|
||||
|
||||
def setText(self, value):
|
||||
self.lineEdit.setText(value)
|
||||
|
124
python/plugins/processing/gui/DirectorySelectorDialog.py
Normal file
124
python/plugins/processing/gui/DirectorySelectorDialog.py
Normal file
@ -0,0 +1,124 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
DirectorySelectorDialog.py
|
||||
---------------------
|
||||
Date : May 2016
|
||||
Copyright : (C) 2016 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__ = 'May 2016'
|
||||
__copyright__ = '(C) 2016, Victor Olaya'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
import os
|
||||
|
||||
from qgis.PyQt import uic
|
||||
from qgis.PyQt.QtCore import QSettings
|
||||
from qgis.PyQt.QtWidgets import QDialog, QAbstractItemView, QPushButton, QDialogButtonBox, QFileDialog
|
||||
from qgis.PyQt.QtGui import QStandardItemModel, QStandardItem
|
||||
|
||||
pluginPath = os.path.split(os.path.dirname(__file__))[0]
|
||||
WIDGET, BASE = uic.loadUiType(
|
||||
os.path.join(pluginPath, 'ui', 'DlgMultipleSelection.ui'))
|
||||
|
||||
|
||||
class DirectorySelectorDialog(BASE, WIDGET):
|
||||
|
||||
def __init__(self, parent, options):
|
||||
super(DirectorySelectorDialog, self).__init__(None)
|
||||
self.setupUi(self)
|
||||
|
||||
self.lstLayers.setSelectionMode(QAbstractItemView.ExtendedSelection)
|
||||
|
||||
self.options = options
|
||||
|
||||
# Additional buttons
|
||||
self.btnAdd = QPushButton(self.tr('Add'))
|
||||
self.buttonBox.addButton(self.btnAdd,
|
||||
QDialogButtonBox.ActionRole)
|
||||
self.btnRemove = QPushButton(self.tr('Remove'))
|
||||
self.buttonBox.addButton(self.btnRemove,
|
||||
QDialogButtonBox.ActionRole)
|
||||
self.btnRemoveAll = QPushButton(self.tr('Remove all'))
|
||||
self.buttonBox.addButton(self.btnRemoveAll,
|
||||
QDialogButtonBox.ActionRole)
|
||||
|
||||
self.btnAdd.clicked.connect(self.addDirectory)
|
||||
self.btnRemove.clicked.connect(lambda: self.removeRows())
|
||||
self.btnRemoveAll.clicked.connect(lambda: self.removeRows(True))
|
||||
|
||||
self.populateList()
|
||||
|
||||
def populateList(self):
|
||||
model = QStandardItemModel()
|
||||
for option in self.options:
|
||||
item = QStandardItem(option)
|
||||
model.appendRow(item)
|
||||
|
||||
self.lstLayers.setModel(model)
|
||||
|
||||
def accept(self):
|
||||
self.selectedoptions = []
|
||||
model = self.lstLayers.model()
|
||||
for i in xrange(model.rowCount()):
|
||||
item = model.item(i)
|
||||
self.selectedoptions.append(item.text())
|
||||
QDialog.accept(self)
|
||||
|
||||
def reject(self):
|
||||
QDialog.reject(self)
|
||||
|
||||
def addDirectory(self):
|
||||
settings = QSettings()
|
||||
if settings.contains('/Processing/lastDirectory'):
|
||||
path = settings.value('/Processing/lastDirectory')
|
||||
else:
|
||||
path = ''
|
||||
|
||||
folder = QFileDialog.getExistingDirectory(self,
|
||||
self.tr('Select directory'),
|
||||
path,
|
||||
QFileDialog.ShowDirsOnly)
|
||||
|
||||
if folder == '':
|
||||
return
|
||||
|
||||
model = self.lstLayers.model()
|
||||
item = QStandardItem(folder)
|
||||
model.appendRow(item)
|
||||
|
||||
settings.setValue('/Processing/lastDirectory',
|
||||
os.path.dirname(folder))
|
||||
|
||||
def removeRows(self, removeAll=False):
|
||||
if removeAll:
|
||||
self.lstLayers.model().clear()
|
||||
else:
|
||||
self.lstLayers.setUpdatesEnabled(False)
|
||||
indexes = sorted(self.lstLayers.selectionModel().selectedIndexes())
|
||||
for i in reversed(indexes):
|
||||
self.lstLayers.model().removeRow(i.row())
|
||||
self.lstLayers.setUpdatesEnabled(True)
|
||||
|
||||
def value(self):
|
||||
folders = []
|
||||
model = self.lstLayers.model()
|
||||
for i in xrange(model.rowCount()):
|
||||
folders.append(model.item(i).text())
|
||||
|
||||
return ';'.join(folders)
|
@ -193,10 +193,10 @@ class ScriptEditorDialog(BASE, WIDGET):
|
||||
return
|
||||
|
||||
if self.algType == self.SCRIPT_PYTHON:
|
||||
scriptDir = ScriptUtils.scriptsFolder()
|
||||
scriptDir = ScriptUtils.defaultScriptsFolder()
|
||||
filterName = self.tr('Python scripts (*.py)')
|
||||
elif self.algType == self.SCRIPT_R:
|
||||
scriptDir = RUtils.RScriptsFolder()
|
||||
scriptDir = RUtils.defaultRScriptsFolder()
|
||||
filterName = self.tr('Processing R script (*.rsx)')
|
||||
|
||||
self.filename = QFileDialog.getOpenFileName(
|
||||
@ -224,10 +224,10 @@ class ScriptEditorDialog(BASE, WIDGET):
|
||||
def saveScript(self, saveAs):
|
||||
if self.filename is None or saveAs:
|
||||
if self.algType == self.SCRIPT_PYTHON:
|
||||
scriptDir = ScriptUtils.scriptsFolder()
|
||||
scriptDir = ScriptUtils.defaultScriptsFolder()
|
||||
filterName = self.tr('Python scripts (*.py)')
|
||||
elif self.algType == self.SCRIPT_R:
|
||||
scriptDir = RUtils.RScriptsFolder()
|
||||
scriptDir = RUtils.defaultRScriptsFolder()
|
||||
filterName = self.tr('Processing R script (*.rsx)')
|
||||
|
||||
self.filename = unicode(QFileDialog.getSaveFileName(self,
|
||||
|
@ -55,7 +55,7 @@ class ModelerAlgorithmProvider(AlgorithmProvider):
|
||||
AlgorithmProvider.initializeSettings(self)
|
||||
ProcessingConfig.addSetting(Setting(self.getDescription(),
|
||||
ModelerUtils.MODELS_FOLDER, self.tr('Models folder', 'ModelerAlgorithmProvider'),
|
||||
ModelerUtils.modelsFolder(), valuetype=Setting.FOLDER))
|
||||
ModelerUtils.defaultModelsFolder(), valuetype=Setting.MULTIPLE_FOLDERS))
|
||||
|
||||
def modelsFolder(self):
|
||||
return ModelerUtils.modelsFolder()
|
||||
@ -70,11 +70,12 @@ class ModelerAlgorithmProvider(AlgorithmProvider):
|
||||
return QIcon(os.path.join(pluginPath, 'images', 'model.png'))
|
||||
|
||||
def _loadAlgorithms(self):
|
||||
folder = ModelerUtils.modelsFolder()
|
||||
self.loadFromFolder(folder)
|
||||
folders = ModelerUtils.modelsFolders()
|
||||
self.algs = []
|
||||
for f in folders:
|
||||
self.loadFromFolder(f)
|
||||
|
||||
def loadFromFolder(self, folder):
|
||||
self.algs = []
|
||||
if not os.path.exists(folder):
|
||||
return
|
||||
for path, subdirs, files in os.walk(folder):
|
||||
|
@ -310,7 +310,7 @@ class ModelerDialog(BASE, WIDGET):
|
||||
else:
|
||||
filename = unicode(QFileDialog.getSaveFileName(self,
|
||||
self.tr('Save Model'),
|
||||
ModelerUtils.modelsFolder(),
|
||||
ModelerUtils.defaultModelsFolder(),
|
||||
self.tr('Processing models (*.model)')))
|
||||
if filename:
|
||||
if not filename.endswith('.model'):
|
||||
@ -341,7 +341,7 @@ class ModelerDialog(BASE, WIDGET):
|
||||
|
||||
def openModel(self):
|
||||
filename = unicode(QFileDialog.getOpenFileName(self,
|
||||
self.tr('Open Model'), ModelerUtils.modelsFolder(),
|
||||
self.tr('Open Model'), ModelerUtils.defaultModelsFolder(),
|
||||
self.tr('Processing models (*.model *.MODEL)')))
|
||||
if filename:
|
||||
try:
|
||||
|
@ -36,11 +36,16 @@ class ModelerUtils:
|
||||
ACTIVATE_MODELS = 'ACTIVATE_MODELS'
|
||||
|
||||
@staticmethod
|
||||
def modelsFolder():
|
||||
folder = ProcessingConfig.getSetting(ModelerUtils.MODELS_FOLDER)
|
||||
if folder is None:
|
||||
folder = unicode(os.path.join(userFolder(), 'models'))
|
||||
def defaultModelsFolder():
|
||||
folder = unicode(os.path.join(userFolder(), 'models'))
|
||||
mkdir(folder)
|
||||
|
||||
return os.path.abspath(folder)
|
||||
|
||||
@staticmethod
|
||||
def modelsFolders():
|
||||
folder = ProcessingConfig.getSetting(ModelerUtils.MODELS_FOLDER)
|
||||
if folder is not None:
|
||||
return folder.split(';')
|
||||
else:
|
||||
return [ModelerUtils.defaultModelsFolder()]
|
||||
|
||||
|
@ -58,7 +58,7 @@ class ScriptAlgorithmProvider(AlgorithmProvider):
|
||||
ProcessingConfig.addSetting(Setting(self.getDescription(),
|
||||
ScriptUtils.SCRIPTS_FOLDER,
|
||||
self.tr('Scripts folder', 'ScriptAlgorithmProvider'),
|
||||
ScriptUtils.scriptsFolder(), valuetype=Setting.FOLDER))
|
||||
ScriptUtils.defaultScriptsFolder(), valuetype=Setting.MULTIPLE_FOLDERS))
|
||||
|
||||
def unload(self):
|
||||
AlgorithmProvider.unload(self)
|
||||
@ -74,8 +74,10 @@ class ScriptAlgorithmProvider(AlgorithmProvider):
|
||||
return self.tr('Scripts', 'ScriptAlgorithmProvider')
|
||||
|
||||
def _loadAlgorithms(self):
|
||||
folder = ScriptUtils.scriptsFolder()
|
||||
self.algs = ScriptUtils.loadFromFolder(folder)
|
||||
folders = ScriptUtils.scriptsFolders()
|
||||
self.algs = []
|
||||
for f in folders:
|
||||
self.algs.extend(ScriptUtils.loadFromFolder(f))
|
||||
|
||||
def addAlgorithmsFromFolder(self, folder):
|
||||
self.algs.extend(ScriptUtils.loadFromFolder(folder))
|
||||
|
@ -39,14 +39,19 @@ class ScriptUtils(object):
|
||||
ACTIVATE_SCRIPTS = 'ACTIVATE_SCRIPTS'
|
||||
|
||||
@staticmethod
|
||||
def scriptsFolder():
|
||||
folder = ProcessingConfig.getSetting(ScriptUtils.SCRIPTS_FOLDER)
|
||||
if folder is None:
|
||||
folder = unicode(os.path.join(userFolder(), 'scripts'))
|
||||
def defaultScriptsFolder():
|
||||
folder = unicode(os.path.join(userFolder(), 'scripts'))
|
||||
mkdir(folder)
|
||||
|
||||
return os.path.abspath(folder)
|
||||
|
||||
@staticmethod
|
||||
def scriptsFolders():
|
||||
folder = ProcessingConfig.getSetting(ScriptUtils.SCRIPTS_FOLDER)
|
||||
if folder is not None:
|
||||
return folder.split(';')
|
||||
else:
|
||||
return [ScriptUtils.defaultScriptsFolder()]
|
||||
|
||||
@staticmethod
|
||||
def loadFromFolder(folder):
|
||||
if not os.path.exists(folder):
|
||||
|
Loading…
x
Reference in New Issue
Block a user