Пример #1
0
class Ui_frmRptTitleBase(object):
    def setupUi(self, frmRptTitleBase):
        frmRptTitleBase.setObjectName(_fromUtf8("frmRptTitleBase"))
        frmRptTitleBase.resize(347, 495)
        self.gridLayout = QtGui.QGridLayout(frmRptTitleBase)
        self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
        self.scrollArea = QtGui.QScrollArea(frmRptTitleBase)
        self.scrollArea.setWidgetResizable(True)
        self.scrollArea.setObjectName(_fromUtf8("scrollArea"))
        self.scrollAreaWidgetContents = QtGui.QWidget(self.scrollArea)
        self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 327, 475))
        self.scrollAreaWidgetContents.setObjectName(_fromUtf8("scrollAreaWidgetContents"))
        self.verticalLayout = QtGui.QVBoxLayout(self.scrollAreaWidgetContents)
        self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
        self.label_10 = QtGui.QLabel(self.scrollAreaWidgetContents)
        self.label_10.setObjectName(_fromUtf8("label_10"))
        self.verticalLayout.addWidget(self.label_10)
        self.cboBorder = QtGui.QComboBox(self.scrollAreaWidgetContents)
        self.cboBorder.setObjectName(_fromUtf8("cboBorder"))
        self.cboBorder.addItem(_fromUtf8(""))
        self.cboBorder.addItem(_fromUtf8(""))
        self.cboBorder.addItem(_fromUtf8(""))
        self.cboBorder.addItem(_fromUtf8(""))
        self.cboBorder.addItem(_fromUtf8(""))
        self.cboBorder.addItem(_fromUtf8(""))
        self.verticalLayout.addWidget(self.cboBorder)
        self.label = QtGui.QLabel(self.scrollAreaWidgetContents)
        self.label.setObjectName(_fromUtf8("label"))
        self.verticalLayout.addWidget(self.label)
        self.btnTitleColor = QgsColorButton(self.scrollAreaWidgetContents)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.btnTitleColor.sizePolicy().hasHeightForWidth())
        self.btnTitleColor.setSizePolicy(sizePolicy)
        self.btnTitleColor.setMinimumSize(QtCore.QSize(32, 0))
        self.btnTitleColor.setMaximumSize(QtCore.QSize(1000, 16777215))
        self.btnTitleColor.setText(_fromUtf8(""))
        self.btnTitleColor.setObjectName(_fromUtf8("btnTitleColor"))
        self.verticalLayout.addWidget(self.btnTitleColor)
        self.label_2 = QtGui.QLabel(self.scrollAreaWidgetContents)
        self.label_2.setObjectName(_fromUtf8("label_2"))
        self.verticalLayout.addWidget(self.label_2)
        self.btnTitleFont = QtGui.QPushButton(self.scrollAreaWidgetContents)
        self.btnTitleFont.setObjectName(_fromUtf8("btnTitleFont"))
        self.verticalLayout.addWidget(self.btnTitleFont)
        self.label_3 = QtGui.QLabel(self.scrollAreaWidgetContents)
        self.label_3.setObjectName(_fromUtf8("label_3"))
        self.verticalLayout.addWidget(self.label_3)
        self.txtTitleHeight = QtGui.QLineEdit(self.scrollAreaWidgetContents)
        self.txtTitleHeight.setObjectName(_fromUtf8("txtTitleHeight"))
        self.verticalLayout.addWidget(self.txtTitleHeight)
        self.label_4 = QtGui.QLabel(self.scrollAreaWidgetContents)
        self.label_4.setObjectName(_fromUtf8("label_4"))
        self.verticalLayout.addWidget(self.label_4)
        self.cboTitleHAlign = QtGui.QComboBox(self.scrollAreaWidgetContents)
        self.cboTitleHAlign.setObjectName(_fromUtf8("cboTitleHAlign"))
        self.cboTitleHAlign.addItem(_fromUtf8(""))
        self.cboTitleHAlign.addItem(_fromUtf8(""))
        self.cboTitleHAlign.addItem(_fromUtf8(""))
        self.verticalLayout.addWidget(self.cboTitleHAlign)
        self.label_5 = QtGui.QLabel(self.scrollAreaWidgetContents)
        self.label_5.setObjectName(_fromUtf8("label_5"))
        self.verticalLayout.addWidget(self.label_5)
        self.txtTitleLeft = QtGui.QLineEdit(self.scrollAreaWidgetContents)
        self.txtTitleLeft.setObjectName(_fromUtf8("txtTitleLeft"))
        self.verticalLayout.addWidget(self.txtTitleLeft)
        self.label_6 = QtGui.QLabel(self.scrollAreaWidgetContents)
        self.label_6.setObjectName(_fromUtf8("label_6"))
        self.verticalLayout.addWidget(self.label_6)
        self.txtTitleText = QtGui.QLineEdit(self.scrollAreaWidgetContents)
        self.txtTitleText.setObjectName(_fromUtf8("txtTitleText"))
        self.verticalLayout.addWidget(self.txtTitleText)
        self.label_7 = QtGui.QLabel(self.scrollAreaWidgetContents)
        self.label_7.setObjectName(_fromUtf8("label_7"))
        self.verticalLayout.addWidget(self.label_7)
        self.txtTitleTop = QtGui.QLineEdit(self.scrollAreaWidgetContents)
        self.txtTitleTop.setObjectName(_fromUtf8("txtTitleTop"))
        self.verticalLayout.addWidget(self.txtTitleTop)
        self.label_8 = QtGui.QLabel(self.scrollAreaWidgetContents)
        self.label_8.setObjectName(_fromUtf8("label_8"))
        self.verticalLayout.addWidget(self.label_8)
        self.cboTitleVAlign = QtGui.QComboBox(self.scrollAreaWidgetContents)
        self.cboTitleVAlign.setObjectName(_fromUtf8("cboTitleVAlign"))
        self.cboTitleVAlign.addItem(_fromUtf8(""))
        self.cboTitleVAlign.addItem(_fromUtf8(""))
        self.cboTitleVAlign.addItem(_fromUtf8(""))
        self.verticalLayout.addWidget(self.cboTitleVAlign)
        self.label_9 = QtGui.QLabel(self.scrollAreaWidgetContents)
        self.label_9.setObjectName(_fromUtf8("label_9"))
        self.verticalLayout.addWidget(self.label_9)
        self.txtTitleWidth = QtGui.QLineEdit(self.scrollAreaWidgetContents)
        self.txtTitleWidth.setObjectName(_fromUtf8("txtTitleWidth"))
        self.verticalLayout.addWidget(self.txtTitleWidth)
        self.scrollArea.setWidget(self.scrollAreaWidgetContents)
        self.gridLayout.addWidget(self.scrollArea, 0, 0, 1, 1)

        self.retranslateUi(frmRptTitleBase)
        QtCore.QMetaObject.connectSlotsByName(frmRptTitleBase)

    def retranslateUi(self, frmRptTitleBase):
        frmRptTitleBase.setWindowTitle(QtGui.QApplication.translate("frmRptTitleBase", "Form", None, QtGui.QApplication.UnicodeUTF8))
        self.label_10.setText(QtGui.QApplication.translate("frmRptTitleBase", "Border", None, QtGui.QApplication.UnicodeUTF8))
        self.cboBorder.setItemText(0, QtGui.QApplication.translate("frmRptTitleBase", "None", None, QtGui.QApplication.UnicodeUTF8))
        self.cboBorder.setItemText(1, QtGui.QApplication.translate("frmRptTitleBase", "All", None, QtGui.QApplication.UnicodeUTF8))
        self.cboBorder.setItemText(2, QtGui.QApplication.translate("frmRptTitleBase", "Top", None, QtGui.QApplication.UnicodeUTF8))
        self.cboBorder.setItemText(3, QtGui.QApplication.translate("frmRptTitleBase", "Right", None, QtGui.QApplication.UnicodeUTF8))
        self.cboBorder.setItemText(4, QtGui.QApplication.translate("frmRptTitleBase", "Bottom", None, QtGui.QApplication.UnicodeUTF8))
        self.cboBorder.setItemText(5, QtGui.QApplication.translate("frmRptTitleBase", "Left", None, QtGui.QApplication.UnicodeUTF8))
        self.label.setText(QtGui.QApplication.translate("frmRptTitleBase", "Fore Color", None, QtGui.QApplication.UnicodeUTF8))
        self.label_2.setText(QtGui.QApplication.translate("frmRptTitleBase", "Font", None, QtGui.QApplication.UnicodeUTF8))
        self.btnTitleFont.setText(QtGui.QApplication.translate("frmRptTitleBase", "Select Font...", None, QtGui.QApplication.UnicodeUTF8))
        self.label_3.setText(QtGui.QApplication.translate("frmRptTitleBase", "Height (cm)", None, QtGui.QApplication.UnicodeUTF8))
        self.label_4.setText(QtGui.QApplication.translate("frmRptTitleBase", "Horizontal Alignment", None, QtGui.QApplication.UnicodeUTF8))
        self.cboTitleHAlign.setItemText(0, QtGui.QApplication.translate("frmRptTitleBase", "Left", None, QtGui.QApplication.UnicodeUTF8))
        self.cboTitleHAlign.setItemText(1, QtGui.QApplication.translate("frmRptTitleBase", "Right", None, QtGui.QApplication.UnicodeUTF8))
        self.cboTitleHAlign.setItemText(2, QtGui.QApplication.translate("frmRptTitleBase", "Center", None, QtGui.QApplication.UnicodeUTF8))
        self.label_5.setText(QtGui.QApplication.translate("frmRptTitleBase", "Left (cm)", None, QtGui.QApplication.UnicodeUTF8))
        self.label_6.setText(QtGui.QApplication.translate("frmRptTitleBase", "Text", None, QtGui.QApplication.UnicodeUTF8))
        self.label_7.setText(QtGui.QApplication.translate("frmRptTitleBase", "Top (cm)", None, QtGui.QApplication.UnicodeUTF8))
        self.label_8.setText(QtGui.QApplication.translate("frmRptTitleBase", "Vertical Alignment", None, QtGui.QApplication.UnicodeUTF8))
        self.cboTitleVAlign.setItemText(0, QtGui.QApplication.translate("frmRptTitleBase", "Top", None, QtGui.QApplication.UnicodeUTF8))
        self.cboTitleVAlign.setItemText(1, QtGui.QApplication.translate("frmRptTitleBase", "Middle", None, QtGui.QApplication.UnicodeUTF8))
        self.cboTitleVAlign.setItemText(2, QtGui.QApplication.translate("frmRptTitleBase", "Bottom", None, QtGui.QApplication.UnicodeUTF8))
        self.label_9.setText(QtGui.QApplication.translate("frmRptTitleBase", "Width (cm)", None, QtGui.QApplication.UnicodeUTF8))
