From 7602a26251a853f70625f016056542b52cd86e0b Mon Sep 17 00:00:00 2001 From: patricev Date: Wed, 22 Mar 2017 09:51:07 +0100 Subject: [PATCH 1/8] working --- EasyCustomLabeling/EasyCustomLabeling.py | 897 ++++++------------ .../EasyCustomLabelingDialog.py | 40 +- .../EasyCustomLabeling_backup.py | 629 ++++++++++++ EasyCustomLabeling/__init__.py | 2 +- EasyCustomLabeling/default_label_style.qml | 304 ++++++ EasyCustomLabeling/labeledlayer/__init__.py | 0 .../labeledlayer/labeledlayer_pluginlayer.py | 714 ++++++++++++++ .../labeledlayer_pluginlayer_type.py | 44 + EasyCustomLabeling/metadata.txt | 15 +- EasyCustomLabeling/resources.py | 9 +- EasyCustomLabeling/test/test_ddproperties.py | 34 + EasyCustomLabeling/ui_EasyCustomLabeling.py | 39 +- EasyCustomLabeling/ui_EasyCustomLabeling.ui | 26 - 13 files changed, 2091 insertions(+), 662 deletions(-) create mode 100644 EasyCustomLabeling/EasyCustomLabeling_backup.py create mode 100644 EasyCustomLabeling/default_label_style.qml create mode 100644 EasyCustomLabeling/labeledlayer/__init__.py create mode 100644 EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py create mode 100644 EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer_type.py create mode 100644 EasyCustomLabeling/test/test_ddproperties.py diff --git a/EasyCustomLabeling/EasyCustomLabeling.py b/EasyCustomLabeling/EasyCustomLabeling.py index 67a3c46..0cba171 100644 --- a/EasyCustomLabeling/EasyCustomLabeling.py +++ b/EasyCustomLabeling/EasyCustomLabeling.py @@ -1,629 +1,328 @@ -# -*- coding: iso-8859-1 -*- -""" +# -*- coding: utf-8 -*- +""" /*************************************************************************** -Name :EasyCustomLabeling -Description : plugin allowing a quick duplication of layer, ready to start manual customisation of labels (position, size, colors.. ) based on data fields -Date : 23/01/204 -copyright : (C) 2013 by regis haubourg - Agence de l'eau Adour Garonne -version : 0.5 port to QGIS v2 API and new SIP version -email : regis dot haubourg at eau-adour-garonne.fr + PostTelemac + A QGIS plugin + Post Traitment or Telemac + ------------------- + begin : 2015-07-07 + git sha : $Format:%H$ + copyright : (C) 2015 by Artelia + email : patrice.Verchere@arteliagroup.com ***************************************************************************/ +""" + +#import QT +#from PyQt4 import QtCore ,QtGui +from qgis.PyQt import QtCore ,QtGui +#import qgis +import qgis +#Other standart libs import +import os.path +import time +import sys +import subprocess +#sys.path.append(os.path.join(os.path.dirname(__file__),'libs_telemac')) +#Posttelemac library import +#import .resources_rc + +from .labeledlayer.labeledlayer_pluginlayer import LabeledPluginLayer + +from .labeledlayer.labeledlayer_pluginlayer_type import LabeledLayerPluginLayerType +from . import resources +""" +from . import resources_rc + +from .meshlayer.post_telemac_pluginlayer import SelafinPluginLayer +from .meshlayer.post_telemac_pluginlayer_type import SelafinPluginLayerType +from .meshlayerdialogs.posttelemac_about import aboutDialog + +from .meshlayertools import utils + +#Processing +DOPROCESSING = False #set to false to make the plugin reloader work +if DOPROCESSING: + from processing.core.Processing import Processing + from posttelemacprovider.PostTelemacProvider import PostTelemacProvider + cmd_folder = os.path.split(inspect.getfile(inspect.currentframe()))[0] + if cmd_folder not in sys.path: + sys.path.insert(0, cmd_folder) + +""" + + +""" /*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * + +Main Class + ***************************************************************************/ """ -#Python ressources -import datetime -import resources -import os.path + + +class EasyCustomLabeling(QtCore.QObject): + """QGIS Plugin Implementation.""" -# Import the PyQt and QGIS libraries -from PyQt4 import QtGui -from PyQt4.QtCore import * -from PyQt4.QtGui import * -from qgis.core import * -from qgis.utils import * - -# Import the code for the dialog -from EasyCustomLabelingDialog import EasyCustomLabelingDialog - -# load translation libraries - -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() ) + def __init__(self, iface): + """Constructor. - 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): + :param iface: An interface instance that will be passed to this class + which provides the hook by which you can manipulate the QGIS + application at run time. + :type iface: QgsInterface + """ + + #*********************************************************************** + QtCore.QObject.__init__(self) #init from QObject parent + # Save reference to the QGIS interface + self.iface = iface + # initialize plugin directory + self.plugin_dir = os.path.dirname(__file__) + # initialize locale + locale = QtCore.QSettings().value('locale/userLocale')[0:2] + locale_path = os.path.join( + self.plugin_dir, + 'i18n', + 'EasyCustomLabeling_{}.qm'.format(locale)) + + if os.path.exists(locale_path): + #app=QApplication(['']) + self.translator = QtCore.QTranslator() + #self.translator = QTranslator(app) + self.translator.load(locale_path) + QtCore.QCoreApplication.installTranslator(self.translator) + """ + + if qVersion() > '4.3.3': + print 'ok' + QCoreApplication.installTranslator(self.translator) + #app.installTranslator(self.translator) + """ + #*********************************************************************** + + self.pluginLayerType = None + self.addToRegistry() + #self.slf=[] + self.lbllayer=[] + + # Declare instance attributes + self.actions = [] + self.menu = self.tr(u'&EasyCustomLabeling') + # TODO: We are going to let the user set this up in a future iteration + #toolbar + try: + from qgis.PyQt.QtGui import QToolBar + except: + from qgis.PyQt.QtWidgets import QToolBar + toolbars = self.iface.mainWindow().findChildren(QToolBar) + + test = True + for toolbar1 in toolbars: + if toolbar1.windowTitle() == u'mLabelToolBar': + self.toolbar = toolbar1 + test = False + break + if test: + self.toolbar = self.iface.addToolBar(u'mLabelToolBar') + self.toolbar.setObjectName(u'mLabelToolBar') + + #self.dlg_about = None + + #Processing + #if DOPROCESSING : self.provider = PostTelemacProvider() + - # 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 "" 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) + # noinspection PyMethodMayBeStatic + def tr(self, message): + """Get the translation for a string using Qt translation API. + We implement this ourselves since we do not inherit QObject. + :param message: String for translation. + :type message: str, QString + :returns: Translated version of message. + :rtype: QString + """ + # noinspection PyTypeChecker,PyArgumentList,PyCallByClass + return QtCore.QCoreApplication.translate('EasyCustomLabeling', message) + + + def add_action( + self, + icon_path, + text, + callback, + enabled_flag=True, + add_to_menu=True, + add_to_toolbar=True, + status_tip=None, + whats_this=None, + parent=None): + """Add a toolbar icon to the toolbar. + + :param icon_path: Path to the icon for this action. Can be a resource + path (e.g. ':/plugins/foo/bar.png') or a normal file system path. + :type icon_path: str + + :param text: Text that should be shown in menu items for this action. + :type text: str + + :param callback: Function to be called when the action is triggered. + :type callback: function + + :param enabled_flag: A flag indicating if the action should be enabled + by default. Defaults to True. + :type enabled_flag: bool + + :param add_to_menu: Flag indicating whether the action should also + be added to the menu. Defaults to True. + :type add_to_menu: bool + + :param add_to_toolbar: Flag indicating whether the action should also + be added to the toolbar. Defaults to True. + :type add_to_toolbar: bool + + :param status_tip: Optional text to show in a popup when mouse pointer + hovers over the action. + :type status_tip: str + + :param parent: Parent widget for the new action. Defaults None. + :type parent: QWidget + + :param whats_this: Optional text to show in the status bar when the + mouse pointer hovers over the action. + + :returns: The action that was created. Note that the action is also + added to self.actions list. + :rtype: QAction + """ + + icon = QtGui.QIcon(icon_path) + + try: + from qgis.PyQt.QtGui import QAction + except: + from qgis.PyQt.QtWidgets import QAction + + action = QAction(icon, text, parent) + action.triggered.connect(callback) + action.setEnabled(enabled_flag) + if status_tip is not None: + action.setStatusTip(status_tip) + + if whats_this is not None: + action.setWhatsThis(whats_this) - - - - - # @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 + if add_to_toolbar: + self.toolbar.addAction(action) - 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 add_to_menu: + self.iface.addPluginToMenu( + self.menu, + action) + self.actions.append(action) - - - - - 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() + return action + + def initGui(self): + """Create the menu entries and toolbar icons inside the QGIS GUI.""" + + icon_path = ':/plugins/EasyCustomLabeling/icon.png' + self.add_action( + icon_path, + text=self.tr(u'EasyCustomLabeling'), + callback=self.run, + parent=self.iface.mainWindow()) + """ + self.add_action( + icon_path, + text=self.tr(u'PostTelemac Help'), + add_to_toolbar=False, + callback=self.showHelp, + parent=self.iface.mainWindow()) + self.add_action( + icon_path, + text=self.tr(u'PostTelemac About'), + add_to_toolbar=False, + callback=self.showAbout, + parent=self.iface.mainWindow()) + """ - 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() + #Processing thing + #if DOPROCESSING : Processing.addProvider(self.provider) - feat = QgsFeature() + + + def unload(self): + """Removes the plugin menu item and icon from QGIS GUI.""" + for action in self.actions: + self.iface.removePluginMenu( + self.tr(u'&EasyCustomLabeling'), + action) + self.toolbar.removeAction(action) + # remove the toolbar + if len(self.toolbar.actions()) == 0 : + del self.toolbar + #if DOPROCESSING : Processing.removeProvider(self.provider) + + def run(self): - #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() + """Run method that performs all the real work""" + + activelayer = self.iface.activeLayer() + self.lbllayer.append(LabeledPluginLayer() ) #add selafin to list otherwise it can not work with multiple selafin files + success = self.lbllayer[-1].loadLabeledPluginLayer(activelayer) - # 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) + if success: + try: #qgis 2 + qgis.core.QgsMapLayerRegistry.instance().addMapLayer(self.lbllayer[-1]) + self.iface.setActiveLayer(activelayer) + except: #qgis 3 + qgis.core.QgsProject.instance().addMapLayer(self.lbllayer[-1]) - # 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 ) + """ + def showHelp(self): + if sys.platform == 'linux2': + subprocess.call(["xdg-open", 'https://github.com/ArteliaTelemac/PostTelemac/wiki']) + else: + os.startfile('https://github.com/ArteliaTelemac/PostTelemac/wiki') - # 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 ? - + def showAbout(self): + if not self.dlg_about: + self.dlg_about = aboutDialog() + self.dlg_about.setWindowModality(2) + r = self.dlg_about.exec_() + """ - ## 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(' 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 + #Specific functions + def addToRegistry(self): + #Add telemac_viewer in QgsPluginLayerRegistry + """ + if utils.getQgisVersion() < 2.20: + reg = qgis.core.QgsPluginLayerRegistry.instance() + else: + reg = qgis.core.QgsApplication.pluginLayerRegistry() + """ + #qgis.core.QgsPluginLayerRegistry.instance().pluginLayerTypes() - 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() + try: #qgis2 + reg = qgis.core.QgsPluginLayerRegistry.instance() + except: #qgis3 + reg = qgis.core.QgsApplication.pluginLayerRegistry() - #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", "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 ", None, QtGui.QApplication.UnicodeUTF8)) - try: - QDesktopServices.openUrl(QUrl("https://github.com/haubourg/EasyCustomLabeling/wiki")) - except: - pass - - + + if u'labeledlayer' in reg.pluginLayerTypes(): + reg.removePluginLayerType('labeledlayer') + self.pluginLayerType = LabeledLayerPluginLayerType() + reg.addPluginLayerType(self.pluginLayerType) + + \ No newline at end of file diff --git a/EasyCustomLabeling/EasyCustomLabelingDialog.py b/EasyCustomLabeling/EasyCustomLabelingDialog.py index 2f2930b..bfca973 100644 --- a/EasyCustomLabeling/EasyCustomLabelingDialog.py +++ b/EasyCustomLabeling/EasyCustomLabelingDialog.py @@ -28,23 +28,33 @@ * * ***************************************************************************/ """ - +""" from PyQt4.QtCore import * from PyQt4.QtGui import * +""" +from qgis.PyQt import QtCore, QtGui +try: #qt4 + from qgis.PyQt.QtGui import QDialog +except: #qt5 + from qgis.PyQt.QtWidgets import QDialog + from qgis.core import * -from ui_EasyCustomLabeling import Ui_EasyCustomLabeling +from .ui_EasyCustomLabeling import Ui_EasyCustomLabeling class EasyCustomLabelingDialog(QDialog, Ui_EasyCustomLabeling): - - def __init__(self, ldp): - QDialog.__init__(self) - # Set up the user interface from Designer. - self.setupUi(self) - - self.loadFields(ldp) - - def loadFields(self, ldp): - fields = ldp.fieldNameMap() - for fieldname, index in fields.iteritems(): - self.labelfield.addItem(fieldname) - \ No newline at end of file + + def __init__(self, ldp): + QDialog.__init__(self) + # Set up the user interface from Designer. + self.setupUi(self) + + self.loadFields(ldp) + + def loadFields(self, ldp): + fields = ldp.fieldNameMap() + """ + for fieldname, index in fields.iteritems(): + self.labelfield.addItem(fieldname) + """ + for fieldname, index in fields.items(): + self.labelfield.addItem(fieldname) \ No newline at end of file diff --git a/EasyCustomLabeling/EasyCustomLabeling_backup.py b/EasyCustomLabeling/EasyCustomLabeling_backup.py new file mode 100644 index 0000000..67a3c46 --- /dev/null +++ b/EasyCustomLabeling/EasyCustomLabeling_backup.py @@ -0,0 +1,629 @@ +# -*- coding: iso-8859-1 -*- +""" +/*************************************************************************** +Name :EasyCustomLabeling +Description : plugin allowing a quick duplication of layer, ready to start manual customisation of labels (position, size, colors.. ) based on data fields +Date : 23/01/204 +copyright : (C) 2013 by regis haubourg - Agence de l'eau Adour Garonne +version : 0.5 port to QGIS v2 API and new SIP version +email : regis dot haubourg at eau-adour-garonne.fr + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +""" +#Python ressources +import datetime +import resources +import os.path + +# Import the PyQt and QGIS libraries +from PyQt4 import QtGui +from PyQt4.QtCore import * +from PyQt4.QtGui import * +from qgis.core import * +from qgis.utils import * + +# Import the code for the dialog +from EasyCustomLabelingDialog import EasyCustomLabelingDialog + +# load translation libraries + +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 "" 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(' 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", "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 ", None, QtGui.QApplication.UnicodeUTF8)) + try: + QDesktopServices.openUrl(QUrl("https://github.com/haubourg/EasyCustomLabeling/wiki")) + except: + pass + + diff --git a/EasyCustomLabeling/__init__.py b/EasyCustomLabeling/__init__.py index 4c78d21..48a0071 100644 --- a/EasyCustomLabeling/__init__.py +++ b/EasyCustomLabeling/__init__.py @@ -18,5 +18,5 @@ This script initializes the plugin, making it known to QGIS. """ def classFactory(iface): - from EasyCustomLabeling import EasyCustomLabeling + from .EasyCustomLabeling import EasyCustomLabeling return EasyCustomLabeling(iface) diff --git a/EasyCustomLabeling/default_label_style.qml b/EasyCustomLabeling/default_label_style.qml new file mode 100644 index 0000000..fe981bb --- /dev/null +++ b/EasyCustomLabeling/default_label_style.qml @@ -0,0 +1,304 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 0 + Value + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + generatedlayout + + + + + + + + + 1 + diff --git a/EasyCustomLabeling/labeledlayer/__init__.py b/EasyCustomLabeling/labeledlayer/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py b/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py new file mode 100644 index 0000000..0722873 --- /dev/null +++ b/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py @@ -0,0 +1,714 @@ +# coding: utf-8 +""" +/*************************************************************************** + PostTelemac + A QGIS plugin + Post Traitment or Telemac + ------------------- + begin : 2015-07-07 + git sha : $Format:%H$ + copyright : (C) 2015 by Artelia + email : patrice.Verchere@arteliagroup.com + ***************************************************************************/ + + ***************************************************************************/ + Implementation of QgsPluginLayer class, used to show selafin res + + + ***************************************************************************/ +""" +#unicode behaviour +from __future__ import unicode_literals +#Standart import +import qgis +import qgis.core +import qgis.utils +#Qt +from qgis.PyQt import QtCore, QtGui +try: #qt4 + from qgis.PyQt.QtGui import QApplication, QMessageBox +except: #qt5 + from qgis.PyQt.QtWidgets import QApplication, QMessageBox + +# other import +import collections +import time +import gc +import os +import numpy as np +#plugin impport +from ..EasyCustomLabelingDialog import EasyCustomLabelingDialog + +class LabeledPluginLayer( qgis.core.QgsPluginLayer ): + """ + QgsPluginLayer implmentation for drawing selafin file results + + """ + LAYER_TYPE = "labeledlayer" + + + def __init__(self): + #qgis.core.QgsPluginLayer.__init__(self,'test') + qgis.core.QgsPluginLayer.__init__(self, LabeledPluginLayer.LAYER_TYPE,None) + self.prj = qgis.core.QgsProject.instance() + self.iface = qgis.utils.iface + self.pixelDistWithNoHeaderLine = 40 + self.pixelDistWithSimpleHeaderLine = 100 + + + self.labelFields = [ + #qgis.core.QgsField( "LblField", QtCore.QVariant.String, "varchar", 255), + qgis.core.QgsField( "LblX", QtCore.QVariant.Double, "numeric", 255) , + qgis.core.QgsField( "LblY", QtCore.QVariant.Double, "numeric", 255) , + qgis.core.QgsField( "LblAlignH", QtCore.QVariant.String, "varchar", 12), + qgis.core.QgsField( "LblAlignV", QtCore.QVariant.String, "varchar", 12), + qgis.core.QgsField( "LblSize", QtCore.QVariant.Int, "integer", 2 ), + qgis.core.QgsField( "LblRot", QtCore.QVariant.Double, "numeric", 10, 2), + qgis.core.QgsField( "LblBold", QtCore.QVariant.Int, "integer", 1), + qgis.core.QgsField( "LblItalic", QtCore.QVariant.Int, "integer", 1), + qgis.core.QgsField( "LblColor", QtCore.QVariant.String, "varchar", 7), + qgis.core.QgsField( "LblFont", QtCore.QVariant.String, "varchar", 64), + qgis.core.QgsField( "LblUnder", QtCore.QVariant.Int, "integer", 1), + qgis.core.QgsField( "LblStrike", QtCore.QVariant.Int, "integer", 1), + qgis.core.QgsField( "LblShow", QtCore.QVariant.Int, "integer", 1), + qgis.core.QgsField( "LblShowCO", QtCore.QVariant.Int, "integer", 1), + qgis.core.QgsField( "LblAShow", QtCore.QVariant.Int, "integer", 1) + ] + + self.labelfielddefaultvalue = {'LblShow' : 1, + 'LblSize' : 9, + 'LblAShow' : 1, + 'LblAlignV' : 'Half', + 'LblAlignH' : 'Center'} + + self.parent_layer_path = None + self.parentvectorlayer = None + + self.headerlinelayer = None + + #self.selectedObjects = [] + self.selectedObjectsIds = [] + self.fieldnametolabel = None + + + def loadLabeledPluginLayer(self,vectorlayer = None, parentlayeralreadychecked = False): + #check and add proper fields to parent layer + if not vectorlayer is None: + self.disconnectParentLayer() + + self.parentvectorlayer = vectorlayer + + try: #qgis2 + self.setLayerName(vectorlayer.name()+'_HeaderLineLabel') + except: #qgis3 + self.setName(vectorlayer.name()+'_HeaderLineLabel') + + + success = self.initParentLayer(parentlayeralreadychecked) + + if success: + + #create Header Line layer + self.resetHeaderLineLayer() + self.headerlinelayer.startEditing() + self.reinitHeaderLineLayer() + self.headerlinelayer.commitChanges() + + #connecting signals from parent layer - do connexion aftter parent layer check + self.connectParentLayer() + #otherwiwe it doesn't show + + self.setValid(True) + self.triggerRepaint() + + return True + else: + return False + else: + + try: + self.iface.messageBar().pushMessage("Error", QApplication.translate("EasyCustomLabeling", "There is no layer currently selected, \n please click on the vector layer you need to label", None, QApplication.UnicodeUTF8), level=0, duration=3) + except: + self.iface.messageBar().pushMessage("Error", QApplication.translate("EasyCustomLabeling", "There is no layer currently selected, \n please click on the vector layer you need to label", None), level=0, duration=3) + return False + + + + #******************************************************************************************************* + #**************************** connexions ******************************************* + #******************************************************************************************************* + + def connectParentLayer(self): + self.parentvectorlayer.attributeValueChanged.connect(self.attributeValueChanged) + self.parentvectorlayer.geometryChanged.connect(self.geometryChanged) + self.parentvectorlayer.featuresDeleted.connect(self.featuresDeleted) + self.parentvectorlayer.featureAdded.connect(self.featureAdded) + + def disconnectParentLayer(self): + try: + self.parentvectorlayer.attributeValueChanged.disconnect(self.attributeValueChanged) + self.parentvectorlayer.geometryChanged.disconnect(self.geometryChanged) + self.parentvectorlayer.featuresDeleted.disconnect(self.featuresDeleted) + self.parentvectorlayer.featureAdded.disconnect(self.featureAdded) + except: + pass + + + #******************************************************************************************************* + #**************************** Plugin Layer methods ******************************************* + #******************************************************************************************************* + + + def legendSymbologyItems(self, iconSize): + return [] + + def isValid(self): + return True + + def crs(self): + if not self.parentvectorlayer is None: + return self.parentvectorlayer.crs() + else: + return None + + def createMapRenderer(self,rendererContext): + if not self.headerlinelayer is None: + self.renderer = self.headerlinelayer.createMapRenderer(rendererContext) + else: + self.renderer = None + return self.renderer + + def dataProvider(self): + if not self.parentvectorlayer is None: + return self.parentvectorlayer.dataProvider() + else: + return None + + def extent(self): + if not self.parentvectorlayer is None: + return self.parentvectorlayer.extent() + else: + return None + + def name(self): + if not self.parentvectorlayer is None: + return self.parentvectorlayer.name()+'_HeaderLineLabel' + else: + return None + + def writeXml(self, node, doc): + """ + implementation of method from QgsMapLayer to save layer in qgsproject + return True ifsuccessful + """ + #prj = qgis.core.QgsProject.instance() + element = node.toElement() + element.setAttribute("type", "plugin") #must be written to work + element.setAttribute("name", LabeledPluginLayer.LAYER_TYPE) #must be written to work + element.setAttribute("parent_layer", os.path.normpath( self.parentvectorlayer.source() )) + element.setAttribute("labelfield", self.parentvectorlayer.customProperty("labeling/fieldName") ) + return True + + def readXml(self, node): + """ + implementation of method from QgsMapLayer to load layer from qgsproject + return True ifsuccessful + """ + + element = node.toElement() + self.parent_layer_path = self.prj.readPath( element.attribute('parent_layer') ) + self.fieldnametolabel = element.attribute('labelfield') + + if os.path.isfile(self.parent_layer_path) : + basename = os.path.basename(self.parent_layer_path).split('.') + if len(basename)>0: + basename = basename[0] + try: #qgis2 + layers = self.prj.mapLayers() + except: #qgis3 + layers = qgis.core.QgsMapLayerRegistry.instance().mapLayers().values() + layerfound = False + #check if parent layer is already loaded + for layer in layers: + if os.path.normpath(layer.source()) == os.path.normpath(self.parent_layer_path): + self.parentvectorlayer = layer + layerfound = True + break + + if not layerfound: #if not found, wait a temp layer and activate readMapLayer signal when the parent layer will be loaded + self.parentvectorlayer = qgis.core.QgsVectorLayer(self.parent_layer_path,basename,"ogr") + self.loadLabeledPluginLayer(self.parentvectorlayer,True) + self.prj.readMapLayer.connect(self.layerAddedtoProject) + return True + else: #if parent layer is found + self.loadLabeledPluginLayer(self.parentvectorlayer,True) + return True + + else: + return False + + def layerAddedtoProject(self, layer,node ): + if isinstance(layer, qgis.core.QgsVectorLayer): + if not self.parent_layer_path is None and os.path.normpath(layer.source()) == os.path.normpath(self.parent_layer_path): + self.parentvectorlayer = layer + self.loadLabeledPluginLayer(self.parentvectorlayer,True) + self.prj.readMapLayer.disconnect(self.layerAddedtoProject) + + #******************************************************************************************************* + #**************************** Parent Layer initialization ******************************************* + #******************************************************************************************************* + + + def initParentLayer(self,parentlayeralreadychecked = False): + # + #Layer to be labeled (called parentlayer) validity check and fields creation + #Return True if operation successfull (parent layer checked, parent layer initialized) + # + + if self.checkParentLayer(parentlayeralreadychecked): #also disconnect parent layer + + + parentlayerfields = self.parentvectorlayer.fields() + parenlayerfieldname = [field.name() for field in parentlayerfields] + #create fields + for field in self.labelFields: + if not field.name() in parenlayerfieldname: + parentpr = self.parentvectorlayer.dataProvider() + self.parentvectorlayer.startEditing() + parentpr.addAttributes([field ]) + self.parentvectorlayer.updateFields() + self.parentvectorlayer.commitChanges() + + #assin default values + self.parentvectorlayer.startEditing() + for feature in self.parentvectorlayer.getFeatures(): + for key, value in self.labelfielddefaultvalue.items(): + if int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 4 : #qgis2 + if isinstance(feature[key],QtCore.QPyNullVariant) or feature[key] is None : + self.parentvectorlayer.changeAttributeValue(feature.id(),self.parentvectorlayer.fields().indexFromName(key), value) + elif int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 5 : #qgis3 + if isinstance(feature[key],QtCore.QVariant) or feature[key] is None : + self.parentvectorlayer.changeAttributeValue(feature.id(),self.parentvectorlayer.fields().indexFromName(key), value) + if len(self.selectedObjectsIds)>0: + if feature.id() in self.selectedObjectsIds: + self.parentvectorlayer.changeAttributeValue(feature.id(),self.parentvectorlayer.fields().indexFromName("LblShow"), 1) + else: + self.parentvectorlayer.changeAttributeValue(feature.id(),self.parentvectorlayer.fields().indexFromName("LblShow"), 0) + self.parentvectorlayer.commitChanges() + + + + + # #generic labeling properties + self.parentvectorlayer.setCustomProperty("labeling/fieldName", self.fieldnametolabel ) # TODO replace default value with dialog input + self.parentvectorlayer.setCustomProperty("labeling","pal" ) # new gen labeling activated + self.parentvectorlayer.setCustomProperty("labeling/fontSize","8" ) # default value + self.parentvectorlayer.setCustomProperty("labeling/multiLineLabels","true" ) # default value + self.parentvectorlayer.setCustomProperty("labeling/enabled","true" ) # default value + #self.parentvectorlayer.setCustomProperty("labeling/displayAll", "true") # force all labels to display + self.parentvectorlayer.setCustomProperty("labeling/priority", "10") # puts a high priority to labeling layer + self.parentvectorlayer.setCustomProperty("labeling/multilineAlign","1") # multiline align to center + #self.parentvectorlayer.setCustomProperty("labeling/wrapChar", "%") # multiline break symbol + + #line properties case + self.parentvectorlayer.setCustomProperty("labeling/placement","4" ) + + + #assign data defined properties + if int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 4 : #qgis2 + # #data defined properties + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/PositionX", "1~~0~~~~LblX") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/PositionY", "1~~0~~~~LblY") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Hali", "1~~0~~~~LblAlignH") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Vali","1~~0~~~~LblAlignV") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Size" ,"1~~0~~~~LblSize") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Rotation" ,"1~~0~~~~LblRot" ) + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Bold" , "1~~0~~~~LblBold") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Italic" ,"1~~0~~~~LblItalic") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Underline" ,"1~~0~~~~LblUnder") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Strikeout" ,"1~~0~~~~LblStrike") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Color" ,"1~~0~~~~LblColor") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Family" ,"1~~0~~~~LblFont") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Show", "1~~0~~~~LblShow") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/AlwaysShow", "1~~0~~~~LblAShow") + + elif int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 5 : #qgis3 + self.parentvectorlayer.setCustomProperty("labeling/ddProperties", + '\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + ') + + + self.connectParentLayer() + + return True + else: + return False + + + + def checkParentLayer(self,skipchecking = False): + # + #perform control on parent layer + #Return True if checking sucessfull (no aborting, evrything ok) + # + + self.disconnectParentLayer() + + if not skipchecking : #first time loading + + sourceLayer = self.parentvectorlayer + + if not sourceLayer.type() == sourceLayer.VectorLayer: + try: + self.iface.messageBar().pushMessage("Error", QApplication.translate("EasyCustomLabeling", "Current active layer is not a vector layer. \n Please click on the vector layer you need to label", None, QApplication.UnicodeUTF8), level=0, duration=3) + except: + self.iface.messageBar().pushMessage("Error", QApplication.translate("EasyCustomLabeling", "Current active layer is not a vector layer. \n Please click on the vector layer you need to label", None), level=0, duration=3) + return False + + + # detect if selection exists on that layer + nbSelectedObjects = sourceLayer.selectedFeatureCount() + self.selectedObjectsIds = [] + ret = 0 + if not nbSelectedObjects == 0 : + #dialog to ask if user wants to use current selection or not + msgBox = QMessageBox() + msgBox.setIcon(QMessageBox.Question) + msgBox.setWindowTitle ("EasyCustomLabeling") + try: + msgBox.setText(QApplication.translate("EasyCustomLabeling", "Use %n selected object(s) only for labeling ?" , None, QApplication.UnicodeUTF8, nbSelectedObjects)) + except: + msgBox.setText(QApplication.translate("EasyCustomLabeling", "Use %n selected object(s) only for labeling ?" , None, 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 False + elif ret == 65536 : # No button65536 use entire layer + pass + #print('use entire layer') + elif ret == 16384 : + print('use selection') + self.selectedObjectsIds = [fet.id() for fet in sourceLayer.selectedFeatures()] + + + #nbSelectedObjects = sourceLayer.selectedFeatureCount() + + + if sourceLayer.selectedFeatureCount() > 500 : #alert if many objects selected + + msgBox = QMessageBox() + try: + msgBox.setText(QApplication.translate("EasyCustomLabeling","Your layer contains many objects. Continue anyway?", None, QApplication.UnicodeUTF8)) + except: + msgBox.setText(QApplication.translate("EasyCustomLabeling","Your layer contains many objects. Continue anyway?", None)) + 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 False + + + + #asks for default field to use as labeling (thanks to Victor Axbom Layer to labeled layer plugin) + # create the dialog + self.dlg = EasyCustomLabelingDialog(sourceLayer.dataProvider()) + ret_dlg_field = self.dlg.exec_() + #cancels if user cancels dialog: + if ret_dlg_field == 0 : + return False + + self.fieldnametolabel = self.dlg.labelfield.currentText() + # show the dialog + # if self.dlg.exec_(): + # return True# print 'dialog execution' + # else : + # return + + # self.iface.mapCanvas().refresh() + # returns self.dlg.labelfield.currentText() + + + #self.selectedObjects = sourceLayer.selectedFeatures() + return True + + else: + + return True + + + + #******************************************************************************************************* + #**************************** Header Line Layer methods ******************************************* + #******************************************************************************************************* + + + def resetHeaderLineLayer(self): + # + # header line layer creation + # + if not self.parentvectorlayer is None: + type = "LineString?crs="+str(self.parentvectorlayer.crs().authid()) + name='temp' + self.headerlinelayer = qgis.core.QgsVectorLayer(type, name, "memory") + self.pr = self.headerlinelayer.dataProvider() + self.headerlinelayer.startEditing() + # add fields + self.pr.addAttributes([qgis.core.QgsField("Value", QtCore.QVariant.Double) ]) + self.headerlinelayer.updateFields() + pathpointvelocityqml = os.path.join(os.path.dirname(__file__), '..','default_label_style.qml') + self.headerlinelayer.loadNamedStyle(pathpointvelocityqml) + else: + self.headerlinelayer = None + + + + + def attributeValueChanged(self,FeatureId , idx , variant): + # + #When label position is changed + # + + DEBUG = False + + if DEBUG : print('attributeValueChanged') + + if self.parentvectorlayer.fields()[idx].name() in ['LblX','LblY']: + + if DEBUG : print('attributeValueChanged', FeatureId,idx, variant) + + self.parentvectorlayer.startEditing() + self.headerlinelayer.startEditing() + + self.disconnectParentLayer() + + fet = qgis.core.QgsFeature() + if self.parentvectorlayer.getFeatures(qgis.core.QgsFeatureRequest().setFilterFid(FeatureId)).nextFeature(fet): + if DEBUG : print('ids',[fett.id() for fett in self.headerlinelayer.getFeatures()], [fett.id() for fett in self.parentvectorlayer.getFeatures()]) + if isinstance(fet['LblX'], float) and isinstance(fet['LblY'], float) : + fettemp = qgis.core.QgsFeature() + if self.headerlinelayer.getFeatures(qgis.core.QgsFeatureRequest().setFilterFid(FeatureId + 1)).nextFeature(fettemp): #memory layer id start at 1 ... + if DEBUG : print('case2 ok') + self.adjustFeature(fet, fettemp,update = True) + self.headerlinelayer.commitChanges() + self.triggerRepaint() + self.connectParentLayer() + + if self.parentvectorlayer.fields()[idx].name() in ['LblShow']: + self.headerlinelayer.startEditing() + fet = qgis.core.QgsFeature() + if self.parentvectorlayer.getFeatures(qgis.core.QgsFeatureRequest().setFilterFid(FeatureId)).nextFeature(fet): + fettemp = qgis.core.QgsFeature() + if self.headerlinelayer.getFeatures(qgis.core.QgsFeatureRequest().setFilterFid(FeatureId + 1)).nextFeature(fettemp): #memory layer id start at 1 ... + self.adjustFeature(fet, fettemp,update = True) + self.headerlinelayer.commitChanges() + self.triggerRepaint() + + + def featuresDeleted(self,list): + # + #When parent layer feature is deleted + # + DEBUG = False + self.disconnectParentLayer() + self.headerlinelayer.startEditing() + if DEBUG : print('featuresDeleted', list) + self.reinitHeaderLineLayer() + self.triggerRepaint() + self.headerlinelayer.commitChanges() + self.connectParentLayer() + + def featureAdded(self,FeatureId): + # + #When parent layer feature is added + # + DEBUG = False + self.disconnectParentLayer() + self.headerlinelayer.startEditing() + if DEBUG : print('featureAdded', FeatureId) + + if int(FeatureId)<0: #while editing - create proper fields + fet = qgis.core.QgsFeature() + if self.parentvectorlayer.getFeatures(qgis.core.QgsFeatureRequest().setFilterFid(FeatureId)).nextFeature(fet): + if DEBUG : print('while editing ok') + self.checkDefaultFieldValue(fet) + + if int(FeatureId)>0: #editing finished - create header line + self.reinitHeaderLineLayer() + self.headerlinelayer.commitChanges() + self.connectParentLayer() + + + def geometryChanged(self,FeatureId,geom): + # + #When parent layer geometry is changed + # + self.disconnectParentLayer() + self.headerlinelayer.startEditing() + DEBUG = False + if DEBUG : print('geometryChanged', FeatureId,geom) + fet = qgis.core.QgsFeature() + if self.parentvectorlayer.getFeatures(qgis.core.QgsFeatureRequest().setFilterFid(FeatureId)).nextFeature(fet): + if DEBUG : print('ids',[fett.id() for fett in self.headerlinelayer.getFeatures()], [fett.id() for fett in self.parentvectorlayer.getFeatures()]) + if isinstance(fet['LblX'], float) and isinstance(fet['LblY'], float) : + fettemp = qgis.core.QgsFeature() + if self.headerlinelayer.getFeatures(qgis.core.QgsFeatureRequest().setFilterFid(FeatureId + 1)).nextFeature(fettemp): #memory layer id start at 1 ... + if DEBUG : print('case2 ok') + self.adjustFeature(fet, fettemp,update = True) + self.headerlinelayer.commitChanges() + self.triggerRepaint() + self.connectParentLayer() + + + + + def reinitHeaderLineLayer(self): + # + #recreate an header line layer + # + + DEBUG = False + if DEBUG : print('case1') + + if not self.parentvectorlayer is None: + + parentlayereditmode = self.parentvectorlayer.isEditable() + + self.parentvectorlayer.startEditing() + self.resetHeaderLineLayer() + for fet in self.parentvectorlayer.getFeatures(): + if fet.id()>=0: + self.checkDefaultFieldValue(fet) + fettemp = qgis.core.QgsFeature(self.headerlinelayer.fields()) + if isinstance(fet['LblX'], float) and isinstance(fet['LblY'], float) : + self.adjustFeature(fet, fettemp) + self.pr.addFeatures([fettemp]) + if DEBUG : print('ids after ',[fett.id() for fett in self.headerlinelayer.getFeatures()], [fett.id() for fett in self.parentvectorlayer.getFeatures()]) + #self.triggerRepaint() + #self.parentvectorlayer.commitChanges() + """ + if parentlayereditmode : + self.parentvectorlayer.commitChanges() + self.parentvectorlayer.startEditing() + else: + self.parentvectorlayer.commitChanges() + """ + + def checkDefaultFieldValue(self,feature): + # + #On feature creation in parent layer, check for default fields + # + for key, value in self.labelfielddefaultvalue.items(): + if int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 4 : #qgis2 + if isinstance(feature[key],QtCore.QPyNullVariant) or feature[key] is None : + self.parentvectorlayer.changeAttributeValue(feature.id(),self.parentvectorlayer.fields().indexFromName(key), value) + elif int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 5 : #qgis3 + if isinstance(feature[key],QtCore.QVariant) or feature[key] is None : + self.parentvectorlayer.changeAttributeValue(feature.id(),self.parentvectorlayer.fields().indexFromName(key), value) + + + + + #******************************************************************************************************* + #**************************** Header Line Layer core methods ********************************* + #******************************************************************************************************* + + def adjustFeature(self,parentfet, labelfet, update = False): + # + #header line creation process - parent layer and headerlinelayer must be on editing mode + # + + #compute new header line geom + + if parentfet["LblShow"] and isinstance(parentfet['LblX'], float) and isinstance(parentfet['LblY'], float) : + pointlabel = qgis.core.QgsPoint(parentfet['LblX'],parentfet['LblY']) + #ending point of header line + if parentfet.geometry().type() == 0 : #point 0 : point 1 : line 2 : polygon + pointfeature = parentfet.geometry().asPoint() + + elif parentfet.geometry().type() == 1 : #point 0 : point 1 : line 2 : polygon + parentgeom = qgis.core.QgsGeometry(parentfet.geometry()) + parentgeom.convertToSingleType() + pointfeature = parentgeom.interpolate(.5 * parentgeom.length()).asPoint() #point in he middle of polyline + templine = qgis.core.QgsGeometry.fromPolyline([pointlabel,pointfeature]) + if templine.intersects(parentfet.geometry()): + intersect = templine.intersection(parentfet.geometry()) + if len(intersect.asMultiPoint())==0: #single point + pointfeature = intersect.asPoint() + else: #mulilines + #pass + intersect.convertToSingleType() + pointfeature = intersect.asPoint() + + elif parentfet.geometry().type() == 2 : #point 0 : point 1 : line 2 : polygon + pointfeature = parentfet.geometry().centroid().asPoint() + templine = qgis.core.QgsGeometry.fromPolyline([pointlabel,pointfeature]) + if templine.intersects(parentfet.geometry()): + intersect = templine.intersection(parentfet.geometry()) + if len(intersect.asMultiPolyline())==0: #singleline + pointfeature = intersect.interpolate(.25 * intersect.length()).asPoint() + else: #mulilines + #pass + intersect.convertToSingleType() + pointfeature = intersect.interpolate(.25 * intersect.length()).asPoint() + + + newgeom = self.generateHeaderLine(pointlabel, pointfeature) + + if pointlabel.x()= 3.2 to restore all labels correctly description[fr]=Permet de rapidement une couche dédiée à l'étiquetage personnalisé. Nécessite Memory layer Saver >= 3.2 pour sauver les couches d'étiquetage avec le projet. -version=1.3.4 +version=2.0.0 about=EasyCustomLabeling is a plugin for QGIS, designed to simplify the work for manual and data defined labeling. The tool duplicates a data vector layer into a new memory layer made of lines, adds all necessary fields for advanced custom labeling like label location, rotation, color, font, callout, alignements. The resulting layer is activated ready to use labeling tools. Data is saved in Memory Layer provider, which means it is NOT saved to a file or a database. To make thoses layers persistent, please install Memory Layer Saver v3.2 or higher plugin, that saves all memory layers to a qdatastream file along the project named myqgisprojectname.qgs.mldata. about[fr]=EasyCustomLabeling est une extension développée pour simplifer le travail d'étiquetage personnalisé et basé sur des champs de données. Cet outil duplique une couche vecteur dans une couche mémoire de lignes, et y ajoute tous les champs nécessaires pour l'étiquetage personnalisé (emplacement de l'étiquette, rotation, couleur, police, alignements...). La couche résultante est prête à être modifiée directement (éditable et outils d'étiquetages activés). Les données sont sauvées en mémoire, ce qui signifie qu'elles ne sont PAS sauvées dans un fichier ou une base. Pour sauver ces données et pouvoir réouvrir un projet avec les étiquettes, il faut installer l'extension Memory Layer Saver (v >=3.2), qui sauve toutes les couches mémoires dans un fichier Qdatastream (fichier: projet_qgis.qgs.mldata) changelog= - 1.3.4: use new style signal-slot. The issue was that the action was never activated on some machine without error or warning messages for the user. Funded by IT QGIS User Group. https://github.com/haubourg/EasyCustomLabeling/pull/11 - 1.3.3: solves error in labeling reconnection on project loads..again + 2.0.0 : QGis 3.0 compatible + 1.3.4: use new style signal-slot. The issue was that the action was never activated on some machine without error or warning messages for the user. Funded by IT QGIS User Group. https://github.com/haubourg/EasyCustomLabeling/pull/11 + 1.3.3: solves error in labeling reconnection on project loads..again 1.3.2: workaround label layer detection that causes label to be not in sync with callouts after project reloading 1.3.1: cosmetic settings for Horizontal alignement centered if deltaX is under tolerance stops when users cancels in dialog for field's choice @@ -42,8 +44,9 @@ changelog= - Miss an option to choose datasource format to save layer - Callouts can only be modified in the session where labeling layer was created changelog[fr]= - 1.3.4: Corrige certains cas d'erreurs liés à une méthode obsolète. financé par le QGIS user Group Italien. https://github.com/haubourg/EasyCustomLabeling/pull/11 - 1.3.3: corrige des soucis de reconnection de flèches au chargement du projet.. de nouveau + 2.0.0 : QGis 3.0 compatible + 1.3.4: Corrige certains cas d'erreurs liés à une méthode obsolète. financé par le QGIS user Group Italien. https://github.com/haubourg/EasyCustomLabeling/pull/11 + 1.3.3: corrige des soucis de reconnection de flèches au chargement du projet.. de nouveau 1.3.2: Contournement du bug de mauvaise reconnection des connecteurs d'étiquettes au chargement du projet 1.3.1: - Amélioration du centrage des étiquettes lorsqu'elle sont déplacées de moins de 2cm - réactive l'annulation dans le dialogue de choix de champ diff --git a/EasyCustomLabeling/resources.py b/EasyCustomLabeling/resources.py index d300295..7f363f7 100644 --- a/EasyCustomLabeling/resources.py +++ b/EasyCustomLabeling/resources.py @@ -7,9 +7,10 @@ # # WARNING! All changes made in this file will be lost! -from PyQt4 import QtCore +#from PyQt4 import QtCore +from qgis.PyQt import QtCore, QtGui -qt_resource_data = "\ +qt_resource_data = b"\ \x00\x00\x05\xe4\ \x89\ \x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ @@ -207,7 +208,7 @@ \xa9\x47\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\ " -qt_resource_name = "\ +qt_resource_name = b"\ \x00\x07\ \x07\x3b\xe0\xb3\ \x00\x70\ @@ -227,7 +228,7 @@ \x00\x72\x00\x72\x00\x6f\x00\x77\x00\x2e\x00\x70\x00\x6e\x00\x67\ " -qt_resource_struct = "\ +qt_resource_struct = b"\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ \x00\x00\x00\x14\x00\x02\x00\x00\x00\x02\x00\x00\x00\x03\ diff --git a/EasyCustomLabeling/test/test_ddproperties.py b/EasyCustomLabeling/test/test_ddproperties.py new file mode 100644 index 0000000..447e30f --- /dev/null +++ b/EasyCustomLabeling/test/test_ddproperties.py @@ -0,0 +1,34 @@ +import qgis +import xml.etree.ElementTree as ET +import xml + +vl = iface.activeLayer() + +prop = vl.customProperty("labeling/ddProperties") + +#print(prop,type(prop)) + +tree = ET.ElementTree(ET.fromstring(prop)) +root = tree.getroot() +print(prop) +temp = root[0][1][0] +print(temp.attrib) +print(temp[0].attrib) +print(temp[1].attrib) +print(temp[2].attrib) + +print(root[0],len(root[0])) + + + +"""for elem in tree.iter(): + #print(elem.tag, elem.attrib) + if 'name' in elem.attrib.keys(): + if elem.attrib['name'] == 'PositionX': + changexactive = True + #print(elem.attrib['value']) + #elem.attrib['value'] = '2' +""" + +#print(xml.etree.ElementTree.tostring(root, encoding='utf8', method='xml')) +#print(xml.etree.ElementTree.tostring(root)) \ No newline at end of file diff --git a/EasyCustomLabeling/ui_EasyCustomLabeling.py b/EasyCustomLabeling/ui_EasyCustomLabeling.py index b9d13e0..68dc0d0 100644 --- a/EasyCustomLabeling/ui_EasyCustomLabeling.py +++ b/EasyCustomLabeling/ui_EasyCustomLabeling.py @@ -7,7 +7,13 @@ # # WARNING! All changes made in this file will be lost! -from PyQt4 import QtCore, QtGui +#from PyQt4 import QtCore, QtGui + +from qgis.PyQt import QtCore, QtGui +try: #qt4 + from qgis.PyQt.QtGui import QDialog, QDialogButtonBox, QSplitter, QLabel, QComboBox, QApplication +except: #qt5 + from qgis.PyQt.QtWidgets import QDialog, QDialogButtonBox, QSplitter, QLabel, QComboBox, QApplication try: _fromUtf8 = QtCore.QString.fromUtf8 @@ -24,20 +30,20 @@ def setupUi(self, EasyCustomLabeling): EasyCustomLabeling.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) EasyCustomLabeling.setSizeGripEnabled(True) EasyCustomLabeling.setModal(True) - self.buttonBox = QtGui.QDialogButtonBox(EasyCustomLabeling) + self.buttonBox = QDialogButtonBox(EasyCustomLabeling) self.buttonBox.setGeometry(QtCore.QRect(100, 100, 191, 23)) - self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) + self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok) self.buttonBox.setObjectName(_fromUtf8("buttonBox")) - self.splitter = QtGui.QSplitter(EasyCustomLabeling) + self.splitter = QSplitter(EasyCustomLabeling) self.splitter.setGeometry(QtCore.QRect(20, 20, 261, 20)) self.splitter.setOrientation(QtCore.Qt.Horizontal) self.splitter.setObjectName(_fromUtf8("splitter")) - self.label = QtGui.QLabel(self.splitter) + self.label = QLabel(self.splitter) self.label.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) self.label.setObjectName(_fromUtf8("label")) - self.labelfield = QtGui.QComboBox(self.splitter) + self.labelfield = QComboBox(self.splitter) self.labelfield.setObjectName(_fromUtf8("labelfield")) - self.label_2 = QtGui.QLabel(EasyCustomLabeling) + self.label_2 = QLabel(EasyCustomLabeling) self.label_2.setGeometry(QtCore.QRect(10, 60, 301, 21)) font = QtGui.QFont() font.setFamily(_fromUtf8("Arial")) @@ -49,13 +55,24 @@ def setupUi(self, EasyCustomLabeling): self.label_2.setObjectName(_fromUtf8("label_2")) self.retranslateUi(EasyCustomLabeling) + """ QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), EasyCustomLabeling.accept) QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), EasyCustomLabeling.reject) + """ + self.buttonBox.accepted.connect(EasyCustomLabeling.accept) + self.buttonBox.rejected.connect(EasyCustomLabeling.reject) + QtCore.QMetaObject.connectSlotsByName(EasyCustomLabeling) def retranslateUi(self, EasyCustomLabeling): - EasyCustomLabeling.setWindowTitle(QtGui.QApplication.translate("EasyCustomLabeling", "EasyCustomLabeling", None, QtGui.QApplication.UnicodeUTF8)) - EasyCustomLabeling.setToolTip(QtGui.QApplication.translate("EasyCustomLabeling", "Choose labeling field", None, QtGui.QApplication.UnicodeUTF8)) - self.label.setText(QtGui.QApplication.translate("EasyCustomLabeling", "Label field", None, QtGui.QApplication.UnicodeUTF8)) - self.label_2.setText(QtGui.QApplication.translate("EasyCustomLabeling", "Note: Chosen labeling field is copied in LblField. ", None, QtGui.QApplication.UnicodeUTF8)) + try: #qgis2 + EasyCustomLabeling.setWindowTitle(QApplication.translate("EasyCustomLabeling", "EasyCustomLabeling", None, QApplication.UnicodeUTF8)) + EasyCustomLabeling.setToolTip(QApplication.translate("EasyCustomLabeling", "Choose labeling field", None, QApplication.UnicodeUTF8)) + self.label.setText(QApplication.translate("EasyCustomLabeling", "Label field", None, QApplication.UnicodeUTF8)) + self.label_2.setText(QApplication.translate("EasyCustomLabeling", "Note: Chosen labeling field is copied in LblField. ", None, QApplication.UnicodeUTF8)) + except: + EasyCustomLabeling.setWindowTitle(QApplication.translate("EasyCustomLabeling", "EasyCustomLabeling", None)) + EasyCustomLabeling.setToolTip(QApplication.translate("EasyCustomLabeling", "Choose labeling field", None)) + self.label.setText(QApplication.translate("EasyCustomLabeling", "Label field", None)) + self.label_2.setText(QApplication.translate("EasyCustomLabeling", "Note: Chosen labeling field is copied in LblField. ", None)) diff --git a/EasyCustomLabeling/ui_EasyCustomLabeling.ui b/EasyCustomLabeling/ui_EasyCustomLabeling.ui index 33438cc..92a1b4a 100644 --- a/EasyCustomLabeling/ui_EasyCustomLabeling.ui +++ b/EasyCustomLabeling/ui_EasyCustomLabeling.ui @@ -75,32 +75,6 @@ - - - - 10 - 60 - 301 - 21 - - - - - Arial - 10 - true - - - - Note: Chosen labeling field is copied in LblField. - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - From bf8d66f21673e357f7c54e9c6eba10a5ffaf8ed9 Mon Sep 17 00:00:00 2001 From: patricev Date: Wed, 22 Mar 2017 11:37:15 +0100 Subject: [PATCH 2/8] working --- EasyCustomLabeling/EasyCustomLabeling.py | 2 +- .../labeledlayer/labeledlayer_pluginlayer.py | 85 ++++++++++++++++--- 2 files changed, 75 insertions(+), 12 deletions(-) diff --git a/EasyCustomLabeling/EasyCustomLabeling.py b/EasyCustomLabeling/EasyCustomLabeling.py index 0cba171..e90e42b 100644 --- a/EasyCustomLabeling/EasyCustomLabeling.py +++ b/EasyCustomLabeling/EasyCustomLabeling.py @@ -282,7 +282,7 @@ def run(self): self.iface.setActiveLayer(activelayer) except: #qgis 3 qgis.core.QgsProject.instance().addMapLayer(self.lbllayer[-1]) - + self.iface.setActiveLayer(activelayer) diff --git a/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py b/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py index 0722873..2eab784 100644 --- a/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py +++ b/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py @@ -52,14 +52,14 @@ def __init__(self): qgis.core.QgsPluginLayer.__init__(self, LabeledPluginLayer.LAYER_TYPE,None) self.prj = qgis.core.QgsProject.instance() self.iface = qgis.utils.iface - self.pixelDistWithNoHeaderLine = 40 - self.pixelDistWithSimpleHeaderLine = 100 + self.pixelDistWithNoHeaderLine = 1 #distance in centimeters on map canvas when header line is not shown + self.pixelDistWithSimpleHeaderLine = 3 #distance in centimeters on map canvas when header line is simple (else double headerline) self.labelFields = [ #qgis.core.QgsField( "LblField", QtCore.QVariant.String, "varchar", 255), - qgis.core.QgsField( "LblX", QtCore.QVariant.Double, "numeric", 255) , - qgis.core.QgsField( "LblY", QtCore.QVariant.Double, "numeric", 255) , + qgis.core.QgsField( "LblX", QtCore.QVariant.Double, "numeric", 20,10) , + qgis.core.QgsField( "LblY", QtCore.QVariant.Double, "numeric", 20,10) , qgis.core.QgsField( "LblAlignH", QtCore.QVariant.String, "varchar", 12), qgis.core.QgsField( "LblAlignV", QtCore.QVariant.String, "varchar", 12), qgis.core.QgsField( "LblSize", QtCore.QVariant.Int, "integer", 2 ), @@ -72,7 +72,8 @@ def __init__(self): qgis.core.QgsField( "LblStrike", QtCore.QVariant.Int, "integer", 1), qgis.core.QgsField( "LblShow", QtCore.QVariant.Int, "integer", 1), qgis.core.QgsField( "LblShowCO", QtCore.QVariant.Int, "integer", 1), - qgis.core.QgsField( "LblAShow", QtCore.QVariant.Int, "integer", 1) + qgis.core.QgsField( "LblAShow", QtCore.QVariant.Int, "integer", 1), + qgis.core.QgsField( "LblScale", QtCore.QVariant.Double, "numeric", 255) ] self.labelfielddefaultvalue = {'LblShow' : 1, @@ -117,9 +118,10 @@ def loadLabeledPluginLayer(self,vectorlayer = None, parentlayeralreadychecked = #connecting signals from parent layer - do connexion aftter parent layer check self.connectParentLayer() #otherwiwe it doesn't show - + self.parentvectorlayer.commitChanges() self.setValid(True) self.triggerRepaint() + self.iface.setActiveLayer(self.parentvectorlayer) return True else: @@ -143,6 +145,12 @@ def connectParentLayer(self): self.parentvectorlayer.geometryChanged.connect(self.geometryChanged) self.parentvectorlayer.featuresDeleted.connect(self.featuresDeleted) self.parentvectorlayer.featureAdded.connect(self.featureAdded) + if False: #not working + if int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 4 : #qgis2 + self.parentvectorlayer.layerDeleted.connect(self.removeHeaderLineLayer) + if int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 5 : #qgis3 + self.parentvectorlayer.willBeDeleted.connect(self.removeHeaderLineLayer) + def disconnectParentLayer(self): try: @@ -150,6 +158,12 @@ def disconnectParentLayer(self): self.parentvectorlayer.geometryChanged.disconnect(self.geometryChanged) self.parentvectorlayer.featuresDeleted.disconnect(self.featuresDeleted) self.parentvectorlayer.featureAdded.disconnect(self.featureAdded) + if False: #not working + if int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 4 : #qgis2 + self.parentvectorlayer.layerDeleted.disconnect(self.removeHeaderLineLayer) + if int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 5 : #qgis3 + self.parentvectorlayer.willBeDeleted.disconnect(self.removeHeaderLineLayer) + except: pass @@ -253,6 +267,8 @@ def layerAddedtoProject(self, layer,node ): self.parentvectorlayer = layer self.loadLabeledPluginLayer(self.parentvectorlayer,True) self.prj.readMapLayer.disconnect(self.layerAddedtoProject) + + #******************************************************************************************************* #**************************** Parent Layer initialization ******************************************* @@ -309,6 +325,9 @@ def initParentLayer(self,parentlayeralreadychecked = False): self.parentvectorlayer.setCustomProperty("labeling/priority", "10") # puts a high priority to labeling layer self.parentvectorlayer.setCustomProperty("labeling/multilineAlign","1") # multiline align to center #self.parentvectorlayer.setCustomProperty("labeling/wrapChar", "%") # multiline break symbol + + self.parentvectorlayer.setCustomProperty("labeling/drawLabels","true" ) # default value + self.parentvectorlayer.setCustomProperty("labeling/isExpression","false" ) # default value #line properties case self.parentvectorlayer.setCustomProperty("labeling/placement","4" ) @@ -333,6 +352,7 @@ def initParentLayer(self,parentlayeralreadychecked = False): self.parentvectorlayer.setCustomProperty("labeling/dataDefined/AlwaysShow", "1~~0~~~~LblAShow") elif int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 5 : #qgis3 + # #data defined properties self.parentvectorlayer.setCustomProperty("labeling/ddProperties", '\ @@ -462,6 +482,19 @@ def checkParentLayer(self,skipchecking = False): #**************************** Header Line Layer methods ******************************************* #******************************************************************************************************* + def removeHeaderLineLayer(self): + print('remove') + self.disconnectParentLayer() + if not self.parentvectorlayer is None: + try: + if int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 4 : #qgis2 + qgis.core.QgsMapLayerRegistry.instance().removeMapLayer(self) + #self.iface.setActiveLayer(activelayer) + elif int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 5 : #qgis3 + qgis.core.QgsProject.instance().removeMapLayer(self) + #self.iface.setActiveLayer(activelayer) + except: + pass def resetHeaderLineLayer(self): # @@ -636,7 +669,7 @@ def checkDefaultFieldValue(self,feature): def adjustFeature(self,parentfet, labelfet, update = False): # #header line creation process - parent layer and headerlinelayer must be on editing mode - # + #update means only one feature is changed #compute new header line geom @@ -673,7 +706,7 @@ def adjustFeature(self,parentfet, labelfet, update = False): pointfeature = intersect.interpolate(.25 * intersect.length()).asPoint() - newgeom = self.generateHeaderLine(pointlabel, pointfeature) + newgeom = self.generateHeaderLine(parentfet,pointlabel, pointfeature,update) if pointlabel.x() Date: Thu, 23 Mar 2017 11:09:05 +0100 Subject: [PATCH 3/8] still working --- .../labeledlayer/labeledlayer_pluginlayer.py | 323 ++++++++++++------ EasyCustomLabeling/test/test_style.py | 7 + 2 files changed, 221 insertions(+), 109 deletions(-) create mode 100644 EasyCustomLabeling/test/test_style.py diff --git a/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py b/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py index 2eab784..9b3bcbe 100644 --- a/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py +++ b/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py @@ -56,6 +56,7 @@ def __init__(self): self.pixelDistWithSimpleHeaderLine = 3 #distance in centimeters on map canvas when header line is simple (else double headerline) + self.labelFields = [ #qgis.core.QgsField( "LblField", QtCore.QVariant.String, "varchar", 255), qgis.core.QgsField( "LblX", QtCore.QVariant.Double, "numeric", 20,10) , @@ -90,6 +91,12 @@ def __init__(self): #self.selectedObjects = [] self.selectedObjectsIds = [] self.fieldnametolabel = None + if False: + self.changeCrs() + self.iface.mapCanvas().destinationCrsChanged.connect(self.changeCrs) + + + def loadLabeledPluginLayer(self,vectorlayer = None, parentlayeralreadychecked = False): @@ -122,6 +129,7 @@ def loadLabeledPluginLayer(self,vectorlayer = None, parentlayeralreadychecked = self.setValid(True) self.triggerRepaint() self.iface.setActiveLayer(self.parentvectorlayer) + self.headerlinelayer.styleChanged.connect(self.saveheaderstyle) return True else: @@ -133,7 +141,17 @@ def loadLabeledPluginLayer(self,vectorlayer = None, parentlayeralreadychecked = except: self.iface.messageBar().pushMessage("Error", QApplication.translate("EasyCustomLabeling", "There is no layer currently selected, \n please click on the vector layer you need to label", None), level=0, duration=3) return False - + + + def changeCrs(self): + try: + #self.setCrs(qgis.utils.iface.mapCanvas().mapSettings().destinationCrs()) + self.xform = qgis.core.QgsCoordinateTransform(self.crs(), qgis.utils.iface.mapCanvas().mapSettings().destinationCrs()) + self.meshrenderer.changeTriangulationCRS() + self.forcerefresh = True + self.triggerRepaint() + except Exception as e: + pass #******************************************************************************************************* @@ -229,17 +247,20 @@ def readXml(self, node): return True ifsuccessful """ + DEBUG = False + element = node.toElement() - self.parent_layer_path = self.prj.readPath( element.attribute('parent_layer') ) + #self.parent_layer_path = self.prj.readPath( element.attribute('parent_layer') ) + self.parent_layer_path = os.path.normpath( element.attribute('parent_layer') ) self.fieldnametolabel = element.attribute('labelfield') if os.path.isfile(self.parent_layer_path) : basename = os.path.basename(self.parent_layer_path).split('.') if len(basename)>0: basename = basename[0] - try: #qgis2 - layers = self.prj.mapLayers() - except: #qgis3 + try: #qgis3 + layers = self.prj.mapLayers().values() + except: #qgis2 layers = qgis.core.QgsMapLayerRegistry.instance().mapLayers().values() layerfound = False #check if parent layer is already loaded @@ -253,18 +274,26 @@ def readXml(self, node): self.parentvectorlayer = qgis.core.QgsVectorLayer(self.parent_layer_path,basename,"ogr") self.loadLabeledPluginLayer(self.parentvectorlayer,True) self.prj.readMapLayer.connect(self.layerAddedtoProject) + if DEBUG : print('readXml - not found' , self.name()) return True else: #if parent layer is found self.loadLabeledPluginLayer(self.parentvectorlayer,True) + if DEBUG : print('readXml found' , self.name()) return True else: return False def layerAddedtoProject(self, layer,node ): + DEBUG = False + if isinstance(layer, qgis.core.QgsVectorLayer): + if DEBUG : print('layerAddedtoProject - called' , self.name(),os.path.normpath(layer.source()) == os.path.normpath(self.parent_layer_path) ) + if DEBUG : print('layerAddedtoProject - called' , os.path.normpath(layer.source()) , os.path.normpath(self.parent_layer_path) ) + if not self.parent_layer_path is None and os.path.normpath(layer.source()) == os.path.normpath(self.parent_layer_path): self.parentvectorlayer = layer + if DEBUG : print('layerAddedtoProject - found' , self.name()) self.loadLabeledPluginLayer(self.parentvectorlayer,True) self.prj.readMapLayer.disconnect(self.layerAddedtoProject) @@ -284,6 +313,7 @@ def initParentLayer(self,parentlayeralreadychecked = False): if self.checkParentLayer(parentlayeralreadychecked): #also disconnect parent layer + #check fields even parent layer is already checked parentlayerfields = self.parentvectorlayer.fields() parenlayerfieldname = [field.name() for field in parentlayerfields] #create fields @@ -295,81 +325,84 @@ def initParentLayer(self,parentlayeralreadychecked = False): self.parentvectorlayer.updateFields() self.parentvectorlayer.commitChanges() - #assin default values - self.parentvectorlayer.startEditing() - for feature in self.parentvectorlayer.getFeatures(): - for key, value in self.labelfielddefaultvalue.items(): - if int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 4 : #qgis2 - if isinstance(feature[key],QtCore.QPyNullVariant) or feature[key] is None : - self.parentvectorlayer.changeAttributeValue(feature.id(),self.parentvectorlayer.fields().indexFromName(key), value) - elif int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 5 : #qgis3 - if isinstance(feature[key],QtCore.QVariant) or feature[key] is None : - self.parentvectorlayer.changeAttributeValue(feature.id(),self.parentvectorlayer.fields().indexFromName(key), value) - if len(self.selectedObjectsIds)>0: - if feature.id() in self.selectedObjectsIds: - self.parentvectorlayer.changeAttributeValue(feature.id(),self.parentvectorlayer.fields().indexFromName("LblShow"), 1) - else: - self.parentvectorlayer.changeAttributeValue(feature.id(),self.parentvectorlayer.fields().indexFromName("LblShow"), 0) - self.parentvectorlayer.commitChanges() - - - - - # #generic labeling properties - self.parentvectorlayer.setCustomProperty("labeling/fieldName", self.fieldnametolabel ) # TODO replace default value with dialog input - self.parentvectorlayer.setCustomProperty("labeling","pal" ) # new gen labeling activated - self.parentvectorlayer.setCustomProperty("labeling/fontSize","8" ) # default value - self.parentvectorlayer.setCustomProperty("labeling/multiLineLabels","true" ) # default value - self.parentvectorlayer.setCustomProperty("labeling/enabled","true" ) # default value - #self.parentvectorlayer.setCustomProperty("labeling/displayAll", "true") # force all labels to display - self.parentvectorlayer.setCustomProperty("labeling/priority", "10") # puts a high priority to labeling layer - self.parentvectorlayer.setCustomProperty("labeling/multilineAlign","1") # multiline align to center - #self.parentvectorlayer.setCustomProperty("labeling/wrapChar", "%") # multiline break symbol - - self.parentvectorlayer.setCustomProperty("labeling/drawLabels","true" ) # default value - self.parentvectorlayer.setCustomProperty("labeling/isExpression","false" ) # default value + #assign default values only the first time + if not parentlayeralreadychecked : + + #assin default values + self.parentvectorlayer.startEditing() + for feature in self.parentvectorlayer.getFeatures(): + for key, value in self.labelfielddefaultvalue.items(): + if int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 4 : #qgis2 + if isinstance(feature[key],QtCore.QPyNullVariant) or feature[key] is None : + self.parentvectorlayer.changeAttributeValue(feature.id(),self.parentvectorlayer.fields().indexFromName(key), value) + elif int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 5 : #qgis3 + if isinstance(feature[key],QtCore.QVariant) or feature[key] is None : + self.parentvectorlayer.changeAttributeValue(feature.id(),self.parentvectorlayer.fields().indexFromName(key), value) + if len(self.selectedObjectsIds)>0: + if feature.id() in self.selectedObjectsIds: + self.parentvectorlayer.changeAttributeValue(feature.id(),self.parentvectorlayer.fields().indexFromName("LblShow"), 1) + else: + self.parentvectorlayer.changeAttributeValue(feature.id(),self.parentvectorlayer.fields().indexFromName("LblShow"), 0) + self.parentvectorlayer.commitChanges() + + + + + # #generic labeling properties + self.parentvectorlayer.setCustomProperty("labeling/fieldName", self.fieldnametolabel ) # TODO replace default value with dialog input + self.parentvectorlayer.setCustomProperty("labeling","pal" ) # new gen labeling activated + self.parentvectorlayer.setCustomProperty("labeling/fontSize","8" ) # default value + self.parentvectorlayer.setCustomProperty("labeling/multiLineLabels","true" ) # default value + self.parentvectorlayer.setCustomProperty("labeling/enabled","true" ) # default value + #self.parentvectorlayer.setCustomProperty("labeling/displayAll", "true") # force all labels to display + self.parentvectorlayer.setCustomProperty("labeling/priority", "10") # puts a high priority to labeling layer + self.parentvectorlayer.setCustomProperty("labeling/multilineAlign","1") # multiline align to center + #self.parentvectorlayer.setCustomProperty("labeling/wrapChar", "%") # multiline break symbol + + self.parentvectorlayer.setCustomProperty("labeling/drawLabels","true" ) # default value + self.parentvectorlayer.setCustomProperty("labeling/isExpression","false" ) # default value - #line properties case - self.parentvectorlayer.setCustomProperty("labeling/placement","4" ) - - - #assign data defined properties - if int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 4 : #qgis2 - # #data defined properties - self.parentvectorlayer.setCustomProperty("labeling/dataDefined/PositionX", "1~~0~~~~LblX") - self.parentvectorlayer.setCustomProperty("labeling/dataDefined/PositionY", "1~~0~~~~LblY") - self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Hali", "1~~0~~~~LblAlignH") - self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Vali","1~~0~~~~LblAlignV") - self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Size" ,"1~~0~~~~LblSize") - self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Rotation" ,"1~~0~~~~LblRot" ) - self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Bold" , "1~~0~~~~LblBold") - self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Italic" ,"1~~0~~~~LblItalic") - self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Underline" ,"1~~0~~~~LblUnder") - self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Strikeout" ,"1~~0~~~~LblStrike") - self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Color" ,"1~~0~~~~LblColor") - self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Family" ,"1~~0~~~~LblFont") - self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Show", "1~~0~~~~LblShow") - self.parentvectorlayer.setCustomProperty("labeling/dataDefined/AlwaysShow", "1~~0~~~~LblAShow") + #line properties case + self.parentvectorlayer.setCustomProperty("labeling/placement","4" ) - elif int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 5 : #qgis3 - # #data defined properties - self.parentvectorlayer.setCustomProperty("labeling/ddProperties", - '\ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - ') + + #assign data defined properties + if int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 4 : #qgis2 + # #data defined properties + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/PositionX", "1~~0~~~~LblX") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/PositionY", "1~~0~~~~LblY") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Hali", "1~~0~~~~LblAlignH") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Vali","1~~0~~~~LblAlignV") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Size" ,"1~~0~~~~LblSize") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Rotation" ,"1~~0~~~~LblRot" ) + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Bold" , "1~~0~~~~LblBold") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Italic" ,"1~~0~~~~LblItalic") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Underline" ,"1~~0~~~~LblUnder") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Strikeout" ,"1~~0~~~~LblStrike") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Color" ,"1~~0~~~~LblColor") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Family" ,"1~~0~~~~LblFont") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/Show", "1~~0~~~~LblShow") + self.parentvectorlayer.setCustomProperty("labeling/dataDefined/AlwaysShow", "1~~0~~~~LblAShow") + + elif int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 5 : #qgis3 + # #data defined properties + self.parentvectorlayer.setCustomProperty("labeling/ddProperties", + '\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + ') self.connectParentLayer() @@ -481,7 +514,27 @@ def checkParentLayer(self,skipchecking = False): #******************************************************************************************************* #**************************** Header Line Layer methods ******************************************* #******************************************************************************************************* + + + def saveheaderstyle(self): + stylefilename = self.getHeaderStyleFileName() + if not stylefilename is None: + self.headerlinelayer.saveNamedStyle(stylefilename) + self.triggerRepaint() + + def getHeaderStyleFileName(self): + if not self.parentvectorlayer is None: + dir_to_save = os.path.dirname(self.parentvectorlayer.source()) + basename = os.path.basename(self.parentvectorlayer.source()).split('.') + if len(basename)>0: + basename = basename[0] + basename = basename + '_ECL.qml' + return os.path.join(dir_to_save,basename) + else: + return None + + def removeHeaderLineLayer(self): print('remove') self.disconnectParentLayer() @@ -501,7 +554,7 @@ def resetHeaderLineLayer(self): # header line layer creation # if not self.parentvectorlayer is None: - type = "LineString?crs="+str(self.parentvectorlayer.crs().authid()) + type = "MultiLineString?crs="+str(self.parentvectorlayer.crs().authid()) name='temp' self.headerlinelayer = qgis.core.QgsVectorLayer(type, name, "memory") self.pr = self.headerlinelayer.dataProvider() @@ -509,8 +562,13 @@ def resetHeaderLineLayer(self): # add fields self.pr.addAttributes([qgis.core.QgsField("Value", QtCore.QVariant.Double) ]) self.headerlinelayer.updateFields() - pathpointvelocityqml = os.path.join(os.path.dirname(__file__), '..','default_label_style.qml') + if not self.getHeaderStyleFileName() is None and os.path.isfile(self.getHeaderStyleFileName()): + pathpointvelocityqml = self.getHeaderStyleFileName() + else: + pathpointvelocityqml = os.path.join(os.path.dirname(__file__), '..','default_label_style.qml') self.headerlinelayer.loadNamedStyle(pathpointvelocityqml) + self.headerlinelayer.setCrs(self.parentvectorlayer.crs()) + self.setCrs(self.parentvectorlayer.crs()) else: self.headerlinelayer = None @@ -670,14 +728,23 @@ def adjustFeature(self,parentfet, labelfet, update = False): # #header line creation process - parent layer and headerlinelayer must be on editing mode #update means only one feature is changed - + DEBUG = False #compute new header line geom if parentfet["LblShow"] and isinstance(parentfet['LblX'], float) and isinstance(parentfet['LblY'], float) : + #getpointlabel pointlabel = qgis.core.QgsPoint(parentfet['LblX'],parentfet['LblY']) + #ending point of header line if parentfet.geometry().type() == 0 : #point 0 : point 1 : line 2 : polygon pointfeature = parentfet.geometry().asPoint() + if DEBUG : print('pointfeature0',pointfeature) + + if pointfeature == qgis.core.QgsPoint(0,0): #multigeometry case + pointfeature = parentfet.geometry().asMultiPoint() + if DEBUG : print('pointfeature1',pointfeature) + pointfeature = [qgis.core.QgsPoint(pointfet) for pointfet in pointfeature] + if DEBUG : print('pointfeature2',pointfeature) elif parentfet.geometry().type() == 1 : #point 0 : point 1 : line 2 : polygon parentgeom = qgis.core.QgsGeometry(parentfet.geometry()) @@ -694,21 +761,46 @@ def adjustFeature(self,parentfet, labelfet, update = False): pointfeature = intersect.asPoint() elif parentfet.geometry().type() == 2 : #point 0 : point 1 : line 2 : polygon - pointfeature = parentfet.geometry().centroid().asPoint() - templine = qgis.core.QgsGeometry.fromPolyline([pointlabel,pointfeature]) - if templine.intersects(parentfet.geometry()): - intersect = templine.intersection(parentfet.geometry()) - if len(intersect.asMultiPolyline())==0: #singleline - pointfeature = intersect.interpolate(.25 * intersect.length()).asPoint() - else: #mulilines - #pass - intersect.convertToSingleType() - pointfeature = intersect.interpolate(.25 * intersect.length()).asPoint() + polygon = parentfet.geometry().asPolygon() + if int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 4 : #qgis2 + if len(polygon)==0: #mutlipart geom + polygon = parentfet.geometry().asMultiPolygon() + polygon = [qgis.core.QgsGeometry.fromPolygon(polyg) for polyg in polygon] + pointfeature = [polyg.centroid().asPoint() for polyg in polygon] + else: + pointfeature = [parentfet.geometry().centroid().asPoint()] + #don t do line if label interesects polygon + if qgis.core.QgsGeometry(qgis.core.QgsGeometry.fromPoint(pointlabel)).intersects(parentfet.geometry()): + pointlabel = pointfeature[0] + + elif int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 5 : #qgis3 + #qgis2 method makes dump.... + pointfeature = [parentfet.geometry().centroid().asPoint()] + + for pointfet in pointfeature: + templine = qgis.core.QgsGeometry.fromPolyline([pointlabel,pointfet]) + if templine.intersects(parentfet.geometry()): + intersect = templine.intersection(parentfet.geometry()) + if len(intersect.asMultiPolyline())==0: #singleline + #pointfet = intersect.interpolate(.25 * intersect.length()).asPoint() + pointfeature[pointfeature.index(pointfet)] = intersect.interpolate(.25 * intersect.length()).asPoint() + else: #mulilines + intersect.convertToSingleType() + #pointfet = intersect.interpolate(.25 * intersect.length()).asPoint() + pointfeature[pointfeature.index(pointfet)] = intersect.interpolate(.25 * intersect.length()).asPoint() - + #compute heaer line geometry newgeom = self.generateHeaderLine(parentfet,pointlabel, pointfeature,update) - if pointlabel.x() Date: Mon, 27 Mar 2017 09:42:02 +0200 Subject: [PATCH 4/8] work --- .../labeledlayer/labeledlayer_pluginlayer.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py b/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py index 9b3bcbe..9ec66b4 100644 --- a/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py +++ b/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py @@ -774,8 +774,18 @@ def adjustFeature(self,parentfet, labelfet, update = False): pointlabel = pointfeature[0] elif int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 5 : #qgis3 - #qgis2 method makes dump.... - pointfeature = [parentfet.geometry().centroid().asPoint()] + polygon = parentfet.geometry().asPolygon() + if len(polygon)==0: #mutlipart geom + #qgis2 method makes dump.... + tempgeom = qgis.core.QgsGeometry(parentfet.geometry()) + tempgeom.convertToSingleType() + pointfeature = [tempgeom.centroid().asPoint()] + else: + pointfeature = [parentfet.geometry().centroid().asPoint()] + #don t do line if label interesects polygon + if qgis.core.QgsGeometry(qgis.core.QgsGeometry.fromPoint(pointlabel)).intersects(parentfet.geometry()): + pointlabel = pointfeature[0] + for pointfet in pointfeature: templine = qgis.core.QgsGeometry.fromPolyline([pointlabel,pointfet]) From 150a326a4f854e724c434192508b7e72e5aaae31 Mon Sep 17 00:00:00 2001 From: patricev Date: Tue, 28 Mar 2017 11:34:26 +0200 Subject: [PATCH 5/8] adapt to non shapefile layer --- .../labeledlayer/labeledlayer_pluginlayer.py | 101 ++++++++++-------- 1 file changed, 54 insertions(+), 47 deletions(-) diff --git a/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py b/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py index 9ec66b4..e9d6510 100644 --- a/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py +++ b/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py @@ -83,14 +83,17 @@ def __init__(self): 'LblAlignV' : 'Half', 'LblAlignH' : 'Center'} - self.parent_layer_path = None + self.parent_layer_source = None self.parentvectorlayer = None - + self.incremementId = None #some parent vector layer have id starting at 0, other at 1 ... Used for comparing parentlayerid and headerlinelayer id + self.headerlinelayer = None + self.resetHeaderLineLayer() #self.selectedObjects = [] self.selectedObjectsIds = [] self.fieldnametolabel = None + if False: self.changeCrs() self.iface.mapCanvas().destinationCrsChanged.connect(self.changeCrs) @@ -105,6 +108,7 @@ def loadLabeledPluginLayer(self,vectorlayer = None, parentlayeralreadychecked = self.disconnectParentLayer() self.parentvectorlayer = vectorlayer + self.incremementId = 1 - int(self.parentvectorlayer.getFeatures().next().id() ) try: #qgis2 self.setLayerName(vectorlayer.name()+'_HeaderLineLabel') @@ -214,13 +218,14 @@ def dataProvider(self): if not self.parentvectorlayer is None: return self.parentvectorlayer.dataProvider() else: - return None + #return None + return self.headerlinelayer.dataProvider() def extent(self): if not self.parentvectorlayer is None: return self.parentvectorlayer.extent() else: - return None + return self.headerlinelayer.extent() def name(self): if not self.parentvectorlayer is None: @@ -237,7 +242,7 @@ def writeXml(self, node, doc): element = node.toElement() element.setAttribute("type", "plugin") #must be written to work element.setAttribute("name", LabeledPluginLayer.LAYER_TYPE) #must be written to work - element.setAttribute("parent_layer", os.path.normpath( self.parentvectorlayer.source() )) + element.setAttribute("parent_layer", self.parentvectorlayer.source() ) element.setAttribute("labelfield", self.parentvectorlayer.customProperty("labeling/fieldName") ) return True @@ -250,48 +255,44 @@ def readXml(self, node): DEBUG = False element = node.toElement() - #self.parent_layer_path = self.prj.readPath( element.attribute('parent_layer') ) - self.parent_layer_path = os.path.normpath( element.attribute('parent_layer') ) + self.parent_layer_source = element.attribute('parent_layer') self.fieldnametolabel = element.attribute('labelfield') - if os.path.isfile(self.parent_layer_path) : - basename = os.path.basename(self.parent_layer_path).split('.') - if len(basename)>0: - basename = basename[0] - try: #qgis3 - layers = self.prj.mapLayers().values() - except: #qgis2 - layers = qgis.core.QgsMapLayerRegistry.instance().mapLayers().values() - layerfound = False - #check if parent layer is already loaded - for layer in layers: - if os.path.normpath(layer.source()) == os.path.normpath(self.parent_layer_path): - self.parentvectorlayer = layer - layerfound = True - break - - if not layerfound: #if not found, wait a temp layer and activate readMapLayer signal when the parent layer will be loaded - self.parentvectorlayer = qgis.core.QgsVectorLayer(self.parent_layer_path,basename,"ogr") - self.loadLabeledPluginLayer(self.parentvectorlayer,True) - self.prj.readMapLayer.connect(self.layerAddedtoProject) - if DEBUG : print('readXml - not found' , self.name()) - return True - else: #if parent layer is found - self.loadLabeledPluginLayer(self.parentvectorlayer,True) - if DEBUG : print('readXml found' , self.name()) - return True - - else: - return False + if DEBUG : print('parent_layer_path',self.parent_layer_source ) + try: #qgis3 + layers = self.prj.mapLayers().values() + except: #qgis2 + layers = qgis.core.QgsMapLayerRegistry.instance().mapLayers().values() + layerfound = False + #check if parent layer is already loaded + for layer in layers: + if DEBUG : print('source',layer.source(), self.parent_layer_source) + if layer.source() == self.parent_layer_source: + self.parentvectorlayer = layer + layerfound = True + break + + if not layerfound: #if not found, wait a temp layer and activate readMapLayer signal when the parent layer will be loaded + self.prj.readMapLayer.connect(self.layerAddedtoProject) + self.setValid(True) + if DEBUG : print('readXml - not found' , self.name()) + return True + else: #if parent layer is found + self.loadLabeledPluginLayer(self.parentvectorlayer,True) + if DEBUG : print('readXml found' , self.name()) + return True + + + def layerAddedtoProject(self, layer,node ): DEBUG = False - + if isinstance(layer, qgis.core.QgsVectorLayer): - if DEBUG : print('layerAddedtoProject - called' , self.name(),os.path.normpath(layer.source()) == os.path.normpath(self.parent_layer_path) ) - if DEBUG : print('layerAddedtoProject - called' , os.path.normpath(layer.source()) , os.path.normpath(self.parent_layer_path) ) + if DEBUG : print('layerAddedtoProject - called' , self.name(),os.path.normpath(layer.source()) == os.path.normpath(self.parent_layer_source) ) + if DEBUG : print('layerAddedtoProject - called' , os.path.normpath(layer.source()) , os.path.normpath(self.parent_layer_source) ) - if not self.parent_layer_path is None and os.path.normpath(layer.source()) == os.path.normpath(self.parent_layer_path): + if not self.parent_layer_source is None and layer.source() == self.parent_layer_source: self.parentvectorlayer = layer if DEBUG : print('layerAddedtoProject - found' , self.name()) self.loadLabeledPluginLayer(self.parentvectorlayer,True) @@ -347,7 +348,6 @@ def initParentLayer(self,parentlayeralreadychecked = False): - # #generic labeling properties self.parentvectorlayer.setCustomProperty("labeling/fieldName", self.fieldnametolabel ) # TODO replace default value with dialog input self.parentvectorlayer.setCustomProperty("labeling","pal" ) # new gen labeling activated @@ -569,8 +569,11 @@ def resetHeaderLineLayer(self): self.headerlinelayer.loadNamedStyle(pathpointvelocityqml) self.headerlinelayer.setCrs(self.parentvectorlayer.crs()) self.setCrs(self.parentvectorlayer.crs()) - else: - self.headerlinelayer = None + else: #create temporary layer - needed when loading a project + #self.headerlinelayer = None + type = "MultiLineString?crs="+str(qgis.utils.iface.mapCanvas().mapSettings().destinationCrs().authid()) + name='temp' + self.headerlinelayer = qgis.core.QgsVectorLayer(type, name, "memory") @@ -598,7 +601,8 @@ def attributeValueChanged(self,FeatureId , idx , variant): if DEBUG : print('ids',[fett.id() for fett in self.headerlinelayer.getFeatures()], [fett.id() for fett in self.parentvectorlayer.getFeatures()]) if isinstance(fet['LblX'], float) and isinstance(fet['LblY'], float) : fettemp = qgis.core.QgsFeature() - if self.headerlinelayer.getFeatures(qgis.core.QgsFeatureRequest().setFilterFid(FeatureId + 1)).nextFeature(fettemp): #memory layer id start at 1 ... + #self.headerlinelayer.getFeatures(qgis.core.QgsFeatureRequest().setFilterFid(FeatureId + 1)).nextFeature(fettemp): + if self.headerlinelayer.getFeatures(qgis.core.QgsFeatureRequest().setFilterFid(FeatureId + self.incremementId)).nextFeature(fettemp): if DEBUG : print('case2 ok') self.adjustFeature(fet, fettemp,update = True) self.headerlinelayer.commitChanges() @@ -610,7 +614,8 @@ def attributeValueChanged(self,FeatureId , idx , variant): fet = qgis.core.QgsFeature() if self.parentvectorlayer.getFeatures(qgis.core.QgsFeatureRequest().setFilterFid(FeatureId)).nextFeature(fet): fettemp = qgis.core.QgsFeature() - if self.headerlinelayer.getFeatures(qgis.core.QgsFeatureRequest().setFilterFid(FeatureId + 1)).nextFeature(fettemp): #memory layer id start at 1 ... + #if self.headerlinelayer.getFeatures(qgis.core.QgsFeatureRequest().setFilterFid(FeatureId + 1)).nextFeature(fettemp): #memory layer id start at 1 ... + if self.headerlinelayer.getFeatures(qgis.core.QgsFeatureRequest().setFilterFid(FeatureId + self.incremementId)).nextFeature(fettemp): self.adjustFeature(fet, fettemp,update = True) self.headerlinelayer.commitChanges() self.triggerRepaint() @@ -663,7 +668,8 @@ def geometryChanged(self,FeatureId,geom): if DEBUG : print('ids',[fett.id() for fett in self.headerlinelayer.getFeatures()], [fett.id() for fett in self.parentvectorlayer.getFeatures()]) if isinstance(fet['LblX'], float) and isinstance(fet['LblY'], float) : fettemp = qgis.core.QgsFeature() - if self.headerlinelayer.getFeatures(qgis.core.QgsFeatureRequest().setFilterFid(FeatureId + 1)).nextFeature(fettemp): #memory layer id start at 1 ... + #if self.headerlinelayer.getFeatures(qgis.core.QgsFeatureRequest().setFilterFid(FeatureId + 1)).nextFeature(fettemp): #memory layer id start at 1 ... + if self.headerlinelayer.getFeatures(qgis.core.QgsFeatureRequest().setFilterFid(FeatureId + self.incremementId)).nextFeature(fettemp): if DEBUG : print('case2 ok') self.adjustFeature(fet, fettemp,update = True) self.headerlinelayer.commitChanges() @@ -884,9 +890,10 @@ def generateHeaderLine(self,parentfet,pointlabel, pointfeaturelist,update): headermiddlepoint = headermiddlepoint.asPoint() #return qgis.core.QgsGeometry.fromPolyline([pointlabel,headermiddlepoint,pointfeature]) multipoly.append([pointlabel,headermiddlepoint,pointfeature]) - if len(multipoly) == 0: return qgis.core.QgsGeometry() + elif len(multipoly) == 1 : + return qgis.core.QgsGeometry.fromPolyline(multipoly[0]) else: return qgis.core.QgsGeometry.fromMultiPolyline(multipoly) From f9527af26239f35ebd8cf487bee20635c28316c7 Mon Sep 17 00:00:00 2001 From: patricev Date: Mon, 3 Apr 2017 10:00:13 +0200 Subject: [PATCH 6/8] nearly ok --- .../labeledlayer/labeledlayer_pluginlayer.py | 84 +++++++++++++------ .../labeledlayer_pluginlayer_type.py | 56 ++++++++----- EasyCustomLabeling/test/test_polygon.py | 20 +++++ EasyCustomLabeling/test/test_widget.py | 70 ++++++++++++++++ 4 files changed, 185 insertions(+), 45 deletions(-) create mode 100644 EasyCustomLabeling/test/test_polygon.py create mode 100644 EasyCustomLabeling/test/test_widget.py diff --git a/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py b/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py index e9d6510..2814785 100644 --- a/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py +++ b/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py @@ -26,9 +26,10 @@ #Qt from qgis.PyQt import QtCore, QtGui try: #qt4 - from qgis.PyQt.QtGui import QApplication, QMessageBox + from qgis.PyQt.QtGui import QApplication, QMessageBox, QDialog, QVBoxLayout, QDialogButtonBox except: #qt5 - from qgis.PyQt.QtWidgets import QApplication, QMessageBox + from qgis.PyQt.QtWidgets import QApplication, QMessageBox, QDialog, QVBoxLayout, QDialogButtonBox + # other import import collections @@ -83,7 +84,7 @@ def __init__(self): 'LblAlignV' : 'Half', 'LblAlignH' : 'Center'} - self.parent_layer_source = None + self.parent_layer_id = None self.parentvectorlayer = None self.incremementId = None #some parent vector layer have id starting at 0, other at 1 ... Used for comparing parentlayerid and headerlinelayer id @@ -94,6 +95,8 @@ def __init__(self): self.selectedObjectsIds = [] self.fieldnametolabel = None + #self.styledlg = QDialog() + if False: self.changeCrs() self.iface.mapCanvas().destinationCrsChanged.connect(self.changeCrs) @@ -104,11 +107,17 @@ def __init__(self): def loadLabeledPluginLayer(self,vectorlayer = None, parentlayeralreadychecked = False): #check and add proper fields to parent layer + DEBUG = False if not vectorlayer is None: self.disconnectParentLayer() self.parentvectorlayer = vectorlayer - self.incremementId = 1 - int(self.parentvectorlayer.getFeatures().next().id() ) + + fet = qgis.core.QgsFeature() + if self.parentvectorlayer.getFeatures().nextFeature(fet): + self.incremementId = 1 - int(fet.id() ) + else: + self.incremementId = 0 try: #qgis2 self.setLayerName(vectorlayer.name()+'_HeaderLineLabel') @@ -119,17 +128,20 @@ def loadLabeledPluginLayer(self,vectorlayer = None, parentlayeralreadychecked = success = self.initParentLayer(parentlayeralreadychecked) if success: - + if DEBUG : print('loadLabeledPluginLayer - success - parent layer : ',self.parentvectorlayer.source(),'count : ',self.parentvectorlayer.featureCount()) #create Header Line layer self.resetHeaderLineLayer() self.headerlinelayer.startEditing() self.reinitHeaderLineLayer() self.headerlinelayer.commitChanges() + if DEBUG : print('loadLabeledPluginLayer - success - hh layer',self.headerlinelayer.featureCount() ) + #connecting signals from parent layer - do connexion aftter parent layer check self.connectParentLayer() #otherwiwe it doesn't show self.parentvectorlayer.commitChanges() + if DEBUG : print('loadLabeledPluginLayer - success - parent layer : ',self.parentvectorlayer.source(),'count : ',self.parentvectorlayer.featureCount()) self.setValid(True) self.triggerRepaint() self.iface.setActiveLayer(self.parentvectorlayer) @@ -239,10 +251,13 @@ def writeXml(self, node, doc): return True ifsuccessful """ #prj = qgis.core.QgsProject.instance() + self.saveheaderstyle() + element = node.toElement() element.setAttribute("type", "plugin") #must be written to work element.setAttribute("name", LabeledPluginLayer.LAYER_TYPE) #must be written to work - element.setAttribute("parent_layer", self.parentvectorlayer.source() ) + #element.setAttribute("parent_layer", self.parentvectorlayer.source() ) + element.setAttribute("parent_layer", self.parentvectorlayer.id() ) element.setAttribute("labelfield", self.parentvectorlayer.customProperty("labeling/fieldName") ) return True @@ -255,10 +270,11 @@ def readXml(self, node): DEBUG = False element = node.toElement() - self.parent_layer_source = element.attribute('parent_layer') + #self.parent_layer_source = element.attribute('parent_layer') + self.parent_layer_id = element.attribute('parent_layer') self.fieldnametolabel = element.attribute('labelfield') - if DEBUG : print('parent_layer_path',self.parent_layer_source ) + if DEBUG : print('parent_layer_id',self.parent_layer_id ) try: #qgis3 layers = self.prj.mapLayers().values() except: #qgis2 @@ -266,8 +282,9 @@ def readXml(self, node): layerfound = False #check if parent layer is already loaded for layer in layers: - if DEBUG : print('source',layer.source(), self.parent_layer_source) - if layer.source() == self.parent_layer_source: + #if DEBUG : print('source',layer.source(), self.parent_layer_source) + if DEBUG : print('source',layer.id(), self.parent_layer_id) + if layer.id() == self.parent_layer_id: self.parentvectorlayer = layer layerfound = True break @@ -289,12 +306,12 @@ def layerAddedtoProject(self, layer,node ): DEBUG = False if isinstance(layer, qgis.core.QgsVectorLayer): - if DEBUG : print('layerAddedtoProject - called' , self.name(),os.path.normpath(layer.source()) == os.path.normpath(self.parent_layer_source) ) - if DEBUG : print('layerAddedtoProject - called' , os.path.normpath(layer.source()) , os.path.normpath(self.parent_layer_source) ) + if DEBUG : print('layerAddedtoProject - called' , 'name : ',self.name() ,' - id match : ',layer.id() == self.parent_layer_id) + #if DEBUG : print('layerAddedtoProject - called' , layer.source() , self.parent_layer_source) - if not self.parent_layer_source is None and layer.source() == self.parent_layer_source: + if not self.parent_layer_id is None and layer.id() == self.parent_layer_id: self.parentvectorlayer = layer - if DEBUG : print('layerAddedtoProject - found' , self.name()) + if DEBUG : print('layerAddedtoProject - found' , 'name : ',self.name()) self.loadLabeledPluginLayer(self.parentvectorlayer,True) self.prj.readMapLayer.disconnect(self.layerAddedtoProject) @@ -517,11 +534,14 @@ def checkParentLayer(self,skipchecking = False): def saveheaderstyle(self): + print('stylechanged') stylefilename = self.getHeaderStyleFileName() if not stylefilename is None: self.headerlinelayer.saveNamedStyle(stylefilename) self.triggerRepaint() + + def getHeaderStyleFileName(self): if not self.parentvectorlayer is None: dir_to_save = os.path.dirname(self.parentvectorlayer.source()) @@ -560,8 +580,8 @@ def resetHeaderLineLayer(self): self.pr = self.headerlinelayer.dataProvider() self.headerlinelayer.startEditing() # add fields - self.pr.addAttributes([qgis.core.QgsField("Value", QtCore.QVariant.Double) ]) - self.headerlinelayer.updateFields() + #self.pr.addAttributes([qgis.core.QgsField("Value", QtCore.QVariant.Double) ]) + #self.headerlinelayer.updateFields() if not self.getHeaderStyleFileName() is None and os.path.isfile(self.getHeaderStyleFileName()): pathpointvelocityqml = self.getHeaderStyleFileName() else: @@ -569,13 +589,20 @@ def resetHeaderLineLayer(self): self.headerlinelayer.loadNamedStyle(pathpointvelocityqml) self.headerlinelayer.setCrs(self.parentvectorlayer.crs()) self.setCrs(self.parentvectorlayer.crs()) + + else: #create temporary layer - needed when loading a project #self.headerlinelayer = None - type = "MultiLineString?crs="+str(qgis.utils.iface.mapCanvas().mapSettings().destinationCrs().authid()) + if int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 4 : #qgis2 + crstemp = qgis.utils.iface.mapCanvas().mapSettings().destinationCrs() + elif int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 5 : #qgis3 + crstemp = qgis.core.QgsProject.instance().crs() + + type = "MultiLineString?crs="+str(crstemp.authid()) name='temp' self.headerlinelayer = qgis.core.QgsVectorLayer(type, name, "memory") - - + self.setCrs(crstemp) + def attributeValueChanged(self,FeatureId , idx , variant): @@ -701,15 +728,20 @@ def reinitHeaderLineLayer(self): self.adjustFeature(fet, fettemp) self.pr.addFeatures([fettemp]) if DEBUG : print('ids after ',[fett.id() for fett in self.headerlinelayer.getFeatures()], [fett.id() for fett in self.parentvectorlayer.getFeatures()]) - #self.triggerRepaint() - #self.parentvectorlayer.commitChanges() """ - if parentlayereditmode : - self.parentvectorlayer.commitChanges() - self.parentvectorlayer.startEditing() - else: - self.parentvectorlayer.commitChanges() + #self.styledlg = QDialog() + self.tt = qgis.gui.QgsSingleSymbolRendererV2Widget(self.headerlinelayer, qgis.core.QgsStyleV2.defaultStyle() ,self.headerlinelayer.rendererV2()) + self.tt.setDockMode(False) + self.tt.setMapCanvas(self.iface.mapCanvas()) + self.layout = QVBoxLayout() + self.layout.addWidget(self.tt) + self.buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.buttons.accepted.connect(self.styledlg.accept) + self.buttons.rejected.connect(self.styledlg.reject) + self.layout.addWidget(self.buttons) + self.styledlg.setLayout(self.layout) """ + def checkDefaultFieldValue(self,feature): # diff --git a/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer_type.py b/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer_type.py index 2645ec6..f53dc8e 100644 --- a/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer_type.py +++ b/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer_type.py @@ -1,42 +1,60 @@ import qgis.core import qgis.utils +import qgis -#import PyQT from qgis.PyQt import QtCore -#import posttelemac from .labeledlayer_pluginlayer import LabeledPluginLayer +try: + from qgis.PyQt.QtGui import QDialog, QVBoxLayout, QDialogButtonBox +except: + from qgis.PyQt.QtWidgets import QDialog, QVBoxLayout, QDialogButtonBox class LabeledLayerPluginLayerType(qgis.core.QgsPluginLayerType): def __init__(self): - #qgis.core.QgsPluginLayerType.__init__(self, SelafinPluginLayer.LAYER_TYPE) qgis.core.QgsPluginLayerType.__init__(self, LabeledPluginLayer.LAYER_TYPE) - self.iface = qgis.utils.iface - def createLayer(self): return LabeledPluginLayer() - #if False: def showLayerProperties(self, layer): - self.iface.showLayerProperties(layer.headerlinelayer) - - #tt = qgis.gui.QgsSimpleLineSymbolLayerV2Widget(iface.activeLayer()) - - """ - self.iface.addDockWidget( QtCore.Qt.RightDockWidgetArea, layer.propertiesdialog ) - self.iface.mapCanvas().setRenderFlag(True) - return True - """ - #print('properties') - #self.iface.showLayerProperties(layer) - return True + if False: + if not layer.styledlg is None and layer.styledlg.exec_(): + #layer.headerlinelayer.styleChanged.disconnect(layer.saveheaderstyle) + if True: + layer.headerlinelayer.setRendererV2(layer.tt.renderer()) + #layer.headerlinelayer.triggerRepaint() + #layer.triggerRepaint() + if False: + layer.tt.applyChanges() + return True + else: + return False + + if True: + if int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 4 : #qgis2 + tt = qgis.gui.QgsSymbolV2SelectorDialog( layer.headerlinelayer.rendererV2().symbol(), qgis.core.QgsStyleV2.defaultStyle(), + layer.headerlinelayer, # QgsVectorLayer + None, # Parent + False # Embedded + ) + elif int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 5 : #qgis3 + tt = qgis.gui.QgsSymbolSelectorDialog( layer.headerlinelayer.renderer().symbol(), qgis.core.QgsStyle.defaultStyle(), + layer.headerlinelayer, # QgsVectorLayer + None, # Parent + False # Embedded + ) + if tt.exec_(): + + layer.triggerRepaint() + layer.headerlinelayer.styleChanged.emit() + return True def addToRegistry(self): - #Add telemac_viewer in QgsPluginLayerRegistry + #Add labeledlayer in QgsPluginLayerRegistry if u'labeledlayer' in QgsPluginLayerRegistry.instance().pluginLayerTypes(): QgsPluginLayerRegistry.instance().removePluginLayerType('labeledlayer') self.pluginLayerType = self() diff --git a/EasyCustomLabeling/test/test_polygon.py b/EasyCustomLabeling/test/test_polygon.py new file mode 100644 index 0000000..84ad43a --- /dev/null +++ b/EasyCustomLabeling/test/test_polygon.py @@ -0,0 +1,20 @@ +import qgis +from qgis.core import QgsPoint +from qgis.PyQt import QtCore + +obj = QtCore.QObject() + +#geom2 = qgis.core.QgsGeometry.fromPolygon(obj) + +geom2 = qgis.core.QgsGeometry.fromPolygon([[QgsPoint(0,0),QgsPoint(1,0),QgsPoint(1,1),QgsPoint(0,1)]] ) + +geom = qgis.core.QgsGeometry.fromMultiPolygon([[[QgsPoint(0,0),QgsPoint(1,0),QgsPoint(1,1),QgsPoint(0,1)]],\ + [[QgsPoint(2,2),QgsPoint(3,2),QgsPoint(3,3),QgsPoint(2,3)]]] ) + + + +print(geom2.asPolygon()) +print(geom2.asMultiPolygon()) +tt = geom.asMultiPolygon() + +print(type(geom)) \ No newline at end of file diff --git a/EasyCustomLabeling/test/test_widget.py b/EasyCustomLabeling/test/test_widget.py new file mode 100644 index 0000000..9fe07c0 --- /dev/null +++ b/EasyCustomLabeling/test/test_widget.py @@ -0,0 +1,70 @@ +vl = iface.activeLayer() +stmana= vl.styleManager() #QgsMapLayerStyleManager +stmananame = stmana.currentStyle () +maplayersyle = vl.styleManager().style(stmananame ) #QgsMapLayerStyle + + + +renderer = vl.rendererV2() #QgsFeatureRendererV2 +print(renderer.__class__) + +#print(renderer.symbol()) + + + +#print(maplayersyle.xmlData () ) + + + +#tt = qgis.gui.QgsCategorizedSymbolRendererWidget(vl) + +#tt = qgis.gui.QgsSimpleLineSymbolLayerV2Widget(vl) +#tt = qgis.gui.QgsLinePatternFillSymbolLayerWidget(vl) +#tt = qgis.gui.QgsMarkerLineSymbolLayerV2Widget(vl) +#tt = qgis.gui.QgsArrowSymbolLayerWidget (vl) +#tt = qgis.gui.QgsGeometryGeneratorSymbolLayerWidget(vl) +#tt = qgis.gui.QgsLinePatternFillSymbolLayerWidget(vl) +#tt = qgis.gui.QgsMapLayerStyleManagerWidget(vl,iface.mapCanvas()) + +#QgsPanelWidget + +#QgsLayerPropertiesWidget (QgsSymbolLayerV2 *layer, const QgsSymbolV2 *symbol, const QgsVectorLayer *vl, QWidget *parent=nullptr) +#tt = qgis.gui.QgsLayerPropertiesWidget(renderer.symbol().symbolLayer(0), renderer.symbol() , vl) + +#QgsSingleSymbolRendererV2Widget (QgsVectorLayer *layer, QgsStyleV2 *style, QgsFeatureRendererV2 *renderer) +#tt = qgis.gui.QgsSingleSymbolRendererV2Widget(vl, qgis.core.QgsStyleV2.defaultStyle() ,renderer) +#tt.setDockMode(False) + + +#tt = qgis.gui.QgsRendererV2PropertiesDialog(vl,qgis.core.QgsStyleV2.defaultStyle(),True) +#tt.exec_() +#tt.onOK () + + +tt = qgis.gui.QgsSymbolV2SelectorDialog( vl.rendererV2().symbol(), qgis.core.QgsStyleV2.defaultStyle(), + vl, # QgsVectorLayer + None, # Parent + False # Embedded + ) +if tt.exec_(): + + vl.triggerRepaint() +#qgis.gui.QgsPanelWidget.openPanel(tt) +#res = tt.openPanel(tt) +print('res',res) +#tt.applyChanges () +#vl.setRendererV2(tt.renderer()) +#tt.showSymbolLevelsDialog(renderer) + +#QgsStyleV2ManagerDialog (QgsStyleV2 *style, QWidget *parent=nullptr) +#tt = qgis.gui.QgsStyleV2ManagerDialog(qgis.core.QgsStyleV2.defaultStyle() ) +#QgsSymbolV2SelectorWidget (QgsSymbolV2 *symbol, QgsStyleV2 *style, const QgsVectorLayer *vl, QWidget *parent=nullptr) +#tt = qgis.gui.QgsSymbolV2SelectorWidget(renderer.symbol(),qgis.core.QgsStyleV2.defaultStyle() , vl ) + +#tt.show() +#tt.exec_() +print('ok') +#tt.exec_() +#vl.setRendererV2(tt.renderer()) +#vl.triggerRepaint() + From 039cd99c39d8136b3c1ce78c5d9ffce190e4643c Mon Sep 17 00:00:00 2001 From: patricev Date: Mon, 3 Apr 2017 16:48:56 +0200 Subject: [PATCH 7/8] near final release --- .../EasyCustomLabelingDialog.py | 19 +++-- .../EasyCustomLabelingDialog_backup.py | 63 +++++++++++++++++ .../labeledlayer/labeledlayer_pluginlayer.py | 28 +++----- EasyCustomLabeling/ui_EasyCustomLabeling.ui | 69 +++++++++---------- 4 files changed, 120 insertions(+), 59 deletions(-) create mode 100644 EasyCustomLabeling/EasyCustomLabelingDialog_backup.py diff --git a/EasyCustomLabeling/EasyCustomLabelingDialog.py b/EasyCustomLabeling/EasyCustomLabelingDialog.py index bfca973..51fa3e4 100644 --- a/EasyCustomLabeling/EasyCustomLabelingDialog.py +++ b/EasyCustomLabeling/EasyCustomLabelingDialog.py @@ -32,25 +32,32 @@ from PyQt4.QtCore import * from PyQt4.QtGui import * """ -from qgis.PyQt import QtCore, QtGui +from qgis.PyQt import QtCore, QtGui, uic try: #qt4 from qgis.PyQt.QtGui import QDialog except: #qt5 from qgis.PyQt.QtWidgets import QDialog - +import os from qgis.core import * from .ui_EasyCustomLabeling import Ui_EasyCustomLabeling -class EasyCustomLabelingDialog(QDialog, Ui_EasyCustomLabeling): +FORM_CLASS, _ = uic.loadUiType(os.path.join( + os.path.dirname(__file__), 'ui_EasyCustomLabeling.ui')) + +class EasyCustomLabelingDialog(QDialog, FORM_CLASS): - def __init__(self, ldp): - QDialog.__init__(self) + def __init__(self, ldp, parent = None): + super(EasyCustomLabelingDialog, self).__init__(parent) # Set up the user interface from Designer. + # After setupUI you can access any designer object by doing + # self., and you can use autoconnect slots - see + # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html + # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.loadFields(ldp) - def loadFields(self, ldp): + def loadFields(self,ldp): fields = ldp.fieldNameMap() """ for fieldname, index in fields.iteritems(): diff --git a/EasyCustomLabeling/EasyCustomLabelingDialog_backup.py b/EasyCustomLabeling/EasyCustomLabelingDialog_backup.py new file mode 100644 index 0000000..b1410d6 --- /dev/null +++ b/EasyCustomLabeling/EasyCustomLabelingDialog_backup.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +""" +/*************************************************************************** +Layer to labeled layer + A QGIS plugin +Make it possible to use data-defined labeling on existing layer. +The plug-in creates new attributes in the existing shapefile. + ------------------- + begin : 2012-11-01 + copyright : (C) 2012 by Victor Axbom + email : - + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + ***************************************************************************/ +""" +""" +from PyQt4.QtCore import * +from PyQt4.QtGui import * +""" +from qgis.PyQt import QtCore, QtGui, uic +try: #qt4 + from qgis.PyQt.QtGui import QDialog +except: #qt5 + from qgis.PyQt.QtWidgets import QDialog + +from qgis.core import * +from .ui_EasyCustomLabeling import Ui_EasyCustomLabeling + +FORM_CLASS, _ = uic.loadUiType(os.path.join( + os.path.dirname(__file__), 'ui_EasyCustomLabeling.ui')) + +class EasyCustomLabelingDialog(QDialog, Ui_EasyCustomLabeling): + + def __init__(self, ldp): + QDialog.__init__(self) + # Set up the user interface from Designer. + self.setupUi(self) + + self.loadFields(ldp) + + def loadFields(self, ldp): + fields = ldp.fieldNameMap() + """ + for fieldname, index in fields.iteritems(): + self.labelfield.addItem(fieldname) + """ + for fieldname, index in fields.items(): + self.labelfield.addItem(fieldname) \ No newline at end of file diff --git a/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py b/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py index 2814785..2cb60c6 100644 --- a/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py +++ b/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py @@ -87,7 +87,7 @@ def __init__(self): self.parent_layer_id = None self.parentvectorlayer = None self.incremementId = None #some parent vector layer have id starting at 0, other at 1 ... Used for comparing parentlayerid and headerlinelayer id - + self.addheaderlinelayer = 1 #True self.headerlinelayer = None self.resetHeaderLineLayer() @@ -127,7 +127,7 @@ def loadLabeledPluginLayer(self,vectorlayer = None, parentlayeralreadychecked = success = self.initParentLayer(parentlayeralreadychecked) - if success: + if success and self.addheaderlinelayer : if DEBUG : print('loadLabeledPluginLayer - success - parent layer : ',self.parentvectorlayer.source(),'count : ',self.parentvectorlayer.featureCount()) #create Header Line layer self.resetHeaderLineLayer() @@ -421,8 +421,8 @@ def initParentLayer(self,parentlayeralreadychecked = False): \ ') - - self.connectParentLayer() + if self.addheaderlinelayer : + self.connectParentLayer() return True else: @@ -509,6 +509,7 @@ def checkParentLayer(self,skipchecking = False): return False self.fieldnametolabel = self.dlg.labelfield.currentText() + self.addheaderlinelayer = self.dlg.checkBox_hllayer.checkState() # show the dialog # if self.dlg.exec_(): # return True# print 'dialog execution' @@ -534,7 +535,6 @@ def checkParentLayer(self,skipchecking = False): def saveheaderstyle(self): - print('stylechanged') stylefilename = self.getHeaderStyleFileName() if not stylefilename is None: self.headerlinelayer.saveNamedStyle(stylefilename) @@ -785,18 +785,12 @@ def adjustFeature(self,parentfet, labelfet, update = False): if DEBUG : print('pointfeature2',pointfeature) elif parentfet.geometry().type() == 1 : #point 0 : point 1 : line 2 : polygon - parentgeom = qgis.core.QgsGeometry(parentfet.geometry()) - parentgeom.convertToSingleType() - pointfeature = parentgeom.interpolate(.5 * parentgeom.length()).asPoint() #point in he middle of polyline - templine = qgis.core.QgsGeometry.fromPolyline([pointlabel,pointfeature]) - if templine.intersects(parentfet.geometry()): - intersect = templine.intersection(parentfet.geometry()) - if len(intersect.asMultiPoint())==0: #single point - pointfeature = intersect.asPoint() - else: #mulilines - #pass - intersect.convertToSingleType() - pointfeature = intersect.asPoint() + polyline = parentfet.geometry().asPolyline() + if len(polyline) == 0: + polyline = parentfet.geometry().asMultiPolyline() + pointfeature = [qgis.core.QgsGeometry.fromPolyline(polyl).nearestPoint(qgis.core.QgsGeometry.fromPoint(pointlabel)).asPoint() for polyl in polyline] + else: + pointfeature = [ qgis.core.QgsGeometry.fromPolyline(polyline).nearestPoint(qgis.core.QgsGeometry.fromPoint(pointlabel)).asPoint() ] elif parentfet.geometry().type() == 2 : #point 0 : point 1 : line 2 : polygon polygon = parentfet.geometry().asPolygon() diff --git a/EasyCustomLabeling/ui_EasyCustomLabeling.ui b/EasyCustomLabeling/ui_EasyCustomLabeling.ui index 92a1b4a..3304fcd 100644 --- a/EasyCustomLabeling/ui_EasyCustomLabeling.ui +++ b/EasyCustomLabeling/ui_EasyCustomLabeling.ui @@ -6,7 +6,7 @@ 0 0 - 308 + 350 135 @@ -40,41 +40,38 @@ true - - - - 100 - 100 - 191 - 23 - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - 20 - 20 - 261 - 20 - - - - Qt::Horizontal - - - - - - - Label field - - - - + + + + + + + + Label field + + + + + + + + + + Create header line layer + + + true + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + From db40328211a0ba99bef52b4ef6102b8ff669190c Mon Sep 17 00:00:00 2001 From: patricev Date: Wed, 5 Apr 2017 17:12:38 +0200 Subject: [PATCH 8/8] details --- .../labeledlayer/labeledlayer_pluginlayer.py | 50 ++++++++++++------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py b/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py index 2cb60c6..d0b7c25 100644 --- a/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py +++ b/EasyCustomLabeling/labeledlayer/labeledlayer_pluginlayer.py @@ -54,8 +54,8 @@ def __init__(self): self.prj = qgis.core.QgsProject.instance() self.iface = qgis.utils.iface self.pixelDistWithNoHeaderLine = 1 #distance in centimeters on map canvas when header line is not shown - self.pixelDistWithSimpleHeaderLine = 3 #distance in centimeters on map canvas when header line is simple (else double headerline) - + self.pixelDistWithSimpleHeaderLine = 2 #distance in centimeters on map canvas when header line is simple (else double headerline) + self.pixelDistBufferTargetPoint = 0.05 #distance in centimeters on map canvas when header line is simple (else double headerline) self.labelFields = [ @@ -113,21 +113,21 @@ def loadLabeledPluginLayer(self,vectorlayer = None, parentlayeralreadychecked = self.parentvectorlayer = vectorlayer - fet = qgis.core.QgsFeature() - if self.parentvectorlayer.getFeatures().nextFeature(fet): - self.incremementId = 1 - int(fet.id() ) - else: - self.incremementId = 0 - try: #qgis2 self.setLayerName(vectorlayer.name()+'_HeaderLineLabel') except: #qgis3 self.setName(vectorlayer.name()+'_HeaderLineLabel') - success = self.initParentLayer(parentlayeralreadychecked) if success and self.addheaderlinelayer : + + fet = qgis.core.QgsFeature() + if self.parentvectorlayer.getFeatures().nextFeature(fet): + self.incremementId = 1 - int(fet.id() ) + else: + self.incremementId = 0 + if DEBUG : print('loadLabeledPluginLayer - success - parent layer : ',self.parentvectorlayer.source(),'count : ',self.parentvectorlayer.featureCount()) #create Header Line layer self.resetHeaderLineLayer() @@ -474,14 +474,9 @@ def checkParentLayer(self,skipchecking = False): return False elif ret == 65536 : # No button65536 use entire layer pass - #print('use entire layer') elif ret == 16384 : - print('use selection') self.selectedObjectsIds = [fet.id() for fet in sourceLayer.selectedFeatures()] - - #nbSelectedObjects = sourceLayer.selectedFeatureCount() - if sourceLayer.selectedFeatureCount() > 500 : #alert if many objects selected @@ -720,13 +715,16 @@ def reinitHeaderLineLayer(self): self.parentvectorlayer.startEditing() self.resetHeaderLineLayer() + feattoadd = [] for fet in self.parentvectorlayer.getFeatures(): if fet.id()>=0: self.checkDefaultFieldValue(fet) fettemp = qgis.core.QgsFeature(self.headerlinelayer.fields()) if isinstance(fet['LblX'], float) and isinstance(fet['LblY'], float) : self.adjustFeature(fet, fettemp) - self.pr.addFeatures([fettemp]) + feattoadd.append(fettemp) + if len(feattoadd)>0: + self.pr.addFeatures(feattoadd) if DEBUG : print('ids after ',[fett.id() for fett in self.headerlinelayer.getFeatures()], [fett.id() for fett in self.parentvectorlayer.getFeatures()]) """ #self.styledlg = QDialog() @@ -804,7 +802,7 @@ def adjustFeature(self,parentfet, labelfet, update = False): #don t do line if label interesects polygon if qgis.core.QgsGeometry(qgis.core.QgsGeometry.fromPoint(pointlabel)).intersects(parentfet.geometry()): pointlabel = pointfeature[0] - + elif int(qgis.PyQt.QtCore.QT_VERSION_STR[0]) == 5 : #qgis3 polygon = parentfet.geometry().asPolygon() if len(polygon)==0: #mutlipart geom @@ -817,7 +815,7 @@ def adjustFeature(self,parentfet, labelfet, update = False): #don t do line if label interesects polygon if qgis.core.QgsGeometry(qgis.core.QgsGeometry.fromPoint(pointlabel)).intersects(parentfet.geometry()): pointlabel = pointfeature[0] - + for pointfet in pointfeature: templine = qgis.core.QgsGeometry.fromPolyline([pointlabel,pointfet]) @@ -893,9 +891,11 @@ def generateHeaderLine(self,parentfet,pointlabel, pointfeaturelist,update): self.parentvectorlayer.changeAttributeValue(parentfet.id(),self.parentvectorlayer.fields().indexFromName("LblScale"), scale) #then compute headerline + #self.pixelDistBufferTargetPoint distnoheaderinmeters = scale * self.pixelDistWithNoHeaderLine/100.0 distsimpleheaderinmeters = scale * self.pixelDistWithSimpleHeaderLine/100.0 + disttargetpoinbuffer = scale * self.pixelDistBufferTargetPoint/100.0 #distnoheaderinmeters = self.iface.mapCanvas().mapUnitsPerPixel() * self.pixelDistWithNoHeaderLine #distsimpleheaderinmeters = self.iface.mapCanvas().mapUnitsPerPixel() * self.pixelDistWithSimpleHeaderLine @@ -905,7 +905,12 @@ def generateHeaderLine(self,parentfet,pointlabel, pointfeaturelist,update): if distfeat < distnoheaderinmeters: pass elif distfeat < distsimpleheaderinmeters : - multipoly.append([pointlabel,pointfeature]) + #multipoly.append([pointlabel,pointfeature]) + geomtemp = qgis.core.QgsGeometry.fromPolyline([pointlabel,pointfeature]) + if parentfet.geometry().type() in [0,1]: + geomtemp = geomtemp.difference( qgis.core.QgsGeometry.fromPoint(pointfeature).buffer( disttargetpoinbuffer ,12 )) + #print(geomtemp2.asPolyline()) + multipoly.append(geomtemp.asPolyline()) #return qgis.core.QgsGeometry.fromPolyline([pointlabel,pointfeature]) else: headermiddlepoint = qgis.core.QgsGeometry(qgis.core.QgsGeometry.fromPoint(pointlabel)) @@ -914,8 +919,15 @@ def generateHeaderLine(self,parentfet,pointlabel, pointfeaturelist,update): else: headermiddlepoint.translate(-distnoheaderinmeters,0) headermiddlepoint = headermiddlepoint.asPoint() + + #return qgis.core.QgsGeometry.fromPolyline([pointlabel,headermiddlepoint,pointfeature]) - multipoly.append([pointlabel,headermiddlepoint,pointfeature]) + geomtemp = qgis.core.QgsGeometry.fromPolyline([pointlabel,headermiddlepoint,pointfeature]) + if parentfet.geometry().type() in [0,1]: + geomtemp = geomtemp.difference( qgis.core.QgsGeometry.fromPoint(pointfeature).buffer( disttargetpoinbuffer ,12 )) + #print(geomtemp2.asPolyline()) + multipoly.append(geomtemp.asPolyline()) + if len(multipoly) == 0: return qgis.core.QgsGeometry() elif len(multipoly) == 1 :