GEPS 036: Extended Alternative Place Name Handling

From Gramps
Jump to: navigation, search
Gnome-important.png
GEPS Closed

This GEPS (Gramps Enhancement Proposal) is closed and available in the version of Gramps indicated below.
Do not edit this page. Submit bugs/features to https://gramps-project.org/bugs/.

Implemented for the release of Gramps 4.2

The purpose of this GEPS is to provide a proposal to extend the alternative place name handling in Gramps. This includes additional information for alternative place names like a date when the alternative name was valid, a language code to identify the language of the name and some other attributes.

Plan

The intention of the extended alternative place names in Gramps is to provide for each alternative place name the following information:

  • Place Name: Name of the place
  • Language ISO-Code: Language used to write the place name
  • Date: The date or time span when the place name was valid
  • Citation-List: List of source citations for the alternative place name

Design

This sections describes the planned software design for the alternative place name extension.

Actual Data Model

To explain the needed design changes to the existing data objects, the following section describes the actual data model. Hereby the focus is on the place object and the corresponding data objects which are associated with the place object. In the following figure, a classical UML class diagram shows the “data view” of the place related objects.

Actual Data Model

“Data view” means in this context, that the associations between the classes show the data relation of the classes but not the way this relation is technically realized. To show the technical realization the following UML class diagram shows the same objects but from the “implementation view”.

Actual Implementation Model

As it can be seen, the implementation realizes the aggregation with a generalization. For Python this will be a realization with multiple inheritance. One important point in the actual design is, that the alternative place names are currently realized by a simple list of strings which represent the alternative names.

New Design Proposal

To extend the alternative names with addition information, there is a need for a dedicated PlaceName class to encapsulate all the attributes of an alternative place name. In the following figure the planned “data view” design for the integration of a PlaceName class is shown.


New Data Model

As it can be seen, the new PlaceName class contains attributes for name, date, type and lang-iso code. These attributes are based on Python primitives like stings and also Gramps objects like Date and PlaceType.

In the following figure the “implementation view” of the planned design is shown. In this diagram the new PlaceName class is shown in a red color.

New Implementation Model

One important design aspect is the realization of the “relation” between the Place class and the PlaceName class. In contrast to the typical realization based on inheritance, the PlaceName class is integrated with an aggregation. This approach has two advantages:

  1. The “classical” semantic of “has-an” (aggregation) and “is-an” (inheritance) relation between classes/objects is valid.
  2. A multiple inheritance of CitationBase is avoided. Because the need for a 1:n relation between PlaceNameClass and CitationBase the PlaceNameClass must inherit from CitationBase. But the classical GRAMPS approach to include a 1:n relation in the PlaceClass is to inherit it from the corresponding class. That means, PlaceClass would have inherit from PlaceNameClass which in fact would lead to the following scenario (just as an example)

Double Inheritance

And this construct should be avoided because it could lead to confusion and it introduces more complexity than needed into the model. Furthermore it is not much away from the “deadly diamond of death”. (http://www.python-course.eu/python3_multiple_inheritance.php).

The data structure to store the PlaceName objects inside the Place class should be a simple list. The declaration of this attribute could look like the following:

alt_names_list = []

This is the same declaration as the original list of alternative names besides the fact that PlaceName objects will be stored in this list and not strings.

API

To provide the ability to implement this extension without disturbing existing functionality, the following API methods of the Place class should be adapted to the new internal data structure but should provide the same behavior as the old API methods.

  • _merge_alt_names()
  • get_alternative_names()
  • set_alternative_names()
  • add_alternative_name()
  • get_all_names()

If these API functions behave the same as before, the change for GEDCOM export, DB backup, GRAMPS XML, Reports etc. can be gradually delivered.

Of course, the realted editors like PlaceEditor in GRAMPS need to be adapted to the new model. Also new dialogs for add/edit alternative place names must be added.

Serialization

To store the new PlaceName objects in the database the original database class DbBsddb doesn't need to be changed. But it is necessary to change the functions serialize(), unserialized(), from_struct() and to_struct() of the class Place.

Place::serialize() The original code block for the serialization contains a snippet like the following:

self.name, self.alt_names,
self.place_type.serialize(), self.code,
[al.serialize() for al in self.alt_loc],

Due to the fact that the alt_names is now a list of PlaceName objects, it could be serialized like the list of alternative locations.

self.name, [an.serialize() for an in self.alt_names],
self.place_type.serialize(), self.code,
[al.serialize() for al in self.alt_loc],

That approach assumes, that the PlaceName object provides a method called serialize(). The same is also for the unserialize() method valid.

Place::unserialize() To unserialize the PlaceName list inside the unserialize() method of the Place object, this methods needs also to be changed. The following shows the original code snippet to unserialize the Place object.

(self.handle, self.gramps_id, self.title, self.long, self.lat,
placeref_list, self.name, self.alt_names, the_type, self.code,
alt_loc, urls, media_list, citation_list, note_list,
self.change, tag_list, self.private) = data

self.place_type = PlaceType()
self.place_type.unserialize(the_type)
self.alt_loc = [Location().unserialize(al) for al in alt_loc]
self.placeref_list = [PlaceRef().unserialize(pr) for pr in placeref_list]

In this snippet the reference to the internal list of alternative names is replaced by a local variable alt_names. This local variable is used to initialize the internal list of PlaceName objects with the proper data. The following snippet shows this approach

(self.handle, self.gramps_id, self.title, self.long, self.lat,
placeref_list, self.name, the_type, self.code,
alt_loc, urls, media_list, citation_list, note_list,
self.change, tag_list, self.private) = data

self.place_type = PlaceType()
self.place_type.unserialize(the_type)
self.alt_names = [PlaceName().unserialize(an) for an in alt_names]
self.alt_loc = [Location().unserialize(al) for al in alt_loc]
self.placeref_list = [PlaceRef().unserialize(pr) for pr in placeref_list]