Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow the definition of public interfaces for plugins #1370

Closed
wants to merge 2 commits into from

Conversation

m-kuhn
Copy link
Member

@m-kuhn m-kuhn commented May 19, 2014

As an example, the method syncExtent() from the globe plugin can be called from python.

# Needs to be done before calling pluginInterface()
from qgis import globe

glb = iface.pluginInterface( 'libglobeplugin' ) # On windows it's just 'globeplugin'
glb.syncExtent()

Question: should a "lib" prefix be stripped away for platform independence?

This is particularly interesting to get access to functionality from python
To make use of it:

from qgis import globe

glb = iface.pluginInterface( 'libglobeplugin' ) # On windows it's just 'globeplugin'
glb.syncExtent()
@wonder-sk
Copy link
Member

Hi Matthias

so if I understand the PR correctly, this adds the possibility to implement QgsPluginInterface interface within plugins and thus allow third parties to access some of the plugin's functionality. In order to access the functionality, in C++, one needs access to plugin's header file, in Python there has to be a sip-based module.

Throwing in some ideas...

I am wondering if we couldn't use QObject introspection with QMetaObject when working with plugin interface objects. The introspection allows us to find out what are instance's signals, slots and properties. At least in Python, a helper could automatically add appropriate Python methods and properties. This would avoid the need to deliver also additional SIP modules and plugin headers. Additionally, IIRC on Mac there are problems if a plugin is used both as a shared library and as a plugin (in CMake SHARED vs MODULE argument for ADD_LIBRARY) - for that GRASS provider+plugin come with qgis-grass library which contains common code used by both provider and plugin.

In case we would decide for QObject-based approach, instead of having explicit plugin interface classes, the QgisInterface could allow registration of custom QObject instances with a known name. That could be then used also by some other parts of QGIS application (which are not exposed in API) to exposes some functionality.

In the future, for globe plugin, it would be good to actually have qgis 3D library that would provide the functionality that could be expected from the plugin interface. But I understand that would mean a lot of work :-)

@mhugent
Copy link
Contributor

mhugent commented Jun 2, 2014

assigned to @wonder-sk

@m-kuhn
Copy link
Member Author

m-kuhn commented Jun 3, 2014

Hi Martin,

I don't know if the QObject based approach you propose works, I don't have the experience to answer this question, so I cannot comment on the feasibility.

How would you handle custom classes required by the plugin interface? As soon as there is no simple interface with only basic setters and getters using primitive datatypes or pyqt datatypes there is the need for further header files / sip bindings anyway.

Couldn't being forced to use the signal/slot/properties system also add an overhead which can result in a performance impact (or other undesired effects)?

IMO, if somebody wants this type of ducktyping support for his objects, he can just write a python plugin and it will do all that. If there is a C++ plugin written, I prefer to keep it the C++ way where headers need be provided in order to use the code, compiler, IDE etc. are all built to support this style of development.

@wonder-sk
Copy link
Member

How would you handle custom classes required by the plugin interface? As soon as there is no simple interface with only basic setters and getters using primitive datatypes or pyqt datatypes there is the need for further header files / sip bindings anyway.

True, with the need to provide wrappers for further data types it would get more complicated. My feeling is that if there is a need to export some classes, this is best done by adding the classes to one of QGIS libraries. For example, if we wanted to provide georeferencer functionality outside of the plugin, the best idea would be to move the code to the analysis library and provide wrappers there. The plugin interface (if still needed) could then just provide access to the "live" instance.

My inspiration comes mainly from QML - as far as I understand, objects there are based on QObject and the interaction is done with properties, signals and slots.

Couldn't being forced to use the signal/slot/properties system also add an overhead which can result in a performance impact (or other undesired effects)?

I assume the overhead is practically non-existent unless one would do millions of calls... I have no data to confirm that though :-)

@m-kuhn
Copy link
Member Author

m-kuhn commented Jun 3, 2014

What about third-party libs on which plugins depend?
E.g.
For osg/osgearth, I have written some sip-wrappers for internal datastructures. I don't think we would want these neither in one of the libraries sourcecodes nor am I sure that they will be accepted and don't have the time to invest to get them accepted upstream.
To get them through QObject style classes this would mean to wrap them into QVariants to get this done?
For things like this it is indeed possible to get millions of calls (e.g. implementing some rendering callbacks).

PS: I am not sure if I will ever integrate these wrappers, but they serve as a good example.

@wonder-sk
Copy link
Member

There's always trouble with third-party libs :-) If we needed to pass pointer to some instances of their classes, It should be fairly easy to pass the pointers through QVariant. That way the client may also use the API directly (now talking about C/C++).

But it is also worth noting that if we provide a plugin interface for such third-party data structures, we are effectively making them a part of our API, because any other plugin then may start using that functionality (even if technically it is not a part of QGIS libraries).

@m-kuhn
Copy link
Member Author

m-kuhn commented Jun 3, 2014

And QVariant adds more overhead again. And you need to start casting and checking if the cast went ok. I like the compiler way of checking at build time and letting me know that I'm a moron if I try to pass class A when it expects class B. Another problem with QVariant is, that it's not perfect in terms of subclassing. If you have subclass B inheriting from subclass A, and you wrap an object of B in a QVariant and on the other end retrieve the value as A, the conversion will fail. It's not hard to work around this, but it's a possible source of problems and you need to write code that deals with situations, that the compiler could check in well-written code in a language like C++.

What's the main drawback of my proposed approach again?

  • Need to write .h and .sip files.
  • Mac OS X shared lib problems (is this a real problem?)

I personally don't consider the first one to be a drawback, but a different approach, more C++ like by declaring the interface (and this PR only applies to C++ plugins) in a header file.
As I never work with Mac OS X, I can't say anything about the second one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants