Skip to content

Commit

Permalink
Partial port of destination wrappers to c++ API
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Apr 1, 2020
1 parent 9c857ec commit c98cd8d
Show file tree
Hide file tree
Showing 16 changed files with 456 additions and 93 deletions.
Expand Up @@ -9,7 +9,6 @@




class QgsProcessingLayerOutputDestinationWidget : QWidget
{
%Docstring
Expand Down Expand Up @@ -52,6 +51,16 @@ Returns the widgets current value.
Sets the ``context`` in which the widget is shown, e.g., the
parent model algorithm, a linked map canvas, and other relevant information which allows the widget
to fine-tune its behavior.
%End

void addOpenAfterRunningOption();
%Docstring
Adds the "Open output file after running" option to the widget.
%End

bool openAfterRunning() const;
%Docstring
Returns ``True`` if the widget has the "Open output file after running" option checked.
%End

signals:
Expand Down
Expand Up @@ -302,6 +302,11 @@ current value is associated with.
Returns the current value of the parameter.

.. seealso:: :py:func:`setParameterValue`
%End

virtual QVariantMap customProperties() const;
%Docstring
Returns any custom properties set by the wrapper.
%End

void registerProcessingContextGenerator( QgsProcessingContextGenerator *generator );
Expand Down
3 changes: 0 additions & 3 deletions python/plugins/processing/algs/gdal/GdalAlgorithmDialog.py
Expand Up @@ -100,9 +100,6 @@ def connectParameterSignals(self):
for c in w.findChildren(QWidget):
self.connectWidgetChangedSignals(c)

for output_widget in self.outputWidgets.values():
self.connectWidgetChangedSignals(output_widget)

def connectWidgetChangedSignals(self, w):
if isinstance(w, QLineEdit):
w.textChanged.connect(self.parametersHaveChanged)
Expand Down
6 changes: 3 additions & 3 deletions python/plugins/processing/algs/qgis/CheckValidity.py
Expand Up @@ -96,13 +96,13 @@ def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterBoolean(self.IGNORE_RING_SELF_INTERSECTION,
self.tr('Ignore ring self intersections'), defaultValue=False))

self.addParameter(QgsProcessingParameterFeatureSink(self.VALID_OUTPUT, self.tr('Valid output'), QgsProcessing.TypeVectorAnyGeometry, '', True))
self.addParameter(QgsProcessingParameterFeatureSink(self.VALID_OUTPUT, self.tr('Valid output'), QgsProcessing.TypeVectorAnyGeometry, None, True))
self.addOutput(QgsProcessingOutputNumber(self.VALID_COUNT, self.tr('Count of valid features')))

self.addParameter(QgsProcessingParameterFeatureSink(self.INVALID_OUTPUT, self.tr('Invalid output'), QgsProcessing.TypeVectorAnyGeometry, '', True))
self.addParameter(QgsProcessingParameterFeatureSink(self.INVALID_OUTPUT, self.tr('Invalid output'), QgsProcessing.TypeVectorAnyGeometry, None, True))
self.addOutput(QgsProcessingOutputNumber(self.INVALID_COUNT, self.tr('Count of invalid features')))

self.addParameter(QgsProcessingParameterFeatureSink(self.ERROR_OUTPUT, self.tr('Error output'), QgsProcessing.TypeVectorAnyGeometry, '', True))
self.addParameter(QgsProcessingParameterFeatureSink(self.ERROR_OUTPUT, self.tr('Error output'), QgsProcessing.TypeVectorAnyGeometry, None, True))
self.addOutput(QgsProcessingOutputNumber(self.ERROR_COUNT, self.tr('Count of errors')))

def name(self):
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/qgis/UniqueValues.py
Expand Up @@ -79,7 +79,7 @@ def initAlgorithm(self, config=None):
self.tr('Target field(s)'),
parentLayerParameterName=self.INPUT, type=QgsProcessingParameterField.Any, allowMultiple=True))

self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Unique values'), optional=True, defaultValue=''))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Unique values'), optional=True, defaultValue=None))

