Skip to content
Permalink
Browse files

[processing] Port field mapper wrapper and widget to c++

Fixes #36706
  • Loading branch information
nyalldawson committed Jun 1, 2020
1 parent dbe9aa0 commit 146094f6b21876d10a3770ffe0018f1ce8a1047d
@@ -92,6 +92,13 @@ corresponding expression.
void scrollTo( const QModelIndex &index ) const;
%Docstring
Scroll the fields view to ``index``
%End

signals:

void changed();
%Docstring
Emitted when the fields defined in the widget are changed.
%End

public slots:
@@ -54,205 +54,17 @@
from processing.tools import dataobjects


pluginPath = os.path.dirname(__file__)
WIDGET, BASE = uic.loadUiType(
os.path.join(pluginPath, 'fieldsmappingpanelbase.ui'))


class FieldsMappingPanel(BASE, WIDGET):

def __init__(self, parent=None):
super(FieldsMappingPanel, self).__init__(parent)
self.setupUi(self)

self.addButton.setIcon(QgsApplication.getThemeIcon("/mActionNewAttribute.svg"))
self.deleteButton.setIcon(QgsApplication.getThemeIcon('/mActionDeleteAttribute.svg'))
self.upButton.setIcon(QgsApplication.getThemeIcon('/mActionArrowUp.svg'))
self.downButton.setIcon(QgsApplication.getThemeIcon('/mActionArrowDown.svg'))
self.resetButton.setIcon(QgsApplication.getThemeIcon('/mIconClearText.svg'))

self.configure()

self.layerCombo.setAllowEmptyLayer(True)
self.layerCombo.setFilters(QgsMapLayerProxyModel.VectorLayer)
self.dialogType = None
self.layer = None

def configure(self):
self.model = self.fieldsView.model()
self.fieldsView.setDestinationEditable(True)

def setLayer(self, layer):
if layer is None or self.layer == layer:
return
self.layer = layer
if self.model.rowCount(QModelIndex()) == 0:
self.on_resetButton_clicked()
return
dlg = QMessageBox(self)
dlg.setText(self.tr("Do you want to reset the field mapping?"))
dlg.setStandardButtons(
QMessageBox.StandardButtons(QMessageBox.Yes |
QMessageBox.No))
dlg.setDefaultButton(QMessageBox.No)
if dlg.exec_() == QMessageBox.Yes:
self.on_resetButton_clicked()

def value(self):
# Value is a dict with name, type, length, precision and expression
mapping = self.fieldsView.mapping()
results = []
for f in mapping:
results.append({
'name': f.field.name(),
'type': f.field.type(),
'length': f.field.length(),
'precision': f.field.precision(),
'expression': f.expression,
})
return results

def setValue(self, value):
if type(value) != dict:
return
destinationFields = QgsFields()
expressions = {}
for field_def in value:
f = QgsField(field_def.get('name'),
field_def.get('type', QVariant.Invalid),
field_def.get(QVariant.typeToName(field_def.get('type', QVariant.Invalid))),
field_def.get('length', 0),
field_def.get('precision', 0))
try:
expressions[f.name()] = field_def['expressions']
except AttributeError:
pass
destinationFields.append(f)

if len(destinationFields):
self.fieldsView.setDestinationFields(destinationFields, expressions)

@pyqtSlot(bool, name='on_addButton_clicked')
def on_addButton_clicked(self, checked=False):
rowCount = self.model.rowCount(QModelIndex())
self.model.appendField(QgsField('new_field'))
index = self.model.index(rowCount, 0)
self.fieldsView.selectionModel().select(
index,
QItemSelectionModel.SelectionFlags(
QItemSelectionModel.Clear |
QItemSelectionModel.Select |
QItemSelectionModel.Current |
QItemSelectionModel.Rows))
self.fieldsView.scrollTo(index)

@pyqtSlot(bool, name='on_deleteButton_clicked')
def on_deleteButton_clicked(self, checked=False):
self.fieldsView.removeSelectedFields()

@pyqtSlot(bool, name='on_upButton_clicked')
def on_upButton_clicked(self, checked=False):
self.fieldsView.moveSelectedFieldsUp()

@pyqtSlot(bool, name='on_downButton_clicked')
def on_downButton_clicked(self, checked=False):
self.fieldsView.moveSelectedFieldsDown()

@pyqtSlot(bool, name='on_resetButton_clicked')
def on_resetButton_clicked(self, checked=False):
"""Load fields from layer"""
if self.layer:
self.fieldsView.setSourceFields(self.layer.fields())
self.fieldsView.setDestinationFields(self.layer.fields())

@pyqtSlot(bool, name='on_loadLayerFieldsButton_clicked')
def on_loadLayerFieldsButton_clicked(self, checked=False):
layer = self.layerCombo.currentLayer()
if layer is None:
return

