コード例 #1
0
class EasyCustomLabeling(QObject):
# class EasyCustomLabeling:

  def __init__(self, iface):
    # Save reference to the QGIS interface
    QObject.__init__(self) #init from  QObject parent
    self.iface = iface
    self.qgsVersion = unicode(QGis.QGIS_VERSION_INT)
    print '# EasyCustomLabeling debug trace: plugin loaded at ' + str(datetime.datetime.now())
    #QgsMessageLog.logMessage('# EasyCustomLabeling debug trace: plugin loaded at ' + str(datetime.datetime.now()))
    # For i18n support, finds locale and translates with i18.qm files
    pluginName = 'EasyCustomLabeling'
    userPluginPath = QFileInfo(QgsApplication.qgisUserDbFilePath()).path() + "/python/plugins/"+ pluginName
    systemPluginPath = QgsApplication.prefixPath() + "/python/plugins/"+ pluginName
    overrideLocale = bool(QSettings().value("locale/overrideFlag", False))
     
    #print 'userPluginPath: '+ userPluginPath
    if not overrideLocale:
        localeFullName = QLocale.system().name()
    else:
        localeFullName = QSettings().value("locale/userLocale", "")

    if QFileInfo(userPluginPath).exists():
        translationPath = userPluginPath + "/i18n/"+pluginName+"_" + localeFullName + ".qm"
    else:
        translationPath = systemPluginPath + "/i18n/"+pluginName+"_"  + localeFullName + ".qm"
    # print translationPath
    self.localePath = translationPath

    if QFileInfo(self.localePath).exists():
        self.translator = QTranslator()
        self.translator.load(self.localePath)
        QCoreApplication.installTranslator(self.translator)
        # print('localepath exists')
    # print('translation debug info :' + ' overrideLocale=' + str(overrideLocale) + '; localeFullName=' +localeFullName + '; translationPath=' + translationPath )

   

  def initGui(self):
    #Create actions triggered by the plugin
    self.actionLabel = QAction( QIcon( ":/plugins/EasyCustomLabeling/icon.png" ), QtGui.QApplication.translate("EasyCustomLabeling", "Generates a layer ready for custom labeling tools", None, QtGui.QApplication.UnicodeUTF8), self.iface.mainWindow() )
    
    self.actionAbout = QAction(QIcon(os.path.join( os.path.dirname(__file__), "icon.png" )), QtGui.QApplication.translate("EasyCustomLabeling", "Help", None, QtGui.QApplication.UnicodeUTF8), self.iface.mainWindow())

    # connect the action to the run method
    self.actionAbout.triggered.connect(self.runAbout)
    self.actionLabel.triggered.connect(self.runLabel)

   # adds buttons to labeling toolbar if exists
    self.toolBar = self.iface.pluginToolBar()
    toolbars = self.iface.mainWindow().findChildren(QToolBar)
    toolbarFound = False
    #checks all existing toolbars for labeling toolbar
    for toolbar in toolbars:
        if toolbar.objectName() == "mLabelToolBar":
            #QMessageBox.warning( None, "DEBUG", "LabelToolBar Found")
            self.toolBar = toolbar
            #saves mLabelToolbar for unload plugin action
            global actions
            actions = self.toolBar.actions()
            #append easy labeling actions to list
            actions_easylabel = actions
            actions_easylabel.append(self.actionLabel)
            #clear all actions of toolbar
            self.toolBar.clear()
            i=0
            for a in actions:
                self.toolBar.addAction(actions_easylabel[i])
                i=i+1
            toolbarFound = True

    if not toolbarFound :
        QMessageBox.warning( None, "DEBUG", "labeling toolbar not found. Please use menu Extension/Easy Custom Labeling")

    self.iface.addPluginToMenu( "&" + QtGui.QApplication.translate("EasyCustomLabeling", "Easy Custom labeling", None, QtGui.QApplication.UnicodeUTF8), self.actionLabel)
    self.iface.addPluginToMenu( "&" + QtGui.QApplication.translate("EasyCustomLabeling", "Easy Custom labeling", None, QtGui.QApplication.UnicodeUTF8), self.actionAbout)

    #connects labelLayerCheck class to QgisInterface::currentLayerChanged signal (QgsMapLayer * layer)   
    #self.iface.currentLayerChanged.connect(self.labelLayerChecked)
    proj = QgsProject.instance()

    proj.readProject.connect(self.labelLayerChecked)  

    # print 'init GUI connecting to readProject '
    # QObject.connect(self.iface, SIGNAL("currentLayerChanged ( QgsMapLayer *)"), self.labelLayerChecked)

    #disconnects if label layers closed? 

  def labelLayerChecked(self):
    
    # print 'project loaded. labelLayerchecked triggered '
    #  Checks if some labeling layers are already there, and replug, if not already  labelLayerModified events

    layers = iface.legendInterface().layers()
    # print layers
    tag =''
    connectSuccess = 'f'
   
    for layer in layers:
        tag =''
        # print layer.name() 
      
        if not layer.type() == 0 : 
            # print 'non vector layer > quit'
            return
        tag = layer.abstract()
        # print 'tag: ' + tag
        if "<labeling_layer>" in tag or "Label_" in layer.name() :
            # print 'ECL Debug: labeling layer found > reconnecting modification events to callout drawing'
            layer.attributeValueChanged.connect(self.labelLayerModified)
            connectSuccess = 't'
        # else :
            # return

    # if connectSuccess == 'f':
        # iface.messageBar().pushMessage("Error", QtGui.QApplication.translate("EasyCustomLabeling", "EasyCustomLabeling Error: For some reason, at least one labeling layer could not be reconnected to plugin events. Callouts line will not follow when moving label", None, QtGui.QApplication.UnicodeUTF8), level=2, duration=10)

        
      


       
  # @pyqtSlot(int, int, str)
  def labelLayerModified(self, FeatureId, idx, variant):
        sender = self.sender()
        # print ' declenche le signal' 
        # editedLayer = self.iface.activeLayer()
        if not sender or not sender.type()==0:
            return
            # print 'no sender caught or non vector layer'
     
        editedLayer = sender 
        
        dp = editedLayer.dataProvider()

        LblXok = False
        LblYok = False
        LblAlignHok= False
        LblAlignVok= False
        LblShowCOok= False
        LblShowok= False

        for f in dp.fields():
            if f.name() == 'LblX':
                LblXok = True
                # print 'LblXok'
            elif f.name() == 'LblY':
                LblYok = True  
                # print 'LblYok'
            elif f.name() == 'LblAlignH':
                LblAlignHok = True 
                # print 'LblAlignHok'
            elif f.name() == 'LblAlignV':
                LblAlignVok = True  
                # print 'LblAlignVok'
            elif f.name() == 'LblShowCO':
                LblShowCOok = True
                # print 'LblShowCOok' 
            elif f.name() == 'LblShow':
                LblShowok = True
                # print 'LblShowok'

       
        #gets new attrib and geom > retune WKT with new label XY
        editFeature = QgsFeature()
        if editedLayer == None or editedLayer.getFeatures(QgsFeatureRequest().setFilterFid(FeatureId)).nextFeature(editFeature) is False  :
            return
        else:
            # print 'traitement signal' 
            editGeom = editFeature.geometry()
            WKTLine = editGeom.exportToWkt()
            editLayerProvider = editedLayer.dataProvider()
            fields = editLayerProvider.fields()
            fieldname= fields[idx].name()
            originX = editGeom.asPolyline()[0].x()
            originY = editGeom.asPolyline()[0].y()
            finalX  = editGeom.asPolyline()[len(editGeom.asPolyline())-1].x()
            finalY  = editGeom.asPolyline()[len(editGeom.asPolyline())-1].y()
            # print ('signal edited param: fieldname ' + fieldname +'; variant '+ str(variant) + '; FeatureId' +str(FeatureId) +'; originX '+ str(originX) + '; originY ' + str(originY) + '; finalX ' +str(finalX)+ '; finalY ' + str(finalY))

            scale = iface.mapCanvas().scale()
            radius_threshold = 1 #cm on screen


            if fieldname == 'LblX' :
                if variant==NULL :   #case when user unpins the label > sets arrow back to arrow based on point location
                    # print ('lblX returns NULL test')
                    WKTLine = 'LINESTRING('+ str(originX+0.0001) +' '+  str(originY +0.0001 ) + ' , '+ str(originX)+ ' ' +str(originY)+ ')'
                    editedLayer.changeGeometry(FeatureId, QgsGeometry.fromWkt( WKTLine ))
                    return
                if isinstance(variant, basestring): # test case, when editing from attribute table, variant is sent as text! converts to float
                    variant = float(variant)
                newFinalX = variant
                newFinalY = finalY
                
                newWKT = 'LINESTRING('+ str(originX) +' '+  str(originY) + ' ,' + str(newFinalX)+ ' ' +str(finalY)+ ')'  
                coLength =  QgsGeometry.fromWkt( newWKT ).length()
                coscreenlength  = 100* coLength / scale 

                if newFinalX < originX and coscreenlength >= radius_threshold:
                    # middleX = originX - abs(finalY - originY ) 
                    editedLayer.changeAttributeValue(FeatureId, editLayerProvider.fieldNameIndex('LblAlignH'), 'Right')
                    
                elif newFinalX > originX and coscreenlength >= radius_threshold:
                    # middleX = originX + abs(finalY - originY ) 
                    editedLayer.changeAttributeValue(FeatureId, editLayerProvider.fieldNameIndex('LblAlignH'), 'Left')
                else :
                    editedLayer.changeAttributeValue(FeatureId, editLayerProvider.fieldNameIndex('LblAlignH'), 'Center')
                     
                editedLayer.changeGeometry(FeatureId, QgsGeometry.fromWkt( newWKT ))

                
            if fieldname == 'LblY':
                if variant == NULL  :   #case when user unpins the label > sets arrow back to arrow based on point location
                    # print ('lblX returns NULL test')      
                    WKTLine = 'LINESTRING('+ str(originX+0.0001) +' '+  str(originY +0.0001 ) + ' , '+ str(originX)+ ' ' +str(originY)+ ')'
                    editedLayer.changeGeometry(FeatureId, QgsGeometry.fromWkt( WKTLine ))
                    return
                if isinstance(variant, basestring):  # test case, when editing from attribute table, variant is sent as text! converts to float
                    variant = float(variant)
                newFinalX = finalX
                newFinalY = variant               
               
                deltaY =  abs(newFinalY - originY )
                deltaX =  abs(newFinalX - originX )


            
            
                

                if newFinalX < originX   and newFinalY > originY    and  deltaY < deltaX : # cas quandran ul 1 ok
                    middleX = originX - deltaY
                    middleY = newFinalY
                    
                elif newFinalX < originX and newFinalY > originY    and  deltaY >= deltaX : #cas quadrant ul 2 ok 
                    middleX = originX 
                    middleY = originY + deltaX
                    
                if newFinalX < originX   and newFinalY <= originY    and  deltaY < deltaX  : # cas quandran ll 1
                    middleX = originX - deltaY
                    middleY = newFinalY 
                    
                elif newFinalX < originX and newFinalY <= originY    and  deltaY >= deltaX : #cas quadrant ll 2
                    middleX = originX 
                    middleY = originY - deltaX
                    
                if newFinalX >= originX and newFinalY > originY     and deltaY > deltaX  : # cas quandran ur alternatif
                    middleX = originX 
                    middleY = newFinalY - deltaX
                    
                elif newFinalX >= originX  and newFinalY > originY    and deltaY < deltaX: #cas quadrant ur nominal ok
                    middleX = originX + deltaY
                    middleY = newFinalY
                    
                if newFinalX >= originX and newFinalY <= originY    and deltaY > deltaX  : # cas quandran lr alternatif
                    middleX = originX
                    middleY = originY - deltaX
                    
                elif newFinalX >= originX and newFinalY <= originY    and deltaY < deltaX: #cas quadrant lr nominal
                    middleX = originX + deltaY
                    middleY = newFinalY

                
                newWKT = 'LINESTRING('+ str(originX) +' '+  str(originY) + ' , '+ str(middleX)+' '+ str(middleY) +' ,' + str(newFinalX)+ ' ' +str(newFinalY)+ ')'
                editedLayer.changeGeometry(FeatureId, QgsGeometry.fromWkt( newWKT ))
                
                 # change visibility status  if label is close to origin point (screen distance tolerance)
            
               
                coLength =  QgsGeometry.fromWkt( newWKT ).length()
                coscreenlength  = 100* coLength / scale 

                if coscreenlength < radius_threshold :
                    # print 'under radius_threshold'
                    editedLayer.changeAttributeValue(FeatureId, editLayerProvider.fieldNameIndex('LblShowCO'), '0')
                else :
                    editedLayer.changeAttributeValue(FeatureId, editLayerProvider.fieldNameIndex('LblShowCO'), '1')

                          

           #if label is masked or shown , does the same for CallOut
            elif fieldname == 'LblShow':   
                if variant == 0 :
                    editedLayer.changeAttributeValue(FeatureId, editLayerProvider.fieldNameIndex('LblShowCO'), '0')
                else :
                    editedLayer.changeAttributeValue(FeatureId, editLayerProvider.fieldNameIndex('LblShowCO'), '1')
                    
     

            else :
                return False, "fieldname not in LblX or LblY."
           
            # refresh map layer - attempt to solve issue when callout show only after refreshing labeling parameters
            
            editedLayer.triggerRepaint() 
        
  def unload( self):
    # disconnects signals todo
    # self.iface.currentLayerChanged.disconnect()

    # Remove the plugin menu item and icon
    self.toolBar.removeAction( self.actionLabel)
    self.iface.removePluginMenu( "&" + QtGui.QApplication.translate("EasyCustomLabeling", "Easy Custom labeling", None, QtGui.QApplication.UnicodeUTF8), self.actionLabel)
    self.iface.removePluginMenu( "&" + QtGui.QApplication.translate("EasyCustomLabeling", "Easy Custom labeling", None, QtGui.QApplication.UnicodeUTF8), self.actionAbout)

    #remove action from mLabelToolBar if exists
    toolbars = self.iface.mainWindow().findChildren(QToolBar)

  

    for toolbar in toolbars:
        if toolbar.objectName() == "mLabelToolBar":
            self.toolBar = toolbar
            # You have to save all of the actions from the toolbar
            actions = self.toolBar.actions()
            # then, you clear the complete toolbar
            self.toolBar.clear()
            # and you re-add only the actions yo uwant
            i=0
            for a in actions:
                self.toolBar.addAction(actions[i])
                i=i+1

             
   
