コード例 #1
0
    def runLabel(self):
        self.iface.mapCanvas().freeze(1)
        sourceLayer = self.iface.activeLayer()

        # keepUserSelection = False
        try:
            if not sourceLayer:
                iface.messageBar().pushMessage(
                    "Error",
                    QtGui.QApplication.translate(
                        "EasyCustomLabeling",
                        "There is no layer currently selected, \n please click on the vector layer you need to label",
                        None, QtGui.QApplication.UnicodeUTF8),
                    level=0,
                    duration=3)
                return
            if not sourceLayer.type() == sourceLayer.VectorLayer:
                iface.messageBar().pushMessage(
                    "Error",
                    QtGui.QApplication.translate(
                        "EasyCustomLabeling",
                        "Current active layer is not a vector layer. \n Please click on the vector layer you need to label",
                        None, QtGui.QApplication.UnicodeUTF8),
                    level=0,
                    duration=3)
                return

            # detect if selection exists on that layer
            #debug
            nbSelectedObjects = sourceLayer.selectedFeatureCount()
            # print '# nbSelectedObjects: ' + str(nbSelectedObjects)
            ret = 0
            if not nbSelectedObjects == 0:
                #dialog to ask if user wants to use current selection or not
                msgBox = QMessageBox()
                msgBox.setIcon(QtGui.QMessageBox.Question)
                msgBox.setWindowTitle("EasyCustomLabeling")
                msgBox.setText(
                    QtGui.QApplication.translate(
                        "EasyCustomLabeling",
                        "Use %n selected object(s) only for labeling ?", None,
                        QtGui.QApplication.UnicodeUTF8, nbSelectedObjects))
                msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No
                                          | QMessageBox.Cancel)
                msgBox.setDefaultButton(QMessageBox.Ok)

                ret = msgBox.exec_()  #ret_val = 16384 si OK, 4194304 sinon

                if ret == 4194304:  # cancel  button finish program
                    self.iface.mapCanvas().freeze(0)
                    print 'dialog keep selection: ' + str(ret)
                    return
                elif ret == 65536:  # No button65536  use entire layer
                    print 'use entire layer'
                elif ret == 16384:
                    print 'use selection'

            nbSelectedObjects = sourceLayer.selectedFeatureCount()

            if sourceLayer.selectedFeatureCount(
            ) > 500:  #alert if  many objects selected

                msgBox = QMessageBox()
                msgBox.setText(
                    QtGui.QApplication.translate(
                        "EasyCustomLabeling",
                        "Your layer contains many objects. Continue anyway?",
                        None, QtGui.QApplication.UnicodeUTF8))
                msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
                msgBox.setDefaultButton(
                    QMessageBox.Ok)  # This function was introduced in Qt 4.3.
                ret2 = msgBox.exec_()  #ret_val = 1024 si OK, 4194304 sinon
                # print 'dialog many objects: ' + str(ret)
                if ret2 != 1024:
                    print 'user cancel on too many object question'
                    return

            #end of general tests and user interaction --------------------------------------------------
            sourceLayerProvider = sourceLayer.dataProvider()
            sourceLayerFields = sourceLayerProvider.fields()

            feat = QgsFeature()

            #asks for default field to use as labeling (thanks to Victor Axbom Layer to labeled layer plugin)
            # create the dialog
            self.dlg = EasyCustomLabelingDialog(sourceLayerProvider)
            ret_dlg_field = self.dlg.exec_()
            #cancels if user cancels dialog:
            if ret_dlg_field == 0:
                return
            # show the dialog
            # if self.dlg.exec_():
            #     return True# print 'dialog execution'
            # else :
            #     return

            # self.iface.mapCanvas().refresh()
            # returns self.dlg.labelfield.currentText()

        # creates new memory labelLayer and provider
        #labelLayer = QgsVectorLayer( "Point", "Label", "memory") # creates points  memory layer
            labelLayer = QgsVectorLayer(
                "LineString", "Label",
                "memory")  # creates lines  memory layer - test v0.6
            labelLayer.setLayerName("Label_" + sourceLayer.name())
            labelLayer.setCrs(sourceLayer.crs())
            labelLayerProvider = labelLayer.dataProvider()
            labelLayerFields = labelLayerProvider.fields()
            # print 'nom du champ 1 : ' + str(sourceLayerFields[1].name())
            #convert field map to a list
            sourceLayerFieldsList = []
            for f in sourceLayerFields:
                # print 'debug date : champ: ' + str(f.name()) + 'type_champ ' + str(f.typeName())
                if f.type() == 14:
                    f.setType(10)
                sourceLayerFieldsList.append(f)
            #print 'sourceLayerFieldsList: ' + str(sourceLayerFieldsList)
            #copy sourceLayer fields into it
            r = labelLayerProvider.addAttributes(sourceLayerFieldsList)
            #print 'ajout des champs source: ' + str(r)

            # # adds specific fields for data driven custom labeling
            labelFields = [
                QgsField("LblField", QVariant.String, "varchar", 255),
                QgsField("LblX", QVariant.String, "varchar", 255),
                QgsField("LblY", QVariant.String, "varchar", 255),
                QgsField("LblAlignH", QVariant.String, "varchar", 12),
                QgsField("LblAlignV", QVariant.String, "varchar", 12),
                QgsField("LblSize", QVariant.Int, "integer", 2),
                QgsField("LblRot", QVariant.Double, "numeric", 10, 2),
                QgsField("LblBold", QVariant.Int, "integer", 1),
                QgsField("LblItalic", QVariant.Int, "integer", 1),
                QgsField("LblColor", QVariant.String, "varchar", 7),
                QgsField("LblFont", QVariant.String, "varchar", 64),
                QgsField("LblUnder", QVariant.Int, "integer", 1),
                QgsField("LblStrike", QVariant.Int, "integer", 1),
                QgsField("LblShow", QVariant.Int, "integer", 1),
                QgsField("LblShowCO", QVariant.Int, "integer", 1),
                QgsField("LblAShow", QVariant.Int, "integer", 1)
            ]

            r = labelLayerProvider.addAttributes(labelFields)

            # print 'ajout des champs de labeling: ' + str(r)

            labelFields = labelLayerProvider.fields(
            )  # replace labelFields with source FIELDS + labelingFields

            # iterate objects of layer to load new destination labelLayerProvider
            # print 'start loop on source layer attributes'

            if ret == 16384:
                selectedFeatures = sourceLayer.selectedFeatures()
            else:
                selectedFeatures = sourceLayer.getFeatures()

            for sourceFeat in selectedFeatures:
                labelLayerFields = labelLayerProvider.fields()
                # print 'length of field map: ' + str(len(labelLayerFields))

                # for f in labelLayerFields:
                # print str(f.name())
                labelFeature = QgsFeature(labelLayerFields)
                geom = sourceFeat.geometry()
                #labelFeature.setGeometry(QgsGeometry.fromPoint(geom.centroid().asPoint())) # create geometry as centroid
                WKTLine = 'LINESTRING(' + str(
                    geom.centroid().asPoint().x() + 0.0001) + ' ' + str(
                        geom.centroid().asPoint().y() + 0.0001) + ' , ' + str(
                            geom.centroid().asPoint().x()) + ' ' + str(
                                geom.centroid().asPoint().y()) + ')'
                # print 'WKTLine: '+ WKTLine
                labelFeature.setGeometry(QgsGeometry.fromWkt(
                    WKTLine))  # create geometry as centroid

                attrs = sourceFeat.attributes()
                sourceFieldCount = len(attrs)
                # print 'length of copied attributes : '+ str(len(attrs))
                # print 'attributs sources ' + str(attrs)
                for i, a in enumerate(attrs):
                    #print str(i) + ' ' + str(a)
                    labelFeature[i] = a
                #labelFeature.setAttributes(attrs)

                labelFeature['LblField'] = sourceFeat[
                    self.dlg.labelfield.currentText(
                    )]  #gets fields chosen by user in dialog
                labelFeature['LblShow'] = 1
                labelFeature['LblSize'] = 9
                labelFeature['LblAShow'] = 1
                labelFeature['LblAlignV'] = 'Half'
                labelFeature['LblAlignH'] = 'Center'
                # displayFieldName = sourceLayer.displayField()
                # if displayFieldName :
                #     # print ' valeur du champ label : ' + str(sourceFeat[displayFieldName])
                #     labelFeature['LblField'] = str(sourceFeat[displayFieldName])
                # else:
                #     labelFeature['LblField'] = str(sourceFeat[0])
                #-- prefill some attributes examples (default = deactivated)
                # labelFeature['LblX'] = str(geom.centroid().asPoint().x()) # coord x
                # labelFeature['LblY'] = str(geom.centroid().asPoint().y()) # coord x

                labelLayerProvider.addFeatures([labelFeature])
                labelLayer.updateExtents()

            labelMapLayer = QgsMapLayerRegistry.instance().addMapLayer(
                labelLayer, True)  # adds map layer to map registry

            # # customize style
            rendererV2 = labelMapLayer.rendererV2()
            # creates default style for label (transparent point, default labeling )
            style_path = os.path.join(os.path.dirname(__file__),
                                      "label_style.qml")
            (errorMsg, result) = labelMapLayer.loadNamedStyle(style_path)

            # for QGIS 2.1 and > , use data defined pen size >0 with $length / $scale > 0.05 to display arrows only
            # or use a flag , and compute it to 1 if label is moved.  how to hide easily if needed ?

            ## parameters for advanced labeling -- picked up from a qgs model file

            # #generic labeling properties
            labelMapLayer.setCustomProperty(
                "labeling/fieldName",
                "LblField")  # TODO replace default value with dialog input
            labelMapLayer.setCustomProperty(
                "labeling", "pal")  # new gen labeling activated
            labelMapLayer.setCustomProperty("labeling/fontSize",
                                            "8")  # default value
            labelMapLayer.setCustomProperty("labeling/multiLineLabels",
                                            "true")  # default value
            labelMapLayer.setCustomProperty("labeling/enabled",
                                            "true")  # default value
            #labelMapLayer.setCustomProperty("labeling/displayAll", "true") # force all labels to display
            labelMapLayer.setCustomProperty(
                "labeling/priority",
                "10")  # puts a high priority to labeling layer
            labelMapLayer.setCustomProperty("labeling/multilineAlign",
                                            "1")  # multiline align to center
            #labelMapLayer.setCustomProperty("labeling/wrapChar", "%") # multiline break symbol

            #line properties case
            labelMapLayer.setCustomProperty("labeling/placement", "4")

            # #data defined properties
            labelMapLayer.setCustomProperty("labeling/dataDefined/PositionX",
                                            "1~~0~~~~LblX")
            labelMapLayer.setCustomProperty("labeling/dataDefined/PositionY",
                                            "1~~0~~~~LblY")
            labelMapLayer.setCustomProperty("labeling/dataDefined/Hali",
                                            "1~~0~~~~LblAlignH")
            labelMapLayer.setCustomProperty("labeling/dataDefined/Vali",
                                            "1~~0~~~~LblAlignV")
            labelMapLayer.setCustomProperty("labeling/dataDefined/Size",
                                            "1~~0~~~~LblSize")
            labelMapLayer.setCustomProperty("labeling/dataDefined/Rotation",
                                            "1~~0~~~~LblRot")
            labelMapLayer.setCustomProperty("labeling/dataDefined/Bold",
                                            "1~~0~~~~LblBold")
            labelMapLayer.setCustomProperty("labeling/dataDefined/Italic",
                                            "1~~0~~~~LblItalic")
            labelMapLayer.setCustomProperty("labeling/dataDefined/Underline",
                                            "1~~0~~~~LblUnder")
            labelMapLayer.setCustomProperty("labeling/dataDefined/Strikeout",
                                            "1~~0~~~~LblStrike")
            labelMapLayer.setCustomProperty("labeling/dataDefined/Color",
                                            "1~~0~~~~LblColor")
            labelMapLayer.setCustomProperty("labeling/dataDefined/Family",
                                            "1~~0~~~~LblFont")
            labelMapLayer.setCustomProperty("labeling/dataDefined/Show",
                                            "1~~0~~~~LblShow")
            labelMapLayer.setCustomProperty("labeling/dataDefined/AlwaysShow",
                                            "1~~0~~~~LblAShow")
            # sets a tag in abstract metadata to help reconnect layer on project read (avoid having to read data, which causes problem with mem Layer Saver still populating data)
            labelMapLayer.setAbstract(
                '<labeling_layer> do not remove - used by EasyCustomLabeling plugin to reconnect labeling layers'
            )
            labelLayer.updateExtents()

            # activates editing
            self.iface.setActiveLayer(labelMapLayer)
            labelLayer.startEditing()
            self.iface.actionToggleEditing().trigger()

            # connects label layer attributes values changed to labelLayerModified function
            labelLayer.attributeValueChanged.connect(self.labelLayerModified)

            #redraws registry and mapcanvas.
            if hasattr(labelMapLayer,
                       "setCacheImage") and QGis.QGIS_VERSION_INT < 20600:
                labelMapLayer.setCacheImage(None)

            labelMapLayer.triggerRepaint()
            self.iface.legendInterface().refreshLayerSymbology(labelMapLayer)
            self.iface.actionToggleEditing().trigger()
            iface.messageBar().pushMessage(
                "Avertissement",
                QtGui.QApplication.translate(
                    "EasyCustomLabeling",
                    "Turn on editing mode on label layer to start customizing labels"
                ),
                level=0,
                duration=3)

        except:
            # print 'runLabel exception loop '
            # if sourceLayer and not keepUserSelection :
            #     sourceLayer.removeSelection()
            print 'exception caught'
            raise

        finally:
            if QGis.QGIS_VERSION_INT < 20600:
                QgsMapLayerRegistry.instance().clearAllLayerCaches(
                )  #clean cache to allow mask layer to appear on refresh

            # if sourceLayer and not keepUserSelection :
            #     sourceLayer.removeSelection()

            self.iface.mapCanvas().freeze(0)
            self.iface.mapCanvas().refresh()