Merge branch 'gramps51'

This commit is contained in:
prculley 2019-11-08 11:46:40 -06:00
commit e3eedb2219
59 changed files with 15495 additions and 26407 deletions

View File

@ -473,11 +473,10 @@ table.eventlist tbody tr td.ColumnSources {
margin: 0px auto; margin: 0px auto;
display: block; display: block;
border: solid 1px #999; border: solid 1px #999;
max-width: 800px;
height: auto; height: auto;
} }
@media only screen and (max-width: 1080px) { @media only screen and (max-width: 1600px) {
#GalleryDisplay img { #GalleryDisplay img {
max-width: 100%; max-width: 100%;
} }

View File

@ -838,11 +838,10 @@ div#EventDetail table.eventlist tbody tr td.ColumnDate {
} }
#GalleryDisplay img { #GalleryDisplay img {
margin: 0 auto; margin: 0 auto;
max-width: 800px;
height: auto; height: auto;
} }
@media only screen and (max-width: 1080px) { @media only screen and (max-width: 1600px) {
#GalleryDisplay img { #GalleryDisplay img {
max-width: 100%; max-width: 100%;
} }

View File

@ -524,11 +524,10 @@ table.eventlist tbody tr td.ColumnSources {
margin: 0px auto; margin: 0px auto;
display: block; display: block;
border: solid 1px #7C8F7C; border: solid 1px #7C8F7C;
max-width: 800px;
height: auto; height: auto;
} }
@media only screen and (max-width: 1080px) { @media only screen and (max-width: 1600px) {
#GalleryDisplay img { #GalleryDisplay img {
max-width: 100%; max-width: 100%;
} }

View File

@ -512,15 +512,15 @@ table.eventlist tbody tr td.ColumnSources {
margin: 0px auto; margin: 0px auto;
display: block; display: block;
border: solid 1px #669; border: solid 1px #669;
max-width: 800px;
height: auto; height: auto;
} }
@media only screen and (max-width: 1080px) { @media only screen and (max-width: 1600px) {
#GalleryDisplay img { #GalleryDisplay img {
max-width: 100%; max-width: 100%;
} }
} }
#GalleryDetail h3 { #GalleryDetail h3 {
text-align: center; text-align: center;
} }

View File

@ -512,11 +512,10 @@ table.eventlist tbody tr td.ColumnSources {
margin: 0px auto; margin: 0px auto;
display: block; display: block;
border: solid 1px #EA8414; border: solid 1px #EA8414;
max-width: 800px;
height: auto; height: auto;
} }
@media only screen and (max-width: 1080px) { @media only screen and (max-width: 1600px) {
#GalleryDisplay img { #GalleryDisplay img {
max-width: 100%; max-width: 100%;
} }

View File

@ -513,11 +513,10 @@ table.eventlist tbody tr td.ColumnSources {
margin: 0px auto; margin: 0px auto;
display: block; display: block;
border: solid 1px #7CA3DD; border: solid 1px #7CA3DD;
max-width: 800px;
height: auto; height: auto;
} }
@media only screen and (max-width: 1080px) { @media only screen and (max-width: 1600px) {
#GalleryDisplay img { #GalleryDisplay img {
max-width: 100%; max-width: 100%;
} }

View File

@ -82,6 +82,7 @@ body > div {
} }
.content { .content {
padding: 1.5em 1.5em; padding: 1.5em 1.5em;
overflow: auto;
background: url(../images/Web_Mainz_Mid.png) #FFF2C6 repeat; background: url(../images/Web_Mainz_Mid.png) #FFF2C6 repeat;
} }
#ThumbnailPreview div.snapshot { #ThumbnailPreview div.snapshot {
@ -467,11 +468,10 @@ table.eventlist tbody tr td.ColumnSources {
margin: 0px auto; margin: 0px auto;
display:block; display:block;
border: solid 1px #7D5925; border: solid 1px #7D5925;
max-width: 800px;
height: auto; height: auto;
} }
@media only screen and (max-width: 1080px) { @media only screen and (max-width: 1600px) {
#GalleryDisplay img { #GalleryDisplay img {
max-width: 100%; max-width: 100%;
} }

View File

@ -747,11 +747,10 @@ table.eventlist tbody tr td.ColumnSources {
} }
#GalleryDisplay img { #GalleryDisplay img {
margin:0 auto; margin:0 auto;
max-width: 800px;
height: auto; height: auto;
} }
@media only screen and (max-width: 1080px) { @media only screen and (max-width: 1600px) {
#GalleryDisplay img { #GalleryDisplay img {
max-width: 100%; max-width: 100%;
} }

View File

@ -9,7 +9,7 @@
# the Free Software Foundation; either version 2 of the License, or # the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
@ -20,10 +20,10 @@
# #
# $Id: $ # $Id: $
# #
************************************************************************************************** *******************************************************************************
GRAMPS Cascading Style Sheet GRAMPS Cascading Style Sheet
Style Name: Combined Ancestor Tree Style Sheet Style Name: Combined Ancestor Tree Style Sheet
*************************************************************************************************** *******************************************************************************
# #
===== Ancestor Graph Color Scheme ===== ===== Ancestor Graph Color Scheme =====
Males #BCEAF6 Males #BCEAF6
@ -33,10 +33,8 @@ Unknown #000
===== Web Graphics ===== ===== Web Graphics =====
Males Web_Gender_Male.png Males Web_Gender_Male.png
Females Web_Gender_Female.png Females Web_Gender_Female.png
# ------------------------------------------------------------------------------------------------- */ # -------------------------------------------------------------------------- #
/* Subsections : Ancestors Tree -------------------------------------------- */
/* Subsections : Ancestors Tree
----------------------------------------------------- */
#tree { #tree {
page-break-before:always; page-break-before:always;
margin:0; margin:0;
@ -52,8 +50,8 @@ Females Web_Gender_Female.png
} }
#treeContainer div.boxbg { #treeContainer div.boxbg {
position:absolute; position:absolute;
margin:0; margin:0px;
padding:0; padding:0px;
background:none; background:none;
} }
#treeContainer div.boxbg a, #treeContainer div.boxbg a,
@ -61,41 +59,43 @@ Females Web_Gender_Female.png
position:relative; position:relative;
z-index:10; z-index:10;
display:block; display:block;
font:normal .7em/1.4em sans-serif; font:normal 1.1em/1.4em sans-serif;
text-align:center; text-align:center;
word-break:break-word;
word-wrap:break-word;
text-decoration:none; text-decoration:none;
color: #00029D; color: #00029D;
width:118px; width:280px;
padding:5px 20px 7px 20px; min-height: 70px;
margin-left:16px; margin-left:16px;
background-color: #FFF; border: solid 2px #000;
border: solid 1px #000; border-radius: 10px;
} }
#treeContainer div.boxbg a.noThumb, #treeContainer div.boxbg a.noThumb,
#treeContainer div.AncCol3 a, #treeContainer div.AncCol4 a,
#treeContainer div.AncCol4 a,
#treeContainer div.AncCol3 span.unlinked,
#treeContainer div.AncCol4 span.unlinked { #treeContainer div.AncCol4 span.unlinked {
margin-top:10px; margin-top:10px;
float: right;
} }
#treeContainer div.boxbg a:hover { #treeContainer div.boxbg a:hover {
position:relative; position:relative;
z-index:999; z-index:999;
font-size:1em; font-size:1.3em;
word-break:break-word;
word-wrap:break-word;
text-decoration:none; text-decoration:none;
color: #00029D; color: #00029D;
width:190px; width:400px;
margin-left:-20px; margin-left:-20px;
padding:10px 25px 12px 25px; padding: 0px 0px 0px 40px;
border: solid 2px #000;
} }
#treeContainer div.boxbg a:hover, #treeContainer div.boxbg a:hover,
#treeContainer div.AncCol3 a:hover,
#treeContainer div.AncCol4 a:hover { #treeContainer div.AncCol4 a:hover {
margin-top:-44px; margin-top:-44px;
} }
#treeContainer div.boxbg a.noThumb:hover { #treeContainer div.boxbg a.noThumb:hover {
margin-top:0; margin-top:0;
padding-left: 10px;
} }
#treeContainer div.AncCol0 a:hover { #treeContainer div.AncCol0 a:hover {
margin-left:12px; margin-left:12px;
@ -105,48 +105,73 @@ Females Web_Gender_Female.png
} }
#treeContainer div.boxbg span.thumbnail { #treeContainer div.boxbg span.thumbnail {
display:block; display:block;
max-width:80px; position: absolute;
max-height:65px; max-width:85px;
margin:0 auto; max-height:75px;
padding:4px 0; left: 3px;
top: 3px;
} }
#treeContainer div.boxbg span.thumbnail img { #treeContainer div.boxbg a.thumbnail table td.img {
max-width:80px; padding-right: 5px;
max-height:65px;
margin:0 auto;
} }
#treeContainer div.boxbg a:hover span.thumbnail, #treeContainer div.boxbg a:hover span.thumbnail img { #treeContainer div.boxbg a.thumbnail:hover table td.img {
height:80px; padding-right: 9px;
} }
#treeContainer div.AncCol3 span.thumbnail, #treeContainer div.AncCol4 span.thumbnail { #treeContainer div.boxbg a.thumbnail table td.name {
padding-top:3px;
padding-left: 2px;
padding-right: 23px;
width: 90%;
}
#treeContainer div.boxbg a.thumbnail img {
margin-left:0px;
padding-left: 0px;
border-radius: 5px;
}
#treeContainer div.boxbg a.thumbnail:hover img {
max-height:90%;
margin-left:5px;
position: absolute;
left: 0px;
top: 4px;
border-radius: 5px;
}
#treeContainer div.boxbg table td:first-child, table th:first-child {
padding-left: 5px;
padding-top: 5px;
}
#IndividualDetail div.subsection table tr td:first-child {
padding-left: 5px;
padding-top: 5px;
}
#treeContainer #treeContainer div.AncCol4 span.thumbnail {
display:none; display:none;
} }
#treeContainer div.boxbg a:hover span.thumbnail { #treeContainer div.boxbg a:hover span.thumbnail {
display:block; display:block;
} }
#treeContainer div.boxbg span.fullname { #treeContainer div.boxbg span.fullname {
display: none; display: none;
} }
#treeContainer div.boxbg span.shortname { #treeContainer div.boxbg span.shortname {
display: inline; display: inline;
} }
#treeContainer div.boxbg a:hover span.fullname { #treeContainer div.boxbg a:hover span.fullname {
display: inline; display: inline;
} }
#treeContainer div.boxbg a:hover span.shortname { #treeContainer div.boxbg a:hover span.shortname {
display: none; display: none;
} }
#treeContainer div.boxbg a:hover {
float: right;
margin-top: 10px;
border: solid 4px #000;
}
#treeContainer div.male a, #treeContainer div.male a,
#treeContainer div.male span.unlinked { #treeContainer div.male span.unlinked {
background:url(../images/Web_Gender_Male.png) #BCEAF6 no-repeat top right; background:url(../images/Web_Gender_Male.png) #BCEAF6 no-repeat top right;
} }
#treeContainer div.female a, #treeContainer div.female a,
#treeContainer div.female span.unlinked { #treeContainer div.female span.unlinked {
background:url(../images/Web_Gender_Female.png) #FFC0CB no-repeat top right; background:url(../images/Web_Gender_Female.png) #FFC0CB no-repeat top right;
} }

View File

@ -9,6 +9,12 @@ beg
- h Hans_Peter.8 17/4/1904 #bp Rønne,_Bornholm,_Denmark 29/1/1977 #dp San_Francisco,_San_Francisco_Co.,_CA - h Hans_Peter.8 17/4/1904 #bp Rønne,_Bornholm,_Denmark 29/1/1977 #dp San_Francisco,_San_Francisco_Co.,_CA
end end
notes Hansdotter Anna.1
beg
******************************************************************890123456789
******************************************************************89 123456789
end notes
notes Smith Hjalmar.5 notes Smith Hjalmar.5
beg beg
BIOGRAPHY BIOGRAPHY
@ -61,7 +67,7 @@ Some Bold Unicode Characters: ࣶǼЀج⿄㑝&#15691
Some Italic Unicode Characters: ࣶǼЀج⿄㑝㵋圛墉幵聟聦𐅉🚶🛈 Some Italic Unicode Characters: ࣶǼЀج⿄㑝㵋圛墉幵聟聦𐅉🚶🛈
end notes end notes
fam Smith Gus.6 +~1920 Michaels Evelyn.25 ~1897 fam Smith Gus.6 +~1920 Michaels Evelyn.25 ~1897 0
fam Smith Hjalmar.5 +31/10/1927 #mp Reno,_Washoe_Co.,_NV Ohman Marjorie.26 3/6/1903 #bp Denver,_Denver_Co.,_CO,_Denver_Co.,_Colorado,_USA 22/6/1980 #dp Reno,_Washoe_Co.,_NV fam Smith Hjalmar.5 +31/10/1927 #mp Reno,_Washoe_Co.,_NV Ohman Marjorie.26 3/6/1903 #bp Denver,_Denver_Co.,_CO,_Denver_Co.,_Colorado,_USA 22/6/1980 #dp Reno,_Washoe_Co.,_NV
beg beg
@ -98,13 +104,18 @@ beg
- h Martin.17 1794..1796 #bp Tommarp,_Kristianstad_Län,_Sweden #dp Sweden - h Martin.17 1794..1796 #bp Tommarp,_Kristianstad_Län,_Sweden #dp Sweden
end end
fam Willard Edwin.42 ~1886 +~1910 Smith Kirsti_Marie.2 fam Willard Edwin.42 ~1886 0 +~1910 Smith Kirsti_Marie.2
fam Smith Magnes.38 +24/8/1884 #mp Rønne,_Bornholm,_Denmark Streiffert Anna.43 23/9/1860 #bp Hoya/Jona/Hoia,_Sweden 2/2/1927 #dp Rønne,_Bornholm,_Denmark fam Smith Magnes.38 +24/8/1884 #mp Rønne,_Bornholm,_Denmark Streiffert Anna.43 23/9/1860 #bp Hoya/Jona/Hoia,_Sweden 2/2/1927 #dp Rønne,_Bornholm,_Denmark
fam Tester The.14 + Tester Mrs.44 0 fam Tester The.14 + Tester Mrs.44 0
beg beg
- h Tom.45 0 - h Tom.45 Von_Tester_y_tested 0
- Fake.46 von_Person 1954 #bp Fremont,_Alameda_Co.,_CA
- f Mary.47 0
- f Martha.48 0
- h John.49 0
- h Mark.50 0
end end
notes Tester Mrs.44 notes Tester Mrs.44

File diff suppressed because it is too large Load Diff

View File

@ -1,47 +1,52 @@
Anna Hansdotter;;;;;2/10/1864-29/9/1945 Anna Hansdotter;;;;;2/10/1864-29/9/1945
Keith Lloyd Smith;Lloyd Smith;Janis Green;;;11/8/1966 Keith Lloyd Smith;Lloyd Smith;Janis Green;;;11/8/1966
Hans Peter Smith;Gustaf Smith;Anna Hansdotter;;;17/4/1904-29/1/1977 Hans Peter Smith;Gustaf Smith;Anna Hansdotter;;;17/4/1904-29/1/1977
Hanna Smith;Martin Smith0;Elna Jefferson;;;29/1/1821 Hanna Smith;Martin Smith0;Elna Jefferson;;;29/1/1821
Herman Julius Nielsen;;;;;31/8/1889-1945 Herman Julius Nielsen;;;;;31/8/1889-1945
Evelyn Michaels;;;;;1897 Evelyn Michaels;;;;;1897
Marjorie Lee Smith;Hjalmar Smith0;Marjorie Ohman;;;4/11/1934 Marjorie Lee Smith;Hjalmar Smith0;Marjorie Ohman;;;4/11/1934
Gus Smith;Gustaf Smith;Anna Hansdotter;;;11/9/1897-21/10/1963 Gus Smith;Gustaf Smith;Anna Hansdotter;;;11/9/1897-21/10/1963
Jennifer Anderson;;;;;5/11/1907-29/5/1985 Jennifer Anderson;;;;;5/11/1907-29/5/1985
Lillie Harriet Jones;;;;;2/5/1910-26/6/1990 Lillie Harriet Jones;;;;;2/5/1910-26/6/1990
John Hjalmar Smith;Hjalmar Smith0;Marjorie Ohman;;;30/1/1932 John Hjalmar Smith;Hjalmar Smith0;Marjorie Ohman;;;30/1/1932
Eric Lloyd Smith;Lloyd Smith;Janis Green;;;28/8/1963 Eric Lloyd Smith;Lloyd Smith;Janis Green;;;28/8/1963
Amber Marie Smith;Edwin Smith;Janice Adams;;;12/4/1998 Amber Marie Smith;Edwin Smith;Janice Adams;;;12/4/1998
Carl Emil Smith;Gustaf Smith;Anna Hansdotter;;;20/12/1899-28/1/1959 Carl Emil Smith;Gustaf Smith;Anna Hansdotter;;;20/12/1899-28/1/1959
Hjalmar Smith;Gustaf Smith;Anna Hansdotter;;;31/1/1893-25/9/1894 Hjalmar Smith;Gustaf Smith;Anna Hansdotter;;;31/1/1893-25/9/1894
Martin Smith;Martin Smith0;Elna Jefferson;;;19/11/1830-1899 Martin Smith;Martin Smith0;Elna Jefferson;;;19/11/1830-1899
Astrid Shermanna Augusta Smith;Gustaf Smith;Anna Hansdotter;;;31/1/1889-21/12/1963 Astrid Shermanna Augusta Smith;Gustaf Smith;Anna Hansdotter;;;31/1/1889-21/12/1963
Gustaf Smith, Sr.;Martin Smith;Kerstina Hansdotter;;;28/11/1862-23/7/1930 Gustaf Smith, Sr.;Martin Smith;Kerstina Hansdotter;;;28/11/1862-23/7/1930
Marta Ericsdotter;;;;;1775 Marta Ericsdotter;;;;;1775
Kirsti Marie Smith;Gustaf Smith;Anna Hansdotter;;;15/12/1886-18/7/1966 Kirsti Marie Smith;Gustaf Smith;Anna Hansdotter;;;15/12/1886-18/7/1966
Ingeman Smith;;;;;1770 Ingeman Smith;;;;;1770
Anna Streiffert;;;;;23/9/1860-2/2/1927 Anna Streiffert;;;;;23/9/1860-2/2/1927
Craig Peter Smith;Lloyd Smith;Janis Green;;;1966 Craig Peter Smith;Lloyd Smith;Janis Green;;;1966
Magnes Smith;Martin Smith;Kerstina Hansdotter;;;6/10/1858-20/2/1910 Magnes Smith;Martin Smith;Kerstina Hansdotter;;;6/10/1858-20/2/1910
Janice Ann Adams;;;;;26/8/1965 Janice Ann Adams;;;;;26/8/1965
Marjorie Ohman;;;;;3/6/1903-22/6/1980 Marjorie Ohman;;;;;3/6/1903-22/6/1980
Darcy Horne;;;;;2/7/1966 Darcy Horne;;;;;2/7/1966
Alice Paula Perkins;;;;;22/11/1933 Lloyd Smith;Hans Smith;Lillie Jones;;;13/3/1935
Lars Peter Smith;Eric Smith;Darcy Horne;;;16/9/1991 Alice Paula Perkins;;;;;22/11/1933
Ingeman Smith0;Martin Smith0;Elna Jefferson;;;29/1/1826 Lars Peter Smith;Eric Smith;Darcy Horne;;;16/9/1991
Lloyd Smith;Hans Smith;Lillie Jones;;;13/3/1935 Elna Jefferson;;;;;14/9/1800-
Elna Jefferson;;;;;14/9/1800- Edwin Michael Smith;John Smith;Alice Perkins;;;24/5/1961
Edwin Michael Smith;John Smith;Alice Perkins;;;24/5/1961 Kerstina Hansdotter;;;;;29/11/1832-1908
Kerstina Hansdotter;;;;;29/11/1832-1908 Martin Smith0;Ingeman Smith;Marta Ericsdotter;;;1794-
Martin Smith0;Ingeman Smith;Marta Ericsdotter;;;1794- Ingeman Smith0;Martin Smith0;Elna Jefferson;;;29/1/1826
Marjorie Alice Smith0;John Smith;Alice Perkins;;;5/2/1960 Marjorie Alice Smith0;John Smith;Alice Perkins;;;5/2/1960
Janis Elaine Green;;;;;2/12/1935 Janis Elaine Green;;;;;2/12/1935
Mason Michael Smith;Edwin Smith;Janice Adams;;;26/6/1996 Mason Michael Smith;Edwin Smith;Janice Adams;;;26/6/1996
Edwin Willard;;;;;1886 Edwin Willard;;;;;1886
Ingar Smith;Martin Smith0;Elna Jefferson;;;1823 Ingar Smith;Martin Smith0;Elna Jefferson;;;1823
Hjalmar Smith0;Gustaf Smith;Anna Hansdotter;;;7/4/1895-26/6/1975 Hjalmar Smith0;Gustaf Smith;Anna Hansdotter;;;7/4/1895-26/6/1975
Emil Smith;Martin Smith;Kerstina Hansdotter;;;27/9/1860 Emil Smith;Martin Smith;Kerstina Hansdotter;;;27/9/1860
雪 Ke 柯;Herman Nielsen;Astrid Smith;;; 雪 Ke 柯;Herman Nielsen;Astrid Smith;;;
The Tester;Lloyd Smith;Janis Green;;;29/12/1954 ピーター リチミシキスイミ;;;;;
Mrs Tester;;;;; The Tester;Lloyd Smith;Janis Green;;;29/12/1954
ピーター リチミシキスイミ;;;;; Mrs Tester;;;;;
Tom Tester;The Tester;Mrs Tester;;; Tom Von Tester y tested;The Tester;Mrs Tester;;;
Fake von Person, I;The Tester;Mrs Tester;;;1954-
Mary Tester;The Tester;Mrs Tester;;;
Martha Tester;The Tester;Mrs Tester;;;
John Tester;The Tester;Mrs Tester;;;
Mark Tester;The Tester;Mrs Tester;;;

View File

