<!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 — 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 — 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 — 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 — 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 — 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>