Example #1
0
class QvFormSimbMapificacio(QvFormBaseMapificacio):
    def __init__(self, llegenda, capa=None, amplada=500):
        super().__init__(llegenda, amplada)
        if capa is None:
            self.capa = llegenda.currentLayer()
        else:
            self.capa = capa
        self.info = None
        if not self.iniParams():
            return

        self.setWindowTitle('Modificar mapa simbòlic ' + self.renderParams.tipusMapa.lower())

        self.layout = QVBoxLayout()
        self.layout.setSpacing(14)
        self.setLayout(self.layout)

        self.color = QComboBox(self)
        self.color.setEditable(False)
        self.comboColors(self.color)

        self.contorn = QComboBox(self)
        self.contorn.setEditable(False)
        self.comboColors(self.contorn, mv.MAP_CONTORNS)

        self.color.currentIndexChanged.connect(self.canviaContorns)

        self.metode = QComboBox(self)
        self.metode.setEditable(False)
        if self.renderParams.numCategories > 1:
            self.metode.addItems(mv.MAP_METODES_MODIF.keys())
        else:
            self.metode.addItems(mv.MAP_METODES.keys())
        self.metode.setCurrentIndex(-1)
        self.metode.currentIndexChanged.connect(self.canviaMetode)

        self.nomIntervals = QLabel("Nombre d'intervals:", self)
        self.intervals = QSpinBox(self)
        self.intervals.setMinimum(min(2, self.renderParams.numCategories))
        self.intervals.setMaximum(max(mv.MAP_MAX_CATEGORIES, self.renderParams.numCategories))
        self.intervals.setSingleStep(1)
        self.intervals.setValue(4)
        if self.renderParams.tipusMapa == 'Àrees':
            self.intervals.setSuffix("  (depèn del mètode)")
        # self.intervals.valueChanged.connect(self.deselectValue)

        self.nomTamany = QLabel("Tamany cercle:", self)
        self.tamany = QSpinBox(self)
        self.tamany.setMinimum(1)
        self.tamany.setMaximum(12)
        self.tamany.setSingleStep(1)
        self.tamany.setValue(4)

        self.bInfo = QPushButton('Info')
        self.bInfo.clicked.connect(self.veureInfo)

        self.buttons = QDialogButtonBox()
        self.buttons.addButton(QDialogButtonBox.Ok)
        self.buttons.accepted.connect(self.accept)
        self.buttons.addButton(QDialogButtonBox.Cancel)
        self.buttons.rejected.connect(self.cancel)
        self.buttons.addButton(self.bInfo, QDialogButtonBox.ResetRole)

        self.gSimb = QGroupBox('Simbologia del mapa')
        self.lSimb = QFormLayout()
        self.lSimb.setSpacing(14)
        self.gSimb.setLayout(self.lSimb)

        self.lSimb.addRow('Color base:', self.color)
        self.lSimb.addRow('Color contorn:', self.contorn)
        if self.renderParams.tipusMapa == 'Àrees':
            self.lSimb.addRow('Mètode classificació:', self.metode)
            self.lSimb.addRow(self.nomIntervals, self.intervals)
            self.nomTamany.setVisible(False)
            self.tamany.setVisible(False)
        else:
            self.metode.setVisible(False)
            self.nomIntervals.setVisible(False)
            self.intervals.setVisible(False)
            self.lSimb.addRow(self.nomTamany, self.tamany)

        self.wInterval = []
        for w in self.iniIntervals():
            self.wInterval.append(w)
        self.gInter = self.grupIntervals()

        self.layout.addWidget(self.gSimb)
        if self.renderParams.tipusMapa == 'Àrees':
            self.layout.addWidget(self.gInter)
        self.layout.addWidget(self.buttons)

        self.valorsInicials()

    def iniParams(self):
        self.info = QgsExpressionContextUtils.layerScope(self.capa).variable(mv.MAP_ID)
        if self.info is None:
            return False
        self.renderParams = QvMapRendererParams.fromLayer(self.capa)
        if self.renderParams.msgError == '':
            self.custom = (self.renderParams.modeCategories == 'Personalitzat')
            return True
        else:
            self.msgInfo("No s'han pogut recuperar els paràmetres del mapa simbòlic\n\n" +
                         "Error: " + self.renderParams.msgError)
            return False

    @pyqtSlot()
    def veureInfo(self):
        if self.info is not None:
            box = QMessageBox(self)
            box.setWindowTitle('Info del mapa simbòlic')
            txt = '<table width="600">'
            params = self.info.split('\n')
            for param in params:
                linea = param.strip()
                if linea.endswith(':'):
                    linea += ' ---'
                txt += '<tr><td><nobr>&middot;&nbsp;{}</nobr></td></tr>'.format(linea)
            txt += '</table>'
            box.setTextFormat(Qt.RichText)
            box.setText("Paràmetres d'agregació de dades:")
            box.setInformativeText(txt)
            box.setIcon(QMessageBox.Information)
            box.setStandardButtons(QMessageBox.Ok)
            box.setDefaultButton(QMessageBox.Ok)
            box.exec()

    def valorsInicials(self):
        self.color.setCurrentIndex(self.color.findText(self.renderParams.colorBase))
        self.contorn.setCurrentIndex(self.contorn.findText(self.renderParams.colorContorn))
        self.intervals.setValue(self.renderParams.numCategories)
        self.tamany.setValue(self.renderParams.increase)
        self.metode.setCurrentIndex(self.metode.findText(self.renderParams.modeCategories))

    def valorsFinals(self):
        self.renderParams.colorBase = self.color.currentText()
        self.renderParams.colorContorn = self.contorn.currentText()
        self.renderParams.modeCategories = self.metode.currentText()
        self.renderParams.numCategories = self.intervals.value()
        self.renderParams.increase = self.tamany.value()
        if self.custom:
            self.renderParams.rangsCategories = []
            for fila in self.wInterval:
                self.renderParams.rangsCategories.append((fila[0].text(), fila[2].text()))
            self.renderParams.numCategories = len(self.renderParams.rangsCategories)

    def txtRang(self, num):
        if type(num) == str:
            return num
        return QvApp().locale.toString(num, 'f', self.renderParams.numDecimals)

    def iniFilaInterval(self, iniValor, finValor):
        maxSizeB = 27
        # validator = QDoubleValidator(self)
        # validator.setLocale(QvApp().locale)
        # validator.setNotation(QDoubleValidator.StandardNotation)
        # validator.setDecimals(5)
        validator = QvVerifNumero(self)
        ini = QLineEdit(self)
        ini.setText(self.txtRang(iniValor))
        ini.setValidator(validator)
        sep = QLabel('-', self)
        fin = QLineEdit(self)
        fin.setText(self.txtRang(finValor))
        fin.setValidator(validator)
        fin.editingFinished.connect(self.nouTall)
        add = QPushButton('+', self)
        add.setMaximumSize(maxSizeB, maxSizeB)
        add.setToolTip('Afegeix nou interval')
        add.clicked.connect(self.afegirFila)
        add.setFocusPolicy(Qt.NoFocus)
        rem = QPushButton('-', self)
        rem.setMaximumSize(maxSizeB, maxSizeB)
        rem.setToolTip('Esborra interval')
        rem.clicked.connect(self.eliminarFila)
        rem.setFocusPolicy(Qt.NoFocus)
        return [ini, sep, fin, add, rem]

    def iniIntervals(self):
        for cat in self.renderParams.rangsCategories:
            yield self.iniFilaInterval(cat.lowerValue(), cat.upperValue())

    def grupIntervals(self):
        group = QGroupBox('Definició dels intervals')
        # group.setMinimumWidth(400)
        layout = QGridLayout()
        layout.setSpacing(10)
        # layout.setColumnMinimumWidth(4, 40)
        numFilas = len(self.wInterval)
        for fila, widgets in enumerate(self.wInterval):
            for col, w in enumerate(widgets):
                # Primera fila: solo +
                if fila == 0 and col > 3:
                    w.setVisible(False)
                # # Ultima fila: no hay + ni -
                elif fila > 0 and fila == (numFilas - 1) and col > 2:
                    w.setVisible(False)
                else:
                    w.setVisible(True)
                # Valor inicial deshabilitado (menos 1a fila)
                if col == 0 and fila != 0:
                    w.setDisabled(True)
                w.setProperty('Fila', fila)
                layout.addWidget(w, fila, col)
        group.setLayout(layout)
        return group

    def actGrupIntervals(self):
        self.intervals.setValue(len(self.wInterval))

        self.setUpdatesEnabled(False)
        self.buttons.setVisible(False)
        self.gInter.setVisible(False)

        self.layout.removeWidget(self.buttons)
        self.layout.removeWidget(self.gInter)

        self.gInter.deleteLater()
        self.gInter = self.grupIntervals()

        self.layout.addWidget(self.gInter)
        self.layout.addWidget(self.buttons)

        self.gInter.setVisible(True)
        self.buttons.setVisible(True)

        self.adjustSize()
        self.setUpdatesEnabled(True)

    @pyqtSlot()
    def afegirFila(self):
        masFilas = (len(self.wInterval) < mv.MAP_MAX_CATEGORIES)
        if masFilas:
            f = self.sender().property('Fila') + 1
            ini = self.wInterval[f][0]
            val = ini.text()
            ini.setText('')
            w = self.iniFilaInterval(val, '')
            self.wInterval.insert(f, w)
            self.actGrupIntervals()
            self.wInterval[f][2].setFocus()
        else:
            self.msgInfo("S'ha arribat al màxim d'intervals possibles")

    @pyqtSlot()
    def eliminarFila(self):
        f = self.sender().property('Fila')
        ini = self.wInterval[f][0]
        val = ini.text()
        del self.wInterval[f]
        ini = self.wInterval[f][0]
        ini.setText(val)
        self.actGrupIntervals()

    @pyqtSlot()
    def nouTall(self):
        w = self.sender()
        if w.isModified():
            f = w.property('Fila') + 1
            if f < len(self.wInterval):
                ini = self.wInterval[f][0]
                ini.setText(w.text())
            w.setModified(False)

    @pyqtSlot()
    def canviaMetode(self):
        self.custom = (self.metode.currentText() == 'Personalitzat')
        if self.custom:
            self.intervals.setValue(len(self.wInterval))
        self.intervals.setEnabled(not self.custom)
        self.gInter.setVisible(self.custom)
        self.adjustSize()
        # print('GSIMB -> Ancho:', self.gSimb.size().width(), '- Alto:', self.gSimb.size().height())
        # print('FORM -> Ancho:', self.size().width(), '- Alto:', self.size().height())

    @pyqtSlot()
    def canviaContorns(self):
        self.comboColors(self.contorn, mv.MAP_CONTORNS,
                         mv.MAP_COLORS[self.color.currentText()], True)

    def leSelectFocus(self, wLineEdit):
        lon = len(wLineEdit.text())
        if lon > 0:
            wLineEdit.setSelection(0, lon)
        wLineEdit.setFocus()

    def validaNum(self, wLineEdit):
        val = wLineEdit.validator()
        if val is None:
            return True
        res = val.validate(wLineEdit.text(), 0)
        if res[0] == QValidator.Acceptable:
            return True
        else:
            self.msgInfo("Cal introduir un nombre enter o amb decimals.\n"
                         "Es farà servir la coma (,) per separar els decimals.\n"
                         "I pels milers, opcionalment, el punt (.)")
            self.leSelectFocus(wLineEdit)
            return False

    def validaInterval(self, wLineEdit1, wLineEdit2):
        num1, _ = QvApp().locale.toFloat(wLineEdit1.text())
        num2, _ = QvApp().locale.toFloat(wLineEdit2.text())
        if num2 >= num1:
            return True
        else:
            self.msgInfo("El segon nombre de l'interval ha de ser major que el primer")
            self.leSelectFocus(wLineEdit2)
            return False

    def validaFila(self, fila):
        wLineEdit1 = fila[0]
        wLineEdit2 = fila[2]
        if not self.validaNum(wLineEdit1):
            return False
        if not self.validaNum(wLineEdit2):
            return False
        if not self.validaInterval(wLineEdit1, wLineEdit2):
            return False
        return True

    def valida(self):
        if self.custom:
            for fila in self.wInterval:
                if not self.validaFila(fila):
                    return False
        return True

    def procesa(self):
        self.valorsFinals()
        try:
            mapRenderer = self.renderParams.mapRenderer(self.llegenda)
            if self.custom:
                self.renderParams.colorBase = mv.MAP_COLORS[self.renderParams.colorBase]
                self.renderParams.colorContorn = mv.MAP_CONTORNS[self.renderParams.colorContorn]
                self.renderer = mapRenderer.customRender(self.capa)
            else:
                self.renderParams.colorBase = mv.MAP_COLORS[self.renderParams.colorBase]
                if self.renderParams.colorContorn == 'Base':
                    self.renderParams.colorContorn = self.renderParams.colorBase
                else:
                    self.renderParams.colorContorn = mv.MAP_CONTORNS[self.renderParams.colorContorn]
                self.renderParams.modeCategories = \
                    mv.MAP_METODES_MODIF[self.renderParams.modeCategories]
                self.renderer = mapRenderer.calcRender(self.capa)
            if self.renderer is None:
                return "No s'ha pogut elaborar el mapa simbòlic"
            err = self.llegenda.saveStyleToGeoPackage(self.capa, mv.MAP_ID)
            if err != '':
                return "Hi ha hagut problemes al desar la simbologia\n({})".format(err)
            # self.llegenda.modificacioProjecte('mapModified')
            return ''
        except Exception as e:
            return "No s'ha pogut modificar el mapa simbòlic\n({})".format(str(e))