Skip to content

Commit

Permalink
Port more model API across to c++
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jun 20, 2017
1 parent f6358b2 commit 1a4a654
Show file tree
Hide file tree
Showing 10 changed files with 299 additions and 169 deletions.
44 changes: 36 additions & 8 deletions python/core/processing/qgsprocessingmodelalgorithm.sip
Expand Up @@ -535,6 +535,31 @@ Copies are protected to avoid slicing
:rtype: QgsProcessingModelAlgorithm.ChildAlgorithm
%End

bool removeChildAlgorithm( const QString &id );
%Docstring
Attempts to remove the child algorithm with matching ``id``.
Returns true if the algorithm could be removed, or false
if the algorithm could not be removed (e.g. due to other
child algorithms depending on it).
:rtype: bool
%End

QSet< QString > dependentChildAlgorithms( const QString &childId ) const;
%Docstring
Returns a list of the child algorithm IDs depending on the child
algorithm with the specified ``childId``.
.. seealso:: dependsOnChildAlgorithms()
:rtype: set of str
%End

QSet< QString > dependsOnChildAlgorithms( const QString &childId ) const;
%Docstring
Returns a list of the child algorithm IDs on which the child
algorithm with the specified ``childId`` depends upon.
.. seealso:: dependentChildAlgorithms()
:rtype: set of str
%End

void addModelParameter( QgsProcessingParameterDefinition *definition /Transfer/, const QgsProcessingModelAlgorithm::ModelParameter &component );
%Docstring
Adds a new parameter to the model, with the specified ``definition`` and graphical ``component``.
Expand All @@ -551,12 +576,22 @@ Copies are protected to avoid slicing
.. seealso:: removeModelParameter()
%End

void removeModelParameter( const QString &name );
bool removeModelParameter( const QString &name );
%Docstring
Removes an existing model parameter by ``name``. The definition of the matching parameter
is deleted.
Returns false if the parameter could not be deleted (e.g. if a child algorithm
depends on the parameter).
.. seealso:: addModelParameter()
.. seealso:: updateModelParameter()
:rtype: bool
%End

bool childAlgorithmsDependOnParameter( const QString &name ) const;
%Docstring
Returns true if any child algorithms depend on the model parameter
with the specified ``name``.
:rtype: bool
%End

QMap<QString, QgsProcessingModelAlgorithm::ModelParameter> parameterComponents() const;
Expand Down Expand Up @@ -597,13 +632,6 @@ Copies are protected to avoid slicing
:rtype: QgsProcessingModelAlgorithm.ModelParameter
%End



QStringList dependentChildAlgorithms( const QString &childId ) const;
%Docstring
:rtype: list of str
%End

};


Expand Down
111 changes: 5 additions & 106 deletions python/plugins/processing/modeler/ModelerAlgorithm.py
Expand Up @@ -179,8 +179,6 @@ class ModelerAlgorithm(QgsProcessingModelAlgorithm):
def __init__(self):
super().__init__()

# The dialog where this model is being edited
self.modelerdialog = None
self.descriptionFile = None
self.helpContent = {}

Expand All @@ -200,99 +198,6 @@ def updateAlgorithm(self, alg):
ModelerGraphicItem.BOX_WIDTH,
(i + 1.5) * ModelerGraphicItem.BOX_HEIGHT))

def removeAlgorithm(self, name):
"""Returns True if the algorithm could be removed, False if
others depend on it and could not be removed.
"""
if self.hasDependencies(name):
return False
del self.algs[name]
self.modelerdialog.hasChanged = True
return True

def removeParameter(self, name):
"""Returns True if the parameter could be removed, False if
others depend on it and could not be removed.
"""
if self.hasDependencies(name):
return False
self.removeModelParameter(name)
self.modelerdialog.hasChanged = True
return True

def hasDependencies(self, name):
"""This method returns True if some other element depends on
the passed one.
"""
for alg in list(self.algs.values()):
for value in list(alg.params.values()):
if value is None:
continue
if isinstance(value, list):
for v in value:
if isinstance(v, ValueFromInput):
if v.name == name:
return True
elif isinstance(v, ValueFromOutput):
if v.alg == name:
return True
if isinstance(value, ValueFromInput):
if value.name == name:
return True
elif isinstance(value, ValueFromOutput):
if value.alg == name:
return True
if alg.childId() != name:
for dep in alg.dependencies():
if (dep == name):
return True
return False

