[Qgis-developer] QgsMapLayerRegistry questions

Ricardo Filipe Soares Garcia da ricardo.garcia.silva at gmail.com
Sun Sep 5 09:43:37 EDT 2010


Thanks Germán, your suggestion works great.
Now I have the code up and running again!

Cheers

2010/9/4 Germán Carrillo <carrillo.german at gmail.com>:
> Hi Ricardo,
> what if you use the legendInterface class for getting the loaded layers?
> Try this (in the Python console):
> -------------------------------------------------------
> from PyQt4.QtCore import SIGNAL
> q = qgis.utils.iface
> l = q.legendInterface()
> def f( layerId ):
> for i in l.layers():
> print i.name(), i.geometryType()
> q.connect( QgsMapLayerRegistry.instance(), SIGNAL(
> "layerWillBeRemoved(QString)" ), f )
> -------------------------------------------------------
> I'm not sure it works if the user starts a new project...
> Regards,
> Germán
>
> On Sat, Sep 4, 2010 at 7:53 AM, Ricardo Filipe Soares Garcia da
> <ricardo.garcia.silva at gmail.com> wrote:
>>
>> Hi list
>>
>> I'm trying to toggle my plugin's availability based on the presence or
>> absence of loaded vector layers of type 'line'.
>> For this purpose I have a _get_loaded_layers() and a
>> toggle_availability() methods (code follows in the end of this
>> message).
>>
>> After searching the online API docs, it seems that the
>> QgsMapLayerRegistry class is the one that notifies the rest of the
>> application about layers being added or removed.
>> So I connect my plugin's toggle_availability() method to the
>> layerWasAdded() and layerWillBeRemoved() signals of the
>> QgsMapLayerRegistry.instance() object.
>>
>> When the user adds a new layer everything goes fine, my plugin's
>> availability is toggled based on the presence of vector lines,
>> including the new layer that was added.
>> Also, if the user removes just one layer at a time, everything works
>> as expected as well.
>>
>> Unfortunately, when several layers are removed at the same time (for
>> example, if the user had an open project and decides to create a new
>> one), my plugin is causing Qgis to segfault (very ugly!).
>>
>> It seems to be connected to what is happening with the
>> QgsmapLayerRegistry instance when the layerWillBeRemoved() signal is
>> emmited repeatedly. It seems to me that I am crashing Qgis because I
>> am trying to call QgsMapLayerRegistry.instance().mapLayers() while the
>> layers are being deleted... and that causes the segfault.
>> I don't know what happens to the mapLayerRegistry instance, but its
>> mapLayers() method seems to be the source of the error.
>>
>> Reading the pyQgis cookbook, I realized that when layers are removed
>> from the mapLayerRegistry they are also deleted from Qgis, which seems
>> a bit inconsistent, compared with the loading procedure. What I mean
>> is, if layers can be loaded without being automatically added to the
>> mapLayerRegistry, maybe they could also be removed from the
>> mapLayerRegistry without being deleted from Qgis (Maybe this is the
>> reason for having a layerWillBeRemoved() signal instead of a
>> layerWasRemoved()?).
>>
>> Anyway, I don't understand why it works OK if layers are removed one
>> at a time and not if they all get removed.
>> I've tried to use the QgsMapLayerRegistry.removedAll() signal to catch
>> those situations when all layers get removed at once. It does work,
>> but the problem is that the QgsMapLayerRegistry.layerWillBeRemoved()
>> is still geting called at the same time and will crash Qgis.
>>
>> So, I'd like to request your help in determining the best way to be
>> notified when a layer is removed from the map canvas.
>>
>> Thanks
>>
>> #(python code follows)
>>
>>
>> def initGui(self):
>>        self.action = QAction(QIcon(":/plugins/ProfileFromLine/icon.png"),
>> \
>>            "Profile from line", self.iface.mainWindow())
>>        self.toggle_plugin_availability()
>>        QObject.connect(self.action, SIGNAL("activated()"), self.run)
>>        self.iface.addToolBarIcon(self.action)
>>        self.iface.addPluginToMenu("&Profile from line", self.action)
>>        QObject.connect(self.layerRegistry,
>> SIGNAL("layerWasAdded(QgsMapLayer *)"),
>> self.toggle_plugin_availability)
>>        QObject.connect(self.layerRegistry,
>> SIGNAL("layerWillBeRemoved(QString)"),
>> self.toggle_plugin_availability)
>>
>>
>> def _get_loaded_layers(self):
>>        availableLayers = {"vectorLine" : [], "raster" : []}
>>        loadedLayers = self.layerRegistry.mapLayers()
>>        for layer in loadedLayers.itervalues():
>>            layerType = layer.type()
>>            if layerType == 0: # it's a vector layer
>>                if layer.geometryType() == 1: # it's a line
>>                    availableLayers["vectorLine"].append(layer)
>>            elif layerType == 1: #it's a raster layer
>>                availableLayers["raster"].append(layer)
>>        return availableLayers
>>
>> def toggle_plugin_availability(self, arg=None):
>>        print("toggle_plugin_availability method called")
>>        numLinesLayers = len(self._get_loaded_layers()["vectorLine"])
>>        if numLinesLayers == 0:
>>            self.action.setEnabled(False)
>>        elif numLinesLayers == 1 and type(arg) == QString:
>>            layerAboutToGo = self.layerRegistry.mapLayer(arg)
>>            if layerAboutToGo.type() == 0:
>>                if layerAboutToGo.geometryType() == 1:
>>                    self.action.setEnabled(False)
>>
>>
>>
>> --
>> ___________________________ ___ __
>> Ricardo Garcia Silva
>> _______________________________________________
>> Qgis-developer mailing list
>> Qgis-developer at lists.osgeo.org
>> http://lists.osgeo.org/mailman/listinfo/qgis-developer
>
> --
> -----------
>   |\__
> (:>__)(
>   |/
>
> Soluciones Geoinformáticas Libres
> http://geotux.tuxfamily.org/
>



-- 
___________________________ ___ __
Ricardo Garcia Silva


More information about the Qgis-developer mailing list