Gramplets
This page describes the technical details of Gramplets. If you are interested in using Gramplets, please see Gramps 3.0 Wiki Manual - Gramplets.
Contents
Gramplet Interface
A Gramplet is a type of GRAMPS plugin. A Gramplet is a mini-view that is designed to be composed with other Gramplets or Views to create a way to see your Family Tree that is just right for you. In fact, Gramplets can be made to do just about anything that you want. There are 6 main kinds of plugins:
- Reports: output for printing or display
- Tools: a method for processing data
- Quick View: a list of details based on the current object
- Importer: reads a file into your current tree
- Exporter: writes a file from your current tree
- Gramplets: interactive views for moving, analysing, displaying, etc.
There are two plugin directories: a global/system one, and a private/personal one. You can easily create a plugin by simply putting a file in your personal plugin directory (usually in .gramps/plugins).
Hello World
In teaching programming, a common "first program" is to write a program that says "Hello World". Let's jump right in and take a look at such a gramplet:
def init(gui): gui.set_text("Hello world!") from DataViews import register register(type="gramplet", name="Hello World Gramplet", tname="Hello World Gramplet", height = 20, content = init, title="Sample Gramplet", )
If you copy this text into a file in your plugins directory, and then either restart GRAMPS or go to Help -> Plugin Status -> Reload, the you'll be able to create this Gramplet. On the Gramplet View, right-click in an open area and select the "Hello World Gramplet". You should then see:
Explanation
The main work of a Gramplet is performed in a function, or a class. In this very simple example, a function init is defined that takes a single argument, gui. The function simply sets the gui's text area to be "Hello World!", and that's it. It does this just once, and never changes.
Before a plugin can be used, it needs to be "registered". The Gramplet interfaces uses a slightly different method for registering than the other plugins. Here, you import the "register" function from the DataViews module. Then you call the register function with a number of named-arguments. There are a number of named-arguments that you can provide, including: name, height, content, title, expand, state, and data. We will explore those in detail, below.
Hello World, with Class
Here is the same functionality again, but this time as a class:
from DataViews import register, Gramplet class HelloWorldGramplet(Gramplet): def init(self): self.set_text("Hello world!") register(type="gramplet", name="Hello World2 Gramplet", tname="Hello World Gramplet", height = 20, content = HelloWorldGramplet, title="Sample2 Gramplet", )
This is the recommended method of creating a Gramplet. The following details describe the properties and methods of this class.
Register Options
- type: the case-insensitive keyword "gramplet"
- name: the gramplet's name, unique among gramplets
- tname: the gramplet's name, translated
- height: the minimum or maximum height of the gramplet in normal mode
- content: the function or class name of your code
- title: the default gramplet title; user changeable
At the bare minimum, you need to have the above 6 options when registering your Gramplets.
In addition, you can use the following as well:
- detached_width: the size in pixels of the minimum and default detached height
- detached_height: the size in pixels of the minimum and default detached height
- expand: whether or not the Gramplet should expand to fill the column, if it can
Core Methods
- init(): run once, on construction
- main(): run once per update
- update(): don't change this, it calls main
- active_changed(): run when active-changed is triggered
- db_changed(): run when db-changed is triggered
- set_tooltip(TEXT) - tooltip for gramplet
Don't call main directly; use the update method.
In the db_changed method, you should connect all of the signals that will trigger an update. That typically looks like:
def db_changed(self): self.dbstate.db.connect('person-add', self.update) self.dbstate.db.connect('person-delete', self.update) self.dbstate.db.connect('person-update', self.update) self.dbstate.db.connect('family-add', self.update) self.dbstate.db.connect('family-delete', self.update) self.dbstate.db.connect('family-update', self.update)
Textual Output Methods
The most common kinds of Gramplets are text-based. There are a number of methods to assist with handling this text.
- set_text(TEXT) - clear and set text to TEXT
- append_text(TEXT, scroll_to=POSITION)
- POSITION is 'begin' (top), 'end' (bottom) or 'start' (start of append)
- clear_text() - clears all text
- set_use_markup(BOOLEAN-VALUE)
- render_text(TEXT) - for use with B, I, U, and TT tags
- link(TEXT, LINK-TYPE, DATA) -
- TEXT can be any text
- LINK-TYPE is:
- 'Person' - and DATA is a person handle
- 'PersonList' - and DATA is a list of handles
- 'Family' - and DATA is a family handle
- 'Surname' - and DATA is a person
- 'Given' -
- 'Filter' - and DATA is either:
- 'all people' -
- 'males' - all males
- 'females' - all females
- 'people with unknown gender' - people marked as unknown
- 'people with incomplete names' - people who have a missing surname or given name
- 'people with missing birth dates' - people who have missing birth dates
- 'disconnected people' - people with no parents and no children
- 'all families' - all families
- 'unique surnames' - list of all unique surnames
- 'people with media' - people who have media
- 'media references' - all of the media
- 'unique media' -
- 'missing media' - media for which the file does not exist
- 'media by size' -
- 'list of people'-
- 'URL' - and DATA is a URL
- 'WIKI' - and DATA is a wiki page
- 'Attribute' - and DATA is an attribute (eg, 'Nickname')
- no_wrap() - turn word wrap off
Using Tags
Tags are the manner in which you format the text.
tag = self.gui.buffer.create_tag("fixed") tag.set_property("font", "Courier 8") ... start, end = self.gui.buffer.get_bounds() self.gui.buffer.apply_tag_by_name("fixed", start, end) self.append_text("", scroll_to="begin")
GUI Interface
Occasionally, you might have to dive down to the graphical objects that compose a Gramplet.
- gui
- gui.buffer
- gui.textview
- gui.get_container_widget()
If you wanted to put an arbitrary gtk object into the main area of a Gramplet, then you need to replace the standard textview object with your own. Here is the basic structure:
from gettext import gettext as _ from DataViews import Gramplet, register import gtk class WidgetGramplet(Gramplet): def init(self): self.gui.WIDGET = gtk.WIDGET() self.gui.get_container_widget().remove(self.gui.textview) self.gui.get_container_widget().add_with_viewport(self.gui.WIDGET) self.gui.WIDGET.show() register(type="gramplet", name= "Widget Gramplet", tname=_("Widget Gramplet"), height=100, expand=False, content = WidgetGramplet, title=_("Widget"), )
In fact, with Python, gtk, and cairo, you can make your own widgets that do pretty much anything and look very nice. Here is an example adding a Cairo Clock (which really keeps time) to GRAMPS: ClockGramplet.zip
Here it is on the Gramplet view:
and detached:
GUI Options
- add_option(OPTION)
- OPTION is one of the menu options:
- NumberOption
- EnumeratedListOption
- StringOption
- ColorOption
- TextOption
- BooleanOption
- FilterOption
- PersonOption
- FamilyOption
- NoteOption
- MediaOption
- see src/gen/plug/menu/ for others
- OPTION is one of the menu options:
- build_options()
- save_options()
- get_option_widget(TEXT)
- get_option(TEXT)
Predifined Properties
There are a number of preset properties:
- dbstate
- dbstate.db
- dbstate.db.connect(SIGNAL, METHOD)
- dbstate.db.get_person_from_handle(HANDLE)
- dbstate.get_active_person()
- dbstate.db
- uistate
Persistance
- gui
- gui.data
- on_load()
- on_save()
- save_text_to_data()
- load_data_to_text()
Advanced Settings
- force_update: set True to have the gramplet update, even when minimized