self.fieldsView.setSourceFields(layer.fields())
self.fieldsView.setDestinationFields(layer.fields())


class FieldsMappingWidgetWrapper(WidgetWrapper):

def __init__(self, *args, **kwargs):
super(FieldsMappingWidgetWrapper, self).__init__(*args, **kwargs)
self._layer = None

def createPanel(self):
return FieldsMappingPanel()

def createWidget(self):
self.panel = self.createPanel()
self.panel.dialogType = self.dialogType

if self.dialogType == DIALOG_MODELER:
self.combobox = QComboBox()
self.combobox.addItem(QCoreApplication.translate('Processing', '[Preconfigure]'), None)
#fieldsMappingInputs = self.dialog.getAvailableValuesOfType(FieldsMapper.ParameterFieldsMapping)
#for input in fieldsMappingInputs:
# self.combobox.addItem(self.dialog.resolveValueDescription(input), input)

def updatePanelEnabledState():
if self.combobox.currentData() is None:
self.panel.setEnabled(True)
else:
self.panel.setEnabled(False)

self.combobox.currentIndexChanged.connect(updatePanelEnabledState)

widget = QWidget()
widget.setLayout(QVBoxLayout())
widget.layout().addWidget(self.combobox)
widget.layout().addWidget(self.panel)
return widget
else:
return self.panel

def postInitialize(self, wrappers):
for wrapper in wrappers:
if wrapper.parameterDefinition().name() == self.parameterDefinition().parentLayerParameterName():
if wrapper.parameterValue():
self.setLayer(wrapper.parameterValue())
wrapper.widgetValueHasChanged.connect(self.parentLayerChanged)
break

# remove exiting spacers to get FieldsMappingPanel fully expanded
if self.dialogType in (DIALOG_STANDARD, DIALOG_MODELER):
layout = self.widget.parent().layout()
spacer = layout.itemAt(layout.count() - 1)
if isinstance(spacer, QSpacerItem):
layout.removeItem(spacer)

def parentLayerChanged(self, layer=None):
self.setLayer(self.sender().widgetValue())

def setLayer(self, layer):
context = dataobjects.createContext()
if layer == self._layer:
return
if isinstance(layer, QgsProcessingFeatureSourceDefinition):
layer, ok = layer.source.valueAsString(context.expressionContext())
if isinstance(layer, str):
layer = QgsProcessingUtils.mapLayerFromString(layer, context)
if not isinstance(layer, QgsVectorLayer):
layer = None
self._layer = layer
self.panel.setLayer(self._layer)

def linkedVectorLayer(self):
return self._layer

def setValue(self, value):
self.panel.setValue(value)

def value(self):
if self.dialogType == DIALOG_MODELER:
if self.combobox.currentData() is None:
return self.panel.value()
else:
return self.comboValue(combobox=self.combobox)
else:
return self.panel.value()
@@ -79,10 +79,6 @@ QgsRefactorFieldsAlgorithm *QgsRefactorFieldsAlgorithm::createInstance() const
void QgsRefactorFieldsAlgorithm::initParameters( const QVariantMap & )
{
std::unique_ptr< QgsProcessingParameterFieldMapping > param = qgis::make_unique< QgsProcessingParameterFieldMapping> ( QStringLiteral( "FIELDS_MAPPING" ), QObject::tr( "Fields mapping" ), QStringLiteral( "INPUT" ) );

QVariantMap metadata;
metadata.insert( QStringLiteral( "widget_wrapper" ), QStringLiteral( "processing.algs.qgis.ui.FieldsMappingPanel.FieldsMappingWidgetWrapper" ) );
param->setMetadata( metadata );
addParameter( param.release() );
}

@@ -270,6 +270,7 @@ SET(QGIS_GUI_SRCS
processing/qgsprocessingconfigurationwidgets.cpp
processing/qgsprocessingenummodelerwidget.cpp
processing/qgsprocessingfeaturesourceoptionswidget.cpp
processing/qgsprocessingfieldmapwidgetwrapper.cpp
processing/qgsprocessingguiregistry.cpp
processing/qgsprocessingmaplayercombobox.cpp
processing/qgsprocessingmatrixmodelerwidget.cpp
@@ -991,6 +992,7 @@ SET(QGIS_GUI_HDRS
processing/qgsprocessingconfigurationwidgets.h
processing/qgsprocessingenummodelerwidget.h
processing/qgsprocessingfeaturesourceoptionswidget.h
processing/qgsprocessingfieldmapwidgetwrapper.h
processing/qgsprocessinggui.h
processing/qgsprocessingguiregistry.h
processing/qgsprocessingmaplayercombobox.h

0 comments on commit 146094f

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