Opened 14 years ago

Closed 14 years ago

Last modified 14 years ago

#2392 closed patch (fixed)

Plugin layer registry

Reported by: mwalker Owned by: wonder
Priority: major: does not work as expected Milestone:
Component: Python plugins and bindings Version: Trunk
Keywords: plugin layer Cc: pka
Must Fix for Release: No Platform: All
Platform Version: Awaiting user input: no

Description

This patch adds a plugin layer registry to support plugin specific maplayers.

Plugins can register a function that creates the specific subclass of QgsMapLayer. This allows to instantiate the corresponding plugin layer when reading the project file.

Workflow

see sample plugin for details

  • create subclass of QgsMapLayer
    • implement isEditable(), draw() and writeXml()
  • create subclass of QgsPluginLayerCreator
    • implement createLayer() e.g. as callback to a plugin function
  • init plugin
    • register PluginLayerCreator using QgsPluginLayerRegistry.instance().addCreator()
  • add layer
    • create PluginMapLayer instance of layer type QgsMapLayer.PluginLayer
    • add layer using QgsMapLayerRegistry.instance().addMapLayer()
  • save project
    • calls PluginMapLayer.writeXml()
    • save plugin id string as attribute "type"
  • load project
    • QgsPluginLayerRegistry calls createLayer() for all registered QgsPluginLayerCreators
    • plugin creates and adds a new PluginMapLayer instance if the attribute "type" matches their id string
  • unload plugin
    • unregister PluginLayerCreator using QgsPluginLayerRegistry.instance().removeCreator()

Attachments (3)

enh2392_plugin_layer_registry.diff (10.6 KB ) - added by mwalker 14 years ago.
Plugin layer registry patch
enh2392_sample_layer_plugin.tar.gz (5.3 KB ) - added by mwalker 14 years ago.
Sample layer plugin
sample_layer_plugin_updated.tar.gz (7.1 KB ) - added by wonder 14 years ago.
plugin compatible with implementation in trunk

Download all attachments as: .zip

Change History (8)

by mwalker, 14 years ago

Plugin layer registry patch

by mwalker, 14 years ago

Sample layer plugin

comment:1 by trapanator, 14 years ago

+1

very interesting patch!

comment:2 by lutra, 14 years ago

Type: enhancementpatch

comment:3 by mhugent, 14 years ago

Owner: changed from borysiasty to wonder

Martin, do you have time to review this patch?

comment:4 by lutra, 14 years ago

Resolution: fixed
Status: newclosed

applied in r12834

comment:5 by wonder, 14 years ago

Applied in r12834 with several modifications:

  • plugin layers are subclassed from QgsPluginLayer and not directly from QgsMapLayer for convenience
  • each plugin layer type has its unique name used in QgsPluginLayerRegistry - instead of dynamically assigned IDs
  • layer creator has been enhanced to return the unique layer type name and to be able to open layer's properties dialog (and renamed to QgsPluginLayerType as it's not just a creator)
  • simplified creation of plugin layers: for the unique type name the registry returns instance of the layer
  • when the plugin layer type is removed from registry, layer of that type are removed automatically

I've modified also the sample plugin to reflect my changes.

Sample plugin from the example:

LAYER_TYPE = "sample"

class SamplePluginLayer(QgsPluginLayer):
  def __init__(self, width=None):
    QgsPluginLayer.__init__(self, LAYER_TYPE, "Sample plugin layer")

    self.width = width if width is not None else 256
    self.setValid(True)

  def draw(self, rendererContext):
    painter = rendererContext.painter()
    painter.setPen(Qt.red)
    painter.drawRect(32, 32, self.width, 128)
    return True

  def readXml(self, node):
    self.width = node.toElement().attribute("width", "256").toInt()[0]
    return True

  def writeXml(self, node, doc):
    element = node.toElement()
    # write plugin layer type to project (essential to be read from project)
    element.setAttribute("type", "plugin")
    element.setAttribute("name", LAYER_TYPE)
    # custom properties
    element.setAttribute("width", str(self.width))
    return True

Definition of the layer's type with auxiliary methods:

class SamplePluginLayerType(QgsPluginLayerType):
  def __init__(self):
    QgsPluginLayerType.__init__(self, LAYER_TYPE)

  def createLayer(self):
    return SamplePluginLayer()

  def showLayerProperties(self, layer):
    res = QInputDialog.getInt(None, "Sample plugin", "Set width of the rectangle", layer.width, 1, 1000)
    if res[1]: # dialog was not cancelled
      layer.width = res[0]
      # trigger repaint
      layer.setCacheImage(None)
      layer.emit(SIGNAL("repaintRequested()"))

    # indicate that we have shown the properties dialog
    return True

Registration:

    QgsPluginLayerRegistry.instance().addPluginLayerType( SamplePluginLayerType() )

Creation of the layer:

layer = SamplePluginLayer()
# -or-
QgsPluginLayerRegistry.instance().pluginLayerType(LAYER_TYPE).createLayer()

Finalization:

    QgsPluginLayerRegistry.instance().removePluginLayerType(LAYER_TYPE)

by wonder, 14 years ago

plugin compatible with implementation in trunk

Note: See TracTickets for help on using tickets.