Esempio n. 1
0
def view_list(request):
    """View the list of all personas"""

    graph.update_if_needed()
    if len(graph) == 0:
        return render_to_response('geneaprove/firsttime.html',
                                  context_instance=RequestContext(request))

    styles = Styles(style_rules, graph=graph, decujus=1)  # ??? Why "1"
    all = extended_personas(nodes=None,
                            styles=styles,
                            event_types=event_types_for_pedigree,
                            graph=graph,
                            as_css=True)

    all = [p for p in all.itervalues()]
    all.sort(key=lambda x: x.surname)

    all = [{
        'surname': p.surname,
        'given_name': p.given_name,
        'birth': p.birth,
        'death': p.death,
        'marriage': p.marriage
    } for p in all]

    data = {
        'persons': all,
    }

    return HttpResponse(to_json(data), content_type='application/json')
Esempio n. 2
0
def view_list(request):
    """View the list of all personas"""

    graph.update_if_needed()
    if len(graph) == 0:
        return render_to_response(
            'geneaprove/firsttime.html',
            context_instance=RequestContext(request))

    styles = Styles(style_rules, graph=graph, decujus=1)  # ??? Why "1"
    all = extended_personas(
        nodes=None, styles=styles, event_types=event_types_for_pedigree,
        graph=graph, as_css=True)

    all = [p for p in all.itervalues()]
    all.sort(key=lambda x: x.surname)

    all = [{'surname': p.surname,
            'given_name': p.given_name,
            'birth': p.birth,
            'death': p.death,
            'marriage': p.marriage}
           for p in all]

    data = {
        'persons': all,
    }

    return HttpResponse(to_json(data), content_type='application/json')
Esempio n. 3
0
def view(request, id):
    """Display all details known about persona ID"""

    id = int(id)

    graph.update_if_needed()
    #if len(graph) == 0:
    #    return render_to_response(
    #        'geneaprove/firsttime.html',
    #        context_instance=RequestContext(request))

    styles = None
    p = extended_personas(
        nodes=set([graph.node_from_id(id)]),
        styles=styles, as_css=True, graph=graph, schemes=None)

    query = models.P2P.objects.filter(
        type=models.P2P.sameAs)

    node = graph.node_from_id(id)
    assertions = list(models.P2P.objects.filter(
        type=models.P2P.sameAs,
        person1__in=node.ids.union(node.different)))

    decujus = p[node.main_id]

    decujus.all_chars = decujus.all_chars.values()
    decujus.all_events = decujus.all_events.values()
    decujus.all_groups = decujus.all_groups.values()

    data = {
        "person": decujus,
        "p2p": assertions,
    }
    return HttpResponse(to_json(data), content_type='application/json')
Esempio n. 4
0
def personaEvents(request, id):
    """All events for the person"""

    id = int(id)

    graph.update_if_needed()

    schemes = set()  # The surety schemes that are needed
    styles = None
    p = extended_personas(nodes=set([graph.node_from_id(id)]),
                          styles=styles,
                          as_css=True,
                          graph=graph,
                          schemes=schemes)

    data = [
        "%s: %s (%s)%s" % (e.event.name, e.event.date, e.event.place,
                           u"\u2713" if e.event.sources else u"\u2717")
        for i, e in p[id].all_events.items()
        if e.role == 'principal' and not e.assertion.disproved
    ]
    data.extend("%s: %s%s%s" % (c.char.name, " ".join(
        "%s:%s" % (p.name, p.value)
        for p in c.parts), "(%s)" % c.char.date if c.char.date else "",
                                u"\u2713" if c.char.sources else u"\u2717")
                for k, c in p[id].all_chars.items()
                if not c.assertion.disproved and c.char.name not in ("_UID", ))

    return HttpResponse(to_json(data, year_only=False),
                        content_type="application/json")
Esempio n. 5
0
    def to_json(self, value):
        # We will however return a simpler version of the information computed
        # above (which includes all known events for the persons)

        show_age = False
        def person_to_json_for_pedigree(obj):
            if isinstance(obj, models.Persona):
                d = obj.death
                if show_age and obj.birth:
                    if d:
                        if d.Date:
                            d.Date += " (age %s)" % (
                                str(d.Date.years_since(obj.birth.Date)), )
                    else:
                        d = {Date: " (age %s)" % (
                           str(DateRange.today().years_since(obj.birth.Date)), )}

                return {
                    'id':   obj.id,
                    'givn': obj.given_name,
                    'surn': obj.surname,
                    'sex':  obj.sex,
                    'generation': obj.generation,
                    'parents': obj.parents if hasattr(obj, 'parents') else None,
                    'children': obj.children if hasattr(obj, 'children') else None,
                    'style': obj.styles,
                    'birth': obj.birth,
                    'marriage': obj.marriage,
                    'death': d}

        return to_json(value, custom=person_to_json_for_pedigree,
                       year_only=self.year_only)
