On Tue, 23 Jul 2019 at 00:58, Áron Gergely <aron.gerg...@rasterra.nl> wrote:
>
>
>
> On 22/07/2019 01:11, Nyall Dawson wrote:
> > On Sun, 21 Jul 2019 at 21:16, Áron Gergely<aron.gerg...@rasterra.nl>  wrote:
> >
> >> 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.
> > Couldn't you achieve the same result by setting your bad layer handler
> > directly in initGui?
> No, for some strange reason the bad layer handler would not get assigned
> when I tried within initGui.
> I tried to find out why by looking at debug messages on qgis launch,
> reading the source code,
> but it is a lot to take in with my rusty C skills so I have not found
> the answer.


Ehhhh- right. The built-in handler is set AFTER plugins are loaded, so
it wipes out any custom handler implemented by a plugin! I think this
is a bug -- as it makes that API call rather useless. PR inbound.


> But I reckoned it may be due to the plugin being loaded before a
> QgsProject singleton would be initialized.
> >> # 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
> > The bad news is -- unfortunately you cannot. The inbuilt bad layer
> > handler isn't exposed to Python in any way, and as soon as you set a
> > new bad layer
> > handler method the existing inbuilt one is completely deleted.
> Understood - if that part is not exposed to the python API then I will
> not pursue the above. Thanks for letting me know!

Well, it's possible we could work around this by NOT deleting the
inbuilt one when a new one is set. But honestly, I think your use case
is better server by my proposed API addition.


> Thanks for your insight Nyall!
> Sounds bad with that IT Department. :(
>
> But yes, I think that would be helpful. (I wonder who else hit a wall
> with the broken paths? )

I suspect lots of people. Personally, as a user, everytime I see that
dialog popup a little bit dies inside of me...

> Although my problem (or rather, our problem with Raymond) is similar but
> not exactly the same:

Nope - it IS the same ;) You can see it in
https://github.com/qgis/QGIS/pull/30842

> We created a plugin that helps to achieve consistent map layouts: the
> plugin itself ships with the correct resources (logos, symbols, and a
> world map layer)
> for specific map layouting tasks and has a simple workflow via dialogs
> that creates the right layouts which the users would fill in or adapt to
> meet their needs.
>
> The problem is that since we ship the resources with the plugin, the
> resource paths are on the plugin path which is different across machines.
> So when users create map layouts, save the project file and pass it to
> another user to work on they see missing items and broken layer path,
> even though they have the plugin installed.

So what you would do here is implement a custom pre-processor which
detects some hardcoded path to the plugin resource, and swaps it out
with the actual path to the python plugin. E.g.

def my_processor(path):
   if path.endswith('my_plugins_super_north_arrow.svg'):
      return os.path.join(os.path.dirname(__file__),
'resources/my_plugins_super_north_arrow.svg')
   return path

QgsPathResolver.setPathPreprocessor(my_processor)

Basically - whenever a path ending in
'my_plugins_super_north_arrow.svg' is requested, it gets (silently)
modified to point to a subfolder off your plugin's actual runtime
location. You'd just need to make sure the intercepted resources have
a distinct enough name to not clash with other (non-plugin) paths!
(e.g. don't just check for "north_arrow.svg"!).


Nyall



> On the longer term we believe it would be good to have a resource
> sharing system that is native to QGIS.
> That would make it very easy to share resources for plugins as well,
> without needing to instruct the users to get the resource sharing
> plugin, connect to resource repo X and pull resources a, b, c,... and so on.
>
> I had discussions about this with Raymond and we are looking to write a
> QEP about 'native' resource sharing.
>
> We might as well be able to live without a solution for now, as native
> resource sharing would answer our needs best.
>
> Best regards,
> Aron
> >> 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 dom in domNodes:
> >>              dataSource = self.dataSource(dom)
> >>
> >>              if dataSource is '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
> >>
> >> _______________________________________________
> >> QGIS-Developer mailing list
> >> QGIS-Developer@lists.osgeo.org
> >> List info:https://lists.osgeo.org/mailman/listinfo/qgis-developer
> >> Unsubscribe:https://lists.osgeo.org/mailman/listinfo/qgis-developer
>
_______________________________________________
QGIS-Developer mailing list
QGIS-Developer@lists.osgeo.org
List info: https://lists.osgeo.org/mailman/listinfo/qgis-developer
Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-developer

Reply via email to