self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT_HTML_FILE, self.tr('HTML report'), self.tr('HTML files (*.html)'), None, True))
self.addOutput(QgsProcessingOutputNumber(self.TOTAL_VALUES, self.tr('Total unique values')))
Expand Down
20 changes: 11 additions & 9 deletions python/plugins/processing/gui/AlgorithmDialog.py
Expand Up @@ -47,6 +47,7 @@
QgsProcessingFeatureSourceDefinition)
from qgis.gui import (QgsGui,
QgsMessageBar,
QgsProcessingLayerOutputDestinationWidget,
QgsProcessingAlgorithmDialogBase)
from qgis.utils import iface

Expand Down Expand Up @@ -155,16 +156,17 @@ def getParameterValues(self):
parameters[param.name()] = 'memory:'
continue

try:
wrapper = self.mainWidget().wrappers[param.name()]
except KeyError:
continue

widget = wrapper.wrappedWidget()
value = wrapper.parameterValue()

dest_project = None
if not param.flags() & QgsProcessingParameterDefinition.FlagHidden and \
isinstance(param, (QgsProcessingParameterRasterDestination,
QgsProcessingParameterFeatureSink,
QgsProcessingParameterVectorDestination)):
if self.mainWidget().checkBoxes[param.name()].isChecked():
dest_project = QgsProject.instance()

widget = self.mainWidget().outputWidgets[param.name()]
value = widget.value()
if wrapper.customProperties().get('OPEN_AFTER_RUNNING'):
dest_project = QgsProject.instance()

if value and isinstance(value, QgsProcessingOutputLayerDefinition):
value.destinationProject = dest_project
Expand Down
102 changes: 37 additions & 65 deletions python/plugins/processing/gui/ParametersPanel.py
Expand Up @@ -25,32 +25,17 @@
__date__ = 'August 2012'
__copyright__ = '(C) 2012, Victor Olaya'

import os

from functools import partial

from qgis.core import (QgsProcessingParameterDefinition,
QgsProcessingParameterExtent,
QgsProcessingParameterRasterDestination,
QgsProcessingParameterFeatureSink,
QgsProcessingParameterVectorDestination,
QgsProcessingOutputLayerDefinition,
QgsProject,
QgsProcessingModelAlgorithm,
QgsVectorFileWriter)
QgsProcessingModelAlgorithm)
from qgis.gui import (QgsProcessingContextGenerator,
QgsProcessingParameterWidgetContext,
QgsProcessingLayerOutputDestinationWidget,
QgsProcessingParametersWidget)
QgsProcessingParametersWidget,
QgsGui,
QgsProcessingGui)
from qgis.utils import iface

from qgis.PyQt.QtCore import QCoreApplication
from qgis.PyQt.QtWidgets import (
QLabel,
QCheckBox
)
from osgeo import gdal

from processing.gui.wrappers import WidgetWrapperFactory, WidgetWrapper
from processing.tools.dataobjects import createContext

Expand All @@ -62,8 +47,6 @@ def __init__(self, parent, alg, in_place=False):
self.in_place = in_place

self.wrappers = {}
self.outputWidgets = {}
self.checkBoxes = {}

self.processing_context = createContext()

Expand Down Expand Up @@ -160,47 +143,40 @@ def initWidgets(self):
if output.flags() & QgsProcessingParameterDefinition.FlagHidden:
continue

if self.in_place and param.name() in ('INPUT', 'OUTPUT'):
if self.in_place and output.name() in ('INPUT', 'OUTPUT'):
continue

label = QLabel(output.description())
widget = QgsProcessingLayerOutputDestinationWidget(output, False)
widget.setWidgetContext(widget_context)
wrapper = QgsGui.processingGuiRegistry().createParameterWidgetWrapper(output, QgsProcessingGui.Standard)
wrapper.setWidgetContext(widget_context)
wrapper.registerProcessingContextGenerator(self.context_generator)
self.wrappers[output.name()] = wrapper

self.addOutputLabel(label)
label = wrapper.createWrappedLabel()
if label is not None:
self.addOutputLabel(label)

widget = wrapper.createWrappedWidget(self.processing_context)
self.addOutputWidget(widget)
if isinstance(output, (QgsProcessingParameterRasterDestination, QgsProcessingParameterFeatureSink,
QgsProcessingParameterVectorDestination)):
check = QCheckBox()
check.setText(QCoreApplication.translate('ParametersPanel', 'Open output file after running algorithm'))

def skipOutputChanged(widget, checkbox, skipped):

enabled = not skipped