Esempio n. 6
0
def view(request, id):
    """JSON data for a specific event"""
    id = int(id)
    data = extended_events([id]).get(id, None)
    return HttpResponse(
        to_json(data, year_only=False),
        content_type='application/json')
Esempio n. 7
0
def view(request, id):
    """View a specific source"""

    id = int(id)

    graph.update_if_needed()
    if len(graph) == 0:
        return render_to_response('geneaprove/firsttime.html',
                                  context_instance=RequestContext(request))

    schemes = set()  # The surety schemes that are needed
    sources = extended_sources([id], schemes=schemes)

    surety_schemes = dict()
    for s in schemes:
        surety_schemes[s] = models.Surety_Scheme.objects.get(id=s).parts.all()

    data = {
        'source': sources[id],
        'parts': list_of_citations(None, sources[id]),
        'repository_types': models.Repository_Type.objects.all(),
        'source_types': Citations.source_types(),
        'schemes': surety_schemes
    }
    return HttpResponse(to_json(data), content_type='application/json')
Esempio n. 8
0
def personaEvents(request, id):
    """All events for the person"""

    id = int(id)

    graph.update_if_needed()

    schemes = set()  # The surety schemes that are needed
    styles = None
    p = extended_personas(
        nodes=set([graph.node_from_id(id)]),
        styles=styles, as_css=True, graph=graph, schemes=schemes)

    data = ["%s: %s (%s)%s" % (e.event.name, e.event.date, e.event.place,
                               u"\u2713" if e.event.sources else u"\u2717")
            for i, e in p[id].all_events.items()
            if e.role == 'principal'
            and not e.assertion.disproved]
    data.extend("%s: %s%s%s" % (
                c.char.name,
                " ".join("%s:%s" % (p.name, p.value) for p in c.parts),
                "(%s)" % c.char.date if c.char.date else "",
                u"\u2713" if c.char.sources else u"\u2717")
                for k, c in p[id].all_chars.items()
                if not c.assertion.disproved
                and c.char.name not in ("_UID", ))

    return HttpResponse(
        to_json(data, year_only=False),
        content_type="application/json")
Esempio n. 9
0
def getLegend(request):
    all_rules = geneaprove.views.custom_highlight.style_rules
    rules = []
    for name, type, tests, style in all_rules:
        rules.append({'name': name, 'css': style_to_css(style)})
    return HttpResponse(to_json({'rules': rules}),
                        content_type='application/json')
Esempio n. 10
0
def view_list(request):
    """View the list of a all known places"""

    # ??? How do we get the list of parts immediately too ?
    places = models.Place.objects.order_by('name')
    return HttpResponse(
        to_json(places),
        content_type='application/json')
Esempio n. 11
0
def getLegend(request):
    all_rules = geneaprove.views.custom_highlight.style_rules
    rules = []
    for name, type, tests, style in all_rules:
        rules.append({'name': name, 'css': style_to_css(style)})
    return HttpResponse(
        to_json({'rules': rules}),
        content_type='application/json')
Esempio n. 12
0
def citationParts(request, medium):
    """
    Return the list of citation parts needed for this medium.
    :param medium: either the id of the mediaType, or the id of a source.
    """
    if medium.isdigit():
        src = models.Source.objects.get(id=medium)
        result = list_of_citations(None, src)
    else:
        result = list_of_citations(medium)
    return HttpResponse(to_json(result), content_type="application/json")
Esempio n. 13
0
def get_settings(request):
    """
    Return the user settings. These include the following fields:
    * defaultPerson
      id of the person to show when the user connects initially.
      It returns -1 if the database is currently empty.
    """

    p = models.Persona.objects.aggregate(Min('id'))
    data = {"defaultPerson": p['id__min'] if p else -1}
    return HttpResponse(to_json(data), content_type='application/json')
Esempio n. 14
0
def citation_model(request, id):
    """
    Return the citation model for a given id
    """
    citation = Citations.get_citation(id)
    data = {
        'biblio': citation.biblio,
        'full': citation.full,
        'short': citation.short
    }
    return HttpResponse(to_json(data), content_type='application/json')
Esempio n. 15
0
def surety_schemes_view(request):
    schemes = [{'id': s.id,
                'name': s.name,
                'description': s.description,
                'parts': [
                    {'id': p.id,
                     'name': p.name,
                     'description': p.description,
                     'sequence': p.sequence_number} for p in s.parts.all()]
            } for s in models.Surety_Scheme.objects.all()]
            
    return HttpResponse(to_json(schemes), content_type='application/json')
Esempio n. 16
0
def import_gedcom(request):
    # params = json.loads(request.body)  # parse angularJS JSON parameters
    try:
        print "MANU import_gedcom FILES=%s", request.FILES
        data = request.FILES['file']
        #data = params['file']
        success, errors = GedcomFileImporter().parse(data)
        graph.mark_as_invalid()   # Will need a refresh
        resp = {'error': errors, 'success': success}
    except KeyError:
        resp = {'error': 'No file specified', 'success': False}

    return HttpResponse(to_json(resp), content_type='application/json')
Esempio n. 17
0
def import_gedcom(request):
    # params = json.loads(request.body)  # parse angularJS JSON parameters
    try:
        print "MANU import_gedcom FILES=%s", request.FILES
        data = request.FILES['file']
        #data = params['file']
        success, errors = GedcomFileImporter().parse(data)
        graph.mark_as_invalid()  # Will need a refresh
        resp = {'error': errors, 'success': success}
    except KeyError:
        resp = {'error': 'No file specified', 'success': False}

    return HttpResponse(to_json(resp), content_type='application/json')
Esempio n. 18
0
def get_settings(request):
    """
    Return the user settings. These include the following fields:
    * defaultPerson
      id of the person to show when the user connects initially.
      It returns -1 if the database is currently empty.
    """

    p = models.Persona.objects.aggregate(Min('id'))
    data = {
        "defaultPerson": p['id__min'] if p else -1
    }
    return HttpResponse(to_json(data), content_type='application/json')
Esempio n. 19
0
def getLegend(request):
    """
    Return the list of highlighting rules
    """
    # pylint: disable=unused-argument

    all_rules = geneaprove.views.custom_highlight.style_rules()
    rules = []
    for name, _, _, style in all_rules:
        rules.append({'name': name, 'css': style_to_css(style)})
    return HttpResponse(
        to_json({'rules': rules}),
        content_type='application/json')
Esempio n. 20
0
def higherSourceReprList(request, source_id):
    """
    The list of representations for the higher sources of source_id.
    :return: a list of tuples (id,title)
    """
    result = []
    s = models.Source.objects.get(id=source_id)
    if s:
        s = s.higher_source
        while s:
            for r in models.Representation.objects.filter(source=s).all:
                result.append((r.id, r.comments))
            s = s.higher_source
    return HttpResponse(to_json(result), content_type="application/json")
Esempio n. 21
0
def higherSourceReprList(request, source_id):
    """
    The list of representations for the higher sources of source_id.
    :return: a list of tuples (id,title)
    """
    result = []
    s = models.Source.objects.get(id=source_id)
    if s:
        s = s.higher_source
        while s:
            for r in models.Representation.objects.filter(source=s).all:
                result.append((r.id, r.comments))
            s = s.higher_source
    return HttpResponse(to_json(result), content_type="application/json")
Esempio n. 22
0
def surety_schemes_view(request):
    schemes = [{
        'id':
        s.id,
        'name':
        s.name,
        'description':
        s.description,
        'parts': [{
            'id': p.id,
            'name': p.name,
            'description': p.description,
            'sequence': p.sequence_number
        } for p in s.parts.all()]
    } for s in models.Surety_Scheme.objects.all()]

    return HttpResponse(to_json(schemes), content_type='application/json')
Esempio n. 23
0
def fullCitation(request):
    """
    Compute the full citation, given the parts. This does not edit the
    database.
    :return: a dictionary of 'full', 'short' and 'biblio'.
    """
    result = {}

    if request.method == 'POST':
        medium = request.POST.get('sourceMediaType')
        params = request.POST

        if request.POST.get('_higherSource'):
            higher = models.Source.objects.get(
                id=int(request.POST.get('_higherSource')))
            params = prepare_citation_parts(higher, request.POST)

        result = Citations.get_citation(medium).cite(params)
    return HttpResponse(to_json(result), content_type="application/json")
