Compare commits

..

342 Commits

Author SHA1 Message Date
John Ralls 17c1dfe950 File copy doesn't work if the glob can match directories. 2018-08-05 13:18:35 -07:00
John Ralls 4531cbd049 Install the docs/gramps directory in the bundle.
Fixes bug #10705.
2018-08-04 21:40:34 -07:00
Paul Culley d24fc82031 Fix error when opening bsddb db in read-only mode (#628)
Fixes #10615
2018-06-22 10:44:13 +10:00
Paul Culley 16a9cd4c93 Fix FanChartDesc for typo (#610)
Fixes #10565

- Bug occurs when selected person has more than 4 parents.
2018-05-09 13:23:05 +10:00
Paul Culley 94018ed33a Fix multi-page Graph output to pdf with filenames containg spaces (#560)
Fixes #10470
2018-03-03 09:02:17 +11:00
arnaullv ffd77dc404 Updated catalan translation 2018-02-20 18:19:49 +00:00
Zdeněk Hataš 7c6e531c26 Czech translation fixes 2018-02-19 19:11:00 +01:00
Sam Manzi bc4b006dbe Increment year to 2018 for About box. 2018-02-13 13:29:09 +11:00
John Ralls 40da63a0fb Release gramps 4.2.8 on Mac. 2018-02-10 11:02:33 -08:00
John Ralls 6fafe8f6c3 Update pyicu to v 2.0.3 2018-02-10 11:01:25 -08:00
John Ralls 66a0c619b9 Consolidate Python2 and Python3 meta-modules.
GObject-Introspection now works with Python3 so the split isn't needed any more.
2018-02-10 11:01:24 -08:00
Nick Hall 6ffc095db0 Bump to 4.2.9 2018-02-09 21:12:16 +00:00
Nick Hall 5a5f4970f7 Release Gramps 4.2.8 2018-02-09 21:05:56 +00:00
Nick Hall ea3d49e50c Update Changelog and NEWS files 2018-02-09 21:02:23 +00:00
prculley e4b6d9beda Fix Geography views for bad 'dbstate.is_open()' test
Fixes #10417
2018-02-09 09:01:41 -06:00
Nick Hall b6f68c03bb Bump to 4.2.8 2018-02-08 20:36:04 +00:00
Nick Hall f5a66c3958 Release Gramps 4.2.7 2018-02-08 20:27:16 +00:00
Nick Hall c6ce61b4b9 Update ChangeLog and NEWS files 2018-02-08 19:58:51 +00:00
Nick Hall 9c050491ef Update translation template for new release 2018-02-08 17:51:13 +00:00
prculley 54ab2820c3 Fix Export View to CSV when Unicode characters are present
Fixes #10404
2018-02-06 22:26:04 +00:00
prculley 1bf9fef1cb Fix several intl date displayers for missing parameter.
Fixes #10196
2018-02-05 09:40:18 -06:00
niememat dafde8df12 Update finnish translation 2018-01-29 20:52:22 +02:00
Paul Culley ac6eb9661c DescendantTree report; fix crashes and Title spacing for Gramps42 (#537)
* Fix DescendentTree report for crashes

Fixes #10377

* Fix DescendentTree report; more space beneath Title

Issue #10377
2018-01-29 14:35:03 +11:00
Paul Culley 09bc188a1c Fix Book XML handler to deal with unusual characters in Book name Gramps42 (#536)
* Fix Book XML handler to deal with unusual characters in Book name

Fixes #10387

* Fix 'Generate Book' dialog for bad transient parent

* Fix Book XML handler for unusual characters in report name

Issue #10387
2018-01-29 14:29:43 +11:00
Leonhaeuser 4d68f68742 update German translation 2018-01-27 15:30:53 +01:00
Nick Hall 70a634da1e Add support for new genealogy tree report category
Issue #10223.
2018-01-26 22:19:40 +00:00
prculley ec44396680 Fix Media Preview Gramplet for closed db
Fixes #10332
2018-01-22 21:30:44 +00:00
prculley 5490ff0b84 Suport FTM 2017 Gedcom tags on import
Bug #10285
FTM adds subordinate PLAC and OBJE data to INDI.ADDR which is
non-standard.  So treat it as a Residence Event, instead of an
Address.
FTM puts _DATE and _TEXT tags subordinate to OBJE, also non-standard.
2018-01-22 21:30:44 +00:00
prculley a339e68877 Fix Person, Family Sidebar Filters to add custom Event types
Fixes #10112
Also fix Family Sidebar Filter RelType init with closed db
2018-01-22 21:30:44 +00:00
prculley dd0956d6ce Fix QuestionDialog display for html like characters in title
Fixes #10298
2018-01-22 21:30:44 +00:00
prculley 7911785ea4 Fix FamilyRelationshpType _DATAMAP order to correspond with values
Fixes #10275
2018-01-22 21:30:43 +00:00
prculley 9eebeb05da Fix Gedcom import for illegal Gedcom Family Attributes
Issue #10262
TMG Gedcom exports an illegal NCHI with sub-data for FAM.  Gramps
could not handle this and attached the sub-data to the FAM creating
some corrupted Event records.
2018-01-22 21:30:43 +00:00
prculley a492511533 Fix Gedcom export for bad Hebrew Months
Fixes #10245
2018-01-22 21:30:43 +00:00
prculley ed907def1f Change INSTALL to replace 'python' with 'python3 for script invokes 2018-01-22 21:30:43 +00:00
prculley 22a9cbdcc8 Fix CSV importer for place event name using gramps_id
Fixes #10239
2018-01-22 21:30:43 +00:00
prculley 84e0d45ab6 Fix Geography view 'Find' when db is closed.
Fixes #10229
2018-01-22 21:30:43 +00:00
prculley 85f42908f4 Fix interactive search for exception on click then down arrow
Fixes #10226
2018-01-22 21:30:43 +00:00
prculley da1c942509 Create where_is utility to locate a binary in the standard places
This is particularly useful on Mac OS X where Gramps is passed a PATH
that does not include elements added by the terminal shell.
2018-01-22 21:30:43 +00:00
prculley d98db27dcc Fix relationship Graph so Unicode chars on Multiple pages works.
Fixes: #9783, #9359, #8080, #6782, #6108
Bugs: #6431, #4164, #1485, #2964, #2790
2018-01-22 21:30:43 +00:00
prculley 2b74e0734a update authors file 2018-01-22 21:30:43 +00:00
prculley ebae9c3915 Fix Gedcom import for "1 MARR Y" issue
Fixes #10188
2018-01-22 21:30:43 +00:00
Paul Culley 286289aaf7 Fix Export Web Family Tree for errors on file write (#525)
Fixes #10364
2018-01-20 16:59:05 +11:00
Paul Culley e8489bf53c Fix Citation Editor to Tab out of Confidence ComboBox (#526)
Fixes #10351
2018-01-20 16:30:53 +11:00
John Ralls 9946d6f993 Reset the dependencies on the new meta-module. 2018-01-15 07:36:58 -08:00
John Ralls 00f87cc70e Use online modules.
Instead of the path that works on my machines only.
2018-01-15 07:33:21 -08:00
John Ralls 2fbc0b8aeb Consolidate Python2 and Python3 meta-modules.
GObject-Introspection now works with Python3 so the split isn't needed any more.
2018-01-15 07:27:43 -08:00
Nick Hall 56122b0a54 Use None as the foreground colour for untagged rows in list views
The call to get_style_context is not required.  It also caused
problems in Windows due to excessive calls to the foreground_color
method.

Fixes #10365.
2018-01-14 18:03:14 +00:00
Nick Hall 6648ecb5ff Fix shading colour in relationship view for dark themes
Fixes #7749.
2018-01-09 18:11:59 +00:00
Nick Hall 1b2d0a1956 Fix link colour for dark themes
Issue #7749.
2018-01-09 18:11:42 +00:00
Nick Hall 6bdac08358 Fix default foreground colour in list views for dark themes
Issue #7749.
2018-01-09 18:11:22 +00:00
prculley e74dc2fa8c fix Undo; crashes due to race in Gtk
Some Redraws occur during a model clear when the row changed signal
is emmitted.  Model is only partially cleared at that point.
Under some conditions, some more of the model gets
cleared before the redraw completes, and redraw fails.
fixes #9932
2017-10-14 10:05:24 -05:00
prculley 314f7cce65 Gedcom import with OBJE/FORM URL on event
Fixes #7593.
2017-10-14 01:35:33 +01:00
Josip 11776db76d EOFError [Ran out of input] in Clipboard (#411)
[EOFError: Ran out of input] for Clipboard when you drag and
drop the bolded lines in selected tabs of Person Edit

Attempt to drag and drop any of the "bolded lines" in the Events or
Names tabs into the clipboard window. The unbolded lines drag and drop
ok.

Fixes #8788.
2017-10-14 01:26:49 +01:00
Josip eecf48e6e5 Cannot drag & drop textual value via clipboard
Allows dnd of textual values from clipboard and shows icon of
target-type during dragging instead of row image, except for text target
shows actual text as drag icon.

Fixes #7532.
2017-10-14 01:21:41 +01:00
prculley bedebc524b Fix 'DbBsddbRead' object has no attribute '_Callback__callback_map'
Fixes #10219
Same idea as 87a5412 for Gramps50
2017-10-06 14:32:25 -05:00
SNoiraud c01ee8ed7d Reports - Narrated Web Site Failure
Fixes #10206
2017-09-24 21:17:20 +02:00
John Ralls 578f4bdf62 Fix link path in gramps-launcher compile instructions. 2017-08-26 16:38:31 -07:00
John Ralls baadf6158a Release 4.2.6 on Mac. 2017-08-26 11:19:32 -07:00
romjerome 024204771b bump to 4.2.7 2017-08-01 11:08:29 +02:00
romjerome 7ed03d43d5 make official '4.2.6' release 2017-08-01 11:04:28 +02:00
romjerome 24d97f528e Update ChangeLog and NEWS files 2017-08-01 10:58:22 +02:00
romjerome d9bb009e6b typos 2017-08-01 10:52:48 +02:00
Zdeněk Hataš 16d7f92b97 update to recent pot 2017-07-31 10:38:24 +02:00
romjerome 1a1c82c261 start '4.2.6' section 2017-07-29 15:16:25 +02:00
romjerome b9cd0450dc Update template
no modified or new message id, update references (header and comments)
2017-07-29 15:09:59 +02:00
vantu5z df01461171 update Russian translation
- merge last template
- fix typo
- change 'е' to 'ё' in some words
2017-07-26 17:41:01 +03:00
Nick Hall b573c7d7cf Fix HasCitation rule in citation filter sidebar
Filter parameters should be of type str.

Fixes #10076.

(cherry picked from commit adb4883291)
2017-07-24 23:52:10 -07:00
Nick Hall 60f944adcf Remove deprecated locale flag
re.L is deprecated and re.U is now default.

(cherry picked from commit da3db4bc28)

Fixes #10136
2017-07-24 23:50:44 -07:00
Paul Franklin 9e12a5d364 Date Editor has 'Type' and 'Quality' labels swapped
Fixes #10135
2017-07-23 11:24:46 -07:00
Leonhaeuser c138aeb8c6 update German translation
Fix #0010131
2017-07-15 00:21:32 +02:00
Lajos Nemeséri 00a5ea1a39 Update Hungarian translation 2017-07-08 13:33:01 +02:00
John Ralls 9bb4aaaf49 Open web links with /usr/bin/open on Mac and Python older than 3.5
Works around https://bugs.python.org/issue24452
Fixes #10105
2017-07-03 10:16:19 -07:00
John Ralls ae6db43fc4 FamilyGroup Report crash
Python's sort routine gratuitously converts the bytearrays returned by
ICU::Collator::getByteArray to a string when storing it. This resulted
in a TypeError when attempting to compare a just-returned bytearray
with a stored string.

We work around this by converting the bytearray into its hexadecimal
representation and then decoding that into a string.

Fixes #10077.
2017-06-27 12:15:30 -07:00
Paul Franklin 5972477550 names not displayed in relationship graph
Issue #10093
2017-06-22 17:26:58 -07:00
Paul Franklin 215f6bf88d Outdated Bugtracker link in Unexpected Error reporting wizard
Fixes #10100
2017-06-21 09:37:54 -07:00
Paul Franklin fc3e41d696 Family Lines Report generates empty PDFs when name [has double-quotes]
Fixes #10096
2017-06-21 09:18:19 -07:00
Paul Franklin 706d29a480 non-local character in DB name causes crash on Windows
Fixes #10095
2017-06-19 09:50:15 -07:00
Josip 26c50fdbdd Quick search with Czech characters -> Crash
Crash happen when checking for "event.string" in "treeview_keypress"
function in "gramps/gui/widgets/interactivesearchbox.py"
Note that

https://lazka.github.io/pgi-docs/Gdk-3.0/classes/EventKey.html#Gdk.EventKey
says it is deprecated and should never be used.

Gdk.keyval_to_unicode return the corresponding unicode character, or 0
if there is no corresponding character.

Fixes #9130.

(cherry picked from commit bc17245331)
2017-06-10 18:52:18 +02:00
John Ralls 7a61a0e96f 8366: February 29th invalid date in Julian dual-dated leap year 2017-05-31 12:07:16 -07:00
Paul Franklin efab48d5cc 10033: Note isn't included on CIR when it is attached to a name 2017-05-19 06:48:32 -07:00
Nick Hall 647a3b226a Revert bugs #8785 and #9700
Expanding tree selectors by default caused performance issues.
The expanded person selector also made it more difficult to
select a specific person in some circumstances.

GEPS 041 has been created to discuss a better selector design.
2017-05-15 17:16:33 +01:00
Sam Manzi db3655d156 Fix bug 9975 Incorrect SoundEx result (#388) 2017-05-05 16:30:47 +10:00
Paul Culley 95e0f43bf5 bug 9564; fix exception on Event filter editor (#378)
for 'Events occurring on a particular day of the week' filter
2017-04-30 12:51:24 +10:00
Paul Franklin 77e9d796da 9995: Bug in the Name Editor / Group As 2017-03-22 17:21:03 -07:00
Paul Franklin 2af262435d add datestrings to gramps42 Turkish translation 2017-03-16 10:24:38 -07:00
Sam Manzi 4fca41c8c9 Merge pull request #352 from beernarrd/sl-gramps42
Sl gramps42
2017-02-12 14:59:10 +11:00
Nick Hall 8c7133ab00 9945: Write PlaceID links in CSV export
When places are included in the export use PlaceID links,
otherwise generate a formatted place for the event.
2017-02-11 18:47:07 +00:00
beernarrd 425c15e6f5 Merge branch 'maintenance/gramps42' into sl-gramps42 2017-02-09 17:47:00 +01:00
Doug Reider 0ab7c316f0 Fix bookmarks keybinding on Mac to match the documentation. 2017-02-08 21:16:31 -07:00
Bernard Banko a219421e36 updated sl translation 2017-02-08 01:37:00 +01:00
Bernard Banko 7bbc976141 corrected slovenian name editor keywords 2017-02-08 01:09:57 +01:00
Paul Franklin f1b311c9cd 9004: Error printing graphical report ancestor tree 2017-02-07 09:24:27 -08:00
Jérôme Rapinat 3c2231591f 9004: Error printing graphical report ancestor tree 2017-02-07 09:18:00 -08:00
Peter Landgren ac18460059 Update Swedish translation 2017-02-02 10:43:22 +01:00
romjerome aebe2810f8 9907: add a spacing value for children widgets
fit better for some Gtk themes
2017-02-02 10:26:19 +01:00
romjerome 4ff908bcef 8855: update API doc for place displayer 2017-02-02 10:24:07 +01:00
Matti Niemelä f8c1a54def update finnish translation 2017-01-25 14:50:13 +01:00
romjerome 3d1ec9e658 9904: revert fd83162
TODO: need a solution for recursive iteration and private records
2017-01-25 14:38:12 +01:00
romjerome fd83162289 9904: Errors printing graphical report ancestor tree 2017-01-24 17:27:51 +01:00
romjerome f092144a93 9908: Custom Family Relations not shown in the filter siderbar 2017-01-24 17:24:00 +01:00
romjerome 041d969cce 9899: fix non-textual value on place name 2017-01-14 14:53:02 +01:00
Luigi Toscano c656b38d9e Italian translation: updates and fixes 2017-01-11 01:56:23 +01:00
Luigi Toscano 2f1df8ac69 Refresh it.po using the current pot template 2017-01-08 16:22:14 +01:00
Nick Hall 49416739c1 9878: Update note text before closing
The object must be updated so that changes can be detected.
2017-01-03 21:28:10 +00:00
SNoiraud 5f2a6df0d0 9865: Can not link the place on geography view 2017-01-02 11:30:49 +01:00
Paul Franklin 0be00be4d9 9862: ancestor tree doesn't use replacements 2016-12-28 20:17:15 -08:00
Josip ab17a5340a 8128: GtkDialog mapped without a transient parent
Fix Reorder Relationships dialog

(cherry picked from commit 3b4ceeb630)
2016-12-23 14:22:44 +01:00
prculley e578316bd9 bug 9235: Shrink size of Break Lock (and other QuestionDialogs) 2016-12-23 10:43:46 +11:00
prculley 1c83948b40 bug 9470; Don't allow selecton of Active or Home person until actually commited 2016-12-23 10:30:05 +11:00
Sam Manzi 63ce7383cc Merge pull request #297 from prculley/bug9478_42
bug 9478; fix quick search exception when nothing in searched list
2016-12-23 10:17:00 +11:00
prculley 11f0c0254b bug 9478; fix quick search exception when nothing in searched list 2016-12-22 09:03:49 -06:00
Paul Franklin d691cfdb1c bump to 4.2.6 2016-12-17 21:38:51 -08:00
Paul Franklin 58b12e702a 9612: Problem adding parents [with Latin names] 2016-12-17 18:32:34 -08:00
Paul Franklin 2bd1a4b757 Merge branch 'maintenance/gramps42' of file:///misc/home2-rw/pf/gramps/my-git-gramps/git-gramps_my-barerepo into maintenance/gramps42 2016-12-17 10:27:27 -08:00
John Ralls 54b6563e63 Release 4.2.5 on Mac. 2016-12-16 15:12:03 -08:00
John Ralls 0964bfd683 Fix failure to load default gramplets if GExiv2 is missing or too old. 2016-12-16 15:10:22 -08:00
romjerome 35ceba1e4d make official 4.2.5 release 2016-12-15 21:55:19 +00:00
Nick Hall dc82105fa4 Add ChangeLog file to manifest 2016-12-15 21:54:37 +00:00
romjerome c5d40f70d0 update ChangeLog files 2016-12-15 21:28:40 +00:00
romjerome 77ccb1770b make official 4.2.5 release 2016-12-15 16:45:15 +01:00
romjerome 68f54f9b08 update News file 2016-12-15 16:33:03 +01:00
romjerome 78c807814d fix a missing import 2016-12-15 15:59:10 +01:00
romjerome a515501552 Tag editor: Tweak improvement on buttons order 2016-12-15 15:50:53 +01:00
SNoiraud 0e05b2f535 9340: The configparser is assuming the wrong encoding. 2016-12-15 09:28:54 +01:00
SNoiraud b999e2df78 9563: Sorting in family tab of narrated web report 2016-12-14 10:20:34 +01:00
Leonhaeuser 906035b022 fix 0009696 2016-12-13 23:32:48 +01:00
Sam Manzi 9be31757e0 9801 Silence remaining PyGIWarning 2016-12-14 07:42:36 +11:00
SNoiraud cc50e4e972 9563: Sorting of relationships in family tab of narrated web report 2016-12-13 14:19:38 +01:00
Josip 4a583e187c Support for Windows Python3 pythonw.exe 2016-12-10 22:17:42 +01:00
romjerome bc51334178 start to update NEWS 2016-12-10 10:56:26 +01:00
Nick Hall d1d08a1552 9799: Use latest valid date rather than today
This is useful for historic places when an event date is not
available.
2016-12-09 19:29:53 +00:00
Nick Hall 3a58492424 9813: Modify endonym handling in place displayer
If no language code is matched, the default name is now the first
in the list, rather than a name with no language code.
2016-12-09 19:10:10 +00:00
Nick Hall 9860fdb941 9737: Fix house number concatenation 2016-12-09 18:58:08 +00:00
Espen Berg aedf26b871 Corrected another typo in relationship calculator, Norwegian 2016-12-07 21:57:07 +01:00
Espen Berg 47ba95d005 Language correction in Norwegian locale relationship calculator 2016-12-07 20:00:43 +01:00
Paul Culley 6b5253abce Merge pull request #282 from prculley/gramps42
bug 9818 allow merging of families with one or more parents in common
2016-12-06 09:15:57 -06:00
prculley ca5953f1bc bug 9818 allow merging of families with one or more parents in common 2016-12-06 09:06:03 -06:00
vantu5z 44e89c0a67 update Russian translation 2016-12-06 14:47:38 +03:00
SNoiraud 1acbd3e3f7 7309: Jump to Gramps ID functionality doesn't work 2016-12-05 11:09:38 +01:00
romjerome b568c1bb97 update french translation 2016-12-05 09:44:12 +01:00
romjerome 1b05edf7b4 9276: update translation strings template
No new entry, update references and comments
2016-12-05 09:40:21 +01:00
romjerome 5cd646d22b 9276: ability to search alternate place names when selecting place 2016-12-05 09:37:24 +01:00
romjerome aca78ad3d5 typo on french translation 2016-12-05 09:31:01 +01:00
Espen Berg d85ab22db6 Cleaned out one more line in nb.po 2016-12-04 20:29:46 +01:00
Espen Berg 70998b2a6b The unlocking message is on one loooong line. Inserted line breaks in Norwegian translation for cleanliness 2016-12-04 19:56:32 +01:00
Espen Berg f4a82ce6e0 Revising Norwegian bokmål language file (at last) 2016-12-03 23:10:57 +01:00
Espen Berg 477efa8a5a Revising Norwegian bokmål language file (at last) 2016-12-03 23:10:36 +01:00
romjerome 8f05973b29 9812: 'Check and Repair' tool ignores some objects with tag support 2016-12-03 11:01:28 +01:00
vantu5z cb251ccccf update Russian translation 2016-11-30 13:44:02 +03:00
romjerome 95afffef79 9815: Fix clear map action on Geography 2016-11-29 10:30:40 +01:00
Matti Niemelä e52e0d3734 Update finnish translation 2016-11-29 10:27:16 +01:00
Zdeněk Hataš bb58b6fc1b czech translation update 2016-11-28 14:36:09 +01:00
romjerome de7342d3e8 9801: recommend 'gir1.2-goocanvas-2.0' on debian package 2016-11-26 13:01:28 +01:00
romjerome 46d8839880 8555: Database repair tool always modify all source objects 2016-11-26 12:49:09 +01:00
romjerome 10781bde6b Update french translation 2016-11-24 08:14:08 +01:00
romjerome 7a4b7aa77b Update translation strings template 2016-11-24 08:10:44 +01:00
romjerome c03ccaa740 typo on french translation 2016-11-24 08:08:11 +01:00
Nick Hall d682302612 9534: Exclude places outside valid date ranges 2016-11-22 18:18:35 +00:00
Leonhaeuser 6bbe44f6aa update German translation 2016-11-10 04:51:51 +01:00
Sam Manzi 703703cc75 Merge pull request #265 from prculley/bug9755_42
bug 9755, fix duplicated Gramps IDs on Gedcom import (gramps42)
2016-11-05 14:06:07 +11:00
Nick Hall 17c51b3e76 9767: Fix icon and tooltip in LDS editor
The icon on the family selection button was removed by mistake in
commit 75009f0.
2016-11-01 18:49:15 +00:00
prculley 3e53d086ea bug 9755, fix duplicated Gramps IDs on Gedcom import 2016-10-30 15:31:24 -05:00
Sam Manzi b0fd9bcceb Merge pull request #261 from prculley/csv_42
Fix bug 9733, CSV import Fails, 9676, failure for certain types of cross references etc.
2016-10-29 14:20:38 +11:00
Sam Manzi 7e2585d27e 9685 Fix Unicode error - Markup for invalid date format 2016-10-29 14:09:39 +11:00
prculley cd4afcdb32 Fix bug 9733, CSV import Fails, 9676, failure for certain types of cross references etc. 2016-10-25 12:07:44 -05:00
Paul Culley 4e5112d3fd Merge pull request #258 from prculley/bug9458_42
bug 9458, fix Import Vcard can create multiple surnames with all selected as 'Primary'
2016-10-24 15:51:11 -05:00
Paul Culley 87e38afdde Merge pull request #257 from prculley/bug8993_42
bug 8993; fix Gedcom import in some alternate languages; improper date parsing
2016-10-24 15:44:49 -05:00
prculley 2a55fd268c bug 9458, fix Import Vcard can create multiple surnames with all selected as 'Primary' 2016-10-24 15:40:57 -05:00
prculley dec4380c82 bug 8993; fix Gedcom import in some alternate languages; improper date parsing 2016-10-24 15:31:59 -05:00
romjerome 05d4cc39e3 typo on the french translation 2016-10-23 16:27:02 +02:00
SNoiraud e5a7fdc512 8250 and 9736 : remove patchs. need to found another solution. 2016-10-21 23:13:24 +02:00
vantu5z 3f83395603 update russian translation 2016-10-18 09:44:01 +03:00
SNoiraud 850685c3ef 9736: Export options 'Preview' buttons create hidden quickreport. 2016-10-16 22:41:10 +02:00
Paul Franklin ac00bd1843 9739: Wrong parsing Numeric date format for cs_CZ locale 2016-10-12 13:16:13 -07:00
SNoiraud b2775b3892 9736: Export options 'Preview' buttons create hidden quickreport. 2016-10-11 13:44:17 +02:00
Matti Niemelä f2d822b8b7 Update finnish translation 2016-10-04 17:38:45 +02:00
Leonhaeuser 3d1ec482e4 update German translation 2016-10-03 20:43:30 +02:00
Zdeněk Hataš 9f6e1ebe7d czech translation update 2016-10-01 15:06:49 +02:00
romjerome b7b8daef40 typo, Change FICHIER to File 2016-09-28 15:41:42 +02:00
Lajos Nemeséri 7f6757bcad Update Hungarian translation 2016-09-28 15:32:18 +02:00
Nick Hall 57794a7ed2 9721: Fix alignment radio buttons in style editor 2016-09-25 17:27:04 +01:00
SNoiraud 517f794af6 9700: Select Place search & Source/Citation hierarchy should NOT be expanded 2016-09-16 20:53:37 +02:00
Sveinn í Felli ce59ea6c4a Add 9693: Icelandic translation update(msgfmt error fixed) 2016-09-13 08:01:55 +10:00
Sveinn í Felli 00dc403ec3 Add 9693: Icelandic translation update 2016-09-12 13:38:33 +10:00
John Ralls 68f7238048 Add gir files to bundle.
Enables change of library paths in the typelibs to point at
@executable_path by gtk-mac-bundler.
2016-09-10 13:55:35 -07:00
John Ralls 3c8cd9f7ab Revert "Remove pango modules from bundle, pango no longer uses them."
This reverts commit e311de1964 because for
the moment we have to build with an older Pango.
2016-09-05 15:16:51 -07:00
John Ralls 4a12c344c6 escape illegal '--' in comment. 2016-09-05 15:16:50 -07:00
romjerome fd0d9cf297 bump to '4.2.5' 2016-09-04 16:46:17 +02:00
romjerome ce9f77ac77 make official 4.2.4 release 2016-09-04 16:44:02 +02:00
romjerome eac82f538e Update NEWS file for '4.2.4' 2016-09-04 16:38:42 +02:00
romjerome 6511379220 Update french translation 2016-09-01 17:59:57 +02:00
romjerome 84c8fada7a Update translations template
see rev 19447b
2016-09-01 17:55:34 +02:00
Zdeněk Hataš fd96331b6d czech translation update 2016-08-31 12:36:59 +02:00
Sam Manzi 5a5868d183 Merge pull request #221 from prculley/fax_42
Fixes for the PHON, FAX, EMAIL and WWW Gedcom tags to support Gedcom v5.5.1.
2016-08-31 07:39:32 +10:00
romjerome e53587783e Merge pull request #226 from paulohpmoraes/maintenance/gramps42
Translated untranslated and fuzzy strings.
2016-08-30 11:58:19 +02:00
Paulo Henrique Moraes 072048bdf1 Translated untranslated and fuzzy strings.
Translated untranslated and fuzzy strings. Some changes, corrections and uniformization.
2016-08-29 20:56:37 -03:00
romjerome eec2f8477b Update translations template and french translation
new entry see rev998c3
2016-08-29 17:27:23 +02:00
Matti Niemelä 402cf35f88 Update Finnish translation 2016-08-29 17:17:44 +02:00
Leonhaeuser cd478d0e0d update German translation 2016-08-27 23:19:18 +02:00
vantu5z 8b41cab3fc update russian translation 2016-08-27 13:11:45 +03:00
prculley 19447be47c Fixes for the PHON, FAX, EMAIL and WWW Gedcom tags to support Gedcom v5.5.1. 2016-08-26 10:12:24 -05:00
Paul Culley dd179ad790 Merge pull request #207 from prculley/bug9549_42
bug 9549 Chinese characters are not rendered properly in pdf reports
2016-08-23 13:50:53 -05:00
romjerome 9ca553bf7f Update french translation 2016-08-22 16:08:34 +02:00
romjerome d3768f384f Update translations template 2016-08-22 15:55:26 +02:00
Lajos Nemeséri 3b557ead10 Update Hungarian translation 2016-08-22 15:32:46 +02:00
prculley 87cb2654ab use relative import 2016-08-21 15:07:19 -05:00
Paul Culley a0c96e576f Merge pull request #219 from prculley/CustEvent_42
Cust event 42
2016-08-20 16:15:00 -05:00
prculley 92f444eb7e No need for test files 2016-08-20 16:07:11 -05:00
prculley 9c533916f1 Support for FTM and others Custom Gedcom Event Tags on import 2016-08-20 15:44:56 -05:00
SNoiraud 1f45e8996b 9341: _deeprelationshippath line 98, NoneType in find_deep_relations 2016-08-18 12:13:59 +02:00
SNoiraud f95c8a2036 9341: _deeprelationshippath filter rule, addition of filter rules and classname 2016-08-18 11:44:15 +02:00
SNoiraud 9c10b59c8b Narrativeweb : some dates are incorrect in tar archive. 2016-08-17 00:16:00 +02:00
John Ralls 53dedde014 Update graphviz to 2.38. 2016-08-16 12:12:46 -07:00
John Ralls 47e4b3de25 Change to a binary launcher in Mac app bundles. 2016-08-16 12:12:46 -07:00
SNoiraud 3af32ec258 8250: Gramps crashes when closed while exporting 2016-08-15 10:19:34 +02:00
Zdeněk Hataš 04e123a5ce czech translation update 2016-08-11 14:19:13 +02:00
SNoiraud 70daa4029a 9596: Some events are not shown in familymaps page. 2016-08-08 11:30:57 +02:00
Leonhaeuser 22fb6f2841 update German translation 2016-08-06 23:19:18 +02:00
romjerome eb5c8da8b0 9608: remove old debug bloc (rev 586bd2fc)
special cases generating AttributeError
2016-08-06 11:50:59 +02:00
Paul Culley 586573d289 Merge pull request #216 from prculley/Medi2_42
Medi2 42
2016-08-04 11:28:19 -05:00
prculley 43c1f24c2d Fix whitespace 2016-08-04 11:20:19 -05:00
prculley 998c3c37fc Add GUI and CLI config option to allow easy setting 2016-08-02 16:09:07 -05:00
romjerome a8c32dcb16 Merge pull request #209 from prculley/da_po
update da.po from attached patch file in bug 9609
2016-08-02 14:06:36 +02:00
romjerome 632aada923 Merge pull request #212 from beernarrd/maintenance/gramps42
Bug 9600
2016-08-02 14:01:04 +02:00
Matti Niemelä 883f29901f Update Finnish translation 2016-08-02 13:54:08 +02:00
Bernard Banko 32d7c236e8 semptember corrected to september and update to latest pot 2016-08-02 00:17:20 +02:00
prculley 13b3de4955 update da.po from attached patch file in bug 9609 2016-08-01 11:19:56 -05:00
prculley c83326a4d6 bug 9549 Chinese characters are not rendered properly in pdf reports 2016-07-30 11:19:22 -05:00
prculley 1cada500de Gedcom import media improvements part 2
This PR supports a variety of changes to Media support, mostly having to do with embedded OBJE tag lines.

- Support v5.5.1 OBJE/FORM/MEDI tag on embedded OBJE
- Change OBJE/BLOB tag from "not understood" to "Recognized but not supported"
- Detect multiple FILEs in a single embedded OBJE >> v5.5.1 feature not supported
- Changed OBJE/FORM/TYPE to internationalize the data (same as SourceMediaType)
- Corrected XREF/OBJE/FORM to correctly save and use its value (was a typo in original code) and to accept any case.
- Added test for missing title on embedded OBJE, and use filename if missing.
- Added test for missing FILE on XREF style OBJE, with warning like the embedded OBJE.
- Support _PRIM tag to handle primary photo for Legacy Family Tree, Ancestral Quest, Family Origins, MyHeritage Family Tree Builder, and others.
- Some of these changes would have required making patches to six different nearly identical pieces of code.  So I combined the similar methods and the two functions they called into a single function.
- Added function to check for a subordinate line with a specific tag, and report unexpected lines as not understood.  Used that function in OBJE/REFN/TYPE and OBJE/_PRIM processing.
- Test files imp_FTM_PHOTO.ged and imp_MediaTest.ged have been updated to include testing on these changes.
2016-07-30 10:39:15 -05:00
Paul Culley a6126dbd03 Merge pull request #205 from prculley/42update
backporting some changes to Gramps42 libgedcom
2016-07-28 08:58:22 -05:00
prculley 92d2181621 backporting some changes to Gramps42 libgedcom
Backport of some changes from master:
Minor textual changes:
  GRAMPS > Gramps
  place_displayer > _pd
  __object_ > __media_
  object_parse_tbl > media_parse_tbl
  __find_object_handle > __find_media_handle
  __find_or_create_object > __find_or_create_media
  build_media_object > build_media
  and a few pylint related spacing changes
Sorting of Sources bug9475
Change "class xxx(object)" to "class xxx"
Use "with open" instead of "try: except:"
change "raise NotImplemented" to "raise NotImplementedError()"
2016-07-28 08:46:00 -05:00
prculley 018f60c826 fix Trailing Whitespace on libgedcom.py 2016-07-27 15:40:42 -05:00
Nick Hall 194bafd484 9427: Add new argument to IsEnclosedByRule 2016-07-26 18:35:05 +01:00
SNoiraud 93422189fe Narrativeweb : place title must agree the references.place-auto configuration 2016-07-26 09:23:23 +02:00
Doug Blank 6ade6ba419 Merge pull request #203 from prculley/csv
CSV backport to gramps42 for bug 9501 and 9499
2016-07-17 11:36:02 -04:00
prculley 802bab7bbe CSV backport to gramps42 for bug 9501 and 9499 2016-07-17 10:13:30 -05:00
Matti Niemelä 191bda5418 update Finnish holidays 2016-07-16 20:25:45 -07:00
Paul Franklin cfdbbf7260 Revert "update Finnish holidays"
This reverts commit 718410e28f.
2016-07-16 20:14:10 -07:00
Matti Niemelä 718410e28f update Finnish holidays 2016-07-16 20:06:17 -07:00
Jérôme Rapinat c46a4c4351 9578: Some strings in tools and report dialogs will not translate 2016-07-16 16:56:58 -07:00
Doug Blank 42f9f4701c Merge pull request #200 from prculley/Ged1_42
Bug 9575, Gedcom import improvements in media area to support v5.5.1 and FTM
2016-07-16 17:20:25 -04:00
prculley 016db63648 Bug 9575, Gedcom import improvements in media area to support v5.5.1 and FTM 2016-07-16 15:28:57 -05:00
Doug Blank 57902a4333 Merge pull request #199 from prculley/FTM_LINK_42
Gedcom import of FTM .ged file containing _LINK tags not supported gramps42
2016-07-16 16:03:04 -04:00
prculley e3e61191ba Trailing whitespace 2016-07-16 13:58:58 -05:00
prculley d985980ad7 Gedcom import of FTM .ged file containing _LINK tags not supported 2016-07-16 13:52:10 -05:00
John Ralls 3cdc1bd988 Change pycairo-python3 to pycairo.
pycairo for python2 is now py2cairo.
2016-07-16 10:40:25 -07:00
John Ralls e311de1964 Remove pango modules from bundle, pango no longer uses them. 2016-07-16 10:37:37 -07:00
Doug Blank c5a14c94ae Merge pull request #192 from prculley/bug9479_42
Bug 9479 Gedcom import loses spaces in text fields from FTM
2016-07-16 12:03:48 -04:00
prculley 7e234beff7 Typo 2016-07-16 10:50:55 -05:00
Doug Blank 3e21084f02 Merge pull request #197 from prculley/FTM_photo_42
Bug (Feature) 9580 Gedcom import of FTM file containing _PHOTO tags
2016-07-16 11:23:15 -04:00
Doug Blank e53df38c8a Merge pull request #195 from prculley/bug9579_42
bug 9579 Gedcom import of FTM file with OCCU record crashes import
2016-07-16 11:22:22 -04:00
Leonhaeuser b999680f83 update German translation 2016-07-16 10:42:17 +02:00
prculley a19790c5ea Missed self.photo initializer 2016-07-15 09:49:29 -05:00
prculley a49b0792d0 Bug (Feature) 9580 Gedcom import of FTM file containing _PHOTO tags 2016-07-15 09:35:19 -05:00
SNoiraud 5e7b84bdde 9362: Attempting to select an "Available item" for the Book Report gives an error 2016-07-15 12:07:43 +02:00
prculley 2eed3c4ab6 Fix for either valid or invalid FTM Gedcom 2016-07-14 10:48:33 -05:00
prculley b5260704df bug 9579 Gedcom import of FTM file with OCCU record crashes import 2016-07-14 10:48:33 -05:00
vantu5z 28cc175fb5 update russian translation
merge with new template and backporte translations from master
2016-07-14 15:59:58 +03:00
Paul Franklin 73eaf011a0 9570: crash - 'NoneType' object has no attribute 'get_child_ref_list' 2016-07-11 13:53:04 -07:00
SNoiraud f1156c9627 9560: Family Page maps are non-functional in Narrative Web report 2016-07-11 21:22:31 +02:00
prculley a72e6f158c Bug 9479 Gedcom import loses spaces in text fields from FTM 2016-07-08 12:02:34 -05:00
Paul Franklin 2ac3935092 9568: Translated text will not be printed in the program 2016-07-07 11:27:49 -07:00
Leonhaeuser 62f47ffd6d update German translation 2016-07-06 20:55:52 +02:00
SNoiraud 87bd65c855 9566: String not translated in geoplaces 2016-07-06 00:03:35 +02:00
Paul Franklin fd1f290752 9556: Descendant Report does not recognise auto. place title generation 2016-07-02 20:42:26 -07:00
SNoiraud 71a25a9e28 9557: Translated text will not be printed (bad copy/paste) 2016-07-02 23:00:34 +02:00
SNoiraud ef28c52f4c 9557: Translated text will not be printed in the program 2016-07-02 22:21:00 +02:00
SNoiraud ef75fc8c15 Revert "9557 : Translated text will not be printed in the program"
This reverts commit 72a9897283.
2016-07-02 22:18:32 +02:00
SNoiraud 72a9897283 9557 : Translated text will not be printed in the program 2016-07-02 11:04:22 +02:00
SNoiraud 96f2091ee9 8452: Geography : Attempting to print crashes (add parent to dialog) 2016-06-29 08:27:56 +02:00
SNoiraud f24ef15518 8452: Geography : Attempting to print crashes(core dumps python) 2016-06-28 10:47:02 +02:00
prculley be6715cd99 9124: GEDCOM doesn't accept CR as a line terminator
Original code used readline() when file was in binary mode; this works
only if file contains '\n', true only for CRLF and LF line endings.
Switched to file text mode with correct encoding and universal newline
support.
2016-06-27 21:09:43 +01:00
Matti Niemelä 16e2ed4f54 Update finnish holidays 2016-06-24 16:45:07 +02:00
Matti Niemelä 31ad46d73e Update finnish translation 2016-06-24 16:40:20 +02:00
vantu5z 73ee71eb2a Update Russian translation 2016-06-22 10:07:02 +03:00
Paul Franklin 4619dbe1a5 9537: Wrong Numeric date format for cs_CZ locale 2016-06-21 14:15:46 -07:00
vantu5z be1bf15964 Ru.po merged with new template 2016-06-21 11:20:11 +03:00
SNoiraud a9fe12c394 9495: Narrativeweb: inconsistent & incomplete display of place hierarchy labels 2016-06-21 08:00:09 +02:00
Paul Franklin d460e9a6eb Merge pull request #178 from vantu5z/maintenance/gramps42
9529: change translation of trees
2016-06-20 14:46:35 +00:00
vantu5z d4373249f7 9529: change translation of trees 2016-06-20 09:44:15 +03:00
SNoiraud 75f383f90f 9495: Narratedweb : inconsistent & incomplete display of place hierarchy labels 2016-06-18 19:30:36 +02:00
SNoiraud f776dc480e 9494: Narratedweb : surname listing errors for people with multiple partners 2016-06-18 19:28:10 +02:00
romjerome 7d4da1d9ef Minor improvement on french translation 2016-06-12 16:02:29 +02:00
Paul Franklin 7786cdcf4c 9517: [In "Verify" people w/ death event w/o date are not thought dead] 2016-06-11 20:28:03 -07:00
Jérôme Rapinat 2ea2cb135e 9453: While starting gramps, it fails to pop up "tips of the day" 2016-06-07 02:04:25 -07:00
Leonhaeuser 22ad26b7ef Update German translation 2016-06-04 16:31:55 +02:00
Doug Blank dc77d95274 Merge pull request #169 from prculley/bug9459_42
bug 9459 GEDCOM import in CLI mode with .ged file containing ANSEL encoding tries to pop up gui
2016-06-02 17:38:19 -04:00
prculley 8b6bd226af bug 9459 fix merge conflict 2016-06-02 16:14:40 -05:00
Doug Blank 6e0a6c4c87 Merge pull request #168 from prculley/bug9123_42
bug 9123 GEDCOM import with media files that have no path fails
2016-06-02 16:08:22 -04:00
Doug Blank c8d5a40efc Merge pull request #165 from prculley/bug8729
bug 8729 place names empty if Gedcom ADDR record contains no street
2016-06-02 16:08:11 -04:00
Nick Hall 54d9d45486 9472: Use first matching name when generating place titles 2016-05-30 23:07:00 +01:00
prculley 92659145d0 bug 9123 GEDCOM import with media files that have no path fails 2016-05-28 18:08:12 -05:00
SNoiraud 8acb425674 9474: [Geography] Geoclose and mother handle 2016-05-28 22:07:33 +02:00
prculley c8d097269c bug 8729 place names empty if Gedcom ADDR record contains no street 2016-05-28 11:48:03 -05:00
Nick Hall fd4737bfc9 Tidy up place configuration options 2016-05-27 19:30:34 +01:00
Leonhaeuser 4a27671337 update German translation 2016-05-26 22:03:38 +02:00
Nick Hall 5cec72ed04 Use CSS to fade background colour in ValidatableMaskedEntry 2016-05-26 18:27:14 +01:00
Doug Blank 9ad824d56e Merge pull request #157 from prculley/bug7949
Bug 7949, crash on GEDCOM import with empty _AKA lines
2016-05-24 12:14:33 -04:00
prculley b77089e97f Bug 7949, crash on GEDCOM import with empty _AKA lines 2016-05-24 09:26:23 -05:00
Nick Hall 57a963d0b2 9427: Add inclusive option to IsEnclosedBy rule 2016-05-23 15:27:00 +01:00
SNoiraud df55780880 9075: Saving/closing new person window with Alt-o does not find gender 2016-05-23 11:10:02 +02:00
Nick Hall 170d63f378 Fix to allow deferred translation of place type 2016-05-22 22:50:19 +01:00
Nick Hall 31bdd8f5f1 9466: Include all place types in place report 2016-05-22 19:10:07 +01:00
Nick Hall 8f396cb6e9 9314: Allow place selection both individually and by filter
Add the places selected individually to the list generated by
the filter.
2016-05-22 18:26:42 +01:00
Nick Hall f3dcc68a44 8785: Expand tree in selectors automatically 2016-05-22 18:00:57 +01:00
Nick Hall ed936f9975 9381: Fix Encloses gramplet to display correct place references 2016-05-21 18:57:23 +01:00
romjerome 6f94ec8ef3 Update for appdata stuff 2016-05-16 12:15:25 +02:00
Paul Franklin 653e18db5a 9408: UnboundLocalError on ODF doc backend 2016-05-16 11:47:31 +02:00
josip 1e9de5517f 8429: Media Preview: wrong frame
fix signals
2016-05-16 11:38:38 +02:00
Matti Niemelä 9caa89fe3b Update Finnish translation 2016-05-16 11:28:40 +02:00
Sam Manzi 56e640731f Merge pull request #149 from prculley/bug9416
Bug 9416 GEDCOM import PLAC:FORM in local mode doesn't work
2016-05-13 09:31:26 +10:00
Sam Manzi 826c9a4122 Merge pull request #144 from prculley/bug9414
Bug 9414 fix empty Place Alternate Names on import
2016-05-13 08:54:45 +10:00
Sam Manzi d9c095a8d3 Merge pull request #143 from prculley/bug9448
Bug 9448: Merge unit test for PlaceCheck not working correctly
2016-05-13 08:51:40 +10:00
prculley 89e0297881 Bug 9416 GEDCOM import PLAC:FORM in local mode doesn't work 2016-05-12 10:36:57 -05:00
prculley 848fe67ada Bug 9414 fix empty Place Alternate Names on import 2016-05-12 09:27:12 -05:00
prculley 47f798077e Bug 9448: Merge unit test for PlaceCheck not working correctly 2016-05-12 09:14:00 -05:00
Doug Blank 358428181b Merge pull request #129 from prculley/bug9173
Bug 9173, fix broken GEDCOM import PLAC:FORM handling
2016-05-11 17:02:38 -04:00
Doug Blank c48034eca8 Merge pull request #128 from prculley/bug9415
Bug 9415 Place Alt Names gets duplicated entries
2016-05-11 17:02:23 -04:00
Doug Blank f8486d4954 Merge pull request #131 from prculley/bug9425
Bug 9425 GEDCOM import some Place Names & Titles are blank
2016-05-11 16:40:31 -04:00
Doug Blank 9ce3a52d33 Merge pull request #132 from prculley/bug9430
Bug 9430 GEDCOM import PLAC or ADDR attached Notes etc. are lost
2016-05-11 16:40:10 -04:00
erikdrgm d2de684c5e Updated 160510 nl translation 2016-05-10 09:57:44 +02:00
Doug Blank c405b58a75 Merge pull request #136 from RossGammon/app2
Followup to PR 134
2016-05-08 13:52:14 -04:00
Doug Blank e3e787c038 Merge pull request #134 from RossGammon/appstream
9443: Gramps not appearing in Gnome Software
2016-05-08 09:29:12 -04:00
prculley 987f9d0729 Bug 9430 GEDCOM import PLAC or ADDR attached Notes etc. are lost 2016-05-06 12:13:38 -05:00
prculley 9a207499c3 Bug 9425 GEDCOM import some Place Names & Titles are blank 2016-05-06 11:25:24 -05:00
prculley c7d8f6ba6e Bug 9173, fix broken GEDCOM import PLAC:FORM handling 2016-05-06 11:09:50 -05:00
prculley 30fb4916f3 Bug 9415 Place Alt Names gets duplicated entries 2016-05-05 16:07:31 -05:00
Doug Blank c3e0d8c7c0 Merge pull request #126 from prculley/bug8809
Bug 8809 Multiple GEDCOM imports creates duplicate event IDs
2016-05-05 13:22:57 -04:00
prculley a7a8b72df4 Bug 8809 Multiple GEDCOM imports creates duplicate event IDs 2016-05-05 11:45:11 -05:00
SNoiraud e9c076520a 9417: The place page in webreport is complete mess (missing parenthesis) 2016-05-04 20:34:56 +02:00
SNoiraud 8103bb7b4a 9417: The place page in webreport is complete mess 2016-05-04 17:47:44 +02:00
SNoiraud 93882fa9cb 7390: Gallery tab of Source view does not display .ods files 2016-05-04 12:05:57 +02:00
romjerome 2534368419 Typo on french translation 2016-05-01 11:47:54 +02:00
SNoiraud aa71dd095d 9405: Narrated Web report - Individual sort order not correct on the Surnames tab 2016-04-24 22:27:31 +02:00
Sam Manzi 880a583a0f 8981 Specify required GtkSpell and GExiv2 version 2016-04-23 10:20:12 +10:00
SNoiraud 88bdc33051 9377: Narrated web : possible value not defined 2016-04-21 09:03:00 +02:00
SNoiraud 155a03a92f 9377: Narrated web report link to thumbnails is broken on certain pages 2016-04-21 08:41:35 +02:00
SNoiraud f322ab43a6 9389: Narrated Web report - Individual page sort order has changed 2016-04-20 08:33:25 +02:00
John Ralls 29b94e5de8 Bug 8563: Gramps reports that it can't find dictionaries.
Turns out it was really that enchant couldn't find its backend because
an environment variable wasn't set.
2016-04-16 15:07:06 -07:00
Zdeněk Hataš e4573b9b7a czech translation update 2016-04-16 14:40:30 +02:00
John Ralls 73d13ba826 Release 4.2.3 2016-04-11 07:29:24 -07:00
romjerome 0414893c34 bump to 4.2.4 2016-04-10 18:57:46 +02:00
178 changed files with 88462 additions and 96229 deletions
+13
View File
@@ -0,0 +1,13 @@
2018-02-09 prculley <paulr2787@gmail.com>
* gramps/plugins/view/geoclose.py,
gramps/plugins/view/geoevents.py,
gramps/plugins/view/geofamclose.py,
gramps/plugins/view/geofamily.py, gramps/plugins/view/geoperson.py,
gramps/plugins/view/geoplaces.py: Fix Geography views for bad
'dbstate.is_open()' test Fixes #10417
2018-02-08 Nick Hall <nick-h@gramps-project.org>
* Bump to 4.2.8
+8 -8
View File
@@ -33,11 +33,11 @@ all required and optional dependencies. Missing dependencies will
result in runtime errors.
To build and install, whether from a tarball or git repo:
python setup.py build
sudo python setup.py install
python3 setup.py build
sudo python3 setup.py install
You can avoid using sudo for the install step by specifying a prefix to which you have write priviledge. The default is /usr/local, which is usually owned by root. You can learn of more options with
python setup.py --help
python3 setup.py --help
One can use gramps from the command line without installing it by
setting the following environment variables, but that won't provide
@@ -71,7 +71,7 @@ from the source directory.
b) You installed Gramps, and want to start it from the PYTHONPATH. In this
case use the command:
python -c 'from gramps.grampsapp import main; main()'
python3 -c 'from gramps.grampsapp import main; main()'
The executable 'gramps' in /usr/local/bin or /usr/bin from a) does
this for you.
@@ -79,7 +79,7 @@ from the source directory.
b) You downloaded the Gramps source code to a directory, and want to run it.
You can start Gramps from the source code directory with
python Gramps.py
python3 Gramps.py
See gramps/gen/const.py how Gramps finds its resource directories in case
you encounter problems.
@@ -90,17 +90,17 @@ If you would like to install Gramps without being root, or in an
alternative location on windows, supply the --root argument to setup.py
For example:
python setup.py install --root ~/test
python3 setup.py install --root ~/test
Packager's issues
------------------
There is a MANIFEST.in file to indicate the work needed.
To create a source distribution run:
python setup.py sdist
python3 setup.py sdist
If Gramps is built outside of the source tree in a temporary location (e.g. when
packaging for a distribution), the --resourcepath option can be used to specify
the path to the installed location of the Gramps resources (e.g. /usr/share):
python setup.py install --resourcepath=/usr/share
python3 setup.py install --resourcepath=/usr/share
+1
View File
@@ -1,4 +1,5 @@
include AUTHORS
include ChangeLog
include COPYING
include FAQ
include Gramps.py
+207 -8
View File
@@ -1,3 +1,202 @@
2018-02-09
Version 4.2.8
* Fix Geography views for bad 'dbstate.is_open()' test
2018-02-08
Version 4.2.7
* Fix Export View to CSV when Unicode characters are present
* Fix several intl date displayers for missing parameter
* DescendantTree report; fix crashes and Title spacing
* Fix Book XML handler to deal with unusual characters in Book name
* Add support for new genealogy tree report category
* Fix Media Preview Gramplet for closed db
* Suport FTM 2017 Gedcom tags on import
* Fix Person, Family Sidebar Filters to add custom Event types
* Fix QuestionDialog display for html like characters in title
* Fix FamilyRelationshpType _DATAMAP order to correspond with values
* Fix Gedcom import for illegal Gedcom Family Attributes
* Fix Gedcom export for bad Hebrew Months
* Change INSTALL to replace 'python' with 'python3 for script invokes
* Fix CSV importer for place event name using gramps_id
* Fix Geography view 'Find' when db is closed
* Fix interactive search for exception on click then down arrow
* Create where_is utility to locate a binary in the standard places
* Fix relationship Graph so Unicode chars on Multiple pages works
* Update authors file
* Fix Gedcom import for "1 MARR Y" issue
* Fix Export Web Family Tree for errors on file write
* Fix Citation Editor to Tab out of Confidence ComboBox
* Reset the dependencies on the new meta-module
* Use online modules
* Consolidate Python2 and Python3 meta-modules
* Use None as the foreground colour for untagged rows in list views
* Fix shading colour in relationship view for dark themes
* Fix link colour for dark themes
* Fix default foreground colour in list views for dark themes
* Fix Undo; crashes due to race in Gtk
* Gedcom import with OBJE/FORM URL on event
* EOFError [Ran out of input] in Clipboard
* Cannot drag & drop textual value via clipboard
* Fix 'DbBsddbRead' object has no attribute '_Callback__callback_map'
* Reports - Narrated Web Site Failure
* Fix link path in gramps-launcher compile instructions
* Update translations: fi, de
2017-08-01
Version 4.2.6
* Fix HasCitation rule in citation filter sidebar
* Fix use of regular expressions
* Date Editor had 'Type' and 'Quality' labels swapped
* Fix FamilyGroup Report
* Fix names not displayed in relationship graph
* Fix outdated Bugtracker link in reporting wizard
* Fix replacements in Ancestor tree
* Fix Default Browser Setting
* Fix linking place on OpenStreetMap view
* Fix Family Lines Report having unescaped characters
* Fix non-local character in DB name (Windows OS)
* Fix checking for "event.string" in "treeview_keypress"
* Fix invalid February 29th date in Julian dual-dated
* Fix Note on CIR when it is attached to a (preferred or alternative) name through the names dialog.
* Improve time loading for person selector in census forms
* Fix incorrect SoundEx result
* Fix Error printing on ancestor tree graphical report
* Fix custom filter creation with 'Events occurring on a particular day of the week'
* Bug in the Name Editor / Group As
* Gramps CSV export of Places did not generate correct Title.
* Add custom Family Relations not shown in the filter siderbar
* Fix non-textual value on Tag report
* Fix 'interface.dont-ask' config key ignored on Note edition
* Fix Reorder Relationships dialog
* Shrink size of Break Lock (and other QuestionDialogs)
* Only selection of Active or Home person if commited
* Fix quick search exception when nothing in searched list
* Fix problem adding parents
* Fix bookmarks keybinding on Mac
* Fix failure to load default gramplets if GExiv2 is missing or too old.
* Update API doc for place displayer
* Add datestrings to Turkish translation
* Update translations: cs, de, fr, fi, hu, it, ru, sl, sv, tr
2016-12-15
Version 4.2.5
* The configparser is assuming the wrong encoding
* Sorting in family tab of narrated web report
* Silence remaining PyGIWarning
* Sorting of relationships in family tab of narrated web report
* Use latest valid date rather than today
* Modify endonym handling in place displayer
* Fix house number concatenation
* Allow merging of families with one or more parents in common
* Jump to Gramps ID functionality doesn't work
* Ability to search alternate place names when selecting place
* Fix clear map action on Geography
* Database repair tool always edit all source objects
* Database repair tool ignored some objects with tag
* "Enclosing" gramplet includes places outside valid date ranges
* Fix icon and tooltip in LDS editor
* CSV import fails
* Fix duplicated Gramps IDs on Gedcom import
* Unexpected error Preferences > Dates > Markup for invalid date format
* Fix Import Vcard, can create multiple surnames with all selected as 'Primary'
* Fix Gedcom import in some alternate languages; improper date parsing
* Export options 'Preview' buttons create hidden quickreport
* Alignment radio buttons in the style editor do not work
* Select Place search & Source/Citation hierarchy should NOT be expanded
* Tweak improvement on Tag editor
* Support for Windows Python3 pythonw.exe
* Wrong parsing Numeric date format for cs_CZ locale
* Fix Norwegian relationship calculator
* Fix Icelandic and German translations
* Update translations: cs, de, fi, fr, hu, is, nb, ru
2016-09-04
Version 4.2.4
* fixes for the PHON, FAX, EMAIL and WWW Gedcom tags to support Gedcom v5.5.1
* use more relative import
* Support for FTM and others Custom Gedcom Event Tags on import
* fix '_deeprelationshippath' filter rule
* Narrativeweb: some dates are incorrect in tar archive.
* MacOS: Update graphviz to 2.38 and change to a binary launcher in app bundles.
* Gramps crashes when closed while exporting
* Some events are not shown in familymaps page.
* Remove old debug bloc on place selection.
* Add GUI and CLI config option to allow easy setting
* Chinese characters are not rendered properly in pdf reports
* Support v5.5.1 OBJE/FORM/MEDI tag on embedded OBJE
* Sorting of Sources on gedcom
* Change "class xxx(object)" to "class xxx"
* Use "with open" instead of "try: except:"
* Change "raise NotImplemented" to "raise NotImplementedError()"
* Add new argument to IsEnclosedByRule
* Narrativeweb: place title must agree the references.place-auto configuration
* Improvements on CSV file format support
* update Finnish holidays
* Some strings in tools and report dialogs will not translate
* Gedcom import improvements in media area to support v5.5.1 and FTM
* Trailing whitespace
* Gedcom import of FTM .ged file containing _LINK tags not supported
* Change pycairo-python3 to pycairo.
* pycairo for python2 is now py2cairo.
* Remove pango modules from bundle, pango no longer uses them.
* Gedcom import loses spaces in text fields from FTM
* Gedcom import of FTM file containing _PHOTO tags
* Missed self.photo initializer
* Attempting to select an "Available item" for the Book Report gives an error
* Fix for either valid or invalid FTM Gedcom
* Gedcom import of FTM file with OCCU record crashes import
* crash - 'NoneType' object has no attribute 'get_child_ref_list'
* Family Page maps are non-functional in Narrative Web report
* Gedcom import loses spaces in text fields from FTM
* String not translated in geoplaces
* Descendant Report does not recognise auto. place title generation
* Translated text will not be printed in the program
* Geography: Attempting to print crashes (add parent to dialog)
* GEDCOM doesn't accept CR as a line terminator
* Wrong Numeric date format for cs_CZ locale
* Narrativeweb: inconsistent & incomplete display of place hierarchy labels
* Narratedweb: surname listing errors for people with multiple partners
* In "Verify" people w/ death event w/o date are not thought dead
* While starting gramps, it fails to pop up "tips of the day"
* GEDCOM import in CLI mode with .ged file containing ANSEL encoding tries to pop up gui
* fix merge conflict
* Use first matching name when generating place titles
* GEDCOM import with media files that have no path fails
* [Geography] Geoclose and mother handle
* place names empty if Gedcom ADDR record contains no street
* Tidy up place configuration options
* Use CSS to fade background colour in ValidatableMaskedEntry
* crash on GEDCOM import with empty _AKA lines
* Add inclusive option to IsEnclosedBy rule
* Saving/closing new person window with Alt-o does not find gender
* Fix to allow deferred translation of place type
* Include all place types in place report
* Allow place selection both individually and by filter on textual report
* Expand tree in selectors automatically
* Fix Encloses gramplet to display correct place references
* Update for appdata stuff
* UnboundLocalError on ODF doc backend
* Media Preview: wrong frame
* fix signals
* GEDCOM import PLAC:FORM in local mode doesn't work
* fix empty Place Alternate Names on import
* Merge unit test for PlaceCheck not working correctly
* GEDCOM import some Place Names & Titles are blank
* GEDCOM import PLAC or ADDR attached Notes etc. are lost
* Gramps not appearing in Gnome Software
* fix broken GEDCOM import PLAC:FORM handling
* Place Alt Names gets duplicated entries
* Multiple GEDCOM imports creates duplicate event IDs
* The place page in webreport is complete mess
* Gallery tab of Source view does not display .ods files
* Narrated Web report - Individual sort order not correct on the Surnames tab
* Specify required GtkSpell and GExiv2 version
* Narrated web report link to thumbnails is broken on certain pages
* Narrated Web report - Individual page sort order has changed
* Gramps reports that it can't find dictionaries.
* Turns out it was really that enchant couldn't find its backend because an environment variable wasn't set.
* Update translations: cs, da, de, fi, fr, hu, pt_BR, ru, sl
2016-04-10
Version 4.2.3
* Creation of the "graphic calendar report" failed
@@ -520,8 +719,8 @@ Version 3.4.4 of Gramps! "The Ministry of Silly Names", a maintenance release.
* fix annoying errors on navigation related to citations gramplet and tag object.
* listing the Family Trees can corrupt them.
* various fix around handling Gedcom file format
* fix citations and sources import on ProGen format
* better date handling and better alternate translation support on some textual reports according to locale under windows
* fix citations and sources import on ProGen format
* better date handling and better alternate translation support on some textual reports according to locale under windows
* avoid Errors when setting wrong value as markup for invalid dates (Preferences)
* fix paragraph layout on PDF format or print output
* New: New-Zealand holidays
@@ -539,7 +738,7 @@ Version 3.4.3 of Gramps! "Whenever life gets you down, Mrs. Brown", a maintenanc
* Sorting (both in the main display window, and particularly in Narrative Web output) now uses PyICU (if that module is available). Inclusion of PyICU is 'strongly recommended'. This resolves a number of bugs particularly related to sorting of non-Latin characters, and sorting on MS Windows and Mac OS X. Some changes have been made in Narrative Web to support contractions for alphabetic indices.
* The automatic Addon checking and download now works once again (the location used in Gramps 3.4.2 and before had been changed, so the the automatic process was no longer working).
* Import from Pro-Gen has been updated (at last) to take account of the change to Citations (in 3.4.0)
* Import and Export of address fields in GEDCOM has been improved so that the round-trip works properly.
* Import and Export of address fields in GEDCOM has been improved so that the round-trip works properly.
* GEDCOM Repositories not imported correctly from FTM for Windows and Heredis.
* Fixes to a number of errors in filtering notes.
* Fix some errors in determining whether someone is alive (e.g. for filtering out alive people).
@@ -548,7 +747,7 @@ Version 3.4.3 of Gramps! "Whenever life gets you down, Mrs. Brown", a maintenanc
* Fixed update problems with citation bottombar gramplet (bug #6336)
* Fixed Open Document Text output in Book report (bug #6457)
* A number of changes to Narrative Web:
** Media objects attached to Marriage events and Sources are not included in Narrative Web Site
** Media objects attached to Marriage events and Sources are not included in Narrative Web Site
** restructure the families index so families are indexed under both spouses, and the family name is normalised
** separate out Families section in individual and families pages so individual page links to the family page and family page links to both people
** normalise links to families so the link is only displayed if the family page is present, and the gid is included when appropriate
@@ -566,7 +765,7 @@ Version 3.4.3 of Gramps! "Whenever life gets you down, Mrs. Brown", a maintenanc
** Implemented a generalised back reference function to display the 'References' section of all pages. This recursively displays references till one is found for which a page exists.
** Removed list of people and families from heading of the event pages as these are now in the 'References' section.
** Fixed bug "0005968: Narrated Web Site not copying Source Citations files such as jpg or pdf docs to web site
** Fixed bug "0005946 GRAMPS failed to insert jpeg image into proper place for an event" by displaying a thumbnail for citation media in the 'Source References' section (with a link to the media page)
** Fixed bug "0005946 GRAMPS failed to insert jpeg image into proper place for an event" by displaying a thumbnail for citation media in the 'Source References' section (with a link to the media page)
** Tidy up media pages - remove unused parameters, use list of media items generated in first pass. Should fix bugs 2365, 5905 and 6009.
** Tidy up sources pages - fix numbering of repositories, remove unused parameters, fix title of individual source pages
** Bug: reset NarrWeb navigation menu layout when style sheet doesn't support it
@@ -574,7 +773,7 @@ Version 3.4.3 of Gramps! "Whenever life gets you down, Mrs. Brown", a maintenanc
** Fix option to suppress Gramps ID (bug #6237)
* a number of technical changes to Narrative Web
** Removed a lot of redundant code and parameters (mainly connected with the old way of determining the objects to be included in the report).
** Movement of some large chunks of code within the source file and some initial work towards GEPS 022: Narrative Website Refactor. Functionality should be unchanged.
** Movement of some large chunks of code within the source file and some initial work towards GEPS 022: Narrative Website Refactor. Functionality should be unchanged.
** Moved routines for calculating objects to be output so they can be part of default list building classes.
* Various updated translations: da, de, es, fr, it, nb, nl, pt_BR, pt_PT, sv, uk
@@ -766,7 +965,7 @@ Version 3.1.3 -- the "What name?" release.
2009-06-06
Version 3.1.2 -- the "Skip the impersonations" release.
* Contains translation updates and small bug fixes. No new features.
* ca, cs, de, fr, he, it, nb, nl, pl, pt_br, ru, sk, sv,
* ca, cs, de, fr, he, it, nb, nl, pl, pt_br, ru, sk, sv,
* fixes a failure in 'Check & Repair Database'
* fixes to Gramplets
* fixes to CLI regressions
@@ -879,7 +1078,7 @@ Version 2.2.5 -- the "Now go away or I shall taunt you a second time" release
Version 2.2.4 -- the "When you're chewing on life's gristle, Don't grumble, give a whistle" release
* Improved handling of readonly files
* Enhanced parsing of longitute and latitude and mapping
* Enhanced parsing of longitute and latitude and mapping
(Benny Malengier/Zsolt Foldvari)
* Check and repair improvements
* Reference map rebuild tool
+3
View File
@@ -94,6 +94,9 @@
<author title="contributor">
Nick Hall &lt;<html:a href="mailto:nick__hall@hotmail.com">nick__hall@hotmail.com</html:a>&gt;
</author>
<author title="contributor">
Paul Culley &lt;<html:a href="mailto:paulr2787@gmail.com">paulr2787@gmail.com</html:a>&gt;
</author>
<author title="contributor">
Peter Landgren &lt;<html:a href="mailto:peter.talken@telia.com">peter.talken@telia.com</html:a>&gt;
</author>
+31 -17
View File
@@ -1,18 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<application>
<id type="desktop">gramps.desktop</id>
<licence>CC0</licence>
<description>
<_p>Gramps is a genealogy program that is both intuitive for hobbyists and feature-complete for professional genealogists.</_p>
<_p>It gives you the ability to record the many details of the life of an individual as well as the complex relationships between various people, places and events.</_p>
<_p>All of your research is kept organized, searchable and as precise as you need it to be.</_p>
</description>
<url type="homepage">http://gramps-project.org/</url>
<screenshots>
<screenshot width="1226" height="740">http://www.gramps-project.org/wiki/images/5/5f/AppData1.png</screenshot>
<screenshot width="1226" height="740">http://www.gramps-project.org/wiki/images/6/68/AppData2.png</screenshot>
<screenshot type="default" width="1226" height="740">http://www.gramps-project.org/wiki/images/e/e9/AppData3.png</screenshot>
<screenshot width="1226" height="740">http://www.gramps-project.org/wiki/images/6/68/AppData4.png</screenshot>
<screenshot width="1226" height="740">http://www.gramps-project.org/wiki/images/5/50/AppData5.png</screenshot>
</screenshots>
</application>
<component type="desktop">
<id>gramps.desktop</id>
<metadata_license>CC0</metadata_license>
<name>Gramps</name>
<summary>Genealogical research program</summary>
<description>
<_p>Gramps is a genealogy program that is both intuitive for hobbyists and feature-complete for professional genealogists.</_p>
<_p>It gives you the ability to record the many details of the life of an individual as well as the complex relationships between various people, places and events.</_p>
<_p>All of your research is kept organized, searchable and as precise as you need it to be.</_p>
</description>
<url type="homepage">https://gramps-project.org/</url>
<url type="bugtracker">https://gramps-project.org/bugs/</url>
<url type="help">https://gramps-project.org/wiki/index.php?title=Main_page</url>
<project_license>GPL-2.0+</project_license>
<developer_name>Gramps Development Team</developer_name>
<screenshots>
<screenshot width="1226" height="740">http://www.gramps-project.org/wiki/images/5/5f/AppData1.png</screenshot>
<screenshot width="1226" height="740">http://www.gramps-project.org/wiki/images/6/68/AppData2.png</screenshot>
<screenshot type="default" width="1226" height="740">http://www.gramps-project.org/wiki/images/e/e9/AppData3.png</screenshot>
<screenshot width="1226" height="740">http://www.gramps-project.org/wiki/images/6/68/AppData4.png</screenshot>
<screenshot width="1226" height="740">http://www.gramps-project.org/wiki/images/5/50/AppData5.png</screenshot>
</screenshots>
<provides>
<binary>gramps</binary>
</provides>
</component>
+2 -2
View File
@@ -92,9 +92,9 @@ gramps(1) @VERSION@ gramps(1)
might produce different gramps IDs in the resulting database.
**-e** , **--export=** *FICHIER*
**-e** , **--export=** *FILE*
Export data into *FILE* . For **gramps-xml** , **gedcom**
, **wft** , **gramps-pkg** , et **geneweb** , the *FILE* is the
, **wft** , **gramps-pkg** , and **geneweb** , the *FILE* is the
name of the resulting file.
When more than one output file is given, each has to be preceded
+1
View File
@@ -31,6 +31,7 @@ Depends:
${python3:Depends}
Recommends:
graphviz,
gir1.2-goocanvas-2.0,
libosmgpsmap-1.0-0,
gir1.2-osmgpsmap-1.0,
python3-pyicu
+8
View File
@@ -10,3 +10,11 @@ Name
:members:
:undoc-members:
:show-inheritance:
Place
====================================
.. automodule:: gramps.gen.display.place
:members:
:undoc-members:
:show-inheritance:
+27 -4
View File
@@ -46,7 +46,8 @@ log = logging.getLogger(".")
#-------------------------------------------------------------------------
from gramps.gen.plug import BasePluginManager
from gramps.gen.plug.docgen import (StyleSheet, StyleSheetList, PaperStyle,
PAPER_PORTRAIT, PAPER_LANDSCAPE, graphdoc)
PAPER_PORTRAIT, PAPER_LANDSCAPE, graphdoc,
treedoc)
from gramps.gen.plug.menu import (FamilyOption, PersonOption, NoteOption,
MediaOption, PersonListOption, NumberOption,
BooleanOption, DestinationOption, StringOption,
@@ -54,8 +55,8 @@ from gramps.gen.plug.menu import (FamilyOption, PersonOption, NoteOption,
from gramps.gen.display.name import displayer as name_displayer
from gramps.gen.errors import ReportError, FilterError
from gramps.gen.plug.report import (CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_BOOK,
CATEGORY_GRAPHVIZ, CATEGORY_CODE,
ReportOptions, append_styles)
CATEGORY_GRAPHVIZ, CATEGORY_TREE,
CATEGORY_CODE, ReportOptions, append_styles)
from gramps.gen.plug.report._paper import paper_sizes
from gramps.gen.const import USER_HOME
from gramps.gen.dbstate import DbState
@@ -233,6 +234,15 @@ class CommandLineReport(object):
if name not in self.option_class.options_dict:
self.option_class.options_dict[name] = \
menu.get_option_by_name(name).get_value()
if category == CATEGORY_TREE:
# Need to include Genealogy Tree options
self.__toptions = treedoc.TreeOptions()
menu = self.option_class.menu
self.__toptions.add_menu_options(menu)
for name in menu.get_all_option_names():
if name not in self.option_class.options_dict:
self.option_class.options_dict[
name] = menu.get_option_by_name(name).get_value()
self.option_class.load_previous_values()
_validate_options(self.option_class, database)
self.show = options_str_dict.pop('show', None)
@@ -301,6 +311,10 @@ class CommandLineReport(object):
for graph_format in graphdoc.FORMATS:
self.options_help['off'][2].append(
graph_format["type"] + "\t" + graph_format["descr"] )
elif self.category == CATEGORY_TREE:
for tree_format in treedoc.FORMATS:
self.options_help['off'][2].append(
tree_format["type"] + "\t" + tree_format["descr"])
else:
self.options_help['off'][2] = "NA"
@@ -478,6 +492,15 @@ class CommandLineReport(object):
# Pick the first one as the default.
self.format = graphdoc.FORMATS[0]["class"]
_chosen_format = graphdoc.FORMATS[0]["type"]
elif self.category == CATEGORY_TREE:
for tree_format in treedoc.FORMATS:
if tree_format['type'] == self.options_dict['off']:
if not self.format: # choose the first one, not the last
self.format = tree_format["class"]
if self.format is None:
# Pick the first one as the default.
self.format = tree_format.FORMATS[0]["class"]
_chosen_format = tree_format.FORMATS[0]["type"]
else:
self.format = None
if _chosen_format and _format_str:
@@ -640,7 +663,7 @@ def cl_report(database, name, category, report_class, options_class,
clr.selected_style,
PaperStyle(clr.paper,clr.orien,clr.marginl,
clr.marginr,clr.margint,clr.marginb))
elif category == CATEGORY_GRAPHVIZ:
elif category in [CATEGORY_GRAPHVIZ, CATEGORY_TREE]:
clr.option_class.handler.doc = clr.format(
clr.option_class,
PaperStyle(clr.paper,clr.orien,clr.marginl,
+1
View File
@@ -283,6 +283,7 @@ register('paths.quick-backup-filename',
register('preferences.date-format', 0)
register('preferences.calendar-format-report', 0)
register('preferences.cprefix', 'C%04d')
register('preferences.alternate-fonthandler', False)
register('preferences.default-source', False)
register('preferences.tag-on-import', False)
register('preferences.tag-on-import-format', _("Imported %Y/%m/%d %H:%M:%S"))
+4 -4
View File
@@ -55,8 +55,8 @@ from gramps.version import VERSION, VERSION_TUPLE, major_version
#-------------------------------------------------------------------------
URL_HOMEPAGE = "http://gramps-project.org/"
URL_MAILINGLIST = "http://sourceforge.net/mail/?group_id=25770"
URL_BUGHOME = "http://bugs.gramps-project.org"
URL_BUGTRACKER = "http://bugs.gramps-project.org/bug_report_page.php"
URL_BUGHOME = "http://gramps-project.org/bugs"
URL_BUGTRACKER = "http://gramps-project.org/bugs/bug_report_page.php"
URL_WIKISTRING = "http://gramps-project.org/wiki/index.php?title="
URL_MANUAL_PAGE = "Gramps_%s_Wiki_Manual" % major_version
URL_MANUAL_DATA = '%s_-_Entering_and_editing_data:_detailed' % URL_MANUAL_PAGE
@@ -132,7 +132,7 @@ 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 += git_revision
#VERSION += "-1"
#
@@ -190,7 +190,7 @@ GTK_GETTEXT_DOMAIN = 'gtk30'
#
#-------------------------------------------------------------------------
COPYRIGHT_MSG = "© 2001-2006 Donald N. Allingham\n" \
"© 2007-2016 The Gramps Developers"
"© 2007-2018 The Gramps Developers"
COMMENTS = _("Gramps\n (Genealogical Research and Analysis "
"Management Programming System)\n"
"is a personal genealogy program.")
+7 -1
View File
@@ -171,6 +171,9 @@ class DateParserCZ(DateParser):
'vyp.' : Date.QUAL_CALCULATED,
}
# bug 9739 _grampslocale.py gets '%-d.%-m.%Y' and makes it be '%/d.%/m.%Y'
fmt = DateParser.fmt.replace('/', '') # so counteract that
def init_strings(self):
DateParser.init_strings(self)
self._text2 = re.compile('(\d+)?\.?\s+?%s\.?\s*((\d+)(/\d+)?)?\s*$'
@@ -225,7 +228,10 @@ class DateDisplayCZ(DateDisplay):
display = DateDisplay.display_formatted
def orig_display(self, date):
# bug 9537 _grampslocale.py gets '%-d.%-m.%Y' and makes it be '%/d.%/m.%Y'
_tformat = DateDisplay._tformat.replace('/', '') # so counteract that
def orig_display(self, date): # unused: only here for historical reference
"""
Return a text string representing the date.
"""
+1 -1
View File
@@ -221,7 +221,7 @@ class DateDisplayDE(DateDisplay):
)
# this definition must agree with its "_display_gregorian" method
def _display_gregorian(self, date_val):
def _display_gregorian(self, date_val, **kwargs):
"""
display gregorian calendar date in different format
"""
+1 -1
View File
@@ -155,7 +155,7 @@ class DateDisplayEL(DateDisplay):
)
# this definition must agree with its "_display_gregorian" method
def _display_gregorian(self, date_val):
def _display_gregorian(self, date_val, **kwargs):
"""
display gregorian calendar date in different format
"""
+1 -1
View File
@@ -185,7 +185,7 @@ class DateDisplayLT(DateDisplay):
"mmmm-MM-DD (ISO)", "mmmm m. mėnesio diena d.", "Mėn diena, metai")
# this definition must agree with its "_display_gregorian" method
def _display_gregorian(self, date_val):
def _display_gregorian(self, date_val, **kwargs):
"""
display gregorian calendar date in different format
"""
+1 -1
View File
@@ -164,7 +164,7 @@ class DateDisplayNL(DateDisplay):
)
# this definition must agree with its "_display_gregorian" method
def _display_gregorian(self, date_val):
def _display_gregorian(self, date_val, **kwargs):
"""
display gregorian calendar date in different format
"""
+1 -1
View File
@@ -215,7 +215,7 @@ class DateDisplayPL(DateDisplay):
"XII"
)
def _display_gregorian(self, date_val):
def _display_gregorian(self, date_val, **kwargs):
"""
display gregorian calendar date in different format
"""
+1 -1
View File
@@ -240,7 +240,7 @@ class DateDisplaySR_Base(DateDisplay):
"VII", "VIII", "IX", "X", "XI", "XII"
)
def _display_gregorian(self, date_val):
def _display_gregorian(self, date_val, **kwargs):
"""
display gregorian calendar date in different format
"""
+5 -6
View File
@@ -194,6 +194,7 @@ class DateParser(object):
_locale = GrampsLocale(lang='en', languages='en')
fmt = _grampslocale.tformat
_fmt_parse = re.compile(".*%(\S).*%(\S).*%(\S).*")
# RFC-2822 only uses capitalized English abbreviated names, no locales.
@@ -343,8 +344,7 @@ class DateParser(object):
Date.CAL_SWEDISH : self._parse_swedish,
}
fmt = _grampslocale.tformat
match = self._fmt_parse.match(fmt.lower())
match = self._fmt_parse.match(self.fmt.lower())
if match:
self.dmy = (match.groups() == ('d', 'm', 'y') or \
match.groups() == ('d', 'b', 'y'))
@@ -597,12 +597,11 @@ class DateParser(object):
y = self._get_int(groups[0])
m = self._get_int(groups[3])
d = self._get_int(groups[4])
if check and not check((d, m, y)):
return Date.EMPTY
if groups[2]: # slash year digit
if groups[2] and julian_valid((d, m, y + 1)): # slash year digit
return (d, m, y + 1, True)
else:
if check is None or check((d, m, y)):
return (d, m, y, False)
return Date.EMPTY
# Database datetime format, used in ex. MSSQL
# YYYYMMDD HH:MM:SS or YYYYMMDD or YYYYMMDDHHMMSS
+9 -7
View File
@@ -763,11 +763,11 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
# The DB_PRIVATE flag must go if we ever move to multi-user setup
env_flags = db.DB_CREATE | db.DB_PRIVATE |\
db.DB_INIT_MPOOL |\
db.DB_INIT_LOG | db.DB_INIT_TXN
# As opposed to before, we always try recovery on databases
env_flags |= db.DB_RECOVER
db.DB_INIT_MPOOL
if not self.readonly:
env_flags |= db.DB_INIT_LOG | db.DB_INIT_TXN
# As opposed to before, we always try recovery on databases
env_flags |= db.DB_RECOVER
# Environment name is now based on the filename
env_name = name
@@ -782,7 +782,8 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
pass
raise DbEnvironmentError(msg)
self.env.txn_checkpoint()
if not self.readonly:
self.env.txn_checkpoint()
if callback:
callback(25)
@@ -1478,7 +1479,8 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
return
if self.txn:
self.transaction_abort(self.transaction)
self.env.txn_checkpoint()
if not self.readonly:
self.env.txn_checkpoint()
self.__close_metadata()
self.name_group.close()
+10 -5
View File
@@ -65,13 +65,18 @@ class PlaceDisplay(object):
else:
places = places[index:]
names = [item[0] for item in places]
if config.get('preferences.place-number'):
if len(places) > 1 and int(places[0][1]) == PlaceType.NUMBER:
names = names[1:]
names[0] = places[0][0] + ' ' + names[0]
types = [item[1] for item in places]
try:
idx = types.index(PlaceType.NUMBER)
except ValueError:
idx = None
if idx is not None and len(places) > idx+1:
combined = (places[idx][0] + ' ' + places[idx+1][0],
places[idx+1][1])
places = places[:idx] + [combined] + places[idx+2:]
names = [item[0] for item in places]
if config.get('preferences.place-reverse'):
names.reverse()
+3
View File
@@ -166,6 +166,9 @@ class FilterParser(handler.ContentHandler):
# HasEvent rule has extra primary role field in v3.4.7
if self.r == rules.person.HasEvent and len(self.a) == 5:
self.a.append('1')
# IsEnclosedBy rule has extra inclusive field in v4.2.4
if self.r == rules.place.IsEnclosedBy and len(self.a) == 1:
self.a.append('0')
#-------------------------------------------------------------------------
#
+1 -3
View File
@@ -82,9 +82,7 @@ class Rule(object):
for i in range(len(self.labels)):
if self.list[i]:
try:
self.regex[i] = re.compile(
str(self.list[i]),
re.I|re.U|re.L)
self.regex[i] = re.compile(self.list[i], re.I)
except re.error:
self.regex[i] = re.compile('')
self.match_substring = self.match_regex
@@ -68,8 +68,8 @@ def get_family_handle_people(db, exclude_handle, family_handle):
def possibly_add_handle(h):
if h != None and h != exclude_handle:
people.add(db.get_person_from_handle(h))
people.add(h)
possibly_add_handle(family.get_father_handle())
possibly_add_handle(family.get_mother_handle())
@@ -94,7 +94,9 @@ def get_person_family_people(db, person, person_handle):
def find_deep_relations(db, progress, person, path, seen, target_people):
if len(target_people) < 1:
return []
if person is None:
return []
handle = person.get_handle()
if handle in seen:
return []
@@ -109,7 +111,8 @@ def find_deep_relations(db, progress, person, path, seen, target_people):
family_people = get_person_family_people(db, person, handle)
for family_person in family_people:
return_paths += find_deep_relations(db, progress, family_person, person_path, seen, target_people)
pers = db.get_person_from_handle(family_person)
return_paths += find_deep_relations(db, progress, pers, person_path, seen, target_people)
if progress: progress.step()
return return_paths
@@ -45,7 +45,7 @@ class IsEnclosedBy(Rule):
Rule that checks for a place enclosed by another place
"""
labels = [_('ID:')]
labels = [_('ID:'), _('Inclusive:')]
name = _('Places enclosed by another place')
description = _('Matches a place enclosed by a particular place')
category = _('General filters')
@@ -59,6 +59,8 @@ class IsEnclosedBy(Rule):
def apply(self, db, place):
if self.handle is None:
return False
if self.list[1] == '1' and place.handle == self.handle:
return True
if located_in(db, place.handle, self.handle):
return True
return False
+4 -4
View File
@@ -49,11 +49,11 @@ class FamilyRelType(GrampsType):
_DEFAULT = MARRIED
_DATAMAP = [
(UNKNOWN, _("Unknown"), "Unknown"),
(CUSTOM, _("Custom"), "Custom"),
(MARRIED, _("Married"), "Married"),
(UNMARRIED, _("Unmarried"), "Unmarried"),
(CIVIL_UNION, _("Civil Union"), "Civil Union"),
(UNMARRIED, _("Unmarried"), "Unmarried"),
(MARRIED, _("Married"), "Married"),
(UNKNOWN, _("Unknown"), "Unknown"),
(CUSTOM, _("Custom"), "Custom"),
]
def __init__(self, value=None):
Regular → Executable
+8 -4
View File
@@ -577,9 +577,13 @@ class Place(CitationBase, NoteBase, MediaBase, UrlBase, PrimaryObject):
:param acquisition: instance to merge
:type acquisition: :class:'~.place.Place
"""
if acquisition.name and (acquisition.name not in self.alt_names):
self.alt_names.append(acquisition.name)
if acquisition.name.value:
if acquisition.name != self.name:
if acquisition.name not in self.alt_names:
self.alt_names.append(acquisition.name)
for addendum in acquisition.alt_names:
if addendum not in self.alt_names:
self.alt_names.append(addendum)
if addendum.value:
if addendum != self.name:
if addendum not in self.alt_names:
self.alt_names.append(addendum)
Regular → Executable
+6
View File
@@ -200,6 +200,12 @@ class PlaceName(SecondaryObject, DateBase):
else:
return EQUAL
def __eq__(self, other):
return self.is_equal(other)
def __ne__(self, other):
return not self.is_equal(other)
def set_value(self, value):
"""
Set the name for the PlaceName instance.
+28 -4
View File
@@ -1389,8 +1389,14 @@ class PlaceCheck(unittest.TestCase, PrivacyBaseTest, MediaBaseTest,
def setUp(self):
self.phoenix = Place()
self.phoenix.set_title('Place 1')
self.titanic = Place(self.phoenix)
self.ref_obj = Place(self.phoenix)
# __init__ copy has bad side effects, don't use it
# self.titanic = Place(self.phoenix)
self.titanic = Place()
self.titanic.set_title('Place 1')
# __init__ copy has bad side effects, don't use it
# self.ref_obj = Place(self.phoenix)
self.ref_obj = Place()
self.ref_obj.set_title('Place 1')
self.amsterdam = PlaceName()
self.amsterdam.set_value('Amsterdam')
self.rotterdam = PlaceName()
@@ -1433,9 +1439,11 @@ class PlaceCheck(unittest.TestCase, PrivacyBaseTest, MediaBaseTest,
self.titanic.add_alternative_name(self.leiden)
self.ref_obj.set_name(self.amsterdam)
self.ref_obj.set_type(PlaceType.CITY)
self.ref_obj.add_alternative_name(self.amsterdam)
self.ref_obj.add_alternative_name(self.rotterdam)
# Base name shouldn't be in alt_names list
# self.ref_obj.add_alternative_name(self.amsterdam)
# alt_names must be in correct order for test to pass
self.ref_obj.add_alternative_name(self.utrecht)
self.ref_obj.add_alternative_name(self.rotterdam)
self.ref_obj.add_alternative_name(self.leiden)
self.phoenix.merge(self.titanic)
self.assertEqual(self.phoenix.serialize(), self.ref_obj.serialize())
@@ -1496,6 +1504,22 @@ class PlaceCheck(unittest.TestCase, PrivacyBaseTest, MediaBaseTest,
self.phoenix.merge(self.titanic)
self.assertEqual(self.phoenix.serialize(), self.ref_obj.serialize())
def test_merge_empty(self):
self.phoenix.set_name(self.amsterdam)
self.phoenix.set_type(PlaceType.CITY)
self.phoenix.add_alternative_name(self.rotterdam)
self.titanic.set_title('Place 2')
# titanic gets empty name
self.titanic.set_type(PlaceType.CITY)
self.titanic.add_alternative_name(self.utrecht)
self.titanic.add_alternative_name(PlaceName()) # empty alt_name
self.ref_obj.set_name(self.amsterdam)
self.ref_obj.set_type(PlaceType.CITY)
self.ref_obj.add_alternative_name(self.rotterdam)
self.ref_obj.add_alternative_name(self.utrecht)
self.phoenix.merge(self.titanic)
self.assertEqual(self.phoenix.serialize(), self.ref_obj.serialize())
class RepoCheck(unittest.TestCase, PrivacyBaseTest, NoteBaseTest, UrlBaseTest):
def setUp(self):
self.phoenix = Repository()
+26 -6
View File
@@ -134,15 +134,35 @@ class MergeFamilyQuery(object):
with DbTxn(_('Merge Family'), self.database) as trans:
phoenix_father = self.database.get_person_from_handle(self.phoenix_fh)
titanic_father = self.database.get_person_from_handle(self.titanic_fh)
self.merge_person(phoenix_father, titanic_father, 'father', trans)
if self.phoenix_fh != self.titanic_fh:
if self.phoenix_fh:
phoenix_father = self.database.get_person_from_handle(
self.phoenix_fh)
else:
phoenix_father = None
if self.titanic_fh:
titanic_father = self.database.get_person_from_handle(
self.titanic_fh)
else:
titanic_father = None
self.merge_person(phoenix_father, titanic_father,
'father', trans)
phoenix_mother = self.database.get_person_from_handle(self.phoenix_mh)
titanic_mother = self.database.get_person_from_handle(self.titanic_mh)
if self.phoenix_mh != self.titanic_mh:
if self.phoenix_mh:
phoenix_mother = self.database.get_person_from_handle(
self.phoenix_mh)
else:
phoenix_mother = None
if self.titanic_mh:
titanic_mother = self.database.get_person_from_handle(
self.titanic_mh)
else:
titanic_mother = None
self.merge_person(phoenix_mother, titanic_mother,
'mother', trans)
self.phoenix = self.database.get_family_from_handle(new_handle)
self.titanic = self.database.get_family_from_handle(old_handle)
self.merge_person(phoenix_mother, titanic_mother, 'mother', trans)
phoenix_father = self.database.get_person_from_handle(self.phoenix_fh)
phoenix_mother = self.database.get_person_from_handle(self.phoenix_mh)
+2 -2
View File
@@ -27,7 +27,7 @@ The "plug" package for handling plugins in Gramps.
from ._plugin import Plugin
from ._pluginreg import (PluginData, PluginRegister, REPORT, TOOL,
CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_CODE,
CATEGORY_WEB, CATEGORY_BOOK, CATEGORY_GRAPHVIZ,
CATEGORY_WEB, CATEGORY_BOOK, CATEGORY_GRAPHVIZ, CATEGORY_TREE,
TOOL_DEBUG, TOOL_ANAL, TOOL_DBPROC, TOOL_DBFIX, TOOL_REVCTL,
TOOL_UTILS, CATEGORY_QR_MISC, CATEGORY_QR_PERSON,
CATEGORY_QR_FAMILY, CATEGORY_QR_EVENT, CATEGORY_QR_SOURCE,
@@ -49,7 +49,7 @@ __all__ = [ "docbackend", "docgen", "menu", Plugin, PluginData,
PluginRegister, BasePluginManager,
ImportPlugin, ExportPlugin, DocGenPlugin,
REPORT, TOOL, CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_CODE,
CATEGORY_WEB, CATEGORY_BOOK, CATEGORY_GRAPHVIZ,
CATEGORY_WEB, CATEGORY_BOOK, CATEGORY_GRAPHVIZ, CATEGORY_TREE,
TOOL_DEBUG, TOOL_ANAL, TOOL_DBPROC, TOOL_DBFIX, TOOL_REVCTL,
TOOL_UTILS, CATEGORY_QR_MISC, CATEGORY_QR_PERSON,
CATEGORY_QR_FAMILY, CATEGORY_QR_EVENT, CATEGORY_QR_SOURCE,
+4 -1
View File
@@ -94,8 +94,10 @@ CATEGORY_CODE = 2
CATEGORY_WEB = 3
CATEGORY_BOOK = 4
CATEGORY_GRAPHVIZ = 5
CATEGORY_TREE = 6
REPORT_CAT = [ CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_CODE,
CATEGORY_WEB, CATEGORY_BOOK, CATEGORY_GRAPHVIZ]
CATEGORY_WEB, CATEGORY_BOOK, CATEGORY_GRAPHVIZ,
CATEGORY_TREE]
#possible tool categories
TOOL_DEBUG = -1
TOOL_ANAL = 0
@@ -1009,6 +1011,7 @@ def make_environment(**kwargs):
'CATEGORY_WEB': CATEGORY_WEB,
'CATEGORY_BOOK': CATEGORY_BOOK,
'CATEGORY_GRAPHVIZ': CATEGORY_GRAPHVIZ,
'CATEGORY_TREE': CATEGORY_TREE,
'TOOL_DEBUG': TOOL_DEBUG,
'TOOL_ANAL': TOOL_ANAL,
'TOOL_DBPROC': TOOL_DBPROC,
+1
View File
@@ -37,3 +37,4 @@ from .textdoc import TextDoc, IndexMark,INDEX_TYPE_ALP, INDEX_TYPE_TOC,\
URL_PATTERN, LOCAL_HYPERLINK, LOCAL_TARGET
from .drawdoc import DrawDoc
from .graphdoc import GVDoc
from .treedoc import TreeDoc
+69 -26
View File
@@ -8,6 +8,8 @@
# Copyright (C) 2007 Brian G. Matherly
# Copyright (C) 2009 Benny Malengier
# Copyright (C) 2009 Gary Burton
# Copyright (C) 2017 Mindaugas Baranauskas
# Copyright (C) 2017 Paul Culley
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -42,7 +44,7 @@ import sys
#-------------------------------------------------------------------------------
from ...const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
from ...utils.file import search_for
from ...utils.file import search_for, where_is
from . import BaseDoc
from ..menu import NumberOption, TextOption, EnumeratedListOption, \
BooleanOption
@@ -101,13 +103,10 @@ if win():
DETACHED_PROCESS = DWORD(0x00000008).value
else:
_DOT_FOUND = search_for("dot")
if search_for("gs") == 1:
_GS_CMD = "gs"
else:
_GS_CMD = ""
#-------------------------------------------------------------------------------
_GS_CMD = where_is("gs")
#------------------------------------------------------------------------------
#
# GVOptions
#
@@ -581,6 +580,7 @@ class GVDocBase(BaseDoc, GVDoc):
def start_subgraph(self, graph_id):
""" Implement GVDocBase.start_subgraph() """
graph_id = graph_id.replace(' ', '_') # for user-defined ID with space
self.write(
' subgraph cluster_%s\n' % graph_id +
' {\n' +
@@ -658,6 +658,8 @@ class GVPsDoc(GVDocBase):
# disappeared. I used 1 inch margins always.
# See bug tracker issue 2815
# :cairo does not work with Graphviz 2.26.3 and later See issue 4164
# recent versions of Graphvis doesn't even try, just puts out a single
# large page.
command = 'dot -Tps:cairo -o"%s" "%s"' % (self._filename, tmp_dot)
if win():
@@ -669,8 +671,8 @@ class GVPsDoc(GVDocBase):
dotversion = str(Popen(['dot', '-V'],
stderr=PIPE).communicate(input=None)[1])
# Problem with dot 2.26.3 and later and multiple pages, which gives "cairo: out of
# memory" If the :cairo is skipped for these cases it gives acceptable
# result.
# memory" If the :cairo is skipped for these cases it gives bad
# result for non-Latin-1 characters (utf-8).
if (dotversion.find('2.26.3') or dotversion.find('2.28.0') != -1) and (self.vpages * self.hpages) > 1:
command = command.replace(':cairo','')
os.system(command)
@@ -920,9 +922,11 @@ class GVPdfGsDoc(GVDocBase):
# Generate PostScript using dot
# Reason for using -Tps:cairo. Needed for Non Latin-1 letters
# See bug tracker issue 2815
# :cairo does not work with Graphviz 2.26.3 and later See issue 4164
command = 'dot -Tps:cairo -o"%s" "%s"' % ( tmp_ps, tmp_dot )
# :cairo does not work with with multi-page See issue 4164
# recent versions of Graphvis doesn't even try, just puts out a single
# large page, so we use Ghostscript to split it up.
command = 'dot -Tps:cairo -o"%s" "%s"' % (tmp_ps, tmp_dot)
if win():
dotversion = str(Popen(['dot', '-V'],
creationflags=DETACHED_PROCESS,
@@ -931,26 +935,65 @@ class GVPdfGsDoc(GVDocBase):
else:
dotversion = str(Popen(['dot', '-V'],
stderr=PIPE).communicate(input=None)[1])
# Problem with dot 2.26.3 and later and multiple pages, which gives "cairo: out
# of memory". If the :cairo is skipped for these cases it gives
# acceptable result.
if (dotversion.find('2.26.3') or dotversion.find('2.28.0') != -1) and (self.vpages * self.hpages) > 1:
command = command.replace(':cairo','')
os.system(command)
# Add .5 to remove rounding errors.
paper_size = self._paper.get_size()
width_pt = int( (paper_size.get_width_inches() * 72) + 0.5 )
height_pt = int( (paper_size.get_height_inches() * 72) + 0.5 )
width_pt = int((paper_size.get_width_inches() * 72) + .5)
height_pt = int((paper_size.get_height_inches() * 72) + .5)
if (self.vpages * self.hpages) == 1:
# -dDEVICEWIDTHPOINTS=%d' -dDEVICEHEIGHTPOINTS=%d
command = '%s -q -sDEVICE=pdfwrite -dNOPAUSE '\
'-dDEVICEWIDTHPOINTS=%d -dDEVICEHEIGHTPOINTS=%d '\
'-sOutputFile="%s" "%s" -c quit' % (
_GS_CMD, width_pt, height_pt, self._filename, tmp_ps)
os.system(command)
os.remove(tmp_ps)
return
# Margins (in centimeters) to pixels 72/2.54=28.345
MarginT = int(28.345 * self._paper.get_top_margin())
MarginB = int(28.345 * self._paper.get_bottom_margin())
MarginR = int(28.345 * self._paper.get_right_margin())
MarginL = int(28.345 * self._paper.get_left_margin())
MarginX = MarginL + MarginR
MarginY = MarginT + MarginB
# Convert to PDF using ghostscript
command = '%s -q -sDEVICE=pdfwrite -dNOPAUSE -dDEVICEWIDTHPOINTS=%d' \
' -dDEVICEHEIGHTPOINTS=%d -sOutputFile="%s" "%s" -c quit' \
% ( _GS_CMD, width_pt, height_pt, self._filename, tmp_ps )
list_of_pieces = []
x_rng = range(1, self.hpages + 1) if 'L' in self.pagedir \
else range(self.hpages , 0, -1)
y_rng = range(1, self.vpages + 1) if 'B' in self.pagedir \
else range(self.vpages , 0, -1)
if self.pagedir[0] in 'TB':
the_list = ((x, y) for y in y_rng for x in x_rng)
else:
the_list = ((x, y) for x in x_rng for y in y_rng)
for x, y in the_list:
# Slit PS file to pieces of PDF
PageOffsetX = (x - 1) * (MarginX - width_pt)
PageOffsetY = (y - 1) * (MarginY - height_pt)
tmp_pdf_piece = "%s_%d_%d.pdf" % (tmp_ps, x, y)
list_of_pieces.append(tmp_pdf_piece)
# Generate Ghostscript code
command = '%s -q -dBATCH -dNOPAUSE -dSAFER -g%dx%d '\
'-sOutputFile="%s" -r72 -sDEVICE=pdfwrite '\
'-c "<</.HWMargins [%d %d %d %d] /PageOffset [%d %d]>> '\
'setpagedevice" -f "%s"' % (
_GS_CMD, width_pt + 10, height_pt + 10, tmp_pdf_piece,
MarginL, MarginB, MarginR, MarginT,
PageOffsetX + 5, PageOffsetY + 5, tmp_ps)
# Execute Ghostscript
os.system(command)
# Merge pieces to single multipage PDF ;
command = '%s -q -dBATCH -dNOPAUSE '\
'-sOUTPUTFILE="%s" -r72 -sDEVICE=pdfwrite %s '\
% (_GS_CMD, self._filename, ' '.join(list_of_pieces))
os.system(command)
# Clean temporary files
os.remove(tmp_ps)
for tmp_pdf_piece in list_of_pieces:
os.remove(tmp_pdf_piece)
os.remove(tmp_dot)
#-------------------------------------------------------------------------------
+632
View File
@@ -0,0 +1,632 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2017-2018 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
""" LaTeX Genealogy Tree adapter for Trees """
#-------------------------------------------------------------------------
#
# Standard Python modules
#
#-------------------------------------------------------------------------
from abc import ABCMeta, abstractmethod
import os
import shutil
from io import StringIO
import tempfile
import logging
#-------------------------------------------------------------------------
#
# Gramps modules
#
#-------------------------------------------------------------------------
from ...utils.file import search_for
from ...lib import Person, EventType, EventRoleType, Date
from ...display.place import displayer as _pd
from ...utils.file import media_path_full
from . import BaseDoc, PAPER_PORTRAIT
from ..menu import NumberOption, TextOption, EnumeratedListOption
from ...constfunc import win
from ...config import config
from ...const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
#-------------------------------------------------------------------------
#
# set up logging
#
#-------------------------------------------------------------------------
LOG = logging.getLogger(".treedoc")
#-------------------------------------------------------------------------
#
# Private Constants
#
#-------------------------------------------------------------------------
_DETAIL = [{'name': _("Full"), 'value': "full"},
{'name': _("Medium"), 'value': "medium"},
{'name': _("Short"), 'value': "short"}]
_MARRIAGE = [{'name': _("Default"), 'value': ""},
{'name': _("Above"), 'value': "marriage above"},
{'name': _("Below"), 'value': "marriage below"},
{'name': _("Not shown"), 'value': "no marriage"}]
_COLOR = [{'name': _("None"), 'value': "none"},
{'name': _("Default"), 'value': "default"},
{'name': _("Preferences"), 'value': "preferences"}]
_TIMEFLOW = [{'name': _("Down (↓)"), 'value': ""},
{'name': _("Up (↑)"), 'value': "up"},
{'name': _("Right (→)"), 'value': "right"},
{'name': _("Left (←)"), 'value': "left"}]
_EDGES = [{'name': _("Perpendicular"), 'value': ""},
{'name': _("Rounded"), 'value': "rounded", },
{'name': _("Swing"), 'value': "swing", },
{'name': _("Mesh"), 'value': 'mesh'}]
_NOTELOC = [{'name': _("Top"), 'value': "t"},
{'name': _("Bottom"), 'value': "b"}]
_NOTESIZE = [{'name': _("Tiny"), 'value': "tiny"},
{'name': _("Script"), 'value': "scriptsize"},
{'name': _("Footnote"), 'value': "footnotesize"},
{'name': _("Small"), 'value': "small"},
{'name': _("Normal"), 'value': "normalsize"},
{'name': _("Large"), 'value': "large"},
{'name': _("Very large"), 'value': "Large"},
{'name': _("Extra large"), 'value': "LARGE"},
{'name': _("Huge"), 'value': "huge"},
{'name': _("Extra huge"), 'value': "Huge"}]
if win():
_LATEX_FOUND = search_for("lualatex.exe")
else:
_LATEX_FOUND = search_for("lualatex")
#------------------------------------------------------------------------------
#
# TreeOptions
#
#------------------------------------------------------------------------------
class TreeOptions:
"""
Defines all of the controls necessary
to configure the genealogy tree reports.
"""
def add_menu_options(self, menu):
"""
Add all graph related options to the menu.
:param menu: The menu the options should be added to.
:type menu: :class:`.Menu`
:return: nothing
"""
################################
category = _("Node Options")
################################
detail = EnumeratedListOption(_("Node detail"), "full")
for item in _DETAIL:
detail.add_item(item["value"], item["name"])
detail.set_help(_("Detail of information to be shown in a node."))
menu.add_option(category, "detail", detail)
marriage = EnumeratedListOption(_("Marriage"), "")
for item in _MARRIAGE:
marriage.add_item(item["value"], item["name"])
marriage.set_help(_("Position of marriage information."))
menu.add_option(category, "marriage", marriage)
nodesize = NumberOption(_("Node size"), 25, 5, 100, 5)
nodesize.set_help(_("One dimension of a node, in mm. If the timeflow "
"is up or down then this is the width, otherwise "
"it is the height."))
menu.add_option(category, "nodesize", nodesize)
levelsize = NumberOption(_("Level size"), 35, 5, 100, 5)
levelsize.set_help(_("One dimension of a node, in mm. If the timeflow "
"is up or down then this is the height, otherwise "
"it is the width."))
menu.add_option(category, "levelsize", levelsize)
nodecolor = EnumeratedListOption(_("Color"), "none")
for item in _COLOR:
nodecolor.add_item(item["value"], item["name"])
nodecolor.set_help(_("Node color."))
menu.add_option(category, "nodecolor", nodecolor)
################################
category = _("Tree Options")
################################
timeflow = EnumeratedListOption(_("Timeflow"), "")
for item in _TIMEFLOW:
timeflow.add_item(item["value"], item["name"])
timeflow.set_help(_("Direction that the graph will grow over time."))
menu.add_option(category, "timeflow", timeflow)
edges = EnumeratedListOption(_("Edge style"), "")
for item in _EDGES:
edges.add_item(item["value"], item["name"])
edges.set_help(_("Style of the edges between nodes."))
menu.add_option(category, "edges", edges)
leveldist = NumberOption(_("Level distance"), 5, 1, 20, 1)
leveldist.set_help(_("The minimum amount of free space, in mm, "
"between levels. For vertical graphs, this "
"corresponds to spacing between rows. For "
"horizontal graphs, this corresponds to spacing "
"between columns."))
menu.add_option(category, "leveldist", leveldist)
################################
category = _("Note")
################################
note = TextOption(_("Note to add to the tree"), [""])
note.set_help(_("This text will be added to the tree."))
menu.add_option(category, "note", note)
noteloc = EnumeratedListOption(_("Note location"), 't')
for item in _NOTELOC:
noteloc.add_item(item["value"], item["name"])
noteloc.set_help(_("Whether note will appear on top "
"or bottom of the page."))
menu.add_option(category, "noteloc", noteloc)
notesize = EnumeratedListOption(_("Note size"), 'normalsize')
for item in _NOTESIZE:
notesize.add_item(item["value"], item["name"])
notesize.set_help(_("The size of note text."))
menu.add_option(category, "notesize", notesize)
#------------------------------------------------------------------------------
#
# TreeDoc
#
#------------------------------------------------------------------------------
class TreeDoc(metaclass=ABCMeta):
"""
Abstract Interface for genealogy tree document generators. Output formats
for genealogy tree reports must implement this interface to be used by the
report system.
"""
@abstractmethod
def start_tree(self, option_list):
"""
Write the start of a tree.
"""
@abstractmethod
def end_tree(self):
"""
Write the end of a tree.
"""
@abstractmethod
def start_subgraph(self, level, subgraph_type, family, option_list=None):
"""
Write the start of a subgraph.
"""
@abstractmethod
def end_subgraph(self, level):
"""
Write the end of a subgraph.
"""
@abstractmethod
def write_node(self, db, level, node_type, person, marriage_flag,
option_list=None):
"""
Write the contents of a node.
"""
#------------------------------------------------------------------------------
#
# TreeDocBase
#
#------------------------------------------------------------------------------
class TreeDocBase(BaseDoc, TreeDoc):
"""
Base document generator for all Graphviz document generators. Classes that
inherit from this class will only need to implement the close function.
The close function will generate the actual file of the appropriate type.
"""
def __init__(self, options, paper_style):
BaseDoc.__init__(self, None, paper_style)
self._filename = None
self._tex = StringIO()
self._paper = paper_style
get_option = options.menu.get_option_by_name
self.detail = get_option('detail').get_value()
self.marriage = get_option('marriage').get_value()
self.nodesize = get_option('nodesize').get_value()
self.levelsize = get_option('levelsize').get_value()
self.nodecolor = get_option('nodecolor').get_value()
self.timeflow = get_option('timeflow').get_value()
self.edges = get_option('edges').get_value()
self.leveldist = get_option('leveldist').get_value()
self.note = get_option('note').get_value()
self.noteloc = get_option('noteloc').get_value()
self.notesize = get_option('notesize').get_value()
def write_start(self):
"""
Write the start of the document.
"""
paper_size = self._paper.get_size()
name = paper_size.get_name().lower()
if name == 'custom size':
width = str(paper_size.get_width())
height = str(paper_size.get_width())
paper = 'papersize={%scm,%scm}' % (width, height)
elif name in ('a', 'b', 'c', 'd', 'e'):
paper = 'ansi' + name + 'paper'
else:
paper = name + 'paper'
if self._paper.get_orientation() == PAPER_PORTRAIT:
orientation = 'portrait'
else:
orientation = 'landscape'
lmargin = self._paper.get_left_margin()
rmargin = self._paper.get_right_margin()
tmargin = self._paper.get_top_margin()
bmargin = self._paper.get_bottom_margin()
if lmargin == rmargin == tmargin == bmargin:
margin = 'margin=%scm'% lmargin
else:
if lmargin == rmargin:
margin = 'hmargin=%scm' % lmargin
else:
margin = 'hmargin={%scm,%scm}' % (lmargin, rmargin)
if tmargin == bmargin:
margin += ',vmargin=%scm' % tmargin
else:
margin += ',vmargin={%scm,%scm}' % (tmargin, bmargin)
self.write(0, '\\documentclass[%s]{article}\n' % orientation)
self.write(0, '\\IfFileExists{libertine.sty}{\n')
self.write(0, ' \\usepackage{libertine}\n')
self.write(0, '}{}\n')
self.write(0, '\\usepackage[%s,%s]{geometry}\n' % (paper, margin))
self.write(0, '\\usepackage[all]{genealogytree}\n')
self.write(0, '\\usepackage{color}\n')
self.write(0, '\\begin{document}\n')
if self.nodecolor == 'preferences':
male_bg = config.get('preferences.color-gender-male-death')[1:]
female_bg = config.get('preferences.color-gender-female-death')[1:]
neuter_bg = config.get('preferences.color-gender-unknown-death')[1:]
self.write(0, '\\definecolor{male-bg}{HTML}{%s}\n' % male_bg)
self.write(0, '\\definecolor{female-bg}{HTML}{%s}\n' % female_bg)
self.write(0, '\\definecolor{neuter-bg}{HTML}{%s}\n' % neuter_bg)
if ''.join(self.note) != '' and self.noteloc == 't':
for line in self.note:
self.write(0, '{\\%s %s}\\par\n' % (self.notesize, line))
self.write(0, '\\bigskip\n')
self.write(0, '\\begin{tikzpicture}\n')
def start_tree(self, option_list):
self.write(0, '\\genealogytree[\n')
self.write(0, 'processing=database,\n')
if self.marriage:
info = self.detail + ' ' + self.marriage
else:
info = self.detail
self.write(0, 'database format=%s,\n' % info)
if self.timeflow:
self.write(0, 'timeflow=%s,\n' % self.timeflow)
if self.edges:
self.write(0, 'edges=%s,\n' % self.edges)
if self.leveldist != 5:
self.write(0, 'level distance=%smm,\n' % self.leveldist)
if self.nodesize != 25:
self.write(0, 'node size=%smm,\n' % self.nodesize)
if self.levelsize != 35:
self.write(0, 'level size=%smm,\n' % self.levelsize)
if self.nodecolor == 'none':
self.write(0, 'tcbset={male/.style={},\n')
self.write(0, ' female/.style={},\n')
self.write(0, ' neuter/.style={}},\n')
if self.nodecolor == 'preferences':
self.write(0, 'tcbset={male/.style={colback=male-bg},\n')
self.write(0, ' female/.style={colback=female-bg},\n')
self.write(0, ' neuter/.style={colback=neuter-bg}},\n')
for option in option_list:
self.write(0, '%s,\n' % option)
self.write(0, ']{\n')
def end_tree(self):
self.write(0, '}\n')
def write_end(self):
"""
Write the end of the document.
"""
self.write(0, '\\end{tikzpicture}\n')
if ''.join(self.note) != '' and self.noteloc == 'b':
self.write(0, '\\bigskip\n')
for line in self.note:
self.write(0, '\\par{\\%s %s}\n' % (self.notesize, line))
self.write(0, '\\end{document}\n')
def start_subgraph(self, level, subgraph_type, family, option_list=None):
options = ['id=%s' % family.gramps_id]
if option_list:
options.extend(option_list)
if subgraph_type == 'sandclock':
self.write(level, 'sandclock{\n')
else:
self.write(level, '%s[%s]{\n' % (subgraph_type, ','.join(options)))
def end_subgraph(self, level):
self.write(level, '}\n')
def write_node(self, db, level, node_type, person, marriage_flag,
option_list=None):
options = ['id=%s' % person.gramps_id]
if option_list:
options.extend(option_list)
self.write(level, '%s[%s]{\n' % (node_type, ','.join(options)))
if person.gender == Person.MALE:
self.write(level+1, 'male,\n')
elif person.gender == Person.FEMALE:
self.write(level+1, 'female,\n')
elif person.gender == Person.UNKNOWN:
self.write(level+1, 'neuter,\n')
name = person.get_primary_name()
nick = name.get_nick_name()
surn = name.get_surname()
name_parts = [self.format_given_names(name),
'\\nick{{{}}}'.format(nick) if nick else '',
'\\surn{{{}}}'.format(surn) if surn else '']
self.write(level+1, 'name = {{{}}},\n'.format(
' '.join([e for e in name_parts if e])))
for eventref in person.get_event_ref_list():
if eventref.role == EventRoleType.PRIMARY:
event = db.get_event_from_handle(eventref.ref)
self.write_event(db, level+1, event)
if marriage_flag:
for handle in person.get_family_handle_list():
family = db.get_family_from_handle(handle)
for eventref in family.get_event_ref_list():
if eventref.role == EventRoleType.FAMILY:
event = db.get_event_from_handle(eventref.ref)
self.write_event(db, level+1, event)
for attr in person.get_attribute_list():
if str(attr.get_type()) == 'Occupation':
self.write(level+1, 'profession = {%s},\n' % attr.get_value())
if str(attr.get_type()) == 'Comment':
self.write(level+1, 'comment = {%s},\n' % attr.get_value())
for mediaref in person.get_media_list():
media = db.get_object_from_handle(mediaref.ref)
path = media_path_full(db, media.get_path())
if os.path.isfile(path):
self.write(level+1, 'image = {%s},\n' % path)
break # first image only
self.write(level, '}\n')
def write_event(self, db, level, event):
"""
Write an event.
"""
modifier = None
if event.type == EventType.BIRTH:
event_type = 'birth'
if 'died' in event.description.lower():
modifier = 'died'
if 'stillborn' in event.description.lower():
modifier = 'stillborn'
# modifier = 'out of wedlock'
elif event.type == EventType.BAPTISM:
event_type = 'baptism'
elif event.type == EventType.ENGAGEMENT:
event_type = 'engagement'
elif event.type == EventType.MARRIAGE:
event_type = 'marriage'
elif event.type == EventType.DIVORCE:
event_type = 'divorce'
elif event.type == EventType.DEATH:
event_type = 'death'
elif event.type == EventType.BURIAL:
event_type = 'burial'
if 'killed' in event.description.lower():
modifier = 'killed'
elif event.type == EventType.CREMATION:
event_type = 'burial'
modifier = 'cremated'
else:
return
date = event.get_date_object()
if date.get_calendar() == Date.CAL_GREGORIAN:
calendar = 'AD' # GR
elif date.get_calendar() == Date.CAL_JULIAN:
calendar = 'JU'
else:
calendar = ''
if date.get_modifier() == Date.MOD_ABOUT:
calendar = 'ca' + calendar
date_str = self.format_iso(date.get_ymd(), calendar)
if date.get_modifier() == Date.MOD_BEFORE:
date_str = '/' + date_str
elif date.get_modifier() == Date.MOD_AFTER:
date_str = date_str + '/'
elif date.is_compound():
stop_date = self.format_iso(date.get_stop_ymd(), calendar)
date_str = date_str + '/' + stop_date
place = _pd.display_event(db, event)
if modifier:
event_type += '+'
self.write(level, '%s = {%s}{%s}{%s},\n' %
(event_type, date_str, place, modifier))
elif place == '':
event_type += '-'
self.write(level, '%s = {%s},\n' % (event_type, date_str))
else:
self.write(level, '%s = {%s}{%s},\n' %
(event_type, date_str, place))
def format_given_names(self, name):
"""
Format given names.
"""
first = name.get_first_name()
call = name.get_call_name()
if call:
if call in first:
where = first.index(call)
return '{before}\\pref{{{call}}}{after}'.format(
before=first[:where],
call=call,
after=first[where+len(call):])
else:
# ignore erroneous call name
return first
else:
return first
def format_iso(self, date_tuple, calendar):
"""
Format an iso date.
"""
year, month, day = date_tuple
if year == 0:
iso_date = ''
elif month == 0:
iso_date = str(year)
elif day == 0:
iso_date = '%s-%s' % (year, month)
else:
iso_date = '%s-%s-%s' % (year, month, day)
if calendar and calendar != 'AD':
iso_date = '(%s)%s' % (calendar, iso_date)
return iso_date
def write(self, level, text):
"""
Write indented text.
"""
self._tex.write(' '*level + text)
def open(self, filename):
""" Implement TreeDocBase.open() """
self._filename = os.path.normpath(os.path.abspath(filename))
self.write_start()
def close(self):
"""
This isn't useful by itself. Other classes need to override this and
actually generate a file.
"""
self.write_end()
#------------------------------------------------------------------------------
#
# TreeTexDoc
#
#------------------------------------------------------------------------------
class TreeTexDoc(TreeDocBase):
"""
TreeTexDoc implementation that generates a .tex file.
"""
def close(self):
""" Implements TreeDocBase.close() """
TreeDocBase.close(self)
# Make sure the extension is correct
if self._filename[-4:] != ".tex":
self._filename += ".tex"
with open(self._filename, "w") as texfile:
texfile.write(self._tex.getvalue())
#------------------------------------------------------------------------------
#
# TreePdfDoc
#
#------------------------------------------------------------------------------
class TreePdfDoc(TreeDocBase):
"""
TreePdfDoc implementation that generates a .pdf file.
"""
def close(self):
""" Implements TreeDocBase.close() """
TreeDocBase.close(self)
# Make sure the extension is correct
if self._filename[-4:] != ".pdf":
self._filename += ".pdf"
with tempfile.TemporaryDirectory() as tmpdir:
with open(os.path.join(tmpdir, 'temp.tex'), "w") as texfile:
texfile.write(self._tex.getvalue())
os.system('lualatex -output-directory %s temp.tex >/dev/null'
% tmpdir)
shutil.copy(os.path.join(tmpdir, 'temp.pdf'), self._filename)
#------------------------------------------------------------------------------
#
# Various Genealogy Tree formats.
#
#------------------------------------------------------------------------------
FORMATS = []
if _LATEX_FOUND:
FORMATS += [{'type' : "pdf",
'ext' : "pdf",
'descr': _("PDF"),
'mime' : "application/pdf",
'class': TreePdfDoc}]
FORMATS += [{'type' : "tex",
'ext' : "tex",
'descr': _("LaTeX File"),
'mime' : "application/x-latex",
'class': TreeTexDoc}]
+84 -65
View File
@@ -457,79 +457,98 @@ class BookList(object):
"""
Saves the current BookList to the associated file.
"""
f = open(self.file, "w")
f.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
f.write('<booklist>\n')
for name in sorted(self.bookmap): # enable a diff of archived copies
book = self.get_book(name)
dbname = book.get_dbname()
f.write('<book name="%s" database="%s">\n' % (name, dbname) )
for item in book.get_item_list():
f.write(' <item name="%s" trans_name="%s">\n' %
(item.get_name(),item.get_translated_name() ) )
options = item.option_class.handler.options_dict
for option_name in sorted(options.keys()): # enable a diff
option_value = options[option_name]
if isinstance(option_value, (list, tuple)):
f.write(' <option name="%s" value="" '
'length="%d">\n' % (
escape(option_name),
len(options[option_name]) ) )
for list_index in range(len(option_value)):
option_type = type_name(option_value[list_index])
value = escape(str(option_value[list_index]))
with open(self.file, "w", encoding="utf-8") as b_f:
b_f.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
b_f.write('<booklist>\n')
for name in sorted(self.bookmap): # enable a diff of archived copies
book = self.get_book(name)
dbname = escape(book.get_dbname())
b_f.write(' <book name="%s" database="%s">'
'\n' % (escape(name), dbname))
for item in book.get_item_list():
b_f.write(' <item name="%s" '
'trans_name="%s">\n' % (
item.get_name(),
item.get_translated_name()))
options = item.option_class.handler.options_dict
for option_name in sorted(options.keys()): # enable a diff
option_value = options[option_name]
if isinstance(option_value, (list, tuple)):
b_f.write(' <option name="%s" value="" '
'length="%d">\n' % (
escape(option_name),
len(options[option_name])))
for list_index in range(len(option_value)):
option_type = type_name(
option_value[list_index])
value = escape(str(option_value[list_index]))
value = value.replace('"', '&quot;')
b_f.write(' <listitem number="%d" '
'type="%s" value="%s"/>\n' % (
list_index,
option_type,
value))
b_f.write(' </option>\n')
else:
option_type = type_name(option_value)
value = escape(str(option_value))
value = value.replace('"', '&quot;')
f.write(' <listitem number="%d" type="%s" '
'value="%s"/>\n' % (
list_index,
option_type,
value ) )
f.write(' </option>\n')
else:
option_type = type_name(option_value)
value = escape(str(option_value))
value = value.replace('"', '&quot;')
f.write(' <option name="%s" type="%s" '
'value="%s"/>\n' % (
escape(option_name),
option_type,
value) )
b_f.write(' <option name="%s" type="%s" '
'value="%s"/>\n' % (
escape(option_name),
option_type,
value))
f.write(' <style name="%s"/>\n' % item.get_style_name() )
f.write(' </item>\n')
if book.get_paper_name():
f.write(' <paper name="%s"/>\n' % book.get_paper_name() )
if book.get_orientation() is not None: # 0 is legal
f.write(' <orientation value="%s"/>\n' %
book.get_orientation() )
if book.get_paper_metric() is not None: # 0 is legal
f.write(' <metric value="%s"/>\n' % book.get_paper_metric() )
if book.get_custom_paper_size():
size = book.get_custom_paper_size()
f.write(' <size value="%f %f"/>\n' % (size[0], size[1]) )
if book.get_margins():
for pos in range(len(book.get_margins())):
f.write(' <margin number="%s" value="%f"/>\n' %
(pos, book.get_margin(pos)) )
if book.get_format_name():
f.write(' <format name="%s"/>\n' % book.get_format_name() )
if book.get_output():
f.write(' <output name="%s"/>\n' % book.get_output() )
f.write('</book>\n')
b_f.write(' <style name="%s"/>'
'\n' % item.get_style_name())
b_f.write(' </item>\n')
if book.get_paper_name():
b_f.write(' <paper name="%s"/>'
'\n' % book.get_paper_name())
if book.get_orientation() is not None: # 0 is legal
b_f.write(' <orientation value="%s"/>'
'\n' % book.get_orientation())
if book.get_paper_metric() is not None: # 0 is legal
b_p_metric = book.get_paper_metric()
if isinstance(b_p_metric, bool):
b_p_metric = int(b_p_metric)
b_f.write(' <metric value="%s"/>'
'\n' % b_p_metric)
if book.get_custom_paper_size():
size = book.get_custom_paper_size()
b_f.write(' <size value="%f %f"/>'
'\n' % (size[0], size[1]))
if book.get_margins():
for pos in range(len(book.get_margins())):
b_f.write(' <margin number="%s" '
'value="%f"/>\n' % (
pos, book.get_margin(pos)))
if book.get_format_name():
b_f.write(' <format name="%s"/>'
'\n' % book.get_format_name())
if book.get_output():
b_f.write(' <output name="%s"/>'
'\n' % escape(book.get_output()))
b_f.write(' </book>\n')
b_f.write('</booklist>\n')
f.write('</booklist>\n')
f.close()
def parse(self):
"""
Loads the BookList from the associated file, if it exists.
"""
try:
p = make_parser()
p.setContentHandler(BookParser(self, self.dbase))
the_file = open(self.file)
p.parse(the_file)
the_file.close()
parser = make_parser()
parser.setContentHandler(BookParser(self, self.dbase))
# bug 10387; XML should be utf8, but was not previously saved
# that way. So try to read utf8, if fails, try with system
# encoding. Only an issue on non-utf8 systems.
try:
with open(self.file, encoding="utf-8") as the_file:
parser.parse(the_file)
except UnicodeDecodeError:
with open(self.file) as the_file:
parser.parse(the_file)
except (IOError, OSError, ValueError, SAXParseException, KeyError,
AttributeError):
pass
+2 -1
View File
@@ -39,7 +39,7 @@ import os
# Report categories
from .. import (CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_CODE, CATEGORY_WEB,
CATEGORY_BOOK, CATEGORY_GRAPHVIZ)
CATEGORY_BOOK, CATEGORY_GRAPHVIZ, CATEGORY_TREE)
standalone_categories = {
CATEGORY_TEXT : ("RepText", _("Text Reports")),
@@ -48,6 +48,7 @@ standalone_categories = {
CATEGORY_WEB : ("RepWeb", _("Web Pages")),
CATEGORY_BOOK : ("RepBook", _("Books")),
CATEGORY_GRAPHVIZ : ("Graphs", _("Graphs")),
CATEGORY_TREE : ("Trees", _("Trees")),
}
book_categories = {
CATEGORY_TEXT : _("Text"),
+2
View File
@@ -52,6 +52,8 @@ def soundex(strval):
return "Z000"
strval = strval.decode('ASCII', 'ignore')
str2 = strval[0]
translator = strval.maketrans('','',IGNORE)
strval = strval.translate(translator)
strval = strval.translate(TABLE)
if not strval:
return "Z000"
+1 -2
View File
@@ -310,8 +310,7 @@ class Callback(object):
for key in keymap:
self.__callback_map[signal_name].remove(key)
self.__callback_map[signal_name] = None
self.__callback_map = None
del self.__callback_map
self.__callback_map = {}
def emit(self, signal_name, args=tuple()):
"""
+9 -4
View File
@@ -393,8 +393,9 @@ def find_children(db,p):
childlist = []
for family_handle in p.get_family_handle_list():
family = db.get_family_from_handle(family_handle)
for child_ref in family.get_child_ref_list():
childlist.append(child_ref.ref)
if family:
for child_ref in family.get_child_ref_list():
childlist.append(child_ref.ref)
return childlist
#-------------------------------------------------------------------------
@@ -522,10 +523,14 @@ def preset_name(basepers, name, sibling=False):
def family_name(family, db, noname=_("unknown")):
"""Builds a name for the family from the parents names"""
father = None
mother = None
father_handle = family.get_father_handle()
mother_handle = family.get_mother_handle()
father = db.get_person_from_handle(father_handle)
mother = db.get_person_from_handle(mother_handle)
if father_handle:
father = db.get_person_from_handle(father_handle)
if mother_handle:
mother = db.get_person_from_handle(mother_handle)
if father and mother:
fname = name_displayer.display(father)
mname = name_displayer.display(mother)
+3 -1
View File
@@ -31,6 +31,7 @@ import csv
#
#-------------------------------------------------------------------------
from .tabbeddoc import *
from ...constfunc import win
class CSVTab(TabbedDoc):
@@ -48,7 +49,8 @@ class CSVTab(TabbedDoc):
else:
self.filename = filename
self.f = open(self.filename, "w")
self.f = open(self.filename, "w",
encoding='utf_8_sig' if win() else 'utf_8')
self.writer = csv.writer(self.f)
def close(self):
+19 -1
View File
@@ -62,7 +62,7 @@ def find_file( filename):
try:
if os.path.isfile(filename):
return(filename)
except UnicodeError:
except UnicodeError as err:
LOG.error("Filename %s raised a Unicode Error %s.", repr(filename), err)
LOG.debug("Filename %s not found.", repr(filename))
@@ -185,6 +185,24 @@ def search_for(name):
return 1
return 0
def where_is(name):
""" This command is similar to the Linux "whereis -b file" command.
It looks for an executable file (name) in the PATH python is using, as
well as several likely other paths. It returns the first file found,
or an empty string if not found.
"""
paths = set(os.environ['PATH'].split(os.pathsep))
if not win():
paths.update(("/bin", "/usr/bin", "/usr/local/bin", "/opt/local/bin",
"/opt/bin"))
for i in paths:
fname = os.path.join(i, name)
if os.access(fname, os.X_OK) and not os.path.isdir(fname):
return fname
return ""
def create_checksum(full_path):
"""
Create a md5 hash for the given file.
+4 -2
View File
@@ -32,6 +32,7 @@ import codecs
import locale
import collections
import logging
from binascii import hexlify
LOG = logging.getLogger("." + __name__)
LOG.propagate = True
@@ -856,8 +857,9 @@ class GrampsLocale(object):
"""
if HAVE_ICU and self.collator:
#ICU can digest strings and unicode
return self.collator.getCollationKey(string).getByteArray()
# ICU can digest strings and unicode
# Use hexlify() as to make a consistent string, fixing bug #10077
return hexlify(self.collator.getCollationKey(string).getByteArray()).decode()
else:
if isinstance(string, bytes):
string = string.decode("utf-8", "replace")
+22 -7
View File
@@ -21,7 +21,7 @@
"""
Location utility functions
"""
from ..lib.date import Today
from ..lib.date import Date, Today
#-------------------------------------------------------------------------
#
@@ -33,7 +33,7 @@ def get_location_list(db, place, date=None, lang=''):
Return a list of place names for display.
"""
if date is None:
date = Today()
date = __get_latest_date(place)
visited = [place.handle]
lines = [(__get_name(place, date, lang), place.get_type())]
while True:
@@ -53,16 +53,31 @@ def get_location_list(db, place, date=None, lang=''):
return lines
def __get_name(place, date, lang):
local_name = '?'
endonym = None
for place_name in place.get_all_names():
name_date = place_name.get_date_object()
if name_date.is_empty() or date.match_exact(name_date):
name_lang = place_name.get_language()
if name_lang == '':
local_name = place_name.get_value()
if place_name.get_language() == lang:
return place_name.get_value()
return local_name
if endonym is None:
endonym = place_name.get_value()
return endonym if endonym is not None else '?'
def __get_latest_date(place):
latest_date = None
for place_name in place.get_all_names():
date = place_name.get_date_object()
if date.is_empty() or date.modifier == Date.MOD_AFTER:
return Today()
else:
if date.is_compound():
date1, date2 = date.get_start_stop_range()
date = Date(*date2)
if date.modifier == Date.MOD_BEFORE:
date = date - 1
if latest_date is None or date > latest_date:
latest_date = date
return latest_date
#-------------------------------------------------------------------------
#
+18 -5
View File
@@ -46,6 +46,7 @@ from .gen.const import APP_GRAMPS, USER_DIRLIST, HOME_DIR
from .gen.constfunc import mac
from .version import VERSION_TUPLE
from .gen.constfunc import win, get_env_var
from .gen.config import config
#-------------------------------------------------------------------------
#
@@ -73,10 +74,15 @@ try:
_encoding = sys.stdout.encoding
except:
_encoding = "UTF-8"
sys.stdout = open(sys.stdout.fileno(), mode='w', encoding=_encoding,
buffering=1, errors='backslashreplace')
sys.stderr = open(sys.stderr.fileno(), mode='w', encoding=_encoding,
buffering=1, errors='backslashreplace')
try:
# On Windows there is no std handles in GUI mode
sys.stdout = open(sys.stdout.fileno(), mode='w', encoding=_encoding,
buffering=1, errors='backslashreplace')
sys.stderr = open(sys.stderr.fileno(), mode='w', encoding=_encoding,
buffering=1, errors='backslashreplace')
except:
pass
#-------------------------------------------------------------------------
#
@@ -99,7 +105,7 @@ form = logging.Formatter(fmt="%(asctime)s.%(msecs).03d: %(levelname)s: "
# Create the log handlers
if win():
# If running in GUI mode redirect stdout and stderr to log file
if hasattr(sys.stdout, "fileno") and sys.stdout.fileno() < 0:
if not sys.stdout:
logfile = os.path.join(HOME_DIR,
"Gramps%s%s.log") % (VERSION_TUPLE[0],
VERSION_TUPLE[1])
@@ -244,6 +250,8 @@ def show_settings():
from gi import Repository
repository = Repository.get_default()
if repository.enumerate_versions("OsmGpsMap"):
import gi
gi.require_version('OsmGpsMap', '1.0')
from gi.repository import OsmGpsMap as osmgpsmap
try:
osmgpsmap_str = osmgpsmap._version
@@ -259,6 +267,8 @@ def show_settings():
from gi import Repository
repository = Repository.get_default()
if repository.enumerate_versions("GExiv2"):
import gi
gi.require_version('GExiv2', '0.10')
from gi.repository import GExiv2
try:
gexiv2_str = GExiv2._version
@@ -447,6 +457,9 @@ def run():
startcli(error, argpars)
def main():
if win() and ('PANGOCAIRO_BACKEND' not in os.environ) and \
config.get('preferences.alternate-fonthandler'):
os.environ['PANGOCAIRO_BACKEND'] = "fontconfig"
errors = run()
if errors and isinstance(errors, list):
for error in errors:
+83 -45
View File
@@ -38,6 +38,8 @@ from gi.repository import GObject
from gi.repository import Gdk
from gi.repository import Gtk
from gi.repository import GdkPixbuf
from gi.repository import Pango
import cairo
#-------------------------------------------------------------------------
#
@@ -117,6 +119,7 @@ def map2class(target):
'place-link': ClipPlace,
'placeref': ClipPlaceRef,
'note-link': ClipNote,
'TEXT': ClipText,
}
return d[target] if target in d else None
@@ -1018,6 +1021,7 @@ class ClipboardListView(object):
self._widget.connect('drag-data-get', self.object_drag_data_get)
self._widget.connect('drag-begin', self.object_drag_begin)
self._widget.connect_after('drag-begin', self.object_after_drag_begin)
self._widget.connect('drag-data-received',
self.object_drag_data_received)
self._widget.connect('drag-end', self.object_drag_end)
@@ -1202,7 +1206,35 @@ class ClipboardListView(object):
def object_drag_begin(self, widget, drag_context):
""" Handle the beginning of a drag operation. """
pass
def object_after_drag_begin(self, widget, drag_context):
tree_selection = widget.get_selection()
model, paths = tree_selection.get_selected_rows()
if len(paths) == 1:
path = paths[0]
node = model.get_iter(path)
target = model.get_value(node, 0)
if target == "TEXT":
layout = widget.create_pango_layout(model.get_value(node,4))
layout.set_alignment(Pango.Alignment.CENTER)
width, height = layout.get_pixel_size()
surface = cairo.ImageSurface(cairo.FORMAT_RGB24,
width, height)
ctx = cairo.Context(surface)
style_ctx = self._widget.get_style_context()
Gtk.render_background(style_ctx, ctx, 0, 0, width, height)
ctx.save()
Gtk.render_layout(style_ctx, ctx, 0, 0 , layout)
ctx.restore()
Gtk.drag_set_icon_surface(drag_context, surface)
else:
try:
if map2class(target):
Gtk.drag_set_icon_pixbuf(drag_context,
map2class(target).ICON, 0, 0)
except:
Gtk.drag_set_icon_default(drag_context)
def object_drag_end(self, widget, drag_context):
""" Handle the end of a drag operation. """
pass
@@ -1218,7 +1250,10 @@ class ClipboardListView(object):
path = paths[0]
node = model.get_iter(path)
o = model.get_value(node,1)
sel_data.set(tgs[0], 8, o.pack())
if model.get_value(node, 0) == 'TEXT':
sel_data.set_text(o._value, -1)
else:
sel_data.set(tgs[0], 8, o.pack())
elif len(paths) > 1:
raw_list = []
for path in paths:
@@ -1279,54 +1314,57 @@ class ClipboardListView(object):
# Just select the first match.
wrapper_class = self._target_type_to_wrapper_class_map[
str(possible_wrappers[0])]
o = wrapper_class(self.dbstate, sel_data)
if title:
o._title = title
if value:
o._value = value
if dbid:
o._dbid = dbid
if dbname:
o._dbname = dbname
try:
o = wrapper_class(self.dbstate, sel_data)
if title:
o._title = title
if value:
o._value = value
if dbid:
o._dbid = dbid
if dbname:
o._dbname = dbname
# If the wrapper object is a subclass of ClipDropList then
# the drag data was a list of objects and we need to decode
# all of them.
if isinstance(o,ClipDropList):
o_list = o.get_objects()
else:
o_list = [o]
for o in o_list:
if o.__class__.DRAG_TARGET is None:
continue
data = [o.__class__.DRAG_TARGET.drag_type, o, None,
o._type, o._value, o._dbid, o._dbname]
contains = model_contains(model, data)
if ((context.action if hasattr(context, "action") else context.get_actions())
!= Gdk.DragAction.MOVE) and contains:
continue
drop_info = widget.get_dest_row_at_pos(x, y)
if drop_info:
path, position = drop_info
node = model.get_iter(path)
if (position == Gtk.TreeViewDropPosition.BEFORE
or position == Gtk.TreeViewDropPosition.INTO_OR_BEFORE):
model.insert_before(node, data)
else:
model.insert_after(node, data)
# If the wrapper object is a subclass of ClipDropList then
# the drag data was a list of objects and we need to decode
# all of them.
if isinstance(o,ClipDropList):
o_list = o.get_objects()
else:
model.append(data)
o_list = [o]
for o in o_list:
if o.__class__.DRAG_TARGET is None:
continue
data = [o.__class__.DRAG_TARGET.drag_type, o, None,
o._type, o._value, o._dbid, o._dbname]
contains = model_contains(model, data)
if ((context.action if hasattr(context, "action") else context.get_actions())
!= Gdk.DragAction.MOVE) and contains:
continue
drop_info = widget.get_dest_row_at_pos(x, y)
if drop_info:
path, position = drop_info
node = model.get_iter(path)
if (position == Gtk.TreeViewDropPosition.BEFORE
or position == Gtk.TreeViewDropPosition.INTO_OR_BEFORE):
model.insert_before(node, data)
else:
model.insert_after(node, data)
else:
model.append(data)
# FIXME: there is one bug here: if you multi-select and drop
# on self, then it moves the first, and copies the rest.
# FIXME: there is one bug here: if you multi-select and drop
# on self, then it moves the first, and copies the rest.
if ((context.action if hasattr(context, "action") else context.get_actions()) ==
Gdk.DragAction.MOVE):
context.finish(True, True, time)
if ((context.action if hasattr(context, "action") else context.get_actions()) ==
Gdk.DragAction.MOVE):
context.finish(True, True, time)
# remember time for double drop workaround.
self._previous_drop_time = realTime
return o_list
# remember time for double drop workaround.
self._previous_drop_time = realTime
return o_list
except EOFError:
return None
# proxy methods to provide access to the real widget functions.
+48 -18
View File
@@ -66,6 +66,7 @@ from gramps.gen.plug.utils import available_updates
from .plug import PluginWindows
from gramps.gen.errors import WindowActiveError
from .spell import HAVE_GTKSPELL
from gramps.gen.constfunc import win
_ = glocale.translation.gettext
#-------------------------------------------------------------------------
@@ -237,7 +238,7 @@ class ConfigureDialog(ManagedWindow):
obj.get_text(), parent=self.window)
obj.set_text('<b>%s</b>')
self.__config.set(constant, unicode(obj.get_text()))
self.__config.set(constant, conv_to_unicode(obj.get_text()))
def update_entry(self, obj, constant):
"""
@@ -1103,44 +1104,66 @@ class GrampsPreferences(ConfigureDialog):
return _('Display'), grid
def add_places_panel(self, configdialog):
row = 0
grid = Gtk.Grid()
grid.set_border_width(12)
grid.set_column_spacing(6)
grid.set_row_spacing(6)
self.add_checkbox(grid, _("Enable automatic place title generation"),
row, 'preferences.place-auto', stop=3)
auto = self.add_checkbox(grid,
_("Enable automatic place title generation"),
0, 'preferences.place-auto',
extra_callback=self.auto_title_changed)
row = 0
grid2 = Gtk.Grid()
grid2.set_border_width(12)
grid2.set_column_spacing(6)
grid2.set_row_spacing(6)
grid.attach(grid2, 1, 1, 1, 1)
self.place_widgets = []
cbox = self.add_checkbox(grid2, _("Suppress comma after house number"),
row, 'preferences.place-number', start=0)
self.place_widgets.append(cbox)
row += 1
self.add_checkbox(grid, _("Suppress comma after house number"),
row, 'preferences.place-number', stop=3)
row += 1
self.add_checkbox(grid, _("Reverse display order"),
row, 'preferences.place-reverse', stop=3)
cbox = self.add_checkbox(grid2, _("Reverse display order"),
row, 'preferences.place-reverse', start=0)
self.place_widgets.append(cbox)
row += 1
# Place restriction
obox = Gtk.ComboBoxText()
formats = [_("Full place name"),
_("-> Hamlet/VillageTown/City"),
_("Hamlet/VillageTown/City ->")]
_("-> Hamlet/Village/Town/City"),
_("Hamlet/Village/Town/City ->")]
list(map(obox.append_text, formats))
active = config.get('preferences.place-restrict')
obox.set_active(active)
obox.connect('changed', self.place_restrict_changed)
lwidget = BasicLabel("%s: " % _('Restrict'))
grid.attach(lwidget, 0, row, 1, 1)
grid.attach(obox, 1, row, 2, 1)
grid2.attach(lwidget, 0, row, 1, 1)
grid2.attach(obox, 1, row, 2, 1)
self.place_widgets.append(obox)
row += 1
self.add_entry(grid, _("Language"),
row, 'preferences.place-lang')
entry = self.add_entry(grid2, _("Language"),
row, 'preferences.place-lang')
self.place_widgets.append(entry)
row += 1
self.auto_title_changed(auto)
return _('Places'), grid
def auto_title_changed(self, obj):
"""
Update sensitivity of place configuration widgets.
"""
active = obj.get_active()
for widget in self.place_widgets:
widget.set_sensitive(active)
def add_text_panel(self, configdialog):
row = 0
grid = Gtk.Grid()
@@ -1264,8 +1287,15 @@ class GrampsPreferences(ConfigureDialog):
grid.set_row_spacing(6)
current_line = 0
self.add_checkbox(grid,
_('Add default source on GEDCOM import'),
if win():
self.add_checkbox(grid,
_('Use alternate Font handler for GUI and Reports '
'(requires restart)'),
current_line, 'preferences.alternate-fonthandler')
current_line += 1
self.add_checkbox(grid,
_('Add default source on GEDCOM import'),
current_line, 'preferences.default-source')
current_line += 1
+2 -3
View File
@@ -580,9 +580,8 @@ class DbManager(CLIDbManager):
node = self.model.get_iter(path)
filename = conv_to_unicode(self.model.get_value(node, FILE_COL), 'utf8')
try:
name_file = open(filename, "r")
file_name_to_delete=name_file.read()
name_file.close()
with open(filename, "r", encoding='utf-8') as name_file:
file_name_to_delete = name_file.read()
remove_filename(file_name_to_delete)
directory = conv_to_unicode(self.data_to_delete[1], 'utf8')
for (top, dirs, files) in os.walk(directory):
+5 -2
View File
@@ -24,6 +24,7 @@
#
#-------------------------------------------------------------------------
import sys
import html
import logging
_LOG = logging.getLogger(".dialog")
@@ -92,7 +93,8 @@ class QuestionDialog(object):
self.top.set_title("%s - Gramps" % msg1)
label1 = self.xml.get_object('qd_label1')
label1.set_text('<span weight="bold" size="larger">%s</span>' % msg1)
label1.set_text('<span weight="bold" size="larger">%s</span>' %
html.escape(msg1))
label1.set_use_markup(True)
label2 = self.xml.get_object('qd_label2')
@@ -124,7 +126,8 @@ class QuestionDialog2(object):
self.top.set_title("%s - Gramps" % msg1)
label1 = self.xml.get_object('qd_label1')
label1.set_text('<span weight="bold" size="larger">%s</span>' % msg1)
label1.set_text('<span weight="bold" size="larger">%s</span>' %
html.escape(msg1))
label1.set_use_markup(True)
label2 = self.xml.get_object('qd_label2')
+8 -3
View File
@@ -25,7 +25,7 @@
#-------------------------------------------------------------------------
import os
import webbrowser
import sys
#------------------------------------------------------------------------
#
# GRAMPS modules
@@ -33,7 +33,7 @@ import webbrowser
#------------------------------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.gen.const import URL_MANUAL_PAGE, URL_WIKISTRING
from gramps.gen.constfunc import is_quartz
from gramps.gen.constfunc import is_quartz, mac
from gramps.gen.config import config
from gramps.gui.utils import open_file_with_default_application as run_file
@@ -74,4 +74,9 @@ def display_url(link, uistate=None):
"""
Open the specified URL in a browser.
"""
webbrowser.open_new_tab(link)
if (mac() and sys.version_info.major == 3 and sys.version_info.minor < 5):
import subprocess
proc = subprocess.call(['/usr/bin/open', link],
stderr=subprocess.STDOUT)
else:
webbrowser.open_new_tab(link)
+5 -4
View File
@@ -1210,16 +1210,17 @@ class EditFamily(EditPrimary):
child = self.db.get_person_from_handle(ref.ref)
if child:
pname = child.get_primary_name()
preset_name(child, name)
if len(name.get_surname_list()) < 2:
preset_name(child, name) # add the known family surnames, etc.
surnames = name.get_surname_list()
if len(surnames) < 2:
return name
else:
#return first for the father, and last for the mother
if parent == 'father':
name.set_surname_list(name.get_surname_list()[0])
name.set_surname_list([surnames[0]])
return name
else:
name.set_surname_list(name.get_surname_list()[-1])
name.set_surname_list([surnames[-1]])
return name
return name
+5
View File
@@ -303,6 +303,11 @@ class EditNote(EditPrimary):
self.obj.set_styledtext(text)
_LOG.debug(str(text))
def close(self, *obj):
"""Called when cancel button clicked."""
self.update_note()
super().close()
def save(self, *obj):
"""Save the data."""
self.ok_button.set_sensitive(False)
+3 -3
View File
@@ -245,7 +245,7 @@ class EditPerson(EditPrimary):
WIKI_HELP_PAGE,
_('manual|Editing_information_about_people'))
self.given.connect("focus_out_event", self._given_focus_out_event)
self.given.connect("focus-out-event", self._given_focus_out_event)
self.top.get_object("editnamebtn").connect("clicked",
self._edit_name_clicked)
self.top.get_object("multsurnamebtn").connect("clicked",
@@ -696,8 +696,8 @@ class EditPerson(EditPrimary):
None, None, self._make_home_person),
])
self.all_action.set_visible(True)
self.home_action.set_visible(True)
self.all_action.set_visible(not self.added)
self.home_action.set_visible(not self.added)
ui_top_cm = '''
<menuitem action="ActivePerson"/>
+3 -3
View File
@@ -559,7 +559,7 @@ class EditRule(ManagedWindow):
key=lambda s: s.lower())
t = MySelect(_name2typeclass[v], additional)
elif v == _('Inclusive:'):
t = MyBoolean(_('Include original person'))
t = MyBoolean(_('Include selected Gramps ID'))
elif v == _('Case sensitive:'):
t = MyBoolean(_('Use exact case of letters'))
elif v == _('Regular-Expression matching:'):
@@ -581,8 +581,8 @@ class EditRule(ManagedWindow):
elif v == _('Day of Week:'):
long_days = displayer.long_days
days_of_week = long_days[2:] + long_days[1:2]
t = MyList(map(str, range(7)), days_of_week)
else:
t = MyList(list(map(str, range(7))), days_of_week)
else:
t = MyEntry()
t.set_hexpand(True)
tlist.append(t)
@@ -142,15 +142,7 @@ class CitationSidebarFilter(SidebarFilter):
gid = str(self.filter_id.get_text()).strip()
page = str(self.filter_page.get_text()).strip()
date = str(self.filter_date.get_text()).strip()
model = self.filter_conf.get_model()
node = self.filter_conf.get_active_iter()
conf_name = model.get_value(node, 0) # The value is actually the text
conf = Citation.CONF_NORMAL
for i in list(conf_strings.keys()):
if _(conf_strings[i]) == conf_name:
conf = i
break
# conf = self.citn.get_confidence_level()
conf = str(self.filter_conf.get_active())
note = str(self.filter_note.get_text()).strip()
regex = self.filter_regex.get_active()
tag = self.tag.get_active() > 0
@@ -67,20 +67,30 @@ class FamilySidebarFilter(SidebarFilter):
self.filter_event = Event()
self.filter_event.set_type((EventType.CUSTOM, ''))
self.etype = Gtk.ComboBox(has_entry=True)
try: # should use if dbstate.is_open(), but not in gramps42
self.custom_types = dbstate.db.get_event_types()
except:
self.custom_types = []
self.family_stub = Family()
self.family_stub.set_relationship((FamilyRelType.CUSTOM, ''))
self.rtype = Gtk.ComboBox(has_entry=True)
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_family = Family()
self.filter_family.set_relationship((FamilyRelType.CUSTOM, ''))
self.rtype = Gtk.ComboBox(has_entry=True)
try: # should use if dbstate.is_open(), but not in gramps42
self.custom_types = dbstate.db.get_family_relation_types()
except:
self.custom_types = []
self.rel_menu = widgets.MonitoredDataType(
self.rtype,
self.family_stub.set_relationship,
self.family_stub.get_relationship)
self.filter_family.set_relationship,
self.filter_family.get_relationship,
custom_values=self.custom_types)
self.filter_note = widgets.BasicEntry()
@@ -137,7 +147,7 @@ class FamilySidebarFilter(SidebarFilter):
child = str(self.filter_child.get_text()).strip()
note = str(self.filter_note.get_text()).strip()
etype = self.filter_event.get_type().xml_str()
rtype = self.family_stub.get_relationship().xml_str()
rtype = self.filter_family.get_relationship().xml_str()
regex = self.filter_regex.get_active()
tag = self.tag.get_active() > 0
generic = self.generic.get_active() > 0
@@ -78,10 +78,15 @@ class PersonSidebarFilter(SidebarFilter):
self.filter_event = Event()
self.filter_event.set_type((EventType.CUSTOM, ''))
self.etype = Gtk.ComboBox(has_entry=True)
try: # Should use if dbstate.isopen() but not in gramps42
self.custom_types = dbstate.db.get_event_types()
except:
self.custom_types = []
self.event_menu = widgets.MonitoredDataType(
self.etype,
self.filter_event.set_type,
self.filter_event.get_type)
self.etype,
self.filter_event.set_type,
self.filter_event.get_type,
custom_values=self.custom_types)
self.filter_note = widgets.BasicEntry()
self.filter_gender = Gtk.ComboBoxText()
@@ -139,7 +139,7 @@ class PlaceSidebarFilter(SidebarFilter):
generic_filter.add_rule(rule)
if enclosed:
rule = IsEnclosedBy([enclosed])
rule = IsEnclosedBy([enclosed, '0'])
generic_filter.add_rule(rule)
rule = HasData([name, ptype, code], use_regex=regex)
+4 -1
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkDialog" id="hidedialog">
@@ -97,6 +97,7 @@
<property name="margin_bottom">12</property>
<property name="hexpand">True</property>
<property name="wrap">True</property>
<property name="max_width_chars">80</property>
</object>
<packing>
<property name="left_attach">1</property>
@@ -760,6 +761,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">label</property>
<property name="max_width_chars">80</property>
</object>
<packing>
<property name="expand">False</property>
@@ -778,6 +780,7 @@
<property name="label" translatable="yes">label</property>
<property name="use_markup">True</property>
<property name="wrap">True</property>
<property name="max_width_chars">80</property>
</object>
<packing>
<property name="expand">False</property>
+1 -1
View File
@@ -198,7 +198,7 @@
<child>
<object class="GtkComboBox" id="confidence">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Conveys the submitter's quantitative evaluation of the credibility of a piece of information, based upon its supporting evidence. It is not intended to eliminate the receiver's need to evaluate the evidence for themselves.
Very Low =Unreliable evidence or estimated data
Low =Questionable reliability of evidence (interviews, census, oral genealogies, or potential for bias for example, an autobiography)
+2 -2
View File
@@ -266,7 +266,7 @@
</attributes>
</object>
<packing>
<property name="left_attach">3</property>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
@@ -298,7 +298,7 @@
</attributes>
</object>
<packing>
<property name="left_attach">0</property>
<property name="left_attach">3</property>
<property name="top_attach">0</property>
</packing>
</child>
+3 -1
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<requires lib="grampswidgets" version="0.0"/>
@@ -247,11 +247,13 @@
<property name="use_action_appearance">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Select Family</property>
<property name="relief">none</property>
<child>
<object class="GtkImage" id="image2693">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">gtk-index</property>
<child internal-child="accessible">
<object class="AtkObject" id="image2693-atkobject">
<property name="AtkObject::accessible-description" translatable="yes">Selector</property>
+1 -1
View File
@@ -3,7 +3,7 @@
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkDialog" id="reorder">
<property name="visible">True</property>
<property name="visible">False</property>
<property name="can_focus">False</property>
<property name="border_width">12</property>
<property name="default_width">500</property>
+4 -1
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<requires lib="grampswidgets" version="0.0"/>
@@ -947,6 +947,7 @@
<property name="halign">center</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
<property name="group">lalign</property>
</object>
<packing>
<property name="expand">False</property>
@@ -964,6 +965,7 @@
<property name="halign">center</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
<property name="group">lalign</property>
</object>
<packing>
<property name="expand">False</property>
@@ -981,6 +983,7 @@
<property name="halign">center</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
<property name="group">lalign</property>
</object>
<packing>
<property name="expand">False</property>
+3 -2
View File
@@ -32,8 +32,6 @@ from gi.repository import Gtk
# Standard Python modules
#
#-------------------------------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
from collections import defaultdict
#-------------------------------------------------------------------------
@@ -41,6 +39,8 @@ from collections import defaultdict
# GRAMPS modules
#
#-------------------------------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
from gramps.gen.const import PLUGINS_GLADE
from gramps.gen.plug.report._constants import standalone_categories
from . import tool
@@ -88,6 +88,7 @@ class PluginDialog(ManagedWindow):
self.uistate = uistate
self.dialog = Gtk.Builder()
self.dialog.set_translation_domain(glocale.get_localedomain())
self.dialog.add_from_file(PLUGINS_GLADE)
self.dialog.connect_signals({
"on_report_apply_clicked" : self.on_apply_clicked,
+1 -1
View File
@@ -119,7 +119,7 @@ class ExportAssistant(Gtk.Assistant, ManagedWindow) :
#set_window is present in both parent classes
ManagedWindow.set_window(self, self, None,
self.top_title, isWindow=True)
self.top_title, isWindow=True)
#set up callback method for the export plugins
self.callback = self.pulse_progressbar
+1 -1
View File
@@ -70,7 +70,7 @@ class DisplayBuf(ManagedWindow):
scrolled_window.add(document.text_view)
self.window.vbox.pack_start(scrolled_window, True, True, 0)
self.window.show_all()
def build_menu_names(self, obj):
return ('View', _('Quick View'))
+10 -3
View File
@@ -101,6 +101,8 @@ def _initialize_options(options, dbstate, uistate):
if not hasattr(options, "menu"):
return
dbase = dbstate.get_database()
if dbase.get_total() == 0:
return
menu = options.menu
for name in menu.get_all_option_names():
@@ -142,6 +144,8 @@ def _get_subject(options, dbase):
options: The ReportOptions class
dbase: the database for which it corresponds
"""
if dbase.get_total() == 0:
return
if not hasattr(options, "menu"):
return ""
menu = options.menu
@@ -366,6 +370,9 @@ class BookSelector(ManagedWindow):
def __init__(self, dbstate, uistate):
self.db = dbstate.db
if self.db.get_total() == 0:
WarningDialog(_("Your database is empty."), parent=uistate.window)
return
self.dbstate = dbstate
self.uistate = uistate
self.title = _('Book')
@@ -716,7 +723,7 @@ class BookSelector(ManagedWindow):
"""
if self.book.item_list:
BookDialog(self.dbstate, self.uistate,
self.book, BookOptions)
self.book, BookOptions, track=self.track)
else:
WarningDialog(_('No items'), _('This book has no items.'),
parent=self.window)
@@ -909,14 +916,14 @@ class BookDialog(DocReportDialog):
Create a dialog selecting target, format, and paper/HTML options.
"""
def __init__(self, dbstate, uistate, book, options):
def __init__(self, dbstate, uistate, book, options, track=[]):
self.format_menu = None
self.options = options
self.is_from_saved_book = False
self.page_html_added = False
self.book = book
DocReportDialog.__init__(self, dbstate, uistate, options,
'book', _("Book"))
'book', _("Book"), track=track)
self.options.options_dict['bookname'] = self.book.name
self.database = dbstate.db
+4 -3
View File
@@ -58,16 +58,17 @@ class DocReportDialog(ReportDialog):
dialogs for docgen derived reports.
"""
def __init__(self, dbstate, uistate, option_class, name, trans_name):
def __init__(self, dbstate, uistate, option_class, name, trans_name,
track=[]):
"""Initialize a dialog to request that the user select options
for a basic *stand-alone* report."""
self.style_name = "default"
self.firstpage_added = False
self.CSS = PLUGMAN.process_plugin_data('WEBSTUFF')
self.dbname = dbstate.db.get_dbname()
ReportDialog.__init__(self, dbstate, uistate, option_class,
name, trans_name)
name, trans_name, track=track)
# Allow for post processing of the format frame, since the
# show_all task calls events that may reset values
@@ -0,0 +1,288 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2007-2008 Brian G. Matherly
# Copyright (C) 2007-2009 Stephane Charette
# Copyright (C) 2009 Gary Burton
# Contribution 2009 by Bob Ham <rah@bash.sh>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2012-2013 Paul Franklin
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""base class for generating dialogs for graph-based reports """
#------------------------------------------------------------------------
#
# python modules
#
#------------------------------------------------------------------------
from abc import ABCMeta, abstractmethod
import os
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
#-------------------------------------------------------------------------------
#
# GTK+ modules
#
#-------------------------------------------------------------------------------
from gi.repository import Gtk
from gi.repository import GObject
#-------------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------------
from gramps.gen.config import config
from gramps.gen.plug.report import CATEGORY_GRAPHVIZ
from ._reportdialog import ReportDialog
from ._papermenu import PaperFrame
import gramps.gen.plug.docgen.graphdoc as graphdoc
from gramps.gen.plug.menu import Menu
#-------------------------------------------------------------------------------
#
# BaseFormatComboBox
#
#-------------------------------------------------------------------------------
class BaseFormatComboBox(Gtk.ComboBox):
"""
Combo box base class for graph-based report format choices.
"""
FORMATS=[]
def set(self, active=None):
self.store = Gtk.ListStore(GObject.TYPE_STRING)
self.set_model(self.store)
cell = Gtk.CellRendererText()
self.pack_start(cell, True)
self.add_attribute(cell, 'text', 0)
index = 0
active_index = 0
for item in self.FORMATS:
name = item["descr"]
self.store.append(row=[name])
if item['type'] == active:
active_index = index
index += 1
self.set_active(active_index)
def get_label(self):
return self.FORMATS[self.get_active()]["descr"]
def get_reference(self):
return self.FORMATS[self.get_active()]["class"]
def get_paper(self):
return 1
def get_styles(self):
return 0
def get_ext(self):
return '.%s' % self.FORMATS[self.get_active()]['ext']
def get_oformat_str(self): # the report's output-format type
return self.FORMATS[self.get_active()]["type"]
def is_file_output(self):
return True
def get_clname(self):
return self.FORMATS[self.get_active()]["type"]
#-----------------------------------------------------------------------
#
# GraphReportDialog
#
#-----------------------------------------------------------------------
class GraphReportDialog(ReportDialog, metaclass=ABCMeta):
"""A base class of ReportDialog customized for graph-based reports."""
def __init__(self, dbstate, uistate, opt, name, translated_name):
"""Initialize a dialog to request that the user select options
for a graphviz report. See the ReportDialog class for
more information."""
self.category = self.get_category()
self._goptions = self.get_options()
self.dbname = dbstate.db.get_dbname()
ReportDialog.__init__(self, dbstate, uistate, opt,
name, translated_name)
def init_options(self, option_class):
try:
if issubclass(option_class, object): # Old-style class
self.options = option_class(self.raw_name,
self.dbstate.get_database())
except TypeError:
self.options = option_class
menu = Menu()
self._goptions.add_menu_options(menu)
for category in menu.get_categories():
for name in menu.get_option_names(category):
option = menu.get_option(category, name)
self.options.add_menu_option(category, name, option)
self.options.load_previous_values()
def init_interface(self):
ReportDialog.init_interface(self)
self.doc_type_changed(self.format_menu)
self.notebook.set_current_page(1) # don't start on "Paper Options"
def setup_format_frame(self):
"""Set up the format frame of the dialog."""
self.make_doc_menu()
self.format_menu.set(self.options.handler.get_format_name())
self.format_menu.connect('changed', self.doc_type_changed)
label = Gtk.Label(label="%s:" % _("Output Format"))
label.set_halign(Gtk.Align.START)
self.grid.attach(label, 1, self.row, 1, 1)
self.format_menu.set_hexpand(True)
self.grid.attach(self.format_menu, 2, self.row, 2, 1)
self.row += 1
self.open_with_app = Gtk.CheckButton(_("Open with default viewer"))
self.open_with_app.set_active(
config.get('interface.open-with-default-viewer'))
self.grid.attach(self.open_with_app, 2, self.row, 2, 1)
self.row += 1
ext = self.format_menu.get_ext()
if ext is None:
ext = ""
else:
spath = self.get_default_directory()
if self.options.get_output():
base = os.path.basename(self.options.get_output())
else:
if self.dbname is None:
default_name = self.raw_name
else:
default_name = self.dbname + "_" + self.raw_name
base = "%s%s" % (default_name, ext) # "ext" already has a dot
spath = os.path.normpath(os.path.join(spath, base))
self.target_fileentry.set_filename(spath)
def setup_report_options_frame(self):
self.paper_label = Gtk.Label(label='<b>%s</b>' % _("Paper Options"))
self.paper_label.set_use_markup(True)
handler = self.options.handler
self.paper_frame = PaperFrame(
handler.get_paper_metric(),
handler.get_paper_name(),
handler.get_orientation(),
handler.get_margins(),
handler.get_custom_paper_size(),
)
self.notebook.insert_page(self.paper_frame, self.paper_label, 0)
self.paper_frame.show_all()
ReportDialog.setup_report_options_frame(self)
def doc_type_changed(self, obj):
"""
This routine is called when the user selects a new file
format for the report. It adjusts the various dialog sections
to reflect the appropriate values for the currently selected
file format. For example, a HTML document doesn't need any
paper size/orientation options, but it does need a template
file. Those changes are made here.
"""
self.open_with_app.set_sensitive(True)
fname = self.target_fileentry.get_full_path(0)
(spath, ext) = os.path.splitext(fname)
ext_val = obj.get_ext()
if ext_val:
fname = spath + ext_val
else:
fname = spath
self.target_fileentry.set_filename(fname)
def make_document(self):
"""Create a document of the type requested by the user.
"""
pstyle = self.paper_frame.get_paper_style()
self.doc = self.format(self.options, pstyle)
self.options.set_document(self.doc)
def on_ok_clicked(self, obj):
"""The user is satisfied with the dialog choices. Validate
the output file name before doing anything else. If there is
a file name, gather the options and create the report."""
# Is there a filename? This should also test file permissions, etc.
if not self.parse_target_frame():
self.window.run()
# Preparation
self.parse_format_frame()
self.parse_user_options()
self.options.handler.set_paper_metric(
self.paper_frame.get_paper_metric())
self.options.handler.set_paper_name(self.paper_frame.get_paper_name())
self.options.handler.set_orientation(self.paper_frame.get_orientation())
self.options.handler.set_margins(self.paper_frame.get_paper_margins())
self.options.handler.set_custom_paper_size(
self.paper_frame.get_custom_paper_size())
# Create the output document.
self.make_document()
# Save options
self.options.handler.save_options()
config.set('interface.open-with-default-viewer',
self.open_with_app.get_active())
def parse_format_frame(self):
"""Parse the format frame of the dialog. Save the user
selected output format for later use."""
self.format = self.format_menu.get_reference()
format_name = self.format_menu.get_clname()
self.options.handler.set_format_name(format_name)
def setup_style_frame(self):
"""Required by ReportDialog"""
pass
@abstractmethod
def make_doc_menu(self):
"""
Build a menu of document types that are appropriate for
this graph report.
"""
@abstractmethod
def get_category(self):
"""
Return the report category.
"""
@abstractmethod
def get_options(self):
"""
Return the graph options.
"""
+38 -225
View File
@@ -1,12 +1,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2007-2008 Brian G. Matherly
# Copyright (C) 2007-2009 Stephane Charette
# Copyright (C) 2009 Gary Burton
# Contribution 2009 by Bob Ham <rah@bash.sh>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2012-2013 Paul Franklin
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -23,174 +18,42 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
#------------------------------------------------------------------------
#
# python modules
#
#------------------------------------------------------------------------
import os
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
"""class for generating dialogs for graphviz-based reports """
#-------------------------------------------------------------------------------
#
# GTK+ modules
# Gramps modules
#
#-------------------------------------------------------------------------------
from gi.repository import Gtk
from gi.repository import GObject
#-------------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------------
from gramps.gen.config import config
from ._graphreportdialog import GraphReportDialog, BaseFormatComboBox
from gramps.gen.plug.report import CATEGORY_GRAPHVIZ
from ._reportdialog import ReportDialog
from ._papermenu import PaperFrame
import gramps.gen.plug.docgen.graphdoc as graphdoc
from gramps.gen.plug.menu import Menu
#-------------------------------------------------------------------------------
#
# GraphvizFormatComboBox
#
#-------------------------------------------------------------------------------
class GraphvizFormatComboBox(Gtk.ComboBox):
"""
Format combo box class for Graphviz report.
"""
def set(self, active=None):
self.store = Gtk.ListStore(GObject.TYPE_STRING)
self.set_model(self.store)
cell = Gtk.CellRendererText()
self.pack_start(cell, True)
self.add_attribute(cell, 'text', 0)
index = 0
active_index = 0
for item in graphdoc.FORMATS:
name = item["descr"]
self.store.append(row=[name])
if item['type'] == active:
active_index = index
index += 1
self.set_active(active_index)
def get_label(self):
return graphdoc.FORMATS[self.get_active()]["descr"]
def get_reference(self):
return graphdoc.FORMATS[self.get_active()]["class"]
def get_paper(self):
return 1
def get_styles(self):
return 0
def get_ext(self):
return '.%s' % graphdoc.FORMATS[self.get_active()]['ext']
def get_oformat_str(self): # the report's output-format type
return graphdoc.FORMATS[self.get_active()]["type"]
def is_file_output(self):
return True
def get_clname(self):
return graphdoc.FORMATS[self.get_active()]["type"]
#-----------------------------------------------------------------------
#
# GraphvizReportDialog
#
#-----------------------------------------------------------------------
class GraphvizReportDialog(ReportDialog):
"""A class of ReportDialog customized for graphviz based reports."""
def __init__(self, dbstate, uistate, opt, name, translated_name):
"""Initialize a dialog to request that the user select options
for a graphviz report. See the ReportDialog class for
more information."""
self.category = CATEGORY_GRAPHVIZ
self.__gvoptions = graphdoc.GVOptions()
self.dbname = dbstate.db.get_dbname()
ReportDialog.__init__(self, dbstate, uistate, opt,
name, translated_name)
def init_options(self, option_class):
try:
if issubclass(option_class, object): # Old-style class
self.options = option_class(self.raw_name,
self.dbstate.get_database())
except TypeError:
self.options = option_class
menu = Menu()
self.__gvoptions.add_menu_options(menu)
for category in menu.get_categories():
for name in menu.get_option_names(category):
option = menu.get_option(category, name)
self.options.add_menu_option(category, name, option)
self.options.load_previous_values()
class GraphvizReportDialog(GraphReportDialog):
def init_interface(self):
ReportDialog.init_interface(self)
self.doc_type_changed(self.format_menu)
self.notebook.set_current_page(1) # don't start on "Paper Options"
def setup_format_frame(self):
"""Set up the format frame of the dialog."""
def make_doc_menu(self):
"""
Build a menu of document types that are appropriate for
this graph report.
"""
self.format_menu = GraphvizFormatComboBox()
self.format_menu.set(self.options.handler.get_format_name())
self.format_menu.connect('changed', self.doc_type_changed)
label = Gtk.Label(label="%s:" % _("Output Format"))
label.set_halign(Gtk.Align.START)
self.grid.attach(label, 1, self.row, 1, 1)
self.format_menu.set_hexpand(True)
self.grid.attach(self.format_menu, 2, self.row, 2, 1)
self.row += 1
self.open_with_app = Gtk.CheckButton(_("Open with default viewer"))
self.open_with_app.set_active(
config.get('interface.open-with-default-viewer'))
self.grid.attach(self.open_with_app, 2, self.row, 2, 1)
self.row += 1
def get_category(self):
"""
Return the report category.
"""
return CATEGORY_GRAPHVIZ
ext = self.format_menu.get_ext()
if ext is None:
ext = ""
else:
spath = self.get_default_directory()
if self.options.get_output():
base = os.path.basename(self.options.get_output())
else:
if self.dbname is None:
default_name = self.raw_name
else:
default_name = self.dbname + "_" + self.raw_name
base = "%s%s" % (default_name, ext) # "ext" already has a dot
spath = os.path.normpath(os.path.join(spath, base))
self.target_fileentry.set_filename(spath)
def setup_report_options_frame(self):
self.paper_label = Gtk.Label(label='<b>%s</b>' % _("Paper Options"))
self.paper_label.set_use_markup(True)
handler = self.options.handler
self.paper_frame = PaperFrame(
handler.get_paper_metric(),
handler.get_paper_name(),
handler.get_orientation(),
handler.get_margins(),
handler.get_custom_paper_size(),
)
self.notebook.insert_page(self.paper_frame, self.paper_label, 0)
self.paper_frame.show_all()
ReportDialog.setup_report_options_frame(self)
def get_options(self):
"""
Return the graph options.
"""
return graphdoc.GVOptions()
def doc_type_changed(self, obj):
"""
@@ -201,81 +64,31 @@ class GraphvizReportDialog(ReportDialog):
paper size/orientation options, but it does need a template
file. Those changes are made here.
"""
self.open_with_app.set_sensitive(True)
fname = self.target_fileentry.get_full_path(0)
(spath, ext) = os.path.splitext(fname)
GraphReportDialog.doc_type_changed(self, obj)
ext_val = obj.get_ext()
if ext_val:
fname = spath + ext_val
else:
fname = spath
self.target_fileentry.set_filename(fname)
output_format_str = obj.get_oformat_str()
output_format_str = obj.get_clname()
if output_format_str in ['gvpdf', 'gspdf', 'ps']:
# Always use 72 DPI for PostScript and PDF files.
self.__gvoptions.dpi.set_value(72)
self.__gvoptions.dpi.set_available(False)
self._goptions.dpi.set_value(72)
self._goptions.dpi.set_available(False)
else:
self.__gvoptions.dpi.set_available(True)
self._goptions.dpi.set_available(True)
if output_format_str in ['gspdf', 'dot']:
# Multiple pages only valid for dot and PDF via GhostsScript.
self.__gvoptions.h_pages.set_available(True)
self.__gvoptions.v_pages.set_available(True)
self._goptions.h_pages.set_available(True)
self._goptions.v_pages.set_available(True)
else:
self.__gvoptions.h_pages.set_value(1)
self.__gvoptions.v_pages.set_value(1)
self.__gvoptions.h_pages.set_available(False)
self.__gvoptions.v_pages.set_available(False)
self._goptions.h_pages.set_value(1)
self._goptions.v_pages.set_value(1)
self._goptions.h_pages.set_available(False)
self._goptions.v_pages.set_available(False)
def make_document(self):
"""Create a document of the type requested by the user.
"""
pstyle = self.paper_frame.get_paper_style()
self.doc = self.format(self.options, pstyle)
self.options.set_document(self.doc)
def on_ok_clicked(self, obj):
"""The user is satisfied with the dialog choices. Validate
the output file name before doing anything else. If there is
a file name, gather the options and create the report."""
# Is there a filename? This should also test file permissions, etc.
if not self.parse_target_frame():
self.window.run()
# Preparation
self.parse_format_frame()
self.parse_user_options()
self.options.handler.set_paper_metric(
self.paper_frame.get_paper_metric())
self.options.handler.set_paper_name(self.paper_frame.get_paper_name())
self.options.handler.set_orientation(self.paper_frame.get_orientation())
self.options.handler.set_margins(self.paper_frame.get_paper_margins())
self.options.handler.set_custom_paper_size(
self.paper_frame.get_custom_paper_size())
# Create the output document.
self.make_document()
# Save options
self.options.handler.save_options()
config.set('interface.open-with-default-viewer',
self.open_with_app.get_active())
def parse_format_frame(self):
"""Parse the format frame of the dialog. Save the user
selected output format for later use."""
self.format = self.format_menu.get_reference()
format_name = self.format_menu.get_clname()
self.options.handler.set_format_name(format_name)
def setup_style_frame(self):
"""Required by ReportDialog"""
pass
#-------------------------------------------------------------------------------
#
# GraphvizFormatComboBox
#
#-------------------------------------------------------------------------------
class GraphvizFormatComboBox(BaseFormatComboBox):
FORMATS = graphdoc.FORMATS
+6 -2
View File
@@ -54,8 +54,9 @@ from .. import add_gui_options, make_gui_option
from ...user import User
from ...dialog import ErrorDialog, OptionDialog
from gramps.gen.plug.report import (CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_BOOK,
CATEGORY_CODE, CATEGORY_WEB, CATEGORY_GRAPHVIZ,
standalone_categories)
CATEGORY_CODE, CATEGORY_WEB,
CATEGORY_GRAPHVIZ, CATEGORY_TREE,
standalone_categories)
from gramps.gen.plug.docgen import StyleSheet, StyleSheetList
from ...managedwindow import ManagedWindow
from ._stylecombobox import StyleComboBox
@@ -673,6 +674,9 @@ def report(dbstate, uistate, person, report_class, options_class,
elif category == CATEGORY_GRAPHVIZ:
from ._graphvizreportdialog import GraphvizReportDialog
dialog_class = GraphvizReportDialog
elif category == CATEGORY_TREE:
from ._treereportdialog import TreeReportDialog
dialog_class = TreeReportDialog
elif category == CATEGORY_WEB:
from ._webreportdialog import WebReportDialog
dialog_class = WebReportDialog
@@ -0,0 +1,64 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""class for generating dialogs for graphviz-based reports """
#-------------------------------------------------------------------------------
#
# Gramps modules
#
#-------------------------------------------------------------------------------
from ._graphreportdialog import GraphReportDialog, BaseFormatComboBox
from gramps.gen.plug.report import CATEGORY_TREE
import gramps.gen.plug.docgen.treedoc as treedoc
#-----------------------------------------------------------------------
#
# TreeReportDialog
#
#-----------------------------------------------------------------------
class TreeReportDialog(GraphReportDialog):
def make_doc_menu(self):
"""
Build a menu of document types that are appropriate for
this graph report.
"""
self.format_menu = TreeFormatComboBox()
def get_category(self):
"""
Return the report category.
"""
return CATEGORY_TREE
def get_options(self):
"""
Return the graph options.
"""
return treedoc.TreeOptions()
#-------------------------------------------------------------------------------
#
# TreeFormatComboBox
#
#-------------------------------------------------------------------------------
class TreeFormatComboBox(BaseFormatComboBox):
FORMATS = treedoc.FORMATS
+4
View File
@@ -58,12 +58,16 @@ HAVE_GTKSPELL = False
repository = Repository.get_default()
if repository.enumerate_versions("GtkSpell"):
try:
import gi
gi.require_version('GtkSpell', '3.0')
from gi.repository import GtkSpell as Gtkspell
HAVE_GTKSPELL = True
except:
pass
elif repository.enumerate_versions("Gtkspell"):
try:
import gi
gi.require_version('GtkSpell', '3.0')
from gi.repository import Gtkspell
HAVE_GTKSPELL = True
except:
+4 -1
View File
@@ -121,10 +121,11 @@ class UndoHistory(ManagedWindow):
self.window.vbox.pack_start(scrolled_window, True, True, 0)
self.window.show_all()
self.sel_chng_hndlr = self.selection.connect('changed',
self._selection_changed)
self._build_model()
self._update_ui()
self.selection.connect('changed', self._selection_changed)
self.show()
def _selection_changed(self, obj):
@@ -227,6 +228,7 @@ class UndoHistory(ManagedWindow):
)
def _build_model(self):
self.selection.handler_block(self.sel_chng_hndlr)
self.model.clear()
fg = bg = None
@@ -244,6 +246,7 @@ class UndoHistory(ManagedWindow):
mod_text = txn.get_description()
self.model.append(row=[time_text, mod_text, fg, bg])
path = (self.undodb.undo_count,)
self.selection.handler_unblock(self.sel_chng_hndlr)
self.selection.select_path(path)
def update(self):
+15
View File
@@ -538,6 +538,21 @@ def rgb_to_hex(rgb):
rgbint = (int(rgb[0] * 255), int(rgb[1] * 255), int(rgb[2] * 255))
return '#%02x%02x%02x' % rgbint
def get_link_color(context):
"""
Find the link color for the current theme.
"""
from gi.repository import Gtk
if Gtk.get_minor_version() > 11:
col = context.get_color(Gtk.StateFlags.LINK)
else:
found, col = context.lookup_color('link_color')
if not found:
col.parse('blue')
return rgb_to_hex((col.red, col.green, col.blue))
def edit_object(dbstate, uistate, reftype, ref):
"""
Invokes the appropriate editor for an object type and given handle.
+6 -8
View File
@@ -278,14 +278,12 @@ class ListView(NavigationView):
def foreground_color(self, column, renderer, model, iter_, data=None):
'''
Set the foreground color of the cell renderer. We use a cell data
function because we don't want to set the color of untagged rows.
function because there is a problem returning None from a model.
'''
fg_color = model.get_value(iter_, model.color_column())
#for color errors, typically color column is badly set
if fg_color:
renderer.set_property('foreground', fg_color)
else:
LOG.debug('Bad color set: ' + str(fg_color))
if fg_color == '':
fg_color = None
renderer.set_property('foreground', fg_color)
def set_active(self):
"""
@@ -891,7 +889,7 @@ class ListView(NavigationView):
self.edit(obj)
return True
# Custom interactive search
if event.string:
if Gdk.keyval_to_unicode(event.keyval):
return self.searchbox.treeview_keypress(obj, event)
return False
@@ -919,7 +917,7 @@ class ListView(NavigationView):
else:
self.edit(obj)
return True
elif event.string:
elif Gdk.keyval_to_unicode(event.keyval):
# Custom interactive search
return self.searchbox.treeview_keypress(obj, event)
return False
+1 -1
View File
@@ -353,7 +353,7 @@ class NavigationView(PageView):
dialog.vbox.set_spacing(10)
dialog.vbox.set_border_width(12)
hbox = Gtk.Box()
hbox.pack_start(Gtk.Label("%s: " % _('ID', True, True, 0)), False)
hbox.pack_start(Gtk.Label(label="%s: " % _('ID')), True, True, 0)
text = Gtk.Entry()
text.set_activates_default(True)
hbox.pack_start(text, False, True, 0)
+1 -1
View File
@@ -628,7 +628,7 @@ class EditTag(object):
hbox.pack_start(self.color, False, False, 5)
top.add_button(_('_Help'), Gtk.ResponseType.HELP)
top.add_button(_('_OK'), Gtk.ResponseType.OK)
top.add_button(_('_Cancel'), Gtk.ResponseType.CANCEL)
top.add_button(_('_OK'), Gtk.ResponseType.OK)
top.show_all()
return top
@@ -138,7 +138,7 @@ class CitationBaseModel(object):
tag_handle = data[0]
cached, tag_color = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached:
tag_color = "#000000000000"
tag_color = ""
tag_priority = None
for handle in data[COLUMN_TAGS]:
tag = self.db.get_tag_from_handle(handle)
@@ -297,7 +297,7 @@ class CitationBaseModel(object):
tag_handle = data[0]
cached, tag_color = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached:
tag_color = "#000000000000"
tag_color = ""
tag_priority = None
for handle in data[COLUMN2_TAGS]:
tag = self.db.get_tag_from_handle(handle)
+1 -1
View File
@@ -208,7 +208,7 @@ class EventModel(FlatBaseModel):
tag_handle = data[0]
cached, tag_color = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached:
tag_color = "#000000000000"
tag_color = ""
tag_priority = None
for handle in data[COLUMN_TAGS]:
tag = self.db.get_tag_from_handle(handle)
+1 -1
View File
@@ -220,7 +220,7 @@ class FamilyModel(FlatBaseModel):
tag_handle = data[0]
cached, tag_color = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached:
tag_color = "#000000000000"
tag_color = ""
tag_priority = None
for handle in data[13]:
tag = self.db.get_tag_from_handle(handle)
+1 -1
View File
@@ -187,7 +187,7 @@ class MediaModel(FlatBaseModel):
tag_handle = data[0]
cached, tag_color = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached:
tag_color = "#000000000000"
tag_color = ""
tag_priority = None
for handle in data[11]:
tag = self.db.get_tag_from_handle(handle)
+1 -1
View File
@@ -150,7 +150,7 @@ class NoteModel(FlatBaseModel):
tag_handle = data[0]
cached, value = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached:
tag_color = "#000000000000"
tag_color = ""
tag_priority = None
for handle in data[Note.POS_TAGS]:
tag = self.db.get_tag_from_handle(handle)
+1 -1
View File
@@ -545,7 +545,7 @@ class PeopleBaseModel(BaseModel):
tag_handle = data[0]
cached, value = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached:
tag_color = "#000000000000"
tag_color = ""
tag_priority = None
for handle in data[COLUMN_TAGS]:
tag = self.db.get_tag_from_handle(handle)
+3 -2
View File
@@ -126,7 +126,8 @@ class PlaceBaseModel(object):
return value
def column_name(self, data):
return str(data[6][0])
# need for spacing on the french translation
return _(',').join([data[6][0]] + [name[0] for name in data[7]])
def column_longitude(self, data):
if not data[3]:
@@ -199,7 +200,7 @@ class PlaceBaseModel(object):
tag_handle = data[0]
cached, value = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached:
tag_color = "#000000000000"
tag_color = ""
tag_priority = None
for handle in data[16]:
tag = self.db.get_tag_from_handle(handle)
+1 -1
View File
@@ -253,7 +253,7 @@ class RepositoryModel(FlatBaseModel):
tag_handle = data[0]
cached, tag_color = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached:
tag_color = "#000000000000"
tag_color = ""
tag_priority = None
for handle in data[8]:
tag = self.db.get_tag_from_handle(handle)
+1 -1
View File
@@ -143,7 +143,7 @@ class SourceModel(FlatBaseModel):
tag_handle = data[0]
cached, value = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached:
tag_color = "#000000000000"
tag_color = ""
tag_priority = None
for handle in data[11]:
tag = self.db.get_tag_from_handle(handle)
+1 -1
View File
@@ -897,7 +897,7 @@ class TreeBaseModel(GObject.GObject, Gtk.TreeModel, BaseModel):
# Header rows dont get the foreground color set
if col == self.color_column():
#color must not be utf-8
return "#000000000000"
return ""
# Return the node name for the first column
if col == 0:
+1
View File
@@ -31,6 +31,7 @@ from .photo import *
from .placeentry import *
from .monitoredwidgets import *
from .selectionwidget import SelectionWidget, Region
from .shadebox import *
from .shortlistcomboentry import *
from .springseparator import *
from .statusbar import Statusbar
+1 -1
View File
@@ -615,7 +615,7 @@ class FanChartDescWidget(FanChartBaseWidget):
elif nrparent <= 4:
angleinc = math.pi/2
else:
angleinc = 2 * math.pi / nrchild
angleinc = 2 * math.pi / nrparent
for data in self.parentsroot:
self.draw_innerring(cr, data[0], data[1], startangle, angleinc)
startangle += angleinc
+1 -1
View File
@@ -180,7 +180,7 @@ class GrampletBar(Gtk.Notebook):
if filename and os.path.exists(filename):
cp = configparser.ConfigParser()
try:
cp.read(filename)
cp.read(filename, encoding='utf-8')
except:
pass
for sec in cp.sections():
+2 -7
View File
@@ -50,7 +50,7 @@ from gramps.gen.errors import WindowActiveError
from gramps.gen.const import URL_MANUAL_PAGE, VERSION_DIR
from ..editors import EditPerson, EditFamily
from ..managedwindow import ManagedWindow
from ..utils import is_right_click, rgb_to_hex
from ..utils import is_right_click, get_link_color
from .menuitem import add_menuitem
from ..plug.quick import run_quick_report_by_name
from ..display import display_help, display_url
@@ -197,12 +197,7 @@ class LinkTag(Gtk.TextTag):
lid = 0
#obtaining the theme link color once. Restart needed on theme change!
linkcolor = Gtk.Label(label='test') #needed to avoid label destroyed to early
linkcolor = linkcolor.get_style_context().lookup_color('link_color')
if linkcolor[0]:
linkcolor = rgb_to_hex((linkcolor[1].red, linkcolor[1].green,
linkcolor[1].blue))
else:
linkcolor = 'blue'
linkcolor = get_link_color(linkcolor.get_style_context())
def __init__(self, buffer):
LinkTag.lid += 1
+4 -2
View File
@@ -70,7 +70,7 @@ class InteractiveSearchBox():
function handling keypresses from the treeview
for the typeahead find capabilities
"""
if not event.string:
if not Gdk.keyval_to_unicode(event.keyval):
return False
if self._key_cancels_search(event.keyval):
return False
@@ -399,7 +399,7 @@ class InteractiveSearchBox():
self._search_window.hide()
self._search_entry.set_text("")
self._treeview.emit('focus-in-event', event)
self.__selected_search_result = None
self.__selected_search_result = 0
def _position_func(self, userdata=None):
tree_window = self._treeview.get_window()
@@ -440,6 +440,8 @@ class InteractiveSearchBox():
search_column = self._treeview.get_search_column()
is_tree = not (model.get_flags() & Gtk.TreeModelFlags.LIST_ONLY)
while True:
if not cur_iter: # can happen on empty list
return False
if (self.search_equal_func(model, search_column,
text, cur_iter)):
count += 1
+2 -6
View File
@@ -49,7 +49,7 @@ from gi.repository import Pango
#
#-------------------------------------------------------------------------
from gramps.gen.constfunc import has_display, win
from ..utils import rgb_to_hex
from ..utils import get_link_color
#-------------------------------------------------------------------------
#
@@ -85,11 +85,7 @@ class LinkLabel(Gtk.EventBox):
GObject.GObject.__init__(self)
st_cont = self.get_style_context()
col = st_cont.lookup_color('link_color')
if col[0]:
self.color = rgb_to_hex((col[1].red, col[1].green, col[1].blue))
else:
self.color = 'blue'
self.color = get_link_color(st_cont)
if emph:
#emphasize a link
+13 -13
View File
@@ -73,7 +73,7 @@ def scale_to_fit(orig_x, orig_y, target_x, target_y):
def resize_keep_aspect(orig_x, orig_y, target_x, target_y):
"""
Calculates the dimensions of the rectangle obtained from
the rectangle orig_x * orig_y by scaling to fit
the rectangle orig_x * orig_y by scaling to fit
target_x * target_y keeping the aspect ratio.
"""
orig_aspect = orig_x / orig_y
@@ -178,7 +178,7 @@ class SelectionWidget(Gtk.ScrolledWindow):
"right-button-clicked": (GObject.SignalFlags.RUN_FIRST, None, ()),
"zoomed-in": (GObject.SignalFlags.RUN_FIRST, None, ()),
"zoomed-out": (GObject.SignalFlags.RUN_FIRST, None, ())
}
}
def __init__(self):
"""
@@ -216,9 +216,9 @@ class SelectionWidget(Gtk.ScrolledWindow):
self._button_press_event)
self.event_box.connect('button-release-event',
self._button_release_event)
self.event_box.connect('motion-notify-event',
self.connect('motion-notify-event',
self._motion_notify_event)
self.event_box.connect('scroll-event',
self.connect('scroll-event',
self._motion_scroll_event)
self.event_box.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
self.event_box.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK)
@@ -419,7 +419,7 @@ class SelectionWidget(Gtk.ScrolledWindow):
if w >= 1 and h >= 1 and self.pixbuf:
subpixbuf = self.pixbuf.new_subpixbuf(region.x1, region.y1, w, h)
size = resize_keep_aspect(w, h, *thumbnail_size)
return subpixbuf.scale_simple(size[0], size[1],
return subpixbuf.scale_simple(size[0], size[1],
GdkPixbuf.InterpType.BILINEAR)
else:
return None
@@ -476,12 +476,12 @@ class SelectionWidget(Gtk.ScrolledWindow):
offset_y = (image_rect[1] - viewport_rect.height) / 2
else:
offset_y = 0.0
return (int(coords[0] * self.scale - offset_x),
return (int(coords[0] * self.scale - offset_x),
int(coords[1] * self.scale - offset_y))
def _screen_to_image(self, coords):
"""
Translates viewport coordinates to original (unscaled) image coordinates
Translates viewport coordinates to original (unscaled) image coordinates
using the current scale and viewport size.
"""
viewport_rect = self.viewport.get_allocation()
@@ -494,7 +494,7 @@ class SelectionWidget(Gtk.ScrolledWindow):
offset_y = (image_rect[1] - viewport_rect.height) / 2
else:
offset_y = 0.0
return (int((coords[0] + offset_x) / self.scale),
return (int((coords[0] + offset_x) / self.scale),
int((coords[1] + offset_y) / self.scale))
def _truncate_to_image_size(self, coords):
@@ -557,7 +557,7 @@ class SelectionWidget(Gtk.ScrolledWindow):
x1, y1, x2, y2 = self._rect_image_to_screen(self.selection)
# transparent shading
self._draw_transparent_shading(cr, x1, y1, x2, y2, w, h,
self._draw_transparent_shading(cr, x1, y1, x2, y2, w, h,
offset_x, offset_y)
# selection frame
@@ -571,7 +571,7 @@ class SelectionWidget(Gtk.ScrolledWindow):
x1, y1, x2, y2 = self._rect_image_to_screen(region.coords())
self._draw_region_frame(cr, x1, y1, x2, y2)
def _draw_transparent_shading(self, cr, x1, y1, x2, y2, w, h,
def _draw_transparent_shading(self, cr, x1, y1, x2, y2, w, h,
offset_x, offset_y):
"""
Draws the shading for a selection box.
@@ -631,7 +631,7 @@ class SelectionWidget(Gtk.ScrolledWindow):
Recalculates the sizes using the current scale and updates
the buffers.
"""
self.scaled_size = (int(self.original_image_size[0] * self.scale),
self.scaled_size = (int(self.original_image_size[0] * self.scale),
int(self.original_image_size[1] * self.scale))
self.scaled_image = self.pixbuf.scale_simple(self.scaled_size[0],
self.scaled_size[1],
@@ -704,7 +704,7 @@ class SelectionWidget(Gtk.ScrolledWindow):
self.emit("selection-cleared")
elif self.grabber != INSIDE:
# clicked on one of the grabbers
dx, dy = (event.x - self.start_point_screen[0],
dx, dy = (event.x - self.start_point_screen[0],
event.y - self.start_point_screen[1])
self.grabber_to_draw = self._modify_selection(dx, dy)
self.current.set_coords(*self.selection)
@@ -744,7 +744,7 @@ class SelectionWidget(Gtk.ScrolledWindow):
# selection or dragging (mouse button pressed)
if self.grabber is not None and self.grabber != INSIDE:
# dragging the grabber
dx, dy = (event.x - self.start_point_screen[0],
dx, dy = (event.x - self.start_point_screen[0],
event.y - self.start_point_screen[1])
self.grabber_to_draw = self._modify_selection(dx, dy)
elif self._can_select():
+58
View File
@@ -0,0 +1,58 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2018 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
__all__ = ["ShadeBox"]
#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
import logging
_LOG = logging.getLogger(".widgets.shadebox")
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
from gi.repository import Gtk
#-------------------------------------------------------------------------
#
# ShadeBox class
#
#-------------------------------------------------------------------------
class ShadeBox(Gtk.EventBox):
"""
An EventBox with a shaded background.
"""
def __init__(self, use_shade):
Gtk.EventBox.__init__(self)
self.use_shade = use_shade
def do_draw(self, cr):
if self.use_shade:
tv = Gtk.TextView()
tv_context = tv.get_style_context()
width = self.get_allocated_width()
height = self.get_allocated_height()
Gtk.render_background(tv_context, cr, 0, 0, width, height)
self.get_child().draw(cr)
+2 -6
View File
@@ -60,7 +60,7 @@ from .toolcomboentry import ToolComboEntry
from .springseparator import SpringSeparatorAction
from ..spell import Spell
from ..display import display_url
from ..utils import SystemFonts, rgb_to_hex
from ..utils import SystemFonts, get_link_color
from gramps.gen.config import config
from gramps.gen.constfunc import has_display
from ..actiongroup import ActionGroup
@@ -184,11 +184,7 @@ class StyledTextEditor(Gtk.TextView):
self.set_buffer(self.textbuffer)
st_cont = self.get_style_context()
col = st_cont.lookup_color('link_color')
if col[0]:
self.linkcolor = rgb_to_hex((col[1].red, col[1].green, col[1].blue))
else:
self.linkcolor = 'blue'
self.linkcolor = get_link_color(st_cont)
self.textbuffer.linkcolor = self.linkcolor
self.match = None
+40 -187
View File
@@ -43,7 +43,6 @@ from gi.repository import GObject
from gi.repository import GLib
from gi.repository import Gdk
from gi.repository import Gtk
from gi.repository import GdkPixbuf
from gi.repository import Pango
#-------------------------------------------------------------------------
@@ -63,111 +62,6 @@ from .undoableentry import UndoableEntry
#
#============================================================================
class FadeOut(GObject.GObject):
"""
I am a helper class to draw the fading effect of the background
Call my methods :meth:`start` and :meth:`stop` to control the fading.
"""
__gsignals__ = {
'done': (GObject.SignalFlags.RUN_FIRST,
None,
()),
'color-changed': (GObject.SignalFlags.RUN_FIRST,
None,
(Gdk.Color, )),
}
# How long time it'll take before we start (in ms)
COMPLAIN_DELAY = 500
MERGE_COLORS_DELAY = 100
def __init__(self, widget, err_color = "#ffd5d5"):
GObject.GObject.__init__(self)
self.ERROR_COLOR = err_color
self._widget = widget
self._start_color = None
self._background_timeout_id = -1
self._countdown_timeout_id = -1
self._done = False
def _merge_colors(self, src_color, dst_color, steps=10):
"""
Change the background of widget from src_color to dst_color
in the number of steps specified
"""
##_LOG.debug('_merge_colors: %s -> %s' % (src_color, dst_color))
rs, gs, bs = src_color.red, src_color.green, src_color.blue
rd, gd, bd = dst_color.red, dst_color.green, dst_color.blue
rinc = (rd - rs) / float(steps)
ginc = (gd - gs) / float(steps)
binc = (bd - bs) / float(steps)
for dummy in range(steps):
rs += rinc
gs += ginc
bs += binc
col = Gdk.color_parse("#%02X%02X%02X" % (int(rs) >> 8,
int(gs) >> 8,
int(bs) >> 8))
self.emit('color-changed', col)
yield True
self.emit('done')
self._background_timeout_id = -1
self._done = True
yield False
def _start_merging(self):
# If we changed during the delay
if self._background_timeout_id != -1:
##_LOG.debug('_start_merging: Already running')
return
##_LOG.debug('_start_merging: Starting')
generator = self._merge_colors(self._start_color,
Gdk.color_parse(self.ERROR_COLOR))
self._background_timeout_id = (
GLib.timeout_add(FadeOut.MERGE_COLORS_DELAY, generator.__next__))
self._countdown_timeout_id = -1
def start(self, color):
"""
Schedules a start of the countdown.
:param color: initial background color
:returns: True if we could start, False if was already in progress
"""
if self._background_timeout_id != -1:
##_LOG.debug('start: Background change already running')
return False
if self._countdown_timeout_id != -1:
##_LOG.debug('start: Countdown already running')
return False
if self._done:
##_LOG.debug('start: Not running, already set')
return False
self._start_color = color
##_LOG.debug('start: Scheduling')
self._countdown_timeout_id = GLib.timeout_add(
FadeOut.COMPLAIN_DELAY, self._start_merging)
return True
def stop(self):
"""Stops the fadeout and restores the background color"""
##_LOG.debug('Stopping')
if self._background_timeout_id != -1:
GLib.source_remove(self._background_timeout_id)
self._background_timeout_id = -1
if self._countdown_timeout_id != -1:
GLib.source_remove(self._countdown_timeout_id)
self._countdown_timeout_id = -1
self._widget.update_background(self._start_color, unset=True)
self._done = False
(DIRECTION_LEFT, DIRECTION_RIGHT) = (1, -1)
(INPUT_ASCII_LETTER,
@@ -1013,52 +907,6 @@ class MaskedEntry(UndoableEntry):
def set_stock(self, icon_name):
self.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon_name)
def update_background(self, color, unset=False):
maxvalcol = 65535.
if color:
red = int(color.red/ maxvalcol*255)
green = int(color.green/ maxvalcol*255)
blue = int(color.blue/ maxvalcol*255)
rgba = Gdk.RGBA()
Gdk.RGBA.parse(rgba, 'rgb(%f,%f,%f)'%(red, green, blue))
self.override_background_color(Gtk.StateFlags.NORMAL |
Gtk.StateFlags.ACTIVE | Gtk.StateFlags.SELECTED |
Gtk.StateFlags.FOCUSED, rgba)
#GTK 3: workaround, background not changing in themes, use symbolic
self.override_symbolic_color('bg_color', rgba)
self.override_symbolic_color('base_color', rgba)
self.override_symbolic_color('theme_bg_color', rgba)
self.override_symbolic_color('theme_base_color', rgba)
##self.get_window().set_background_rgba(rgba)
pango_context = self.get_layout().get_context()
font_description = pango_context.get_font_description()
if unset:
font_description.set_weight(Pango.Weight.NORMAL)
else:
font_description.set_weight(Pango.Weight.BOLD)
self.override_font(font_description)
else:
self.override_background_color(Gtk.StateFlags.NORMAL |
Gtk.StateFlags.ACTIVE | Gtk.StateFlags.SELECTED |
Gtk.StateFlags.FOCUSED, None)
# Setting the following to None causes an error (bug #6353).
#self.override_symbolic_color('bg_color', None)
#self.override_symbolic_color('base_color', None)
#self.override_symbolic_color('theme_bg_color', None)
#self.override_symbolic_color('theme_base_color', None)
pango_context = self.get_layout().get_context()
font_description = pango_context.get_font_description()
font_description.set_weight(Pango.Weight.NORMAL)
self.override_font(font_description)
def get_background(self):
backcol = self.get_style_context().get_background_color(Gtk.StateType.NORMAL)
bcol= Gdk.Color.parse('#fff')[1]
bcol.red = int(backcol.red * 65535)
bcol.green = int(backcol.green * 65535)
bcol.blue = int(backcol.blue * 65535)
return bcol
# Gtk.EntryCompletion convenience function
def prefill(self, itemdata, sort=False):
@@ -1091,6 +939,7 @@ class MaskedEntry(UndoableEntry):
VALIDATION_ICON_WIDTH = 16
MANDATORY_ICON = 'dialog-information'
ERROR_ICON = 'process-stop'
FADE_TIME = 2500
class ValidatableMaskedEntry(MaskedEntry):
"""
@@ -1137,7 +986,7 @@ class ValidatableMaskedEntry(MaskedEntry):
#allowed_data_types = (basestring, datetime.date, datetime.time,
#datetime.datetime, object) + number
def __init__(self, data_type=None, err_color = "#ffd5d5", error_icon=ERROR_ICON):
def __init__(self, data_type=None, err_color="pink", error_icon=ERROR_ICON):
self.data_type = None
self.mandatory = False
self.error_icon = error_icon
@@ -1147,9 +996,20 @@ class ValidatableMaskedEntry(MaskedEntry):
self._valid = True
self._def_error_msg = None
self._fade = FadeOut(self, err_color)
self._fade.connect('color-changed', self._on_fadeout__color_changed)
self.__fade_tag = None
provider = Gtk.CssProvider()
css = '.fade {\n'
css += ' background: {};\n'.format(err_color)
css += ' transition: background {:d}ms linear;\n'.format(FADE_TIME)
css += '}'
css += '.bg {\n'
css += ' background: {};\n'.format(err_color)
css += '}'
provider.load_from_data(css.encode('utf8'))
context = self.get_style_context()
context.add_provider(provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
# FIXME put data type support back
#self.set_property('data-type', data_type)
@@ -1270,10 +1130,18 @@ class ValidatableMaskedEntry(MaskedEntry):
reset the background color
"""
##_LOG.debug('Setting state for %s to VALID' % self.model_attribute)
if self.is_valid():
return
self._set_valid_state(True)
self._fade.stop()
self.set_pixbuf(None)
if self.__fade_tag is not None:
GLib.source_remove(self.__fade_tag)
self.__fade_tag = None
self.set_stock(None)
context = self.get_style_context()
context.remove_class('fade')
context.remove_class('bg')
def set_invalid(self, text=None, fade=True):
"""
@@ -1283,6 +1151,8 @@ class ValidatableMaskedEntry(MaskedEntry):
:param fade: if we should fade the background
"""
##_LOG.debug('Setting state for %s to INVALID' % self.model_attribute)
if not self.is_valid():
return
self._set_valid_state(False)
@@ -1311,29 +1181,13 @@ class ValidatableMaskedEntry(MaskedEntry):
self.set_tooltip(text)
if not fade:
if self.error_icon:
self.set_stock(self.error_icon)
self.update_background(Gdk.color_parse(self._fade.ERROR_COLOR))
return
# When the fading animation is finished, set the error icon
# We don't need to check if the state is valid, since stop()
# (which removes this timeout) is called as soon as the user
# types valid data.
def done(fadeout, c):
if self.error_icon:
self.set_stock(self.error_icon)
self.queue_draw()
fadeout.disconnect(c.signal_id)
class SignalContainer(object):
pass
c = SignalContainer()
c.signal_id = self._fade.connect('done', done, c)
if self._fade.start(self.get_background()):
self.set_pixbuf(None)
context = self.get_style_context()
if fade:
self.__fade_tag = GLib.timeout_add(FADE_TIME, self.__fade_finished)
context.add_class('fade')
else:
self.set_stock(self.error_icon)
context.add_class('bg')
def set_blank(self):
"""
@@ -1345,9 +1199,7 @@ class ValidatableMaskedEntry(MaskedEntry):
if self.mandatory:
self.set_stock(MANDATORY_ICON)
self.queue_draw()
self.set_tooltip(_('This field is mandatory'))
self._fade.stop()
valid = False
else:
valid = True
@@ -1382,10 +1234,11 @@ class ValidatableMaskedEntry(MaskedEntry):
self.emit('validation-changed', state)
self._valid = state
# Callbacks
def _on_fadeout__color_changed(self, fadeout, color):
self.update_background(color)
def __fade_finished(self):
"""Set error icon after fade has finished."""
self.__fade_tag = None
self.set_stock(self.error_icon)
return False
def main(args):

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