[QGIS-Developer] Difficulties with custom bad layer handler in plugin code

Áron Gergely aron.gergely at rasterra.nl
Sun Jul 21 04:16:29 PDT 2019


Hello to all contributors,

I am trying to implement a custom bad layer handler that I would ship 
with a plugin (for QGIS 3.4 and above).

The plugin creates map layouts and places a default world map layer in 
them, which we ship with the plugin.
However when users shave the project file and share it among each other, 
many find this layer to be broken.
The layer points to a data in the plugin path, which is not the same 
across machines.

The custom bad layer handler would try to see if this specific layer is 
broken and fix it for the user,
then call the regular bad layer handling "file dialog" to allow them to 
fix any eventual broken layers that are unrelated to the plugin.

I am creating my bad layer handler by subclassing QgsProjectBadLayerHandler,
thin I pass it to QgsProject by calling its setBadLayerHandler() method.
Since I want to pass it before any layer is actually loaded (so when 
launching qgis to open a project file, it would work right away)
I had to resort to a sort of ugly way of using the 
QgsProject.layerLoaded signal to make this happen.

This actually works, for the 1st time when I open a project file with 
bad layers. Then the 2nd time, QGIS always crashes.
It seems once I replaced the bad layer handler during project start, 
QGIS is not able to open a subsequent new project properly.

Here is my example in code:

class MyBadLayerHandler(QgsProjectBadLayerHandler):
     """ This is a custom bad layer handler that would work as the default 
one, except it would automatically fix a specific layer that is broken. 
""" def __init__(self, path):
         QgsProjectBadLayerHandler.__init__(self)
         self.validLayerPath = path

     def handleBadLayers(self, domNodes):
         # Some logic to look for a specific DomNode to fix, oversimplified here: 
for domin domNodes:
             dataSource =self.dataSource(dom)

             if dataSourceis 'the broken path to the layer I want to fix':
                 # set correct data source then force re-read self.setDataSource(domNodes, self.validLayerPath)
                 QgsProject.instance().readLayer(dom)

         # TODO: after this, call the GUI file dialog as in the default bad layer 
handler, to allow the user to fix # any other broken layers... not sure 
how to do this class MyPlugin:
     """My plugin""" def __init__(self):
         self.validPath ='valid path to layer' self.badLayerHandler =None def hackyAndUglyReplacer(self, i, n):
         """ This hacky ugly function is to replace the bad layer handler early 
on, before any layers would be loaded. it is meant to be connected to 
the `layerLoaded` signal of `QgsProject` """ # do not run further if 
there were other layers loaded before (e.g. the signal was emitted 
before) if i !=0:
             return if not self.badLayerHandler:
             self.badLayerHandler = MyBadLayerHandler(self.validPath)
             QgsProject.instance().setBadLayerHandler(self.badLayerHandler)

     def initGui(self):
         # start-up code here... #connect to signal QgsProject.instance().layerLoaded.connect(self.hackyAndUglyReplacer)

     def unload(self):
         try:
             QgsProject.instance().layerLoaded.disconnect()
         except Exception:
             pass


Does anyone know what am I doing wrong here? Have I missed something?
Why does QGIS crash every 2nd time?

I would be happy to pass the bad layer handler a better way than with 
the current signal above. But the other signals I found are emitted 'too 
late' already.
Perhaps here I am also doing something wrong?

I tried looking for help but the web barely has any trace of 
documentation on this.

I also tried to see how this is done in other plugins e.g. the 
changeDataSource plugin, but the authors  seem to have removed the code 
when they ported the plugin to QGIS 3.x
(perhaps a bad sign)

In general it seems to me this part was also overhauled in QGIS3 but 
there aren't many leads to follow on what is the current way of using 
custom bad layer handlers.

Maybe if we could put the story together on how to do this correctly, I 
could document it and put it on the web for others to refer to.

Hope you are having / had a great Sunday!

Best regards,
Aron

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osgeo.org/pipermail/qgis-developer/attachments/20190721/2e034831/attachment.html>


More information about the QGIS-Developer mailing list