Esempio n. 24
0
def view(request, id):
    """Display all details known about persona ID"""

    id = int(id)

    graph.update_if_needed()
    #if len(graph) == 0:
    #    return render_to_response(
    #        'geneaprove/firsttime.html',
    #        context_instance=RequestContext(request))

    styles = None
    p = extended_personas(nodes=set([graph.node_from_id(id)]),
                          styles=styles,
                          as_css=True,
                          graph=graph,
                          schemes=None)

    query = models.P2P.objects.filter(type=models.P2P.sameAs)

    node = graph.node_from_id(id)
    assertions = list(
        models.P2P.objects.filter(type=models.P2P.sameAs,
                                  person1__in=node.ids.union(node.different)))

    decujus = p[node.main_id]

    decujus.all_chars = decujus.all_chars.values()
    decujus.all_events = decujus.all_events.values()
    decujus.all_groups = decujus.all_groups.values()

    data = {
        "person": decujus,
        "p2p": assertions,
    }
    return HttpResponse(to_json(data), content_type='application/json')
Esempio n. 25
0
def view(request, id):
    """JSON data for a specific event"""
    id = int(id)
    data = extended_events([id]).get(id, None)
    return HttpResponse(to_json(data, year_only=False),
                        content_type='application/json')
Esempio n. 26
0
def view(request, decujus=1):
    """Display the statistics for a given person"""

    decujus = int(decujus)

    graph.update_if_needed()
    if len(graph) == 0:
        return render_to_response(
            'geneaprove/firsttime.html',
            context_instance=RequestContext(request))

    # ??? The stats includes persons "Unknown" that were created during a
    # gedcom import for the purpose of preserving families. Will be fixed
    # when we store children differently (for instance in a group)

    distance = dict()
    ancestors = graph.people_in_tree(id=decujus, distance=distance)
    persons = extended_personas(
        nodes=ancestors, styles=None, event_types=event_types_for_pedigree,
        graph=graph)

    f = graph.fathers(decujus)
    fathers = graph.people_in_tree(id=f[0], maxdepthDescendants=0) if f else []
    m = graph.mothers(decujus)
    mothers = graph.people_in_tree(id=m[0], maxdepthDescendants=0) if m else []

    cal = CalendarGregorian()

    generations = dict()  # list of persons for each generation
    for a in ancestors:
        d = distance[a]
        if d not in generations:
            generations[d] = []
        generations[d].append(a)

    ranges = []

    for index in sorted(generations.keys()):
        births = None
        deaths = None
        gen_range = [index + 1, "?", "?", ""]  # gen, min, max, legend
        for p in generations[index]:
            p = persons[p.main_id]
            if p.birth and p.birth.Date:
                if births is None or p.birth.Date < births:
                    births = p.birth.Date
                    year = p.birth.Date.year(cal)
                    if year is not None:
                        gen_range[1] = year

            if p.death and p.death.Date:
                if deaths is None or p.death.Date > deaths:
                    deaths = p.death.Date
                    year = p.death.Date.year(cal)
                    if year is not None:
                        gen_range[2] = year

        gen_range[3] = "Gen. %02d (%d / %d) (%s - %s)" \
            % (index + 1, len(generations[index]), 2 ** (index + 1),
               gen_range[1], gen_range[2])

        # Postprocess the ranges:
        #   generation n's earliest date has to be at least 15 years before
        #     its children's earliest date (can't have children before that)
        #   generation n's latest date (death) has to be after the children's
        #     generation earliest date (first birth)

        if len(ranges) > 0:
            if gen_range[1] == "?":
                gen_range[1] = ranges[-1][1] - 15
            if gen_range[2] == "?" or gen_range[2] < ranges[-1][1]:
                gen_range[2] = ranges[-1][1]
        if gen_range[2] == '?':
            gen_range[2] = datetime.datetime.now().year

        ranges.append(gen_range)

    ages = []
    for a in range(0, 120, 5):
        ages.append([a, 0, 0, 0])  # date_range, males, females, unknown

    for p in persons.itervalues():
        if p.birth and p.birth.Date and p.death and p.death.Date:
            age = p.death.Date.years_since(p.birth.Date)
            if age is not None:
                if p.sex == "M":
                    ages[int(age / 5)][1] += 1
                elif p.sex == "F":
                    ages[int(age / 5)][2] += 1
                else:
                    ages[int(age / 5)][3] += 1

    data = {
        "total_ancestors": len(ancestors),
        "total_father":    len(fathers),
        "total_mother":    len(mothers),
        "total_persons":   len(graph),
        "ranges":          ranges,
        "ages":            ages,
        "decujus":         decujus,
        "decujus_name":  "%s %s" % (
            persons[decujus].given_name, persons[decujus].surname)
    }

    return HttpResponse(to_json(data), content_type='application/json')
