Re: [Qgis-developer] QgsMapLayerRegistry questions
Thanks Germán, your suggestion works great. Now I have the code up and running again! Cheers 2010/9/4 Germán Carrillo : > 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 > 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
Re: [Qgis-developer] QgsMapLayerRegistry questions
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.si...@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(Fals
[Qgis-developer] QgsMapLayerRegistry questions
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@lists.osgeo.org http://lists.osgeo.org/mailman/listinfo/qgis-developer