Пример #2
0
class Ui_PCPropertiesWidget(object):
    def setupUi(self, PCPropertiesWidget):
        PCPropertiesWidget.setObjectName("PCPropertiesWidget")
        PCPropertiesWidget.resize(335, 420)
        self.verticalLayout = QtWidgets.QVBoxLayout(PCPropertiesWidget)
        self.verticalLayout.setObjectName("verticalLayout")
        self.groupBox = QtWidgets.QGroupBox(PCPropertiesWidget)
        self.groupBox.setObjectName("groupBox")
        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupBox)
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.formLayout = QtWidgets.QFormLayout()
        self.formLayout.setObjectName("formLayout")
        self.label = QtWidgets.QLabel(self.groupBox)
        self.label.setObjectName("label")
        self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label)
        self.lineEdit_Name = QtWidgets.QLineEdit(self.groupBox)
        self.lineEdit_Name.setObjectName("lineEdit_Name")
        self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.lineEdit_Name)
        self.label_3 = QtWidgets.QLabel(self.groupBox)
        self.label_3.setObjectName("label_3")
        self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_3)
        self.url = QtWidgets.QLineEdit(self.groupBox)
        self.url.setStyleSheet("background-color: #F0F0F0;")
        self.url.setReadOnly(True)
        self.url.setObjectName("url")
        self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.url)
        self.verticalLayout_2.addLayout(self.formLayout)
        self.label_2 = QtWidgets.QLabel(self.groupBox)
        self.label_2.setObjectName("label_2")
        self.verticalLayout_2.addWidget(self.label_2)
        self.textBrowser = QtWidgets.QTextBrowser(self.groupBox)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.textBrowser.sizePolicy().hasHeightForWidth())
        self.textBrowser.setSizePolicy(sizePolicy)
        self.textBrowser.setMinimumSize(QtCore.QSize(0, 100))
        self.textBrowser.setObjectName("textBrowser")
        self.verticalLayout_2.addWidget(self.textBrowser)
        self.verticalLayout.addWidget(self.groupBox)
        self.groupBox_2 = QtWidgets.QGroupBox(PCPropertiesWidget)
        self.groupBox_2.setObjectName("groupBox_2")
        self.formLayout_2 = QtWidgets.QFormLayout(self.groupBox_2)
        self.formLayout_2.setObjectName("formLayout_2")
        self.label_17 = QtWidgets.QLabel(self.groupBox_2)
        self.label_17.setObjectName("label_17")
        self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_17)
        self.gridLayout = QtWidgets.QGridLayout()
        self.gridLayout.setObjectName("gridLayout")
        self.horizontalSlider_Opacity = QtWidgets.QSlider(self.groupBox_2)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.horizontalSlider_Opacity.sizePolicy().hasHeightForWidth())
        self.horizontalSlider_Opacity.setSizePolicy(sizePolicy)
        self.horizontalSlider_Opacity.setMinimumSize(QtCore.QSize(0, 22))
        self.horizontalSlider_Opacity.setMaximum(100)
        self.horizontalSlider_Opacity.setProperty("value", 100)
        self.horizontalSlider_Opacity.setOrientation(QtCore.Qt.Horizontal)
        self.horizontalSlider_Opacity.setObjectName("horizontalSlider_Opacity")
        self.gridLayout.addWidget(self.horizontalSlider_Opacity, 0, 1, 1, 1)
        self.spinBox_Opacity = QtWidgets.QSpinBox(self.groupBox_2)
        self.spinBox_Opacity.setEnabled(True)
        self.spinBox_Opacity.setMinimumSize(QtCore.QSize(0, 22))
        self.spinBox_Opacity.setPrefix("")
        self.spinBox_Opacity.setMinimum(0)
        self.spinBox_Opacity.setMaximum(100)
        self.spinBox_Opacity.setSingleStep(1)
        self.spinBox_Opacity.setProperty("value", 100)
        self.spinBox_Opacity.setObjectName("spinBox_Opacity")
        self.gridLayout.addWidget(self.spinBox_Opacity, 0, 2, 1, 1)
        self.formLayout_2.setLayout(2, QtWidgets.QFormLayout.FieldRole, self.gridLayout)
        self.label_4 = QtWidgets.QLabel(self.groupBox_2)
        self.label_4.setObjectName("label_4")
        self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_4)
        self.comboBox_ColorType = QtWidgets.QComboBox(self.groupBox_2)
        self.comboBox_ColorType.setObjectName("comboBox_ColorType")
        self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.comboBox_ColorType)
        self.label_Color = QtWidgets.QLabel(self.groupBox_2)
        self.label_Color.setObjectName("label_Color")
        self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_Color)
        self.colorButton_Color = QgsColorButton(self.groupBox_2)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.colorButton_Color.sizePolicy().hasHeightForWidth())
        self.colorButton_Color.setSizePolicy(sizePolicy)
        self.colorButton_Color.setMinimumSize(QtCore.QSize(0, 22))
        self.colorButton_Color.setObjectName("colorButton_Color")
        self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.colorButton_Color)
        self.verticalLayout.addWidget(self.groupBox_2)
        self.groupBox_3 = QtWidgets.QGroupBox(PCPropertiesWidget)
        self.groupBox_3.setObjectName("groupBox_3")
        self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.groupBox_3)
        self.verticalLayout_3.setObjectName("verticalLayout_3")
        self.checkBox_BoxVisible = QtWidgets.QCheckBox(self.groupBox_3)
        self.checkBox_BoxVisible.setObjectName("checkBox_BoxVisible")
        self.verticalLayout_3.addWidget(self.checkBox_BoxVisible)
        self.checkBox_Visible = QtWidgets.QCheckBox(self.groupBox_3)
        self.checkBox_Visible.setChecked(True)
        self.checkBox_Visible.setObjectName("checkBox_Visible")
        self.verticalLayout_3.addWidget(self.checkBox_Visible)
        self.verticalLayout.addWidget(self.groupBox_3)
        spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        self.verticalLayout.addItem(spacerItem)

        self.retranslateUi(PCPropertiesWidget)
        self.spinBox_Opacity.valueChanged['int'].connect(self.horizontalSlider_Opacity.setValue)
        self.horizontalSlider_Opacity.valueChanged['int'].connect(self.spinBox_Opacity.setValue)
        QtCore.QMetaObject.connectSlotsByName(PCPropertiesWidget)
        PCPropertiesWidget.setTabOrder(self.lineEdit_Name, self.url)
        PCPropertiesWidget.setTabOrder(self.url, self.textBrowser)
        PCPropertiesWidget.setTabOrder(self.textBrowser, self.comboBox_ColorType)
        PCPropertiesWidget.setTabOrder(self.comboBox_ColorType, self.colorButton_Color)
        PCPropertiesWidget.setTabOrder(self.colorButton_Color, self.horizontalSlider_Opacity)
        PCPropertiesWidget.setTabOrder(self.horizontalSlider_Opacity, self.spinBox_Opacity)
        PCPropertiesWidget.setTabOrder(self.spinBox_Opacity, self.checkBox_BoxVisible)
        PCPropertiesWidget.setTabOrder(self.checkBox_BoxVisible, self.checkBox_Visible)

    def retranslateUi(self, PCPropertiesWidget):
        _translate = QtCore.QCoreApplication.translate
        PCPropertiesWidget.setWindowTitle(_translate("PCPropertiesWidget", "Form"))
        self.groupBox.setTitle(_translate("PCPropertiesWidget", "&General"))
        self.label.setText(_translate("PCPropertiesWidget", "Name"))
        self.label_3.setText(_translate("PCPropertiesWidget", "URL"))
        self.label_2.setText(_translate("PCPropertiesWidget", "Information"))
        self.groupBox_2.setTitle(_translate("PCPropertiesWidget", "&Material"))
        self.label_17.setText(_translate("PCPropertiesWidget", "Opacity (%)"))
        self.label_4.setText(_translate("PCPropertiesWidget", "Color type"))
        self.label_Color.setText(_translate("PCPropertiesWidget", "Color"))
        self.groupBox_3.setTitle(_translate("PCPropertiesWidget", "&Other Options"))
        self.checkBox_BoxVisible.setText(_translate("PCPropertiesWidget", "Show bounding boxes"))
        self.checkBox_Visible.setText(_translate("PCPropertiesWidget", "Visible on load"))