#main action that duplicates the layer
  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() ) + ' , '+ 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()
        
        #QMessageBox.warning( None, "Avertissement", 'Pensez a enregistrer les editions de votre couche d étiquettes avant de quitter')
        # print 'end of runlabel Action'
        
  def runAbout(self):
    #QMessageBox.about(None, QtGui.QApplication.translate("EasyCustomLabeling", "texte about", None, QtGui.QApplication.UnicodeUTF8), QtGui.QApplication.translate("EasyCustomLabeling", "<strong>Easy custom labeling v. 0.4,  Regis Haubourg (AEAG) - 2012. \n \n Action 1:This plugin duplicate a layer, transforming geometries into centroids, \n and adds all required fields for custom labeling. \n \n Action 2 - Arrow function draws lines between label and original object \n \n WARNING! This plugin requires to use Memory Layer Saver plugin if you want to save labels with project. \n Plugin memory layer saver 2.0 or higher is needed because of new gml behaviour (GDAL 1.9) \n \n Please send bugs or features requests here : http://hub.qgis.org/projects/easycustomlabeling </strong>", None, QtGui.QApplication.UnicodeUTF8))
    try:
        QDesktopServices.openUrl(QUrl("https://github.com/haubourg/EasyCustomLabeling/wiki"))
    except:
        pass
