Gramplets

From Gramps
Revision as of 06:44, 26 March 2010 by Romjerome (talk | contribs) (Hello World, with Class)
Jump to: navigation, search

This page describes the technical details of Gramplets. If you are interested in using Gramplets, please see Gramps 3.2 Wiki Manual - Gramplets.

Gramplet Interface

Gramplet

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:

  1. Reports: output for printing or display
  2. Tools: a method for processing data
  3. Quick View: a list of details based on the current object
  4. Importer: reads a file into your current tree
  5. Exporter: writes a file from your current tree
  6. 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 named HelloWorld.py:

def init(gui):
   gui.set_text("Hello world!")

Then an other python file named HelloWorld.gpr.py

register(GRAMPLET,
         id="Hello World Gramplet", 
         name=_("Hello World Gramplet"),
         description = _("a program that says 'Hello World'"),
         status = STABLE,
         version="0.0.1",
         fname="HelloWorld.py",
         height = 20, 
         gramplet = 'HelloWorldGramplet',
         gramps_target_version="3.2",
         gramplet_title=_("Sample Gramplet") 
         )

If you copy this files 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:

File:HelloWorldGramplet.png

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". 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:

class HelloWorldGramplet(Gramplet):
    def init(self):
        self.set_text("Hello world!")
register(GRAMPLET,
         id="Hello World2 Gramplet", 
         name=_("Hello World2 Gramplet"),
         description = _("a program that says 'Hello World'"),
         version="0.0.1",
         gramps_target_version="3.2",
         status = STABLE,
         fname="HelloWorld2.py",
         height = 20, 
         gramplet = 'HelloWorld2Gramplet',
         gramps_target_version="3.2",
         gramplet_title=_("Sample Gramplet") 
         )

This is the recommended method of creating a Gramplet. The following details describe the properties and methods of this class.

Register Options

  • id: the case-insensitive keyword "gramplet"
  • name: the gramplet's name (can be translated), unique among gramplets
  • height: the minimum or maximum height of the gramplet in normal mode
  • fname: the name of your file
  • title: the default gramplet title; user changeable
  • status: STABLE or UNSTABLE
  • version: a string with 2 dots (such as "1.23.14") representing the version number
  • gramps_target_version: a string with 2 dots representing the version of GRAMPS that this gramplet was written for

At the bare minimum, you need to have the above 8 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)

The method main() can be written as a normal Python method, or it can be written to run nicely in parallel with other GRAMPS code. To make it run nicely in parallel, you should issue a yield True every once in a while. For example:

    def main(self):
        for i in range(5000):
            if i % 500 == 0:
                yield True
        yield False

The True means that there is more to do; False means that there is nothing left to do.

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 A, B, I, U, and TT tags
    • A for creating links; use tag HREF="url" for URLs, and WIKI="name" for pages on the wiki
    • B for bold
    • I for italics
    • U for underlined
    • TT for a fixed-width, typewriter font
  • 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 DEPRECATED
  • set_wrap(BOOL) - change word wrap

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.addon.tgz

Here it is on the Gramplet view:

Clock on Gramplet View

and detached:

Clock Gramplet 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
  • 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()
  • 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

Learning More

To learn more about writing a Gramplet, it is suggested to look at the existing Gramplets. You can see a complete list of the Gramplet source code here:

Click on a filename, and then "(view)" to see the source code of that Gramplet.