Пример #3
0
class Ui_B4UdigNL(object):
    def setupUi(self, B4UdigNL):
        B4UdigNL.setObjectName("B4UdigNL")
        B4UdigNL.resize(324, 432)
        B4UdigNL.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.verticalLayout = QtWidgets.QVBoxLayout(B4UdigNL)
        self.verticalLayout.setObjectName("verticalLayout")
        self.tabWidget = QtWidgets.QTabWidget(B4UdigNL)
        self.tabWidget.setEnabled(True)
        self.tabWidget.setAutoFillBackground(False)
        self.tabWidget.setElideMode(QtCore.Qt.ElideNone)
        self.tabWidget.setObjectName("tabWidget")
        self.messageTab = QtWidgets.QWidget()
        self.messageTab.setObjectName("messageTab")
        self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.messageTab)
        self.verticalLayout_4.setObjectName("verticalLayout_4")
        self.messageBox = QtWidgets.QGroupBox(self.messageTab)
        self.messageBox.setObjectName("messageBox")
        self.gridLayout = QtWidgets.QGridLayout(self.messageBox)
        self.gridLayout.setObjectName("gridLayout")
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.openMsgButton = QtWidgets.QPushButton(self.messageBox)
        self.openMsgButton.setObjectName("openMsgButton")
        self.horizontalLayout.addWidget(self.openMsgButton)
        self.openArchiveButton = QtWidgets.QPushButton(self.messageBox)
        self.openArchiveButton.setObjectName("openArchiveButton")
        self.horizontalLayout.addWidget(self.openArchiveButton)
        spacerItem = QtWidgets.QSpacerItem(68, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem)
        self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
        self.msgListWidget = QtWidgets.QListWidget(self.messageBox)
        self.msgListWidget.setMinimumSize(QtCore.QSize(100, 40))
        self.msgListWidget.setMaximumSize(QtCore.QSize(16777215, 60))
        self.msgListWidget.setObjectName("msgListWidget")
        self.gridLayout.addWidget(self.msgListWidget, 1, 0, 1, 1)
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.gotoButton = QtWidgets.QPushButton(self.messageBox)
        self.gotoButton.setObjectName("gotoButton")
        self.horizontalLayout_2.addWidget(self.gotoButton)
        self.bestScaleButton = QtWidgets.QPushButton(self.messageBox)
        self.bestScaleButton.setObjectName("bestScaleButton")
        self.horizontalLayout_2.addWidget(self.bestScaleButton)
        self.removeMsgButton = QtWidgets.QPushButton(self.messageBox)
        self.removeMsgButton.setObjectName("removeMsgButton")
        self.horizontalLayout_2.addWidget(self.removeMsgButton)
        spacerItem1 = QtWidgets.QSpacerItem(78, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem1)
        self.gridLayout.addLayout(self.horizontalLayout_2, 2, 0, 1, 1)
        self.verticalLayout_4.addWidget(self.messageBox)
        self.additionsBox = QtWidgets.QGroupBox(self.messageTab)
        self.additionsBox.setMaximumSize(QtCore.QSize(16777215, 300))
        self.additionsBox.setObjectName("additionsBox")
        self.gridLayout_2 = QtWidgets.QGridLayout(self.additionsBox)
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.treeWidget = QtWidgets.QTreeWidget(self.additionsBox)
        self.treeWidget.setMinimumSize(QtCore.QSize(100, 100))
        self.treeWidget.setMaximumSize(QtCore.QSize(16777215, 250))
        self.treeWidget.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
        self.treeWidget.setObjectName("treeWidget")
        self.treeWidget.headerItem().setText(0, "1")
        self.gridLayout_2.addWidget(self.treeWidget, 0, 0, 1, 1)
        self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        self.openDocButton = QtWidgets.QPushButton(self.additionsBox)
        self.openDocButton.setObjectName("openDocButton")
        self.horizontalLayout_3.addWidget(self.openDocButton)
        spacerItem2 = QtWidgets.QSpacerItem(168, 17, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_3.addItem(spacerItem2)
        self.gridLayout_2.addLayout(self.horizontalLayout_3, 1, 0, 1, 1)
        self.verticalLayout_4.addWidget(self.additionsBox)
        spacerItem3 = QtWidgets.QSpacerItem(17, 5, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        self.verticalLayout_4.addItem(spacerItem3)
        self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_4.setObjectName("horizontalLayout_4")
        self.saveButton = QtWidgets.QPushButton(self.messageTab)
        self.saveButton.setObjectName("saveButton")
        self.horizontalLayout_4.addWidget(self.saveButton)
        spacerItem4 = QtWidgets.QSpacerItem(13, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_4.addItem(spacerItem4)
        self.helpButton = QtWidgets.QPushButton(self.messageTab)
        self.helpButton.setObjectName("helpButton")
        self.horizontalLayout_4.addWidget(self.helpButton)
        self.closeButton = QtWidgets.QPushButton(self.messageTab)
        self.closeButton.setObjectName("closeButton")
        self.horizontalLayout_4.addWidget(self.closeButton)
        self.verticalLayout_4.addLayout(self.horizontalLayout_4)
        self.tabWidget.addTab(self.messageTab, "")
        self.ThemesTab = QtWidgets.QWidget()
        self.ThemesTab.setObjectName("ThemesTab")
        self.gridLayout_3 = QtWidgets.QGridLayout(self.ThemesTab)
        self.gridLayout_3.setObjectName("gridLayout_3")
        self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_5.setObjectName("horizontalLayout_5")
        self.mColorButton = QgsColorButton(self.ThemesTab)
        self.mColorButton.setMinimumSize(QtCore.QSize(40, 10))
        self.mColorButton.setMaximumSize(QtCore.QSize(40, 10))
        self.mColorButton.setAcceptDrops(False)
        self.mColorButton.setColor(QtGui.QColor(0, 255, 0))
        self.mColorButton.setShowMenu(False)
        self.mColorButton.setProperty("acceptLiveUpdates", False)
        self.mColorButton.setObjectName("mColorButton")
        self.horizontalLayout_5.addWidget(self.mColorButton)
        self.checkBoxData = QtWidgets.QCheckBox(self.ThemesTab)
        self.checkBoxData.setTristate(True)
        self.checkBoxData.setObjectName("checkBoxData")
        self.horizontalLayout_5.addWidget(self.checkBoxData)
        self.gridLayout_3.addLayout(self.horizontalLayout_5, 0, 0, 1, 1)
        self.refreshButton = QtWidgets.QPushButton(self.ThemesTab)
        self.refreshButton.setObjectName("refreshButton")
        self.gridLayout_3.addWidget(self.refreshButton, 0, 1, 2, 1)
        self.horizontalLayout_6 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_6.setObjectName("horizontalLayout_6")
        self.mColorButton_2 = QgsColorButton(self.ThemesTab)
        self.mColorButton_2.setMinimumSize(QtCore.QSize(40, 10))
        self.mColorButton_2.setMaximumSize(QtCore.QSize(40, 10))
        self.mColorButton_2.setAcceptDrops(False)
        self.mColorButton_2.setColor(QtGui.QColor(255, 215, 80))
        self.mColorButton_2.setShowMenu(False)
        self.mColorButton_2.setProperty("acceptLiveUpdates", False)
        self.mColorButton_2.setObjectName("mColorButton_2")
        self.horizontalLayout_6.addWidget(self.mColorButton_2)
        self.checkBoxGas_low = QtWidgets.QCheckBox(self.ThemesTab)
        self.checkBoxGas_low.setTristate(True)
        self.checkBoxGas_low.setObjectName("checkBoxGas_low")
        self.horizontalLayout_6.addWidget(self.checkBoxGas_low)
        self.gridLayout_3.addLayout(self.horizontalLayout_6, 1, 0, 1, 1)
        self.horizontalLayout_7 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_7.setObjectName("horizontalLayout_7")
        self.mColorButton_3 = QgsColorButton(self.ThemesTab)
        self.mColorButton_3.setMinimumSize(QtCore.QSize(40, 10))
        self.mColorButton_3.setMaximumSize(QtCore.QSize(40, 10))
        self.mColorButton_3.setAcceptDrops(False)
        self.mColorButton_3.setColor(QtGui.QColor(255, 175, 60))
        self.mColorButton_3.setShowMenu(False)
        self.mColorButton_3.setProperty("acceptLiveUpdates", False)
        self.mColorButton_3.setObjectName("mColorButton_3")
        self.horizontalLayout_7.addWidget(self.mColorButton_3)
        self.checkBoxGas_high = QtWidgets.QCheckBox(self.ThemesTab)
        self.checkBoxGas_high.setTristate(True)
        self.checkBoxGas_high.setObjectName("checkBoxGas_high")
        self.horizontalLayout_7.addWidget(self.checkBoxGas_high)
        self.gridLayout_3.addLayout(self.horizontalLayout_7, 2, 0, 1, 1)
        self.horizontalLayout_8 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_8.setObjectName("horizontalLayout_8")
        self.mColorButton_4 = QgsColorButton(self.ThemesTab)
        self.mColorButton_4.setMinimumSize(QtCore.QSize(40, 10))
        self.mColorButton_4.setMaximumSize(QtCore.QSize(40, 10))
        self.mColorButton_4.setAcceptDrops(False)
        self.mColorButton_4.setColor(QtGui.QColor(255, 127, 0))
        self.mColorButton_4.setShowMenu(False)
        self.mColorButton_4.setProperty("acceptLiveUpdates", False)
        self.mColorButton_4.setObjectName("mColorButton_4")
        self.horizontalLayout_8.addWidget(self.mColorButton_4)
        self.checkBoxDanger = QtWidgets.QCheckBox(self.ThemesTab)
        self.checkBoxDanger.setTristate(True)
        self.checkBoxDanger.setObjectName("checkBoxDanger")
        self.horizontalLayout_8.addWidget(self.checkBoxDanger)
        self.gridLayout_3.addLayout(self.horizontalLayout_8, 3, 0, 1, 2)
        self.horizontalLayout_20 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_20.setObjectName("horizontalLayout_20")
        self.mColorButton_8 = QgsColorButton(self.ThemesTab)
        self.mColorButton_8.setMinimumSize(QtCore.QSize(40, 10))
        self.mColorButton_8.setMaximumSize(QtCore.QSize(40, 10))
        self.mColorButton_8.setAcceptDrops(False)
        self.mColorButton_8.setColor(QtGui.QColor(255, 0, 0))
        self.mColorButton_8.setShowMenu(False)
        self.mColorButton_8.setProperty("acceptLiveUpdates", False)
        self.mColorButton_8.setObjectName("mColorButton_8")
        self.horizontalLayout_20.addWidget(self.mColorButton_8)
        self.checkBoxElec_land = QtWidgets.QCheckBox(self.ThemesTab)
        self.checkBoxElec_land.setTristate(True)
        self.checkBoxElec_land.setObjectName("checkBoxElec_land")
        self.horizontalLayout_20.addWidget(self.checkBoxElec_land)
        self.gridLayout_3.addLayout(self.horizontalLayout_20, 4, 0, 1, 2)
        self.horizontalLayout_11 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_11.setObjectName("horizontalLayout_11")
        self.mColorButton_7 = QgsColorButton(self.ThemesTab)
        self.mColorButton_7.setMinimumSize(QtCore.QSize(40, 10))
        self.mColorButton_7.setMaximumSize(QtCore.QSize(40, 10))
        self.mColorButton_7.setAcceptDrops(False)
        self.mColorButton_7.setColor(QtGui.QColor(255, 0, 0))
        self.mColorButton_7.setShowMenu(False)
        self.mColorButton_7.setProperty("acceptLiveUpdates", False)
        self.mColorButton_7.setObjectName("mColorButton_7")
        self.horizontalLayout_11.addWidget(self.mColorButton_7)
        self.checkBoxElec_high = QtWidgets.QCheckBox(self.ThemesTab)
        self.checkBoxElec_high.setTristate(True)
        self.checkBoxElec_high.setObjectName("checkBoxElec_high")
        self.horizontalLayout_11.addWidget(self.checkBoxElec_high)
        self.gridLayout_3.addLayout(self.horizontalLayout_11, 5, 0, 1, 1)
        self.horizontalLayout_10 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_10.setObjectName("horizontalLayout_10")
        self.mColorButton_6 = QgsColorButton(self.ThemesTab)
        self.mColorButton_6.setMinimumSize(QtCore.QSize(40, 10))
        self.mColorButton_6.setMaximumSize(QtCore.QSize(40, 10))
        self.mColorButton_6.setAcceptDrops(False)
        self.mColorButton_6.setColor(QtGui.QColor(200, 0, 0))
        self.mColorButton_6.setShowMenu(False)
        self.mColorButton_6.setProperty("acceptLiveUpdates", False)
        self.mColorButton_6.setObjectName("mColorButton_6")
        self.horizontalLayout_10.addWidget(self.mColorButton_6)
        self.checkBoxElec_mid = QtWidgets.QCheckBox(self.ThemesTab)
        self.checkBoxElec_mid.setTristate(True)
        self.checkBoxElec_mid.setObjectName("checkBoxElec_mid")
        self.horizontalLayout_10.addWidget(self.checkBoxElec_mid)
        self.gridLayout_3.addLayout(self.horizontalLayout_10, 6, 0, 1, 2)
        self.horizontalLayout_9 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_9.setObjectName("horizontalLayout_9")
        self.mColorButton_5 = QgsColorButton(self.ThemesTab)
        self.mColorButton_5.setMinimumSize(QtCore.QSize(40, 10))
        self.mColorButton_5.setMaximumSize(QtCore.QSize(40, 10))
        self.mColorButton_5.setAcceptDrops(False)
        self.mColorButton_5.setColor(QtGui.QColor(150, 0, 0))
        self.mColorButton_5.setShowMenu(False)
        self.mColorButton_5.setObjectName("mColorButton_5")
        self.horizontalLayout_9.addWidget(self.mColorButton_5)
        self.checkBoxElec_low = QtWidgets.QCheckBox(self.ThemesTab)
        self.checkBoxElec_low.setTristate(True)
        self.checkBoxElec_low.setObjectName("checkBoxElec_low")
        self.horizontalLayout_9.addWidget(self.checkBoxElec_low)
        self.gridLayout_3.addLayout(self.horizontalLayout_9, 7, 0, 1, 1)
        self.horizontalLayout_16 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_16.setObjectName("horizontalLayout_16")
        self.mColorButton_13 = QgsColorButton(self.ThemesTab)
        self.mColorButton_13.setMinimumSize(QtCore.QSize(40, 10))
        self.mColorButton_13.setMaximumSize(QtCore.QSize(40, 10))
        self.mColorButton_13.setAcceptDrops(False)
        self.mColorButton_13.setColor(QtGui.QColor(182, 74, 0))
        self.mColorButton_13.setShowMenu(False)
        self.mColorButton_13.setProperty("acceptLiveUpdates", False)
        self.mColorButton_13.setObjectName("mColorButton_13")
        self.horizontalLayout_16.addWidget(self.mColorButton_13)
        self.checkBoxChemical = QtWidgets.QCheckBox(self.ThemesTab)
        self.checkBoxChemical.setTristate(True)
        self.checkBoxChemical.setObjectName("checkBoxChemical")
        self.horizontalLayout_16.addWidget(self.checkBoxChemical)
        self.gridLayout_3.addLayout(self.horizontalLayout_16, 8, 0, 1, 1)
        self.vectorCheckBox = QtWidgets.QCheckBox(self.ThemesTab)
        self.vectorCheckBox.setObjectName("vectorCheckBox")
        self.gridLayout_3.addWidget(self.vectorCheckBox, 8, 1, 1, 1)
        self.horizontalLayout_12 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_12.setObjectName("horizontalLayout_12")
        self.mColorButton_9 = QgsColorButton(self.ThemesTab)
        self.mColorButton_9.setMinimumSize(QtCore.QSize(40, 10))
        self.mColorButton_9.setMaximumSize(QtCore.QSize(40, 10))
        self.mColorButton_9.setAcceptDrops(False)
        self.mColorButton_9.setColor(QtGui.QColor(186, 56, 168))
        self.mColorButton_9.setShowMenu(False)
        self.mColorButton_9.setObjectName("mColorButton_9")
        self.horizontalLayout_12.addWidget(self.mColorButton_9)
        self.checkBoxSewer_free = QtWidgets.QCheckBox(self.ThemesTab)
        self.checkBoxSewer_free.setTristate(True)
        self.checkBoxSewer_free.setObjectName("checkBoxSewer_free")
        self.horizontalLayout_12.addWidget(self.checkBoxSewer_free)
        self.gridLayout_3.addLayout(self.horizontalLayout_12, 9, 0, 1, 1)
        self.rasterCheckBox = QtWidgets.QCheckBox(self.ThemesTab)
        self.rasterCheckBox.setEnabled(True)
        self.rasterCheckBox.setObjectName("rasterCheckBox")
        self.gridLayout_3.addWidget(self.rasterCheckBox, 9, 1, 1, 1)
        self.horizontalLayout_13 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_13.setObjectName("horizontalLayout_13")
        self.mColorButton_10 = QgsColorButton(self.ThemesTab)
        self.mColorButton_10.setMinimumSize(QtCore.QSize(40, 10))
        self.mColorButton_10.setMaximumSize(QtCore.QSize(40, 10))
        self.mColorButton_10.setAcceptDrops(False)
        self.mColorButton_10.setColor(QtGui.QColor(128, 0, 128))
        self.mColorButton_10.setShowMenu(False)
        self.mColorButton_10.setProperty("acceptLiveUpdates", False)
        self.mColorButton_10.setObjectName("mColorButton_10")
        self.horizontalLayout_13.addWidget(self.mColorButton_10)
        self.checkBoxSewer_pressure = QtWidgets.QCheckBox(self.ThemesTab)
        self.checkBoxSewer_pressure.setTristate(True)
        self.checkBoxSewer_pressure.setObjectName("checkBoxSewer_pressure")
        self.horizontalLayout_13.addWidget(self.checkBoxSewer_pressure)
        self.gridLayout_3.addLayout(self.horizontalLayout_13, 10, 0, 1, 1)
        self.horizontalLayout_14 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_14.setObjectName("horizontalLayout_14")
        self.mColorButton_11 = QgsColorButton(self.ThemesTab)
        self.mColorButton_11.setMinimumSize(QtCore.QSize(40, 10))
        self.mColorButton_11.setMaximumSize(QtCore.QSize(40, 10))
        self.mColorButton_11.setAcceptDrops(False)
        self.mColorButton_11.setColor(QtGui.QColor(0, 128, 128))
        self.mColorButton_11.setShowMenu(False)
        self.mColorButton_11.setObjectName("mColorButton_11")
        self.horizontalLayout_14.addWidget(self.mColorButton_11)
        self.checkBoxHeat = QtWidgets.QCheckBox(self.ThemesTab)
        self.checkBoxHeat.setTristate(True)
        self.checkBoxHeat.setObjectName("checkBoxHeat")
        self.horizontalLayout_14.addWidget(self.checkBoxHeat)
        self.gridLayout_3.addLayout(self.horizontalLayout_14, 11, 0, 1, 1)
        self.annotationCheckBox = QtWidgets.QCheckBox(self.ThemesTab)
        self.annotationCheckBox.setTristate(True)
        self.annotationCheckBox.setObjectName("annotationCheckBox")
        self.gridLayout_3.addWidget(self.annotationCheckBox, 11, 1, 1, 1)
        self.horizontalLayout_15 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_15.setObjectName("horizontalLayout_15")
        self.mColorButton_12 = QgsColorButton(self.ThemesTab)
        self.mColorButton_12.setMinimumSize(QtCore.QSize(40, 10))
        self.mColorButton_12.setMaximumSize(QtCore.QSize(40, 10))
        self.mColorButton_12.setAcceptDrops(False)
        self.mColorButton_12.setColor(QtGui.QColor(0, 0, 255))
        self.mColorButton_12.setShowMenu(False)
        self.mColorButton_12.setObjectName("mColorButton_12")
        self.horizontalLayout_15.addWidget(self.mColorButton_12)
        self.checkBoxWater = QtWidgets.QCheckBox(self.ThemesTab)
        self.checkBoxWater.setTristate(True)
        self.checkBoxWater.setObjectName("checkBoxWater")
        self.horizontalLayout_15.addWidget(self.checkBoxWater)
        self.gridLayout_3.addLayout(self.horizontalLayout_15, 12, 0, 1, 1)
        self.dimensioningCheckBox = QtWidgets.QCheckBox(self.ThemesTab)
        self.dimensioningCheckBox.setTristate(True)
        self.dimensioningCheckBox.setObjectName("dimensioningCheckBox")
        self.gridLayout_3.addWidget(self.dimensioningCheckBox, 12, 1, 1, 1)
        self.horizontalLayout_17 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_17.setObjectName("horizontalLayout_17")
        self.mColorButton_14 = QgsColorButton(self.ThemesTab)
        self.mColorButton_14.setMinimumSize(QtCore.QSize(40, 10))
        self.mColorButton_14.setMaximumSize(QtCore.QSize(40, 10))
        self.mColorButton_14.setAcceptDrops(False)
        self.mColorButton_14.setColor(QtGui.QColor(145, 138, 111))
        self.mColorButton_14.setShowMenu(False)
        self.mColorButton_14.setObjectName("mColorButton_14")
        self.horizontalLayout_17.addWidget(self.mColorButton_14)
        self.checkBoxOrphan = QtWidgets.QCheckBox(self.ThemesTab)
        self.checkBoxOrphan.setTristate(True)
        self.checkBoxOrphan.setObjectName("checkBoxOrphan")
        self.horizontalLayout_17.addWidget(self.checkBoxOrphan)
        self.gridLayout_3.addLayout(self.horizontalLayout_17, 13, 0, 1, 1)
        self.locationCheckBox = QtWidgets.QCheckBox(self.ThemesTab)
        self.locationCheckBox.setTristate(True)
        self.locationCheckBox.setObjectName("locationCheckBox")
        self.gridLayout_3.addWidget(self.locationCheckBox, 13, 1, 1, 1)
        self.horizontalLayout_18 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_18.setObjectName("horizontalLayout_18")
        self.mColorButton_15 = QgsColorButton(self.ThemesTab)
        self.mColorButton_15.setMinimumSize(QtCore.QSize(40, 10))
        self.mColorButton_15.setMaximumSize(QtCore.QSize(40, 10))
        self.mColorButton_15.setAcceptDrops(False)
        self.mColorButton_15.setColor(QtGui.QColor(111, 92, 16))
        self.mColorButton_15.setShowMenu(False)
        self.mColorButton_15.setObjectName("mColorButton_15")
        self.horizontalLayout_18.addWidget(self.mColorButton_15)
        self.checkBoxOther = QtWidgets.QCheckBox(self.ThemesTab)
        self.checkBoxOther.setTristate(True)
        self.checkBoxOther.setObjectName("checkBoxOther")
        self.horizontalLayout_18.addWidget(self.checkBoxOther)
        self.gridLayout_3.addLayout(self.horizontalLayout_18, 14, 0, 1, 1)
        self.topoCheckBox = QtWidgets.QCheckBox(self.ThemesTab)
        self.topoCheckBox.setTristate(True)
        self.topoCheckBox.setObjectName("topoCheckBox")
        self.gridLayout_3.addWidget(self.topoCheckBox, 14, 1, 1, 1)
        self.tabWidget.addTab(self.ThemesTab, "")
        self.tab = QtWidgets.QWidget()
        self.tab.setObjectName("tab")
        self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.tab)
        self.verticalLayout_3.setObjectName("verticalLayout_3")
        self.groupBox = QtWidgets.QGroupBox(self.tab)
        self.groupBox.setObjectName("groupBox")
        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupBox)
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.horizontalLayout_19 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_19.setObjectName("horizontalLayout_19")
        self.optionMsgDirButton = QtWidgets.QPushButton(self.groupBox)
        self.optionMsgDirButton.setMinimumSize(QtCore.QSize(0, 0))
        self.optionMsgDirButton.setObjectName("optionMsgDirButton")
        self.horizontalLayout_19.addWidget(self.optionMsgDirButton)
        spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_19.addItem(spacerItem5)
        self.verticalLayout_2.addLayout(self.horizontalLayout_19)
        self.textEditDirPreffered = QtWidgets.QTextEdit(self.groupBox)
        self.textEditDirPreffered.setMinimumSize(QtCore.QSize(20, 20))
        self.textEditDirPreffered.setMaximumSize(QtCore.QSize(1000, 100))
        self.textEditDirPreffered.setBaseSize(QtCore.QSize(200, 40))
        self.textEditDirPreffered.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.textEditDirPreffered.setLineWrapMode(QtWidgets.QTextEdit.NoWrap)
        self.textEditDirPreffered.setReadOnly(True)
        self.textEditDirPreffered.setObjectName("textEditDirPreffered")
        self.verticalLayout_2.addWidget(self.textEditDirPreffered)
        self.verticalLayout_3.addWidget(self.groupBox)
        spacerItem6 = QtWidgets.QSpacerItem(20, 318, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        self.verticalLayout_3.addItem(spacerItem6)
        self.tabWidget.addTab(self.tab, "")
        self.verticalLayout.addWidget(self.tabWidget)

        self.retranslateUi(B4UdigNL)
        self.tabWidget.setCurrentIndex(1)
        QtCore.QMetaObject.connectSlotsByName(B4UdigNL)

    def retranslateUi(self, B4UdigNL):
        _translate = QtCore.QCoreApplication.translate
        B4UdigNL.setWindowTitle(_translate("B4UdigNL", "KLIC Viewer"))
        self.messageBox.setTitle(_translate("B4UdigNL", "KLIC Berichten"))
        self.openMsgButton.setText(_translate("B4UdigNL", "&Open Folder..."))
        self.openArchiveButton.setText(_translate("B4UdigNL", "Open &Zip-bestand..."))
        self.gotoButton.setText(_translate("B4UdigNL", "&Ga naar"))
        self.bestScaleButton.setText(_translate("B4UdigNL", "Beste S&chaal"))
        self.removeMsgButton.setText(_translate("B4UdigNL", "&Sluit Bericht"))
        self.additionsBox.setTitle(_translate("B4UdigNL", "Bijlagen"))
        self.openDocButton.setText(_translate("B4UdigNL", "Open &Bijlage(n)"))
        self.saveButton.setText(_translate("B4UdigNL", "Opslaan in Project"))
        self.helpButton.setText(_translate("B4UdigNL", "&Help..."))
        self.closeButton.setText(_translate("B4UdigNL", "Afsl&uiten"))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.messageTab), _translate("B4UdigNL", "Berichten"))
        self.checkBoxData.setText(_translate("B4UdigNL", "Datatransport"))
        self.refreshButton.setText(_translate("B4UdigNL", "&Ververs"))
        self.checkBoxGas_low.setText(_translate("B4UdigNL", "Gas lage druk"))
        self.checkBoxGas_high.setText(_translate("B4UdigNL", "Gas hoge druk"))
        self.checkBoxDanger.setText(_translate("B4UdigNL", "Buisleiding gevaarlijke inhoud"))
        self.checkBoxElec_land.setText(_translate("B4UdigNL", "Electriciteit landelijk  hoogspanningsnet"))
        self.checkBoxElec_high.setText(_translate("B4UdigNL", "Electriciteit hoogspanning"))
        self.checkBoxElec_mid.setText(_translate("B4UdigNL", "Electriciteit middenspanning"))
        self.checkBoxElec_low.setText(_translate("B4UdigNL", "Electriciteit laagspanning"))
        self.checkBoxChemical.setText(_translate("B4UdigNL", "(Petro) chemie"))
        self.vectorCheckBox.setText(_translate("B4UdigNL", "Vector"))
        self.checkBoxSewer_free.setText(_translate("B4UdigNL", "Riool vrij verval"))
        self.rasterCheckBox.setText(_translate("B4UdigNL", "Raster"))
        self.checkBoxSewer_pressure.setText(_translate("B4UdigNL", "Riool onder druk"))
        self.checkBoxHeat.setText(_translate("B4UdigNL", "Warmte"))
        self.annotationCheckBox.setText(_translate("B4UdigNL", "Annotatie"))
        self.checkBoxWater.setText(_translate("B4UdigNL", "Water "))
        self.dimensioningCheckBox.setText(_translate("B4UdigNL", "Maatvoering"))
        self.checkBoxOrphan.setText(_translate("B4UdigNL", "Wees"))
        self.locationCheckBox.setText(_translate("B4UdigNL", "Ligging"))
        self.checkBoxOther.setText(_translate("B4UdigNL", "Overig"))
        self.topoCheckBox.setText(_translate("B4UdigNL", "Topo"))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.ThemesTab), _translate("B4UdigNL", "Thema\'s"))
        self.groupBox.setTitle(_translate("B4UdigNL", "KLIC Berichten"))
        self.optionMsgDirButton.setText(_translate("B4UdigNL", "Standaard folder..."))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("B4UdigNL", "Opties"))
