[Qgis-developer] QgsMapLayerRegistry questions

Ricardo Filipe Soares Garcia da ricardo.garcia.silva at gmail.com
Sat Sep 4 08:53:18 EDT 2010


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


More information about the Qgis-developer mailing list