コード例 #2
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()
コード例 #3
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() ) + ' , '+ 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()
コード例 #4
0
class EasyCustomLabeling(QObject):
    # class EasyCustomLabeling:

    def __init__(self, iface):
        # Save reference to the QGIS interface
        QObject.__init__(self)  #init from  QObject parent
        self.iface = iface
        self.qgsVersion = unicode(QGis.QGIS_VERSION_INT)
        print '# EasyCustomLabeling debug trace: plugin loaded at ' + str(
            datetime.datetime.now())
        #QgsMessageLog.logMessage('# EasyCustomLabeling debug trace: plugin loaded at ' + str(datetime.datetime.now()))
        # For i18n support, finds locale and translates with i18.qm files
        pluginName = 'EasyCustomLabeling'
        userPluginPath = QFileInfo(QgsApplication.qgisUserDbFilePath()).path(
        ) + "/python/plugins/" + pluginName
        systemPluginPath = QgsApplication.prefixPath(
        ) + "/python/plugins/" + pluginName
        overrideLocale = bool(QSettings().value("locale/overrideFlag", False))

        #print 'userPluginPath: '+ userPluginPath
        if not overrideLocale:
            localeFullName = QLocale.system().name()
        else:
            localeFullName = QSettings().value("locale/userLocale", "")

        if QFileInfo(userPluginPath).exists():
            translationPath = userPluginPath + "/i18n/" + pluginName + "_" + localeFullName + ".qm"
        else:
            translationPath = systemPluginPath + "/i18n/" + pluginName + "_" + localeFullName + ".qm"
        # print translationPath
        self.localePath = translationPath

        if QFileInfo(self.localePath).exists():
            self.translator = QTranslator()
            self.translator.load(self.localePath)
            QCoreApplication.installTranslator(self.translator)
            # print('localepath exists')
        # print('translation debug info :' + ' overrideLocale=' + str(overrideLocale) + '; localeFullName=' +localeFullName + '; translationPath=' + translationPath )

    def initGui(self):
        #Create actions triggered by the plugin
        self.actionLabel = QAction(
            QIcon(":/plugins/EasyCustomLabeling/icon.png"),
            QtGui.QApplication.translate(
                "EasyCustomLabeling",
                "Generates a layer ready for custom labeling tools", None,
                QtGui.QApplication.UnicodeUTF8), self.iface.mainWindow())

        self.actionAbout = QAction(
            QIcon(os.path.join(os.path.dirname(__file__), "icon.png")),
            QtGui.QApplication.translate("EasyCustomLabeling", "Help", None,
                                         QtGui.QApplication.UnicodeUTF8),
            self.iface.mainWindow())

        # connect the action to the run method
        QObject.connect(self.actionLabel, SIGNAL("activated()"), self.runLabel)
        QObject.connect(self.actionAbout, SIGNAL("activated()"), self.runAbout)

        # adds buttons to labeling toolbar if exists
        self.toolBar = self.iface.pluginToolBar()
        toolbars = self.iface.mainWindow().findChildren(QToolBar)
        toolbarFound = False
        #checks all existing toolbars for labeling toolbar
        for toolbar in toolbars:
            if toolbar.objectName() == "mLabelToolBar":
                #QMessageBox.warning( None, "DEBUG", "LabelToolBar Found")
                self.toolBar = toolbar
                #saves mLabelToolbar for unload plugin action
                global actions
                actions = self.toolBar.actions()
                #append easy labeling actions to list
                actions_easylabel = actions
                actions_easylabel.append(self.actionLabel)
                #clear all actions of toolbar
                self.toolBar.clear()
                i = 0
                for a in actions:
                    self.toolBar.addAction(actions_easylabel[i])
                    i = i + 1
                toolbarFound = True

        if not toolbarFound:
            QMessageBox.warning(
                None, "DEBUG",
                "labeling toolbar not found. Please use menu Extension/Easy Custom Labeling"
            )

        self.iface.addPluginToMenu(
            "&" + QtGui.QApplication.translate(
                "EasyCustomLabeling", "Easy Custom labeling", None,
                QtGui.QApplication.UnicodeUTF8), self.actionLabel)
        self.iface.addPluginToMenu(
            "&" + QtGui.QApplication.translate(
                "EasyCustomLabeling", "Easy Custom labeling", None,
                QtGui.QApplication.UnicodeUTF8), self.actionAbout)

        #connects labelLayerCheck class to QgisInterface::currentLayerChanged signal (QgsMapLayer * layer)
        #self.iface.currentLayerChanged.connect(self.labelLayerChecked)
        proj = QgsProject.instance()

        proj.readProject.connect(self.labelLayerChecked)

        # print 'init GUI connecting to readProject '
        # QObject.connect(self.iface, SIGNAL("currentLayerChanged ( QgsMapLayer *)"), self.labelLayerChecked)

        #disconnects if label layers closed?

    def labelLayerChecked(self):

        # print 'project loaded. labelLayerchecked triggered '
        #  Checks if some labeling layers are already there, and replug, if not already  labelLayerModified events

        layers = iface.legendInterface().layers()
        # print layers
        tag = ''
        connectSuccess = 'f'

        for layer in layers:
            tag = ''
            # print layer.name()

            if not layer.type() == 0:
                # print 'non vector layer > quit'
                return
            tag = layer.abstract()
            # print 'tag: ' + tag
            if "<labeling_layer>" in tag or "Label_" in layer.name():
                # print 'ECL Debug: labeling layer found > reconnecting modification events to callout drawing'
                layer.attributeValueChanged.connect(self.labelLayerModified)
                connectSuccess = 't'
            # else :
            # return

        # if connectSuccess == 'f':
        # iface.messageBar().pushMessage("Error", QtGui.QApplication.translate("EasyCustomLabeling", "EasyCustomLabeling Error: For some reason, at least one labeling layer could not be reconnected to plugin events. Callouts line will not follow when moving label", None, QtGui.QApplication.UnicodeUTF8), level=2, duration=10)

    # @pyqtSlot(int, int, str)
    def labelLayerModified(self, FeatureId, idx, variant):
        sender = self.sender()
        # print ' declenche le signal'
        # editedLayer = self.iface.activeLayer()
        if not sender or not sender.type() == 0:
            return
            # print 'no sender caught or non vector layer'

        editedLayer = sender

        dp = editedLayer.dataProvider()

        LblXok = False
        LblYok = False
        LblAlignHok = False
        LblAlignVok = False
        LblShowCOok = False
        LblShowok = False

        for f in dp.fields():
            if f.name() == 'LblX':
                LblXok = True
                # print 'LblXok'
            elif f.name() == 'LblY':
                LblYok = True
                # print 'LblYok'
            elif f.name() == 'LblAlignH':
                LblAlignHok = True
                # print 'LblAlignHok'
            elif f.name() == 'LblAlignV':
                LblAlignVok = True
                # print 'LblAlignVok'
            elif f.name() == 'LblShowCO':
                LblShowCOok = True
                # print 'LblShowCOok'
            elif f.name() == 'LblShow':
                LblShowok = True
                # print 'LblShowok'

        #gets new attrib and geom > retune WKT with new label XY
        editFeature = QgsFeature()
        if editedLayer == None or editedLayer.getFeatures(QgsFeatureRequest(
        ).setFilterFid(FeatureId)).nextFeature(editFeature) is False:
            return
        else:
            # print 'traitement signal'
            editGeom = editFeature.geometry()
            WKTLine = editGeom.exportToWkt()
            editLayerProvider = editedLayer.dataProvider()
            fields = editLayerProvider.fields()
            fieldname = fields[idx].name()
            originX = editGeom.asPolyline()[0].x()
            originY = editGeom.asPolyline()[0].y()
            finalX = editGeom.asPolyline()[len(editGeom.asPolyline()) - 1].x()
            finalY = editGeom.asPolyline()[len(editGeom.asPolyline()) - 1].y()
            # print ('signal edited param: fieldname ' + fieldname +'; variant '+ str(variant) + '; FeatureId' +str(FeatureId) +'; originX '+ str(originX) + '; originY ' + str(originY) + '; finalX ' +str(finalX)+ '; finalY ' + str(finalY))

            scale = iface.mapCanvas().scale()
            radius_threshold = 1  #cm on screen

            if fieldname == 'LblX':
                if variant == NULL:  #case when user unpins the label > sets arrow back to arrow based on point location
                    # print ('lblX returns NULL test')
                    WKTLine = 'LINESTRING(' + str(
                        originX +
                        0.0001) + ' ' + str(originY + 0.0001) + ' , ' + str(
                            originX) + ' ' + str(originY) + ')'
                    editedLayer.changeGeometry(FeatureId,
                                               QgsGeometry.fromWkt(WKTLine))
                    return
                if isinstance(
                        variant, basestring
                ):  # test case, when editing from attribute table, variant is sent as text! converts to float
                    variant = float(variant)
                newFinalX = variant
                newFinalY = finalY

                newWKT = 'LINESTRING(' + str(originX) + ' ' + str(
                    originY) + ' ,' + str(newFinalX) + ' ' + str(finalY) + ')'
                coLength = QgsGeometry.fromWkt(newWKT).length()
                coscreenlength = 100 * coLength / scale

                if newFinalX < originX and coscreenlength >= radius_threshold:
                    # middleX = originX - abs(finalY - originY )
                    editedLayer.changeAttributeValue(
                        FeatureId,
                        editLayerProvider.fieldNameIndex('LblAlignH'), 'Right')

                elif newFinalX > originX and coscreenlength >= radius_threshold:
                    # middleX = originX + abs(finalY - originY )
                    editedLayer.changeAttributeValue(
                        FeatureId,
                        editLayerProvider.fieldNameIndex('LblAlignH'), 'Left')
                else:
                    editedLayer.changeAttributeValue(
                        FeatureId,
                        editLayerProvider.fieldNameIndex('LblAlignH'),
                        'Center')

                editedLayer.changeGeometry(FeatureId,
                                           QgsGeometry.fromWkt(newWKT))

            if fieldname == 'LblY':
                if variant == NULL:  #case when user unpins the label > sets arrow back to arrow based on point location
                    # print ('lblX returns NULL test')
                    WKTLine = 'LINESTRING(' + str(
                        originX +
                        0.0001) + ' ' + str(originY + 0.0001) + ' , ' + str(
                            originX) + ' ' + str(originY) + ')'
                    editedLayer.changeGeometry(FeatureId,
                                               QgsGeometry.fromWkt(WKTLine))
                    return
                if isinstance(
                        variant, basestring
                ):  # test case, when editing from attribute table, variant is sent as text! converts to float
                    variant = float(variant)
                newFinalX = finalX
                newFinalY = variant

                deltaY = abs(newFinalY - originY)
                deltaX = abs(newFinalX - originX)

                if newFinalX < originX and newFinalY > originY and deltaY < deltaX:  # cas quandran ul 1 ok
                    middleX = originX - deltaY
                    middleY = newFinalY

                elif newFinalX < originX and newFinalY > originY and deltaY >= deltaX:  #cas quadrant ul 2 ok
                    middleX = originX
                    middleY = originY + deltaX

                if newFinalX < originX and newFinalY <= originY and deltaY < deltaX:  # cas quandran ll 1
                    middleX = originX - deltaY
                    middleY = newFinalY

                elif newFinalX < originX and newFinalY <= originY and deltaY >= deltaX:  #cas quadrant ll 2
                    middleX = originX
                    middleY = originY - deltaX

                if newFinalX >= originX and newFinalY > originY and deltaY > deltaX:  # cas quandran ur alternatif
                    middleX = originX
                    middleY = newFinalY - deltaX

                elif newFinalX >= originX and newFinalY > originY and deltaY < deltaX:  #cas quadrant ur nominal ok
                    middleX = originX + deltaY
                    middleY = newFinalY

                if newFinalX >= originX and newFinalY <= originY and deltaY > deltaX:  # cas quandran lr alternatif
                    middleX = originX
                    middleY = originY - deltaX

                elif newFinalX >= originX and newFinalY <= originY and deltaY < deltaX:  #cas quadrant lr nominal
                    middleX = originX + deltaY
                    middleY = newFinalY

                newWKT = 'LINESTRING(' + str(originX) + ' ' + str(
                    originY) + ' , ' + str(middleX) + ' ' + str(
                        middleY) + ' ,' + str(newFinalX) + ' ' + str(
                            newFinalY) + ')'
                editedLayer.changeGeometry(FeatureId,
                                           QgsGeometry.fromWkt(newWKT))

                # change visibility status  if label is close to origin point (screen distance tolerance)

                coLength = QgsGeometry.fromWkt(newWKT).length()
                coscreenlength = 100 * coLength / scale

                if coscreenlength < radius_threshold:
                    # print 'under radius_threshold'
                    editedLayer.changeAttributeValue(
                        FeatureId,
                        editLayerProvider.fieldNameIndex('LblShowCO'), '0')
                else:
                    editedLayer.changeAttributeValue(
                        FeatureId,
                        editLayerProvider.fieldNameIndex('LblShowCO'), '1')

        #if label is masked or shown , does the same for CallOut
            elif fieldname == 'LblShow':
                if variant == 0:
                    editedLayer.changeAttributeValue(
                        FeatureId,
                        editLayerProvider.fieldNameIndex('LblShowCO'), '0')
                else:
                    editedLayer.changeAttributeValue(
                        FeatureId,
                        editLayerProvider.fieldNameIndex('LblShowCO'), '1')

            else:
                return False, "fieldname not in LblX or LblY."

            # refresh map layer - attempt to solve issue when callout show only after refreshing labeling parameters

            editedLayer.triggerRepaint()

    def unload(self):
        # disconnects signals todo
        # self.iface.currentLayerChanged.disconnect()

        # Remove the plugin menu item and icon
        self.toolBar.removeAction(self.actionLabel)
        self.iface.removePluginMenu(
            "&" + QtGui.QApplication.translate(
                "EasyCustomLabeling", "Easy Custom labeling", None,
                QtGui.QApplication.UnicodeUTF8), self.actionLabel)
        self.iface.removePluginMenu(
            "&" + QtGui.QApplication.translate(
                "EasyCustomLabeling", "Easy Custom labeling", None,
                QtGui.QApplication.UnicodeUTF8), self.actionAbout)

        #remove action from mLabelToolBar if exists
        toolbars = self.iface.mainWindow().findChildren(QToolBar)

        for toolbar in toolbars:
            if toolbar.objectName() == "mLabelToolBar":
                self.toolBar = toolbar
                # You have to save all of the actions from the toolbar
                actions = self.toolBar.actions()
                # then, you clear the complete toolbar
                self.toolBar.clear()
                # and you re-add only the actions yo uwant
                i = 0
                for a in actions:
                    self.toolBar.addAction(actions[i])
                    i = i + 1


#main action that duplicates the layer

    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()

            #QMessageBox.warning( None, "Avertissement", 'Pensez a enregistrer les editions de votre couche d étiquettes avant de quitter')
            # print 'end of runlabel Action'

    def runAbout(self):
        #QMessageBox.about(None, QtGui.QApplication.translate("EasyCustomLabeling", "texte about", None, QtGui.QApplication.UnicodeUTF8), QtGui.QApplication.translate("EasyCustomLabeling", "<strong>Easy custom labeling v. 0.4,  Regis Haubourg (AEAG) - 2012. \n \n Action 1:This plugin duplicate a layer, transforming geometries into centroids, \n and adds all required fields for custom labeling. \n \n Action 2 - Arrow function draws lines between label and original object \n \n WARNING! This plugin requires to use Memory Layer Saver plugin if you want to save labels with project. \n Plugin memory layer saver 2.0 or higher is needed because of new gml behaviour (GDAL 1.9) \n \n Please send bugs or features requests here : http://hub.qgis.org/projects/easycustomlabeling </strong>", None, QtGui.QApplication.UnicodeUTF8))
        try:
            QDesktopServices.openUrl(
                QUrl("https://github.com/haubourg/EasyCustomLabeling/wiki"))
        except:
            pass