# Do not try to open formats that are write-only.
value = widget.value()
if value and isinstance(value, QgsProcessingOutputLayerDefinition) and isinstance(output, (
QgsProcessingParameterFeatureSink, QgsProcessingParameterVectorDestination)):
filename = value.sink.staticValue()
if filename not in ('memory:', ''):
path, ext = os.path.splitext(filename)
format = QgsVectorFileWriter.driverForExtension(ext)
drv = gdal.GetDriverByName(format)
if drv:
if drv.GetMetadataItem(gdal.DCAP_OPEN) is None:
enabled = False

checkbox.setEnabled(enabled)
checkbox.setChecked(enabled)

check.setChecked(not widget.outputIsSkipped())
check.setEnabled(not widget.outputIsSkipped())
widget.skipOutputChanged.connect(partial(skipOutputChanged, widget, check))
self.addOutputWidget(check)
self.checkBoxes[output.name()] = check

self.outputWidgets[output.name()] = widget

# def skipOutputChanged(widget, checkbox, skipped):
# TODO
# enabled = not skipped
#
# # Do not try to open formats that are write-only.
# value = widget.value()
# if value and isinstance(value, QgsProcessingOutputLayerDefinition) and isinstance(output, (
# QgsProcessingParameterFeatureSink, QgsProcessingParameterVectorDestination)):
# filename = value.sink.staticValue()
# if filename not in ('memory:', ''):
# path, ext = os.path.splitext(filename)
# format = QgsVectorFileWriter.driverForExtension(ext)
# drv = gdal.GetDriverByName(format)
# if drv:
# if drv.GetMetadataItem(gdal.DCAP_OPEN) is None:
# enabled = False
#
# checkbox.setEnabled(enabled)
# checkbox.setChecked(enabled)

for wrapper in list(self.wrappers.values()):
wrapper.postInitialize(list(self.wrappers.values()))
Expand All @@ -213,11 +189,7 @@ def setParameters(self, parameters):
if not param.name() in parameters:
continue

if not param.isDestination():
value = parameters[param.name()]
value = parameters[param.name()]

wrapper = self.wrappers[param.name()]
wrapper.setParameterValue(value, self.processing_context)
else:
dest_widget = self.outputWidgets[param.name()]
dest_widget.setValue(parameters[param.name()])
wrapper = self.wrappers[param.name()]
wrapper.setParameterValue(value, self.processing_context)
Expand Up @@ -521,7 +521,6 @@ def switchToCommentTab(self):
self.commentEdit.selectAll()

def setupUi(self):
self.checkBoxes = {}
self.showAdvanced = False
self.wrappers = {}
self.valueItems = {}
Expand Down
5 changes: 5 additions & 0 deletions src/gui/processing/qgsprocessingguiregistry.cpp
Expand Up @@ -58,6 +58,11 @@ QgsProcessingGuiRegistry::QgsProcessingGuiRegistry()
addParameterWidgetFactory( new QgsProcessingMeshLayerWidgetWrapper() );
addParameterWidgetFactory( new QgsProcessingBandWidgetWrapper() );
addParameterWidgetFactory( new QgsProcessingMultipleLayerWidgetWrapper() );
addParameterWidgetFactory( new QgsProcessingFeatureSinkWidgetWrapper() );
addParameterWidgetFactory( new QgsProcessingVectorDestinationWidgetWrapper() );
addParameterWidgetFactory( new QgsProcessingRasterDestinationWidgetWrapper() );
addParameterWidgetFactory( new QgsProcessingFileDestinationWidgetWrapper() );
addParameterWidgetFactory( new QgsProcessingFolderDestinationWidgetWrapper() );
}

QgsProcessingGuiRegistry::~QgsProcessingGuiRegistry()
Expand Down
21 changes: 21 additions & 0 deletions src/gui/processing/qgsprocessingoutputdestinationwidget.cpp
Expand Up @@ -26,6 +26,7 @@
#include <QMenu>
#include <QFileDialog>
#include <QInputDialog>
#include <QCheckBox>

///@cond NOT_STABLE

Expand Down Expand Up @@ -186,6 +187,26 @@ void QgsProcessingLayerOutputDestinationWidget::setWidgetContext( const QgsProce
mBrowserModel = context.browserModel();
}