@ -30,66 +30,65 @@
[P0014],"Denver, Denver Co., CO","Denver, Denver Co., CO",City,39.7392,104.9903 W,,[P0024], [P0014],"Denver, Denver Co., CO","Denver, Denver Co., CO",City,39.7392,104.9903 W,,[P0024],
Person,Surname,Given,Call,Suffix,Prefix,Title,Gender,Birth date,Birth place,Birth source,Baptism date,Baptism place,Baptism source,Death date,Death place,Death source,Burial date,Burial place,Burial source,Note Person,Surname,Given,Call,Suffix,Prefix,Title,Gender,Birth date,Birth place,Birth source,Baptism date,Baptism place,Baptism source,Death date,Death place,Death source,Burial date,Burial place,Burial source,Note
[I0030],Adams,Janice Ann,,,,,female,26 Aug 1965,"Fremont, Alameda Co., CA",,,,,,,,,,, [I0030],Adams,Janice Ann,,,,,female,1965-08-26,[P0013],,,,,,,,,,,
[I0016],Anderson,Jennifer,,,,,female,5 Nov 1907,"Rønne, Bornholm, Denmark",,,,,29 May 1985,"San Francisco, San Francisco Co., CA",,,,, [I0016],Anderson,Jennifer,,,,,female,1907-11-05,[P0003],,,,,1985-05-29,[P0002],,,,,
[I0025],Ericsdotter,Marta,,,,,female,about 1775,Sweden,,,,,,,,,,, [I0025],Ericsdotter,Marta,,,,,female,about 1775,[P0008],,,,,,,,,,,
[I0041],Green,Janis Elaine,,,,,female,2 Dec 1935,,,,,,,,,,,, [I0041],Green,Janis Elaine,,,,,female,1935-12-02,,,,,,,,,,,,
[I0000],Hansdotter,Anna,,,,,female,2 Oct 1864,"Löderup, Malmöhus Län, Sweden",,,,,29 Sep 1945,"Sparks, Washoe Co., NV",,,,, [I0000],Hansdotter,Anna,,,,,female,1864-10-02,[P0000],,,,,1945-09-29,[P0001],,,,,
[I0038],Hansdotter,Kerstina,,,,,female,29 Nov 1832,"Smestorp, Kristianstad Län, Sweden",,,,,before 1908,Sweden,,,,, [I0038],Hansdotter,Kerstina,,,,,female,1832-11-29,[P0019],,,,,before 1908,[P0008],,,,,
[I0032],Horne,Darcy,,,,,female,2 Jul 1966,"Sacramento, Sacramento Co., CA",,,,,,,,,,, [I0032],Horne,Darcy,,,,,female,1966-07-02,[P0015],,,,,,,,,,,
[I0036],Jefferson,Elna,,,,,female,14 Sep 1800,"Gladsax, Kristianstad Län, Sweden",,,,,,Sweden,,,,, [I0036],Jefferson,Elna,,,,,female,1800-09-14,[P0004],,,,,,[P0008],,,,,
[I0017],Jones,Lillie Harriet,,,,,female,2 May 1910,"Rønne, Bornholm, Denmark",,,,,26 Jun 1990,,,,,, [I0017],Jones,Lillie Harriet,,,,,female,1910-05-02,[P0003],,,,,1990-06-26,,,,,,
[I0042],Ke 柯,雪,,,,,male,,,,,,,,,,,,, [I0042],Ke 柯,雪,,,,,male,,,,,,,,,,,,,
[I0013],Michaels,Evelyn,,,,,female,about 1897,,,,,,,,,,,, [I0013],Michaels,Evelyn,,,,,female,about 1897,,,,,,,,,,,,
[I0012],Nielsen,Herman Julius,,,,,male,31 Aug 1889,"Rønne, Bornholm, Denmark",,,,,1945,,,,,, [I0012],Nielsen,Herman Julius,,,,,male,1889-08-31,[P0003],,,,,1945,,,,,,
[I0031],Ohman,Marjorie,,,,,female,3 Jun 1903,"Denver, Denver Co., CO, Denver Co., Colorado, USA",,,,,22 Jun 1980,"Reno, Washoe Co., NV",,,,, [I0031],Ohman,Marjorie,,,,,female,1903-06-03,[P0014],,,,,1980-06-22,[P0005],,,,,
[I0034],Perkins,Alice Paula,,,,,female,22 Nov 1933,"Sparks, Washoe Co., NV",,,,,,,,,,, [I0034],Perkins,Alice Paula,,,,,female,1933-11-22,[P0001],,,,,,,,,,,
[I0002],Smith,Amber Marie,,,,,female,12 Apr 1998,"Hayward, Alameda Co., CA",,,,,,,,,,, [I0002],Smith,Amber Marie,,,,,female,1998-04-12,[P0006],,,,,,,,,,,
[I0023],Smith,Astrid Shermanna Augusta,,,,,female,31 Jan 1889,"Rønne, Bornholm, Denmark",,,,,21 Dec 1963,"San Francisco, San Francisco Co., CA",,,,, [I0023],Smith,Astrid Shermanna Augusta,,,,,female,1889-01-31,[P0003],,,,,1963-12-21,[P0002],,,,,
[I0020],Smith,Carl Emil,,,,,male,20 Dec 1899,"Rønne, Bornholm, Denmark",,,,,28 Jan 1959,"Reno, Washoe Co., NV",,,,, [I0020],Smith,Carl Emil,,,,,male,1899-12-20,[P0003],,,,,1959-01-28,[P0005],,,,,
[I0029],Smith,Craig Peter,,,,,male,after 1966,"San Francisco, San Francisco Co., CA",,,,,,,,,,, [I0029],Smith,Craig Peter,,,,,male,after 1966,[P0002],,,,,,,,,,,
[I0037],Smith,Edwin Michael,,,,,male,24 May 1961,"San Jose, Santa Clara Co., CA","Birth, Death and Marriage Records",,,,,,,,,, [I0037],Smith,Edwin Michael,,,,,male,1961-05-24,[P0017],"Birth, Death and Marriage Records",,,,,,,,,,
[I0009],Smith,Emil,,,,,male,27 Sep 1860,"Simrishamn, Kristianstad Län, Sweden",,,,,,,,,,, [I0009],Smith,Emil,,,,,male,1860-09-27,[P0012],,,,,,,,,,,
[I0019],Smith,Eric Lloyd,,,,Dr.,male,28 Aug 1963,"San Francisco, San Francisco Co., CA",,,,,,,,,,, [I0019],Smith,Eric Lloyd,,,,Dr.,male,1963-08-28,[P0002],,,,,,,,,,,
[I0015],Smith,Gus,,,,,male,11 Sep 1897,"Rønne, Bornholm, Denmark",,,,,21 Oct 1963,"San Francisco, San Francisco Co., CA",,,,, [I0015],Smith,Gus,,,,,male,1897-09-11,[P0003],,,,,1963-10-21,[P0002],,,,,
[I0024],Smith,Gustaf,,Sr.,,,male,28 Nov 1862,"Grostorp, Kristianstad Län, Sweden",,,,,before 23 Jul 1930,"Sparks, Washoe Co., NV",,,,, [I0024],Smith,Gustaf,,Sr.,,,male,1862-11-28,[P0009],,,,,before 1930-07-23,[P0001],,,,,
[I0011],Smith,Hanna,,,,,female,29 Jan 1821,"Gladsax, Kristianstad Län, Sweden",,,,,,,,,,, [I0011],Smith,Hanna,,,,,female,1821-01-29,[P0004],,,,,,,,,,,
[I0010],Smith,Hans Peter,,,,,male,17 Apr 1904,"Rønne, Bornholm, Denmark",Birth Records,,,,29 Jan 1977,"San Francisco, San Francisco Co., CA",,5 Feb 1977,"San Francisco, San Francisco Co., CA",findagrave.com, [I0010],Smith,Hans Peter,,,,,male,1904-04-17,[P0003],Birth Records,,,,1977-01-29,[P0002],,1977-02-05,[P0002],findagrave.com,
[I0021],Smith,Hjalmar,,,,,male,31 Jan 1893,"Rønne, Bornholm, Denmark",,,,,25 Sep 1894,"Rønne, Bornholm, Denmark",,,,, [I0021],Smith,Hjalmar,,,,,male,1893-01-31,[P0003],,,,,1894-09-25,[P0003],,,,,
[I0008],Smith,Hjalmar,,,,,male,7 Apr 1895,"Rønne, Bornholm, Denmark",,3 Jun 1895,"Rønne Bornholm, Denmark",,26 Jun 1975,"Reno, Washoe Co., NV",,,,, [I0008],Smith,Hjalmar,,,,,male,1895-04-07,[P0003],,1895-06-03,[P0021],,1975-06-26,[P0005],,,,,
[I0007],Smith,Ingar,,,,,female,after 1823,"Gladsax, Kristianstad Län, Sweden",,,,,,,,,,, [I0007],Smith,Ingar,,,,,female,after 1823,[P0004],,,,,,,,,,,
[I0027],Smith,Ingeman,,,,,male,about 1770,Sweden,,,,,,,,,,, [I0027],Smith,Ingeman,,,,,male,about 1770,[P0008],,,,,,,,,,,
[I0004],Smith,Ingeman,,,,,male,29 Jan 1826,"Gladsax, Kristianstad Län, Sweden",,,,,,,,,,, [I0004],Smith,Ingeman,,,,,male,1826-01-29,[P0004],,,,,,,,,,,
[I0018],Smith,John Hjalmar,,,,,male,30 Jan 1932,"San Francisco, San Francisco Co., CA",,,,,,,,,,, [I0018],Smith,John Hjalmar,,,,,male,1932-01-30,[P0002],,,,,,,,,,,
[I0001],Smith,Keith Lloyd,,,,,male,11 Aug 1966,"San Francisco, San Francisco Co., CA",,,,,,,,,,, [I0001],Smith,Keith Lloyd,,,,,male,1966-08-11,[P0002],,,,,,,,,,,
[I0026],Smith,Kirsti Marie,,,,,female,15 Dec 1886,"Rønne, Bornholm, Denmark",,,,,18 Jul 1966,"San Francisco, San Francisco Co., CA",,,,, [I0026],Smith,Kirsti Marie,,,,,female,1886-12-15,[P0003],,,,,1966-07-18,[P0002],,,,,
[I0035],Smith,Lars Peter,,,,,male,16 Sep 1991,"Santa Rosa, Sonoma Co., CA",,,,,,,,,,, [I0035],Smith,Lars Peter,,,,,male,1991-09-16,[P0016],,,,,,,,,,,
[I0033],Smith,Lloyd,,,,,male,13 Mar 1935,"San Francisco, San Francisco Co., CA",,,,,,,,,,, [I0033],Smith,Lloyd,,,,,male,1935-03-13,[P0002],,,,,,,,,,,
[I0003],Smith,Magnes,,,,,male,6 Oct 1858,"Simrishamn, Kristianstad Län, Sweden",,,,,20 Feb 1910,"Rønne, Bornholm, Denmark",,,,, [I0003],Smith,Magnes,,,,,male,1858-10-06,[P0012],,,,,1910-02-20,[P0003],,,,,
[I0040],Smith,Marjorie Alice,,,,,female,5 Feb 1960,"San Jose, Santa Clara Co., CA",,,,,,,,,,, [I0040],Smith,Marjorie Alice,,,,,female,1960-02-05,[P0017],,,,,,,,,,,
[I0014],Smith,Marjorie Lee,,,,,female,4 Nov 1934,"Reno, Washoe Co., NV",,,,,,,,,,, [I0014],Smith,Marjorie Lee,,,,,female,1934-11-04,[P0005],,,,,,,,,,,
[I0022],Smith,Martin,,,,,male,19 Nov 1830,"Gladsax, Kristianstad Län, Sweden",,23 Nov 1830,"Gladsax, Kristianstad Län, Sweden",,between 1899 and 1905,Sweden,,,,, [I0022],Smith,Martin,,,,,male,1830-11-19,[P0004],,1830-11-23,[P0004],,between 1899 and 1905,[P0008],,,,,
[I0039],Smith,Martin,,,,,male,between 1794 and 1796,"Tommarp, Kristianstad Län, Sweden",,,,,,Sweden,,,,, [I0039],Smith,Martin,,,,,male,between 1794 and 1796,[P0020],,,,,,[P0008],,,,,
[I0005],Smith,Mason Michael,,,,,male,26 Jun 1996,"Hayward, Alameda Co., CA",,,,,,,,,,, [I0005],Smith,Mason Michael,,,,,male,1996-06-26,[P0006],,,,,,,,,,,
[I0028],Streiffert,Anna,,,,,female,23 Sep 1860,"Hoya/Jona/Hoia, Sweden",,,,,2 Feb 1927,"Rønne, Bornholm, Denmark",,,,, [I0028],Streiffert,Anna,,,,,female,1860-09-23,[P0011],,,,,1927-02-02,[P0003],,,,,
[I0006],Willard,Edwin,,,,,male,about 1886,,,,,,,,,,,, [I0006],Willard,Edwin,,,,,male,about 1886,,,,,,,,,,,,
[I0043],リチミシキスイミ,ピーター,,,,,male,,,,,,,,,,,,,
Marriage,Husband,Wife,Date,Place,Source,Note Marriage,Husband,Wife,Date,Place,Source,Note
[F0000],[I0039],[I0036],about 1816,"Gladsax, Kristianstad Län, Sweden",, [F0000],[I0039],[I0036],about 1816,[P0004],,
[F0001],[I0027],[I0025],about 1790,Sweden,, [F0001],[I0027],[I0025],about 1790,[P0008],,
[F0002],[I0022],[I0038],about 1856,,, [F0002],[I0022],[I0038],about 1856,,,
[F0003],[I0024],[I0000],27 Nov 1885,"Rønne, Bornholm, Denmark",, [F0003],[I0024],[I0000],1885-11-27,[P0003],,
[F0004],[I0006],[I0026],about 1910,,, [F0004],[I0006],[I0026],about 1910,,,
[F0005],[I0012],[I0023],30 Nov 1912,"Rønne, Bornholm, Denmark",, [F0005],[I0012],[I0023],1912-11-30,[P0003],,
[F0006],[I0008],[I0031],31 Oct 1927,"Reno, Washoe Co., NV",, [F0006],[I0008],[I0031],1927-10-31,[P0005],,
[F0007],[I0015],[I0013],about 1920,,, [F0007],[I0015],[I0013],about 1920,,,
[F0008],[I0033],[I0041],10 Aug 1958,"San Francisco, San Francisco Co., CA",, [F0008],[I0033],[I0041],1958-08-10,[P0002],,
[F0009],[I0010],[I0017],,,, [F0009],[I0010],[I0017],,,,
[F0010],[I0019],[I0032],12 Jul 1986,"Woodland, Yolo Co., CA",, [F0010],[I0019],[I0032],1986-07-12,[P0022],,
[F0011],[I0003],[I0028],24 Aug 1884,"Rønne, Bornholm, Denmark",, [F0011],[I0003],[I0028],1884-08-24,[P0003],,
[F0012],[I0018],[I0034],4 Jun 1954,"Sparks, Washoe Co., NV",Marriage Certificae, [F0012],[I0018],[I0034],1954-06-04,[P0001],Marriage Certificae,
[F0013],[I0037],[I0030],27 May 1995,"San Ramon, Conta Costa Co., CA",, [F0013],[I0037],[I0030],1995-05-27,[P0023],,
[F0014],[I0010],[I0016],,,, [F0014],[I0010],[I0016],,,,
Family,Child Family,Child

Can't render this file because it has a wrong number of fields in line 32.

7
debian/changelog vendored
View File

@ -1,3 +1,10 @@
gramps (5.1.1-1) unstable; urgency=medium
* New release
* Add python3-fontconfig to recommends
-- Ross Gammon <rossgammon@debian.org> Tue, 17 Sep 2019 15:21:43 +0200
gramps (5.1.0-1) unstable; urgency=medium gramps (5.1.0-1) unstable; urgency=medium
* New release * New release

3
debian/control vendored
View File

@ -42,7 +42,8 @@ Recommends:
gir1.2-gexiv2-0.10, gir1.2-gexiv2-0.10,
gir1.2-osmgpsmap-1.0, gir1.2-osmgpsmap-1.0,
python3-icu, python3-icu,
gir1.2-geocodeglib-1.0 gir1.2-geocodeglib-1.0,
python3-fontconfig
Suggests: Suggests:
fonts-freefont-ttf, fonts-freefont-ttf,
gir1.2-goocanvas-2.0, gir1.2-goocanvas-2.0,

View File

@ -280,7 +280,7 @@ class CLIManager:
# Attempt to figure out the database title # Attempt to figure out the database title
path = os.path.join(filename, "name.txt") path = os.path.join(filename, "name.txt")
try: try:
with open(path) as ifile: with open(path, encoding='utf8') as ifile:
title = ifile.readline().strip() title = ifile.readline().strip()
except: except:
title = filename title = filename

View File

@ -88,9 +88,9 @@ def _convert_str_to_match_type(str_val, type_val):
return str(str_val) return str(str_val)
elif ret_type == int: elif ret_type == int:
if str_val.isdigit(): try:
return int(str_val) return int(str_val)
else: except ValueError:
print("'%s' is not an integer number" % str_val) print("'%s' is not an integer number" % str_val)
return 0 return 0

View File

@ -757,7 +757,7 @@ class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback):
if self._directory: if self._directory:
filepath = os.path.join(self._directory, "name.txt") filepath = os.path.join(self._directory, "name.txt")
try: try:
with open(filepath, "r") as name_file: with open(filepath, "r", encoding='utf8') as name_file:
name = name_file.readline().strip() name = name_file.readline().strip()
except (OSError, IOError) as msg: except (OSError, IOError) as msg:
LOG.error(str(msg)) LOG.error(str(msg))

View File

@ -212,7 +212,7 @@ def show_settings():
Gtk.get_minor_version(), Gtk.get_micro_version()) Gtk.get_minor_version(), Gtk.get_micro_version())
except: # any failure to 'get' the version except: # any failure to 'get' the version
gtkver_str = 'unknown version' gtkver_str = 'unknown version'
except ImportError: except (ImportError, ValueError):
gtkver_str = 'not found' gtkver_str = 'not found'
# no DISPLAY is a RuntimeError in an older pygtk (e.g. 2.17 in Fedora 14) # no DISPLAY is a RuntimeError in an older pygtk (e.g. 2.17 in Fedora 14)
except RuntimeError: except RuntimeError:

View File