def getDependsOnAlgorithms(self, name):
"""This method returns a list with names of algorithms
a given one depends on.
"""
alg = self.algs[name]
algs = set()
algs.update(set(alg.dependencies()))
for value in list(alg.params.values()):
if value is None:
continue
if isinstance(value, CompoundValue):
for v in value.values:
if isinstance(v, ValueFromOutput):
algs.add(v.alg)
algs.update(self.getDependsOnAlgorithms(v.alg))
if isinstance(value, list):
for v in value:
if isinstance(v, ValueFromOutput):
algs.add(v.alg)
algs.update(self.getDependsOnAlgorithms(v.alg))
elif isinstance(value, ValueFromOutput):
algs.add(value.alg)
algs.update(self.getDependsOnAlgorithms(value.alg))

return algs

def getDependentAlgorithms(self, name):
"""This method returns a list with the names of algorithms
depending on a given one. It includes the algorithm itself
"""
algs = set()
algs.add(name)
for alg in list(self.algs.values()):
for value in list(alg.params.values()):
if value is None:
continue
if isinstance(value, list):
for v in value:
if isinstance(v, ValueFromOutput) and v.alg == name:
algs.update(self.getDependentAlgorithms(alg.childId()))
elif isinstance(value, ValueFromOutput) and value.alg == name:
algs.update(self.getDependentAlgorithms(alg.childId()))

return algs

def prepareAlgorithm(self, alg):
algInstance = alg.algorithm()
for param in algInstance.parameterDefinitions():
Expand Down Expand Up @@ -331,12 +236,13 @@ def prepareAlgorithm(self, alg):
return algInstance

def deactivateAlgorithm(self, algName):
dependent = self.getDependentAlgorithms(algName)
dependent = self.dependentChildAlgorithms(algName)
for alg in dependent:
self.algs[alg].setActive(False)
self.algs[algName].setActive(False)

def activateAlgorithm(self, algName):
parents = self.getDependsOnAlgorithms(algName)
parents = self.dependsOnChildAlgorithms(algName)
for alg in parents:
if not self.childAlgorithm(alg).isActive():
return False
Expand Down Expand Up @@ -368,7 +274,7 @@ def processAlgorithm(self, parameters, context, feedback):
for alg in toExecute:
if alg.childId() not in executed:
canExecute = True
required = self.getDependsOnAlgorithms(alg.childId())
required = self.dependsOnChildAlgorithms(alg.childId())
for requiredAlg in required:
if requiredAlg != alg.childId() and requiredAlg not in executed:
canExecute = False
Expand Down Expand Up @@ -411,13 +317,6 @@ def asPythonCommand(self, parameters, context):
else:
return None

def setModelerView(self, dialog):
self.modelerdialog = dialog

def updateModelerView(self):
if self.modelerdialog:
self.modelerdialog.repaintModel()

def helpUrl(self):
try:
return getHtmlFromDescriptionsDict(self, self.helpContent)
Expand Down Expand Up @@ -524,7 +423,7 @@ def toPython(self):
for alg in toExecute:
if alg.childId() not in executed:
canExecute = True
required = self.getDependsOnAlgorithms(alg.childId())
required = self.dependsOnChildAlgorithms(alg.childId())
for requiredAlg in required:
if requiredAlg != alg.childId() and requiredAlg not in executed:
canExecute = False
Expand Down
7 changes: 2 additions & 5 deletions python/plugins/processing/modeler/ModelerDialog.py
Expand Up @@ -93,7 +93,7 @@ def __init__(self, model=None):
self.restoreState(settings.value("/Processing/stateModeler", QByteArray()))
self.restoreGeometry(settings.value("/Processing/geometryModeler", QByteArray()))

self.scene = ModelerScene(self)
self.scene = ModelerScene(self, dialog=self)
self.scene.setSceneRect(QRectF(0, 0, self.CANVAS_SIZE, self.CANVAS_SIZE))

self.view.setScene(self.scene)
Expand Down Expand Up @@ -242,13 +242,11 @@ def _mimeDataAlgorithm(items):

else:
self.model = ModelerAlgorithm()
self.model.modelerdialog = self

self.fillInputsTree()
self.fillAlgorithmTree()

self.view.centerOn(0, 0)
self.model.setModelerView(self)
self.help = None

self.hasChanged = False
Expand Down Expand Up @@ -480,7 +478,6 @@ def openModel(self):
try:
alg = ModelerAlgorithm.fromFile(filename)
self.model = alg
self.model.setModelerView(self)
self.textGroup.setText(alg._group)
self.textName.setText(alg._name)
self.repaintModel()
Expand All @@ -502,7 +499,7 @@ def openModel(self):
'See the log for more information.'))