Esempio n. 27
0
def __get_json_sosa_tree(graph, id, max_levels, style_rules,
                  last_descendant_known=-1,
                  maxdepthDescendants=1, last_gen_known=-1):
    """
        :param last_gen_known: is the number of the last generation for which the
            client already has data, and thus do not need to be sent again. -1
            to retrieve all.
        :param maxdepthDescendants:
            The number of generations for which we compute the children.
    """

    decujus = graph.node_from_id(id)
    styles = Styles(style_rules, graph, decujus=decujus.main_id)

    distance = dict()
    ancestors = graph.people_in_tree(
        id=decujus.main_id, maxdepthAncestors=max_levels - 1,
        maxdepthDescendants=0, distance=distance)
    ancestors = [a for a in ancestors if distance[a] >= last_gen_known]

    descendants = graph.people_in_tree(
        id=decujus.main_id, maxdepthAncestors=0,
        distance=distance, maxdepthDescendants=maxdepthDescendants)
    descendants = [
        a for a in descendants
        if a != decujus and distance[a] >= last_descendant_known]

    sosa_tree = dict()
    marriage = dict()
    children = {}

    persons = {}
    all_person_nodes = set(ancestors).union(descendants)
    if all_person_nodes:
        persons = extended_personas(
            all_person_nodes, styles,
            event_types=event_types_for_pedigree, graph=graph)

    def add_parents(p):
        p.generation = distance[graph.node_from_id(p.id)]
        if p.generation >= max_levels:
            return

        fathers = graph.fathers(p.id)
        mothers = graph.mothers(p.id)
        p.parents = [
            None if not fathers else persons.get(fathers[0].main_id, None),
            None if not mothers else persons.get(mothers[0].main_id, None)]

        for pa in p.parents:
            if pa:
                add_parents(pa)

    def add_children(p, gen):
        p.children = []
        sorted = [(persons[node.main_id] if node.main_id in persons else None,
                   node)
                  for node in graph.children(p.id)]
        sorted.sort(
            key=lambda c: c[0].birth.Date if c[0] and c[0].birth else None)
        for c in sorted:
            if c[0]:
                c[0].generation = -gen # distance[c[1]]
                p.children.append(c[0])
                if gen < maxdepthDescendants:
                    add_children(c[0], gen + 1)

    main = persons[decujus.main_id]
    add_parents(main)
    add_children(main, gen=1)

    # We will however return a simpler version of the information computed
    # above (which includes all known events for the persons)

    show_age = False
    def person_to_json_for_pedigree(obj):
        if isinstance(obj, models.Persona):
            d = obj.death
            if show_age and obj.birth:
                if d:
                    if d.Date:
                        d.Date += " (age %s)" % (
                            str(d.Date.years_since(obj.birth.Date)), )
                else:
                    d = {Date: " (age %s)" % (
                       str(DateRange.today().years_since(obj.birth.Date)), )}

            return {
                'id':   obj.id,
                'givn': obj.given_name,
                'surn': obj.surname,
                'sex':  obj.sex,
                'generation': obj.generation,
                'parents': obj.parents if hasattr(obj, 'parents') else None,
                'children': obj.children if hasattr(obj, 'children') else None,
                'style': obj.styles,
                'birth': obj.birth,
                'marriage': obj.marriage,
                'death': d}

    return to_json(
        obj= {'generations': max_levels,
              'descendants': maxdepthDescendants,
              'decujus':     main, 
              'styles':      styles.all_styles()},
        custom=person_to_json_for_pedigree) 