@ -1256,14 +1256,15 @@ class GrampsPreferences(ConfigureDialog):
_("Years, Months, Days")] _("Years, Months, Days")]
list(map(obox.append_text, age_precision)) list(map(obox.append_text, age_precision))
# Combo_box active index is from 0 to 2, we need values from 1 to 3 # Combo_box active index is from 0 to 2, we need values from 1 to 3
constant = 'preferences.age-display-precision' active = config.get('preferences.age-display-precision') - 1
active = config.get(constant) - 1
if active >= 0 and active <= 2: if active >= 0 and active <= 2:
obox.set_active(active) obox.set_active(active)
else: else:
obox.set_active(0) obox.set_active(0)
obox.connect('changed', obox.connect(
lambda obj: config.set(constant, obj.get_active() + 1)) 'changed',
lambda obj: config.set('preferences.age-display-precision',
obj.get_active() + 1))
lwidget = BasicLabel(_("%s: ") lwidget = BasicLabel(_("%s: ")
% _('Age display precision (requires restart)')) % _('Age display precision (requires restart)'))
grid.attach(lwidget, 0, row, 1, 1) grid.attach(lwidget, 0, row, 1, 1)
@ -1300,10 +1301,10 @@ class GrampsPreferences(ConfigureDialog):
obox = Gtk.ComboBoxText() obox = Gtk.ComboBoxText()
formats = FamilyRelType().get_standard_names() formats = FamilyRelType().get_standard_names()
list(map(obox.append_text, formats)) list(map(obox.append_text, formats))
constant = 'preferences.family-relation-type' obox.set_active(config.get('preferences.family-relation-type'))
obox.set_active(config.get(constant))
obox.connect('changed', obox.connect('changed',
lambda obj: config.set(constant, obj.get_active())) lambda obj: config.set('preferences.family-relation-type',
obj.get_active()))
lwidget = BasicLabel(_("%s: ") % _('Default family relationship')) lwidget = BasicLabel(_("%s: ") % _('Default family relationship'))
grid.attach(lwidget, 0, row, 1, 1) grid.attach(lwidget, 0, row, 1, 1)
grid.attach(obox, 1, row, 2, 1) grid.attach(obox, 1, row, 2, 1)
@ -1489,6 +1490,26 @@ class GrampsPreferences(ConfigureDialog):
align=Gtk.Align.CENTER, bold=True) align=Gtk.Align.CENTER, bold=True)
row = 1 row = 1
self.add_pos_int_entry(
grid, _('Markup for invalid date format'),
row, 'preferences.invalid-date-format',
self.update_markup_entry,
helptext=_(
'Convenience markups are:\n'
'<b>&lt;b&gt;Bold&lt;/b&gt;</b>\n'
'<big>&lt;big&gt;'
'Makes font relatively larger&lt;/big&gt;</big>\n'
'<i>&lt;i&gt;Italic&lt;/i&gt;</i>\n'
'<s>&lt;s&gt;Strikethrough&lt;/s&gt;</s>\n'
'<sub>&lt;sub&gt;Subscript&lt;/sub&gt;</sub>\n'
'<sup>&lt;sup&gt;Superscript&lt;/sup&gt;</sup>\n'
'<small>&lt;small&gt;'
'Makes font relatively smaller&lt;/small&gt;</small>\n'
'<tt>&lt;tt&gt;Monospace font&lt;/tt&gt;</tt>\n'
'<u>&lt;u&gt;Underline&lt;/u&gt;</u>\n\n'
'For example: &lt;u&gt;&lt;b&gt;%s&lt;/b&gt;&lt;/u&gt;\n'
'will display <u><b>Underlined bold date</b></u>.\n'))
row += 1
self.add_spinner( self.add_spinner(
grid, _('Date about range'), grid, _('Date about range'),
row, 'behavior.date-about-range', (1, 9999)) row, 'behavior.date-about-range', (1, 9999))
@ -1516,26 +1537,6 @@ class GrampsPreferences(ConfigureDialog):
self.add_spinner( self.add_spinner(
grid, _('Average years between generations'), grid, _('Average years between generations'),
row, 'behavior.avg-generation-gap', (10, 30)) row, 'behavior.avg-generation-gap', (10, 30))
row += 1
self.add_pos_int_entry(
grid, _('Markup for invalid date format'),
row, 'preferences.invalid-date-format',
self.update_markup_entry,
helptext=_(
'Convenience markups are:\n'
'<b>&lt;b&gt;Bold&lt;/b&gt;</b>\n'
'<big>&lt;big&gt;'
'Makes font relatively larger&lt;/big&gt;</big>\n'
'<i>&lt;i&gt;Italic&lt;/i&gt;</i>\n'
'<s>&lt;s&gt;Strikethrough&lt;/s&gt;</s>\n'
'<sub>&lt;sub&gt;Subscript&lt;/sub&gt;</sub>\n'
'<sup>&lt;sup&gt;Superscript&lt;/sup&gt;</sup>\n'
'<small>&lt;small&gt;'
'Makes font relatively smaller&lt;/small&gt;</small>\n'
'<tt>&lt;tt&gt;Monospace font&lt;/tt&gt;</tt>\n'
'<u>&lt;u&gt;Underline&lt;/u&gt;</u>\n\n'
'For example: &lt;u&gt;&lt;b&gt;%s&lt;/b&gt;&lt;/u&gt;\n'
'will display <u><b>Underlined bold date</b></u>.\n'))
return _('Dates'), grid return _('Dates'), grid
@ -2089,9 +2090,9 @@ class GrampsPreferences(ConfigureDialog):
self.all_avail_fonts, callback=self.utf8_update_font, self.all_avail_fonts, callback=self.utf8_update_font,
valueactive=True, setactive=active_val) valueactive=True, setactive=active_val)
if len(available_fonts) == 1: if len(available_fonts) == 1:
single_font = self.all_avail_fonts[choosefont.get_active()][1] single_font = self.all_avail_fonts[choosefont.get_active()][0]
config.set('utf8.selected-font', config.set('utf8.selected-font',
self.all_avail_fonts[single_font]) self.all_avail_fonts[single_font][1])
self.utf8_show_example() self.utf8_show_example()
symbols = Symbols() symbols = Symbols()
all_sbls = symbols.get_death_symbols() all_sbls = symbols.get_death_symbols()

View File

@ -158,24 +158,30 @@ class EditPlace(EditPrimary):
self.obj.set_code, self.obj.get_code, self.obj.set_code, self.obj.get_code,
self.db.readonly) self.db.readonly)
entry = self.top.get_object("lon_entry")
entry.set_ltr_mode()
self.longitude = MonitoredEntry( self.longitude = MonitoredEntry(
self.top.get_object("lon_entry"), entry,
self.obj.set_longitude, self.obj.get_longitude, self.obj.set_longitude, self.obj.get_longitude,
self.db.readonly) self.db.readonly)
self.longitude.connect("validate", self._validate_coordinate, "lon") self.longitude.connect("validate", self._validate_coordinate, "lon")
#force validation now with initial entry #force validation now with initial entry
self.top.get_object("lon_entry").validate(force=True) entry.validate(force=True)
entry = self.top.get_object("lat_entry")
entry.set_ltr_mode()
self.latitude = MonitoredEntry( self.latitude = MonitoredEntry(
self.top.get_object("lat_entry"), entry,
self.obj.set_latitude, self.obj.get_latitude, self.obj.set_latitude, self.obj.get_latitude,
self.db.readonly) self.db.readonly)
self.latitude.connect("validate", self._validate_coordinate, "lat") self.latitude.connect("validate", self._validate_coordinate, "lat")
#force validation now with initial entry #force validation now with initial entry
self.top.get_object("lat_entry").validate(force=True) entry.validate(force=True)
entry = self.top.get_object("latlon_entry")
entry.set_ltr_mode()
self.latlon = MonitoredEntry( self.latlon = MonitoredEntry(
self.top.get_object("latlon_entry"), entry,
self.set_latlongitude, self.get_latlongitude, self.set_latlongitude, self.get_latlongitude,
self.db.readonly) self.db.readonly)

View File

@ -151,24 +151,30 @@ class EditPlaceRef(EditReference):
self.source.set_code, self.source.get_code, self.source.set_code, self.source.get_code,
self.db.readonly) self.db.readonly)
entry = self.top.get_object("lon_entry")
entry.set_ltr_mode()
self.longitude = MonitoredEntry( self.longitude = MonitoredEntry(
self.top.get_object("lon_entry"), entry,
self.source.set_longitude, self.source.get_longitude, self.source.set_longitude, self.source.get_longitude,
self.db.readonly) self.db.readonly)
self.longitude.connect("validate", self._validate_coordinate, "lon") self.longitude.connect("validate", self._validate_coordinate, "lon")
#force validation now with initial entry #force validation now with initial entry
self.top.get_object("lon_entry").validate(force=True) entry.validate(force=True)
entry = self.top.get_object("lat_entry")
entry.set_ltr_mode()
self.latitude = MonitoredEntry( self.latitude = MonitoredEntry(
self.top.get_object("lat_entry"), entry,
self.source.set_latitude, self.source.get_latitude, self.source.set_latitude, self.source.get_latitude,
self.db.readonly) self.db.readonly)
self.latitude.connect("validate", self._validate_coordinate, "lat") self.latitude.connect("validate", self._validate_coordinate, "lat")
#force validation now with initial entry #force validation now with initial entry
self.top.get_object("lat_entry").validate(force=True) entry.validate(force=True)
entry = self.top.get_object("latlon_entry")
entry.set_ltr_mode()
self.latlon = MonitoredEntry( self.latlon = MonitoredEntry(
self.top.get_object("latlon_entry"), entry,
self.set_latlongitude, self.get_latlongitude, self.set_latlongitude, self.get_latlongitude,
self.db.readonly) self.db.readonly)

View File

@ -311,7 +311,10 @@ class PlaceEntry(ObjEntry):
def get_label(self, place): def get_label(self, place):
place_title = place_displayer.display(self.db, place) place_title = place_displayer.display(self.db, place)
return "%s [%s]" % (place_title, place.gramps_id) # When part of the place title contains RTL text, the gramps_id gets
# messed up; so use Unicode FSI/PDI and LRM chars to isolate it.
# see bug 10124 and PR924
return "%s \u2068[%s]\u200e\u2069" % (place_title, place.gramps_id)
def call_editor(self, obj=None): def call_editor(self, obj=None):
if obj is None: if obj is None:
@ -356,7 +359,7 @@ class SourceEntry(ObjEntry):
return self.db.get_source_from_handle(handle) return self.db.get_source_from_handle(handle)
def get_label(self, source): def get_label(self, source):
return "%s [%s]" % (source.get_title(), source.gramps_id) return "%s \u2068[%s]\u200e\u2069" % (source.get_title(), source.gramps_id)
def call_editor(self, obj=None): def call_editor(self, obj=None):
if obj is None: if obj is None:
@ -402,7 +405,8 @@ class MediaEntry(ObjEntry):
return self.db.get_media_from_handle(handle) return self.db.get_media_from_handle(handle)
def get_label(self, object): def get_label(self, object):
return "%s [%s]" % (object.get_description(), object.gramps_id) return "%s \u2068[%s]\u200e\u2069" % (object.get_description(),
object.gramps_id)
def call_editor(self, obj=None): def call_editor(self, obj=None):
if obj is None: if obj is None:
@ -462,7 +466,7 @@ class NoteEntry(ObjEntry):
txt = " ".join(note.get().split()) txt = " ".join(note.get().split())
if len(txt) > 35: if len(txt) > 35:
txt = txt[:35] + "..." txt = txt[:35] + "..."
return "%s [%s]" % (txt, note.gramps_id) return "%s \u2068[%s]\u200e\u2069" % (txt, note.gramps_id)
def call_editor(self, obj=None): def call_editor(self, obj=None):
if obj is None: if obj is None:

View File

