Skip to content
Snippets Groups Projects
layerproperties.py 12 KiB
Newer Older
  • Learn to ignore specific revisions
  • 
    import sys, os, re, enum
    from qgis.core import *
    from qgis.gui import *
    from qgis.PyQt.QtCore import *
    from qgis.PyQt.QtGui import *
    from qgis.PyQt.QtWidgets import *
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    from eotimeseriesviewer.utils import loadUI
    
    
    
    class LabelFieldModel(QgsFieldModel):
    
        """
        A model to show the QgsFields of an QgsVectorLayer.
        Inherits QgsFieldModel and allows to change the name of the 1st column.
        """
    
        def __init__(self, parent):
    
            """
            Constructor
            :param parent:
            """
    
            super(LabelFieldModel, self).__init__(parent)
    
            self.mColumnNames = ['Fields']
    
        def headerData(self, col, orientation, role=Qt.DisplayRole):
            """
            Returns header data
            :param col: int
            :param orientation: Qt.Horizontal | Qt.Vertical
            :param role:
            :return: value
            """
    
            if Qt is None:
                return None
            if orientation == Qt.Horizontal and role == Qt.DisplayRole:
                return self.mColumnNames[col]
            elif orientation == Qt.Vertical and role == Qt.DisplayRole:
                return col
            return None
    
    
        def setHeaderData(self, col, orientation, value, role=Qt.EditRole):
            """
            Sets the header data.
            :param col: int
            :param orientation:
            :param value: any
            :param role:
            """
            result = False
    
            if role == Qt.EditRole:
                if orientation == Qt.Horizontal and col < len(self.mColumnNames) and isinstance(value, str):
                    self.mColumnNames[col] = value
                    result = True
    
            if result == True:
                self.headerDataChanged.emit(orientation, col, col)
            return result
    
    
    class FieldConfigEditorWidget(QWidget):
    
        class ConfigInfo(QStandardItem):
            """
            Describes a QgsEditorWidgetFactory configuration.
            """
            def __init__(self, key:str, factory:QgsEditorWidgetFactory, configWidget:QgsEditorConfigWidget):
                super(FieldConfigEditorWidget.ConfigInfo, self).__init__()
    
                assert isinstance(key, str)
                assert isinstance(factory, QgsEditorWidgetFactory)
                assert isinstance(configWidget, QgsEditorConfigWidget)
                self.mKey = key
                self.mFactory = factory
                self.mConfigWidget = configWidget
                self.setText(factory.name())
                self.setToolTip(factory.name())
                self.mInitialConfig = dict(configWidget.config())
    
    
            def resetConfig(self):
                """
                Resets the widget to its initial values
                """
                self.mConfigWidget.setConfig(dict(self.mInitialConfig))
    
            def factoryKey(self)->str:
                """
                Returns the QgsEditorWidgetFactory key, e.g. "CheckBox"
                :return: str
                """
                return self.mKey
    
            def factoryName(self)->str:
                """
                Returns the QgsEditorWidgetFactory name, e.g. "Checkbox"
                :return: str
                """
                return self.factory().name()
    
            def config(self)->dict:
                """
                Returns the config dictionary
                :return: dict
                """
                return self.mConfigWidget.config()
    
            def configWidget(self)->QgsEditorConfigWidget:
                """
                Returns the QgsEditorConfigWidget
                :return: QgsEditorConfigWidget
                """
                return self.mConfigWidget
    
            def factory(self)->QgsEditorWidgetFactory:
                """
                Returns the QgsEditorWidgetFactory
                :return: QgsEditorWidgetFactory
                """
                return self.mFactory
    
            def editorWidgetSetup(self)->QgsEditorWidgetSetup:
                """
                Creates a QgsEditorWidgetSetup
                :return: QgsEditorWidgetSetup
                """
                return QgsEditorWidgetSetup(self.factoryKey(), self.config())
    
    
        sigChanged = pyqtSignal(object)
    
        def __init__(self, parent, layer:QgsVectorLayer, index:int):
            super(FieldConfigEditorWidget, self).__init__(parent)
    
            self.setLayout(QVBoxLayout())
    
            assert isinstance(layer, QgsVectorLayer)
            assert isinstance(index, int)
    
            self.mLayer = layer
            self.mField = layer.fields().at(index)
            assert isinstance(self.mField, QgsField)
            self.mFieldIndex = index
    
            self.mFieldNameLabel = QLabel(parent)
            self.mFieldNameLabel.setText(self.mField.name())
    
            self.layout().addWidget(self.mFieldNameLabel)
    
            self.gbWidgetType = QgsCollapsibleGroupBox(self)
            self.gbWidgetType.setTitle('Widget Type')
            self.gbWidgetType.setLayout(QVBoxLayout())
            self.cbWidgetType = QComboBox(self.gbWidgetType)
    
            self.stackedWidget = QStackedWidget(self.gbWidgetType)
            self.gbWidgetType.layout().addWidget(self.cbWidgetType)
            self.gbWidgetType.layout().addWidget(self.stackedWidget)
    
    
            currentSetup = self.mLayer.editorWidgetSetup(self.mFieldIndex)
            self.mInitialConf = currentSetup.config()
            refkey = currentSetup.type()
            if refkey == '':
                refkey = QgsGui.editorWidgetRegistry().findBest(self.mLayer, self.mField.name()).type()
    
            self.mItemModel = QStandardItemModel(parent=self.cbWidgetType)
    
            iCurrent = -1
            i = 0
            factories = QgsGui.editorWidgetRegistry().factories()
            for key, fac in factories.items():
                assert isinstance(key, str)
                assert isinstance(fac, QgsEditorWidgetFactory)
                score = fac.fieldScore(self.mLayer, self.mFieldIndex)
                configWidget = fac.configWidget(self.mLayer, self.mFieldIndex, self.stackedWidget)
    
                if isinstance(configWidget, QgsEditorConfigWidget):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                    configWidget.changed.connect(lambda: self.sigChanged.emit(self))
    
                    self.stackedWidget.addWidget(configWidget)
                    confItem = FieldConfigEditorWidget.ConfigInfo(key, fac, configWidget)
                    if key == refkey:
                        iCurrent = i
                    confItem.setEnabled(score > 0)
                    confItem.setData(self, role=Qt.UserRole)
                    self.mItemModel.appendRow(confItem)
    
                    i += 1
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            if iCurrent == -1:
                s = ""
    
            self.cbWidgetType.setModel(self.mItemModel)
            self.cbWidgetType.currentIndexChanged.connect(self.updateConfigWidget)
    
            self.layout().addWidget(self.gbWidgetType)
            self.layout().addStretch()
            self.cbWidgetType.setCurrentIndex(iCurrent)
    
    
            conf = self.currentFieldConfig()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            if not isinstance(conf, FieldConfigEditorWidget.ConfigInfo):
                s = ""
            assert isinstance(conf, FieldConfigEditorWidget.ConfigInfo)
    
            self.mInitialFactoryKey = conf.factoryKey()
            self.mInitialConf = conf.config()
    
    
    
        def setFactory(self, factoryKey:str):
            """
            Shows the QgsEditorConfigWidget of QgsEditorWidgetFactory `factoryKey`
            :param factoryKey: str
            """
            for i in range(self.mItemModel.rowCount()):
                confItem = self.mItemModel.item(i)
                assert isinstance(confItem, FieldConfigEditorWidget.ConfigInfo)
                if confItem.factoryKey() == factoryKey:
                    self.cbWidgetType.setCurrentIndex(i)
                    break
    
    
        def changed(self)->bool:
            """
            Returns True if the QgsEditorWidgetFactory or its configuration has been changed
            :return: bool
            """
            w = self.currentEditorConfigWidget()
            assert isinstance(w, QgsEditorConfigWidget)
    
            recentConfigInfo = self.currentFieldConfig()
    
            if self.mInitialFactoryKey != recentConfigInfo.factoryKey():
                return True
            elif self.mInitialConf != recentConfigInfo.config():
                return True
    
            return False
    
        def apply(self):
            """
            Applies the
            :return:
            """
            if self.changed():
                configInfo = self.currentFieldConfig()
                self.mInitialConf = configInfo.config()
                self.mInitialFactoryKey = configInfo.factoryKey()
                setup = QgsEditorWidgetSetup(self.mInitialFactoryKey, self.mInitialConf)
                self.mLayer.setEditorWidgetSetup(self.mFieldIndex, setup)
    
        def reset(self):
            """
            Resets the widget to its initial status
            """
            if self.changed():
    
                self.setFactory(self.mInitialFactoryKey)
                self.currentEditorConfigWidget().setConfig(self.mInitialConf)
    
        def currentFieldConfig(self)->ConfigInfo:
            i = self.cbWidgetType.currentIndex()
            return self.mItemModel.item(i)
    
        def currentEditorConfigWidget(self)->QgsEditorConfigWidget:
            return self.currentFieldConfig().configWidget()
    
    
        def updateConfigWidget(self, index):
            self.stackedWidget.setCurrentIndex(index)
            fieldConfig = self.currentFieldConfig()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            if isinstance(fieldConfig, FieldConfigEditorWidget.ConfigInfo):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                self.sigChanged.emit(self)
            else:
                s  =""
    
    
    
    class LayerFieldConfigEditorWidget(QWidget, loadUI('layerfieldconfigeditorwidget.ui')):
        """
        A widget to set QgsVetorLayer field settings
        """
        def __init__(self, parent, *args, **kwds):
            super(LayerFieldConfigEditorWidget, self).__init__(parent,  *args, **kwds)
            self.setupUi(self)
    
    
            self.scrollArea.resizeEvent = self.onScrollAreaResize
    
            self.mFieldModel = LabelFieldModel(self)
            self.treeView.setModel(self.mFieldModel)
    
            self.treeView.selectionModel().currentRowChanged.connect(
                lambda current, _ : self.stackedWidget.setCurrentIndex(current.row())
            )
    
    
            self.btnApply = self.buttonBox.button(QDialogButtonBox.Apply)
            self.btnReset = self.buttonBox.button(QDialogButtonBox.Reset)
            self.btnApply.clicked.connect(self.onApply)
            self.btnReset.clicked.connect(self.onReset)
    
    
    
        def onScrollAreaResize(self, resizeEvent:QResizeEvent):
            """
            Forces the stackedWidget's width to fit into the scrollAreas viewport
            :param resizeEvent: QResizeEvent
            """
            assert isinstance(resizeEvent, QResizeEvent)
            self.stackedWidget.setMaximumWidth(resizeEvent.size().width())
            s  =""
    
    
        def onReset(self):
    
            sw = self.stackedWidget
            assert isinstance(sw, QStackedWidget)
    
            for i in range(sw.count()):
                w = sw.widget(i)
                assert isinstance(w, FieldConfigEditorWidget)
                w.reset()
            self.onSettingsChanged()
    
        def onApply(self):
    
            """
            Applies all changes to the QgsVectorLayer
            :return:
            """
    
    
            sw = self.stackedWidget
            assert isinstance(sw, QStackedWidget)
    
            for i in range(sw.count()):
                w = sw.widget(i)
                assert isinstance(w, FieldConfigEditorWidget)
                w.apply()
            self.onSettingsChanged()
    
    
        def setLayer(self, layer:QgsVectorLayer):
            """
    
            Sets the QgsVectorLayer
    
            :param layer:
            """
            self.mFieldModel.setLayer(layer)
            self.updateFieldWidgets()
    
    
        def layer(self)->QgsVectorLayer:
            """
            Returns the current QgsVectorLayer
            :return:
            """
            return self.mFieldModel.layer()
    
        def updateFieldWidgets(self):
            """
            Empties the stackedWidget and populates it with a FieldConfigEditor
            for each QgsVectorLayer field.
            """
    
            sw = self.stackedWidget
            assert isinstance(sw, QStackedWidget)
            while sw.count() > 0:
                sw.removeWidget(sw.widget(0))
    
            lyr = self.layer()
            if isinstance(lyr, QgsVectorLayer):
                for i in range(lyr.fields().count()):
                    w = FieldConfigEditorWidget(sw, lyr, i)
                    w.sigChanged.connect(self.onSettingsChanged)
                    sw.addWidget(w)
    
            self.onSettingsChanged()
    
        def onSettingsChanged(self):
    
            """
            Enables/disables buttons
            :return:
            """
    
            b = False
            for i in range(self.stackedWidget.count()):
                w = self.stackedWidget.widget(i)
                assert isinstance(w, FieldConfigEditorWidget)
                if w.changed():
                    b = True
                    break
    
            self.btnReset.setEnabled(b)
            self.btnApply.setEnabled(b)