Esempio n. 28
0
    def json(self, subset=None):
        """
        Return a json structure that can be sent to the GUI.

        :param id: an integer
            If specified, only the persons related to id will be displayed.

        :param maxdepth: an integer or -1
            The maximum number of generations before and after id to look at.
            This is ignored if id is unspecified.
        """
        def __compute_families(graph, layers, layers_by_id):
            """
            Compute the list of families that include nodes from tmp.

            Sort the families, so that they are organized by layer. A family is
            associated with its right-most layer (in general to the left of the
            layer that contains the children). Within each layer, the families are
            sorted in the order in which they should be displayed in the matrix --
            so for instance the first family should involve the first person of the
            layer to limit crossings of links.

            :param graph:
                a subset of the original graph, which only includes the nodes
                we are interested in, and only the parent/child relations.
            :param layers:
                A list of list of persons, indicating the persons at each layer.
                For instance:   [[person_at_gen0], [person_at_gen1, ...], ...]
            :param layers_by_id:
                for each person, its layer.
            :return: a list of list of tuples (father,mother,child1,child2,...)
            """

            tmp = dict()  # families: (father,mother,child1,child2,...)
            # indexed on (father, mother)

            for n in graph:
                father = mother = None

                for e in graph.in_edges(n):
                    if e.kind == P2P_Link.KIND_FATHER:
                        father = e[0]
                    else:
                        mother = e[0]

                if father is not None or mother is not None:
                    tmp.setdefault((father, mother),
                                   [mother, father]).append(n)

            byLayer = dict()  # Contains list of families for each layer

            for family in tmp.itervalues():
                rightMostLayer = min(layers_by_id[p] for p in family
                                     if p is not None)
                byLayer.setdefault(rightMostLayer + 1, []).append(family)

            # ??? Should be computed independently
            indexInLayer = dict()
            for layer in layers:
                for index, node in enumerate(layer):
                    indexInLayer[node] = index

            # Sort the families within each layer. If one of the parents is in
            # another layer, we want that marriage to appear first.

            mi = min(byLayer.iterkeys())
            ma = max(byLayer.iterkeys())

            result = []
            for lay in range(mi, ma + 1):
                r = byLayer.get(lay, [])
                r.sort(key=lambda family:
                       (-max(layers_by_id[family[0]] if family[0] else 0,
                             layers_by_id[family[1]] if family[1] else 0),
                        min(indexInLayer.get(family[0], -1),
                            indexInLayer.get(family[1], -1))))

                # Pass the ids of the family members, not the nodes
                result.append([
                    map(lambda node: min(node.ids) if node else -1, family)
                    for family in r
                ])

            return result

        # Prepare a temporary graph: it is used to subset the list of nodes
        # to those specified in argument, and the list of edges to the
        # parent/child relationships

        tmp = Digraph()
        for e in self.edges():
            if e.kind in (P2P_Link.KIND_MOTHER, P2P_Link.KIND_FATHER) and \
               e[0] in (subset or self) and \
               e[1] in (subset or self):

                tmp.add_edge(e)

        # Then organize nodes into layers

        #layers_by_id = tmp.rank_longest_path()
        layers_by_id = tmp.rank_minimize_dummy_vertices()

        layers = tmp.get_layers(layers_by_id=layers_by_id)
        print "MANU layers=%s" % (layers, )

        # Organize the nodes within layers
        tmp.sort_nodes_within_layers(layers)
        print "MANU sorted layers=%s" % (layers, )

        # Compute the families
        families = __compute_families(tmp, layers, layers_by_id)
        print "MANU sorted families=%s" % (families, )

        print "MANU graph=%s" % tmp

        result = []
        for lay in range(0, len(layers)):
            result.append([(n.main_id, n.name.encode("utf-8"), n.sex)
                           for n in layers[lay]])

        # for index, l in enumerate(result):
        #    print "MANU layer[%d] = %s" % (index, sorted([p[0] for p in l]))
        return {
            "persons": to_json(result, year_only=True),
            "families": families
        }