def repaintModel(self, controls=True):
self.scene = ModelerScene()
self.scene = ModelerScene(self, dialog=self)
self.scene.setSceneRect(QRectF(0, 0, ModelerAlgorithm.CANVAS_SIZE,
ModelerAlgorithm.CANVAS_SIZE))
self.scene.paintModel(self.model, controls)
Expand Down
19 changes: 11 additions & 8 deletions python/plugins/processing/modeler/ModelerGraphicItem.py
Expand Up @@ -46,10 +46,11 @@ class ModelerGraphicItem(QGraphicsItem):
BOX_HEIGHT = 30
BOX_WIDTH = 200

def __init__(self, element, model, controls):
def __init__(self, element, model, controls, scene=None):
super(ModelerGraphicItem, self).__init__(None)
self.controls = controls
self.model = model
self.scene = scene
self.element = element
if isinstance(element, QgsProcessingModelAlgorithm.ModelParameter):
svg = QSvgRenderer(os.path.join(pluginPath, 'images', 'input.svg'))
Expand Down Expand Up @@ -177,11 +178,11 @@ def contextMenuEvent(self, event):

def deactivateAlgorithm(self):
self.model.deactivateAlgorithm(self.element.childId())
self.model.updateModelerView()
self.scene.dialog.repaintModel()

def activateAlgorithm(self):
if self.model.activateAlgorithm(self.element.childId()):
self.model.updateModelerView()
self.scene.dialog.repaintModel()
else:
QMessageBox.warning(None, 'Could not activate Algorithm',
'The selected algorithm depends on other currently non-active algorithms.\n'
Expand Down Expand Up @@ -211,23 +212,25 @@ def editElement(self):
if dlg.alg is not None:
dlg.alg.setChildId(self.element.childId())
self.model.updateAlgorithm(dlg.alg)
self.model.updateModelerView()
self.scene.dialog.repaintModel()

def removeElement(self):
if isinstance(self.element, QgsProcessingModelAlgorithm.ModelParameter):
if not self.model.removeParameter(self.element.parameterName()):
if not self.model.removeModelParameter(self.element.parameterName()):
QMessageBox.warning(None, 'Could not remove element',
'Other elements depend on the selected one.\n'
'Remove them before trying to remove it.')
else:
self.model.updateModelerView()
self.scene.dialog.haschanged = True
self.scene.dialog.repaintModel()
elif isinstance(self.element, QgsProcessingModelAlgorithm.ChildAlgorithm):
if not self.model.removeAlgorithm(self.element.childId()):
if not self.model.removeChildAlgorithm(self.element.childId()):
QMessageBox.warning(None, 'Could not remove element',
'Other elements depend on the selected one.\n'
'Remove them before trying to remove it.')
else:
self.model.updateModelerView()
self.scene.dialog.haschanged = True
self.scene.dialog.repaintModel()

def getAdjustedText(self, text):
font = QFont('Verdana', 8)
Expand Down
10 changes: 6 additions & 4 deletions python/plugins/processing/modeler/ModelerParametersDialog.py
Expand Up @@ -200,7 +200,8 @@ def getAvailableDependencies(self): # spellok
if self._algName is None:
dependent = []
else:
dependent = self.model.getDependentAlgorithms(self._algName)
dependent = list(self.model.dependentChildAlgorithms(self._algName))
dependent.append(self._algName)
opts = []
for alg in list(self.model.childAlgorithms().values()):
if alg.childId() not in dependent:
Expand All @@ -225,11 +226,11 @@ def getAvailableValuesOfType(self, paramType, outTypes=[], dataType=None):
# upgrade paramType to list
if paramType is None:
paramType = []
elif type(paramType) is not list:
elif not isinstance(paramType, list):
paramType = [paramType]
if outTypes is None:
outTypes = []
elif type(outTypes) is not list:
elif not isinstance(outTypes, list):
outTypes = [outTypes]

values = []
Expand All @@ -249,7 +250,8 @@ def getAvailableValuesOfType(self, paramType, outTypes=[], dataType=None):
if self._algName is None:
dependent = []
else:
dependent = self.model.getDependentAlgorithms(self._algName)
dependent = list(self.model.dependentChildAlgorithms(self._algName))
dependent.insert(self._algName)
for alg in list(self.model.childAlgorithms().values()):
if alg.childId() not in dependent:
for out in alg.algorithm().outputDefinitions():
Expand Down

0 comments on commit 1a4a654

Please sign in to comment.