gramps/doc/extending-gramps/C/extending-gramps.sgml
Donald A. Peterson 74281f9833 New id tags for a happy db2html
svn: r879
2002-03-30 03:43:27 +00:00

775 lines
27 KiB
Plaintext

<!DOCTYPE article PUBLIC "-//GNOME//DTD DocBook PNG Variant V1.1//EN"[
<!ENTITY version "0.5.0"> <!-- replace with application version -->
]>
<!-- =============Document Header ============================= -->
<article id="index"> <!-- please do not change the id -->
<artheader>
<title>Writing Extentions for gramps</title>
<copyright>
<year>2001</year>
<holder>Donald N. Allingham</holder>
</copyright>
<!-- translators: uncomment this:
<copyright>
<year>2001</year>
<holder>ME-THE-TRANSLATOR (Latin translation)</holder>
</copyright>
-->
<!-- do not put authorname in the header except in copyright - use
section "authors" below -->
<!-- Use this legal notice for online documents which depend on -->
<!-- core GNOME packages. -->
<legalnotice id="legalnotice">
<para>
Permission is granted to copy, distribute and/or modify this
document under the terms of the <ulink type="help"
url="gnome-help:fdl"><citetitle>GNU Free Documentation
License</citetitle></ulink>, Version 1.1 or any later version
published by the Free Software Foundation with no Invariant
Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy
of the license can be found <ulink type="help"
url="gnome-help:fdl">here</ulink>.
</para>
<para>
Many of the names used by companies to distinguish their products
and services are claimed as trademarks. Where those names appear
in any GNOME documentation, and those trademarks are made aware to
the members of the GNOME Documentation Project, the names have
been printed in caps or initial caps.
</para>
</legalnotice>
<!-- Use this legal notice for documents which are placed on -->
<!-- the web, shipped in any way other than online documents -->
<!-- (eg. PS, PDF, or RTF), or which do not depend on the -->
<!-- core GNOME distribution. -->
<!-- -->
<!-- If you use this version, you must place the following -->
<!-- line in the document declaration at the top of your -->
<!-- document: -->
<!-- <!ENTITY FDL SYSTEM "fdl.sgml"> -->
<!-- and the following line at the bottom of your document -->
<!-- after the last </sect1>. -->
<!-- &FDL; -->
<!--
<legalnotice id="legalnotice">
<para>
Permission is granted to copy, distribute and/or modify this
document under the terms of the <link linkend="fdl"><citetitle>GNU
Free Documentation License</citetitle></link>, Version 1.1 or any
later version published by the Free Software Foundation with no
Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license can be found in <xref linkend="fdl">.
</para>
<para>
Many of the names used by companies to distinguish their products
and services are claimed as trademarks. Where those names appear
in any GNOME documentation, and those trademarks are made aware to
the members of the GNOME Documentation Project, the names have
been printed in caps or initial caps.
</para>
</legalnotice>
-->
<!-- This is the manual version, not application version. -->
<releaseinfo>
This is version 1.0 of the Writing Extentions for gramps manual.
</releaseinfo>
</artheader>
<!-- ============= Introduction ============================== -->
<sect1 id="intro">
<title>Introduction</title>
<para>
<application>gramps</application> was intended from the start to
allow the user to extend it through a plugin system. Five types of
plugins are supported - filters, reports, tools, import filters,
and export filters. In a way, an export filter can be viewed as a
special type of report, and an import filter can be viewed as a
special type of tool.
</para>
<para>
All plugins are written in the <application>python</application>
language.
</para>
<sect2 id="intro-filter">
<title>Filters</title>
<para>
A filter is a plugin that be used to temporarily display or hide
individuals in the <interface>People View</interface>. The
filter is the simplest form of plugin, which only needs to
determine if a person meets or fails to meet its criteria. It
operates on a single person at a time.
</para>
<para>
Filters should never alter a database.
</para>
</sect2>
<sect2 id="intro-report">
<title>Reports</title>
<para>
A report is a plugin that generates output. The output may be in
either a interactive, graphical form, or as an output
file. Report plugins are passed a reference to the internal
database and a reference to the active person, which allows the
plugn to operate on a single person, the entire database, or
anything in between.
</para>
<para>
Plugins that conform to the reportplugin interface appear in the
<menuchoice>
<guimenu>Reports</guimenu>
</menuchoice>
menu and in the <interface>Report Selection</interface> dialog
box.
</para>
<para>
A report should never alter the database.
</para>
</sect2>
<sect2 id="intro-tool">
<title>Tools</title>
<para>
A tool is a plugin that alters the database. It may perform
something as small changing the case of some text to something
as complex as merging redundant individuals. Tools plugins are
passed a reference to the internal database, the active person,
and a callback function. The callback function is used to notify
the main program if it needs to update the display with any
modified information.
</para>
<para>
Plugins that conform to the tool plugin interface appear in the
<menuchoice>
<guimenu>Tools</guimenu>
</menuchoice>
menu and in the <interface>Tool Selection</interface> dialog
box.
</para>
<para>
A tool is allowed (and usually expected) to alter the database.
</para>
</sect2>
<sect2 id="intro-import">
<title>Import Filters</title>
<para>
An import filter is a plugin that adds information from another
source to the database. It is similar to a tool, but is called
differently to allow gramps to distinguish it from a tool.
</para>
<para>
Plugins that conform to the import filter calling syntax appear
in the
<menuchoice>
<guimenu>File</guimenu>
<guisubmenu>Import</guisubmenu>
</menuchoice>
menu.
</para>
<para>
An import filter is allowed to modify the database.
</para>
</sect2>
<sect2 id="intro-export">
<title>Export Filters</title>
<para>
An export filter is a plugin that translates the gramps database
into the format expected by another program. Since it generates
an output file, it is similar to a report generator. However,
its calling syntax is different, so that gramps knows how to
distiguish it from a report generator.
</para>
<para>
Plugins that conform to the export filter calling syntax appear
in the
<menuchoice>
<guimenu>File</guimenu>
<guisubmenu>Export</guisubmenu>
</menuchoice>
menu.
</para>
<para>
An export filter should not alter the database.
</para>
</sect2>
</sect1>
<!-- ============= Writing Filters ============================= -->
<sect1 id="writingfilters">
<title>Writing Filters</title>
<para>
Users can create their own filters and add them to
<application>gramps</application>. By adding the filter to the
user's private filter directory (<filename
class="directory">~/.gramps/filters</filename>), the filter will
be automatically recognized the next time that the program is
started.
</para>
<sect2 id="createfilter">
<title>Creating a filter</title>
<para>
Each filter is a class derived from the
<function>Filter.Filter</function> class. The
<function>__init__</function> task may be overridden, but if so,
should call the <function>__init__</function> function on the
<function>Filter.Filter</function> class. The parent class
provides the variable <function>self.text</function>, which
contains the text string passed as the qualifier. This string
provides additional information provided by the user. For
example, if the filter is used to match names, the qualifier
would be used to provide the name that is being compared
against.
</para>
<para>
All filter classes must define a <function>match</function>
function. The function takes one argument (other than
<function>self</function>), which is an object of type
<function>Person</function> to compare against. The function
should return a 1 if the person matches the filter, or a zero if
the person does not.
</para>
<para>
Each filter must be registered, so that
<application>gramps</application> knows about it. This is
accomplished by calling the
<function>Filter.register_filter</function> function. This
function takes three arguments - the filter class, a
description, and flag that indicates if the qualifier string is
needed. The description string appears in the pull down
interface within <application>gramps</application>, and helps
the user choose the appropriate filter. The qualifier flag tells
<application>gramps</application> whether or not the filter
needs a qualifier string. If this flag is 0,
<application>gramps</application> will disable the entry of a
qualifier string.
</para>
<figure id="filtersrc">
<title>Sample filter implementation</title>
<programlisting>
import Filter
import string
# class definition
class SubString(Filter.Filter):
def match(self,person):
name = person.getPrimaryName().getName()
return string.find(name,self.text) >= 0
Filter.register_filter(SubString,
description="Names that contain a substring",
qualifier=1)
</programlisting>
</figure>
</sect2>
</sect1>
<!-- ============= Writing Reports ============================= -->
<sect1 id="writingreports">
<title>Writing Reports</title>
<para>
Users can create their own report generators and add them to
<application>gramps</application>. By adding the report generator
to the user's private plugin directory (<filename
class="directory">~/.gramps/plugins</filename>), the report
generator will be automatically recognized the next time that the
program is started.
</para>
<sect2 id="createreport">
<title>Creating a report generator</title>
<para>
Fewer restrictions are made on report generators than on
filters. The report generator is passed the current
<application>gramps</application> database and the active
person. The generator needs to take special care to make sure
that it does not alter the database in anyway.
</para>
<para>
A report generator is a function that takes two arguments
&mdash; a database (of type <function>RelDataBase</function>)
and the currently selected person (of type
<function>Person</function>). When called, this task should
generate the desired report.
</para>
<para>
This function's implementation can be as simple as generating
output without the user's intervention, or it could display a
graphical interface to allow the user to select options and
customize a report.
</para>
<para>
As with filters, the report generator must be registered before
<application>gramps</application> will understand it. The report
generator is registered using the
<function>Plugins.register_report</function>. This function
takes five arguments.
</para>
<itemizedlist>
<listitem>
<para>
<guilabel>The report generation task</guilabel> This task
that generates the report.
</para>
</listitem>
<listitem>
<para>
<guilabel>The report category</guilabel> The category in
which the report is grouped in the
<menuchoice><guimenu>Reports</guimenu></menuchoice> menu and
in the <interface>Report Selection</interface> dialog.
</para>
</listitem>
<listitem>
<para>
<guilabel>The report name</guilabel>
The name of the report.
</para>
</listitem>
<listitem>
<para>
<guilabel>A text description of the report</guilabel> The
description appears in the report selection tool to provide
the user with a description of what the tools does.
</para>
</listitem>
<listitem>
<para>
<guilabel>A graphic logo in XPM format</guilabel> This may
be either a path to a filename, or a list of strings
containting the XPM data. If a filename is specified, care
must be taken to make sure the file location is relocatable
and can be determined at runtime.
</para>
</listitem>
</itemizedlist>
<para>
While only the task and report name are required, it is
recommended to provide all five parameters.
</para>
<figure id="reportsrc">
<title>Sample report implementation</title>
<programlisting>
import Plugins
def report(database,person):
... actual code ...
Plugins.register_report(
task=report,
category="Category",
name="Report Name",
description="A text descripition of the report generator",
xpm="%s/myfile.xpm" % os.path.dirname(__file__)
)
</programlisting>
</figure>
</sect2>
<sect2 id="alittlehelp">
<title>A little help - Format Interfaces</title>
<para>
<application>gramps</application> provides some help with
writing reports. Several generic python classes exist that aid
in the writing of report generators. These classes provide an
abstract interface for a type of document, such as a drawing,
word processor document, or a spreadsheet. From these core
classes, <application>gramps</application> derives interfaces to
various document formats. This means that by coding to the
generic word processing class (<function>TextDoc</function>), a
report generator can instant access to multiple file formats
(such as HTML, OpenOffice, and AbiWord).
</para>
<para>
This scheme of deriving a output format from a generic base
class also makes it easier to add new formats. Creating a new
derivied class targeting a different format (such as
<application>KWord</application> or
<application>LaTeX</application>) makes it easy for existing
report generators to use the new formats.
</para>
</sect2>
</sect1>
<!-- ============= Writing Tools ============================= -->
<sect1 id="writingtools">
<title>Writing Tools</title>
<para>
Users can create their own tools and add them to
<application>gramps</application>. By adding the tool to the
user's private plugin directory (<filename
class="directory">~/.gramps/plugins</filename>), the tool will be
automatically recognized the next time that
<application>gramps</application> is started.
</para>
<para>
Unlike a report generator, a tool is allowed to modify the
database. The tool is passed the current
<application>gramps</application> database, the active person,
and a callback function. The callback function should be called
with a non-zero argument upon completion of the tool if the
database has been altered.
</para>
<para>
As with filters and report generators, tools must be registered
before <application>gramps</application> will understand it. The
tool is registered using the
<function>Plugins.register_tool</function>. This function takes
four arguments.
</para>
<itemizedlist>
<listitem>
<para>
<guilabel>The tool task</guilabel> This task
that executes the tool.
</para>
</listitem>
<listitem>
<para>
<guilabel>The tool category</guilabel> The category in which
the tool is grouped in the
<menuchoice><guimenu>Tools</guimenu></menuchoice> menu and in
the <interface>Tool Selection</interface> dialog.
</para>
</listitem>
<listitem>
<para>
<guilabel>The tool name</guilabel>
The name of the tool.
</para>
</listitem>
<listitem>
<para>
<guilabel>A text description of the tool</guilabel> The
description appears in the Tool Selection dialog to provide
the user with a description of what the tool does.
</para>
</listitem>
</itemizedlist>
<para>
While only the task and report name are required, it is
recommended to provide all five parameters.
</para>
<figure id="toolsrc">
<title>Sample tool implementation</title>
<programlisting>
import Plugins
def tool(database,person,callback):
... actual code ...
callback(1)
Plugins.register_tool(
task=tool,
category="Category",
name="Tool Name",
description="A text descripition of the tool"
)
</programlisting>
</figure>
</sect1>
<!-- ============= Import Filters ============================= -->
<sect1 id="writingimportfilters">
<title>Writing Import Filters</title>
<para>
Import filters are similar to tools, since they are allowed to
modify the databases. An import filter is a task that accepts
three arguments &mdash; a database, the filename of the file that
is to be imported, and a callback function.
</para>
<para>
The database may or may not have data already in it. The import
filter cannot assume that data neither already exists nor that the
database is empty.
</para>
<para>
The callback function is different from the callback function used
for tools. The import filter's callback function is used to
indicate progress and update the status bar during the import
process. The function takes a value between 0.0 and 1.0, where 0.0
represents the start of the import and 1.0 represents the
completion of the import.
</para>
<para>
As with the other plugin types, an import filter must be
registered with <application>gramps</application>. This is
accomplished by calling the
<function>Plugins.register_import</function> task. The
<function>Plugins.register_import</function> accepts two arguments
&mdash; the function the performs the import and a string
providing a brief description. This description is used as the
menu entry under the
<menuchoice>
<guimenu>File</guimenu>
<guisubmenu>Import</guisubmenu>
</menuchoice>
menu.
</para>
<figure id="importexample">
<title>Sample Import Implementation</title>
<programlisting>
import Plugins
def gedcom_import(database,filename,callback):
... actual code ...
Plugins.register_import(gedcom_import,"GEDCOM import")
</programlisting>
</figure>
</sect1>
<!-- ============= Export Filters ============================= -->
<sect1 id="writingexportfilters">
<title>Writing Export Filters</title>
<para>
Export filters are similar to report generators. They are not
allowed to modify the database. An export filter accepts three
arguments &mdash; a database, the filename of the file that is to
be written, and a callback function.
</para>
<para>
The callback function is indentical from the callback function
used for import filters. The export filter's callback function is
used to indicate progress and update the status bar during the
export process. The function takes a value between 0.0 and 1.0,
where 0.0 represents the start of the export and 1.0 represents
the completion of the export.
</para>
<para>
As with the other plugin types, an export filter must be
registered with <application>gramps</application>. This is
accomplished by calling the
<function>Plugins.register_export</function> task. The
<function>Plugins.register_export</function> accepts two arguments
&mdash; the function the performs the import and a string
providing a brief description. This description is used as the
menu entry under the
<menuchoice>
<guimenu>File</guimenu>
<guisubmenu>Export</guisubmenu>
</menuchoice>
menu.
</para>
<figure id="exportexample">
<title>Sample Export Implementation</title>
<programlisting>
import Plugins
def gedcom_export(database,filename,callback):
... actual code ...
Plugins.register_export(gedcom_export,"GEDCOM export")
</programlisting>
</figure>
</sect1>
<sect1 id="commontasks">
<title>Common tasks</title>
<para>
While this manual does not document the
<application>gramps</application> database interface, this section
shows a few common tasks.
</para>
<sect2 id="gettingnames">
<title>Printing names of people</title>
<para>
This example shows how to display the name of people in the
database. It assumes that the database is called
<function>db</function>. To get a list of people, it calls the
<function>getPersonMap</function> method, which returns a map of
<application>gramps</application> ID to
<function>Person</function> objects. Calling the
<function>valus</function> method of the returned map returns a
list of people. For each person, the primary name is extracted,
and then the <function>Name</function> object's
<function>getName</function> method is called to build a
presentable name from the individual name components.
</para>
<figure id="displaynames">
<title>Displaying names</title>
<programlisting>
for person in db.getPersonMap().values():
name = person.getPrimaryName()
print name.getName()
</programlisting>
</figure>
</sect2>
<sect2 id="listingevents">
<title>Displaying the events of person</title>
<para>
This example shows how to display the public events associated
with a person. It assumes that the person is called
<function>person</function>.
</para>
<figure id="eventexample">
<title>Displaying Event Information</title>
<programlisting>
for event in person.getEventList():
if event.getPrivacy() == 0:
print "Event:",event.getName()
print "Date:",event.getDate()
print "Place:",event.getPlaceName()
</programlisting>
</figure>
</sect2>
<sect2 id="printfamily">
<title>Print the members of each family</title>
<para>
This example shows how to display the parents and children of
each family in the database. It assumes that the database is called
<function>db</function>.
</para>
<figure id="familyexample">
<title>Displaying Family Information</title>
<programlisting>
for family in db.getFamilyMap().values:
print "-------------------"
print "Family ID:",family.getId()
father = family.getFather()
if father != None:
print "Father:",father.getPrimaryName().getName()
mother = family.getMother()
if mother != None:
print "Mother:",mother.getPrimaryName().getName()
for child in family.getChildList():
print "Child:",child.getPrimaryName().getName()
</programlisting>
</figure>
</sect2>
<sect2 id="personsfamily">
<title>Display the marriages/relationships of a person</title>
<para>
This example shows how to display the families and relationships
in which the person is considered a spouse or parent. It assumes
that the person is called <function>person</function>.
</para>
<para>
Relationships between people can be complex. Because someone is
male, does not necessarily mean that the person will be
considered the "Father" of a relationship. In relationships of
type "Partners", the "father" and "mother" of the relationship
should be of the same gender. So to determine the spouse of a
person, it is usually best to compare the person against what is
returned by <function>getFather</function> and
<function>getMother</function> to find the one that is not
equal. It should also be noted that the
<function>getFather</function> and
<function>getMother</function> methods will return None if noone
has been associated with that role in the family.
</para>
<figure id="relexample">
<title>Displaying Relationship Information</title>
<programlisting>
for family in person.getFamilyList():
print "-------------------"
print "Family ID:",family.getId()
print "Relationship Type:",family.getRelationship()
father = family.getFather()
if father != None and father != person:
print "Spouse:",father.getPrimaryName().getName()
mother = family.getMother()
if mother != None and mother != person:
print "Spouse:",mother.getPrimaryName().getName()
</programlisting>
</figure>
</sect2>
</sect1>
<!-- ============= Authors ================================ -->
<sect1 id="authors">
<title>Authors</title>
<para>
<application>gramps</application> was written by Don Allingham
(<email>dallingham@users.sourceforge.net</email>). To find more
information about <application>gramps</application>, please visit
the <ulink url="http://gramps.sourceforge.net" type="http">gramps
web page</ulink>.
</para>
<para>
This manual was written by Don Allingham
(<email>dallingham@users.sourceforge.net</email>).
</para>
<!-- For translations: uncomment this:
<para>
Latin translation was done by ME
(<email>MYNAME@MYADDRESS</email>). Please send all comments and
suggestions regarding this translation to SOMEWHERE.
</para>
-->
</sect1>
<!-- ============= Application License ============================= -->
<sect1 id="license">
<title>License</title>
<para>
This program is free software; you can redistribute it and/or
modify it under the terms of the <ulink type="help"
url="gnome-help:gpl"> <citetitle>GNU General Public
License</citetitle></ulink> as published by the Free Software
Foundation; either version 2 of the License, or (at your option)
any later version.
</para>
<para>
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
<citetitle>GNU General Public License</citetitle> for more
details.
</para>
<para>
A copy of the <citetitle>GNU General Public License</citetitle> is
included as an appendix to the <citetitle>GNOME Users
Guide</citetitle>. You may also obtain a copy of the
<citetitle>GNU General Public License</citetitle> from the Free
Software Foundation by visiting <ulink type="http"
url="http://www.fsf.org">their Web site</ulink> or by writing to
<address>
Free Software Foundation, Inc. <street>59 Temple Place</street> -
Suite 330 <city>Boston</city>, <state>MA</state>
<postcode>02111-1307</postcode> <country>USA</country>
</address>
</para>
</sect1>
</article>