Esempio n. 29
0
    def json(self, subset=None):
        """
        Return a json structure that can be sent to the GUI.

        :param id: an integer
            If specified, only the persons related to id will be displayed.

        :param maxdepth: an integer or -1
            The maximum number of generations before and after id to look at.
            This is ignored if id is unspecified.
        """

        def __compute_families(graph, layers, layers_by_id):
            """
            Compute the list of families that include nodes from tmp.

            Sort the families, so that they are organized by layer. A family is
            associated with its right-most layer (in general to the left of the
            layer that contains the children). Within each layer, the families are
            sorted in the order in which they should be displayed in the matrix --
            so for instance the first family should involve the first person of the
            layer to limit crossings of links.

            :param graph:
                a subset of the original graph, which only includes the nodes
                we are interested in, and only the parent/child relations.
            :param layers:
                A list of list of persons, indicating the persons at each layer.
                For instance:   [[person_at_gen0], [person_at_gen1, ...], ...]
            :param layers_by_id:
                for each person, its layer.
            :return: a list of list of tuples (father,mother,child1,child2,...)
            """

            tmp = dict()  # families: (father,mother,child1,child2,...)
            # indexed on (father, mother)

            for n in graph:
                father = mother = None

                for e in graph.in_edges(n):
                    if e.kind == P2P_Link.KIND_FATHER:
                        father = e[0]
                    else:
                        mother = e[0]

                if father is not None or mother is not None:
                    tmp.setdefault(
                        (father, mother), [mother, father]).append(n)

            byLayer = dict()   # Contains list of families for each layer

            for family in tmp.itervalues():
                rightMostLayer = min(
                    layers_by_id[p] for p in family if p is not None)
                byLayer.setdefault(rightMostLayer + 1, []).append(family)

            # ??? Should be computed independently
            indexInLayer = dict()
            for layer in layers:
                for index, node in enumerate(layer):
                    indexInLayer[node] = index

            # Sort the families within each layer. If one of the parents is in
            # another layer, we want that marriage to appear first.

            mi = min(byLayer.iterkeys())
            ma = max(byLayer.iterkeys())

            result = []
            for lay in range(mi, ma + 1):
                r = byLayer.get(lay, [])
                r.sort(
                    key=lambda family:
                    (-max(layers_by_id[family[0]] if family[0] else 0,
                          layers_by_id[family[1]] if family[1] else 0),
                     min(indexInLayer.get(family[0], -1),
                         indexInLayer.get(family[1], -1))))

                # Pass the ids of the family members, not the nodes
                result.append(
                    [map(lambda node: min(node.ids) if node else -1,
                         family)
                     for family in r])

            return result

        # Prepare a temporary graph: it is used to subset the list of nodes
        # to those specified in argument, and the list of edges to the
        # parent/child relationships

        tmp = Digraph()
        for e in self.edges():
            if e.kind in (P2P_Link.KIND_MOTHER, P2P_Link.KIND_FATHER) and \
               e[0] in (subset or self) and \
               e[1] in (subset or self):

                tmp.add_edge(e)

        # Then organize nodes into layers

        #layers_by_id = tmp.rank_longest_path()
        layers_by_id = tmp.rank_minimize_dummy_vertices()

        layers = tmp.get_layers(layers_by_id=layers_by_id)
        print "MANU layers=%s" % (layers, )

        # Organize the nodes within layers
        tmp.sort_nodes_within_layers(layers)
        print "MANU sorted layers=%s" % (layers, )

        # Compute the families
        families = __compute_families(tmp, layers, layers_by_id)
        print "MANU sorted families=%s" % (families, )

        print "MANU graph=%s" % tmp

        result = []
        for lay in range(0, len(layers)):
            result.append(
                [(n.main_id, n.name.encode("utf-8"), n.sex)
                 for n in layers[lay]])

        # for index, l in enumerate(result):
        #    print "MANU layer[%d] = %s" % (index, sorted([p[0] for p in l]))
        return {"persons": to_json(result, year_only=True),
                "families": families}
Esempio n. 30
0
def editCitation(request, source_id):
    """
    Perform some changes in the citation parts for a source, and returns a
    JSON with the list of parts and their values.
    """
    src = models.Source.objects.get(id=source_id)

    if request.method == 'POST':
        new_type = request.POST.get('sourceMediaType')

        src.parts.all().delete()

        if src.medium != new_type:
            parts = Citations.get_citation(new_type).required_parts()
        else:
            parts = None

        for key, value in request.POST.iteritems():
            if key in ('csrfmiddlewaretoken', 'sourceId'):
                continue
            elif key == 'sourceMediaType':
                # Only set the medium if different from the parent. Otherwise,
                # leave it null, so that changing the parent also changes the
                # lower level sources
                if src.higher_source is None or src.higher_source.medium != value:
                    src.medium = value
                else:
                    src.medium = None
            elif key == '_notes':
                src.comments = value
            elif key == '_abbrev':
                src.abbrev = value
            elif key == '_biblio':
                src.biblio = value
            elif key == '_title':
                src.title = value
            elif key == '_subjectDate':
                src.subject_date = value
            elif key == '_subjectPlace':
                pass
                # src.subject_place = value
            elif key == '_jurisdictionPlace':
                pass
                #src.jurisdiction_place = value
            elif key in ('_repoName', '_repoType', '_repoAddr'):
                # ??? Not handled yet
                pass
            elif key == '_higherSource':
                src.higher_source_id = int(value)
            elif key[0] == '_':
                raise Exception('Field not processed: %s' % key)
            elif value and (parts is None or key in parts):
                # A citation part
                try:
                    type = models.Citation_Part_Type.objects.get(name=key)
                except models.Citation_Part_Type.DoesNotExist:
                    type = models.Citation_Part_Type.objects.create(name=key)
                    type.save()

                p = models.Citation_Part(type=type, value=value)
                src.parts.add(p)

        medium = src.compute_medium()
        if medium:
            params = prepare_citation_parts(src.higher_source, request.POST)
            c = Citations.get_citation(medium).cite(params,
                                                    unknown_as_text=False)
            src.biblio = c.biblio
            src.title = c.full
            src.abbrev = c.short

        src.save()

    return HttpResponse(to_json(list_of_citations(src.medium, src)),
                        content_type="application/json")
