A plugin is an extension module which can be loaded at runtime. It adds new functionality to Snowberry. The plugins are independent and can consist of one or more Python modules.
This article also describes guidelines of Snowberry's design. You get a general overview on the modules and plugins of Snowberry, and we also offer you a tutorial for making plugins to add Snowberry your own functionality.
The main idea was to make Snowberry easy to extend and customize. Python offers a possibility to load plugins at runtime making it easy to fulfill the extensibility requirement. Python has also some other advantages like effortless portability, readability of code and good documentation.
The basis for the system architecture is a combination of plugin and MVC architectures. The program has been divided into modules and plugins where modules create a kind of a frame for the plugins. More information can be found in the API documentation of Snowberry. [Apidoc]
There are 12 modules which are located in your system-specific folder <SYSTEM> [6.1]:
The seven original plugins of Snowberry are located in both <SYSTEM>/plugins and <HOME>/plugins. The plugins are loaded in alphabetical order – that the reason for the naming of the tabs:
Generally speaking the plugins act as independent controllers which, by using the modules, take care of the appearance of the UI presented by ui.py. The internal communications of the application is implemented using the services offered by events.py. A more precise information about the interfaces that the modules and plugins offer is available in the API Documentation of Snowberry. [Apidoc]
Creating Python plug-ins is a rather straightforward process. This section describes the things you need to know to create functioning Snowberry plug-ins. Snowberry assumes all the plug-ins to be valid Python code and reside under folder named plugins in your Snowberry installation directory.
First of all, you should decide a name for your plug-in. The name of the file is important in a sense that Snowberry looks in and loads (in runtime) the files and directories in an alphabetical order. From these files Snowberry then loads the possible user interface widgets to be shown in the application when appropriate. Snowberry plugins folder already contains some built-in plugins you can examine as examples how to create plug-ins and to acquire some insight how they interact with the rest of the system. Of course, you should decide in beforehand the functionality your plug-in is going to add to Snowberry.
Snowberry (ui.py) doesn't encourage the plug-ins to place their user interface widgets explicitly but places them in the order they have been read in to the system. It is possible to explicitly place the widgets, but in general not encouraged. Placing the parts explicitly by yourself it is very likely you wreck the layout algorithm and data structures ui.py uses to manage the user interface. Thus, allowing the whole user interface to become unreadable. Moreover, if you won't use the widgets provided by widgets.py, you are not able to get the benefits of automatically updating the user interface when language settings have been changed.
As described earlier, Snowberry loads the plug-ins in an alphabetical order at runtime. Your plug-in should be placed in a separate folder of its own with a name followed by a dot and an extension “plugin”. There is an example plug-in coming with the standard Snowberry distribution, “example.plugin”. Each and every plug-in bundle should include a sub-folder called contents, in which are placed the actual Python code modules the addon is supposed to provide. Another sub-folder each plug-in should include is conf, which includes the configuration data and other resources the plug-in might have.
The same rules apply to these Python modules as to the addons in general; they shall be loaded in an alphabetical order.
To be effectively loaded, every plug-in that is placed in the plugins directory must have a method called init. Init doesn't take any arguments and it doesn't return anything. It should contain all the necessary initialization code setting up the plug-in to function properly. Usually this means creating the widgets to be displayed and registering the callback functions that implement the handling of events and notifications received from the system. Snowberry uses only events and notifications to broadcast system-wide happenings.
To actually create the widgets and register your event and notification handlers, you have to import the appropriate modules ui.py and events.py, respectively.
If you don't register to listen to events or notifications from the system, your plug-in isn't aware of the happenings in the rest of the system. Also, events.py is used to notify the rest of the system regarding global events taking place in your module.
You should remember creating all of your widgets through ui.py and the interface it exposes. This is done by requesting a part of a user interface from ui.py and using this part to load the widgets. In the following there is some short code snippets taken from tab1_summary.py that will demonstrate the basic functionality of any widget.
In the very first lines of code after the copyright information you can find lines like the following:
import string import ui, events import profiles as pr import addons as ao import language
As you can see, there are several other modules loaded besides just those ui.py and events.py described earlier. The next lines initialize the user interface:
area = ui.createTab(SUMMARY)
This creates a summary tab to the tab area. You'll notice this when running Snowberry. The next lines are usually something like these:
area.setBorder(6) area.setWeight(0) global titleLabel titleLabel = area.createText(//)// titleLabel.setTitleStyle() area.createLine()
They are setting up the user interface widgets and formatting them. The last line in the init function adds the notify listener of this module:
If there were a command listener also, it would be called like this:
The rest of the code deals with the actual code for handling the internal plug-in functionality. One thing you should remember is that if you change some of the visible parts of the user interface, you'll have to call the function updateLayout() in ui.py for you specific area to update the layout (so that the end user can see the updates).
Sending events would be done calling function send() or sendAfter() in events.py. Both of these functions take an event or a notification as their parameter. The difference is that by calling send you allow the events to be sent immediately to all of the registered listeners. SendAfter() sends the events after all of the registered listeners have been delivered the previously sent event.
These are the actual main lines of creating plug-ins to Snowberry. You can easily find out more information in the plugins folder by taking a look at the code in plugins already contained there