Пример #4
0
class Serval(object):
    def __init__(self, iface):
        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.plugin_dir = os.path.dirname(__file__)
        self.uc = UserCommunication(iface, 'Serval')
        self.mode = 'probe'
        self.bands = None
        self.raster = None
        self.px, self.py = [0, 0]
        self.last_point = QgsPointXY(0, 0)
        self.undos = defaultdict(list)
        self.redos = defaultdict(list)
        self.qgis_project = QgsProject()

        self.menu = u'Serval'
        self.actions = []
        self.toolbar = self.iface.addToolBar(u'Serval')
        self.toolbar.setObjectName(u'Serval')

        # Map tools
        self.probeTool = QgsMapToolEmitPoint(self.canvas)
        self.probeTool.setObjectName('ServalProbeTool')
        self.probeTool.setCursor(
            QCursor(QPixmap(icon_path('probe_tool.svg')), hotX=2, hotY=22))
        self.probeTool.canvasClicked.connect(self.point_clicked)
        self.drawTool = QgsMapToolEmitPoint(self.canvas)
        self.drawTool.setObjectName('ServalDrawTool')
        self.drawTool.setCursor(
            QCursor(QPixmap(icon_path('draw_tool.svg')), hotX=2, hotY=22))
        self.drawTool.canvasClicked.connect(self.point_clicked)
        self.gomTool = QgsMapToolEmitPoint(self.canvas)
        self.gomTool.setObjectName('ServalGomTool')
        self.gomTool.setCursor(
            QCursor(QPixmap(icon_path('gom_tool.svg')), hotX=5, hotY=19))
        self.gomTool.canvasClicked.connect(self.point_clicked)

        self.mColorButton = QgsColorButton()
        icon1 = QIcon(icon_path('mIconColorBox.svg'))
        self.mColorButton.setIcon(icon1)
        self.mColorButton.setMinimumSize(QSize(40, 24))
        self.mColorButton.setMaximumSize(QSize(40, 24))
        self.mColorButton.colorChanged.connect(self.set_rgb_from_picker)

        self.b1SBox = BandSpinBox()
        self.b2SBox = BandSpinBox()
        self.b3SBox = BandSpinBox()
        self.sboxes = [self.b1SBox, self.b2SBox, self.b3SBox]
        for sb in self.sboxes:
            sb.user_hit_enter.connect(self.change_cell_value_key)

        self.iface.currentLayerChanged.connect(self.set_active_raster)
        self.qgis_project.layersAdded.connect(self.set_active_raster)
        self.canvas.mapToolSet.connect(self.check_active_tool)

    def initGui(self):

        # Menu and toolbar actions
        self.add_action('serval_icon.svg',
                        text=u'Show Serval Toolbar',
                        add_to_menu=True,
                        add_to_toolbar=False,
                        callback=self.show_toolbar,
                        parent=self.iface.mainWindow())

        self.probe_btn = self.add_action('probe.svg',
                                         text=u'Probing Mode',
                                         whats_this=u'Probing Mode',
                                         add_to_toolbar=True,
                                         callback=self.activate_probing,
                                         parent=self.iface.mainWindow())

        self.draw_btn = self.add_action('draw.svg',
                                        text=u'Drawing Mode',
                                        whats_this=u'Drawing Mode',
                                        add_to_toolbar=True,
                                        callback=self.activate_drawing,
                                        parent=self.iface.mainWindow())

        self.gom_btn = self.add_action(
            'gom.svg',
            text=u'Set Raster Cell Value to NoData',
            whats_this=u'Set Raster Cell Value to NoData',
            add_to_toolbar=True,
            callback=self.activate_gom,
            parent=self.iface.mainWindow())

        self.checkable_tool_btns = [
            self.draw_btn, self.probe_btn, self.gom_btn
        ]

        self.def_nodata_btn = self.add_action(
            'define_nodata.svg',
            text=u'Define/Change Raster NoData Value',
            whats_this=u'Define/Change Raster NoData Value',
            add_to_toolbar=True,
            callback=self.define_nodata,
            parent=self.iface.mainWindow())

        self.toolbar.addWidget(self.mColorButton)

        self.setup_spin_boxes()

        self.undo_btn = self.add_action('undo.svg',
                                        text=u'Undo',
                                        whats_this=u'Undo',
                                        add_to_toolbar=True,
                                        callback=self.undo,
                                        parent=self.iface.mainWindow())

        self.redo_btn = self.add_action('redo.svg',
                                        text=u'Redo',
                                        whats_this=u'Redo',
                                        add_to_toolbar=True,
                                        callback=self.redo,
                                        parent=self.iface.mainWindow())

        self.show_help = self.add_action('help.svg',
                                         text=u'Help',
                                         whats_this=u'Help',
                                         add_to_toolbar=True,
                                         add_to_menu=True,
                                         callback=self.show_website,
                                         parent=self.iface.mainWindow())

        self.set_active_raster()
        self.check_undo_redo_btns()

    def add_action(self,
                   icon_name,
                   text,
                   callback,
                   enabled_flag=True,
                   add_to_menu=False,
                   add_to_toolbar=True,
                   status_tip=None,
                   whats_this=None,
                   parent=None):

        icon = QIcon(icon_path(icon_name))
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)

        if status_tip is not None:
            action.setStatusTip(status_tip)

        if whats_this is not None:
            action.setWhatsThis(whats_this)

        if add_to_toolbar:
            self.toolbar.addAction(action)

        if add_to_menu:
            self.iface.addPluginToMenu(self.menu, action)

        self.actions.append(action)
        return action

    def unload(self):
        self.iface.actionPan().trigger()

        for action in self.actions:
            self.iface.removePluginMenu(u'Serval', action)
            self.iface.removeToolBarIcon(action)

        del self.toolbar

    def show_toolbar(self):
        if self.toolbar:
            self.toolbar.show()

    def check_active_tool(self, tool):
        try:
            if not tool.objectName() in [
                    'ServalDrawTool', 'ServalProbeTool', 'ServalGomTool'
            ]:
                self.probe_btn.setChecked(False)
                self.draw_btn.setChecked(False)
                self.gom_btn.setChecked(False)
        except AttributeError:
            pass

    def set_checked_tool_btn(self, cur_tool_btn):
        for btn in self.checkable_tool_btns:
            if btn == cur_tool_btn:
                btn.setChecked(True)
            else:
                btn.setChecked(False)

    def activate_probing(self):
        self.mode = 'probe'
        self.canvas.setMapTool(self.probeTool)
        self.set_checked_tool_btn(self.probe_btn)

    def activate_drawing(self):
        self.mode = 'draw'
        self.canvas.setMapTool(self.drawTool)
        self.set_checked_tool_btn(self.draw_btn)

    def activate_gom(self):
        self.mode = 'gom'
        self.canvas.setMapTool(self.gomTool)
        self.set_checked_tool_btn(self.gom_btn)

    def setup_spin_boxes(self):

        for sbox in self.sboxes:
            sbox.setMinimumSize(QSize(60, 25))
            sbox.setMaximumSize(QSize(60, 25))
            sbox.setAlignment(Qt.AlignLeft)
            sbox.setButtonSymbols(QAbstractSpinBox.NoButtons)
            sbox.setKeyboardTracking(False)
            sbox.setShowClearButton(False)
            sbox.setExpressionsEnabled(False)
            sbox.setStyleSheet("")
            self.toolbar.addWidget(sbox)

    def point_clicked(self, point=None, button=None):
        # check if active layer is raster
        if self.raster is None:
            self.uc.bar_warn("Choose a raster to work with...", dur=3)
            return

        # check if coordinates trasformation is required
        canvas_srs = self.iface.mapCanvas().mapSettings().destinationCrs()
        if point is None:
            pos = self.last_point
        elif not canvas_srs == self.raster.crs():
            project = QgsProject.instance()
            srs_transform = QgsCoordinateTransform(canvas_srs,
                                                   self.raster.crs(), project)
            try:
                pos = srs_transform.transform(point)
            except QgsCsException as err:
                self.uc.bar_warn(
                    "Point coordinates transformation failed! Check the raster projection:\n\n{}"
                    .format(repr(err)),
                    dur=5)
                return
        else:
            pos = QgsPointXY(point.x(), point.y())

        # keep last clicked point
        self.last_point = pos

        # check if the point is within active raster bounds
        if self.rbounds[0] <= pos.x() <= self.rbounds[2]:
            self.px = int((pos.x() - self.rbounds[0]) /
                          self.raster.rasterUnitsPerPixelX()
                          )  # - self.gt[0]) / self.gt[1])
        else:
            self.uc.bar_info("Out of x bounds", dur=2)
            return

        if self.rbounds[1] <= pos.y() <= self.rbounds[3]:
            self.py = int((self.rbounds[3] - pos.y()) /
                          self.raster.rasterUnitsPerPixelY()
                          )  #  - self.gt[3]) / self.gt[5])
        else:
            self.uc.bar_info("Out of y bounds", dur=2)
            return

        # probe current raster value, dict: band_nr -> value
        vals = self.rdp.identify(pos, QgsRaster.IdentifyFormatValue).results()

        # for rasters having more that 3 bands, ignore other than 1-3
        bands_to_ignore = [i for i in vals.keys() if i > 3]
        for band_nr in bands_to_ignore:
            del vals[band_nr]

        # data types for each band
        dtypes = []

        for nr in range(1, min(4, self.band_count + 1)):
            # bands data type
            dtypes.append(self.bands[nr]['qtype'])

            # check if nodata is defined
            if self.mode == 'gom' and self.bands[nr]['nodata'] is None:
                msg = 'NODATA value is not defined for one of the raster\'s bands.\n'
                msg += 'Please define it in raster properties dialog!'
                self.uc.show_warn(msg)
                return

            # if in probing mode, set band's spinbox value
            if self.mode == 'probe':
                val = vals[nr] if is_number(
                    vals[nr]) else self.bands[nr]['nodata']
                self.bands[nr]['sbox'].setValue(val)
                self.bands[nr]['sbox'].setFocus()
                self.bands[nr]['sbox'].selectAll()

        if not self.mode == 'probe':

            old_vals = [
                v if v is not None else self.bands[k]['nodata']
                for k, v in sorted(vals.items())
            ]
            if self.mode == 'gom':
                temp_vals = [
                    self.bands[nr]['nodata'] for nr in sorted(vals.keys())
                ]
                new_vals = [
                    int(v) if dtypes[i] < 6 else float(v)
                    for i, v in enumerate(temp_vals)
                ]
            else:
                temp_vals = [
                    self.bands[nr]['sbox'].value()
                    for nr in sorted(vals.keys())
                ]
                new_vals = [
                    int(v) if dtypes[i] < 6 else float(v)
                    for i, v in enumerate(temp_vals)
                ]

            # store all bands' changes to undo list
            self.undos[self.raster.id()].append(
                [old_vals, new_vals, self.px, self.py, pos])

            # write the new cell value(s)
            self.change_cell_value(new_vals)

        if self.band_count > 2:
            self.mColorButton.setColor(
                QColor(self.bands[1]['sbox'].value(),
                       self.bands[2]['sbox'].value(),
                       self.bands[3]['sbox'].value()))

    def set_rgb_from_picker(self, c):
        """Set bands spinboxes values after color change in the color picker"""
        self.bands[1]['sbox'].setValue(c.red())
        self.bands[2]['sbox'].setValue(c.green())
        self.bands[3]['sbox'].setValue(c.blue())

    def change_cell_value(self, vals, x=None, y=None):
        """Save new bands values to data provider"""

        if not self.rdp.isEditable():
            success = self.rdp.setEditable(True)
            if not success:
                self.uc.show_warn('QGIS can\'t modify this type of raster')
                return

        if not x:
            x = self.px
            y = self.py

        for nr in range(1, min(4, self.band_count + 1)):
            rblock = QgsRasterBlock(self.bands[nr]['qtype'], 1, 1)
            rblock.setValue(0, 0, vals[nr - 1])
            success = self.rdp.writeBlock(rblock, nr, x, y)
            if not success:
                self.uc.show_warn('QGIS can\'t modify this type of raster')
                return

        self.rdp.setEditable(False)
        self.raster.triggerRepaint()

        # prepare raster for next actions
        self.prepare_raster(True)
        self.check_undo_redo_btns()

    def change_cell_value_key(self):
        """Change cell value after user changes band's spinbox value and hits Enter key"""
        if self.last_point:
            pm = self.mode
            self.mode = 'draw'
            self.point_clicked()
            self.mode = pm

    def undo(self):
        if self.undos[self.raster.id()]:
            data = self.undos[self.raster.id()].pop()
            self.redos[self.raster.id()].append(data)
        else:
            return
        self.change_cell_value(data[0], data[2], data[3])

    def redo(self):
        if self.redos[self.raster.id()]:
            data = self.redos[self.raster.id()].pop()
            self.undos[self.raster.id()].append(data)
        else:
            return
        self.change_cell_value(data[1], data[2], data[3])

    def define_nodata(self):
        """Define and write a new NoData value to raster file"""
        if not self.raster:
            self.uc.bar_warn(
                'Select a raster layer to define/change NoData value!')
            return

        # check if user defined additional NODATA value
        if self.rdp.userNoDataValues(1):
            note = '\nNote: there is a user defined NODATA value.\nCheck the raster properties (Transparency).'
        else:
            note = ''
        # first band data type
        dt = self.rdp.dataType(1)

        # current NODATA value
        if self.rdp.sourceHasNoDataValue(1):
            cur_nodata = self.rdp.sourceNoDataValue(1)
            if dt < 6:
                cur_nodata = '{0:d}'.format(int(float(cur_nodata)))
        else:
            cur_nodata = ''

        label = 'Define/change raster NODATA value.\n\n'
        label += 'Raster data type: {}.{}'.format(dtypes[dt]['name'], note)
        nd, ok = QInputDialog.getText(None, "Define NODATA Value", label,
                                      QLineEdit.Normal, str(cur_nodata))
        if not ok:
            return

        if not is_number(nd):
            self.uc.show_warn('Wrong NODATA value!')
            return

        new_nodata = int(nd) if dt < 6 else float(nd)

        # set the NODATA value for each band
        res = []
        for nr in range(1, min(4, self.band_count + 1)):
            res.append(self.rdp.setNoDataValue(nr, new_nodata))
            self.rdp.sourceHasNoDataValue(nr)

        if False in res:
            self.uc.show_warn('Setting new NODATA value failed!')
        else:
            self.uc.bar_info('Succesful setting new NODATA values!', dur=2)

        self.prepare_raster()
        self.raster.triggerRepaint()

    def check_undo_redo_btns(self):
        """Enable/Disable undo and redo buttons based on availability of undo/redo steps"""
        try:
            if len(self.undos[self.raster.id()]) == 0:
                self.undo_btn.setDisabled(True)
            else:
                self.undo_btn.setEnabled(True)
        except:
            self.undo_btn.setDisabled(True)

        try:
            if len(self.redos[self.raster.id()]) == 0:
                self.redo_btn.setDisabled(True)
            else:
                self.redo_btn.setEnabled(True)
        except:
            self.redo_btn.setDisabled(True)

    def disable_toolbar_actions(self):
        # disable all toolbar actions but Help (for vectors and unsupported rasters)
        for action in self.actions:
            action.setDisabled(True)
        self.show_help.setEnabled(True)

    def check_layer(self, layer):
        """Check if we can work with the raster"""
        if layer == None \
                or not layer.isValid() \
                or not layer.type() == raster_layer_type \
                or not (layer.dataProvider().capabilities() & QgsRasterDataProvider.Create) \
                or layer.crs() is None:
            return False
        else:
            return True

    def set_active_raster(self):
        """Active layer has change - check if it is a raster layer and prepare it for the plugin"""

        if self.bands:
            self.bands = None

        for sbox in self.sboxes:
            sbox.setValue(0)

        layer = self.iface.activeLayer()

        if self.check_layer(layer):
            self.raster = layer
            self.rdp = layer.dataProvider()
            self.band_count = layer.bandCount()

            # is data type supported?
            supported = True
            for nr in range(1, min(4, self.band_count + 1)):
                if self.rdp.dataType(nr) == 0 or self.rdp.dataType(nr) > 7:
                    t = dtypes[self.rdp.dataType(nr)]['name']
                    supported = False

            if supported:
                # enable all toolbar actions
                for action in self.actions:
                    action.setEnabled(True)
                # if raster properties change, get them (refeshes view)
                self.raster.rendererChanged.connect(self.prepare_raster)

                self.prepare_raster(supported)

            # not supported data type
            else:
                msg = 'The raster data type is: {}.'.format(t)
                msg += '\nServal can\'t work with it, sorry!'
                self.uc.show_warn(msg)
                self.reset_raster()

        # it is not a supported raster layer
        else:
            self.reset_raster()

        self.check_undo_redo_btns()

    def reset_raster(self):
        self.raster = None
        self.mColorButton.setDisabled(True)
        self.prepare_raster(False)

    def prepare_raster(self, supported=True):
        """Open raster using GDAL if it is supported"""

        # reset bands' spin boxes
        for i, sbox in enumerate(self.sboxes):
            sbox.setProperty('bandNr', i + 1)
            sbox.setDisabled(True)

        if not supported:
            return

        if self.band_count > 2:
            self.mColorButton.setEnabled(True)
        else:
            self.mColorButton.setDisabled(True)

        extent = self.raster.extent()
        self.rbounds = extent.toRectF().getCoords()

        self.bands = {}
        for nr in range(1, min(4, self.band_count + 1)):
            self.bands[nr] = {}
            self.bands[nr]['sbox'] = self.sboxes[nr - 1]

            # NODATA
            if self.rdp.sourceHasNoDataValue(nr):  # source nodata value?
                self.bands[nr]['nodata'] = self.rdp.sourceNoDataValue(nr)
                # use the src nodata
                self.rdp.setUseSourceNoDataValue(nr, True)
            # no nodata defined in the raster source
            else:
                # check if user defined any nodata values
                if self.rdp.userNoDataValues(nr):
                    # get min nodata value from the first user nodata range
                    nd_ranges = self.rdp.userNoDataValues(nr)
                    self.bands[nr]['nodata'] = nd_ranges[0].min()
                else:
                    # leave nodata undefined
                    self.bands[nr]['nodata'] = None

            # enable band's spin box
            self.bands[nr]['sbox'].setEnabled(True)
            # get bands data type
            dt = self.bands[nr]['qtype'] = self.rdp.dataType(nr)
            # set spin boxes properties
            self.bands[nr]['sbox'].setMinimum(dtypes[dt]['min'])
            self.bands[nr]['sbox'].setMaximum(dtypes[dt]['max'])
            self.bands[nr]['sbox'].setDecimals(dtypes[dt]['dig'])

    @staticmethod
    def show_website():
        QDesktopServices.openUrl(QUrl('https://github.com/erpas/serval/wiki'))
Пример #5
0
class Serval(object):

    LINE_SELECTION = "line"
    POLYGON_SELECTION = "polygon"
    RGB = "RGB"
    SINGLE_BAND = "Single band"

    def __init__(self, iface):
        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.plugin_dir = os.path.dirname(__file__)
        self.uc = UserCommunication(iface, 'Serval')
        self.load_settings()
        self.raster = None
        self.handler = None
        self.spin_boxes = None
        self.exp_dlg = None
        self.exp_builder = None
        self.block_pts_layer = None
        self.px, self.py = [0, 0]
        self.last_point = QgsPointXY(0, 0)
        self.rbounds = None
        self.changes = dict()  # dict with rasters changes {raster_id: RasterChanges instance}
        self.project = QgsProject.instance()
        self.crs_transform = None
        self.all_touched = None
        self.selection_mode = None
        self.spatial_index_time = dict()  # {layer_id: creation time}
        self.spatial_index = dict()  # {layer_id: spatial index}
        self.selection_layers_count = 1
        self.debug = DEBUG
        self.logger = get_logger() if self.debug else None

        self.menu = u'Serval'
        self.actions = []
        self.actions_always_on = []
        self.toolbar = self.iface.addToolBar(u'Serval Main Toolbar')
        self.toolbar.setObjectName(u'Serval Main Toolbar')
        self.toolbar.setToolTip(u'Serval Main Toolbar')

        self.sel_toolbar = self.iface.addToolBar(u'Serval Selection Toolbar')
        self.sel_toolbar.setObjectName(u'Serval Selection Toolbar')
        self.sel_toolbar.setToolTip(u'Serval Selection Toolbar')

        # Map tools
        self.probe_tool = QgsMapToolEmitPoint(self.canvas)
        self.probe_tool.setObjectName('ServalProbeTool')
        self.probe_tool.setCursor(QCursor(QPixmap(icon_path('probe_tool.svg')), hotX=2, hotY=22))
        self.probe_tool.canvasClicked.connect(self.point_clicked)
        self.draw_tool = QgsMapToolEmitPoint(self.canvas)
        self.draw_tool.setObjectName('ServalDrawTool')
        self.draw_tool.setCursor(QCursor(QPixmap(icon_path('draw_tool.svg')), hotX=2, hotY=22))
        self.draw_tool.canvasClicked.connect(self.point_clicked)
        self.selection_tool = RasterCellSelectionMapTool(self.iface, self.uc, self.raster, debug=self.debug)
        self.selection_tool.setObjectName('RasterSelectionTool')
        self.map_tool_btn = dict()  # {map tool: button activating the tool}

        self.iface.currentLayerChanged.connect(self.set_active_raster)
        self.project.layersAdded.connect(self.set_active_raster)
        self.canvas.mapToolSet.connect(self.check_active_tool)

        self.register_exp_functions()

    def load_settings(self):
        """Return plugin settings dict - default values are overriden by user prefered values from QSettings."""
        self.default_settings = {
            "undo_steps": {"value": 3, "vtype": int},
        }
        self.settings = dict()
        s = QSettings()
        s.beginGroup("serval")
        for k, v in self.default_settings.items():
            user_val = s.value(k, v["value"], v["vtype"])
            self.settings[k] = user_val

    def edit_settings(self):
        """Open dialog with plugin settings."""
        s = QSettings()
        s.beginGroup("serval")
        k = "undo_steps"
        cur_val = self.settings[k]
        val_type = self.default_settings[k]["vtype"]
        cur_steps = s.value(k, cur_val, val_type)

        label = 'Nr of Undo/Redo steps:'
        steps, ok = QInputDialog.getInt(None, "Serval Settings", label, cur_steps)
        if not ok:
            return
        if steps >= 0:
            s.setValue("undo_steps", steps)
        self.load_settings()
        self.uc.show_info("Some new settings may require QGIS restart.")

    def initGui(self):
        _ = self.add_action(
            'serval_icon.svg',
            text=u'Show Serval Toolbars',
            add_to_menu=True,
            callback=self.show_toolbar,
            always_on=True, )

        _ = self.add_action(
            'serval_icon.svg',
            text=u'Hide Serval Toolbars',
            add_to_menu=True,
            callback=self.hide_toolbar,
            always_on=True, )

        self.probe_btn = self.add_action(
            'probe.svg',
            text="Probe raster",
            callback=self.activate_probing,
            add_to_toolbar=self.toolbar,
            checkable=True, )
        self.map_tool_btn[self.probe_tool] = self.probe_btn

        self.color_btn = QgsColorButton()
        self.color_btn.setColor(Qt.gray)
        self.color_btn.setMinimumSize(QSize(40, 24))
        self.color_btn.setMaximumSize(QSize(40, 24))
        self.toolbar.addWidget(self.color_btn)
        self.color_picker_connection(connect=True)
        self.color_btn.setDisabled(True)

        self.toolbar.addWidget(QLabel("Band:"))
        self.bands_cbo = QComboBox()
        self.bands_cbo.addItem("1", 1)
        self.toolbar.addWidget(self.bands_cbo)
        self.bands_cbo.currentIndexChanged.connect(self.update_active_bands)
        self.bands_cbo.setDisabled(True)

        self.spin_boxes = BandBoxes()
        self.toolbar.addWidget(self.spin_boxes)
        self.spin_boxes.enter_hit.connect(self.apply_spin_box_values)

        self.draw_btn = self.add_action(
            'draw.svg',
            text="Apply Value(s) To Single Cell",
            callback=self.activate_drawing,
            add_to_toolbar=self.toolbar,
            checkable=True, )
        self.map_tool_btn[self.draw_tool] = self.draw_btn

        self.apply_spin_box_values_btn = self.add_action(
            'apply_const_value.svg',
            text="Apply Value(s) to Selection",
            callback=self.apply_spin_box_values,
            add_to_toolbar=self.toolbar, )

        self.gom_btn = self.add_action(
            'apply_nodata_value.svg',
            text="Apply NoData to Selection",
            callback=self.apply_nodata_value,
            add_to_toolbar=self.toolbar, )

        self.exp_dlg_btn = self.add_action(
            'apply_expression_value.svg',
            text="Apply Expression Value To Selection",
            callback=self.define_expression,
            add_to_toolbar=self.toolbar,
            checkable=False, )

        self.low_pass_filter_btn = self.add_action(
            'apply_low_pass_filter.svg',
            text="Apply Low-Pass 3x3 Filter To Selection",
            callback=self.apply_low_pass_filter,
            add_to_toolbar=self.toolbar,
            checkable=False, )

        self.undo_btn = self.add_action(
            'undo.svg',
            text="Undo",
            callback=self.undo,
            add_to_toolbar=self.toolbar, )

        self.redo_btn = self.add_action(
            'redo.svg',
            text="Redo",
            callback=self.redo,
            add_to_toolbar=self.toolbar, )

        self.set_nodata_btn = self.add_action(
            'set_nodata.svg',
            text="Edit Raster NoData Values",
            callback=self.set_nodata,
            add_to_toolbar=self.toolbar, )

        self.settings_btn = self.add_action(
            'edit_settings.svg',
            text="Serval Settings",
            callback=self.edit_settings,
            add_to_toolbar=self.toolbar,
            always_on=True, )

        self.show_help = self.add_action(
            'help.svg',
            text="Help",
            add_to_menu=True,
            callback=self.show_website,
            add_to_toolbar=self.toolbar,
            always_on=True, )

        # Selection Toolbar

        line_width_icon = QIcon(icon_path("line_width.svg"))
        line_width_lab = QLabel()
        line_width_lab.setPixmap(line_width_icon.pixmap(22, 12))
        self.sel_toolbar.addWidget(line_width_lab)

        self.line_width_sbox = QgsDoubleSpinBox()
        self.line_width_sbox.setMinimumSize(QSize(50, 24))
        self.line_width_sbox.setMaximumSize(QSize(50, 24))
        # self.line_width_sbox.setButtonSymbols(QAbstractSpinBox.NoButtons)
        self.line_width_sbox.setValue(1)
        self.line_width_sbox.setMinimum(0.01)
        self.line_width_sbox.setShowClearButton(False)
        self.line_width_sbox.setToolTip("Selection Line Width")
        self.line_width_sbox.valueChanged.connect(self.update_selection_tool)

        self.width_unit_cbo = QComboBox()
        self.width_units = ("map units", "pixel width", "pixel height", "hairline",)
        for u in self.width_units:
            self.width_unit_cbo.addItem(u)
        self.width_unit_cbo.setToolTip("Selection Line Width Unit")
        self.sel_toolbar.addWidget(self.line_width_sbox)
        self.sel_toolbar.addWidget(self.width_unit_cbo)
        self.width_unit_cbo.currentIndexChanged.connect(self.update_selection_tool)

        self.line_select_btn = self.add_action(
            'select_line.svg',
            text="Select Raster Cells by Line",
            callback=self.activate_line_selection,
            add_to_toolbar=self.sel_toolbar,
            checkable=True, )

        self.polygon_select_btn = self.add_action(
            'select_polygon.svg',
            text="Select Raster Cells by Polygon",
            callback=self.activate_polygon_selection,
            add_to_toolbar=self.sel_toolbar,
            checkable=True, )

        self.selection_from_layer_btn = self.add_action(
            'select_from_layer.svg',
            text="Create Selection From Layer",
            callback=self.selection_from_layer,
            add_to_toolbar=self.sel_toolbar, )

        self.selection_to_layer_btn = self.add_action(
            'selection_to_layer.svg',
            text="Create Memory Layer From Selection",
            callback=self.selection_to_layer,
            add_to_toolbar=self.sel_toolbar, )

        self.clear_selection_btn = self.add_action(
            'clear_selection.svg',
            text="Clear selection",
            callback=self.clear_selection,
            add_to_toolbar=self.sel_toolbar, )

        self.toggle_all_touched_btn = self.add_action(
            'all_touched.svg',
            text="Toggle All Touched Get Selected",
            callback=self.toggle_all_touched,
            checkable=True, checked=True,
            add_to_toolbar=self.sel_toolbar, )
        self.all_touched = True

        self.enable_toolbar_actions(enable=False)
        self.check_undo_redo_btns()

    def add_action(self, icon_name, callback=None, text="", enabled_flag=True, add_to_menu=False, add_to_toolbar=None,
                   status_tip=None, whats_this=None, checkable=False, checked=False, always_on=False):
            
        icon = QIcon(icon_path(icon_name))
        action = QAction(icon, text, self.iface.mainWindow())
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)
        action.setCheckable(checkable)
        action.setChecked(checked)

        if status_tip is not None:
            action.setStatusTip(status_tip)
        if whats_this is not None:
            action.setWhatsThis(whats_this)
        if add_to_toolbar is not None:
            add_to_toolbar.addAction(action)
        if add_to_menu:
            self.iface.addPluginToMenu(self.menu, action)

        self.actions.append(action)
        if always_on:
            self.actions_always_on.append(action)
        return action

    def unload(self):
        self.changes = None
        if self.selection_tool:
            self.selection_tool.reset()
        if self.spin_boxes is not None:
            self.spin_boxes.remove_spinboxes()
        for action in self.actions:
            self.iface.removePluginMenu('Serval', action)
            self.iface.removeToolBarIcon(action)
        del self.toolbar
        del self.sel_toolbar
        self.iface.actionPan().trigger()
        self.unregister_exp_functions()

    def show_toolbar(self):
        if self.toolbar:
            self.toolbar.show()
            self.sel_toolbar.show()

    def hide_toolbar(self):
        if self.toolbar:
            self.toolbar.hide()
            self.sel_toolbar.hide()

    @staticmethod
    def register_exp_functions():
        QgsExpression.registerFunction(nearest_feature_attr_value)
        QgsExpression.registerFunction(nearest_pt_on_line_interpolate_z)
        QgsExpression.registerFunction(intersecting_features_attr_average)
        QgsExpression.registerFunction(interpolate_from_mesh)

    @staticmethod
    def unregister_exp_functions():
        QgsExpression.unregisterFunction('nearest_feature_attr_value')
        QgsExpression.unregisterFunction('nearest_pt_on_line_interpolate_z')
        QgsExpression.unregisterFunction('intersecting_features_attr_average')
        QgsExpression.unregisterFunction('interpolate_from_mesh')

    def uncheck_all_btns(self):
        self.probe_btn.setChecked(False)
        self.draw_btn.setChecked(False)
        self.gom_btn.setChecked(False)
        self.line_select_btn.setChecked(False)
        self.polygon_select_btn.setChecked(False)

    def check_active_tool(self, cur_tool):
        self.uncheck_all_btns()
        if cur_tool in self.map_tool_btn:
            self.map_tool_btn[cur_tool].setChecked(True)
        if cur_tool == self.selection_tool:
            if self.selection_mode == self.LINE_SELECTION:
                self.line_select_btn.setChecked(True)
            else:
                self.polygon_select_btn.setChecked(True)

    def activate_probing(self):
        self.mode = 'probe'
        self.canvas.setMapTool(self.probe_tool)

    def define_expression(self):
        if not self.selection_tool.selected_geometries:
            self.uc.bar_warn("No selection for raster layer. Select some cells and retry...")
            return
        self.handler.select(self.selection_tool.selected_geometries, all_touched_cells=self.all_touched)
        self.handler.create_cell_pts_layer()
        if self.handler.cell_pts_layer.featureCount() == 0:
            self.uc.bar_warn("No selection for raster layer. Select some cells and retry...")
            return
        self.exp_dlg = QgsExpressionBuilderDialog(self.handler.cell_pts_layer)
        self.exp_builder = self.exp_dlg.expressionBuilder()
        self.exp_dlg.accepted.connect(self.apply_exp_value)
        self.exp_dlg.show()

    def apply_exp_value(self):
        if not self.exp_dlg.expressionText() or not self.exp_builder.isExpressionValid():
            return
        QApplication.setOverrideCursor(Qt.WaitCursor)
        exp = self.exp_dlg.expressionText()
        idx = self.handler.cell_pts_layer.addExpressionField(exp, QgsField('exp_val', QVariant.Double))
        self.handler.exp_field_idx = idx
        self.handler.write_block()
        QApplication.restoreOverrideCursor()
        self.raster.triggerRepaint()

    def activate_drawing(self):
        self.mode = 'draw'
        self.canvas.setMapTool(self.draw_tool)

    def get_cur_line_width(self):
        width_coef = {
            "map units": 1.,
            "pixel width": self.raster.rasterUnitsPerPixelX(),
            "pixel height": self.raster.rasterUnitsPerPixelY(),
            "hairline": 0.000001,
        }
        return self.line_width_sbox.value() * width_coef[self.width_unit_cbo.currentText()]

    def set_selection_tool(self, mode):
        if self.raster is None:
            self.uc.bar_warn("Select a raster layer")
            return
        self.selection_mode = mode
        self.selection_tool.init_tool(self.raster, mode=self.selection_mode, line_width=self.get_cur_line_width())
        self.selection_tool.set_prev_tool(self.canvas.mapTool())
        self.canvas.setMapTool(self.selection_tool)

    def activate_line_selection(self):
        self.set_selection_tool(self.LINE_SELECTION)

    def activate_polygon_selection(self):
        self.set_selection_tool(self.POLYGON_SELECTION)

    def update_selection_tool(self):
        """Reactivate the selection tool with updated line width and units."""
        if self.selection_mode == self.LINE_SELECTION:
            self.activate_line_selection()
        elif self.selection_mode == self.POLYGON_SELECTION:
            self.activate_polygon_selection()
        else:
            pass

    def apply_values(self, new_values):
        QApplication.setOverrideCursor(Qt.WaitCursor)
        self.handler.select(self.selection_tool.selected_geometries, all_touched_cells=self.all_touched)
        self.handler.write_block(new_values)
        QApplication.restoreOverrideCursor()
        self.raster.triggerRepaint()

    def apply_values_single_cell(self, new_vals):
        """Create single cell selection and apply the new values."""
        cp = self.last_point
        if self.logger:
            self.logger.debug(f"Changing single cell for pt {cp}")
        col, row = self.handler.point_to_index([cp.x(), cp.y()])
        px, py = self.handler.index_to_point(row, col, upper_left=False)
        d = 0.001
        bbox = QgsRectangle(px - d, py - d, px + d, py + d)
        if self.logger:
            self.logger.debug(f"Changing single cell in {bbox}")
        QApplication.setOverrideCursor(Qt.WaitCursor)
        self.handler.select([QgsGeometry.fromRect(bbox)], all_touched_cells=False, transform=False)
        self.handler.write_block(new_vals)
        QApplication.restoreOverrideCursor()
        self.raster.triggerRepaint()

    def apply_spin_box_values(self):
        if not self.selection_tool.selected_geometries:
            return
        self.apply_values(self.spin_boxes.get_values())

    def apply_nodata_value(self):
        if not self.selection_tool.selected_geometries:
            return
        self.apply_values(self.handler.nodata_values)

    def apply_low_pass_filter(self):
        QApplication.setOverrideCursor(Qt.WaitCursor)
        self.handler.select(self.selection_tool.selected_geometries, all_touched_cells=self.all_touched)
        self.handler.write_block(low_pass_filter=True)
        QApplication.restoreOverrideCursor()
        self.raster.triggerRepaint()

    def clear_selection(self):
        if self.selection_tool:
            self.selection_tool.clear_all_selections()

    def selection_from_layer(self):
        """Create a new selection from layer."""
        self.selection_tool.init_tool(self.raster, mode=self.POLYGON_SELECTION, line_width=self.get_cur_line_width())
        dlg = LayerSelectDialog()
        if not dlg.exec_():
            return
        cur_layer = dlg.cbo.currentLayer()
        if not cur_layer.type() == QgsMapLayerType.VectorLayer:
            return
        self.selection_tool.selection_from_layer(cur_layer)

    def selection_to_layer(self):
        """Create a memory layer from current selection"""
        geoms = self.selection_tool.selected_geometries
        if geoms is None or not self.raster:
            return
        crs_str = self.raster.crs().toProj()
        nr = self.selection_layers_count
        self.selection_layers_count += 1
        mlayer = QgsVectorLayer(f"Polygon?crs={crs_str}&field=fid:int", f"Raster selection {nr}", "memory")
        fields = mlayer.dataProvider().fields()
        features = []
        for i, geom in enumerate(geoms):
            feat = QgsFeature(fields)
            feat["fid"] = i + 1
            feat.setGeometry(geom)
            features.append(feat)
        mlayer.dataProvider().addFeatures(features)
        self.project.addMapLayer(mlayer)

    def toggle_all_touched(self):
        """Toggle selection mode."""
        # button is toggled automatically when clicked, just update the attribute
        self.all_touched = self.toggle_all_touched_btn.isChecked()

    def point_clicked(self, point=None, button=None):
        if self.raster is None:
            self.uc.bar_warn("Choose a raster to work with...", dur=3)
            return

        if self.logger:
            self.logger.debug(f"Clicked point in canvas CRS: {point if point else self.last_point}")

        if point is None:
            ptxy_in_src_crs = self.last_point
        else:
            if self.crs_transform:
                if self.logger:
                    self.logger.debug(f"Transforming clicked point {point}")
                try:
                    ptxy_in_src_crs = self.crs_transform.transform(point)
                except QgsCsException as err:
                    self.uc.show_warn(
                        "Point coordinates transformation failed! Check the raster projection:\n\n{}".format(repr(err)))
                    return
            else:
                ptxy_in_src_crs = QgsPointXY(point.x(), point.y())

        if self.logger:
            self.logger.debug(f"Clicked point in raster CRS: {ptxy_in_src_crs}")
        self.last_point = ptxy_in_src_crs

        ident_vals = self.handler.provider.identify(ptxy_in_src_crs, QgsRaster.IdentifyFormatValue).results()
        cur_vals = list(ident_vals.values())

        # check if the point is within active raster extent
        if not self.rbounds[0] <= ptxy_in_src_crs.x() <= self.rbounds[2]:
            self.uc.bar_info("Out of x bounds", dur=3)
            return
        if not self.rbounds[1] <= ptxy_in_src_crs.y() <= self.rbounds[3]:
            self.uc.bar_info("Out of y bounds", dur=3)
            return

        if self.mode == 'draw':
            new_vals = self.spin_boxes.get_values()
            if self.logger:
                self.logger.debug(f"Applying const value {new_vals}")
            self.apply_values_single_cell(new_vals)
        else:
            self.spin_boxes.set_values(cur_vals)
            if 2 < self.handler.bands_nr < 5:
                self.color_picker_connection(connect=False)
                self.color_btn.setColor(QColor(*self.spin_boxes.get_values()[:4]))
                self.color_picker_connection(connect=True)

    def set_values_from_picker(self, c):
        """Set bands spinboxes values after color change in the color picker"""
        values = None
        if self.handler.bands_nr > 2:
            values = [c.red(), c.green(), c.blue()]
            if self.handler.bands_nr == 4:
                values.append(c.alpha())
        if values:
            self.spin_boxes.set_values(values)

    def set_nodata(self):
        """Set NoData value(s) for each band of current raster."""
        if not self.raster:
            self.uc.bar_warn('Select a raster layer to define/change NoData value!')
            return
        if self.handler.provider.userNoDataValues(1):
            note = '\nNote: there is a user defined NODATA value.\nCheck the raster properties (Transparency).'
        else:
            note = ''
        dt = self.handler.provider.dataType(1)
        
        # current NODATA value
        if self.handler.provider.sourceHasNoDataValue(1):
            cur_nodata = self.handler.provider.sourceNoDataValue(1)
            if dt < 6:
                cur_nodata = '{0:d}'.format(int(float(cur_nodata)))
        else:
            cur_nodata = ''
        
        label = 'Define/change raster NODATA value.\n\n'
        label += 'Raster src_data type: {}.{}'.format(dtypes[dt]['name'], note)
        nd, ok = QInputDialog.getText(None, "Define NODATA Value", label, QLineEdit.Normal, str(cur_nodata))
        if not ok:
            return
        if not is_number(nd):
            self.uc.show_warn('Wrong NODATA value!')
            return
        new_nodata = int(nd) if dt < 6 else float(nd)
        
        # set the NODATA value for each band
        res = []
        for nr in self.handler.bands_range:
            res.append(self.handler.provider.setNoDataValue(nr, new_nodata))
            self.handler.provider.sourceHasNoDataValue(nr)
        
        if False in res:
            self.uc.show_warn('Setting new NODATA value failed!')
        else:
            self.uc.bar_info('Successful setting new NODATA values!', dur=2)

        self.set_active_raster()
        self.raster.triggerRepaint()
        
    def check_undo_redo_btns(self):
        """Enable/Disable undo and redo buttons based on availability of undo/redo for current raster."""
        self.undo_btn.setDisabled(True)
        self.redo_btn.setDisabled(True)
        if self.raster is None or self.raster.id() not in self.changes:
            return
        changes = self.changes[self.raster.id()]
        if changes.nr_undos() > 0:
            self.undo_btn.setEnabled(True)
        if changes.nr_redos() > 0:
            self.redo_btn.setEnabled(True)

    def enable_toolbar_actions(self, enable=True):
        """Enable / disable all toolbar actions but Help (for vectors and unsupported rasters)"""
        for widget in self.actions + [self.width_unit_cbo, self.line_width_sbox]:
            widget.setEnabled(enable)
            if widget in self.actions_always_on:
                widget.setEnabled(True)
        self.spin_boxes.enable(enable)

    @staticmethod
    def check_layer(layer):
        """Check if we can work with the raster"""
        if layer is None:
            return False
        if layer.type() != QgsMapLayerType.RasterLayer:
            return False
        if layer.providerType() != 'gdal':
            return False
        if all([
            layer.isValid(),
            layer.crs() is not None,
            check_gdal_driver_create_option(layer),                 # GDAL driver has CREATE option
            os.path.isfile(layer.dataProvider().dataSourceUri()),   # is it a local file?
        ]):
            return True
        else:
            return False

    def set_bands_cbo(self):
        self.bands_cbo.currentIndexChanged.disconnect(self.update_active_bands)
        self.bands_cbo.clear()
        for band in self.handler.bands_range:
            self.bands_cbo.addItem(f"{band}", [band])
        if self.handler.bands_nr > 1:
            self.bands_cbo.addItem(self.RGB, [1, 2, 3])
        self.bands_cbo.setCurrentIndex(0)
        self.bands_cbo.currentIndexChanged.connect(self.update_active_bands)

    def update_active_bands(self, idx):
        bands = self.bands_cbo.currentData()
        self.handler.active_bands = bands
        self.spin_boxes.create_spinboxes(bands, self.handler.data_types, self.handler.nodata_values)
        self.color_btn.setEnabled(len(bands) > 1)
        self.exp_dlg_btn.setEnabled(len(bands) == 1)

    def set_active_raster(self):
        """Active layer has changed - check if it is a raster layer and prepare it for the plugin"""
        old_spin_boxes_values = self.spin_boxes.get_values()
        self.crs_transform = None
        layer = self.iface.activeLayer()
        if self.check_layer(layer):
            self.raster = layer
            self.crs_transform = None if self.project.crs() == self.raster.crs() else \
                QgsCoordinateTransform(self.project.crs(), self.raster.crs(), self.project)
            self.handler = RasterHandler(self.raster, self.uc, self.debug)
            supported, unsupported_type = self.handler.write_supported()
            if supported:
                self.enable_toolbar_actions()
                self.set_bands_cbo()
                self.spin_boxes.create_spinboxes(self.handler.active_bands,
                                                 self.handler.data_types, self.handler.nodata_values)
                if self.handler.bands_nr == len(old_spin_boxes_values):
                    self.spin_boxes.set_values(old_spin_boxes_values)
                self.bands_cbo.setEnabled(self.handler.bands_nr > 1)
                self.color_btn.setEnabled(len(self.handler.active_bands) > 1)
                self.rbounds = self.raster.extent().toRectF().getCoords()
                self.handler.raster_changed.connect(self.add_to_undo)
                if self.raster.id() not in self.changes:
                    self.changes[self.raster.id()] = RasterChanges(nr_to_keep=self.settings["undo_steps"])
            else:
                msg = f"The raster has unsupported src_data type: {unsupported_type}"
                msg += "\nServal can't work with it, sorry..."
                self.uc.show_warn(msg)
                self.enable_toolbar_actions(enable=False)
                self.reset_raster()
        
        else:
            # unsupported raster
            self.enable_toolbar_actions(enable=False)
            self.reset_raster()

        self.check_undo_redo_btns()

    def add_to_undo(self, change):
        """Add the old and new blocks to undo stack."""
        self.changes[self.raster.id()].add_change(change)
        self.check_undo_redo_btns()
        if self.logger:
            self.logger.debug(self.get_undo_redo_values())

    def get_undo_redo_values(self):
        changes = self.changes[self.raster.id()]
        return f"nr undos: {changes.nr_undos()}, redos: {changes.nr_redos()}"

    def undo(self):
        undo_data = self.changes[self.raster.id()].undo()
        self.handler.write_block_undo(undo_data)
        self.raster.triggerRepaint()
        self.check_undo_redo_btns()

    def redo(self):
        redo_data = self.changes[self.raster.id()].redo()
        self.handler.write_block_undo(redo_data)
        self.raster.triggerRepaint()
        self.check_undo_redo_btns()

    def reset_raster(self):
        self.raster = None
        self.color_btn.setDisabled(True)

    def color_picker_connection(self, connect=True):
        if connect:
            self.color_btn.colorChanged.connect(self.set_values_from_picker)
        else:
            self.color_btn.colorChanged.disconnect(self.set_values_from_picker)

    @staticmethod
    def show_website():
        QDesktopServices.openUrl(QUrl("https://github.com/lutraconsulting/serval/blob/master/Serval/docs/user_manual.md"))

    def recreate_spatial_index(self, layer):
        """Check if spatial index exists for the layer and if it is relatively old and eventually recreate it."""
        ctime = self.spatial_index_time[layer.id()] if layer.id() in self.spatial_index_time else None
        if ctime is None or datetime.now() - ctime > timedelta(seconds=30):
            self.spatial_index = QgsSpatialIndex(layer.getFeatures(), None, QgsSpatialIndex.FlagStoreFeatureGeometries)
            self.spatial_index_time[layer.id()] = datetime.now()

    def get_nearest_feature(self, pt_feat, vlayer_id):
        """Given the point feature, return nearest feature from vlayer."""
        vlayer = self.project.mapLayer(vlayer_id)
        self.recreate_spatial_index(vlayer)
        ptxy = pt_feat.geometry().asPoint()
        near_fid = self.spatial_index.nearestNeighbor(ptxy)[0]
        return vlayer.getFeature(near_fid)

    def nearest_feature_attr_value(self, pt_feat, vlayer_id, attr_name):
        """Find nearest feature to pt_feat and return its attr_name attribute value."""
        near_feat = self.get_nearest_feature(pt_feat, vlayer_id)
        return near_feat[attr_name]

    def nearest_pt_on_line_interpolate_z(self, pt_feat, vlayer_id):
        """Find nearest line feature to pt_feat and interpolate z value from vertices."""
        near_feat = self.get_nearest_feature(pt_feat, vlayer_id)
        near_geom = near_feat.geometry()
        closest_pt_dist = near_geom.lineLocatePoint(pt_feat.geometry())
        closest_pt = near_geom.interpolate(closest_pt_dist)
        return closest_pt.get().z()

    def intersecting_features_attr_average(self, pt_feat, vlayer_id, attr_name, only_center):
        """
        Find all features intersecting current feature (cell center, or raster cell polygon) and calculate average
        value of their attr_name attribute.
        """
        vlayer = self.project.mapLayer(vlayer_id)
        self.recreate_spatial_index(vlayer)
        ptxy = pt_feat.geometry().asPoint()
        pt_x, pt_y = ptxy.x(), ptxy.y()
        dxy = 0.001
        half_pix_x = self.handler.pixel_size_x / 2.
        half_pix_y = self.handler.pixel_size_y / 2.
        if only_center:
            cell = QgsRectangle(pt_x, pt_y, pt_x + dxy, pt_y + dxy)
        else:
            cell = QgsRectangle(pt_x - half_pix_x, pt_y - half_pix_y,
                                pt_x + half_pix_x, pt_y + half_pix_y)
        inter_fids = self.spatial_index.intersects(cell)
        values = []
        for fid in inter_fids:
            feat = vlayer.getFeature(fid)
            if not feat.geometry().intersects(cell):
                continue
            val = feat[attr_name]
            if not is_number(val):
                continue
            values.append(val)
        if len(values) == 0:
            return None
        return sum(values) / float(len(values))

    def interpolate_from_mesh(self, pt_feat, mesh_layer_id, group, dataset, above_existing):
        """Interpolate from mesh."""
        mesh_layer = self.project.mapLayer(mesh_layer_id)
        ptxy = pt_feat.geometry().asPoint()
        dataset_val = mesh_layer.datasetValue(QgsMeshDatasetIndex(group, dataset), ptxy)
        val = dataset_val.scalar()
        if math.isnan(val):
            return val
        if above_existing:
            ident_vals = self.handler.provider.identify(ptxy, QgsRaster.IdentifyFormatValue).results()
            org_val = list(ident_vals.values())[0]
            if org_val == self.handler.nodata_values[0]:
                return val
            return max(org_val, val)
        else:
            return val