@ -766,7 +766,7 @@ class ToolManagedWindowBase(ManagedWindow):
self.notebook = Gtk.Notebook() self.notebook = Gtk.Notebook()
self.notebook.set_border_width(6) self.notebook.set_border_width(6)
self.window.get_content_area().add(self.notebook) self.window.get_content_area().pack_start(self.notebook, True, True, 0)
self.results_text = Gtk.TextView() self.results_text = Gtk.TextView()
self.results_text.connect('button-press-event', self.results_text.connect('button-press-event',

View File

@ -551,16 +551,17 @@ def color_graph_box(alive=False, gender=Person.MALE):
def hex_to_rgb_float(value): def hex_to_rgb_float(value):
""" """
Convert a hexademical value #FF00FF to rgb. Returns tuple of float between Convert a 6 or 12 digit hexademical value to rgb. Returns tuple of floats
0 and 1 between 0 and 1.
""" """
value = value.lstrip('#') value = value.lstrip('#')
lenv = len(value) lenv = len(value)
return tuple(int(value[i:i+lenv//3], 16)/256.0 for i in range(0, lenv, lenv//3)) return tuple(int(value[i:i+lenv//3], 16)/16.0**(lenv//3)
for i in range(0, lenv, lenv//3))
def hex_to_rgb(value): def hex_to_rgb(value):
""" """
Convert a hexadecimal value #FF00FF to rgb. Returns tuple of integers Convert a 6 or 12 digit hexadecimal value to rgb. Returns tuple of integers.
""" """
value = value.lstrip('#') value = value.lstrip('#')
lenv = len(value) lenv = len(value)

View File

@ -435,19 +435,15 @@ class NavigationView(PageView):
hobj = self.get_history() hobj = self.get_history()
menu_len = min(len(items) - 1, MRU_SIZE) menu_len = min(len(items) - 1, MRU_SIZE)
for index in range(0, menu_len):
name, obj = navigation_label(self.dbstate.db, nav_type,
items[index])
menus += menuitem % (nav_type, index, html.escape(name))
self.mru_ui = [MRU_TOP + menus + MRU_BTM]
mitems = items[-MRU_SIZE - 1:-1] # Ignore current handle
mitems.reverse()
data = [] data = []
for index, handle in enumerate(mitems): for index in range(menu_len - 1, -1, -1):
data.append(('%s%02d'%(nav_type, index), name, _obj = navigation_label(self.dbstate.db, nav_type,
make_callback(hobj.push, handle), items[index])
"%s%d" % (mod_key(), index))) menus += menuitem % (nav_type, index, html.escape(name))
data.append(('%s%02d' % (nav_type, index),
make_callback(hobj.push, items[index]),
"%s%d" % (mod_key(), menu_len - 1 - index)))
self.mru_ui = [MRU_TOP + menus + MRU_BTM]
self.mru_action = ActionGroup(name=self.title + '/MRU') self.mru_action = ActionGroup(name=self.title + '/MRU')
self.mru_action.add_actions(data) self.mru_action.add_actions(data)

View File

@ -143,7 +143,7 @@ class PlaceBaseModel:
value = conv_lat_lon('0', data[3], format='DEG')[1] value = conv_lat_lon('0', data[3], format='DEG')[1]
if not value: if not value:
return _("Error in format") return _("Error in format")
return value return ("\u202d" + value + "\u202e") if glocale.rtl_locale else value
def column_latitude(self, data): def column_latitude(self, data):
if not data[4]: if not data[4]:
@ -151,7 +151,7 @@ class PlaceBaseModel:
value = conv_lat_lon(data[4], '0', format='DEG')[0] value = conv_lat_lon(data[4], '0', format='DEG')[0]
if not value: if not value:
return _("Error in format") return _("Error in format")
return value return ("\u202d" + value + "\u202e") if glocale.rtl_locale else value
def sort_longitude(self, data): def sort_longitude(self, data):
if not data[3]: if not data[3]:

View File

@ -64,8 +64,6 @@ from gramps.gen.errors import ValidationError
_RETURN = Gdk.keyval_from_name("Return") _RETURN = Gdk.keyval_from_name("Return")
_KP_ENTER = Gdk.keyval_from_name("KP_Enter") _KP_ENTER = Gdk.keyval_from_name("KP_Enter")
# table for skipping illegal control chars
INVISIBLE = dict.fromkeys(list(range(32)))
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
@ -141,14 +139,10 @@ class MonitoredEntry:
self.obj.connect(signal, callback, *data) self.obj.connect(signal, callback, *data)
def _on_quit(self, obj, event): def _on_quit(self, obj, event):
text = obj.get_text().translate(INVISIBLE).strip() self.set_val(obj.get_text().strip())
self.set_val(text)
obj.set_text(text)
def _on_change(self, obj): def _on_change(self, obj):
new_text = obj.get_text().translate(INVISIBLE) self.set_val(obj.get_text())
self.set_val(new_text)
obj.set_text(new_text)
if self.changed: if self.changed:
self.changed(obj) self.changed(obj)

View File

@ -46,6 +46,11 @@ from gi.repository import Gtk
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
from .undoablebuffer import Stack from .undoablebuffer import Stack
from gramps.gen.const import GRAMPS_LOCALE as glocale
# table for skipping illegal control chars
INVISIBLE = dict.fromkeys(list(range(32)) + [0x202d, 0x202e])
class UndoableInsertEntry: class UndoableInsertEntry:
"""something that has been inserted into our Gtk.editable""" """something that has been inserted into our Gtk.editable"""
@ -84,6 +89,10 @@ class UndoableEntry(Gtk.Entry, Gtk.Editable):
Additional features: Additional features:
- Undo and Redo on CTRL-Z/CTRL-SHIFT-Z - Undo and Redo on CTRL-Z/CTRL-SHIFT-Z
- ltr_mode (forces the field to always be left to right, useful for GPS
coordinates and similar numbers that might contain RTL characters.
See set_ltr_mode.
""" """
__gtype_name__ = 'UndoableEntry' __gtype_name__ = 'UndoableEntry'
@ -94,12 +103,12 @@ class UndoableEntry(Gtk.Entry, Gtk.Editable):
undo_stack_size = 50 undo_stack_size = 50
def __init__(self): def __init__(self):
Gtk.Entry.__init__(self)
self.undo_stack = Stack(self.undo_stack_size) self.undo_stack = Stack(self.undo_stack_size)
self.redo_stack = [] self.redo_stack = []
self.not_undoable_action = False self.not_undoable_action = False
self.undo_in_progress = False self.undo_in_progress = False
self.ltr_mode = False
Gtk.Entry.__init__(self)
self.connect('delete-text', self._on_delete_text) self.connect('delete-text', self._on_delete_text)
self.connect('key-press-event', self._on_key_press_event) self.connect('key-press-event', self._on_key_press_event)
@ -156,10 +165,17 @@ class UndoableEntry(Gtk.Entry, Gtk.Editable):
return False return False
return True return True
text = text.translate(INVISIBLE)
if self.ltr_mode:
if position == 0:
position = 1
elif position >= self.get_text_length():
position -= 1
if not self.undo_in_progress: if not self.undo_in_progress:
self.__empty_redo_stack() self.__empty_redo_stack()
while not self.not_undoable_action: while not self.not_undoable_action:
undo_action = self.insertclass(text, length, self.get_position()) undo_action = self.insertclass(text, length, position)
try: try:
prev_insert = self.undo_stack.pop() prev_insert = self.undo_stack.pop()
except IndexError: except IndexError:
@ -180,6 +196,7 @@ class UndoableEntry(Gtk.Entry, Gtk.Editable):
self.get_buffer().insert_text(position, text, len(text)) self.get_buffer().insert_text(position, text, len(text))
return position + len(text) return position + len(text)
def _on_delete_text(self, editable, start, end): def _on_delete_text(self, editable, start, end):
def can_be_merged(prev, cur): def can_be_merged(prev, cur):
""" """
@ -206,32 +223,49 @@ class UndoableEntry(Gtk.Entry, Gtk.Editable):
return False return False
return True return True
if not self.undo_in_progress: if self.ltr_mode: # limit deletes to area between LRO/PDF
self.__empty_redo_stack() if start == 0:
if self.not_undoable_action: start = 1
return elif start > self.get_text_length() - 1:
undo_action = self.deleteclass(editable, start, end) start -= 1
try: if end == 0:
prev_delete = self.undo_stack.pop() end = 1
except IndexError: elif end > self.get_text_length() - 1:
self.undo_stack.append(undo_action) end -= 1
return elif end < 0:
if not isinstance(prev_delete, self.deleteclass): end = self.get_text_length() - 1
self.undo_stack.append(prev_delete)
self.undo_stack.append(undo_action) while True:
return if not self.undo_in_progress:
if can_be_merged(prev_delete, undo_action): self.__empty_redo_stack()
if prev_delete.start == undo_action.start: # delete key used if self.not_undoable_action:
prev_delete.text += undo_action.text break
prev_delete.end += (undo_action.end - undo_action.start) undo_action = self.deleteclass(self, start, end)
else: # Backspace used try:
prev_delete.text = "%s%s" % (undo_action.text, prev_delete = self.undo_stack.pop()
prev_delete.text) except IndexError:
prev_delete.start = undo_action.start self.undo_stack.append(undo_action)
self.undo_stack.append(prev_delete) break
else: if not isinstance(prev_delete, self.deleteclass):
self.undo_stack.append(prev_delete) self.undo_stack.append(prev_delete)
self.undo_stack.append(undo_action) self.undo_stack.append(undo_action)
break
if can_be_merged(prev_delete, undo_action):
if prev_delete.start == undo_action.start: # delete key used
prev_delete.text += undo_action.text
prev_delete.end += (undo_action.end - undo_action.start)
else: # Backspace used
prev_delete.text = "%s%s" % (undo_action.text,
prev_delete.text)
prev_delete.start = undo_action.start
self.undo_stack.append(prev_delete)
else:
self.undo_stack.append(prev_delete)
self.undo_stack.append(undo_action)
break
self.get_buffer().delete_text(start, end - start)
self.stop_emission_by_name('delete-text')
return True
def begin_not_undoable_action(self): def begin_not_undoable_action(self):
"""don't record the next actions """don't record the next actions
@ -323,3 +357,40 @@ class UndoableEntry(Gtk.Entry, Gtk.Editable):
def _handle_redo(self, redo_action): def _handle_redo(self, redo_action):
raise NotImplementedError raise NotImplementedError
def set_ltr_mode(self):
""" sets up the Entry to always be in LTR left to right even if some
characters are RTL.
This works by inserting the LRO/PDF Unicode Explicit Directional
Override characters around the entry text. These characters are then
protected agains insert/delete operations.
This call must be made before other text is inserted to the Entry.
Note: we only enable this during rtl_local languages because it has a
minor consequence; if cutting a field from this Entry with this mode
enabled, the LRO/PDF characters may end up in the clipboard. If pasted
back into another UndoableEntry, this is ignored, but if pasted in
another app it may be noticable.
"""
if glocale.rtl_locale:
self.get_buffer().set_text("\u202d\u202e", -1)
self.ltr_mode = True
def do_set_position(self, position):
""" In ltr_mode, this ensures that the cursor cannot be put outside
the LRO/PDF characters on the ends of the buffer. """
if position < 0:
position = self.get_text_length()
if self.ltr_mode:
if position == 0:
position = 1
elif position == self.get_text_length():
position -= 1
Gtk.Editable.select_region(self, position, position)
def get_text(self):
""" Used to remove the LRO/PDF characters when in ltr_mode.
"""
text = Gtk.Entry.get_text(self)
return text[1:-1] if self.ltr_mode else text

View File

@ -1541,7 +1541,7 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
Insert a mark at this point in the document. Insert a mark at this point in the document.
""" """
if mark: if mark:
key = escape(mark.key, ESC_MAP) key = escape(mark.key)
key = key.replace('"', '&quot;') key = key.replace('"', '&quot;')
if mark.type == INDEX_TYPE_ALP: if mark.type == INDEX_TYPE_ALP:
self.cntnt.write( self.cntnt.write(

View File

@ -225,7 +225,10 @@ class TitleDPY(DescendantTitleBase):
center = self.database.get_person_from_gramps_id(person_id) center = self.database.get_person_from_gramps_id(person_id)
family2_h = center.get_main_parents_family_handle() family2_h = center.get_main_parents_family_handle()
family2 = self.database.get_family_from_handle(family2_h) if family2_h:
family2 = self.database.get_family_from_handle(family2_h)
else:
family2 = None
person_list = None person_list = None
if family2: if family2:
@ -270,8 +273,11 @@ class TitleDFY(DescendantTitleBase):
parent_list = None parent_list = None
family_h = person.get_main_parents_family_handle() family_h = person.get_main_parents_family_handle()
family = self.database.get_family_from_handle(family_h) if family_h:
if family: #family = fathers parents family = self.database.get_family_from_handle(family_h)
else:
family = None
if family: # family = fathers parents
father_h = family.get_father_handle() father_h = family.get_father_handle()
mother_h = family.get_mother_handle() mother_h = family.get_mother_handle()
parent_list = [self.database.get_person_from_handle(handle) parent_list = [self.database.get_person_from_handle(handle)

View File

@ -82,7 +82,8 @@ class FtreeWriter:
self.option_box.parse_options() self.option_box.parse_options()
self.db = option_box.get_filtered_database(self.db) self.db = option_box.get_filtered_database(self.db)
self.plist = [x for x in self.db.iter_person_handles()] self.plist = self.db.get_person_handles()
self.plist.sort()
# the following are used to update the progress meter # the following are used to update the progress meter
self.total = 2 * len(self.plist) self.total = 2 * len(self.plist)
self.count = 0 self.count = 0

View File

@ -596,7 +596,7 @@ class GedcomWriter(UpdateCallback):
if val.strip(): if val.strip():
self._writeln(2, 'TYPE', val) self._writeln(2, 'TYPE', val)
else: else:
self._writeln(2, 'TYPE', str(event.get_type())) self._writeln(2, 'TYPE', event.get_type().xml_str())
self._dump_event_stats(event, event_ref) self._dump_event_stats(event, event_ref)
if etype == EventType.ADOPT and not adop_written: if etype == EventType.ADOPT and not adop_written:
adop_written = True adop_written = True
@ -656,7 +656,7 @@ class GedcomWriter(UpdateCallback):
attr_type = int(attr.get_type()) attr_type = int(attr.get_type())
name = libgedcom.PERSONALCONSTANTATTRIBUTES.get(attr_type) name = libgedcom.PERSONALCONSTANTATTRIBUTES.get(attr_type)
key = str(attr.get_type()) key = attr.get_type().xml_str()
value = attr.get_value().strip().replace('\r', ' ') value = attr.get_value().strip().replace('\r', ' ')
if key in ("AFN", "RFN", "REFN", "_UID", "_FSFTID"): if key in ("AFN", "RFN", "REFN", "_UID", "_FSFTID"):
@ -735,14 +735,14 @@ class GedcomWriter(UpdateCallback):
child.mrel == ChildRefType.FOSTER: child.mrel == ChildRefType.FOSTER:
self._writeln(2, 'PEDI foster') self._writeln(2, 'PEDI foster')
elif child.frel == child.mrel: elif child.frel == child.mrel:
self._writeln(2, 'PEDI %s' % str(child.frel)) self._writeln(2, 'PEDI %s' % child.frel.xml_str())
else: else:
self._writeln(2, '_FREL %s' % self._writeln(
PEDIGREE_TYPES.get(child.frel.value, 2, '_FREL %s' % PEDIGREE_TYPES.get(
str(child.frel))) child.frel.value, child.frel.xml_str()))
self._writeln(2, '_MREL %s' % self._writeln(
PEDIGREE_TYPES.get(child.mrel.value, 2, '_MREL %s' % PEDIGREE_TYPES.get(
str(child.mrel))) child.mrel.value, child.mrel.xml_str()))
def _parent_families(self, person): def _parent_families(self, person):
""" """
@ -910,9 +910,9 @@ class GedcomWriter(UpdateCallback):
self._writeln(1, 'EVEN', descr) self._writeln(1, 'EVEN', descr)
else: else:
self._writeln(1, 'EVEN') self._writeln(1, 'EVEN')
the_type = str(event.get_type()) the_type = event.get_type()
if the_type: if the_type:
self._writeln(2, 'TYPE', the_type) self._writeln(2, 'TYPE', the_type.xml_str())
def _family_event_attrs(self, attr_list, level): def _family_event_attrs(self, attr_list, level):
""" """
@ -946,7 +946,7 @@ class GedcomWriter(UpdateCallback):
attr_type = int(attr.get_type()) attr_type = int(attr.get_type())
name = libgedcom.FAMILYCONSTANTATTRIBUTES.get(attr_type) name = libgedcom.FAMILYCONSTANTATTRIBUTES.get(attr_type)
key = str(attr.get_type()) key = attr.get_type().xml_str()
value = attr.get_value().replace('\r', ' ') value = attr.get_value().replace('\r', ' ')
if key in ("AFN", "RFN", "REFN", "_UID"): if key in ("AFN", "RFN", "REFN", "_UID"):
@ -1097,7 +1097,8 @@ class GedcomWriter(UpdateCallback):
if reporef.get_call_number(): if reporef.get_call_number():
self._writeln(level + 1, 'CALN', reporef.get_call_number()) self._writeln(level + 1, 'CALN', reporef.get_call_number())
if reporef.get_media_type(): if reporef.get_media_type():
self._writeln(level + 2, 'MEDI', str(reporef.get_media_type())) self._writeln(level + 2, 'MEDI',
reporef.get_media_type().xml_str())
def _person_event_ref(self, key, event_ref): def _person_event_ref(self, key, event_ref):
""" """

View File

@ -91,7 +91,8 @@ class GeneWebWriter:
self.dirname = os.path.dirname (self.filename) self.dirname = os.path.dirname (self.filename)
try: try:
with open(self.filename, "wb") as self.g: with open(self.filename, "wb") as self.g:
self.flist = [x for x in self.db.iter_family_handles()] self.flist = self.db.get_family_handles()
self.flist.sort()
if len(self.flist) < 1: if len(self.flist) < 1:
self.user.notify_error(_("No families matched by selected filter")) self.user.notify_error(_("No families matched by selected filter"))
return False return False

View File

@ -30,7 +30,7 @@
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
import os import os
import sys import sys
from time import localtime import time
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
@ -51,10 +51,10 @@ _ = glocale.translation.gettext
from gramps.gui.plug.export import WriterOptionBox from gramps.gui.plug.export import WriterOptionBox
from gramps.gen.utils.db import family_name from gramps.gen.utils.db import family_name
from gramps.gen.lib import Date, EventType from gramps.gen.lib import Date, EventType
from gramps.gui.glade import Glade
from gramps.gen.display.name import displayer as name_displayer from gramps.gen.display.name import displayer as name_displayer
from gramps.gen.display.place import displayer as _pd from gramps.gen.display.place import displayer as _pd
class CalendarWriter: class CalendarWriter:
def __init__(self, database, filename, user, option_box=None): def __init__(self, database, filename, user, option_box=None):
self.db = database self.db = database
@ -95,24 +95,27 @@ class CalendarWriter:
def export_data(self, filename): def export_data(self, filename):
self.dirname = os.path.dirname (filename) self.dirname = os.path.dirname(filename)
try: try:
with open(filename,"w") as self.g: with open(filename, "w", encoding='utf8',
newline='\r\n') as self.g:
self.writeln("BEGIN:VCALENDAR") self.writeln("BEGIN:VCALENDAR")
self.writeln("PRODID:-//GNU//Gramps//EN") self.writeln("PRODID:-//GNU//Gramps//EN")
self.writeln("VERSION:1.0") self.writeln("VERSION:2.0")
self.total = (len([x for x in self.db.iter_person_handles()]) + p_hndls = self.db.get_person_handles()
len([x for x in self.db.iter_family_handles()])) p_hndls.sort()
for key in self.db.iter_person_handles(): f_hndls = self.db.get_family_handles()
f_hndls.sort()
self.total = len(p_hndls) + len(f_hndls)
for key in p_hndls:
self.write_person(key) self.write_person(key)
self.update() self.update()
for key in self.db.iter_family_handles(): for key in f_hndls:
self.write_family(key) self.write_family(key)
self.update() self.update()
self.writeln("")
self.writeln("END:VCALENDAR") self.writeln("END:VCALENDAR")
return True return True
@ -129,16 +132,11 @@ class CalendarWriter:
if family: if family:
for event_ref in family.get_event_ref_list(): for event_ref in family.get_event_ref_list():
event = self.db.get_event_from_handle(event_ref.ref) event = self.db.get_event_from_handle(event_ref.ref)
if event.get_type() == EventType.MARRIAGE: if event and event.get_type() == EventType.MARRIAGE:
m_date = event.get_date_object()
place_handle = event.get_place_handle()
# feature requests 2356, 1657: avoid genitive form # feature requests 2356, 1657: avoid genitive form
text = "%s - %s" % (family_name(family, self.db), _("Marriage")) text = "%s - %s" % (family_name(family, self.db),
if place_handle: _("Marriage"))
place_title = _pd.display_event(self.db, event) self.write_vevent(text, event)
self.write_vevent( text, m_date, place_title)
else:
self.write_vevent( text, m_date)
def write_person(self, person_handle): def write_person(self, person_handle):
person = self.db.get_person_from_handle(person_handle) person = self.db.get_person_from_handle(person_handle)
@ -147,45 +145,26 @@ class CalendarWriter:
if birth_ref: if birth_ref:
birth = self.db.get_event_from_handle(birth_ref.ref) birth = self.db.get_event_from_handle(birth_ref.ref)
if birth: if birth:
b_date = birth.get_date_object() # feature requests 2356, 1657: avoid genitive form
place_handle = birth.get_place_handle() self.write_vevent("%s - %s" %
if place_handle: (name_displayer.display(person),
# feature requests 2356, 1657: avoid genitive form _("Birth")), birth)
place_title = _pd.display_event(self.db, birth)
self.write_vevent("%s - %s" %
(name_displayer.display(person), _("Birth")),
b_date, place_title)
else:
# feature requests 2356, 1657: avoid genitive form
self.write_vevent("%s - %s" %
(name_displayer.display(person), _("Birth")),
b_date)
death_ref = person.get_death_ref() death_ref = person.get_death_ref()
if death_ref: if death_ref:
death = self.db.get_event_from_handle(death_ref.ref) death = self.db.get_event_from_handle(death_ref.ref)
if death: if death:
d_date = death.get_date_object() # feature requests 2356, 1657: avoid genitive form
place_handle = death.get_place_handle() self.write_vevent("%s - %s" %
if place_handle: (name_displayer.display(person),
# feature requests 2356, 1657: avoid genitive form _("Death")), death)
place_title = _pd.display_event(self.db, death)
self.write_vevent("%s - %s" %
(name_displayer.display(person), _("Death")),
d_date, place_title)
else:
# feature requests 2356, 1657: avoid genitive form
self.write_vevent("%s - %s" %
(name_displayer.display(person), _("Death")),
d_date)
def format_single_date(self, subdate, thisyear, cal): def format_single_date(self, subdate, thisyear, cal):
retval = "" retval = ""
(day, month, year, sl) = subdate (day, month, year, sl) = subdate
if thisyear: if thisyear:
year = localtime().tm_year year = time.localtime().tm_year
if not cal == Date.CAL_GREGORIAN: if not cal == Date.CAL_GREGORIAN:
return "" return ""
@ -196,7 +175,6 @@ class CalendarWriter:
retval = "%s%02d%02d" % (year, month, day) retval = "%s%02d%02d" % (year, month, day)
return retval return retval
def format_date(self, date, thisyear=0): def format_date(self, date, thisyear=0):
retval = "" retval = ""
if date.get_modifier() == Date.MOD_TEXTONLY: if date.get_modifier() == Date.MOD_TEXTONLY:
@ -220,23 +198,43 @@ class CalendarWriter:
start) start)
return retval return retval
def write_vevent(self, event_text, date, location=""): def write_vevent(self, event_text, event):
date = event.get_date_object()
place_handle = event.get_place_handle()
date_string = self.format_date(date, 1) date_string = self.format_date(date, 1)
if date_string is not "": if date_string is not "":
self.writeln("") # self.writeln("")
self.writeln("BEGIN:VEVENT") self.writeln("BEGIN:VEVENT")
self.writeln("SUMMARY:%s %s" % (date.get_year(), event_text)) time_s = time.gmtime(event.change)
if location: self.writeln("DTSTAMP:%04d%02d%02dT%02d%02d%02dZ" % time_s[0:6])
self.writeln("LOCATION:%s" % location) self.writeln("UID:%s@gramps.com" % event.handle)
self.writeln(fold("SUMMARY:%s %s" % (date.get_year(), event_text)))
if place_handle:
location = _pd.display_event(self.db, event)
if location:
self.writeln("LOCATION:%s" % location)
self.writeln("RRULE:FREQ=YEARLY") self.writeln("RRULE:FREQ=YEARLY")
self.writeln(date_string) self.writeln(date_string)
self.writeln("END:VEVENT") self.writeln("END:VEVENT")
#------------------------------------------------------------------------- # -------------------------------------------------------------------------
#
#
# def fold(txt):
#------------------------------------------------------------------------- """ Limit line length to 75 octets (per RFC 5545) """
l_len = 0
text = ''
for char in txt:
c_len = len(char.encode('utf8'))
if c_len + l_len > 75:
l_len = 1
text += '\n ' + char
else:
l_len += c_len
text += char
return text
def exportData(database, filename, user, option_box=None): def exportData(database, filename, user, option_box=None):
cw = CalendarWriter(database, filename, user, option_box) cw = CalendarWriter(database, filename, user, option_box)
return cw.export_data(filename) return cw.export_data(filename)

View File

@ -51,13 +51,13 @@ class AgeStatsGramplet(Gramplet):
def build_options(self): def build_options(self):
from gramps.gen.plug.menu import NumberOption from gramps.gen.plug.menu import NumberOption
self.add_option(NumberOption(_("Max age"), self.add_option(NumberOption(_("Max age"),
self.max_age, 1, 150)) self.max_age, 5, 150, 5))
self.add_option(NumberOption(_("Max age of Mother at birth"), self.add_option(NumberOption(_("Max age of Mother at birth"),
self.max_mother_diff, 1, 150)) self.max_mother_diff, 5, 150, 5))
self.add_option(NumberOption(_("Max age of Father at birth"), self.add_option(NumberOption(_("Max age of Father at birth"),
self.max_father_diff, 1, 150)) self.max_father_diff, 5, 150, 5))
self.add_option(NumberOption(_("Chart width"), self.add_option(NumberOption(_("Chart width"),
self.chart_width, 1, 150)) self.chart_width, 45, 150))
def save_options(self): def save_options(self):
self.max_age = int(self.get_option(_("Max age")).get_value()) self.max_age = int(self.get_option(_("Max age")).get_value())

View File

@ -33,6 +33,7 @@ Family Lines, a Graphviz-based plugin for Gramps.
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
from functools import partial from functools import partial
import html
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
@ -818,10 +819,10 @@ class FamilyLinesReport(Report):
if bth_event and self._incdates: if bth_event and self._incdates:
date = bth_event.get_date_object() date = bth_event.get_date_object()
if self._just_years and date.get_year_valid(): if self._just_years and date.get_year_valid():
birth_str = self._get_date( # localized year birth_str = self.get_date( # localized year
Date(date.get_year())) Date(date.get_year()))
else: else:
birth_str = self._get_date(date) birth_str = self.get_date(date)
# get birth place (one of: hamlet, village, town, city, parish, # get birth place (one of: hamlet, village, town, city, parish,
# county, province, region, state or country) # county, province, region, state or country)
@ -834,10 +835,10 @@ class FamilyLinesReport(Report):
if dth_event and self._incdates: if dth_event and self._incdates:
date = dth_event.get_date_object() date = dth_event.get_date_object()
if self._just_years and date.get_year_valid(): if self._just_years and date.get_year_valid():
death_str = self._get_date( # localized year death_str = self.get_date( # localized year
Date(date.get_year())) Date(date.get_year()))
else: else:
death_str = self._get_date(date) death_str = self.get_date(date)
# get death place (one of: hamlet, village, town, city, parish, # get death place (one of: hamlet, village, town, city, parish,
# county, province, region, state or country) # county, province, region, state or country)
@ -876,8 +877,7 @@ class FamilyLinesReport(Report):
label += '<TD>' label += '<TD>'
# at the very least, the label must have the person's name # at the very least, the label must have the person's name
name = name.replace('"', '&#34;') label += html.escape(name)
label += name.replace('<', '&#60;').replace('>', '&#62;')
if self.includeid == 1: # same line if self.includeid == 1: # same line
label += " (%s)" % p_id label += " (%s)" % p_id
elif self.includeid == 2: # own line elif self.includeid == 2: # own line
@ -964,10 +964,10 @@ class FamilyLinesReport(Report):
if self._incdates: if self._incdates:
date = event.get_date_object() date = event.get_date_object()
if self._just_years and date.get_year_valid(): if self._just_years and date.get_year_valid():
wedding_date = self._get_date( # localized year wedding_date = self.get_date( # localized year
Date(date.get_year())) Date(date.get_year()))
else: else:
wedding_date = self._get_date(date) wedding_date = self.get_date(date)
# get the wedding location # get the wedding location
if self._incplaces: if self._incplaces:
wedding_place = self.get_event_place(event) wedding_place = self.get_event_place(event)
@ -1090,6 +1090,9 @@ class FamilyLinesReport(Report):
place = self._db.get_place_from_handle(place_handle) place = self._db.get_place_from_handle(place_handle)
if place: if place:
place_text = _pd.display(self._db, place) place_text = _pd.display(self._db, place)
place_text = place_text.replace('<', '&#60;') place_text = html.escape(place_text)
place_text = place_text.replace('>', '&#62;')
return place_text return place_text
def get_date(self, date):
""" return a formatted date """
return html.escape(self._get_date(date))

View File

@ -32,6 +32,7 @@ Generate an hourglass graph using the Graphviz generator.
# python modules # python modules
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
import html
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
@ -251,18 +252,17 @@ class HourGlassReport(Report):
""" """
p_id = person.get_gramps_id() p_id = person.get_gramps_id()
name = self._name_display.display(person) name = self._name_display.display(person)
name = name.replace('"', '&#34;') name = html.escape(name)
name = name.replace('<', '&#60;').replace('>', '&#62;')
birth_evt = get_birth_or_fallback(self.__db, person) birth_evt = get_birth_or_fallback(self.__db, person)
if birth_evt: if birth_evt:
birth = self._get_date(birth_evt.get_date_object()) birth = self.get_date(birth_evt.get_date_object())
else: else:
birth = "" birth = ""
death_evt = get_death_or_fallback(self.__db, person) death_evt = get_death_or_fallback(self.__db, person)
if death_evt: if death_evt:
death = self._get_date(death_evt.get_date_object()) death = self.get_date(death_evt.get_date_object())
else: else:
death = "" death = ""
@ -295,7 +295,7 @@ class HourGlassReport(Report):
label = "" label = ""
marriage = utils.find_marriage(self.__db, family) marriage = utils.find_marriage(self.__db, family)
if marriage: if marriage:
label = self._get_date(marriage.get_date_object()) label = self.get_date(marriage.get_date_object())
if self.includeid == 1 and label: # same line if self.includeid == 1 and label: # same line
label = "%s (%s)" % (label, family_id) label = "%s (%s)" % (label, family_id)
elif self.includeid == 1 and not label: elif self.includeid == 1 and not label:
@ -343,7 +343,9 @@ class HourGlassReport(Report):
else: else:
fill = self.colors['unknown'] fill = self.colors['unknown']
return(shape, style, color, fill) return(shape, style, color, fill)
def get_date(self, date):
""" return a formatted date """
return html.escape(self._get_date(date))
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #

View File

@ -40,6 +40,7 @@ Create a relationship graph using Graphviz
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
from functools import partial from functools import partial
import html
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
@ -616,8 +617,7 @@ class RelGraphReport(Report):
# at the very least, the label must have the person's name # at the very least, the label must have the person's name
p_name = self._name_display.display(person) p_name = self._name_display.display(person)
p_name = p_name.replace('"', '&#34;') label += html.escape(p_name)
label += p_name.replace('<', '&#60;').replace('>', '&#62;')
p_id = person.get_gramps_id() p_id = person.get_gramps_id()
if self.includeid == 1: # same line if self.includeid == 1: # same line
label += " (%s)" % p_id label += " (%s)" % p_id
@ -751,10 +751,10 @@ class RelGraphReport(Report):
event_date = event.get_date_object() event_date = event.get_date_object()
if event_date.get_year_valid(): if event_date.get_year_valid():
if self.event_choice in [4, 5]: if self.event_choice in [4, 5]:
return self._get_date( # localized year return self.get_date( # localized year
Date(event_date.get_year())) Date(event_date.get_year()))
elif self.event_choice in [1, 2, 3, 7]: elif self.event_choice in [1, 2, 3, 7]:
return self._get_date(event_date) return self.get_date(event_date)
return '' return ''
def get_place_string(self, event): def get_place_string(self, event):
@ -768,8 +768,11 @@ class RelGraphReport(Report):
""" """
if event and self.event_choice in [2, 3, 5, 6, 7]: if event and self.event_choice in [2, 3, 5, 6, 7]:
place = _pd.display_event(self._db, event) place = _pd.display_event(self._db, event)
return place.replace('<', '&#60;').replace('>', '&#62;') return html.escape(place)
return '' return ''
def get_date(self, date):
""" return a formatted date """
return html.escape(self._get_date(date))
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #

View File

@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import unittest import unittest
import os import os
import difflib import difflib
from unittest.mock import patch
from time import localtime, strptime
from gramps.test.test_util import Gramps from gramps.test.test_util import Gramps
from gramps.gen.const import TEMP_DIR, DATA_DIR from gramps.gen.const import TEMP_DIR, DATA_DIR
@ -33,6 +35,13 @@ TREE_NAME = "Test_exporttest"
TEST_DIR = os.path.abspath(os.path.join(DATA_DIR, "tests")) TEST_DIR = os.path.abspath(os.path.join(DATA_DIR, "tests"))
def mock_localtime(*args):
"""
Mock up a dummy to replace the varying 'time string results'
"""
return strptime("25 Dec 1999", "%d %b %Y")
def call(*args): def call(*args):
""" Call Gramps to perform the action with out and err captured """ """ Call Gramps to perform the action with out and err captured """
#print("call:", args) #print("call:", args)
@ -84,6 +93,8 @@ def compare(expect_file, result_file, dfilter=None):
msg += line msg += line
if dfilter: if dfilter:
fail += dfilter(line) fail += dfilter(line)
else:
fail = True
return msg if fail else "" return msg if fail else ""
@ -184,6 +195,9 @@ class ExportControl(unittest.TestCase):
export dates, file names etc. that don't count as differences. export dates, file names etc. that don't count as differences.
""" """
def setUp(self): def setUp(self):
config.set('behavior.date-before-range', 50)
config.set('behavior.date-after-range', 50)
config.set('behavior.date-about-range', 10)
self.tearDown() # removes it if it existed self.tearDown() # removes it if it existed
# out, err = self.call("-C", TREE_NAME, # out, err = self.call("-C", TREE_NAME,
@ -195,6 +209,17 @@ class ExportControl(unittest.TestCase):
def test_csv(self): def test_csv(self):
""" Run a csv export test """ """ Run a csv export test """
set_format(0) # Use ISO date for test set_format(0) # Use ISO date for test
config.set('database.backend', 'bsddb')
src_file = 'exp_sample_csv.gramps'
tst_file = 'exp_sample_csv.csv'
msg = do_it(src_file, tst_file)
if msg:
self.fail(tst_file + ': ' + msg)
def test_csv_sq(self):
""" Run a csv export test """
set_format(0) # Use ISO date for test
config.set('database.backend', 'sqlite')
src_file = 'exp_sample_csv.gramps' src_file = 'exp_sample_csv.gramps'
tst_file = 'exp_sample_csv.csv' tst_file = 'exp_sample_csv.csv'
msg = do_it(src_file, tst_file) msg = do_it(src_file, tst_file)
@ -204,6 +229,17 @@ class ExportControl(unittest.TestCase):
def test_ged(self): def test_ged(self):
""" Run a Gedcom export test """ """ Run a Gedcom export test """
config.set('preferences.place-auto', True) config.set('preferences.place-auto', True)
config.set('database.backend', 'bsddb')
src_file = 'exp_sample.gramps'
tst_file = 'exp_sample_ged.ged'
msg = do_it(src_file, tst_file, gedfilt)
if msg:
self.fail(tst_file + ': ' + msg)
def test_ged_sq(self):
""" Run a Gedcom export test """
config.set('preferences.place-auto', True)
config.set('database.backend', 'sqlite')
src_file = 'exp_sample.gramps' src_file = 'exp_sample.gramps'
tst_file = 'exp_sample_ged.ged' tst_file = 'exp_sample_ged.ged'
msg = do_it(src_file, tst_file, gedfilt) msg = do_it(src_file, tst_file, gedfilt)
@ -213,15 +249,39 @@ class ExportControl(unittest.TestCase):
def test_vcard(self): def test_vcard(self):
""" Run a vcard export test """ """ Run a vcard export test """
config.set('preferences.place-auto', True) config.set('preferences.place-auto', True)
config.set('database.backend', 'bsddb')
src_file = 'exp_sample.gramps' src_file = 'exp_sample.gramps'
tst_file = 'exp_sample.vcf' tst_file = 'exp_sample.vcf'
msg = do_it(src_file, tst_file, vcffilt) msg = do_it(src_file, tst_file, vcffilt)
if msg: if msg:
self.fail(tst_file + ': ' + msg) self.fail(tst_file + ': ' + msg)
def test_vcard_sq(self):
""" Run a vcard export test """
config.set('preferences.place-auto', True)
config.set('database.backend', 'sqlite')
src_file = 'exp_sample.gramps'
tst_file = 'exp_sample.vcf'
msg = do_it(src_file, tst_file, vcffilt)
if msg:
self.fail(tst_file + ': ' + msg)
@patch('gramps.plugins.export.exportvcalendar.time.localtime', mock_localtime)
def test_vcs(self): def test_vcs(self):
""" Run a Vcalandar export test """ """ Run a Vcalandar export test """
config.set('preferences.place-auto', True) config.set('preferences.place-auto', True)
config.set('database.backend', 'bsddb')
src_file = 'exp_sample.gramps'
tst_file = 'exp_sample.vcs'
msg = do_it(src_file, tst_file)
if msg:
self.fail(tst_file + ': ' + msg)
@patch('gramps.plugins.export.exportvcalendar.time.localtime', mock_localtime)
def test_vcs_sq(self):
""" Run a Vcalandar export test """
config.set('preferences.place-auto', True)
config.set('database.backend', 'sqlite')
src_file = 'exp_sample.gramps' src_file = 'exp_sample.gramps'
tst_file = 'exp_sample.vcs' tst_file = 'exp_sample.vcs'
msg = do_it(src_file, tst_file) msg = do_it(src_file, tst_file)
@ -231,6 +291,17 @@ class ExportControl(unittest.TestCase):
def test_gw(self): def test_gw(self):
""" Run a Geneweb export test """ """ Run a Geneweb export test """
config.set('preferences.place-auto', True) config.set('preferences.place-auto', True)
config.set('database.backend', 'bsddb')
src_file = 'exp_sample.gramps'
tst_file = 'exp_sample.gw'
msg = do_it(src_file, tst_file)
if msg:
self.fail(tst_file + ': ' + msg)
def test_gw_sq(self):
""" Run a Geneweb export test """
config.set('preferences.place-auto', True)
config.set('database.backend', 'sqlite')
src_file = 'exp_sample.gramps' src_file = 'exp_sample.gramps'
tst_file = 'exp_sample.gw' tst_file = 'exp_sample.gw'
msg = do_it(src_file, tst_file) msg = do_it(src_file, tst_file)
@ -241,6 +312,18 @@ class ExportControl(unittest.TestCase):
""" Run a Web Family Tree export test """ """ Run a Web Family Tree export test """
set_format(0) # Use ISO date for test set_format(0) # Use ISO date for test
config.set('preferences.place-auto', True) config.set('preferences.place-auto', True)
config.set('database.backend', 'bsddb')
src_file = 'exp_sample.gramps'
tst_file = 'exp_sample.wft'
msg = do_it(src_file, tst_file)
if msg:
self.fail(tst_file + ': ' + msg)
def test_wft_sq(self):
""" Run a Web Family Tree export test """
set_format(0) # Use ISO date for test
config.set('preferences.place-auto', True)
config.set('database.backend', 'sqlite')
src_file = 'exp_sample.gramps' src_file = 'exp_sample.gramps'
tst_file = 'exp_sample.wft' tst_file = 'exp_sample.wft'
msg = do_it(src_file, tst_file) msg = do_it(src_file, tst_file)

View File

@ -66,6 +66,9 @@ WIKI_HELP_SEC = _('manual|Reorder_Gramps_ID')
PREFIXES = {'person': 'i', 'family': 'f', 'event': 'e', 'place': 'p', PREFIXES = {'person': 'i', 'family': 'f', 'event': 'e', 'place': 'p',
'source': 's', 'citation': 'c', 'repository': 'r', 'source': 's', 'citation': 'c', 'repository': 'r',
'media': 'o', 'note': 'n'} 'media': 'o', 'note': 'n'}
DB_INDXES = {'person': 'p', 'family': 'f', 'event': 'e', 'place': 'l',
'source': 's', 'citation': 'c', 'repository': 'r',
'media': 'o', 'note': 'n'}
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# Actual tool # Actual tool
@ -244,7 +247,7 @@ class ReorderIds(tool.BatchTool, ManagedWindow, UpdateCallback):
self.prim_methods, self.obj_methods = {}, {} self.prim_methods, self.obj_methods = {}, {}
for prim_obj, prim_objs in self.xobjects: for prim_obj, prim_objs in self.xobjects:
iter_handles = "iter_%s_handles" % prim_obj get_handles = "get_%s_handles" % prim_obj
get_number_obj = "get_number_of_%s" % prim_objs get_number_obj = "get_number_of_%s" % prim_objs
prefix_fmt = "%s_prefix" % prim_obj prefix_fmt = "%s_prefix" % prim_obj
get_from_id = "get_%s_from_gramps_id" % prim_obj get_from_id = "get_%s_from_gramps_id" % prim_obj
@ -255,7 +258,7 @@ class ReorderIds(tool.BatchTool, ManagedWindow, UpdateCallback):
self.prim_methods[prim_obj] = (getattr(self.db, prefix_fmt), self.prim_methods[prim_obj] = (getattr(self.db, prefix_fmt),
getattr(self.db, get_number_obj)(), getattr(self.db, get_number_obj)(),
getattr(self.db, next_from_id)()) getattr(self.db, next_from_id)())
self.obj_methods[prim_obj] = (getattr(self.db, iter_handles), self.obj_methods[prim_obj] = (getattr(self.db, get_handles),
getattr(self.db, commit), getattr(self.db, commit),
getattr(self.db, get_from_id), getattr(self.db, get_from_id),
getattr(self.db, get_from_handle), getattr(self.db, get_from_handle),
@ -548,6 +551,9 @@ class ReorderIds(tool.BatchTool, ManagedWindow, UpdateCallback):
self.progress.set_pass( self.progress.set_pass(
_('Reorder %s IDs ...') % _(prim_objs.title()), _('Reorder %s IDs ...') % _(prim_objs.title()),
self.obj_values[prim_obj].quant_id) self.obj_values[prim_obj].quant_id)
# reset the db next_id index to zero so we restart new IDs
# at lowest possible position
setattr(self.db, DB_INDXES[prim_obj] + 'map_index', 0)
# Process reordering # Process reordering
self._reorder(prim_obj) self._reorder(prim_obj)
@ -572,7 +578,7 @@ class ReorderIds(tool.BatchTool, ManagedWindow, UpdateCallback):
dup_ids = [] # list of duplicate identifiers dup_ids = [] # list of duplicate identifiers
new_ids = {} # list of new identifiers new_ids = {} # list of new identifiers
iter_handles, commit, get_from_id, get_from_handle, next_from_id = \ get_handles, commit, get_from_id, get_from_handle, next_from_id = \
self.obj_methods[prim_obj] self.obj_methods[prim_obj]
prefix_fmt = self.obj_values[prim_obj].get_fmt() prefix_fmt = self.obj_values[prim_obj].get_fmt()
@ -585,8 +591,12 @@ class ReorderIds(tool.BatchTool, ManagedWindow, UpdateCallback):
change = self.obj_values[prim_obj].get_change() change = self.obj_values[prim_obj].get_change()
index_max = int("9" * self.obj_values[prim_obj].width_fmt) index_max = int("9" * self.obj_values[prim_obj].width_fmt)
do_same = False do_same = False
# Process in handle order, which is in order handles were created.
# This makes renumberd IDs more consistant.
handles = get_handles()
handles.sort()
for handle in iter_handles(): for handle in handles:
# Update progress # Update progress
if self.uistate: if self.uistate:
self.progress.step() self.progress.step()

View File

@ -196,10 +196,10 @@ class PersonBoxWidgetCairo(_PersonWidgetBase):
if tags and person: if tags and person:
for tag_handle in person.get_tag_list(): for tag_handle in person.get_tag_list():
# For the complete tag, don't modify the default color # For the complete tag, don't modify the default color
# which is black (#000000000000) # which is black
tag = dbstate.db.get_tag_from_handle(tag_handle) tag = dbstate.db.get_tag_from_handle(tag_handle)
if tag.get_color() != "#000000000000": # only if the color if tag.get_color() not in ("#000000", "#000000000000"):
self.bgcolor = tag.get_color() # is not black self.bgcolor = tag.get_color()
self.bgcolor = hex_to_rgb_float(self.bgcolor) self.bgcolor = hex_to_rgb_float(self.bgcolor)
self.bordercolor = hex_to_rgb_float(self.bordercolor) self.bordercolor = hex_to_rgb_float(self.bordercolor)
@ -791,6 +791,7 @@ class PedigreeView(NavigationView):
self._add_db_signal('family-add', self.person_rebuild) self._add_db_signal('family-add', self.person_rebuild)
self._add_db_signal('family-delete', self.person_rebuild) self._add_db_signal('family-delete', self.person_rebuild)
self._add_db_signal('family-rebuild', self.person_rebuild) self._add_db_signal('family-rebuild', self.person_rebuild)
self._add_db_signal('event-update', self.person_rebuild)
def change_db(self, db): def change_db(self, db):
""" """

View File

@ -60,7 +60,7 @@ import logging
from gramps.gen.const import GRAMPS_LOCALE as glocale from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.gen.lib import (FamilyRelType, NoteType, NameType, Person, from gramps.gen.lib import (FamilyRelType, NoteType, NameType, Person,
UrlType, Name, PlaceType, EventRoleType, UrlType, Name, PlaceType, EventRoleType,
Family, Citation, Place) Family, Citation, Place, Date)
from gramps.gen.lib.date import Today from gramps.gen.lib.date import Today
from gramps.gen.const import PROGRAM_NAME, URL_HOMEPAGE from gramps.gen.const import PROGRAM_NAME, URL_HOMEPAGE
from gramps.version import VERSION from gramps.version import VERSION
@ -2916,7 +2916,11 @@ class BasePage: # pylint: disable=C1001
if self.reference_sort: if self.reference_sort:
role = obj[2] # name role = obj[2] # name
elif len(obj[2].split('-')) > 1: elif len(obj[2].split('-')) > 1:
role = obj[2] # date in ISO format dummy_cal, role = obj[2].split(':') # date in ISO format
# dummy_cal is the original calendar. remove it.
if len(role.split(' ')) == 2:
# for sort, remove the modifier before, after...
(dummy_modifier, role) = role.split(' ')
else: else:
role = "3" role = "3"
return role return role
@ -2931,15 +2935,34 @@ class BasePage: # pylint: disable=C1001
if role != "": if role != "":
if self.reference_sort: if self.reference_sort:
role = "" role = ""
elif len(role.split('-')) > 1: elif role[1:2] == ':':
# cal is the original calendar
cal, role = role.split(':')
# conver ISO date to Date for translation. # conver ISO date to Date for translation.
# all modifiers are in english, so convert them
# to the local language
if len(role.split(' - ')) > 1: if len(role.split(' - ')) > 1:
(date1, date2) = role.split(' - ') (date1, date2) = role.split(' - ')
role = self._("between") + " " + date1 + " " role = self._("between") + " " + date1 + " "
role += self._("and") + " " + date2 role += self._("and") + " " + date2
elif len(role.split(' ')) == 2:
(pref, date) = role.split(' ')
if "aft" in pref:
role = self._("after") + " " + date
if "bef" in pref:
role = self._("before") + " " + date
if pref in ("abt", "about"):
role = self._("about") + " " + date
if "c" in pref:
role = self._("circa") + " " + date
if "around" in pref:
role = self._("around") + " " + date
# parse is done in the default language
date = _dp.parse(role) date = _dp.parse(role)
date = self.rlocale.get_date(date) # reset the date to the original calendar
role = " (%s) " % date cdate = date.to_calendar(Date.calendar_names[int(cal)])
ldate = self.rlocale.get_date(cdate)
role = " (%s) " % ldate
else: else:
role = " (%s) " % self._(role) role = " (%s) " % self._(role)
ordered += list_html ordered += list_html

View File

@ -132,7 +132,6 @@ class DrawTree(object):
""" """
return self.tree.handle return self.tree.handle
def buchheim(tree, node_width, h_separation, node_height, v_separation): def buchheim(tree, node_width, h_separation, node_height, v_separation):
""" """
Calculate the position of elements of the graph given a minimum Calculate the position of elements of the graph given a minimum
@ -142,9 +141,30 @@ def buchheim(tree, node_width, h_separation, node_height, v_separation):
min_x = second_walk(draw_tree, 0, node_width+h_separation, 0) min_x = second_walk(draw_tree, 0, node_width+h_separation, 0)
if min_x < 0: if min_x < 0:
third_walk(draw_tree, 0 - min_x) third_walk(draw_tree, 0 - min_x)
top = get_min_coord_y(draw_tree)
height = get_max_coord_y(draw_tree)
return draw_tree return (draw_tree, top, height)
def get_min_coord_y(tree, min_value=100.0):
""" Get the minimum coord_y """
if tree.coord_y < min_value:
min_value = tree.coord_y
for child in tree.children:
min_v = get_min_coord_y(child, min_value)
if min_value > min_v:
min_value = min_v
return min_value
def get_max_coord_y(tree, max_value=0.0):
""" Get the maximum coord_y """
if tree.coord_y > max_value:
max_value = tree.coord_y
for child in tree.children:
max_v = get_max_coord_y(child, max_value)
if max_value < max_v:
max_value = max_v
return max_value
def third_walk(tree, adjust): def third_walk(tree, adjust):
""" """
@ -156,7 +176,6 @@ def third_walk(tree, adjust):
for child in tree.children: for child in tree.children:
third_walk(child, adjust) third_walk(child, adjust)
def firstwalk(tree, node_height, v_separation): def firstwalk(tree, node_height, v_separation):
""" """
Determine horizontal positions. Determine horizontal positions.
@ -189,7 +208,6 @@ def firstwalk(tree, node_height, v_separation):
tree.height = max(tree.height, tree.coord_y) tree.height = max(tree.height, tree.coord_y)
return tree return tree
def apportion(tree, default_ancestor, v_separation): def apportion(tree, default_ancestor, v_separation):
""" """
Figure out relative positions of node in a tree. Figure out relative positions of node in a tree.
@ -263,7 +281,6 @@ def execute_shifts(tree):
child.height = max(child.height, child.coord_y) child.height = max(child.height, child.coord_y)
tree.height = max(tree.height, child.height) tree.height = max(tree.height, child.height)
def ancestor(vil, tree, default_ancestor): def ancestor(vil, tree, default_ancestor):
""" """
The relevant text is at the bottom of page 7 of The relevant text is at the bottom of page 7 of

View File

@ -472,8 +472,11 @@ class MediaPages(BasePage):
if orig_image_path != newpath: if orig_image_path != newpath:
url = self.report.build_url_fname( url = self.report.build_url_fname(
newpath, None, self.uplink) newpath, None, self.uplink)
s_width = 'width: %dpx;' % max_width
mediadisplay += Html("a", href=url) + ( mediadisplay += Html("a", href=url) + (
Html("img", src=url, alt=esc_page_title) Html("img", src=url,
style=s_width,
alt=esc_page_title)
) )
else: else:
dirname = tempfile.mkdtemp() dirname = tempfile.mkdtemp()
@ -507,9 +510,11 @@ class MediaPages(BasePage):
url = self.report.build_url_fname(newpath, url = self.report.build_url_fname(newpath,
None, None,
self.uplink) self.uplink)
s_width = 'width: 48px;'
hyper = Html("a", href=url, hyper = Html("a", href=url,
title=esc_page_title) + ( title=esc_page_title) + (
Html("img", src=img_url, Html("img", src=img_url,
style=s_width,
alt=esc_page_title) alt=esc_page_title)
) )
mediadisplay += hyper mediadisplay += hyper
@ -521,7 +526,9 @@ class MediaPages(BasePage):
summaryarea += mediadisplay summaryarea += mediadisplay
url = self.report.build_url_image("document.png", url = self.report.build_url_image("document.png",
"images", self.uplink) "images", self.uplink)
s_width = 'width: 48px;'
mediadisplay += Html("img", src=url, mediadisplay += Html("img", src=url,
style=s_width,
alt=esc_page_title, alt=esc_page_title,
title=esc_page_title) title=esc_page_title)

View File

@ -846,7 +846,12 @@ class NavWebReport(Report):
if self.reference_sort: if self.reference_sort:
role_or_date = name role_or_date = name
else: else:
role_or_date = str(event.get_date_object()) date = event.get_date_object()
# calendar is the original date calendar
calendar = str(date.get_calendar())
# convert date to gregorian for a correct sort
_date = str(date.to_calendar("gregorian"))
role_or_date = calendar + ":" + _date
else: else:
role_or_date = "" role_or_date = ""
place_fname = self.build_url_fname(place_handle, "plc", place_fname = self.build_url_fname(place_handle, "plc",

View File

@ -85,8 +85,8 @@ _ = glocale.translation.sgettext
LOG = logging.getLogger(".NarrativeWeb") LOG = logging.getLogger(".NarrativeWeb")
getcontext().prec = 8 getcontext().prec = 8
_WIDTH = 160 _WIDTH = 280
_HEIGHT = 120 _HEIGHT = 140
_VGAP = 10 _VGAP = 10
_HGAP = 30 _HGAP = 30
_SHADOW = 5 _SHADOW = 5
@ -1138,15 +1138,20 @@ class PersonPages(BasePage):
death = self.rlocale.get_date(dd_event.get_date_object()) death = self.rlocale.get_date(dd_event.get_date_object())
if death == "": if death == "":
death = "..." death = "..."
value = person_name + "<br/>*", birth, "<br/>+", death value = person_name + "<br/>*"+ birth+ "<br/>+"+ death
tdval = Html("td", value, class_="name")
table = Html("table", class_="table")
if thumbnail_url is None: if thumbnail_url is None:
boxbg += Html("a", href=url, class_="noThumb") + value boxbg += Html("a", href=url, class_="noThumb") + value
else: else:
thumb = Html("span", class_="thumbnail") + ( trow = Html("tr")
Html("img", src=thumbnail_url, alt="Image: " + person_name)) img = Html("img", src=thumbnail_url, alt="Img: " + person_name)
boxbg += Html("a", href=url) + thumb + value trow += Html("td", img, class_="img")
trow += tdval
table += trow
boxbg += Html("a", table, href=url, class_="thumbnail")
shadow = Html( shadow = Html(
"div", class_="shadow", inline=True, "div", "", class_="shadow", inline=True,
style="top: %dpx; left: %dpx;" % (top + _SHADOW, xoff + _SHADOW)) style="top: %dpx; left: %dpx;" % (top + _SHADOW, xoff + _SHADOW))
return [boxbg, shadow] return [boxbg, shadow]
@ -1293,16 +1298,18 @@ class PersonPages(BasePage):
# We now apply the Buchheim algorith to this tree, and it assigns X # We now apply the Buchheim algorith to this tree, and it assigns X
# and Y positions to all elements in the tree. # and Y positions to all elements in the tree.
l_tree = buchheim(layout_tree, _WIDTH, _HGAP, _HEIGHT, _VGAP) l_tree, top, height = buchheim(layout_tree, _WIDTH, _HGAP,
_HEIGHT, _VGAP)
top = abs(top)
# We know the height in 'pixels' where every Ancestor will sit # We know the height in 'pixels' where every Ancestor will sit
# precisely on an integer unit boundary. # precisely on an integer unit boundary.
with Html("div", id="tree", class_="subsection") as tree: with Html("div", id="tree", class_="subsection") as tree:
tree += Html("h4", _('Ancestors'), inline=True) tree += Html("h4", _('Ancestors'), inline=True)
with Html("div", id="treeContainer", with Html("div", id="treeContainer",
style="width:%dpx; height:%dpx;" % ( style="width:%dpx; height:%dpx; top: %dpx" % (
l_tree.width + _XOFFSET + _WIDTH, l_tree.width + _XOFFSET* (generations + 1) + _WIDTH,
l_tree.height + _HEIGHT + _VGAP) height + top + _HEIGHT + _VGAP, top)
) as container: ) as container:
tree += container tree += container
container += self.draw_tree(l_tree, 1, None) container += self.draw_tree(l_tree, 1, None)

View File

@ -126,7 +126,7 @@ class WebCalReport(Report):
self._ = self.rlocale.translation.sgettext self._ = self.rlocale.translation.sgettext
self.html_dir = mgobn('target') self.html_dir = mgobn('target')
self.title_text = mgobn('title') self.title_text = html_escape(mgobn('title'))
filter_option = options.menu.get_option_by_name('filter') filter_option = options.menu.get_option_by_name('filter')
self.filter = filter_option.get_filter() self.filter = filter_option.get_filter()
self.name_format = mgobn('name_format') self.name_format = mgobn('name_format')
@ -621,7 +621,8 @@ class WebCalReport(Report):
# Note. We use '/' here because it is a URL, not a OS # Note. We use '/' here because it is a URL, not a OS
# dependent pathname need to leave home link alone, # dependent pathname need to leave home link alone,
# so look for it ... # so look for it ...
url_fname = url_fname.lower() if nav_text != _("Home"):
url_fname = url_fname.lower()
url = url_fname url = url_fname
add_subdirs = False add_subdirs = False
if not (url.startswith('http:') or url.startswith('/')): if not (url.startswith('http:') or url.startswith('/')):
@ -1632,7 +1633,7 @@ class WebCalReport(Report):
output_file = self.create_file('index', "") output_file = self.create_file('index', "")
# page title # page title
title = self._("My Family Calendar") title = self.title_text
nr_up = 0 nr_up = 0

View File

@ -17,6 +17,7 @@ gramps/gen/db/base.py
gramps/gen/db/exceptions.py gramps/gen/db/exceptions.py
gramps/gen/db/generic.py gramps/gen/db/generic.py
gramps/gen/display/name.py gramps/gen/display/name.py
gramps/gen/display/place.py
gramps/gen/filters/_filterparser.py gramps/gen/filters/_filterparser.py
gramps/gen/filters/_genericfilter.py gramps/gen/filters/_genericfilter.py
gramps/gen/filters/rules/_changedsincebase.py gramps/gen/filters/rules/_changedsincebase.py
@ -742,6 +743,7 @@ gramps/plugins/tool/rebuildgenderstat.py
gramps/plugins/tool/rebuildrefmap.py gramps/plugins/tool/rebuildrefmap.py
gramps/plugins/tool/relcalc.glade gramps/plugins/tool/relcalc.glade
gramps/plugins/tool/relcalc.py gramps/plugins/tool/relcalc.py
gramps/plugins/tool/removespaces.glade
gramps/plugins/tool/removespaces.py gramps/plugins/tool/removespaces.py
gramps/plugins/tool/removeunused.glade gramps/plugins/tool/removeunused.glade
gramps/plugins/tool/removeunused.py gramps/plugins/tool/removeunused.py

View File

@ -85,7 +85,6 @@ gramps/gen/db/utils.py
# gen.display package # gen.display package
# #
gramps/gen/display/__init__.py gramps/gen/display/__init__.py
gramps/gen/display/place.py
# #
# gen.filters package # gen.filters package
# #

1532
po/cs.po

File diff suppressed because it is too large Load Diff

1429
po/de.po

File diff suppressed because it is too large Load Diff

View File

@ -7406,24 +7406,24 @@ msgstr "más de como"
#, python-brace-format #, python-brace-format
msgid "{number_of} year" msgid "{number_of} year"
msgid_plural "{number_of} years" msgid_plural "{number_of} years"
msgstr[0] "" msgstr[0] "{number_of} año"
msgstr[1] "" msgstr[1] "{number_of} años"
#. translators: leave all/any {...} untranslated #. translators: leave all/any {...} untranslated
#: ../gramps/gen/lib/date.py:443 #: ../gramps/gen/lib/date.py:443
#, python-brace-format #, python-brace-format
msgid "{number_of} month" msgid "{number_of} month"
msgid_plural "{number_of} months" msgid_plural "{number_of} months"
msgstr[0] "" msgstr[0] "{number_of} mes"
msgstr[1] "" msgstr[1] "{number_of} meses"
#. translators: leave all/any {...} untranslated #. translators: leave all/any {...} untranslated
#: ../gramps/gen/lib/date.py:454 #: ../gramps/gen/lib/date.py:454
#, python-brace-format #, python-brace-format
msgid "{number_of} day" msgid "{number_of} day"
msgid_plural "{number_of} days" msgid_plural "{number_of} days"
msgstr[0] "" msgstr[0] "{number_of} día"
msgstr[1] "" msgstr[1] "{number_of} días"
#: ../gramps/gen/lib/date.py:461 #: ../gramps/gen/lib/date.py:461
msgid "0 days" msgid "0 days"

1539
po/fi.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

15747
po/he.po

File diff suppressed because it is too large Load Diff

2218
po/hr.po

File diff suppressed because it is too large Load Diff

14284
po/sv.po

File diff suppressed because it is too large Load Diff

1676
po/uk.po

File diff suppressed because it is too large Load Diff