Compare commits

..

131 Commits

Author SHA1 Message Date
romjerome 1c241125d7 8555: Database repair tool always modify all source objects 2016-11-26 12:51:56 +01:00
romjerome e81c82fcc0 9003: Locality data in address was not imported 2015-10-27 09:48:20 +01:00
romjerome 7d91f4fae8 8188: Problem with existing selection in media reference editor
like selection box disappears when scrollbar appears

Now, do not expand bottom section (Media Object fields) by default

Wonder if we should not do that on all Reference Editors?
2015-09-24 11:07:56 +02:00
Nick Hall 78a74cae5c Make place title in GEDCOM export date dependent 2015-07-25 23:17:08 +01:00
Doug Blank 5039ad10f0 7261: Import GEDCOM file from MyHeritage, added __str__ to Attribute 2015-07-23 10:25:36 -04:00
Doug Blank 926bb60650 Merge pull request #43 from sam-m888/8702UpdateMapServicelinksOpenStreetMap
8702 Update Map Service links for OpenStreetMap
2015-07-14 07:04:24 -04:00
Doug Blank 314484cf84 Merge pull request #41 from ennoborg/maintenance/gramps41
8663: add exception for UnicodeEncodeError.
2015-07-13 23:12:01 -04:00
Enno Borgsteede ae0a039216 8663: add exception for UnicodeEncodeError. 2015-07-12 11:41:57 +02:00
kulath 296e8ca562 fix testcasegenerator AttributeError 2015-06-20 00:14:52 +02:00
kulath 4e6a06bfac 0008537: Gedcom import crashes. Fix problem when matching places with
the same name which are enclosed by different places.
2015-06-18 22:52:53 +01:00
Doug Blank 5ff70a665e Merge pull request #37 from ennoborg/maintenance/gramps41
Re-aligned check buttons in remove unused objects dialog.
2015-06-18 16:03:41 -04:00
Enno Borgsteede c0a0c1d302 Re-aligned check buttons in remove unused objects dialog. 2015-06-18 21:34:21 +02:00
kulath e71115af1b 8614: pickleupgrade.txt should not be written for python2 2015-06-18 20:25:33 +01:00
Doug Blank 5828dd3aa8 8537: Gedcom import crashes; kulath patch 2015-06-17 07:59:19 -04:00
Doug Blank 273a5f986f 8614: addresses pickleupgrade.txt issue, by kulath 2015-06-17 06:27:08 -04:00
Hivernat Emmanuel 00032f0cad 7347: fix a bug 'on mouse over' event 2015-06-12 16:37:45 +02:00
Josip 1ed6103a41 8625: Cannot open Citation references from Clip Board 2015-06-12 16:07:44 +02:00
Zdeněk Hataš ea2c71d238 fix mistake that prevent python2 to work 2015-06-07 11:10:22 +02:00
SNoiraud 6605d868cb Geography : bug 8612 : introspection problem with gtk 3.16. 2015-06-07 10:30:00 +02:00
Doug Blank 7a57c8584e 8621: Recursion Filter error 2015-06-06 19:58:41 -04:00
Zdeněk Hataš 46a509ee1d merge inflection fixes for cs lang from gramps42 branch 2015-06-06 14:14:29 +02:00
Josip 1aad1d6be0 Data Verify Tool: fix set transient parent 2015-06-05 12:13:43 +02:00
Josip 104808cf8f Relationship Calculator: fix set transient parent 2015-06-05 12:11:44 +02:00
Josip 8a34d98fb5 8619: Relationship Calculator - can't select person to relate to 2015-06-04 23:01:49 +02:00
erikdrgm c42f714393 Updated 150602 Dutch translation 2015-06-02 21:18:49 +02:00
erikdrgm d8ba31cc29 Merge branch 'maintenance/gramps41' of github.com:gramps-project/gramps into gramps41 2015-06-02 20:48:50 +02:00
Nick Hall f9bb9e5e73 8488: Use place displayer for headings 2015-05-28 19:57:54 +01:00
Nick Hall ed0b50e9b8 8487: Use place displayer to generate title in views 2015-05-28 16:31:59 +01:00
Jérôme Rapinat 19acd368c0 8583: Custom Events not shown in the filter siderbar 2015-05-26 20:51:30 +02:00
Enno Borgsteede 9de644bf1d #4161 #8548: Fix a baptism date error
https://gramps-project.org/bugs/view.php?id=8548#c41455

also reported and patched by 'hmmmpf' on #4161
2015-05-26 20:38:03 +02:00
Jérôme Rapinat bdd70dec1c 4161: Fix empty #buri fields
Still present on Geneweb 6 and 7alpha

patch by 'hmmmpf'
2015-05-26 20:36:37 +02:00
Jérôme Rapinat 2a26ca6c5c 8567: Imprecise French translation in Place dialog
'Enclosed by' was translated in French by 'Lié à'
2015-05-26 18:55:20 +02:00
Jérôme Rapinat f675fc1114 8580: "_Apply" button not translated on "Events comparison" tool 2015-05-26 18:46:44 +02:00
Doug Blank 143df8d42c Merge pull request #23 from belissent/belissent/gramps41
Modification for example.gramps database 
(custom parent relationship, notes)
2015-05-24 17:00:59 -04:00
Josip d71a36b240 8579: Creation of Narration Website report fails 2015-05-24 12:13:54 +02:00
Josip 085d1ee095 8398: lock.file with accent letter cause gramps to crash at start 2015-05-22 18:55:21 +02:00
Leonhaeuser cc2f803b86 update German translation 2015-05-17 10:30:04 +02:00
Josip 9c34e17bd9 Fix AgeStats gramplet for Python3 2015-05-16 12:51:18 +02:00
Josip 136bdd015a fix identation error of 8561#c41511 2015-05-16 06:06:14 +02:00
Josip e0b56f65ef 8561#c41511 2015-05-16 05:04:48 +02:00
Josip 089d028e8f 8562: Cannot create family lines diagram 2015-05-16 04:50:07 +02:00
Josip 6e4ce84396 Set transient parent for errorview and errorreportassistant 2015-05-16 04:19:11 +02:00
Josip 0930c0041f 8561: Problem with importing ged file from My Heritage 2015-05-16 00:32:40 +02:00
Doug Blank ef0492e0ff 8564: Recursion error when filtering for relatives 2015-05-15 18:01:59 -04:00
Josip e1a71dcd34 8497: Error on use of Ctrl-Z 2015-05-14 17:30:41 +02:00
Pierre Bélissent 6895594cdc Modification for exemple.gramps database (custom parent relationship, notes)
Modification for exemple.gramps database (custom parent relationship,
notes):
- Added custom parent relationship for I0044
- Added notes with ID: '_header1', '_footer1', '_custom1'
- Added a date for media O0010
These modifications are used for the DynamicWeb report addon tests.
2015-05-11 18:36:48 +02:00
Josip 45f82f1ec5 Workaround for broken introspection
8474: Crash after merge places
8498: Crash when attempting to add gramplet
8536: clicking on tag icon in person view causes gramps to crash
2015-05-11 17:45:42 +02:00
Josip c26fcf6d56 8445: Drag & Drop to add media: wrong handling of non-ascii characters 2015-05-07 21:04:22 +02:00
Doug Blank 2701d51b62 8541: Crash following update: addon permission issue blocks
re-starting gramps

There were two issues:

1. attempting to read a new addon file that wasn't readable
   threw an exception, aborted updating addons

2. global error catching didn't properly handle error code
   from an OSError for Python3
2015-05-05 13:44:20 -04:00
Matti Niemelä 9683a9e9eb new Finnish translation for gramps41 2015-05-05 00:37:14 -07:00
Jérôme Rapinat d03e9e6553 fix mistake on versioning (inherited from '4.1.3' release) 2015-05-03 17:41:26 +02:00
Josip 0f8b77b706 8469: GUI allows multiple Find Duplicates, then faults
Yet another case of dialog without transient parent
2015-05-03 11:32:07 +02:00
John Ralls a2244c6ab4 Update mac info for 4.1.3 release. 2015-05-02 11:53:51 -07:00
Jérôme Rapinat 2eccc6c4ce 8532: typo on the french translation
plural = single form for month(s) (moi => mois)
2015-05-02 17:02:27 +02:00
Jérôme Rapinat 815596a88d bump to 4.1.4 2015-05-02 10:51:08 +02:00
SNoiraud 98fdeaeb6b narrativeweb : bug 8528 : local variable 'body' referenced before assignment 2015-05-01 10:32:55 +02:00
Jérôme Rapinat 4d57633006 update NEWS before '4.1.3' release 2015-04-30 17:59:33 +02:00
Fabrice Arbogast 9c3450531b 8225 8311: Crash on geneweb export with python3 2015-04-30 17:26:36 +02:00
Jérôme Rapinat 2a35887da7 Don't need a date quality-month inflection in french 2015-04-29 11:08:25 +02:00
Jérôme Rapinat b34e088fe7 8522: fix a typo on commit 436487... 2015-04-29 10:55:54 +02:00
Jérôme Rapinat 189cc853b2 update translation template
was change around GEDCOM SUBM tag

update french translation
2015-04-29 10:50:30 +02:00
John Ralls 1d3d002490 Use MSWin environment variables USERPROFILE and APPDATA.
Instead of GRAMPSHOME. GRAMPSHOME is based on the assumption that
the config directory is GRAMPSHOME/gramps, and that causes the
default location for reports and backups to be ~/Library/Application Support.
The MSWin variables allow the two to be separated.

Thanks to Tim Lyons for the suggestion.

(cherry picked from commit c11c63169f)
2015-04-25 16:58:35 -07:00
kulath eb34416727 0001360: Gedcom input: SUBN and SUBM record handling
Fixed:
(a) Additional spaces beyond the first between a GEDCOM tag and the rest
of the line are not ignored.

(b) The SUBMitter name is ignored (it is overwritten by the XREF).

(c) SUBmissioN data items are not committed to the database.
2015-04-24 10:51:43 +01:00
Leonhaeuser 52842f8200 German translation typo fixes 2015-04-20 13:37:21 +02:00
Paul Franklin 646afece89 Update _datedisplay.py 2015-04-18 15:38:06 -07:00
Josip 45adb70330 fix few more dialog without parent 2015-04-18 23:00:54 +02:00
Josip 4ac02a4ca0 8128: GtkDialog mapped without a transient parent 2015-04-18 21:22:37 +02:00
Stéphane Charette ffe417f43e 8213: event columns too narrow
Web_Basic-Cypress stylesheet improvements
2015-04-18 16:12:23 +02:00
John Ralls dc50b14ed3 Fix gtk-critical error when setting mac menubar. 2015-04-17 15:14:02 -07:00
Josip 35f5426a33 Merge pull request #17 from ennoborg/maintenance/gramps41
Some terms corrected, other ones added.
2015-04-17 21:18:06 +02:00
Enno Borgsteede 8ff85415e8 Some terms corrected, other ones added. 2015-04-16 22:37:33 +02:00
Josip be1980e39a fix typo in commit 93bd200 2015-04-13 15:31:19 +02:00
Josip 93bd200ea0 8473: problem by start program 2015-04-13 01:15:17 +02:00
kulath 906e46b0a5 0002370: GEDCOM import/export round trip causes lost information
Fixed output of Adoption records so "1 ADOP" is only written once for
the person event and the adoption relationship.
2015-04-12 19:04:24 +01:00
Enno Borgsteede 51324b182f 8483: db upgrade fails, fatal damage 2015-04-12 10:44:28 -07:00
Nick Hall 4b8d25083b Merge pull request #15 from sebschub/maintenance/gramps41
Make place type in Place Reference Editor editable, add tooltip (maintenance/gramps41)
2015-04-10 19:14:24 +01:00
Paul Franklin 7ef450515c 8477: date format month/year is not well reported at editing time 2015-04-09 22:05:36 -07:00
Leonhaeuser cb5fb2ed27 typo fix in German translation 2015-04-09 21:50:01 +02:00
Sebastian Schubert b4eae781f8 Make place type in Place Reference Editor editable, add tooltip 2015-04-09 14:04:52 +02:00
Leonhaeuser c5c5889a42 update German translation 2015-04-05 00:25:50 +02:00
Jérôme Rapinat fe2a36c580 6403: add a rule for checking mapping key 2015-04-01 15:52:32 +02:00
kulath e3538e8a8b 0004412: Entering a witness to an event such as marriage
In some circumstances (after a Father's age of Mother's age) a witness
could be ignored.
2015-04-01 14:49:33 +01:00
Matt Keenan 475e78669b 8468: GuiColorOption missing avail-changed event handler 2015-03-31 10:22:35 -07:00
kulath f022597545 0008355: Gramps can't [GEDCOM] import estim. date period exported by
itself

Changed output format to DATE EST FROM TO and DATE CALC FROM TO. Also
changed in Narrative Web (which uses the same functions).
2015-03-31 10:48:44 +01:00
Paul Franklin 672bffe620 7742: bad generation of [timeline report] ODT files since 4.0.0 2015-03-30 13:29:16 -07:00
kulath 70e453f031 Fix bug in processing of Place FORM in GEDCOM import as a result of fix
for 8233.

When an unused Place was removed, PlaceImport still tried to generate
the place hierarchy. Also fixed bug in GEDCOM import where a default
PLAC FORM in the GEDCOM header was ignored.
2015-03-26 12:18:46 +00:00
Leonhaeuser 8a4b9c7ee0 update German translation 2015-03-26 02:34:43 +01:00
Jérôme Rapinat e86f796cf7 Update french translation 2015-03-25 19:51:03 +01:00
Jérôme Rapinat 436487072a xgettext prior to 0.18.3 leads to error
update template after fixing one string
2015-03-25 19:46:32 +01:00
kulath a2a68c64f7 Fix spurious generation of empty 'Alternative Name' in place.merge()
with an empty name

Bug discovered during testing of fix to 8233 (thanks, Enno for
discovering the problem and the fix).
2015-03-25 18:29:01 +00:00
Leonhaeuser c9d9925965 update German translation 2015-03-25 00:19:59 +01:00
kulath 4b8ca4a824 3082, 4439, 7134, 8279 Various fixes for GEDCOM import.
0003082: 1/4 and 1/2 ANSEL characters not supported on importing ANSEL
GEDCOM
0004439: [Info]: characters ignored on a Gedcom encoded ANSI (cp1252
West Europe, USA)
0007134: Failure importing ANSEL encoded gedcom file.
0008279: GEDCOM import fails for ANSI file incorrectly opened with the
utf8 locale