Esempio n. 31
0
def view_list(request):
    """View the list of all sources"""

    sources = models.Source.objects.order_by('abbrev', 'title')
    return HttpResponse(to_json(sources), content_type='application/json')
Esempio n. 32
0
def view_list(request):
    """View the list of a all known places"""

    # ??? How do we get the list of parts immediately too ?
    places = models.Place.objects.order_by('name')
    return HttpResponse(to_json(places), content_type='application/json')
Esempio n. 33
0
def view(request, decujus=1):
    """Display the statistics for a given person"""

    decujus = int(decujus)

    graph.update_if_needed()
    if len(graph) == 0:
        return render_to_response('geneaprove/firsttime.html',
                                  context_instance=RequestContext(request))

    # ??? The stats includes persons "Unknown" that were created during a
    # gedcom import for the purpose of preserving families. Will be fixed
    # when we store children differently (for instance in a group)

    distance = dict()
    ancestors = graph.people_in_tree(id=decujus, distance=distance)
    persons = extended_personas(nodes=ancestors,
                                styles=None,
                                event_types=event_types_for_pedigree,
                                graph=graph)

    f = graph.fathers(decujus)
    fathers = graph.people_in_tree(id=f[0], maxdepthDescendants=0) if f else []
    m = graph.mothers(decujus)
    mothers = graph.people_in_tree(id=m[0], maxdepthDescendants=0) if m else []

    cal = CalendarGregorian()

    generations = dict()  # list of persons for each generation
    for a in ancestors:
        d = distance[a]
        if d not in generations:
            generations[d] = []
        generations[d].append(a)

    ranges = []

    for index in sorted(generations.keys()):
        births = None
        deaths = None
        gen_range = [index + 1, "?", "?", ""]  # gen, min, max, legend
        for p in generations[index]:
            p = persons[p.main_id]
            if p.birth and p.birth.Date:
                if births is None or p.birth.Date < births:
                    births = p.birth.Date
                    year = p.birth.Date.year(cal)
                    if year is not None:
                        gen_range[1] = year

            if p.death and p.death.Date:
                if deaths is None or p.death.Date > deaths:
                    deaths = p.death.Date
                    year = p.death.Date.year(cal)
                    if year is not None:
                        gen_range[2] = year

        gen_range[3] = "Generation %02d (%d out of %d) (%s - %s)" \
            % (index + 1, len(generations[index]), 2 ** (index + 1),
               gen_range[1], gen_range[2])

        # Postprocess the ranges:
        #   generation n's earliest date has to be at least 15 years before
        #     its children's earliest date (can't have children before that)
        #   generation n's latest date (death) has to be after the children's
        #     generation earliest date (first birth)

        if len(ranges) > 0:
            if gen_range[1] == "?":
                gen_range[1] = ranges[-1][1] - 15
            if gen_range[2] == "?" or gen_range[2] < ranges[-1][1]:
                gen_range[2] = ranges[-1][1]
        if gen_range[2] == '?':
            gen_range[2] = datetime.datetime.now().year

        ranges.append(gen_range)

    ages = []
    for a in range(0, 120, 5):
        ages.append([a, 0, 0, 0])  # date_range, males, females, unknown

    for p in persons.itervalues():
        if p.birth and p.birth.Date and p.death and p.death.Date:
            age = p.death.Date.years_since(p.birth.Date)
            if age is not None:
                if p.sex == "M":
                    ages[int(age / 5)][1] += 1
                elif p.sex == "F":
                    ages[int(age / 5)][2] += 1
                else:
                    ages[int(age / 5)][3] += 1

    data = {
        "total_ancestors":
        len(ancestors),
        "total_father":
        len(fathers),
        "total_mother":
        len(mothers),
        "total_persons":
        len(graph),
        "ranges":
        ranges,
        "ages":
        ages,
        "decujus":
        decujus,
        "decujus_name":
        "%s %s" % (persons[decujus].given_name, persons[decujus].surname)
    }

    return HttpResponse(to_json(data), content_type='application/json')