void QgsProcessingLayerOutputDestinationWidget::addOpenAfterRunningOption()
{
mOpenAfterRunningCheck = new QCheckBox( tr( "Open output file after running algorithm" ) );
mOpenAfterRunningCheck->setChecked( !outputIsSkipped() );
mOpenAfterRunningCheck->setEnabled( !outputIsSkipped() );
gridLayout->addWidget( mOpenAfterRunningCheck, 1, 0, 1, 2 );

connect( this, &QgsProcessingLayerOutputDestinationWidget::skipOutputChanged, this, [ = ]( bool skipped )
{
bool enabled = !skipped;
mOpenAfterRunningCheck->setEnabled( enabled );
mOpenAfterRunningCheck->setChecked( enabled );
} );
}

bool QgsProcessingLayerOutputDestinationWidget::openAfterRunning() const
{
return mOpenAfterRunningCheck && mOpenAfterRunningCheck->isChecked();
}

void QgsProcessingLayerOutputDestinationWidget::menuAboutToShow()
{
mMenu->clear();
Expand Down
13 changes: 12 additions & 1 deletion src/gui/processing/qgsprocessingoutputdestinationwidget.h
Expand Up @@ -24,7 +24,7 @@

class QgsProcessingDestinationParameter;
class QgsBrowserGuiModel;

class QCheckBox;
///@cond NOT_STABLE

/**
Expand Down Expand Up @@ -66,6 +66,16 @@ class GUI_EXPORT QgsProcessingLayerOutputDestinationWidget : public QWidget, pri
*/
void setWidgetContext( const QgsProcessingParameterWidgetContext &context );

/**
* Adds the "Open output file after running" option to the widget.
*/
void addOpenAfterRunningOption();

/**
* Returns TRUE if the widget has the "Open output file after running" option checked.
*/
bool openAfterRunning() const;

signals:

/**
Expand Down Expand Up @@ -106,6 +116,7 @@ class GUI_EXPORT QgsProcessingLayerOutputDestinationWidget : public QWidget, pri
bool mDefaultSelection = false;
QString mEncoding;
QgsBrowserGuiModel *mBrowserModel = nullptr;
QCheckBox *mOpenAfterRunningCheck = nullptr;

friend class TestProcessingGui;
};
Expand Down
13 changes: 11 additions & 2 deletions src/gui/processing/qgsprocessingwidgetwrapper.cpp
Expand Up @@ -23,7 +23,7 @@
#include "qgsexpressioncontext.h"
#include "models/qgsprocessingmodelalgorithm.h"
#include "qgsexpressioncontextutils.h"

#include "qgsprocessingwidgetwrapperimpl.h"
#include <QLabel>
#include <QHBoxLayout>

Expand Down Expand Up @@ -151,7 +151,11 @@ QWidget *QgsAbstractProcessingParameterWidgetWrapper::createWrappedWidget( QgsPr
wrappedWidget->setLayout( hLayout );
}

setWidgetValue( mParameterDefinition->defaultValue(), context );
if ( !dynamic_cast<const QgsProcessingDestinationParameter * >( mParameterDefinition ) )
{
// an exception -- output widgets handle this themselves
setWidgetValue( mParameterDefinition->defaultValue(), context );
}

return wrappedWidget;
}
Expand Down Expand Up @@ -203,6 +207,11 @@ QVariant QgsAbstractProcessingParameterWidgetWrapper::parameterValue() const
return widgetValue();
}

QVariantMap QgsAbstractProcessingParameterWidgetWrapper::customProperties() const
{
return QVariantMap();
}

void QgsAbstractProcessingParameterWidgetWrapper::registerProcessingContextGenerator( QgsProcessingContextGenerator *generator )
{
mProcessingContextGenerator = generator;
Expand Down
5 changes: 5 additions & 0 deletions src/gui/processing/qgsprocessingwidgetwrapper.h
Expand Up @@ -344,6 +344,11 @@ class GUI_EXPORT QgsAbstractProcessingParameterWidgetWrapper : public QObject, p
*/
QVariant parameterValue() const;

/**
* Returns any custom properties set by the wrapper.
*/
virtual QVariantMap customProperties() const;

/**
* Registers a Processing context \a generator class that will be used to retrieve
* a Processing context for the wrapper when required.
Expand Down

0 comments on commit c98cd8d

Please sign in to comment.