Fixed GEDCOM import not working properly for Python3; other problems
also corected, including fixing the inability to import Windows CP1252
coded files. Also more consistent fix for 8014. Ensured any error
messages are not lost. Fixed a few ANSEL characters that were not
translated.
2015-03-24 16:36:12 +00:00
Leonhaeuser 57a367e8c4 Fixed 0008456: Translation string missing in Not Related tool for help and close button
made _Close _Apply and _Help translateable in notrelated.glade and updated gramps.pot and de.po
2015-03-23 11:59:59 +01:00
Leonhaeuser 9ff34f2934 small fix in German translation 2015-03-21 16:56:22 +01:00
Jérôme Rapinat 88f5fbeb9e Improve TipsParse for python3 support 2015-03-20 09:24:46 +01:00
Jérôme Rapinat 42cf24205b 8103: typo, minor update 2015-03-20 09:22:49 +01:00
SNoiraud 36c03a0a53 geography: bug8450: Attempting to add a bookmark causes an error. 2015-03-19 19:32:34 +01:00
Leonhaeuser cf264e8d89 German translation fix typo 2015-03-19 19:06:57 +01:00
Jérôme Rapinat ab056c8ac5 update template, one new string\n; 8103: sidebar gramplet does not fit well into Event and Citation views\n under french locale 2015-03-19 15:55:06 +01:00
Jérôme Rapinat cc1f5b734a 8451: Fix crash on Relationships Graph report with unknown gender, related sibling label and french locale 2015-03-19 15:42:40 +01:00
Leonhaeuser ac21380b60 Fixed some errors in German translation 2015-03-19 01:42:11 +01:00
Paul Franklin 706437f57d 7155: Support creating directories in various scenarios 2015-03-18 14:02:35 -07:00
SNoiraud ab0dfc8d68 geography: bug 8450: Attempting to add a bookmark causes an error. 2015-03-17 21:16:26 +01:00
Nick Hall 4cb4d912fe 7992: Fix call to get_participant_from_event during batch transaction
During a batch transaction the secondary tables are closed.  This
causes an error when find_backlink_handles is called.  Although
not ideal, we return an empty string for participants.
2015-03-17 14:13:53 +00:00
Leonhaeuser 315ddd6ffd update German translation 2015-03-16 22:04:56 +01:00
Sveinn í Felli 60ff2584fb update Icelandic translation 2015-03-16 16:22:21 +01:00
Nick Hall d2363249b9 Convert remaining unicode literals 2015-03-15 23:48:12 +00:00
Doug Blank b70adcb74a 8435: Crash when trying to link existing place as an enclosing place using P0001 number 2015-03-15 00:36:30 -04:00
Josip f63385ac4b 8023: HTML view fails to load
support both py2 and py3 with non-ascii chars
2015-03-15 01:04:15 +01:00
Doug Blank d9cc3d3b0e 8023: HTML view fails to load; replaced file with open 2015-03-13 22:12:39 -04:00
leonhaeuser ccbf763ac4 update German translation 2015-03-13 17:41:42 +01:00
Zdeněk Hataš 111c245297 czech translation update 2015-03-13 17:30:46 +01:00
Nick Hall 359d277423 8430: Place displayer should not return None
The place displayer should return an empty string for an event
with no place.
2015-03-12 23:15:27 +00:00
Nick Hall 1a0784b154 Fix another handle type bug 2015-03-12 18:16:11 +00:00
kulath b02e1fe467 0008401: NameError in GEDCOM importer 2015-03-12 17:38:12 +00:00
Paul Franklin 8fe31528cf 8423: Python3 needs new_subpixbuf not subpixbuf 2015-03-12 10:11:11 -07:00
kulath 38b5b8ec54 0008322: Event address is lost on import, i.e. disconnected from event.
On GEDCOM import, Places are only merged if the Place Title and the
whole of the main location are identical.
2015-03-12 12:34:31 +00:00
Jérôme Rapinat 8d57884b5b 8407: gramps -i option in manpage not reflecting what happens; update french translation 2015-03-09 19:03:43 +01:00
erikdrgm 69e7501acc Update Dutch Translation 2015-03-09 10:09:38 +01:00
leonhaeuser 385c10a068 update German translation 2015-03-08 13:08:50 +01:00
Ross Gammon d99adb8bd4 8407: gramps -o option in manpage not reflecting what happens, https://bugs.launchpad.net/ubuntu/+source/gramps/+bug/1427444 2015-03-07 11:24:25 +01:00
leonhaeuser 74995c0994 fix typo 2015-03-05 21:04:07 +01:00
Anthony Fok 14ccc01acb enable python3 to run po/update_po.py 2015-03-01 09:00:12 -08:00
kulath 542450bf6d 0007824: Regression: running gramps from crontab fails 2015-03-01 16:52:08 +00:00
Anthony Fok b381f2dd8b correct incorrect tip49, new gramps.pot 2015-02-28 18:57:33 -08:00
Paul Franklin 25f9ea64fc clarify new string, new gramps.pot 2015-02-28 16:02:32 -08:00
Nick Hall c1b65d8cbe Tidy up About dialog
Use standard string for translator credits.
Add new section for contributors.
Align artwork section properly.
2015-02-28 23:01:53 +00:00
John Ralls 89a5d3fcda Some additional packaging fixups for the new dependency versions. 2015-02-28 14:47:36 -08:00
kulath 38addcedb3 0008380: tag_map is not initialized 2015-02-28 20:51:19 +00:00
John Ralls 6c0fdb27d6 Update mac build for Gramps-4.1.2 2015-02-28 09:27:05 -08:00
Jérôme Rapinat 3e5a7fe970 bump to 4.1.3 2015-02-27 17:11:59 +01:00
112 changed files with 20785 additions and 23593 deletions
+43
View File
@@ -1,3 +1,46 @@
2015-05-01
Version 4.1.3, "Thou shalt not count to five", a maintenance release.
* Fix db upgrade failure
* GtkDialog mapped without a transient parent
* [Gedcom} SUBN and SUBM record handling
* [Gedcom] Import/export round trip causes lost information
* [Gedcom] Entering a witness to an event such as marriage might be ignored
* [Gedcom] Gramps can't import estim. date period exported by itself
* [Gedcom] 1/4 and 1/2 ANSEL characters not supported on importing ANSEL
* [Gedcom] Importing file containing multibyte UTF-8 characters fails
* [Gedcom] Import fails for ANSI file under python 3
* [Gedcom] Failure importing ANSEL encoded gedcom file.
* [Gedcom] Characters ignored on a Gedcom encoded ANSI (cp1252 West Europe, USA)
* [Gedcom] NameError in importer
* [Gedcom] Event address is lost on import, i.e. disconnected from event
* Crash on geneweb export with python3
* GuiColorOption missing avail-changed event handler
* Bad generation of [timeline report] ODT files since 4.0.0
* Fix bad handle in explanation note for unknown event
* Fix spurious generation of empty 'Alternative Name' in place.merge()
* Support creating directories in various scenarios
* Attempting to add a bookmark causes an error
* Long series of "unhandled exception" popup boxes while doing a check & repair
* Crash when trying to link existing place as an enclosing place using P0001 number
* HTML view fails to load
* Relationship Graph crashes
* Python3 needs new_subpixbuf not subpixbuf
* Regression: running gramps from crontab fails
* tag_map is not initialized
* Some labels now fit better on citations sidebar filter
* Event columns in web narrative are too narrow
* Problem by start program (launcher)
* Translation string missing in Not Related tool for help and close button
* Date format month/year is not well reported at editing time [in Italian]
* Fix unknown gender relationships handler for the french locale
* Fix a handle type bug on sidebar filter
* Tidy up About dialog
* Cleanup on some man files
* Convert some remaining unicode literals
* Fix mac menubar setting
* Enable python3 to run po/update_po.py
* Updated translations: cs, de, fr, is, nl
2015-02-28
Version 4.1.2, "That's no ordinary rabbit", a maintenance release.
* Error converting python2 utf-8 strings to python3 str when loading data from database
+8
View File
@@ -248,6 +248,14 @@ table.primobjlist tr.BeginLetter td, table.primobjlist tr.BeginSurname td {
td.ColumnLetter, td.ColumnRowLabel {
font-weight: bold;
}
/* bug #8213 testing by Stephane, 2014-12-6 */
td.ColumnEvent, td.ColumnDate {
white-space: nowrap;
}
td.ColumnPlace, td.ColumnDescription {
width: 20%
}
/* end of customizations by Stephane */
td.ColumnBirth, td.ColumnDeath, td.ColumnPartner, td.ColumnParents {
font-size: 90%;
}
+3 -3
View File
@@ -82,9 +82,9 @@ gramps(1) @VERSION@ gramps(1)
**-i** , **--import=** *FILE*
Import data from *FILE* . If you haven't specified a database then
a temporary database is used; this is deleted when you exit
gramps.
Import data from *FILE* . If you haven't specified a database, then
an empty database is created for you called Family Tree x
(where x is an incrementing number).
When more than one input file is given, each has to be preceded
by **-i** flag. The files are imported in the specified order, i.e.
+2 -2
View File
@@ -82,8 +82,8 @@ gramps(1) @VERSION@ gramps(1)
**-i** , **--import=** *FICHIER*
Importer des données depuis un *FICHIER* . Si vous n'avez pas
spécifié de base de données alors une base de données temporaire
est utilisée; elle sera effacée quand vous quitterez gramps.
spécifié de base de données, alors une base de données vide
est utilisée.
Quand plus d'un fichier doit être importé, chacun doit être
précédé par la commande **-i** . Ces fichiers sont importés dans le
+4 -4
View File
@@ -1,4 +1,4 @@
.TH "GRAMPS" "1" "28 December 2012" "4.0" "Gramps"
.TH "GRAMPS" "1" "09 mars 2015" "4.1" "Gramps"
.SH NAME
gramps \- Gramps Documentation
.
@@ -106,8 +106,8 @@ sources, vous devez utiliser l\(aqoption d\(aqimport.
.TP
.B \fB\-i\fP , \fB\-\-import=\fP \fIFICHIER\fP
Importer des données depuis un \fIFICHIER\fP . Si vous n\(aqavez pas
spécifié de base de données alors une base de données temporaire
est utilisée; elle sera effacée quand vous quitterez gramps.
spécifié de base de données, alors une base de données vide
est utilisée.
.sp
Quand plus d\(aqun fichier doit être importé, chacun doit être
précédé par la commande \fB\-i\fP . Ces fichiers sont importés dans le
@@ -337,6 +337,6 @@ gramps(1) @VERSION@ gramps(1)
.SH AUTHOR
Jerome Rapinat
.SH COPYRIGHT
2012, Gramps project
2015, Gramps project
.\" Generated by docutils manpage writer.
.
+1 -1
View File
@@ -104,7 +104,7 @@ If no action, import or export options are given on the command line then an int
.TP
.BI \-i,\-\^\-import= " FILE"
Import data from \fIFILE\fR. If you haven't specified a database then a temporary database is used; this is deleted when you exit gramps.
Import data from \fIFILE\fR. If you haven't specified a database, then an empty database is created for you called Family Tree x (where x is an incrementing number).
.br
When more than one input file is given, each has to be preceded by \fB\-i\fR
+1 -1
View File
@@ -89,7 +89,7 @@
<_tip number="48"><b>Web Family Tree Format</b><br/>Gramps can export data to the Web Family Tree (WFT) format. This format allows a family tree to be displayed online using a single file, instead of many html files.</_tip>
<_tip number="49"><b>Making a Genealogy Website</b><br/>You can easily export your family tree to a web page. Select the entire database, family lines or selected individuals to a collection of web pages ready for upload to the World Wide Web. The Gramps project provides free hosting of websites made with Gramps.</_tip>
<_tip number="49"><b>Making a Genealogy Website</b><br/>You can easily export your family tree to a web page. Select the entire database, family lines or selected individuals to a collection of web pages ready for upload to the World Wide Web.</_tip>
<_tip number="50"><b>Reporting Bugs in Gramps</b><br/>The best way to report a bug in Gramps is to use the Gramps bug tracking system at http://bugs.gramps-project.org</_tip>
+109 -21
View File
@@ -3,11 +3,11 @@
"http://gramps-project.org/xml/1.6.0/grampsxml.dtd">
<database xmlns="http://gramps-project.org/xml/1.6.0/">
<header>
<created date="2014-11-13" version="4.1.0"/>
<created date="2015-05-10" version="4.1.4"/>
<researcher>
<resname>Alex Roitman,,,</resname>
</researcher>
<mediapath>/home/cristina/gramps/master/example/gramps</mediapath>
<mediapath>/home/pierre/Gramps/master/example/gramps</mediapath>
</header>
<name-formats>
<format number="-1" name="SURNAME, Given (Common)" fmt_str="SURNAME, given (common)" active="1"/>
@@ -91,6 +91,11 @@
<dateval val="1592" type="about"/>
<description>Birth of Abbott, Frances</description>
</event>
<event handle="_a5af0eb6abd74c3d7fc" change="1284030605" id="E3415">
<type>Death</type>
<dateval val="1642-01" type="about"/>
<description>Death of Abbott, Frances</description>
</event>
<event handle="_a5af0eb6add73de72aa" change="1284030598" id="E0014">
<type>Birth</type>
<dateval val="1520" type="about"/>
@@ -17897,11 +17902,6 @@
<type>Death</type>
<dateval val="1850" type="about" quality="estimated"/>
</event>
<event handle="_a5af0eb6abd74c3d7fc" change="1284030605" id="E3415">
<type>Death</type>
<dateval val="1642-01" type="about"/>
<description>Death of Abbott, Frances</description>
</event>
</events>
<people home="_GNUJQCL9MD64AM56OH">
<person handle="_004KQCGYT27EEPQHK" change="1185438865" id="I0552">
@@ -20260,7 +20260,7 @@
<parentin hlink="_HQ8KQCT2UX4S9I0E26"/>
<citationref hlink="_c140d24b31f74169170"/>
</person>
<person handle="_3RFKQCNKMX9HVLNSLW" change="1185438865" id="I1116">
<person handle="_3RFKQCNKMX9HVLNSLW" change="1431174900" id="I1116">
<gender>F</gender>
<name type="Birth Name">
<surname>Garner</surname>
@@ -22104,7 +22104,7 @@
<parentin hlink="_JT4KQC83ZKPOLC0UEJ"/>
<citationref hlink="_c140d24fa2503a14583"/>
</person>
<person handle="_6TFKQCUTO94WB2NHN" change="1185438865" id="I1119">
<person handle="_6TFKQCUTO94WB2NHN" change="1431174900" id="I1119">
<gender>F</gender>
<name type="Birth Name">
<first>Zelpha Josephine</first>
@@ -23913,7 +23913,7 @@
<parentin hlink="_1RUJQCCL9MVRYLMTBO"/>
<citationref hlink="_c140d254dcc234394a3"/>
</person>
<person handle="_9QFKQC54ET79K2SD57" change="1185438865" id="I1115">
<person handle="_9QFKQC54ET79K2SD57" change="1431174900" id="I1115">
<gender>F</gender>
<name type="Birth Name">
<first>Mary M.</first>
@@ -24600,7 +24600,7 @@
<parentin hlink="_4W1KQCYZD6N5M576RA"/>
<citationref hlink="_c140d2566d57b164cf5"/>
</person>
<person handle="_AWFKQCJELLUWDY2PD3" change="1284030919" id="I1123">
<person handle="_AWFKQCJELLUWDY2PD3" change="1431174900" id="I1123">
<gender>M</gender>
<name type="Birth Name">
<first>Robert F.</first>
@@ -27182,7 +27182,7 @@
<parentin hlink="_0Q3KQCBZ4421A3L5B4"/>
<citationref hlink="_c140d25c5be3120050a"/>
</person>
<person handle="_EPFKQCETTDTEL3PYIR" change="1185438865" id="I1114">
<person handle="_EPFKQCETTDTEL3PYIR" change="1431174900" id="I1114">
<gender>F</gender>
<name type="Birth Name">
<first>Mary J.</first>
@@ -28226,7 +28226,7 @@
<parentin hlink="_BWAKQCZLIWDX9ZEFED"/>
<citationref hlink="_c140d25eec45aabbd80"/>
</person>
<person handle="_GNUJQCL9MD64AM56OH" change="1328027440" id="I0044">
<person handle="_GNUJQCL9MD64AM56OH" change="1431174904" id="I0044">
<gender>M</gender>
<name type="Birth Name">
<first>Lewis Anderson</first>
@@ -28454,7 +28454,7 @@
<childof hlink="_05XJQC935HU62H3KL4"/>
<citationref hlink="_c140d25f5c448b251ca"/>
</person>
<person handle="_GYFKQCPH8Q0JDN94GR" change="1185438865" id="I1126">
<person handle="_GYFKQCPH8Q0JDN94GR" change="1431174900" id="I1126">
<gender>F</gender>
<name type="Birth Name">
<first>Anetta</first>
@@ -32105,7 +32105,7 @@
<parentin hlink="_ZA6KQC27P0I8E2JZUC"/>
<citationref hlink="_c140d2677c105a1b132"/>
</person>
<person handle="_MUFKQCMXUJ07MCDUNI" change="1185438865" id="I1121">
<person handle="_MUFKQCMXUJ07MCDUNI" change="1431174900" id="I1121">
<gender>F</gender>
<name type="Birth Name">
<first>Iola Elizabeth Betty</first>
@@ -33279,7 +33279,7 @@
<parentin hlink="_9SEKQCAAWRUCIO7A0M"/>
<citationref hlink="_c140d269f4c7c13bf87"/>
</person>
<person handle="_ORFKQC4KLWEGTGR19L" change="1185438865" id="I1117">
<person handle="_ORFKQC4KLWEGTGR19L" change="1431174900" id="I1117">
<gender>F</gender>
<name type="Birth Name">
<first>Rebecca Catharine</first>
@@ -33963,7 +33963,7 @@
<parentin hlink="_IXDKQCOYLEMDKWJZPC"/>
<citationref hlink="_c140d26b98d33ec7f15"/>
</person>
<person handle="_PXFKQCXEHJX3W1Q1IV" change="1185438865" id="I1125">
<person handle="_PXFKQCXEHJX3W1Q1IV" change="1431174900" id="I1125">
<gender>F</gender>
<name type="Birth Name">
<first>Emma A.</first>
@@ -35695,7 +35695,7 @@
<parentin hlink="_FP4KQCQQX8O84KK3IF"/>
<citationref hlink="_c140d27142a05b2d019"/>
</person>
<person handle="_SOFKQCBYAO18OWC0CS" change="1185438865" id="I1113">
<person handle="_SOFKQCBYAO18OWC0CS" change="1431174900" id="I1113">
<gender>F</gender>
<name type="Birth Name">
<first>Phebe</first>
@@ -37068,7 +37068,7 @@
<parentin hlink="_7ZWJQC8ZR4WJZE09RW"/>
<citationref hlink="_c140d276c1802ec5ac3"/>
</person>
<person handle="_UZFKQCIHVT44DC9KGH" change="1185438865" id="I1128">
<person handle="_UZFKQCIHVT44DC9KGH" change="1431174900" id="I1128">
<gender>F</gender>
<name type="Birth Name">
<first>Antoinette</first>
@@ -42060,12 +42060,12 @@
<childref hlink="_GH0KQCGPLF5J17PELU"/>
<citationref hlink="_c140d286d0e2f46fb29"/>
</family>
<family handle="_8OUJQCUVZ0XML7BQLF" change="1185438865" id="F0018">
<family handle="_8OUJQCUVZ0XML7BQLF" change="1431174900" id="F0018">
<rel type="Married"/>
<father hlink="_35WJQC1B7T7NPV8OLV"/>
<mother hlink="_46WJQCIOLQ0KOX2XCC"/>
<eventref hlink="_a5af0ed602318310d6d" role="Family"/>
<childref hlink="_GNUJQCL9MD64AM56OH"/>
<childref hlink="_GNUJQCL9MD64AM56OH" mrel="Custom relationship to mother" frel="Custom relationship to father"/>
<childref hlink="_SOFKQCBYAO18OWC0CS"/>
<childref hlink="_EPFKQCETTDTEL3PYIR"/>
<childref hlink="_9QFKQC54ET79K2SD57"/>
@@ -63928,6 +63928,94 @@ page 26 Repository:Address</text>
<range start="0" end="705"/>
</style>
</note>
<note handle="_d0436bba4ec328d3b631259a4ee" change="1431184305" id="_header1" type="General">
<text>Title for the example pages</text>
<style name="fontcolor" value="#ef2929">
<range start="0" end="27"/>
</style>
<style name="underline">
<range start="0" end="27"/>
</style>
<style name="fontface" value="Serif">
<range start="0" end="27"/>
</style>
<style name="bold">
<range start="0" end="27"/>
</style>
<style name="fontsize" value="8">
<range start="0" end="27"/>
</style>
</note>
<note handle="_d0436bcc69d6bba278bff5bc7db" change="1431184300" id="_footer1" type="General">
<text>Footer: exported by __GRAMPS_HOMEPAGE__ on __EXPORT_DATE__</text>
</note>
<note handle="_d0436be64ac277b615b79b34e72" change="1431211661" id="_custom1" type="General">
<text>Export date: __EXPORT_DATE__
GRAMPS homepage: __GRAMPS_HOMEPAGE__
GRAMPS version: __GRAMPS_VERSION__
Number of families: __NB_FAMILIES__
Number of persons: __NB_INDIVIDUALS__
Number of media objects: __NB_MEDIA__
Number of sources: __NB_SOURCES__
Number of repositories: __NB_REPOSITORIES__
Number of places: __NB_PLACES__
Search form:
__SEARCH_FORM__
Test link person: Garner von Zieliński, Lewis Anderson Sr
Test link family: Family of Warner, Allen Carl and Garner, Rita Marie
Test link source: World of the Wierd
Test link media: 1897_expeditionsmannschaft_rio_a
Test link place: Warren-Farmington Hills-Troy, MI
Test internet link: blog.codinghorror.com
Test relative path link: relative file path to &quot;archive.zip&quot;
Test relative path link: relative file path to &quot;archive.tgz&quot;
Thumbnail for &quot;1897_expeditionsmannschaft_rio_a&quot;:
__THUMB_O0010__
Image &quot;AntoineClaudet&quot;:
__MEDIA_O0011__
Thumbnail for &quot;1897_expeditionsmannschaft_rio_a&quot; with link:
__THUMB_O0010__
Image &quot;AntoineClaudet&quot; with link:
__MEDIA_O0011__
Wrong media ID:
__MEDIA_wrong id__</text>
<style name="link" value="relative://relative.archive.zip">
<range start="663" end="686"/>
</style>
<style name="link" value="gramps://Media/handle/238CGQ939HG18SS5MG">
<range start="952" end="967"/>
</style>
<style name="link" value="gramps://Media/handle/238CGQ939HG18SS5MG">
<range start="520" end="535"/>
</style>
<style name="link" value="gramps://Family/handle/48TJQCGNNIR5SJRCAK">
<range start="413" end="429"/>
</style>
<style name="link" value="gramps://Person/handle/GNUJQCL9MD64AM56OH">
<range start="355" end="371"/>
</style>
<style name="link" value="http://blog.codinghorror.com/">
<range start="621" end="639"/>
</style>
<style name="link" value="gramps://Source/handle/VUBKMQTA2XZG1V6QP8">
<range start="483" end="499"/>
</style>
<style name="link" value="gramps://Place/handle/3WTJQCB9F2MX9W98VP">
<range start="570" end="585"/>
</style>
<style name="link" value="gramps://Media/handle/Y3ARGQWE088EQRTTDH">
<range start="1002" end="1017"/>
</style>
<style name="link" value="relative://relative.archive.tgz">
<range start="724" end="747"/>
</style>
</note>
</notes>
<bookmarks>
<bookmark target="person" hlink="_AWFKQCJELLUWDY2PD3"/>
+3 -1
View File
@@ -497,6 +497,8 @@ def time_val(dirpath):
if tval_mod > tval:
tval = tval_mod
last = time.strftime('%x %X', time.localtime(tval))
if sys.version_info[0] < 3:
last = last.decode(glocale.encoding)
else:
tval = 0
last = _("Never")
@@ -517,6 +519,6 @@ def find_locker_name(dirpath):
# feature request 2356: avoid genitive form
last = _("Locked by %s") % username
ifile.close()
except (OSError, IOError):
except (OSError, IOError, UnicodeDecodeError):
last = _("Unknown")
return last
+1 -1
View File
@@ -117,7 +117,7 @@ class User(user.User):
"""
self._fileout.write("\r100%\n")
def prompt(self, title, message, accept_label, reject_label):
def prompt(self, title, message, accept_label, reject_label, parent=None):
"""
Prompt the user with a message to select an alternative.
+3 -6
View File
@@ -49,7 +49,7 @@ from .constfunc import get_env_var, conv_to_unicode
#
#-------------------------------------------------------------------------
PROGRAM_NAME = "Gramps"
from ..version import VERSION, VERSION_TUPLE, major_version
from gramps.version import VERSION, VERSION_TUPLE, major_version
#-------------------------------------------------------------------------
#
# Standard GRAMPS Websites
@@ -134,8 +134,8 @@ sys.path.insert(0, ROOT_DIR)
git_revision = get_git_revision(ROOT_DIR)
if sys.platform == 'win32' and git_revision == "":
git_revision = get_git_revision(os.path.split(ROOT_DIR)[1])
#VERSION += git_revision
VERSION += "-1"
VERSION += git_revision
#VERSION += "-1"
#
# Glade files
@@ -215,9 +215,6 @@ DOCUMENTERS = [
'Alexander Roitman',
]
TRANSLATORS = _('TRANSLATORS: Translate this to your '
'name in your native language')
#-------------------------------------------------------------------------
#
# Constants
+3 -1
View File
@@ -221,7 +221,9 @@ class DateDisplayCZ(DateDisplay):
# this must agree with DateDisplayEn's "formats" definition
# (since no locale-specific _display_gregorian exists, here)
def display(self, date):
display = DateDisplay.display_formatted
def orig_display(self, date):
"""
Return a text string representing the date.
"""
+1 -1
View File
@@ -631,4 +631,4 @@ class DateDisplayEn(DateDisplay):
display = DateDisplay.display_formatted
_locale = _grampslocale.glocale # normally set in register_datehandler
_locale = DateDisplay._locale # normally set in register_datehandler
+6 -2
View File
@@ -629,8 +629,12 @@ class DateParser(object):
else:
y = self._get_int(groups[4])
if self.dmy:
m = self._get_int(groups[3])
d = self._get_int(groups[1])
if groups[3] is None:
m = self._get_int(groups[1])
d = 0
else:
m = self._get_int(groups[3])
d = self._get_int(groups[1])
else:
m = self._get_int(groups[1])
d = self._get_int(groups[3])
+6 -1
View File
@@ -27,6 +27,7 @@ Class handling language-specific selection for date parser and displayer.
# Python modules
#
#-------------------------------------------------------------------------
import sys
import time
#-------------------------------------------------------------------------
@@ -35,6 +36,7 @@ import time
#
#-------------------------------------------------------------------------
from ..lib.date import Date
from ..const import GRAMPS_LOCALE as glocale
from . import LANG_TO_DISPLAY, LANG, parser, displayer
#--------------------------------------------------------------
@@ -94,4 +96,7 @@ def format_time(secs):
"""
t = time.localtime(secs)
d = Date(t.tm_year, t.tm_mon, t.tm_mday)
return displayer.display(d) + time.strftime(' %X', t)
if sys.version_info[0] < 3:
return displayer.display(d) + time.strftime(' %X', t).decode(glocale.encoding)
else:
return displayer.display(d) + time.strftime(' %X', t)
+1
View File
@@ -444,6 +444,7 @@ class DbBsddbRead(DbReadBase, Callback):
self.citation_map = {}
self.repository_map = {}
self.note_map = {}
self.tag_map = {}
self.media_map = {}
self.event_map = {}
self.metadata = {}
+11 -9
View File
@@ -2471,14 +2471,14 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
with open(versionpath, "w") as version_file:
version_file.write(version)
versionpath = os.path.join(name, cuni(PCKVERSFN))
_LOG.debug("Write pickle version file to %s" % "Yes")
with open(versionpath, "w") as version_file:
version = "Yes"
if sys.version_info[0] <3:
if isinstance(version, UNITYPE):
version = version.encode('utf-8')
version_file.write(version)
# The pickle upgrade file is not written for Python2; its contents is
# never actually examined, all that matters is whether it is present
if sys.version_info[0] >= 3:
versionpath = os.path.join(name, cuni(PCKVERSFN))
_LOG.debug("Write pickle version file to %s" % "Yes")
with open(versionpath, "w") as version_file:
version = "Yes"
version_file.write(version)
versionpath = os.path.join(name, cuni(SCHVERSFN))
_LOG.debug("Write schema version file to %s" % str(_DBVERSION))
@@ -2529,7 +2529,9 @@ def write_lock_file(name):
try:
user = os.getlogin()
except:
user = os.environ['USER'] #not win, don't need get_env_var
# not win, so don't need get_env_var.
# under cron getlogin() throws and there is no USER.
user = os.environ.get('USER', 'noUSER')
if host:
text = "%s@%s" % (user, host)
else:
+2
View File
@@ -55,6 +55,8 @@ class PlaceDisplay(object):
if place_handle:
place = db.get_place_from_handle(place_handle)
return self.display(db, place, event.get_date_object())
else:
return ""
def display(self, db, place, date=None):
if not place:
@@ -78,22 +78,26 @@ class IsDescendantFamilyOf(Rule):
return
# Add self
self.matches.add(person.handle)
expand = [person]
for family_handle in person.get_family_handle_list():
family = self.db.get_family_from_handle(family_handle)
if family:
# Add every child recursively
for child_ref in family.get_child_ref_list():
if child_ref:
self.add_matches(self.db.get_person_from_handle(child_ref.ref))
# Add spouse
if person.handle == family.get_father_handle():
spouse_handle = family.get_mother_handle()
else:
spouse_handle = family.get_father_handle()
self.matches.add(spouse_handle)
while expand:
person = expand.pop(0)
if person is None:
continue
self.matches.add(person.handle)
for family_handle in person.get_family_handle_list():
family = self.db.get_family_from_handle(family_handle)
if family:
# Add every child recursively
for child_ref in family.get_child_ref_list():
if child_ref:
expand.append(self.db.get_person_from_handle(child_ref.ref))
# Add spouse
if person.handle == family.get_father_handle():
spouse_handle = family.get_mother_handle()
else:
spouse_handle = family.get_father_handle()
self.matches.add(spouse_handle)
def exclude(self):
# This removes root person and his/her spouses from the matches set
@@ -63,34 +63,42 @@ class IsRelatedWith(Rule):
return person.handle in self.relatives
def add_relative(self, person):
"""Recursive function that scans relatives and add them to self.relatives"""
if not(person) or person.handle in self.relatives:
def add_relative(self, start):
"""Non-recursive function that scans relatives and add them to self.relatives"""
if not(start):
return
# Add the relative to the list
self.relatives.append(person.handle)
expand = [start]
relatives = {}
while expand:
person = expand.pop()
# Add the relative to the list
if person is None or (person.handle in relatives):
continue
relatives[person.handle] = True
for family_handle in person.get_parent_family_handle_list():
family = self.db.get_family_from_handle(family_handle)
if family:
# Check Parents
for parent_handle in (family.get_father_handle(), family.get_mother_handle()):
if parent_handle:
self.add_relative(self.db.get_person_from_handle(parent_handle))
# Check Sibilings
for child_ref in family.get_child_ref_list():
self.add_relative(self.db.get_person_from_handle(child_ref.ref))
for family_handle in person.get_family_handle_list():
family = self.db.get_family_from_handle(family_handle)
if family:
# Check Spouse
for parent_handle in (family.get_father_handle(), family.get_mother_handle()):
if parent_handle:
self.add_relative(self.db.get_person_from_handle(parent_handle))
# Check Children
for child_ref in family.get_child_ref_list():
self.add_relative(self.db.get_person_from_handle(child_ref.ref))
return
for family_handle in person.get_parent_family_handle_list():
family = self.db.get_family_from_handle(family_handle)
if family:
# Check Parents
for parent_handle in (family.get_father_handle(), family.get_mother_handle()):
if parent_handle:
expand.append(self.db.get_person_from_handle(parent_handle))
# Check Sibilings
for child_ref in family.get_child_ref_list():
expand.append(self.db.get_person_from_handle(child_ref.ref))
for family_handle in person.get_family_handle_list():
family = self.db.get_family_from_handle(family_handle)
if family:
# Check Spouse
for parent_handle in (family.get_father_handle(), family.get_mother_handle()):
if parent_handle:
expand.append(self.db.get_person_from_handle(parent_handle))
# Check Children
for child_ref in family.get_child_ref_list():
expand.append(self.db.get_person_from_handle(child_ref.ref))
self.relatives = list(relatives.keys())
return
+3
View File
@@ -67,6 +67,9 @@ class AttributeRoot(SecondaryObject, PrivacyBase):
self.type = None
self.value = None
def __str__(self):
return str(self.value)
def serialize(self):
"""
Convert the object to a serialized tuple of data.
+1 -1
View File
@@ -571,7 +571,7 @@ class Place(CitationBase, NoteBase, MediaBase, UrlBase, PrimaryObject):
:param acquisition: instance to merge
:type acquisition: :class:'~.place.Place
"""
if acquisition.name not in self.alt_names:
if acquisition.name and (acquisition.name not in self.alt_names):
self.alt_names.append(acquisition.name)
for addendum in acquisition.alt_names:
+1 -1
View File
@@ -33,7 +33,7 @@ import libxslt
from gramps.plugins.lib.libgrampsxml import GRAMPS_XML_VERSION
from ...const import ROOT_DIR, USER_PLUGINS
from ....version import VERSION
from gramps.version import VERSION
from ...lib import Name, Surname
from ...const import GRAMPS_LOCALE as glocale
_ = glocale.translation.sgettext
+11 -5
View File
@@ -42,7 +42,7 @@ import io
# GRAMPS modules
#
#-------------------------------------------------------------------------
from ...version import VERSION as GRAMPSVERSION, VERSION_TUPLE
from gramps.version import VERSION as GRAMPSVERSION, VERSION_TUPLE
from ..const import IMAGE_DIR
from ..const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
@@ -1100,10 +1100,16 @@ class PluginRegister(object):
continue
lenpd = len(self.__plugindata)
full_filename = os.path.join(dir, filename)
if sys.version_info[0] < 3:
fd = open(full_filename, "r")
else:
fd = io.open(full_filename, "r", encoding='utf-8')
try:
if sys.version_info[0] < 3:
fd = open(full_filename, "r")
else:
fd = io.open(full_filename, "r", encoding='utf-8')
except Exception as msg:
print(_('ERROR: Failed reading plugin registration %(filename)s') % \
{'filename' : filename})
print(msg)
continue
stream = fd.read()
fd.close()
if os.path.exists(os.path.join(os.path.dirname(full_filename),
+1 -1
View File
@@ -50,7 +50,7 @@ LOG = logging.getLogger(".gen.plug")
#-------------------------------------------------------------------------
from ._pluginreg import make_environment
from ..const import USER_PLUGINS
from ...version import VERSION_TUPLE
from gramps.version import VERSION_TUPLE
from . import BasePluginManager
from ..utils.configmanager import safe_eval
from ..config import config
+10 -11
View File
@@ -261,8 +261,15 @@ def get_participant_from_event(db, event_handle, all_=False):
"""
participant = ""
ellipses = False
result_list = list(db.find_backlink_handles(event_handle,
include_classes=['Person', 'Family']))
try:
result_list = list(db.find_backlink_handles(event_handle,
include_classes=['Person', 'Family']))
except:
# during a magic batch transaction find_backlink_handles tries to
# access the reference_map_referenced_map which is closed
# under those circumstances.
return ''
#obtain handles without duplicates
people = set([x[1] for x in result_list if x[0] == 'Person'])
families = set([x[1] for x in result_list if x[0] == 'Family'])
@@ -328,15 +335,7 @@ def navigation_label(db, nav_type, handle):
elif nav_type == 'Event':
obj = db.get_event_from_handle(handle)
if obj:
try:
who = get_participant_from_event(db, handle)
except:
# get_participants_from_event fails when called during a magic
# batch transaction because find_backlink_handles tries to
# access the reference_map_referenced_map which doesn't exist
# under those circumstances. Since setting the navigation_label
# is inessential, just accept this and go on.
who = ''
who = get_participant_from_event(db, handle)
desc = obj.get_description()
label = obj.get_type()
if desc:
+2
View File
@@ -195,4 +195,6 @@ def create_checksum(full_path):
md5sum = hashlib.md5(media_file.read()).hexdigest()
except IOError:
md5sum = ''
except UnicodeEncodeError:
md5sum = ''
return md5sum
+1 -1
View File
@@ -208,7 +208,7 @@ class GrampsLocale(object):
self.lang = loc[0]
self.encoding = loc[1]
else:
(lang, loc) = _check_mswin_locale(lang)
(lang, loc) = _check_mswin_locale(locale.getdefaultlocale()[0])
if lang:
self.lang = lang
self.encoding = loc[1]
+3 -12
View File
@@ -90,10 +90,7 @@ def resize_to_jpeg(source, destination, width, height, crop=None):
(start_x, start_y, end_x, end_y
) = crop_percentage_to_pixel(
img.get_width(), img.get_height(), crop)
if sys.version_info[0] < 3:
img = img.new_subpixbuf(start_x, start_y, end_x-start_x, end_y-start_y)
else:
img = img.subpixbuf(start_x, start_y, end_x-start_x, end_y-start_y)
img = img.new_subpixbuf(start_x, start_y, end_x-start_x, end_y-start_y)
# Need to keep the ratio intact, otherwise scaled images look stretched
# if the dimensions aren't close in size
@@ -231,10 +228,7 @@ def resize_to_buffer(source, size, crop=None):
(start_x, start_y, end_x, end_y
) = crop_percentage_to_pixel(
img.get_width(), img.get_height(), crop)
if sys.version_info[0] < 3:
img = img.new_subpixbuf(start_x, start_y, end_x-start_x, end_y-start_y)
else:
img = img.subpixbuf(start_x, start_y, end_x-start_x, end_y-start_y)
img = img.new_subpixbuf(start_x, start_y, end_x-start_x, end_y-start_y)
# Need to keep the ratio intact, otherwise scaled images look stretched
# if the dimensions aren't close in size
@@ -272,10 +266,7 @@ def resize_to_jpeg_buffer(source, size, crop=None):
) = crop_percentage_to_pixel(
img.get_width(), img.get_height(), crop)
if sys.version_info[0] < 3:
img = img.new_subpixbuf(start_x, start_y, end_x-start_x, end_y-start_y)
else:
img = img.subpixbuf(start_x, start_y, end_x-start_x, end_y-start_y)
img = img.new_subpixbuf(start_x, start_y, end_x-start_x, end_y-start_y)
# Need to keep the ratio intact, otherwise scaled images look stretched
# if the dimensions aren't close in size
+9 -3
View File
@@ -29,6 +29,7 @@ Make an 'Unknown' primary object
# Python modules
#
#-------------------------------------------------------------------------
import sys
import time
import os
@@ -146,8 +147,11 @@ def make_unknown(class_arg, explanation, class_func, commit_func, transaction,
elif isinstance(obj, Tag):
if not hasattr(make_unknown, 'count'):
make_unknown.count = 1 #primitive static variable
tval = time.strftime('%x %X', time.localtime())
if sys.version_info[0] < 3:
tval = tval.decode(glocale.encoding)
obj.set_name(_("Unknown, was missing %(time)s (%(count)d)") % {
'time': time.strftime('%x %X', time.localtime()),
'time': tval,
'count': make_unknown.count})
make_unknown.count += 1
else:
@@ -165,9 +169,11 @@ def create_explanation_note(dbase):
those objects of type "Unknown" need a explanatory note. This funcion
provides such a note for import methods.
"""
tval = time.strftime('%x %X', time.localtime())
if sys.version_info[0] < 3:
tval = tval.decode(glocale.encoding)
note = Note( _('Objects referenced by this note '
'were missing in a file imported on %s.') %
time.strftime('%x %X', time.localtime()))
'were missing in a file imported on %s.') % tval)
note.set_handle(create_id())
note.set_gramps_id(dbase.find_next_note_gramps_id())
# Use defaults for privacy, format and type.
+16 -40
View File
@@ -56,7 +56,7 @@ from gi.repository import GdkPixbuf
#-------------------------------------------------------------------------
from gramps.gen.const import (AUTHORS, AUTHORS_FILE, COMMENTS, COPYRIGHT_MSG,
DOCUMENTERS, LICENSE_FILE, PROGRAM_NAME, SPLASH,
TRANSLATORS, URL_HOMEPAGE, VERSION)
URL_HOMEPAGE, VERSION)
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
from gramps.gen.constfunc import get_env_var
@@ -68,14 +68,6 @@ if config.get('preferences.use-bsddb3') or sys.version_info[0] >= 3:
else:
import bsddb
#-------------------------------------------------------------------------
#
# Constants
#
#-------------------------------------------------------------------------
AUTHORS_HEADER = _('==== Authors ====\n')
CONTRIB_HEADER = _('\n==== Contributors ====\n')
#-------------------------------------------------------------------------
#
# GrampsAboutDialog
@@ -85,20 +77,19 @@ class GrampsAboutDialog(Gtk.AboutDialog):
"""Create an About dialog with all fields set."""
def __init__(self, parent):
"""Setup all the fields shown in the About dialog."""
GObject.GObject.__init__(self)
Gtk.AboutDialog.__init__(self)
self.set_transient_for(parent)
self.set_modal(True)
self.set_name(PROGRAM_NAME)
self.set_version(VERSION)
self.set_copyright(COPYRIGHT_MSG)
self.set_artists([
_("Much of Gramps' artwork is either from\n"
"the Tango Project or derived from the Tango\n"
"Project. This artwork is released under the\n"
"Creative Commons Attribution-ShareAlike 2.5\n"
"license.")
])
artists = _("Much of Gramps' artwork is either from\n"
"the Tango Project or derived from the Tango\n"
"Project. This artwork is released under the\n"
"Creative Commons Attribution-ShareAlike 2.5\n"
"license.")
self.set_artists(artists.split('\n'))
try:
ifile = open(LICENSE_FILE, "r")
@@ -111,12 +102,13 @@ class GrampsAboutDialog(Gtk.AboutDialog):
self.set_website_label(_('Gramps Homepage'))
self.set_website(URL_HOMEPAGE)
self.set_authors(_get_authors())
authors, contributors = _get_authors()
self.set_authors(authors)
if len(contributors) > 0:
self.add_credit_section(_('Contributions by'), contributors)
# Only set translation credits if they are translated
trans_credits = _(TRANSLATORS)
if trans_credits != TRANSLATORS:
self.set_translator_credits(trans_credits)
# TRANSLATORS: Translate this to your name in your native language
self.set_translator_credits(_("translator-credits"))
self.set_documenters(DOCUMENTERS)
self.set_logo(GdkPixbuf.Pixbuf.new_from_file(SPLASH))
@@ -232,25 +224,9 @@ def _get_authors():
parser.parse(authors_file)
authors_file.close()
authors_text = ([AUTHORS_HEADER] + authors +
[CONTRIB_HEADER] + contributors)
authors_text = [authors, contributors]
except (IOError, OSError, SAXParseException):
authors_text = AUTHORS
authors_text = [AUTHORS, []]
return authors_text
#-------------------------------------------------------------------------
#
# _show_url
#
#-------------------------------------------------------------------------
def _show_url(dialog, link, prefix):
"""Show links in About dialog."""
if prefix is not None:
link = prefix + link
display_url(link)
#TODO GTK3: is there an alternative for these:
#Gtk.about_dialog_set_url_hook(_show_url, None)
#Gtk.about_dialog_set_email_hook(_show_url, 'mailto:')
+10 -1
View File
@@ -1564,7 +1564,8 @@ class MultiTreeView(Gtk.TreeView):
def edit_obj(self, objclass, handle):
from .editors import (EditPerson, EditEvent, EditFamily, EditSource,
EditPlace, EditRepository, EditNote, EditMedia)
EditPlace, EditRepository, EditNote, EditMedia,
EditCitation)
if objclass == 'Person':
person = self.dbstate.db.get_person_from_handle(handle)
if person:
@@ -1629,6 +1630,14 @@ class MultiTreeView(Gtk.TreeView):
self.uistate, [], ref)
except WindowActiveError:
pass
elif objclass == 'Citation':
ref = self.dbstate.db.get_citation_from_handle(handle)
if ref:
try:
EditCitation(self.dbstate,
self.uistate, [], ref)
except WindowActiveError:
pass
def short(val,size=60):
if len(val) > size:
+27 -21
View File
@@ -97,7 +97,7 @@ class DisplayNameEditor(ManagedWindow):
def __init__(self, uistate, dbstate, track, dialog):
# Assumes that there are two methods: dialog.name_changed_check(),
# and dialog._build_custom_name_ui()
ManagedWindow.__init__(self, uistate, [], DisplayNameEditor)
ManagedWindow.__init__(self, uistate, track, DisplayNameEditor)
self.dialog = dialog
self.dbstate = dbstate
self.set_window(
@@ -136,7 +136,8 @@ UPPERCASE keyword forces uppercase. Extra parentheses, commas are removed. Other
ManagedWindow.close(self, *obj)
def build_menu_names(self, obj):
return (_(" Name Editor"), _("Preferences"))
# NameEditor is leaf of parent branch
return (_(" Name Editor"), None)
#-------------------------------------------------------------------------
@@ -188,7 +189,6 @@ class ConfigureDialog(ManagedWindow):
self.__setup_pages(configure_page_funcs)
self.window.show_all()
self.show()
def __setup_pages(self, configure_page_funcs):
@@ -231,12 +231,12 @@ class ConfigureDialog(ManagedWindow):
except TypeError:
print("WARNING: ignoring invalid value for '%s'" % constant)
ErrorDialog(_("Invalid or incomplete format definition."),
obj.get_text())
obj.get_text(), parent=self.window)
obj.set_text('<b>%s</b>')
except ValueError:
print("WARNING: ignoring invalid value for '%s'" % constant)
ErrorDialog(_("Invalid or incomplete format definition."),
obj.get_text())
obj.get_text(), parent=self.window)
obj.set_text('<b>%s</b>')
self.__config.set(constant, unicode(obj.get_text()))
@@ -770,7 +770,7 @@ class GrampsPreferences(ConfigureDialog):
# check to see if this pattern already exists
if self.__check_for_name(translation, node):
ErrorDialog(_("This format exists already."),
translation)
translation, parent=self.window)
self.edit_button.emit('clicked')
return
# else, change the name
@@ -1170,13 +1170,15 @@ class GrampsPreferences(ConfigureDialog):
config.set('preferences.date-format', obj.get_active())
OkDialog(_('Change is not immediate'),
_('Changing the date format will not take '
'effect until the next time Gramps is started.'))
'effect until the next time Gramps is started.'),
parent=self.window)
def place_format_changed(self, obj):
config.set('preferences.place-format', obj.get_active())
OkDialog(_('Change is not immediate'),
_('Changing the place format will not take '
'effect until the next time Gramps is started.'))
'effect until the next time Gramps is started.'),
parent=self.window)
def date_calendar_changed(self, obj):
config.set('preferences.calendar-format-report', obj.get_active())
@@ -1388,12 +1390,13 @@ class GrampsPreferences(ConfigureDialog):
def select_mediapath(self, *obj):
f = Gtk.FileChooserDialog(
_("Select media directory"),
action=Gtk.FileChooserAction.SELECT_FOLDER,
buttons=(Gtk.STOCK_CANCEL,
Gtk.ResponseType.CANCEL,
Gtk.STOCK_APPLY,
Gtk.ResponseType.OK))
title=_("Select media directory"),
parent=self.window,
action=Gtk.FileChooserAction.SELECT_FOLDER,
buttons=(Gtk.STOCK_CANCEL,
Gtk.ResponseType.CANCEL,
Gtk.STOCK_APPLY,
Gtk.ResponseType.OK))
mpath = self.dbstate.db.get_mediapath()
if not mpath:
mpath = HOME_DIR
@@ -1412,12 +1415,13 @@ class GrampsPreferences(ConfigureDialog):
def select_dbpath(self, *obj):
f = Gtk.FileChooserDialog(
_("Select database directory"),
action=Gtk.FileChooserAction.SELECT_FOLDER,
buttons=(Gtk.STOCK_CANCEL,
Gtk.ResponseType.CANCEL,
Gtk.STOCK_APPLY,
Gtk.ResponseType.OK))
title=_("Select database directory"),
parent=self.window,
action=Gtk.FileChooserAction.SELECT_FOLDER,
buttons=(Gtk.STOCK_CANCEL,
Gtk.ResponseType.CANCEL,
Gtk.STOCK_APPLY,
Gtk.ResponseType.OK))
dbpath = config.get('behavior.database-path')
if not dbpath:
dbpath = os.path.join(HOME_DIR,'grampsdb')
@@ -1470,7 +1474,9 @@ class GrampsPreferences(ConfigureDialog):
obj.set_text(str(intval))
def build_menu_names(self, obj):
return (_('Preferences'), None)
# Preferences editor my open other dialog so let main dialog
# be leaf in branch
return (_('Preferences'), _('Preferences'))
# FIXME: is this needed?
def _set_button(self, stock):
+22 -13
View File
@@ -83,24 +83,24 @@ class DbLoader(CLIDbLoader):
self.import_info = None
def _warn(self, title, warnmessage):
WarningDialog(title, warnmessage)
WarningDialog(title, warnmessage, parent=self.uistate.window)
def _errordialog(self, title, errormessage):
"""
Show the error.
In the GUI, the error is shown, and a return happens
"""
ErrorDialog(title, errormessage)
ErrorDialog(title, errormessage, parent=self.uistate.window)
return 1
def _dberrordialog(self, msg):
import traceback
exc = traceback.format_exc()
try:
DBErrorDialog(str(msg.value))
DBErrorDialog(str(msg.value), parent=self.uistate.window)
_LOG.error(str(msg.value))
except:
DBErrorDialog(str(msg))
DBErrorDialog(str(msg), parent=self.uistate.window)
_LOG.error(str(msg) +"\n" + exc)
def _begin_progress(self):
@@ -198,7 +198,8 @@ class DbLoader(CLIDbLoader):
_("Could not open file: %s") % filename,
_('File type "%s" is unknown to Gramps.\n\n'
'Valid types are: Gramps database, Gramps XML, '
'Gramps package, GEDCOM, and others.') % extension)
'Gramps package, GEDCOM, and others.') % extension,
parent=self.uistate.window)
import_dialog.destroy()
return False
@@ -220,13 +221,15 @@ class DbLoader(CLIDbLoader):
elif os.path.isdir(filename):
ErrorDialog(
_('Cannot open file'),
_('The selected file is a directory, not a file.\n'))
_('The selected file is a directory, not a file.\n'),
parent=self.uistate.window)
return True
elif os.path.exists(filename):
if not os.access(filename, os.R_OK):
ErrorDialog(
_('Cannot open file'),
_('You do not have read access to the selected file.'))
_('You do not have read access to the selected file.'),
parent=self.uistate.window)
return True
else:
try:
@@ -236,7 +239,8 @@ class DbLoader(CLIDbLoader):
except IOError:
ErrorDialog(
_('Cannot create file'),
_('You do not have write access to the selected file.'))
_('You do not have write access to the selected file.'),
parent=self.uistate.window)
return True
return False
@@ -259,7 +263,8 @@ class DbLoader(CLIDbLoader):
_("Could not import file: %s") % filename,
_("This file incorrectly identifies its character "
"set, so it cannot be accurately imported. Please fix the "
"encoding, and import again") + "\n\n %s" % msg)
"encoding, and import again") + "\n\n %s" % msg,
parent=self.uistate.window)
except Exception:
_LOG.error("Failed to import database.", exc_info=True)
self._end_progress()
@@ -327,7 +332,8 @@ class DbLoader(CLIDbLoader):
str(msg),
_("I have made a backup,\n"
"please upgrade my Family Tree"),
_("Cancel"), self.uistate.window).run():
_("Cancel"),
parent=self.uistate.window).run():
force_schema_upgrade = True
force_bsddb_upgrade = False
force_bsddb_downgrade = False
@@ -341,7 +347,8 @@ class DbLoader(CLIDbLoader):
str(msg),
_("I have made a backup,\n"
"please upgrade my tree"),
_("Cancel"), self.uistate.window).run():
_("Cancel"),
parent=self.uistate.window).run():
force_schema_upgrade = False
force_bsddb_upgrade = True
force_bsddb_downgrade = False
@@ -355,7 +362,8 @@ class DbLoader(CLIDbLoader):
str(msg),
_("I have made a backup,\n"
"please downgrade my Family Tree"),
_("Cancel"), self.uistate.window).run():
_("Cancel"),
parent=self.uistate.window).run():
force_schema_upgrade = False
force_bsddb_upgrade = False
force_bsddb_downgrade = True
@@ -369,7 +377,8 @@ class DbLoader(CLIDbLoader):
str(msg),
_("I have made a backup,\n"
"please upgrade my Family Tree"),
_("Cancel"), self.uistate.window).run():
_("Cancel"),
parent=self.uistate.window).run():
force_schema_upgrade = False
force_bsddb_upgrade = False
force_bsddb_downgrade = False
+1 -1
View File
@@ -248,7 +248,7 @@ class DbManager(CLIDbManager):
if store.get_value(node, STOCK_COL) == Gtk.STOCK_DIALOG_ERROR:
path = conv_to_unicode(store.get_value(node, PATH_COL), 'utf8')
backup = os.path.join(path, u"person.gbkp")
backup = os.path.join(path, "person.gbkp")
self.repair.set_sensitive(os.path.isfile(backup))
else:
self.repair.set_sensitive(False)
+3 -10
View File
@@ -514,17 +514,10 @@ class GalleryTab(ButtonTab, DbGUIElement):
elif self._DND_EXTRA and mytype == self._DND_EXTRA.drag_type:
self.handle_extra_type(mytype, obj)
except pickle.UnpicklingError:
#modern file managers provide URI_LIST. For Windows split sel_data.data
if win():
files = sel_data.get_data().split('\n')
else:
files = sel_data.get_uris()
files = sel_data.get_uris()
for file in files:
if win():
d = conv_to_unicode((file.replace('\0',' ').strip()), None)
else:
d = file
protocol, site, mfile, j, k, l = urlparse(d)
protocol, site, mfile, j, k, l = urlparse(file)
if protocol == "file":
name = url2pathname(mfile)
mime = get_type(name)
+3
View File
@@ -271,6 +271,7 @@ class EditReference(ManagedWindow, DbGUIElement):
if new_id:
old_primary = self.db.get_from_name_and_gramps_id(type, new_id)
if old_primary:
description = None
if type == 'Event':
msg1 = _("Cannot save event. ID already exists.")
description = old_primary.get_description()
@@ -280,6 +281,8 @@ class EditReference(ManagedWindow, DbGUIElement):
elif type == 'Repository':
msg1 = _("Cannot save repository. ID already exists.")
description = old_primary.get_name()
else:
msg1 = _("Cannot save item. ID already exists.")
if description:
msg2 = _("You have attempted to use the existing Gramps "
"ID with value %(id)s. This value is already "
@@ -62,11 +62,13 @@ class EventSidebarFilter(SidebarFilter):
self.filter_event = Event()
self.filter_event.set_type((EventType.CUSTOM, ''))
self.etype = Gtk.ComboBox(has_entry=True)
self.custom_types = dbstate.db.get_event_types()
self.event_menu = widgets.MonitoredDataType(
self.etype,
self.filter_event.set_type,
self.filter_event.get_type)
self.filter_event.get_type,
custom_values=self.custom_types)
self.filter_mainparts = widgets.BasicEntry()
self.filter_date = widgets.DateEntry(uistate, [])
@@ -29,6 +29,7 @@ from gi.repository import Pango
from ... import widgets
from ...dbguielement import DbGUIElement
from gramps.gen.config import config
from gramps.gen.constfunc import UNITYPE
_RETURN = Gdk.keyval_from_name("Return")
_KP_ENTER = Gdk.keyval_from_name("KP_Enter")
@@ -212,6 +213,9 @@ class SidebarFilter(DbGUIElement):
self.__tag_list = []
for handle in self.dbstate.db.get_tag_handles(sort_handles=True):
tag = self.dbstate.db.get_tag_from_handle(handle)
# for python3 this returns a byte object, so conversion needed
if not isinstance(handle, UNITYPE):
handle = handle.decode('utf-8')
self.__tag_list.append((tag.get_name(), handle))
self.on_tags_changed([item[0] for item in self.__tag_list])
-1
View File
@@ -2,7 +2,6 @@
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkDialog" id="clipboard">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">Clipboard</property>
<property name="default_width">500</property>
-1
View File
@@ -391,7 +391,6 @@ You can use the mouse on the picture to select a region, or use these spinbutton
<object class="GtkExpander" id="expander1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="expanded">True</property>
<child>
<object class="GtkNotebook" id="notebook_shared">
<property name="visible">True</property>
+4 -2
View File
@@ -350,11 +350,13 @@
<child>
<object class="GtkComboBox" id="place_type">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">What type of place this is. Eg 'Country', 'City', ... .</property>
<property name="has_entry">True</property>
<child internal-child="entry">
<object class="GtkEntry" id="combobox-entry">
<property name="can_focus">False</property>
<property name="can_focus">True</property>
<property name="overwrite_mode">True</property>
</object>
</child>
</object>
+1 -1
View File
@@ -378,7 +378,7 @@ def __startgramps(errors, argparser):
% e.code, exc_info=True)
except OSError as e:
quit_now = True
exit_code = e[0] or 1
exit_code = e.errno or 1
try:
fn = e.filename
except AttributeError:
@@ -89,6 +89,15 @@ class ErrorReportAssistant(Gtk.Assistant):
self.build_page4()
self.build_page5()
self.create_page_summary()
try:
self.set_transient_for(self.list_toplevels()[-2])
except IndexError:
self.set_position(Gtk.WindowPosition.CENTER)
self.set_urgency_hint(True)
self.set_keep_above(True)
self.set_default_size(800,-1)
self.show_all()
self.ownthread = ownthread
+7 -1
View File
@@ -82,6 +82,13 @@ class ErrorView(object):
def draw_window(self):
title = "%s - Gramps" % _("Error Report")
self.top = Gtk.Dialog(title)
try:
self.top.set_transient_for(self.top.list_toplevels()[-2])
except IndexError:
self.top.set_position(Gtk.WindowPosition.CENTER)
self.top.set_urgency_hint(True)
self.top.set_keep_above(True)
self.top.set_default_size(800,-1)
vbox = self.top.get_content_area()
vbox.set_spacing(5)
self.top.set_border_width(12)
@@ -128,7 +135,6 @@ class ErrorView(object):
vbox.pack_start(tb_expander, True, True, 5)
self.top.add_button(Gtk.STOCK_CANCEL,Gtk.ResponseType.CANCEL)
self.top.add_button(_("Report"),Gtk.ResponseType.YES)
self.top.add_button(Gtk.STOCK_HELP,Gtk.ResponseType.HELP)
+3
View File
@@ -41,6 +41,7 @@ from gramps.gen.const import URL_MANUAL_PAGE
from ..display import display_help
from ..managedwindow import ManagedWindow
from gramps.gen.merge import MergePlaceQuery
from gramps.gen.display.place import displayer as place_displayer
#-------------------------------------------------------------------------
#
@@ -140,6 +141,8 @@ class MergePlace(ManagedWindow):
self.get_widget(widget_name).set_sensitive(False)
# Main window widgets that determine which handle survives
title1 = place_displayer.display(database, self.pl1)
title2 = place_displayer.display(database, self.pl2)
rbutton1 = self.get_widget("handle_btn1")
rbutton_label1 = self.get_widget("label_handle_btn1")
rbutton_label2 = self.get_widget("label_handle_btn2")
+9 -1
View File
@@ -292,10 +292,18 @@ class Navigator(object):
# Functions
#
#-------------------------------------------------------------------------
def cb_menu_position(menu, button):
def cb_menu_position(*args):
"""
Determine the position of the popup menu.
"""
# takes two argument: menu, button
if len(args) == 2:
menu = args[0]
button = args[1]
# broken introspection can't handle MenuPositionFunc annotations corectly
else:
menu = args[0]
button = args[3]
ret_val, x_pos, y_pos = button.get_window().get_origin()
x_pos += button.get_allocation().x
y_pos += button.get_allocation().y + button.get_allocation().height
+11
View File
@@ -241,6 +241,9 @@ class GuiColorOption(Gtk.ColorButton):
self.changekey = self.connect('color-set', self.__color_changed)
self.valuekey = self.__option.connect('value-changed', self.__value_changed)
self.conkey = self.__option.connect('avail-changed', self.__update_avail)
self.__update_avail()
self.set_tooltip_text(self.__option.get_help())
def __color_changed(self, obj): # IGNORE:W0613 - obj is unused
@@ -257,6 +260,13 @@ class GuiColorOption(Gtk.ColorButton):
self.__option.set_value(value)
self.__option.enable_signals()
def __update_avail(self):
"""
Update the availability (sensitivity) of this widget.
"""
avail = self.__option.get_available()
self.set_sensitive(avail)
def __value_changed(self):
"""
Handle the change made programmatically
@@ -270,6 +280,7 @@ class GuiColorOption(Gtk.ColorButton):
remove stuff that blocks garbage collection
"""
self.__option.disconnect(self.valuekey)
self.__option.disconnect(self.conkey)
self.__option = None
#-------------------------------------------------------------------------
+4 -3
View File
@@ -50,9 +50,10 @@ class Progress(object):
Mirros the same interface that the ExportAssistant uses in the
selection, but this is for the preview selection.
"""
def __init__(self):
def __init__(self, uistate):
from gi.repository import Gtk
self.pm = ProgressMeter(_("Selecting Preview Data"), _('Selecting...'))
self.pm = ProgressMeter(_("Selecting Preview Data"), _('Selecting...'),
parent=uistate.window)
self.progress_cnt = 0
self.title = _("Selecting...")
while Gtk.events_pending():
@@ -239,7 +240,7 @@ class WriterOptionBox(object):
Calculate previews to see the selected data.
"""
self.parse_options()
pm = Progress()
pm = Progress(self.uistate)
self.preview_dbase = self.get_filtered_database(self.dbstate.db, pm, preview=True)
pm.close()
self.preview_button.set_sensitive(0)
+14 -7
View File
@@ -527,13 +527,20 @@ class ReportDialog(ManagedWindow):
# we will need to create the file/dir
# need to make sure we can create in the parent dir
parent_dir = os.path.dirname(os.path.normpath(self.target_path))
if not os.access(parent_dir, os.W_OK):
ErrorDialog(_('Permission problem'),
_("You do not have permission to create "
"%s\n\n"
"Please select another path or correct "
"the permissions.") % self.target_path
)
if os.path.isdir(parent_dir):
if not os.access(parent_dir, os.W_OK):
ErrorDialog(_('Permission problem'),
_("You do not have permission to create "
"%s\n\n"
"Please select another path or correct "
"the permissions.") % self.target_path
)
return None
else:
ErrorDialog(_('No directory'),
_('There is no directory %s.\n\n'
'Please select another directory '
'or create it.') % parent_dir )
return None
self.set_default_directory(os.path.dirname(self.target_path) + os.sep)
+4 -2
View File
@@ -103,7 +103,9 @@ class BatchTool(Tool):
Should be used for tools using batch transactions.
"""
def __init__(self, dbstate, user, options_class, name):
def __init__(self, dbstate, user, options_class, name, parent=None):
if user.uistate:
parent = user.uistate.window
if not user.prompt(
_('Undo history warning'),
_('Proceeding with this tool will erase the undo history '
@@ -112,7 +114,7 @@ class BatchTool(Tool):
'made prior to it.\n\n'
'If you think you may want to revert running this tool, '
'please stop here and backup your database.'),
_('_Proceed with the tool'), _('_Stop')):
_('_Proceed with the tool'), _('_Stop'), parent):
self.fail = True
return
+2 -2
View File
@@ -88,7 +88,7 @@ class User(user.User):
self._progress.close()
self._progress = None
def prompt(self, title, message, accept_label, reject_label):
def prompt(self, title, message, accept_label, reject_label, parent=None):
"""
Prompt the user with a message to select an alternative.
@@ -106,7 +106,7 @@ class User(user.User):
:returns: the user's answer to the question
:rtype: bool
"""
dialog = QuestionDialog2(title, message, accept_label, reject_label)
dialog = QuestionDialog2(title, message, accept_label, reject_label, parent)
return dialog.run()
def warn(self, title, warning=""):
+15 -11
View File
@@ -386,7 +386,7 @@ class ViewManager(CLIManager):
hpane.add2(self.notebook)
self.menubar = self.uimanager.get_widget('/MenuBar')
self.toolbar = self.uimanager.get_widget('/ToolBar')
vbox.pack_start(self.menubar, False, True, 0)
self.__attach_menubar(vbox)
vbox.pack_start(self.toolbar, False, True, 0)
vbox.add(hpane)
self.statusbar = Statusbar()
@@ -834,13 +834,15 @@ class ViewManager(CLIManager):
self.uimanager.add_ui_from_string(UIDEFAULT)
self.uimanager.ensure_update()
def __attach_menubar(self, vbox):
vbox.pack_start(self.menubar, False, True, 0)
if _GTKOSXAPPLICATION:
menubar = self.uimanager.get_widget("/MenuBar")
menubar.hide()
self.menubar.hide()
quit_item = self.uimanager.get_widget("/MenuBar/FileMenu/Quit")
about_item = self.uimanager.get_widget("/MenuBar/HelpMenu/About")
prefs_item = self.uimanager.get_widget("/MenuBar/EditMenu/Preferences")
self.macapp.set_menu_bar(menubar)
self.macapp.set_menu_bar(self.menubar)
self.macapp.insert_app_menu_item(about_item, 0)
self.macapp.insert_app_menu_item(prefs_item, 1)
@@ -1306,7 +1308,8 @@ class ViewManager(CLIManager):
_("Backup file already exists! Overwrite?"),
_("The file '%s' exists.") % filename,
_("Proceed and overwrite"),
_("Cancel the backup"))
_("Cancel the backup"),
parent=self.window)
yes_no = question.run()
if not yes_no:
return
@@ -1337,12 +1340,13 @@ class ViewManager(CLIManager):
right pane, otherwise FileChooserDialog will hang.
"""
f = Gtk.FileChooserDialog(
_("Select backup directory"),
action=Gtk.FileChooserAction.SELECT_FOLDER,
buttons=(Gtk.STOCK_CANCEL,
Gtk.ResponseType.CANCEL,
Gtk.STOCK_APPLY,
Gtk.ResponseType.OK))
title=_("Select backup directory"),
parent=self.window,
action=Gtk.FileChooserAction.SELECT_FOLDER,
buttons=(Gtk.STOCK_CANCEL,
Gtk.ResponseType.CANCEL,
Gtk.STOCK_APPLY,
Gtk.ResponseType.OK))
mpath = path_entry.get_text()
if not mpath:
mpath = HOME_DIR
+9 -1
View File
@@ -277,10 +277,18 @@ class Tags(DbGUIElement):
view.add_tag(trans, object_handle, tag_handle)
status.end()
def cb_menu_position(menu, button):
def cb_menu_position(*args):
"""
Determine the position of the popup menu.
"""
# takes two argument: menu, button
if len(args) == 2:
menu = args[0]
button = args[1]
# broken introspection can't handle MenuPositionFunc annotations corectly
else:
menu = args[0]
button = args[3]
ret_val, x_pos, y_pos = button.get_window().get_origin()
x_pos += button.get_allocation().x
y_pos += button.get_allocation().y + button.get_allocation().height
+5 -2
View File
@@ -44,9 +44,10 @@ from gi.repository import Gtk
# GRAMPS modules
#
#-------------------------------------------------------------------------
from gramps.gen.lib.placetype import PlaceType
from gramps.gen.lib import Place, PlaceType
from gramps.gen.datehandler import format_time
from gramps.gen.utils.place import conv_lat_lon
from gramps.gen.display.place import displayer as place_displayer
from gramps.gen.constfunc import cuni
from .flatbasemodel import FlatBaseModel
from .treebasemodel import TreeBaseModel
@@ -116,7 +117,9 @@ class PlaceBaseModel(object):
return len(self.fmap)+1
def column_title(self, data):
return cuni(data[2])
place = Place()
place.unserialize(data)
return place_displayer.display(self.db, place)
def column_name(self, data):
return cuni(data[6])
+9 -1
View File
@@ -734,10 +734,18 @@ class TabLabel(Gtk.HBox):
else:
self.closebtn.hide()
def cb_menu_position(menu, button):
def cb_menu_position(*args):
"""
Determine the position of the popup menu.
"""
# takes two argument: menu, button
if len(args) == 2:
menu = args[0]
button = args[1]
# broken introspection can't handle MenuPositionFunc annotations corectly
else:
menu = args[0]
button = args[3]
ret_val, x_pos, y_pos = button.get_window().get_origin()
x_pos += button.get_allocation().x
y_pos += button.get_allocation().y + button.get_allocation().height
+5 -1
View File
@@ -284,7 +284,11 @@ class UndoableEntry(Gtk.Entry):
self.set_position(undo_action.offset)
def _undo_delete(self, undo_action):
self.insert_text(undo_action.text, undo_action.start)
if not isinstance(undo_action.text, UNITYPE):
undo_action.text = conv_to_unicode(undo_action.text, 'utf-8')
with warnings.catch_warnings():
warnings.simplefilter('ignore')
self.insert_text(undo_action.text, undo_action.start)
if undo_action.delete_key_used:
self.set_position(undo_action.start)
else:
+1 -1
View File
@@ -731,7 +731,7 @@ class FanChartOptions(MenuReportOptions):
p = ParagraphStyle()
p.set_font(f)
p.set_alignment(PARA_ALIGN_CENTER)
p.set_description(_('The style used for the text display of generation ' + "%d" % i))
p.set_description(_('The style used for the text display of generation "%d"') % i)
default_style.add_paragraph_style("FC-Text" + "%02d" % i, p)
# GraphicsStyles
+1 -1
View File
@@ -281,7 +281,7 @@ class TimeLine(Report):
# subtitle if the report's output is in the main/UI language
mark = None
if toc:
mark = IndexMark(title, INDEX_TYPE_TOC, 1)
mark = IndexMark(title_one, INDEX_TYPE_TOC, 1)
self.doc.center_text('TLG-title', title, width / 2.0, 0, mark)
def draw_year_headings(self, year_low, year_high, start_pos, stop_pos):
+37 -16
View File
@@ -532,16 +532,27 @@ class GedcomWriter(UpdateCallback):
extract the real event to discover the event type.
"""
global adop_written
# adop_written is only shared between this function and
# _process_person_event. This is rather ugly code, but it is difficult
# to support an Adoption event without an Adopted relationship from the
# parent(s), an Adopted relationship from the parent(s) without an
# event, and both an event and a relationship. All these need to be
# supported without duplicating the output of the ADOP GEDCOM tag. See
# bug report 2370.
adop_written = False
for event_ref in person.get_event_ref_list():
event = self.dbase.get_event_from_handle(event_ref.ref)
if not event: continue
self._process_person_event(event, event_ref)
self._adoption_records(person)
self._process_person_event(person, event, event_ref)
if not adop_written:
self._adoption_records(person, adop_written)
def _process_person_event(self, event, event_ref):
def _process_person_event(self, person, event, event_ref):
"""
Process a person event, which is not a BIRTH or DEATH event.
"""
global adop_written
etype = int(event.get_type())
# if the event is a birth or death, skip it.
if etype in (EventType.BIRTH, EventType.DEATH):
@@ -578,8 +589,11 @@ class GedcomWriter(UpdateCallback):
if descr:
self._writeln(2, 'NOTE', "Description: " + descr)
self._dump_event_stats(event, event_ref)
if etype == EventType.ADOPT and not adop_written:
adop_written = True
self._adoption_records(person, adop_written)
def _adoption_records(self, person):
def _adoption_records(self, person, adop_written):
"""
Write Adoption events for each child that has been adopted.
@@ -603,7 +617,8 @@ class GedcomWriter(UpdateCallback):
adoptions.append((family, child_ref.frel, child_ref.mrel))
for (fam, frel, mrel) in adoptions:
self._writeln(1, 'ADOP', 'Y')
if not adop_written:
self._writeln(1, 'ADOP', 'Y')
self._writeln(2, 'FAMC', '@%s@' % fam.get_gramps_id())
if mrel == frel:
self._writeln(3, 'ADOP', 'BOTH')
@@ -1080,7 +1095,7 @@ class GedcomWriter(UpdateCallback):
if event.get_place_handle():
place = self.dbase.get_place_from_handle(event.get_place_handle())
self._place(place, 2)
self._place(place, dateobj, 2)
for attr in event.get_attribute_list():
attr_type = attr.get_type()
@@ -1151,8 +1166,8 @@ class GedcomWriter(UpdateCallback):
if lds_ord.get_temple():
self._writeln(index+1, 'TEMP', lds_ord.get_temple())
if lds_ord.get_place_handle():
self._place(
self.dbase.get_place_from_handle(lds_ord.get_place_handle()), 2)
place = self.dbase.get_place_from_handle(lds_ord.get_place_handle())
self._place(place, lds_ord.get_date_object(), 2)
if lds_ord.get_status() != LdsOrd.STATUS_NONE:
self._writeln(2, 'STAT', LDS_STATUS[lds_ord.get_status()])
@@ -1170,16 +1185,22 @@ class GedcomWriter(UpdateCallback):
cal = date.get_calendar()
mod = date.get_modifier()
quality = date.get_quality()
if quality in libgedcom.DATE_QUALITY:
qual_text = libgedcom.DATE_QUALITY[quality] + " "
else:
qual_text = ""
if mod == Date.MOD_SPAN:
val = "FROM %s TO %s" % (
libgedcom.make_gedcom_date(start, cal, mod, quality),
val = "%sFROM %s TO %s" % (
qual_text,
libgedcom.make_gedcom_date(start, cal, mod, None),
libgedcom.make_gedcom_date(date.get_stop_date(),
cal, mod, quality))
cal, mod, None))
elif mod == Date.MOD_RANGE:
val = "BET %s AND %s" % (
libgedcom.make_gedcom_date(start, cal, mod, quality),
val = "%sBET %s AND %s" % (
qual_text,
libgedcom.make_gedcom_date(start, cal, mod, None),
libgedcom.make_gedcom_date(date.get_stop_date(),
cal, mod, quality))
cal, mod, None))
else:
val = libgedcom.make_gedcom_date(start, cal, mod, quality)
self._writeln(level, 'DATE', val)
@@ -1350,7 +1371,7 @@ class GedcomWriter(UpdateCallback):
self._note_references(photo_obj.get_note_list(), level+1)
def _place(self, place, level):
def _place(self, place, dateobj, level):
"""
PLACE_STRUCTURE:=
n PLAC <PLACE_NAME> {1:1}
@@ -1365,7 +1386,7 @@ class GedcomWriter(UpdateCallback):
+1 <<NOTE_STRUCTURE>> {0:M}
"""
if place is None: return
place_name = place_displayer.display(self.dbase, place)
place_name = place_displayer.display(self.dbase, place, dateobj)
self._writeln(level, "PLAC", place_name.replace('\r', ' '), limit=120)
longitude = place.get_longitude()
latitude = place.get_latitude()
+1 -1
View File
@@ -90,7 +90,7 @@ class GeneWebWriter(object):
self.dirname = os.path.dirname (self.filename)
try:
self.g = open(self.filename, "w")
self.g = open(self.filename, "wb")
except IOError as msg:
msg2 = _("Could not create %s") % self.filename
self.user.notify_error(msg2, str(msg))
+6
View File
@@ -140,6 +140,12 @@ class GrampsXmlWriter(UpdateCallback):
"Please make sure you have write access to the "
"directory and try again."))
return 0
else:
raise DbWriteFailure(_('No directory'),
_('There is no directory %s.\n\n'
'Please select another directory '
'or create it.') % base )
return 0
if os.path.exists(filename):
if not os.access(filename, os.W_OK):
+2 -2
View File
@@ -249,9 +249,9 @@ class AgeStatsGramplet(Gramplet):
"""
# first, binify:
#print "create_bargraph", hash
bin = [0] * (max_val/bin_size)
bin = [0] * int(max_val/bin_size)
for value, hash_value in hash.items():
bin[value/bin_size] += hash_value
bin[int(value/bin_size)] += hash_value
text = ""
max_bin = float(max(bin))
if max_bin != 0:
+4 -2
View File
@@ -18,6 +18,8 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
#
from __future__ import unicode_literals
from collections import defaultdict
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
@@ -66,9 +68,9 @@ class GivenNameCloudGramplet(Gramplet):
allnames = [person.get_primary_name()] + person.get_alternate_names()
allnames = set(name.get_first_name().strip() for name in allnames)
for givenname in allnames:
anyNBSP = givenname.split(u'\u00A0')
anyNBSP = givenname.split('\u00A0')
if len(anyNBSP) > 1: # there was an NBSP, a non-breaking space
first_two = anyNBSP[0] + u'\u00A0' + anyNBSP[1].split()[0]
first_two = anyNBSP[0] + '\u00A0' + anyNBSP[1].split()[0]
givensubnames[first_two] += 1
representative_handle[first_two] = person.handle
givenname = ' '.join(anyNBSP[1].split()[1:])
+21 -5
View File
@@ -76,15 +76,31 @@ def importData(database, filename, user):
database.__class__.__bases__ = (DbMixin,) + \
database.__class__.__bases__
try:
ifile = open(filename, "r")
except IOError:
return
if sys.version_info[0] < 3:
try:
ifile = open(filename, "rU")
except IOError:
return
else:
try:
ifile = open(filename, "rb")
except IOError:
return
# print("file opened")
ansel = False
gramps = False
for index in range(50):
line = ifile.readline().split()
# Treat the file as though it is UTF-8 since this is the more modern
# option; and anyway it doesn't really matter as we are only trying to
# detect a CHAR or SOUR line which is only 7-bit ASCII anyway, and we
# ignore anything that can't be translated.
line = ifile.readline()
if sys.version_info[0] < 3:
line = unicode(line, encoding='utf-8', errors='replace')
else:
line = line.decode(encoding='utf-8', errors='replace')
line = line.split()
if len(line) == 0:
break
if len(line) > 2 and line[1][0:4] == 'CHAR' and line[2] == "ANSEL":
+6 -6
View File
@@ -644,9 +644,8 @@ class GeneWebParser(object):
birth_source = self.get_or_create_source(self.decode(fields[idx]))
idx += 1
elif field[0] == '!':
LOG.debug("Baptize at: %s" % fields[idx])
bapt_date = self.parse_date(self.decode(fields[idx][1:]))
idx += 1
LOG.debug("Baptize at: %s" % field[1:])
bapt_date = self.parse_date(self.decode(field[1:]))
elif field == '#bp' and idx < len(fields):
LOG.debug("Birth Place: %s" % fields[idx])
birth_place = self.get_or_create_place(self.decode(fields[idx]))
@@ -668,9 +667,10 @@ class GeneWebParser(object):
death_source = self.get_or_create_source(self.decode(fields[idx]))
idx += 1
elif field == '#buri' and idx < len(fields):
LOG.debug("Burial Date: %s" % fields[idx])
bur_date = self.parse_date(self.decode(fields[idx]))
idx += 1
if fields[idx][0]!='#': # bug in GeneWeb: empty #buri fields
LOG.debug("Burial Date: %s" % fields[idx])
bur_date = self.parse_date(self.decode(fields[idx]))
idx += 1
elif field == '#crem' and idx < len(fields):
LOG.debug("Cremention Date: %s" % fields[idx])
crem_date = self.parse_date(self.decode(fields[idx]))
+2 -1
View File
@@ -693,7 +693,8 @@ class GrampsParser(UpdateCallback):
"places": (None, self.stop_places),
"placeobj": (self.start_placeobj, self.stop_placeobj),
"placeref": (self.start_placeref, self.stop_placeref),
"ptitle": (None, self.stop_ptitle),
"ptitle": (None, self.stop_ptitle),
"locality": (None, self.stop_locality),
"location": (self.start_location, None),
"lds_ord": (self.start_lds_ord, self.stop_lds_ord),
"temple": (self.start_temple, None),
+401 -167
View File
@@ -578,6 +578,10 @@ LDS_STATUS = {
# table for skipping illegal control chars in GEDCOM import
# Only 09, 0A, 0D are allowed.
STRIP_DICT = dict.fromkeys(list(range(9))+list(range(11, 13))+list(range(14, 32)))
# The C1 Control characters are not treated in Latin-1 (ISO-8859-1) as
# undefined, but if they have been used, the file is probably supposed to be
# cp1252
DEL_AND_C1 = dict.fromkeys(list(range(0x7F, 0x9F)))
#-------------------------------------------------------------------------
#
@@ -689,7 +693,7 @@ class GedcomDateParser(DateParser):
#-------------------------------------------------------------------------
class Lexer(object):
def __init__(self, ifile):
def __init__(self, ifile, __add_msg):
self.ifile = ifile
self.current_list = []
self.eof = False
@@ -700,6 +704,7 @@ class Lexer(object):
TOKEN_CONT : self.__fix_token_cont,
TOKEN_CONC : self.__fix_token_conc,
}
self.__add_msg = __add_msg
def readline(self):
if len(self.current_list) <= 1 and not self.eof:
@@ -738,6 +743,7 @@ class Lexer(object):
self.eof = True
return
original_line = line
try:
# According to the GEDCOM 5.5 standard,
# Chapter 1 subsection Grammar
@@ -771,6 +777,13 @@ class Lexer(object):
tag = line[0]
line_value = line[2]
except:
problem = _("Line ignored ")
text = original_line.rstrip('\n\r')
prob_width = 66
problem = problem.ljust(prob_width)[0:(prob_width-1)]
text = text.replace("\n", "\n".ljust(prob_width + 22))
message = "%s %s" % (problem, text)
self.__add_msg(message)
continue
token = TOKENS.get(tag, TOKEN_UNKNOWN)
@@ -780,6 +793,10 @@ class Lexer(object):
if func:
func(data)
else:
# There will normally only be one space between tag and
# line_value, but in case there is more then one, remove extra
# spaces after CONC/CONT processing
data = data[:2] + (data[2].strip(),) + data[3:]
self.current_list.insert(0, data)
def clean_up(self):
@@ -1234,27 +1251,29 @@ class GedInfoParser(object):
#
#-------------------------------------------------------------------------
class BaseReader(object):
def __init__(self, ifile, encoding):
def __init__(self, ifile, encoding, __add_msg):
self.ifile = ifile
self.enc = encoding
self.__add_msg = __add_msg
def reset(self):
self.ifile.seek(0)
def readline(self):
if sys.version_info[0] < 3:
line = unicode(self.ifile.readline(),
encoding=self.enc,
errors='replace')
else:
line = self.ifile.readline()
line = line.decode(self.enc, errors='replace')
return line.translate(STRIP_DICT)
raise NotImplemented
def report_error(self, problem, line):
line = line.rstrip('\n\r')
prob_width = 66
problem = problem.ljust(prob_width)[0:(prob_width-1)]
text = line.replace("\n", "\n".ljust(prob_width + 22))
message = "%s %s" % (problem, text)
self.__add_msg(message)
class UTF8Reader(BaseReader):
def __init__(self, ifile):
BaseReader.__init__(self, ifile, 'utf8')
def __init__(self, ifile, __add_msg):
BaseReader.__init__(self, ifile, 'utf8', __add_msg)
self.reset()
def reset(self):
@@ -1275,23 +1294,61 @@ class UTF8Reader(BaseReader):
class UTF16Reader(BaseReader):
def __init__(self, ifile):
def __init__(self, ifile, __add_msg):
new_file = codecs.EncodedFile(ifile, 'utf8', 'utf16')
BaseReader.__init__(self, new_file, 'utf16')
BaseReader.__init__(self, new_file, '', __add_msg)
self.reset()
def readline(self):
l = self.ifile.readline()
if l.strip():
return l
line = self.ifile.readline()
if sys.version_info[0] < 3:
line = unicode(line,
encoding='utf8',
errors='replace')
if line.strip():
return line.translate(STRIP_DICT)
else:
line = self.ifile.readline()
line = unicode(line,
encoding='utf8',
errors='replace')
return line.translate(STRIP_DICT)
else:
return self.ifile.readline()
line = line.decode('utf8', errors='replace')
return line.translate(STRIP_DICT)
class AnsiReader(BaseReader):
def __init__(self, ifile):
BaseReader.__init__(self, ifile, 'latin1')
def __init__(self, ifile, __add_msg):
BaseReader.__init__(self, ifile, 'latin1', __add_msg)
def readline(self):
line = self.ifile.readline()
if sys.version_info[0] < 3:
line = unicode(line,
encoding=self.enc,
errors='replace')
else:
line = line.decode(self.enc, errors='replace')
if line.translate(DEL_AND_C1) != line:
self.report_error("DEL or C1 control chars in line did you mean CHAR cp1252??", line)
return line.translate(STRIP_DICT)
class CP1252Reader(BaseReader):
def __init__(self, ifile, __add_msg):
BaseReader.__init__(self, ifile, 'cp1252', __add_msg)
def readline(self):
line = self.ifile.readline()
if sys.version_info[0] < 3:
line = unicode(line,
encoding=self.enc,
errors='replace')
else:
line = line.decode(self.enc, errors='replace')
return line.translate(STRIP_DICT)
class AnselReader(BaseReader):
"""
ANSEL to Unicode Conversion
@@ -1311,7 +1368,8 @@ class AnselReader(BaseReader):
TODO: should we allow TAB, as a Gramps extension?
"""
__printable_ascii = list(map(chr, list(range(32, 127)))) # note: up thru 126
__use_ASCII = list(map(chr, [10, 27, 29 , 30, 31])) + __printable_ascii
# LF CR Esc GS RS US
__use_ASCII = list(map(chr, [10, 13, 27, 29 , 30, 31])) + __printable_ascii
# mappings of single byte ANSEL codes to unicode
__onebyte = {
@@ -1324,9 +1382,11 @@ class AnselReader(BaseReader):
b'\xB4' : '\u00fe', b'\xB5' : '\u00e6', b'\xB6' : '\u0153',
b'\xB7' : '\u02ba', b'\xB8' : '\u0131', b'\xB9' : '\u00a3',
b'\xBA' : '\u00f0', b'\xBC' : '\u01a1', b'\xBD' : '\u01b0',
b'\xBE' : '\u25a1', b'\xBF' : '\u25a0',
b'\xC0' : '\u00b0', b'\xC1' : '\u2113', b'\xC2' : '\u2117',
b'\xC3' : '\u00a9', b'\xC4' : '\u266f', b'\xC5' : '\u00bf',
b'\xC6' : '\u00a1', b'\xC7' : '\u00df', b'\xC8' : '\u20ac',
b'\xCD' : '\u0065', b'\xCE' : '\u006f', b'\xCF' : '\u00df',
}
# combining forms (in ANSEL, they precede the modified ASCII character
@@ -1347,6 +1407,7 @@ class AnselReader(BaseReader):
b'\xF3' : '\u0324', b'\xF4' : '\u0325', b'\xF5' : '\u0333',
b'\xF6' : '\u0332', b'\xF7' : '\u0326', b'\xF8' : '\u031c',
b'\xF9' : '\u032e', b'\xFA' : '\ufe22', b'\xFB' : '\ufe23',
b'\xFC' : '\u0338',
b'\xFE' : '\u0313',
}
@@ -1504,52 +1565,94 @@ class AnselReader(BaseReader):
b'\xF9\x48' : '\u1e2a', b'\xF9\x68' : '\u1e2b',
}
@staticmethod
def __ansel_to_unicode(s):
def __ansel_to_unicode(self, s):
""" Convert an ANSEL encoded string to unicode """
buff = StringIO()
while s:
if ord(s[0]) < 128:
if s[0] in AnselReader.__use_ASCII:
head = s[0]
else:
# substitute space for disallowed (control) chars
head = ' '
s = s[1:]
else:
if s[0:2] in AnselReader.__twobyte:
head = AnselReader.__twobyte[s[0:2]]
s = s[2:]
elif s[0] in AnselReader.__onebyte:
head = AnselReader.__onebyte[s[0]]
s = s[1:]
elif s[0] in AnselReader.__acombiners:
c = AnselReader.__acombiners[s[0]]
# always consume the combiner
s = s[1:]
next = s[0]
if next in AnselReader.__printable_ascii:
# consume next as well
s = s[1:]
# unicode: combiner follows base-char
head = next + c
else:
# just drop the unexpected combiner
continue
else:
head = '\ufffd' # "Replacement Char"
s = s[1:]
buff.write(head.encode("utf-8"))
error = ""
if sys.version_info[0] < 3:
while s:
if ord(s[0]) < 128:
if s[0] in AnselReader.__use_ASCII:
head = s[0]
else:
# substitute space for disallowed (control) chars
error += " (%#X)" % ord(s[0])
head = ' '
s = s[1:]
else:
if s[0:2] in AnselReader.__twobyte:
head = AnselReader.__twobyte[s[0:2]]
s = s[2:]
elif s[0] in AnselReader.__onebyte:
head = AnselReader.__onebyte[s[0]]
s = s[1:]
elif s[0] in AnselReader.__acombiners:
c = AnselReader.__acombiners[s[0]]
# always consume the combiner
s = s[1:]
next = s[0]
if next in AnselReader.__printable_ascii:
# consume next as well
s = s[1:]
# unicode: combiner follows base-char
head = next + c
else:
# just drop the unexpected combiner
error += " (%#X)" % ord(s[0])
continue
else:
error += " (%#X)" % ord(s[0])
head = '\ufffd' # "Replacement Char"
s = s[1:]
buff.write(head.encode("utf-8"))
ans = unicode(buff.getvalue(), "utf-8")
else:
ans = buff.getvalue().decode("utf-8")
while s:
if s[0] < 128:
if chr(s[0]) in AnselReader.__use_ASCII:
head = chr(s[0])
else:
# substitute space for disallowed (control) chars
error += " (%#X)" % s[0]
head = ' '
s = s[1:]
else:
if s[0:2] in AnselReader.__twobyte:
head = AnselReader.__twobyte[s[0:2]]
s = s[2:]
elif bytes([s[0]]) in AnselReader.__onebyte:
head = AnselReader.__onebyte[bytes([s[0]])]
s = s[1:]
elif bytes([s[0]]) in AnselReader.__acombiners:
c = AnselReader.__acombiners[bytes([s[0]])]
# always consume the combiner
s = s[1:]
next_byte = s[0]
if next_byte < 128 and chr(next_byte) in AnselReader.__printable_ascii:
# consume next as well
s = s[1:]
# unicode: combiner follows base-char
head = chr(next_byte) + c
else:
# just drop the unexpected combiner
error += " (%#X)" % s[0]
continue
else:
error += " (%#X)" % s[0]
head = '\ufffd' # "Replacement Char"
s = s[1:]
buff.write(head)
ans = buff.getvalue()
if error:
# e.g. Illegal character (oxAB) (0xCB)... 1 NOTE xyz?pqr?lmn
self.report_error(_("Illegal character%s") % error, ans)
buff.close()
return ans
def __init__(self, ifile):
BaseReader.__init__(self, ifile, "")
def __init__(self, ifile, __add_msg):
BaseReader.__init__(self, ifile, "", __add_msg)
def readline(self):
return self.__ansel_to_unicode(self.ifile.readline())
@@ -1807,6 +1910,7 @@ class GedcomParser(UpdateCallback):
__TRUNC_MSG = _("Your GEDCOM file is corrupted. "
"It appears to have been truncated.")
_EMPTY_LOC = Location().serialize()
SyntaxError = "Syntax Error"
BadFile = "Not a GEDCOM file"
@@ -1900,6 +2004,7 @@ class GedcomParser(UpdateCallback):
self.default_tag = None
self.dir_path = os.path.dirname(filename)
self.is_ftw = False
self.addr_is_detail = False
self.groups = None
self.want_parse_warnings = True
@@ -2298,12 +2403,12 @@ class GedcomParser(UpdateCallback):
TOKEN_CTRY : self.__location_ctry,
# Not legal GEDCOM - not clear why these are included at this level
TOKEN_ADDR : self.__ignore,
TOKEN_DATE : self.__location_date,
TOKEN_DATE : self.__ignore, # there is nowhere to put a date
TOKEN_NOTE : self.__location_note,
TOKEN_RNOTE : self.__location_note,
TOKEN__LOC : self.__ignore,
TOKEN__NAME : self.__ignore,
TOKEN_PHON : self.__ignore,
TOKEN_PHON : self.__location_phone,
TOKEN_IGNORE : self.__ignore,
}
self.func_list.append(self.parse_loc_tbl)
@@ -2638,27 +2743,29 @@ class GedcomParser(UpdateCallback):
self.func_list.append(self.note_parse_tbl)
# look for existing place titles, build a map
self.place_names = {}
self.place_names = defaultdict(list)
cursor = dbase.get_place_cursor()
data = next(cursor)
while data:
(handle, val) = data
self.place_names[val[2]] = handle
self.place_names[val[2]].append(handle)
data = next(cursor)
cursor.close()
enc = stage_one.get_encoding()
if enc == "ANSEL":
rdr = AnselReader(ifile)
rdr = AnselReader(ifile, self.__add_msg)
elif enc in ("UTF-8", "UTF8"):
rdr = UTF8Reader(ifile)
elif enc in ("UTF-16", "UTF16", "UNICODE"):
rdr = UTF16Reader(ifile)
rdr = UTF8Reader(ifile, self.__add_msg)
elif enc in ("UTF-16LE", "UTF-16BE", "UTF16", "UNICODE"):
rdr = UTF16Reader(ifile, self.__add_msg)
elif enc in ("CP1252", "WINDOWS-1252"):
rdr = CP1252Reader(ifile, self.__add_msg)
else:
rdr = AnsiReader(ifile)
rdr = AnsiReader(ifile, self.__add_msg)
self.lexer = Lexer(rdr)
self.lexer = Lexer(rdr, self.__add_msg)
self.filename = filename
self.backoff = False
@@ -2716,7 +2823,12 @@ class GedcomParser(UpdateCallback):
else:
message = _("GEDCOM import report: %s errors detected") % \
self.number_of_errors
self.user.info(message, "".join(self.errors), monospaced=True)
if hasattr(self.user.uistate, 'window'):
parent_window = self.user.uistate.window
else:
parent_window = None
self.user.info(message, "".join(self.errors),
parent = parent_window, monospaced=True)
def __clean_up(self):
"""
@@ -2869,41 +2981,73 @@ class GedcomParser(UpdateCallback):
self.dbase.add_note(note, self.trans)
return note
def __find_or_create_place(self, title):
def __loc_is_empty(self, location):
"""
Finds or creates a place based on the GRAMPS ID. If the ID is
already used (is in the db), we return the item in the db. Otherwise,
we create a new place, assign the handle and GRAMPS ID.
"""
place = Place()
# check to see if we've encountered this name before
# if we haven't we need to get a new GRAMPS ID
Determines whether a location is empty.
intid = self.place_names.get(title)
if intid is None:
intid = self.lid2id.get(title)
if intid is None:
new_id = self.dbase.find_next_place_gramps_id()
@param location: The current location
@type location: gen.lib.Location
@return True of False
"""
if location is None:
return True
elif location.serialize() == self._EMPTY_LOC:
return True
elif location.is_empty():
return True
return False
def __find_place(self, title, location, placeref_list):
"""
Finds an existing place based on the title and primary location.
@param title: The place title
@type title: string
@param location: The current location
@type location: gen.lib.Location
@return gen.lib.Place
"""
for place_handle in self.place_names[title]:
place = self.dbase.get_place_from_handle(place_handle)
if place.get_title() == title:
if self.__loc_is_empty(location) and \
self.__loc_is_empty(self.__get_first_loc(place)) and \
place.get_placeref_list() == placeref_list:
return place
elif (not self.__loc_is_empty(location) and \
not self.__loc_is_empty(self.__get_first_loc(place)) and
self.__get_first_loc(place).is_equivalent(location) == IDENTICAL) and \
place.get_placeref_list() == placeref_list:
return place
return None
def __add_place(self, event, sub_state):
"""
Add a new place to an event if not already present, or update a
place.
@param event: The event
@type event: gen.lib.Event
@param substate: The sub-state for PLAC or ADDR elements (i.e. parsed by
event_parse_tbl)
@type sub_state: CurrentState
"""
if sub_state.place:
# see whether this place already exists
place = self.__find_place(sub_state.place.get_title(),
self.__get_first_loc(sub_state.place),
sub_state.place.get_placeref_list())
if place is None:
place = sub_state.place
self.dbase.add_place(place, self.trans)
self.place_names[place.get_title()].append(place.get_handle())
event.set_place_handle(place.get_handle())
else:
new_id = None
else:
new_id = None
# check to see if the name already existed in the database
# if it does, create a new name by appending the GRAMPS ID.
# generate a GRAMPS ID if needed
if self.dbase.has_place_handle(intid):
place.unserialize(self.dbase.get_raw_place_data(intid))
else:
intid = create_id()
place.set_handle(intid)
place.set_title(title)
place.set_gramps_id(new_id)
self.dbase.add_place(place, self.trans)
self.lid2id[title] = intid
return place
place.merge(sub_state.place)
self.dbase.commit_place(place, self.trans)
event.set_place_handle(place.get_handle())
place_title = place_displayer.display(self.dbase, place)
sub_state.pf.load_place(self.place_import, place, place_title)
def __find_file(self, fullname, altpath):
tries = []
@@ -3321,7 +3465,10 @@ class GedcomParser(UpdateCallback):
if line.token_text == self.subm and self.import_researcher:
self.dbase.set_researcher(state.res)
submitter_name = _("SUBM (Submitter): @%s@") % line.token_text
if state.res.get_name() == "":
submitter_name = _("SUBM (Submitter): @%s@") % line.token_text
else:
submitter_name = _("SUBM (Submitter): (@%s@) %s") % (line.token_text, state.res.get_name())
if self.use_def_src:
repo.set_name(submitter_name)
repo.set_handle(create_id())
@@ -3811,10 +3958,13 @@ class GedcomParser(UpdateCallback):
sub_state.level = state.level+1
sub_state.event = event
sub_state.event_ref = event_ref
sub_state.pf = self.place_parser
self.__parse_level(sub_state, self.event_parse_tbl, self.__undefined)
state.msg += sub_state.msg
self.__add_place(event, sub_state)
self.dbase.commit_event(event, self.trans)
event_ref.ref = event.handle
state.person.add_event_ref(event_ref)
@@ -4016,10 +4166,13 @@ class GedcomParser(UpdateCallback):
sub_state.level = state.level+1
sub_state.event = event
sub_state.event_ref = event_ref
sub_state.pf = self.place_parser
self.__parse_level(sub_state, self.event_parse_tbl, self.__undefined)
state.msg += sub_state.msg
self.__add_place(event, sub_state)
self.dbase.add_event(event, self.trans)
event_ref.ref = event.handle
state.person.add_event_ref(event_ref)
@@ -4466,9 +4619,16 @@ class GedcomParser(UpdateCallback):
@type state: CurrentState
"""
try:
state.place = self.__find_or_create_place(line.data)
state.place.set_title(line.data)
state.lds_ord.set_place_handle(state.place.handle)
title = line.data
place = self.__find_place(title, None, None)
if place is None:
place = Place()
place.set_title(title)
self.dbase.add_place(place, self.trans)
self.place_names[place.get_title()].append(place.get_handle())
else:
pass
state.lds_ord.set_place_handle(place.handle)
except NameError:
return
@@ -4832,10 +4992,13 @@ class GedcomParser(UpdateCallback):
sub_state.level = state.level+1
sub_state.event = event
sub_state.event_ref = event_ref
sub_state.pf = self.place_parser
self.__parse_level(sub_state, self.event_parse_tbl, self.__undefined)
state.msg += sub_state.msg
self.__add_place(event, sub_state)
if event.type == EventType.MARRIAGE:
descr = event.get_description()
if descr == "Civil Union":
@@ -4875,9 +5038,12 @@ class GedcomParser(UpdateCallback):
sub_state.level = state.level+1
sub_state.event = event
sub_state.event_ref = event_ref
sub_state.pf = self.place_parser
self.__parse_level(sub_state, self.event_parse_tbl, self.__undefined)
state.msg += sub_state.msg
self.__add_place(event, sub_state)
self.dbase.commit_event(event, self.trans)
event_ref.ref = event.handle
@@ -5157,7 +5323,7 @@ class GedcomParser(UpdateCallback):
# +1 SOUR @<XREF:SOUR>@ {0:M}
if not line.data:
self.__add_msg(_("Empty note ignored"), line, state)
self.__skip_subordinate_levels(level+1, state)
self.__skip_subordinate_levels(state.level+1, state)
else:
new_note = Note(line.data)
new_note.set_gramps_id(self.nid_map[""])
@@ -5305,32 +5471,31 @@ class GedcomParser(UpdateCallback):
if self.is_ftw and state.event.type in FTW_BAD_PLACE:
state.event.set_description(line.data)
else:
# It is possible that we have already got an address structure
# associated with this event. In that case, we will remember the
# location to re-insert later, and set the place as the place name
# and primary location
place_handle = state.event.get_place_handle()
if place_handle:
place = self.dbase.get_place_from_handle(place_handle)
title = line.data
place = state.place
if place:
# We encounter a PLAC, having previously encountered an ADDR
if place.get_title() and place.get_title() != "":
# We have previously found a PLAC
self.__add_msg(_("A second PLAC ignored"), line, state)
# ignore this second PLAC, and use the old one
else:
# This is the first PLAC
place.set_title(line.data)
else:
place = self.__find_or_create_place(line.data)
place.set_title(line.data)
state.event.set_place_handle(place.handle)
# The first thing we encounter is PLAC
state.place = Place()
place = state.place
place.set_title(line.data)
sub_state = CurrentState()
sub_state.place = place
sub_state.level = state.level+1
sub_state.pf = PlaceParser()
self.__parse_level(sub_state, self.event_place_map,
self.__undefined)
state.msg += sub_state.msg
place_title = place_displayer.display(self.dbase, place)
sub_state.pf.load_place(self.place_import, place, place_title)
self.dbase.commit_place(place, self.trans)
def __event_place_note(self, line, state):
"""
@param line: The current line in GedLine format
@@ -5430,8 +5595,8 @@ class GedcomParser(UpdateCallback):
sub_state = CurrentState(level=state.level+1)
sub_state.location = Location()
sub_state.note = []
sub_state.event = state.event
sub_state.place = Place() # temp stash for notes, citations etc
self.__parse_level(sub_state, self.parse_loc_tbl, self.__undefined)
state.msg += sub_state.msg
@@ -5439,22 +5604,53 @@ class GedcomParser(UpdateCallback):
self.__merge_address(free_form, sub_state.location, line, state)
location = sub_state.location
note_list = sub_state.note
place_handle = state.event.get_place_handle()
if place_handle:
place = self.dbase.get_place_from_handle(place_handle)
if self.addr_is_detail and state.place:
# Commit the enclosing place
place = self.__find_place(state.place.get_title(), None,
state.place.get_placeref_list())
if place is None:
place = state.place
self.dbase.add_place(place, self.trans)
self.place_names[place.get_title()].append(place.get_handle())
else:
place.merge(state.place)
self.dbase.commit_place(place, self.trans)
place_title = place_displayer.display(self.dbase, place)
state.pf.load_place(self.place_import, place, place_title)
# Create the Place Details (it is committed with the event)
place_detail = Place()
place_detail.set_name(location.get_street())
place_detail.set_title(location.get_street())
# For RootsMagic etc. Place Details e.g. address, hospital, cemetary
place_detail.set_type((PlaceType.CUSTOM, _("Detail")))
placeref = PlaceRef()
placeref.ref = place.get_handle()
place_detail.set_placeref_list([placeref])
state.place = place_detail
else:
place = self.__find_or_create_place(line.data)
place.set_title(line.data)
place_handle = place.handle
place = state.place
if place:
# We encounter an ADDR having previously encountered a PLAC
if len(place.get_alternate_locations()) != 0 and \
not self.__get_first_loc(place).is_empty():
# We have perviously found an ADDR, or have populated location
# from PLAC title
self.__add_msg(_("Location already populated; ADDR ignored"),
line, state)
# ignore this second ADDR, and use the old one
else:
# This is the first ADDR
place.add_alternate_locations(location)
else:
# The first thing we encounter is ADDR
state.place = Place()
place = state.place
place.add_alternate_locations(location)
self.__add_location(place, location)
list(map(place.add_note, note_list))
state.event.set_place_handle(place_handle)
self.dbase.commit_place(place, self.trans)
# merge notes etc into place
place.merge(sub_state.place)
def __add_location(self, place, location):
"""
@@ -5468,6 +5664,18 @@ class GedcomParser(UpdateCallback):
return
place.add_alternate_locations(location)
def __get_first_loc(self, place):
"""
@param place: A place object
@type place: Place
@return location: the first alternate location if any else None
@type location: gen.lib.location
"""
if len(place.get_alternate_locations()) == 0:
return None
else:
return place.get_alternate_locations()[0]
def __event_phon(self, line, state):
"""
@param line: The current line in GedLine format
@@ -5475,12 +5683,10 @@ class GedcomParser(UpdateCallback):
@param state: The current state
@type state: CurrentState
"""
place_handle = state.event.get_place_handle()
if place_handle:
place = self.dbase.get_place_from_handle(place_handle)
place = state.place
if place:
codes = [place.get_code(), line.data]
place.set_code(' '.join(code for code in codes if code))
self.dbase.commit_place(place, self.trans)
def __event_privacy(self, line, state):
"""
@@ -5626,7 +5832,7 @@ class GedcomParser(UpdateCallback):
"""
while True:
line = self.__get_next_line()
if self.__level_is_finished(line, state.level):
if self.__level_is_finished(line, state.level+1):
break
elif line.token == TOKEN_AGE:
attr = Attribute()
@@ -5647,7 +5853,7 @@ class GedcomParser(UpdateCallback):
"""
while True:
line = self.__get_next_line()
if self.__level_is_finished(line, state.level):
if self.__level_is_finished(line, state.level+1):
break
elif line.token == TOKEN_AGE:
attr = Attribute()
@@ -6635,17 +6841,6 @@ class GedcomParser(UpdateCallback):
url.set_type(UrlType(UrlType.EMAIL))
state.repo.add_url(url)
def __location_date(self, line, state):
"""
@param line: The current line in GedLine format
@type line: GedLine
@param state: The current state
@type state: CurrentState
"""
if not state.location:
state.location = Location()
state.location.set_date_object(line.data)
def __location_adr1(self, line, state):
"""
@param line: The current line in GedLine format
@@ -6714,7 +6909,7 @@ class GedcomParser(UpdateCallback):
state.location = Location()
state.location.set_country(line.data)
def __location_note(self, line, state):
def __location_phone(self, line, state):
"""
@param line: The current line in GedLine format
@type line: GedLine
@@ -6723,9 +6918,19 @@ class GedcomParser(UpdateCallback):
"""
if not state.location:
state.location = Location()
state.location.set_phone(line.data)
def __location_note(self, line, state):
"""
@param line: The current line in GedLine format
@type line: GedLine
@param state: The current state
@type state: CurrentState
"""
if state.event:
self.__parse_note(line, state.event, state.level+1, state)
self.__parse_note(line, state.place, state.level, state)
else:
# This causes notes below SUBMitter to be ignored
self.__not_recognized(line, state.level, state)
def __optional_note(self, line, state):
@@ -6793,6 +6998,11 @@ class GedcomParser(UpdateCallback):
self.gedsource = self.gedmap.get_from_source_tag(line.data)
if line.data.strip() in ["FTW", "FTM"]:
self.is_ftw = True
# Some software (e.g. RootsMagic (http://files.rootsmagic.com/PAF-
# Book/RootsMagic-for-PAF-Users-Printable.pdf) use the Addr fields for
# 'Place Details (address, hospital, cemetary)'
if line.data.strip().lower() in ['rootsmagic']:
self.addr_is_detail = True
# We will use the approved system ID as the name of the generating
# software, in case we do not get the name in the proper place
self.genby = line.data
@@ -7063,8 +7273,13 @@ class GedcomParser(UpdateCallback):
sattr.set_value(line.data)
self.def_src.add_attribute(sattr)
elif line.token == TOKEN_FORM:
if line.data != "LINEAGE-LINKED":
self.__add_msg(_("GEDCOM form not supported"), line, state)
if line.data == "LINEAGE-LINKED":
pass
elif line.data.upper() == "LINEAGE-LINKED":
# Allow Lineage-Linked etc. though it should be in uppercase
self.__add_msg(_("GEDCOM FORM should be in uppercase"), line, state)
else:
self.__add_msg(_("GEDCOM FORM not supported"), line, state)
if self.use_def_src:
sattr = SrcAttribute()
sattr.set_type(_('GEDCOM form'))
@@ -7284,6 +7499,7 @@ class GedcomParser(UpdateCallback):
sattr.set_type(msg)
sattr.set_value(line.data)
self.def_src.add_attribute(sattr)
self.dbase.commit_source(self.def_src, self.trans)
def handle_source(self, line, level, state):
"""
@@ -7438,9 +7654,13 @@ class GedcomParser(UpdateCallback):
sub_state.event_ref = event_ref
sub_state.event = event
sub_state.person = state.person
sub_state.pf = self.place_parser
self.__parse_level(sub_state, event_map, self.__undefined)
state.msg += sub_state.msg
self.__add_place(event, sub_state)
self.dbase.commit_event(event, self.trans)
event_ref.set_reference_handle(event.handle)
@@ -7462,10 +7682,13 @@ class GedcomParser(UpdateCallback):
sub_state.level = state.level+1
sub_state.event = event
sub_state.event_ref = event_ref
sub_state.pf = self.place_parser
self.__parse_level(sub_state, event_map, self.__undefined)
state.msg += sub_state.msg
self.__add_place(event, sub_state)
self.dbase.commit_event(event, self.trans)
event_ref.set_reference_handle(event.handle)
return event_ref
@@ -7609,7 +7832,7 @@ class GedcomStageOne(object):
input_file.read(1)
self.enc = "UTF8"
return input_file
elif line == b"\xff\xfe":
elif line == b"\xff\xfe" or line == b"\xfe\xff":
self.enc = "UTF16"
input_file.seek(0)
return codecs.EncodedFile(input_file, 'utf8', 'utf16')
@@ -7630,25 +7853,33 @@ class GedcomStageOne(object):
reader = self.__detect_file_decoder(self.ifile)
for line in reader:
# Treat the file as though it is UTF-8 since this will be right if a
# BOM was detected; it is the more modern option; and anyway it
# doesn't really matter as we are only trying to detect a CHAR line
# which is only 7-bit ASCII anyway, and we ignore anything that
# can't be translated.
if sys.version_info[0] < 3:
line = unicode(line, encoding='utf-8', errors='replace')
else:
line = line.decode(encoding='utf-8', errors='replace')
line = line.strip()
if not line:
continue
self.lcnt += 1
data = line.split(None, 2) + ['']
try:
data = line.split(None, 2) + ['']
(level, key, value) = data[:3]
level = int(level)
key = conv_to_unicode(key.strip())
value = conv_to_unicode(value.strip())
key = key.strip()
value = value.strip()
except:
LOG.warn(_("Invalid line %d in GEDCOM file.") % self.lcnt)
continue
if level == 0 and key[0] == '@':
if value == ("FAM", "FAMILY") :
if value in ("FAM", "FAMILY") :
current_family_id = key.strip()[1:-1]
elif value == ("INDI", "INDIVIDUAL"):
elif value in ("INDI", "INDIVIDUAL"):
self.pcnt += 1
elif key in ("HUSB", "HUSBAND", "WIFE") and \
self.__is_xref_value(value):
@@ -7658,6 +7889,9 @@ class GedcomStageOne(object):
elif key == 'CHAR' and not self.enc:
assert(isinstance(value, STRTYPE))
self.enc = value
LOG.debug("parse pcnt %d" % self.pcnt)
LOG.debug("parse famc %s" % dict(self.famc))
LOG.debug("parse fams %s" % dict(self.fams))
def get_famc_map(self):
"""
+9
View File
@@ -51,6 +51,15 @@ class PlaceImport(object):
self.loc2handle[location] = handle
self.handle2loc[handle] = location
def remove_location(self, handle):
"""
Remove the location of a place already in the database.
"""
if handle in self.handle2loc:
loc = self.handle2loc[handle]
del(self.loc2handle[loc])
del(self.handle2loc[handle])
def generate_hierarchy(self, trans):
"""
Generate missing places in the place hierarchy.
+14 -4
View File
@@ -181,7 +181,19 @@ class GeoGraphyView(OsmGps, NavigationView):
self.geo_othermap[ident] = cairo.ImageSurface.create_from_png(fh)
#self.geo_othermap[ident] = cairo.ImageSurface.create_from_png(path)
def add_bookmark(self, menu, handle):
def add_bookmark(self, menu):
mlist = self.selected_handles()
if mlist:
self.bookmarks.add(mlist[0])
else:
from gramps.gui.dialog import WarningDialog
WarningDialog(
_("Could Not Set a Bookmark"),
_("A bookmark could not be set because "
"no one was selected."))
def add_bookmark_from_popup(self, menu, handle):
if handle:
self.uistate.set_active(handle, self.navigation_type())
self.bookmarks.add(handle)
@@ -380,9 +392,7 @@ class GeoGraphyView(OsmGps, NavigationView):
clearmap.show()
menu.append(clearmap)
menu.show()
menu.popup(None, None,
lambda menu, data: (event.get_root_coords()[0],
event.get_root_coords()[1], True),
menu.popup(None, None, None,
None, event.button, event.time)
return 1
+3 -3
View File
@@ -41,7 +41,7 @@ from gramps.gen.lib import PlaceType
class OpensStreetMapService(MapService):
"""Map service using http://openstreetmap.org
Resource: http://wiki.openstreetmap.org/index.php/Name_finder
Resource: http://wiki.openstreetmap.org/wiki/Nominatim
"""
def __init__(self):
MapService.__init__(self)
@@ -64,10 +64,10 @@ class OpensStreetMapService(MapService):
city = location.get(PlaceType.CITY)
country = location.get(PlaceType.COUNTRY)
if city and country:
self.url = "http://open.mapquestapi.com/nominatim/v1/"\
self.url = "http://nominatim.openstreetmap.org/"\
"search.php?q=%s%%2C%s" % (city, country)
return
titledescr = place_displayer.display(self.database, place)
self.url = "http://open.mapquestapi.com/nominatim/v1/"\
self.url = "http://nominatim.openstreetmap.org/"\
"search.php?q=%s" % '+'.join(titledescr.split())
+4 -2
View File
@@ -25,6 +25,8 @@
Display a people who have a person's same surname or given name.
"""
from __future__ import unicode_literals
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
ngettext = glocale.translation.ngettext # else "nearby" comments are ignored
@@ -68,9 +70,9 @@ class SameGiven(Rule):
src = self.list[0].upper()
for name in [person.get_primary_name()] + person.get_alternate_names():
if name.first_name:
anyNBSP = name.first_name.split(u'\u00A0')
anyNBSP = name.first_name.split('\u00A0')
if len(anyNBSP) > 1: # there was an NBSP, a non-breaking space
first_two = anyNBSP[0] + u'\u00A0' + anyNBSP[1].split()[0]
first_two = anyNBSP[0] + '\u00A0' + anyNBSP[1].split()[0]
if first_two.upper() == src:
return True
else:
+4 -4
View File
@@ -828,9 +828,9 @@ class RelationshipCalculator(gramps.gen.relationship.RelationshipCalculator):
"""
rel_str = "parents llunyans"
#atgen = u" de la %sena generació"
#bygen = u" per la %sena generació"
#cmt = u" (germans o germanes d'un avantpassat" + atgen % Ga + ")"
#atgen = " de la %sena generació"
#bygen = " per la %sena generació"
#cmt = " (germans o germanes d'un avantpassat" + atgen % Ga + ")"
if in_law_a or in_law_b:
inlaw = self.INLAW
@@ -920,7 +920,7 @@ class RelationshipCalculator(gramps.gen.relationship.RelationshipCalculator):
inlaw = ""
rel_str = "un parent llunyà%s" % inlaw
#bygen = u" per la %sena generació"
#bygen = " per la %sena generació"
if Ga == 0:
# b is descendant of a
+4 -4
View File
@@ -333,7 +333,7 @@ def get_child_unknown(level, inlaw=""):
else:
return "un descendant lointain%s" % inlaw
def get_sibling_unknown(inlaw=""):
def get_sibling_unknown(Ga, inlaw=""):
"""
sibling of an ancestor, gender = unknown
"""
@@ -653,7 +653,7 @@ class RelationshipCalculator(gramps.gen.relationship.RelationshipCalculator):
elif gender_b == Person.FEMALE:
rel_str = "la tante lointaine" + bygen % (Ga + 1)
elif gender_b == Person.UNKNOWN:
rel_str = get_sibling_unknown(inlaw)
rel_str = get_sibling_unknown(Ga, inlaw)
else:
return rel_str
elif Ga == 1:
@@ -672,7 +672,7 @@ class RelationshipCalculator(gramps.gen.relationship.RelationshipCalculator):
rel_str = "la nièce lointaine%s (%dème génération)" % \
(inlaw, Gb)
elif gender_b == Person.UNKNOWN:
rel_str = get_sibling_unknown(inlaw)
rel_str = get_sibling_unknown(Ga, inlaw)
else:
return rel_str
elif Ga == Gb:
@@ -684,7 +684,7 @@ class RelationshipCalculator(gramps.gen.relationship.RelationshipCalculator):
elif gender_b == Person.FEMALE:
rel_str = get_cousine(Ga - 1, 0, inlaw=inlaw)
elif gender_b == Person.UNKNOWN:
rel_str = get_sibling_unknown(inlaw)
rel_str = get_sibling_unknown(Ga, inlaw)
else:
return rel_str
elif Ga > 1 and Ga > Gb:
+9 -1
View File
@@ -205,10 +205,18 @@ class DropdownSidebar(BaseSidebar):
self.viewmanager.notebook.set_current_page(page_no)
self.__handlers_unblock()
def cb_menu_position(menu, button):
def cb_menu_position(*args):
"""
Determine the position of the popup menu.
"""
# takes two argument: menu, button
if len(args) == 2:
menu = args[0]
button = args[1]
# broken introspection can't handle MenuPositionFunc annotations corectly
else:
menu = args[0]
button = args[3]
ret_val, x_pos, y_pos = button.get_window().get_origin()
x_pos += button.get_allocation().x
y_pos += button.get_allocation().y + button.get_allocation().height
+9 -1
View File
@@ -218,10 +218,18 @@ class ExpanderSidebar(BaseSidebar):
self.viewmanager.notebook.set_current_page(page_no)
self.__handlers_unblock()
def cb_menu_position(menu, button):
def cb_menu_position(*args):
"""
Determine the position of the popup menu.
"""
# takes two argument: menu, button
if len(args) == 2:
menu = args[0]
button = args[1]
# broken introspection can't handle MenuPositionFunc annotations corectly
else:
menu = args[0]
button = args[3]
ret_val, x_pos, y_pos = button.get_window().get_origin()
x_pos += button.get_allocation().x
y_pos += button.get_allocation().y + button.get_allocation().height
+2
View File
@@ -3,7 +3,9 @@
<interface>
<requires lib="gtk+" version="3.0"/>
<object class="GtkDialog" id="check">
<!-- This dialog is ManagedWindow class
<property name="visible">True</property>
-->
<property name="can_focus">False</property>
<property name="default_width">450</property>
<property name="default_height">400</property>
+22 -9
View File
@@ -83,7 +83,7 @@ from gramps.gen.constfunc import UNITYPE, cuni, handle2internal, conv_to_unicode
strip_dict = dict.fromkeys(list(range(9))+list(range(11,13))+list(range(14, 32)), " ")
class ProgressMeter(object):
def __init__(self, *args): pass
def __init__(self, *args, **kwargs): pass
def set_pass(self, *args): pass
def step(self): pass
def close(self): pass
@@ -93,7 +93,7 @@ class ProgressMeter(object):
# Low Level repair
#
#-------------------------------------------------------------------------
def cross_table_duplicates(db):
def cross_table_duplicates(db, uistate):
"""
Function to find the presence of identical handles that occur in different
database tables.
@@ -105,7 +105,11 @@ def cross_table_duplicates(db):
:returns: the presence of cross table duplicate handles
:rtype: bool
"""
progress = ProgressMeter(_('Checking Database'),'')
if uistate:
parent = uistate.window
else:
parent = None
progress = ProgressMeter(_('Checking Database'),'', parent)
progress.set_pass(_('Looking for cross table duplicates'), 9)
logging.info('Looking for cross table duplicates')
total_nr_handles = 0
@@ -154,7 +158,7 @@ class Check(tool.BatchTool):
# As such, we run it before starting the transaction.
# We only do this for the dbdir backend.
if self.db.__class__.__name__ == 'DbBsddb':
if cross_table_duplicates(self.db):
if cross_table_duplicates(self.db, uistate):
Report(uistate, _(
"Your Family Tree contains cross table duplicate handles.\n "
"This is bad and can be fixed by making a backup of your\n"
@@ -216,6 +220,11 @@ class Check(tool.BatchTool):
class CheckIntegrity(object):
def __init__(self, dbstate, uistate, trans):
self.uistate = uistate
if self.uistate:
self.parent_window = self.uistate.window
else:
self.parent_window = None
self.db = dbstate.db
self.trans = trans
self.bad_photo = []
@@ -243,7 +252,8 @@ class CheckIntegrity(object):
self.empty_objects = defaultdict(list)
self.replaced_sourceref = []
self.last_img_dir = config.get('behavior.addmedia-image-dir')
self.progress = ProgressMeter(_('Checking Database'),'')
self.progress = ProgressMeter(_('Checking Database'),'',
parent=self.parent_window)
self.explanation = Note(_('Objects referenced by this note '
'were referenced but missing so that is why they have been created '
'when you ran Check and Repair on %s.') %
@@ -723,7 +733,7 @@ class CheckIntegrity(object):
"You may choose to either remove the reference from the database, "
"keep the reference to the missing file, or select a new file."
) % {'file_name' : '<b>%s</b>' % photo_name},
remove_clicked, leave_clicked, select_clicked)
remove_clicked, leave_clicked, select_clicked, parent=self.uistate.window)
missmedia_action = mmd.default_action
elif missmedia_action == 1:
logging.warning(' FAIL: media object "%(desc)s" '
@@ -1939,6 +1949,7 @@ class CheckIntegrity(object):
source = Source()
source.unserialize(info)
new_media_ref_list = []
citation_changed = False
for media_ref in source.get_media_list():
citation_list = media_ref.get_citation_list()
new_citation_list = []
@@ -1961,6 +1972,7 @@ class CheckIntegrity(object):
citation_handle = create_id()
new_citation.set_handle(citation_handle)
self.replaced_sourceref.append(handle)
citation_changed = True
logging.warning(' FAIL: the source "%s" has a media '
'reference with a source citation '
'which is invalid' % (source.gramps_id))
@@ -1970,9 +1982,10 @@ class CheckIntegrity(object):
media_ref.set_citation_list(new_citation_list)
new_media_ref_list.append(media_ref)
source.set_media_list(new_media_ref_list)
self.db.commit_source(source, self.trans)
if citation_changed:
source.set_media_list(new_media_ref_list)
self.db.commit_source(source, self.trans)
if len(self.replaced_sourceref) > 0:
logging.info(' OK: no broken source citations on mediarefs found')
+11 -2
View File
@@ -63,13 +63,22 @@ class DateParserDisplayTest(tool.Tool):
tool.Tool.__init__(self, dbstate, options_class, name)
if uistate:
# Running with gui -> Show message
QuestionDialog(_("Start date test?"),_("This test will create many persons and events in the current database. Do you really want to run this test?"),_("Run test"),self.run_tool)
self.parent_window = uistate.window
QuestionDialog(_("Start date test?"),
_("This test will create many persons and events " \
"in the current database. Do you really want to " \
"run this test?"),
_("Run test"),
self.run_tool,
parent=self.parent_window)
else:
self.parent_window = None
self.run_tool()
def run_tool(self):
self.progress = ProgressMeter(_('Running Date Test'),'')
self.progress = ProgressMeter(_('Running Date Test'),'',
parent=self.parent_window)
self.progress.set_pass(_('Generating dates'),
4)
dates = []
+2 -1
View File
@@ -170,12 +170,13 @@
</child>
<child>
<object class="GtkButton" id="button26">
<property name="label">_Apply</property>
<property name="label" translatable="yes">_Apply</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<signal name="clicked" handler="on_apply_clicked" object="filters" swapped="yes"/>
</object>
<packing>
+6 -5
View File
@@ -134,7 +134,7 @@ class EventComparison(tool.Tool,ManagedWindow):
})
window = self.filterDialog.toplevel
window.show()
#window.show()
self.filters = self.filterDialog.get_object("filter_list")
self.label = _('Event comparison filter selection')
self.set_window(window,self.filterDialog.get_object('title'),
@@ -177,7 +177,8 @@ class EventComparison(tool.Tool,ManagedWindow):
def on_apply_clicked(self, obj):
cfilter = self.filter_model[self.filters.get_active()][1]
progress_bar = ProgressMeter(_('Comparing events'),'')
progress_bar = ProgressMeter(_('Comparing events'),'',
parent=self.window)
progress_bar.set_pass(_('Selecting people'),1)
plist = cfilter.apply(self.db,
@@ -190,7 +191,7 @@ class EventComparison(tool.Tool,ManagedWindow):
self.options.handler.save_options()
if len(plist) == 0:
WarningDialog(_("No matches were found"))
WarningDialog(_("No matches were found"), parent=self.window)
else:
DisplayChart(self.dbstate,self.uistate,plist,self.track)
@@ -238,7 +239,6 @@ class DisplayChart(ManagedWindow):
})
window = self.topDialog.toplevel
window.show()
self.set_window(window, self.topDialog.get_object('title'),
_('Event Comparison Results'))
@@ -306,7 +306,8 @@ class DisplayChart(ManagedWindow):
self.progress_bar.close()
def build_row_data(self):
self.progress_bar = ProgressMeter(_('Comparing Events'),'')
self.progress_bar = ProgressMeter(_('Comparing Events'),'',
parent=self.window)
self.progress_bar.set_pass(_('Building data'),len(self.my_list))
for individual_id in self.my_list:
individual = self.db.get_person_from_handle(individual_id)
+3 -5
View File
@@ -122,7 +122,6 @@ class Merge(tool.Tool,ManagedWindow):
self.menu.set_active(0)
window = top.toplevel
window.show()
self.set_window(window, top.get_object('title'),
_('Find Possible Duplicate People'))
@@ -164,7 +163,7 @@ class Merge(tool.Tool,ManagedWindow):
try:
self.find_potentials(threshold)
except AttributeError as msg:
RunDatabaseRepair(str(msg))
RunDatabaseRepair(str(msg), parent=self.window)
return
self.options.handler.options_dict['threshold'] = threshold
@@ -186,8 +185,8 @@ class Merge(tool.Tool,ManagedWindow):
def find_potentials(self, thresh):
self.progress = ProgressMeter(_('Find Duplicates'),
_('Looking for duplicate people')
)
_('Looking for duplicate people'),
parent=self.window)
index = 0
males = {}
@@ -550,7 +549,6 @@ class ShowMatches(ManagedWindow):
top = Glade(toplevel="mergelist")
window = top.toplevel
window.show()
self.set_window(window, top.get_object('title'),
_('Potential Merges'))
+3 -3
View File
@@ -20,7 +20,7 @@
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="close">
<property name="label">_Close</property>
<property name="label" translatable="yes">_Close</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
@@ -37,7 +37,7 @@
</child>
<child>
<object class="GtkButton" id="help">
<property name="label">_Help</property>
<property name="label" translatable="yes">_Help</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
@@ -146,7 +146,7 @@
</child>
<child>
<object class="GtkButton" id="tagapply">
<property name="label">_Apply</property>
<property name="label" translatable="yes">_Apply</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
+2 -1
View File
@@ -3,7 +3,7 @@
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkDialog" id="relcalc">
<property name="visible">True</property>
<property name="visible">False</property>
<property name="can_focus">False</property>
<property name="default_width">600</property>
<property name="default_height">400</property>
@@ -91,6 +91,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="shadow_type">in</property>
<property name="min_content_height">75</property>
<child>
<object class="GtkTextView" id="text1">
<property name="height_request">75</property>
+6 -6
View File
@@ -98,7 +98,7 @@
<property name="receives_default">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<property name="halign">3</property>
<property name="halign">start</property>
<property name="draw_indicator">True</property>
</object>
<packing>
@@ -116,7 +116,7 @@
<property name="receives_default">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<property name="halign">3</property>
<property name="halign">start</property>
<property name="draw_indicator">True</property>
</object>
<packing>
@@ -134,7 +134,7 @@
<property name="receives_default">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<property name="halign">3</property>
<property name="halign">start</property>
<property name="draw_indicator">True</property>
</object>
<packing>
@@ -152,7 +152,7 @@
<property name="receives_default">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<property name="halign">3</property>
<property name="halign">start</property>
<property name="draw_indicator">True</property>
</object>
<packing>
@@ -170,7 +170,7 @@
<property name="receives_default">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<property name="halign">3</property>
<property name="halign">start</property>
<property name="draw_indicator">True</property>
</object>
<packing>
@@ -188,7 +188,7 @@
<property name="receives_default">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<property name="halign">3</property>
<property name="halign">start</property>
<property name="draw_indicator">True</property>
</object>
<packing>
+9 -3
View File
@@ -129,11 +129,16 @@ class TestcaseGenerator(tool.BatchTool):
def __init__(self, dbstate, user, options_class, name, callback=None):
uistate = user.uistate
if uistate:
self.parent_window = uistate.window
else:
self.parent_window = None
self.person = None
if dbstate.db.readonly:
return
tool.BatchTool.__init__(self, dbstate, user, options_class, name)
tool.BatchTool.__init__(self, dbstate, user, options_class, name,
parent=self.parent_window)
if self.fail:
return
@@ -192,7 +197,7 @@ class TestcaseGenerator(tool.BatchTool):
def init_gui(self,uistate):
title = "%s - Gramps" % _("Generate testcases")
self.top = Gtk.Dialog(title)
self.top = Gtk.Dialog(title, parent=uistate.window)
self.top.set_default_size(400,150)
self.top.vbox.set_spacing(5)
label = Gtk.Label(label='<span size="larger" weight="bold">%s</span>' % _("Generate testcases"))
@@ -279,7 +284,8 @@ class TestcaseGenerator(tool.BatchTool):
while Gtk.events_pending():
Gtk.main_iteration()
self.progress = ProgressMeter(_('Generating testcases'),'')
self.progress = ProgressMeter(_('Generating testcases'),'',
parent=self.parent_window)
self.transaction_count = 0;
if self.options.handler.options_dict['lowlevel']:
+2 -2
View File
@@ -310,7 +310,7 @@ class Verify(tool.Tool, ManagedWindow, UpdateCallback):
self.top.get_object(option).set_value(
self.options.handler.options_dict[option]
)
self.window.show()
self.show()
def build_menu_names(self, obj):
return (_("Tool settings"),self.label)
@@ -539,7 +539,7 @@ class VerifyResults(ManagedWindow):
name_column.set_sort_column_id(VerifyResults.OBJ_NAME_COL)
self.warn_tree.append_column(name_column)
self.window.show()
self.show()
self.window_shown = False
def __dummy(self, obj):
+2 -4
View File
@@ -232,7 +232,7 @@ class GeoClose(GeoGraphyView):
self._createmap(self.refperson, color, self.place_list_ref, True)
if self.refperson_bookmark is None:
self.refperson_bookmark = self.refperson.get_handle()
self.add_bookmark(None, self.refperson_bookmark)
self.add_bookmark_from_popup(None, self.refperson_bookmark)
else:
self.message_layer.add_message(_("You must choose one reference person."))
self.message_layer.add_message(_("Go to the person view and select "
@@ -535,9 +535,7 @@ class GeoClose(GeoGraphyView):
event, lat, lon, prevmark)
itemoption.append(center)
menu.show()
menu.popup(None, None,
lambda menu, data: (event.get_root_coords()[0],
event.get_root_coords()[1], True),
menu.popup(None, None, None,
None, event.button, event.time)
return 0
+3 -5
View File
@@ -335,7 +335,7 @@ class GeoEvents(GeoGraphyView):
hdle = evt.get_handle()
bookm = Gtk.MenuItem(label=_("Bookmark this event"))
bookm.show()
bookm.connect("activate", self.add_bookmark, hdle)
bookm.connect("activate", self.add_bookmark_from_popup, hdle)
itemoption.append(bookm)
if mark[0] != oldplace:
message = "%s :" % mark[0]
@@ -367,11 +367,9 @@ class GeoEvents(GeoGraphyView):
hdle = evt.get_handle()
bookm = Gtk.MenuItem(label=_("Bookmark this event"))
bookm.show()
bookm.connect("activate", self.add_bookmark, hdle)
bookm.connect("activate", self.add_bookmark_from_popup, hdle)
itemoption.append(bookm)
menu.popup(None, None,
lambda menu, data: (event.get_root_coords()[0],
event.get_root_coords()[1], True),
menu.popup(None, None, None,
None, event.button, event.time)
return 1
+2 -4
View File
@@ -255,7 +255,7 @@ class GeoFamClose(GeoGraphyView):
self.message_layer.add_message(_("The other family : %s" % _("Unknown")))
if self.reffamily_bookmark is None:
self.reffamily_bookmark = self.reffamily.get_handle()
self.add_bookmark(None, self.reffamily_bookmark)
self.add_bookmark_from_popup(None, self.reffamily_bookmark)
else:
self.message_layer.add_message(_("You must choose one reference family."))
self.message_layer.add_message(_("Go to the family view and select "
@@ -678,9 +678,7 @@ class GeoFamClose(GeoGraphyView):
event, lat, lon, prevmark)
itemoption.append(center)
menu.show()
menu.popup(None, None,
lambda menu, data: (event.get_root_coords()[0],
event.get_root_coords()[1], True),
menu.popup(None, None, None,
None, event.button, event.time)
return 0
+1 -3
View File
@@ -446,9 +446,7 @@ class GeoFamily(GeoGraphyView):
add_item.show()
menu.append(add_item)
self.add_event_bubble_message(event, lat, lon, prevmark, add_item)
menu.popup(None, None,
lambda menu, data: (event.get_root_coords()[0],
event.get_root_coords()[1], True),
menu.popup(None, None, None,
None, event.button, event.time)
return 1
+2 -4
View File
@@ -607,12 +607,10 @@ class GeoMoves(GeoGraphyView):
hdle = person.get_handle()
bookm = Gtk.MenuItem(label=_("Bookmark this person"))
bookm.show()
bookm.connect("activate", self.add_bookmark, hdle)
bookm.connect("activate", self.add_bookmark_from_popup, hdle)
itemoption.append(bookm)
menu.show()
menu.popup(None, None,
lambda menu, data: (event.get_root_coords()[0],
event.get_root_coords()[1], True),
menu.popup(None, None, None,
None, event.button, event.time)
return 1
+1 -3
View File
@@ -484,9 +484,7 @@ class GeoPerson(GeoGraphyView):
center.connect("activate", self.center_here, event, lat, lon, prevmark)
itemoption.append(center)
menu.show()
menu.popup(None, None,
lambda menu, data: (event.get_root_coords()[0],
event.get_root_coords()[1], True),
menu.popup(None, None, None,
None, event.button, event.time)
return 1
+3 -5
View File
@@ -333,7 +333,7 @@ class GeoPlaces(GeoGraphyView):
hdle = place.get_handle()
bookm = Gtk.MenuItem(label=_("Bookmark this place"))
bookm.show()
bookm.connect("activate", self.add_bookmark, hdle)
bookm.connect("activate", self.add_bookmark_from_popup, hdle)
itemoption.append(bookm)
message = "%s" % mark[0]
prevmark = mark
@@ -357,11 +357,9 @@ class GeoPlaces(GeoGraphyView):
hdle = place.get_handle()
bookm = Gtk.MenuItem(label=_("Bookmark this place"))
bookm.show()
bookm.connect("activate", self.add_bookmark, hdle)
bookm.connect("activate", self.add_bookmark_from_popup, hdle)
itemoption.append(bookm)
menu.popup(None, None,
lambda menu, data: (event.get_root_coords()[0],
event.get_root_coords()[1], True),
menu.popup(None, None, None,
None, event.button, event.time)
return 1
+2 -2
View File
@@ -30,7 +30,7 @@ Can use the Webkit or Gecko ( Mozilla ) library
# Python modules
#
#-------------------------------------------------------------------------
import os
import os, io
import sys
if sys.version_info[0] < 3:
from urlparse import urlunsplit
@@ -557,7 +557,7 @@ class HtmlView(NavigationView):
# Now we have two views : Web and Geography, we need to create the
# startpage only once.
if not os.path.exists(filename):
ufd = file(filename, "w+")
ufd = io.open(filename, "w+", encoding="utf8")
ufd.write(data)
ufd.close()
return urlunsplit(('file', '',
+1 -8
View File
@@ -181,16 +181,9 @@ class MediaView(ListView):
"""
if not sel_data:
return
#modern file managers provide URI_LIST. For Windows split sel_data.data
files = sel_data.get_uris()
for file in files:
if win():
clean_string = conv_to_unicode(
file.replace('\0',' ').replace("\r", " ").strip(),
None)
else:
clean_string = file
protocol, site, mfile, j, k, l = urlparse(clean_string)
protocol, site, mfile, j, k, l = urlparse(file)
if protocol == "file":
name = url2pathname(mfile)
mime = get_type(name)
+1 -1
View File
@@ -987,7 +987,7 @@ class PedigreeView(NavigationView):
rela = lst[2*i+1][1]
line = LineWidget2(1, rela, self.tree_direction)
if lst[i] and lst[i][2]:
if lst[((i+1) // 2) - 1] and lst[((i+1) // 2) - 1][2]:
# Required for popup menu
line.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
line.connect("button-press-event",
+20 -14
View File
@@ -142,7 +142,7 @@ from gramps.plugins.lib.libhtml import Html, xml_lang
# import styled notes from src/plugins/lib/libhtmlbackend.py
from gramps.plugins.lib.libhtmlbackend import HtmlBackend, process_spaces
from gramps.plugins.lib.libgedcom import make_gedcom_date
from gramps.plugins.lib.libgedcom import make_gedcom_date, DATE_QUALITY
from gramps.gen.utils.place import conv_lat_lon
from gramps.gui.pluginmanager import GuiPluginManager
@@ -517,14 +517,20 @@ def format_date(date):
cal = date.get_calendar()
mod = date.get_modifier()
quality = date.get_quality()
if quality in DATE_QUALITY:
qual_text = DATE_QUALITY[quality] + " "
else:
qual_text = ""
if mod == Date.MOD_SPAN:
val = "FROM %s TO %s" % (
make_gedcom_date(start, cal, mod, quality),
make_gedcom_date(date.get_stop_date(), cal, mod, quality))
val = "%sFROM %s TO %s" % (
qual_text,
make_gedcom_date(start, cal, mod, None),
make_gedcom_date(date.get_stop_date(), cal, mod, None))
elif mod == Date.MOD_RANGE:
val = "BET %s AND %s" % (
make_gedcom_date(start, cal, mod, quality),
make_gedcom_date(date.get_stop_date(), cal, mod, quality))
val = "%sBET %s AND %s" % (
qual_text,
make_gedcom_date(start, cal, mod, None),
make_gedcom_date(date.get_stop_date(), cal, mod, None))
else:
val = make_gedcom_date(start, cal, mod, quality)
return val
@@ -5046,14 +5052,14 @@ class DownloadPage(BasePage):
else:
tcell += "&nbsp;"
# clear line for proper styling
# create footer section
footer = self.write_footer()
body += (fullclear, footer)
# clear line for proper styling
# create footer section
footer = self.write_footer()
body += (fullclear, footer)
# send page out for processing
# and close the file
self.XHTMLWriter(downloadpage, of, sio)
# send page out for processing
# and close the file
self.XHTMLWriter(downloadpage, of, sio)
class ContactPage(BasePage):
def __init__(self, report, title):
+1 -1
View File
@@ -18,6 +18,6 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
VERSION_TUPLE = (4, 1, 2)
VERSION_TUPLE = (4, 1, 4)
VERSION = '.'.join(map(str,VERSION_TUPLE))
major_version = "%s.%s" % (VERSION_TUPLE[0], VERSION_TUPLE[1])
+4 -4
View File
@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>Gramps</string>
<key>CFBundleGetInfoString</key>
<string>4.1.1, (C) 1997-2014 The Gramps Team http://www.gramps-project.org</string>
<string>4.1.3, (C) 1997-2015 The Gramps Team http://www.gramps-project.org</string>
<key>CFBundleIconFile</key>
<string>gramps.icns</string>
<key>CFBundleIdentifier</key>
@@ -17,13 +17,13 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>4.1.1-1</string>
<string>4.1.3-1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>4.1.1-1</string>
<string>4.1.3-1</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright 1997 - 2014 The Gramps Team, GNU General Public License.</string>
<string>Copyright 1997 - 2015 The Gramps Team, GNU General Public License.</string>
<key>LSMinimumSystemVersion</key>
<string>10.5</string>
<key>NSHighResolutionCapable</key>

Some files were not shown because too many files have changed in this diff Show More