Skip to content
Permalink
Browse files

[processing] support multiple scripts/models folders (fix #10476)

  • Loading branch information
alexbruy committed May 24, 2016
1 parent d170946 commit d16f04bf3a99aaf80f69146f1ab9d6971ffaf970
@@ -62,8 +62,8 @@ def initializeSettings(self):
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 @@ def getName(self):
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 @@ def RLibs():
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 @@ def checkFileOrFolder(v):
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 @@
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 @@ def createEditor(
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 @@ def text(self):

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)
@@ -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 @@ def openScript(self):
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 @@ def saveAs(self):
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 @@ def initializeSettings(self):
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 @@ def getIcon(self):
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 @@ def saveModel(self, saveAs):
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 @@ def saveModel(self, saveAs):

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 @@ def initializeSettings(self):
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 @@ def getDescription(self):
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))

0 comments on commit d16f04b

Please sign in to comment.
You can’t perform that action at this time.