Compare commits
117 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 17c1dfe950 | |||
| 4531cbd049 | |||
| d24fc82031 | |||
| 16a9cd4c93 | |||
| 94018ed33a | |||
| ffd77dc404 | |||
| 7c6e531c26 | |||
| bc4b006dbe | |||
| 40da63a0fb | |||
| 6fafe8f6c3 | |||
| 66a0c619b9 | |||
| 6ffc095db0 | |||
| 5a5f4970f7 | |||
| ea3d49e50c | |||
| e4b6d9beda | |||
| b6f68c03bb | |||
| f5a66c3958 | |||
| c6ce61b4b9 | |||
| 9c050491ef | |||
| 54ab2820c3 | |||
| 1bf9fef1cb | |||
| dafde8df12 | |||
| ac6eb9661c | |||
| 09bc188a1c | |||
| 4d68f68742 | |||
| 70a634da1e | |||
| ec44396680 | |||
| 5490ff0b84 | |||
| a339e68877 | |||
| dd0956d6ce | |||
| 7911785ea4 | |||
| 9eebeb05da | |||
| a492511533 | |||
| ed907def1f | |||
| 22a9cbdcc8 | |||
| 84e0d45ab6 | |||
| 85f42908f4 | |||
| da1c942509 | |||
| d98db27dcc | |||
| 2b74e0734a | |||
| ebae9c3915 | |||
| 286289aaf7 | |||
| e8489bf53c | |||
| 9946d6f993 | |||
| 00f87cc70e | |||
| 2fbc0b8aeb | |||
| 56122b0a54 | |||
| 6648ecb5ff | |||
| 1b2d0a1956 | |||
| 6bdac08358 | |||
| e74dc2fa8c | |||
| 314f7cce65 | |||
| 11776db76d | |||
| eecf48e6e5 | |||
| bedebc524b | |||
| c01ee8ed7d | |||
| 578f4bdf62 | |||
| baadf6158a | |||
| 024204771b | |||
| 7ed03d43d5 | |||
| 24d97f528e | |||
| d9bb009e6b | |||
| 16d7f92b97 | |||
| 1a1c82c261 | |||
| b9cd0450dc | |||
| df01461171 | |||
| b573c7d7cf | |||
| 60f944adcf | |||
| 9e12a5d364 | |||
| c138aeb8c6 | |||
| 00a5ea1a39 | |||
| 9bb4aaaf49 | |||
| ae6db43fc4 | |||
| 5972477550 | |||
| 215f6bf88d | |||
| fc3e41d696 | |||
| 706d29a480 | |||
| 26c50fdbdd | |||
| 7a61a0e96f | |||
| efab48d5cc | |||
| 647a3b226a | |||
| db3655d156 | |||
| 95e0f43bf5 | |||
| 77e9d796da | |||
| 2af262435d | |||
| 4fca41c8c9 | |||
| 8c7133ab00 | |||
| 425c15e6f5 | |||
| 0ab7c316f0 | |||
| a219421e36 | |||
| 7bbc976141 | |||
| f1b311c9cd | |||
| 3c2231591f | |||
| ac18460059 | |||
| aebe2810f8 | |||
| 4ff908bcef | |||
| f8c1a54def | |||
| 3d1ec9e658 | |||
| fd83162289 | |||
| f092144a93 | |||
| 041d969cce | |||
| c656b38d9e | |||
| 2f1df8ac69 | |||
| 49416739c1 | |||
| 5f2a6df0d0 | |||
| 0be00be4d9 | |||
| ab17a5340a | |||
| e578316bd9 | |||
| 1c83948b40 | |||
| 63ce7383cc | |||
| 11f0c0254b | |||
| d691cfdb1c | |||
| 58b12e702a | |||
| 2bd1a4b757 | |||
| 54b6563e63 | |||
| 0964bfd683 | |||
| 77ccb1770b |
@@ -1,310 +1,13 @@
|
||||
2016-12-15 romjerome <romjerome@users.noreply.github.com>
|
||||
2018-02-09 prculley <paulr2787@gmail.com>
|
||||
|
||||
* gramps/gen/const.py: make official 4.2.5 release
|
||||
* 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
|
||||
|
||||
2016-12-15 romjerome <romjerome@users.noreply.github.com>
|
||||
2018-02-08 Nick Hall <nick-h@gramps-project.org>
|
||||
|
||||
* NEWS: update News file
|
||||
|
||||
2016-12-15 romjerome <romjerome@users.noreply.github.com>
|
||||
|
||||
* gramps/plugins/importer/importprogen.py: fix a missing import
|
||||
|
||||
2016-12-15 romjerome <romjerome@users.noreply.github.com>
|
||||
|
||||
* gramps/gui/views/tags.py: Tag editor: Tweak improvement on buttons
|
||||
order
|
||||
|
||||
2016-12-15 SNoiraud <serge.noiraud@laposte.net>
|
||||
|
||||
* gramps/gui/widgets/grampletbar.py: 9340: The configparser is
|
||||
assuming the wrong encoding.
|
||||
|
||||
2016-12-14 SNoiraud <serge.noiraud@laposte.net>
|
||||
|
||||
* gramps/plugins/webreport/narrativeweb.py: 9563: Sorting in family
|
||||
tab of narrated web report
|
||||
|
||||
2016-12-13 Leonhaeuser <mirko@leonhaeuser.de>
|
||||
|
||||
* po/de.po: fix 0009696
|
||||
|
||||
2016-12-14 Sam Manzi <manzi.sam@gmail.com>
|
||||
|
||||
* gramps/grampsapp.py, gramps/plugins/gramplet/gramplet.gpr.py,
|
||||
gramps/plugins/lib/libmetadata.py,
|
||||
gramps/plugins/lib/maps/constants.py,
|
||||
gramps/plugins/lib/maps/datelayer.py,
|
||||
gramps/plugins/lib/maps/dummylayer.py,
|
||||
gramps/plugins/lib/maps/dummynogps.py,
|
||||
gramps/plugins/lib/maps/geography.py,
|
||||
gramps/plugins/lib/maps/kmllayer.py,
|
||||
gramps/plugins/lib/maps/lifewaylayer.py,
|
||||
gramps/plugins/lib/maps/markerlayer.py,
|
||||
gramps/plugins/lib/maps/messagelayer.py,
|
||||
gramps/plugins/lib/maps/osmgps.py,
|
||||
gramps/plugins/lib/maps/selectionlayer.py,
|
||||
gramps/plugins/view/geography.gpr.py: 9801 Silence remaining
|
||||
PyGIWarning
|
||||
|
||||
2016-12-13 SNoiraud <serge.noiraud@laposte.net>
|
||||
|
||||
* gramps/plugins/webreport/narrativeweb.py: 9563: Sorting of
|
||||
relationships in family tab of narrated web report
|
||||
|
||||
2016-12-10 Josip <bpisoj@gmail.com>
|
||||
|
||||
* gramps/grampsapp.py: Support for Windows Python3 pythonw.exe
|
||||
|
||||
2016-12-10 romjerome <romjerome@users.noreply.github.com>
|
||||
|
||||
* NEWS: start to update NEWS
|
||||
|
||||
2016-12-09 Nick Hall <nick-h@gramps-project.org>
|
||||
|
||||
* gramps/gen/utils/location.py: 9799: Use latest valid date rather
|
||||
than today This is useful for historic places when an event date is not
|
||||
available.
|
||||
|
||||
2016-12-09 Nick Hall <nick-h@gramps-project.org>
|
||||
|
||||
* gramps/gen/utils/location.py: 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 Nick Hall <nick-h@gramps-project.org>
|
||||
|
||||
* gramps/gen/display/place.py: 9737: Fix house number concatenation
|
||||
|
||||
2016-12-07 Espen Berg <espenbe@gmail.com>
|
||||
|
||||
* gramps/plugins/rel/rel_no.py: Corrected another typo in
|
||||
relationship calculator, Norwegian
|
||||
|
||||
2016-12-07 Espen Berg <espenbe@gmail.com>
|
||||
|
||||
* gramps/plugins/rel/rel_no.py: Language correction in Norwegian
|
||||
locale relationship calculator
|
||||
|
||||
2016-12-06 prculley <paulr2787@gmail.com>
|
||||
|
||||
* gramps/gen/merge/mergefamilyquery.py: bug 9818 allow merging of
|
||||
families with one or more parents in common
|
||||
|
||||
2016-12-06 vantu5z <vantu5z@mail.ru>
|
||||
|
||||
* po/ru.po: update Russian translation
|
||||
|
||||
2016-12-05 SNoiraud <serge.noiraud@laposte.net>
|
||||
|
||||
* gramps/gui/views/navigationview.py: 7309: Jump to Gramps ID
|
||||
functionality doesn't work
|
||||
|
||||
2016-12-05 romjerome <romjerome@users.noreply.github.com>
|
||||
|
||||
* po/fr.po: update french translation
|
||||
|
||||
2016-12-05 romjerome <romjerome@users.noreply.github.com>
|
||||
|
||||
* po/gramps.pot: 9276: update translation strings template No new entry, update references and comments
|
||||
|
||||
2016-12-05 romjerome <romjerome@users.noreply.github.com>
|
||||
|
||||
* gramps/gui/views/treemodels/placemodel.py: 9276: ability to search
|
||||
alternate place names when selecting place
|
||||
|
||||
2016-12-05 romjerome <romjerome@users.noreply.github.com>
|
||||
|
||||
* po/fr.po: typo on french translation
|
||||
|
||||
2016-12-04 Espen Berg <espenbe@gmail.com>
|
||||
|
||||
* po/nb.po: Cleaned out one more line in nb.po
|
||||
|
||||
2016-12-04 Espen Berg <espenbe@gmail.com>
|
||||
|
||||
* po/nb.po: The unlocking message is on one loooong line. Inserted
|
||||
line breaks in Norwegian translation for cleanliness
|
||||
|
||||
2016-12-03 Espen Berg <espenbe@gmail.com>
|
||||
|
||||
* po/nb.po: Revising Norwegian bokmål language file (at last)
|
||||
|
||||
2016-12-03 Espen Berg <espenbe@gmail.com>
|
||||
|
||||
* po/nb.po: Revising Norwegian bokmål language file (at last)
|
||||
|
||||
2016-12-03 romjerome <romjerome@users.noreply.github.com>
|
||||
|
||||
* gramps/plugins/tool/check.py: 9812: 'Check and Repair' tool
|
||||
ignores some objects with tag support
|
||||
|
||||
2016-11-30 vantu5z <vantu5z@mail.ru>
|
||||
|
||||
* po/ru.po: update Russian translation
|
||||
|
||||
2016-11-29 romjerome <romjerome@users.noreply.github.com>
|
||||
|
||||
* gramps/plugins/lib/maps/geography.py: 9815: Fix clear map action
|
||||
on Geography
|
||||
|
||||
2016-11-29 Matti Niemelä <matti.u.niemela@gmail.com>
|
||||
|
||||
* po/fi.po: Update finnish translation
|
||||
|
||||
2016-11-28 Zdeněk Hataš <zdenek.hatas@gmail.com>
|
||||
|
||||
* po/cs.po: czech translation update
|
||||
|
||||
2016-11-26 romjerome <romjerome@users.noreply.github.com>
|
||||
|
||||
* debian/control: 9801: recommend 'gir1.2-goocanvas-2.0' on debian
|
||||
package
|
||||
|
||||
2016-11-26 romjerome <romjerome@users.noreply.github.com>
|
||||
|
||||
* gramps/plugins/tool/check.py: 8555: Database repair tool always
|
||||
modify all source objects
|
||||
|
||||
2016-11-24 romjerome <romjerome@users.noreply.github.com>
|
||||
|
||||
* po/fr.po: Update french translation
|
||||
|
||||
2016-11-24 romjerome <romjerome@users.noreply.github.com>
|
||||
|
||||
* po/gramps.pot: Update translation strings template
|
||||
|
||||
2016-11-24 romjerome <romjerome@users.noreply.github.com>
|
||||
|
||||
* po/fr.po: typo on french translation
|
||||
|
||||
2016-11-22 Nick Hall <nick-h@gramps-project.org>
|
||||
|
||||
* gramps/plugins/gramplet/locations.py: 9534: Exclude places outside
|
||||
valid date ranges
|
||||
|
||||
2016-11-10 Leonhaeuser <mirko@leonhaeuser.de>
|
||||
|
||||
* po/de.po: update German translation
|
||||
|
||||
2016-11-01 Nick Hall <nick-h@gramps-project.org>
|
||||
|
||||
* gramps/gui/glade/editldsord.glade: 9767: Fix icon and tooltip in
|
||||
LDS editor The icon on the family selection button was removed by mistake in
|
||||
commit 75009f0.
|
||||
|
||||
2016-10-30 prculley <paulr2787@gmail.com>
|
||||
|
||||
* gramps/plugins/lib/libgedcom.py: bug 9755, fix duplicated Gramps
|
||||
IDs on Gedcom import
|
||||
|
||||
2016-10-29 Sam Manzi <manzi.sam@gmail.com>
|
||||
|
||||
* gramps/gui/configure.py: 9685 Fix Unicode error - Markup for
|
||||
invalid date format
|
||||
|
||||
2016-10-25 prculley <paulr2787@gmail.com>
|
||||
|
||||
* gramps/plugins/importer/importcsv.py: Fix bug 9733, CSV import
|
||||
Fails, 9676, failure for certain types of cross references etc.
|
||||
|
||||
2016-10-24 prculley <paulr2787@gmail.com>
|
||||
|
||||
* gramps/plugins/importer/importvcard.py: bug 9458, fix Import Vcard
|
||||
can create multiple surnames with all selected as 'Primary'
|
||||
|
||||
2016-10-16 prculley <paulr2787@gmail.com>
|
||||
|
||||
* gramps/plugins/lib/libgedcom.py: bug 8993; fix Gedcom import in
|
||||
some alternate languages; improper date parsing
|
||||
|
||||
2016-10-23 romjerome <romjerome@users.noreply.github.com>
|
||||
|
||||
* po/fr.po: typo on the french translation
|
||||
|
||||
2016-10-21 SNoiraud <serge.noiraud@laposte.net>
|
||||
|
||||
* gramps/gui/plug/export/_exportassistant.py,
|
||||
gramps/gui/plug/quick/_textbufdoc.py: 8250 and 9736 : remove patchs.
|
||||
need to found another solution.
|
||||
|
||||
2016-10-18 vantu5z <vantu5z@mail.ru>
|
||||
|
||||
* po/ru.po: update russian translation
|
||||
|
||||
2016-10-16 SNoiraud <serge.noiraud@laposte.net>
|
||||
|
||||
* gramps/gui/plug/quick/_textbufdoc.py: 9736: Export options
|
||||
'Preview' buttons create hidden quickreport.
|
||||
|
||||
2016-10-12 Paul Franklin <pf.98052@gmail.com>
|
||||
|
||||
* gramps/gen/datehandler/_date_cs.py,
|
||||
gramps/gen/datehandler/_dateparser.py: 9739: Wrong parsing Numeric
|
||||
date format for cs_CZ locale
|
||||
|
||||
2016-10-11 SNoiraud <serge.noiraud@laposte.net>
|
||||
|
||||
* gramps/gui/plug/quick/_textbufdoc.py: 9736: Export options
|
||||
'Preview' buttons create hidden quickreport.
|
||||
|
||||
2016-10-04 Matti Niemelä <matti.u.niemela@gmail.com>
|
||||
|
||||
* po/fi.po: Update finnish translation
|
||||
|
||||
2016-10-03 Leonhaeuser <mirko@leonhaeuser.de>
|
||||
|
||||
* po/de.po: update German translation
|
||||
|
||||
2016-10-01 Zdeněk Hataš <zdenek.hatas@gmail.com>
|
||||
|
||||
* po/cs.po: czech translation update
|
||||
|
||||
2016-09-28 romjerome <romjerome@users.noreply.github.com>
|
||||
|
||||
* data/man/en.rst: typo, Change FICHIER to File
|
||||
|
||||
2016-09-28 Lajos Nemeséri <nemeseril@gmail.com>
|
||||
|
||||
* po/hu.po: Update Hungarian translation
|
||||
|
||||
2016-09-25 Nick Hall <nick-h@gramps-project.org>
|
||||
|
||||
* gramps/gui/glade/styleeditor.glade: 9721: Fix alignment radio
|
||||
buttons in style editor
|
||||
|
||||
2016-09-16 SNoiraud <serge.noiraud@laposte.net>
|
||||
|
||||
* gramps/gui/editors/displaytabs/citationembedlist.py,
|
||||
gramps/gui/selectors/baseselector.py: 9700: Select Place search &
|
||||
Source/Citation hierarchy should NOT be expanded
|
||||
|
||||
2016-09-13 Sveinn í Felli <sv1@fellsnet.is>
|
||||
|
||||
* po/is.po: Add 9693: Icelandic translation update(msgfmt error
|
||||
fixed)
|
||||
|
||||
2016-09-12 Sveinn í Felli <sv1@fellsnet.is>
|
||||
|
||||
* po/is.po: Add 9693: Icelandic translation update
|
||||
|
||||
2016-09-10 John Ralls <jralls@ceridwen.us>
|
||||
|
||||
* mac/Info.plist, mac/gramps.bundle, mac/gramps.modules: Add gir
|
||||
files to bundle. Enables change of library paths in the typelibs to point at
|
||||
@executable_path by gtk-mac-bundler.
|
||||
|
||||
2016-08-18 John Ralls <jralls@ceridwen.us>
|
||||
|
||||
* mac/gramps.bundle: Revert "Remove pango modules from bundle, pango
|
||||
no longer uses them." This reverts commit e311de19649371d59c2ab535d4564ee725963b4f because
|
||||
for the moment we have to build with an older Pango.
|
||||
|
||||
2016-08-18 John Ralls <jralls@ceridwen.us>
|
||||
|
||||
* mac/gramps.bundle: escape illegal '--' in comment.
|
||||
|
||||
2016-09-04 romjerome <romjerome@users.noreply.github.com>
|
||||
|
||||
* bump to '4.2.5'
|
||||
* Bump to 4.2.8
|
||||
|
||||
|
||||
@@ -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,3 +1,83 @@
|
||||
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
|
||||
|
||||
@@ -94,6 +94,9 @@
|
||||
<author title="contributor">
|
||||
Nick Hall <<html:a href="mailto:nick__hall@hotmail.com">nick__hall@hotmail.com</html:a>>
|
||||
</author>
|
||||
<author title="contributor">
|
||||
Paul Culley <<html:a href="mailto:paulr2787@gmail.com">paulr2787@gmail.com</html:a>>
|
||||
</author>
|
||||
<author title="contributor">
|
||||
Peter Landgren <<html:a href="mailto:peter.talken@telia.com">peter.talken@telia.com</html:a>>
|
||||
</author>
|
||||
|
||||
@@ -10,3 +10,11 @@ Name
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
Place
|
||||
====================================
|
||||
.. automodule:: gramps.gen.display.place
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
@@ -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,
|
||||
|
||||
+4
-4
@@ -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.")
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
@@ -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}]
|
||||
@@ -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('"', '"')
|
||||
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('"', '"')
|
||||
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('"', '"')
|
||||
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
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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()):
|
||||
"""
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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")
|
||||
|
||||
+83
-45
@@ -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.
|
||||
|
||||
|
||||
+2
-3
@@ -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):
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -155,7 +155,7 @@ class CitationEmbedList(EmbeddedList, DbGUIElement):
|
||||
def share_button_clicked(self, obj):
|
||||
SelectCitation = SelectorFactory('Citation')
|
||||
|
||||
sel = SelectCitation(self.dbstate, self.uistate, self.track, expand=False)
|
||||
sel = SelectCitation(self.dbstate, self.uistate, self.track)
|
||||
object = sel.run()
|
||||
LOG.debug("selected object: %s" % object)
|
||||
# the object returned should either be a Source or a Citation
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,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>
|
||||
|
||||
@@ -723,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)
|
||||
@@ -916,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
|
||||
|
||||
|
||||
@@ -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.
|
||||
"""
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -53,14 +53,13 @@ class BaseSelector(ManagedWindow):
|
||||
IMAGE = 2
|
||||
|
||||
def __init__(self, dbstate, uistate, track=[], filter=None, skip=set(),
|
||||
show_search_bar = True, default=None, expand=True):
|
||||
show_search_bar = True, default=None):
|
||||
"""Set up the dialog with the dbstate and uistate, track of parent
|
||||
windows for ManagedWindow, initial filter for the model, skip with
|
||||
set of handles to skip in the view, and search_bar to show the
|
||||
SearchBar at the top or not.
|
||||
"""
|
||||
self.filter = (2, filter, False)
|
||||
self.expand = expand
|
||||
|
||||
# Set window title, some selectors may set self.title in their __init__
|
||||
if not hasattr(self, 'title'):
|
||||
@@ -133,6 +132,18 @@ class BaseSelector(ManagedWindow):
|
||||
"""
|
||||
iter_ = self.model.get_iter_from_handle(handle)
|
||||
if iter_:
|
||||
if not (self.model.get_flags() & Gtk.TreeModelFlags.LIST_ONLY):
|
||||
# Expand tree
|
||||
parent_iter = self.model.iter_parent(iter_)
|
||||
if parent_iter:
|
||||
parent_path = self.model.get_path(parent_iter)
|
||||
if parent_path:
|
||||
parent_path_list = parent_path.get_indices()
|
||||
for i in range(len(parent_path_list)):
|
||||
expand_path = Gtk.TreePath(
|
||||
tuple([x for x in parent_path_list[:i+1]]))
|
||||
self.tree.expand_row(expand_path, False)
|
||||
|
||||
# Select active object
|
||||
path = self.model.get_path(iter_)
|
||||
self.selection.unselect_all()
|
||||
@@ -293,11 +304,7 @@ class BaseSelector(ManagedWindow):
|
||||
self.tree.set_search_column(search_col)
|
||||
|
||||
self.setupcols = False
|
||||
|
||||
if self.expand:
|
||||
if not (self.model.get_flags() & Gtk.TreeModelFlags.LIST_ONLY):
|
||||
self.tree.expand_all()
|
||||
|
||||
|
||||
def column_clicked(self, obj, data):
|
||||
if self.sort_col != data:
|
||||
self.sortorder = Gtk.SortType.ASCENDING
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -200,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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -142,13 +142,14 @@ class CalcItems(object):
|
||||
"""
|
||||
def __init__(self, dbase):
|
||||
__gui = GUIConnect()
|
||||
self._gui = __gui
|
||||
|
||||
#calculate the printed lines for each box
|
||||
#display_repl = [] #Not used in this report
|
||||
#str = ""
|
||||
#if self.get_val('miss_val'):
|
||||
# str = "_____"
|
||||
self.__calc_l = CalcLines(dbase, [], __gui._locale, __gui._nd)
|
||||
display_repl = __gui.get_val("replace_list")
|
||||
self.__calc_l = CalcLines(dbase, display_repl, __gui._locale, __gui._nd)
|
||||
|
||||
self.__blank_father = None
|
||||
self.__blank_mother = None
|
||||
@@ -170,12 +171,14 @@ class CalcItems(object):
|
||||
working_lines = ""
|
||||
if index[1] % 2 == 0 or (index[1] == 1 and self.center_use == 0):
|
||||
if indi_handle == fams_handle == None:
|
||||
working_lines = self.__blank_father
|
||||
working_lines = self.__calc_l.calc_lines(
|
||||
None, None, self._gui.get_val("father_disp"))
|
||||
else:
|
||||
working_lines = self.disp_father
|
||||
else:
|
||||
if indi_handle == fams_handle == None:
|
||||
working_lines = self.__blank_mother
|
||||
working_lines = self.__calc_l.calc_lines(
|
||||
None, None, self._gui.get_val("mother_disp"))
|
||||
else:
|
||||
working_lines = self.disp_mother
|
||||
|
||||
@@ -228,9 +231,11 @@ class MakeAncestorTree(AscendPerson):
|
||||
|
||||
myself.text = self.calc_items.calc_person(
|
||||
index, indi_handle, fams_handle)
|
||||
# myself.text[0] = myself.text[0] + ' ' + repr(index) # for debugging
|
||||
|
||||
myself.add_mark(self.database,
|
||||
self.database.get_person_from_handle(indi_handle))
|
||||
if indi_handle is not None: # None is legal for an empty box
|
||||
myself.add_mark(self.database,
|
||||
self.database.get_person_from_handle(indi_handle))
|
||||
|
||||
self.canvas.add_box(myself)
|
||||
|
||||
|
||||
@@ -464,8 +464,9 @@ class RecurseDown:
|
||||
#calculate the text.
|
||||
myself.calc_text(self.database, indi_handle, fams_handle)
|
||||
|
||||
myself.add_mark(self.database,
|
||||
self.database.get_person_from_handle(indi_handle))
|
||||
if indi_handle:
|
||||
myself.add_mark(self.database,
|
||||
self.database.get_person_from_handle(indi_handle))
|
||||
|
||||
self.add_to_col(myself)
|
||||
|
||||
@@ -682,8 +683,9 @@ class MakePersonTree(RecurseDown):
|
||||
family2 = family2_h = None
|
||||
if self.do_parents:
|
||||
family2_h = center1.get_main_parents_family_handle()
|
||||
family2 = self.database.get_family_from_handle(family2_h)
|
||||
|
||||
if family2_h:
|
||||
family2 = self.database.get_family_from_handle(family2_h)
|
||||
|
||||
mother2_h = father2_h = None
|
||||
if family2:
|
||||
father2_h = family2.get_father_handle()
|
||||
|
||||
@@ -400,9 +400,7 @@ class CSVWriter(object):
|
||||
birth = self.db.get_event_from_handle(birth_ref.ref)
|
||||
if birth:
|
||||
birthdate = self.format_date( birth)
|
||||
place_handle = birth.get_place_handle()
|
||||
if place_handle:
|
||||
birthplace = _pd.display_event(self.db, birth)
|
||||
birthplace = self.format_place(birth)
|
||||
birthsource = get_primary_source_title(self.db, birth)
|
||||
# Baptism:
|
||||
baptismdate = ""
|
||||
@@ -414,9 +412,7 @@ class CSVWriter(object):
|
||||
baptism = self.db.get_event_from_handle(baptism_ref.ref)
|
||||
if baptism:
|
||||
baptismdate = self.format_date( baptism)
|
||||
place_handle = baptism.get_place_handle()
|
||||
if place_handle:
|
||||
baptismplace = _pd.display_event(self.db, baptism)
|
||||
baptismplace = self.format_place(baptism)
|
||||
baptismsource = get_primary_source_title(self.db, baptism)
|
||||
# Death:
|
||||
deathdate = ""
|
||||
@@ -427,9 +423,7 @@ class CSVWriter(object):
|
||||
death = self.db.get_event_from_handle(death_ref.ref)
|
||||
if death:
|
||||
deathdate = self.format_date( death)
|
||||
place_handle = death.get_place_handle()
|
||||
if place_handle:
|
||||
deathplace = _pd.display_event(self.db, death)
|
||||
deathplace = self.format_place(death)
|
||||
deathsource = get_primary_source_title(self.db, death)
|
||||
# Burial:
|
||||
burialdate = ""
|
||||
@@ -441,9 +435,7 @@ class CSVWriter(object):
|
||||
burial = self.db.get_event_from_handle(burial_ref.ref)
|
||||
if burial:
|
||||
burialdate = self.format_date( burial)
|
||||
place_handle = burial.get_place_handle()
|
||||
if place_handle:
|
||||
burialplace = _pd.display_event(self.db, burial)
|
||||
burialplace = self.format_place(burial)
|
||||
burialsource = get_primary_source_title(self.db, burial)
|
||||
# Write it out:
|
||||
self.write_csv(grampsid_ref, surname, first_name, callname,
|
||||
@@ -501,10 +493,8 @@ class CSVWriter(object):
|
||||
event = self.db.get_event_from_handle(event_ref.ref)
|
||||
if event.get_type() == EventType.MARRIAGE:
|
||||
mdate = self.format_date( event)
|
||||
place_handle = event.get_place_handle()
|
||||
if place_handle:
|
||||
mplace = _pd.display_event(self.db, event)
|
||||
source = get_primary_source_title(self.db, event)
|
||||
mplace = self.format_place(event)
|
||||
source = get_primary_source_title(self.db, event)
|
||||
note = ''
|
||||
self.write_csv(marriage_id, father_id, mother_id, mdate,
|
||||
mplace, source, note)
|
||||
@@ -536,3 +526,18 @@ class CSVWriter(object):
|
||||
|
||||
def format_date(self, date):
|
||||
return get_date(date)
|
||||
|
||||
def format_place(self, event):
|
||||
"""
|
||||
If places are included in the export return a link, else return a
|
||||
formatted place for the given event.
|
||||
"""
|
||||
if self.include_places:
|
||||
place_handle = event.get_place_handle()
|
||||
if place_handle:
|
||||
place = self.db.get_place_from_handle(place_handle)
|
||||
if place:
|
||||
return "[%s]" % place.get_gramps_id()
|
||||
return ""
|
||||
else:
|
||||
return _pd.display_event(self.db, event)
|
||||
|
||||
@@ -48,6 +48,9 @@ log = logging.getLogger(".WriteFtree")
|
||||
from gramps.gen.utils.alive import probably_alive
|
||||
from gramps.gui.plug.export import WriterOptionBox
|
||||
from gramps.gui.glade import Glade
|
||||
from gramps.gui.dialog import ErrorDialog
|
||||
from gramps.gen.const import GRAMPS_LOCALE as glocale
|
||||
_ = glocale.translation.gettext
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@@ -121,8 +124,16 @@ class FtreeWriter(object):
|
||||
id_map[key] = n
|
||||
id_name[key] = get_name(pn, sn, count)
|
||||
|
||||
f = open(self.filename,"w")
|
||||
try:
|
||||
with open(self.filename, "w", encoding='utf_8') as file:
|
||||
return self._export_data(file, id_name, id_map)
|
||||
except IOError as msg:
|
||||
msg2 = _("Could not create %s") % self.filename
|
||||
# cannot set parent below because gramps42 doesn't have it...
|
||||
ErrorDialog(msg2, str(msg))
|
||||
return False
|
||||
|
||||
def _export_data(self, file, id_name, id_map):
|
||||
for key in self.plist:
|
||||
self.update()
|
||||
p = self.db.get_person_from_handle(key)
|
||||
@@ -159,7 +170,7 @@ class FtreeWriter(object):
|
||||
# alive = probably_alive(p, self.db)
|
||||
#else:
|
||||
# alive = 0
|
||||
|
||||
|
||||
if birth:
|
||||
if death:
|
||||
dates = "%s-%s" % (fdate(birth), fdate(death))
|
||||
@@ -170,11 +181,10 @@ class FtreeWriter(object):
|
||||
dates = fdate(death)
|
||||
else:
|
||||
dates = ""
|
||||
|
||||
f.write('%s;%s;%s;%s;%s;%s\n' % (name, father, mother, email, web,
|
||||
dates))
|
||||
|
||||
f.close()
|
||||
|
||||
file.write('%s;%s;%s;%s;%s;%s\n' %
|
||||
(name, father, mother, email, web, dates))
|
||||
|
||||
return True
|
||||
|
||||
def fdate(val):
|
||||
|
||||
@@ -363,7 +363,7 @@ class GrampsXmlWriter(UpdateCallback):
|
||||
for key in group_map:
|
||||
value = self.db.get_name_group_mapping(key)
|
||||
self.g.write(' <map type="group_as" key="%s" value="%s"/>\n'
|
||||
% (key, value) )
|
||||
% (self.fix(key), value))
|
||||
self.g.write(" </namemaps>\n")
|
||||
|
||||
def write_bookmarks(self):
|
||||
|
||||
@@ -390,7 +390,7 @@ try:
|
||||
available = True
|
||||
else:
|
||||
available = False
|
||||
except ImportError:
|
||||
except (ImportError, ValueError):
|
||||
available = False
|
||||
|
||||
if available:
|
||||
|
||||
@@ -66,6 +66,7 @@ class MediaPreview(Gramplet):
|
||||
self.set_has_data(False)
|
||||
self.top.show()
|
||||
else:
|
||||
self.photo.set_image(None)
|
||||
self.set_has_data(False)
|
||||
|
||||
def load_image(self, media):
|
||||
|
||||
@@ -844,6 +844,9 @@ class FamilyLinesReport(Report):
|
||||
# see if we have a table that needs to be terminated
|
||||
if imagePath:
|
||||
label += '</TD></TR></TABLE>'
|
||||
else:
|
||||
# non html label is enclosed by "" so escape other "
|
||||
label = label.replace('"', '\\\"')
|
||||
|
||||
shape = "box"
|
||||
style = "solid"
|
||||
|
||||
@@ -919,6 +919,9 @@ class CSVParser:
|
||||
|
||||
def get_or_create_place(self, place_name):
|
||||
"Return the requested place object tuple-packed with a new indicator."
|
||||
if place_name.startswith("[") and place_name.endswith("]"):
|
||||
place = self.lookup("place", place_name)
|
||||
return (0, place)
|
||||
LOG.debug("get_or_create_place: looking for: %s", place_name)
|
||||
for place_handle in self.db.iter_place_handles():
|
||||
place = self.db.get_place_from_handle(place_handle)
|
||||
|
||||
@@ -134,6 +134,7 @@ from gramps.gui.dialog import WarningDialog
|
||||
from gramps.gen.lib.const import IDENTICAL, DIFFERENT
|
||||
from gramps.gen.lib import (StyledText, StyledTextTag, StyledTextTagType)
|
||||
from gramps.gen.constfunc import conv_to_unicode, win
|
||||
from gramps.gen.lib.urlbase import UrlBase
|
||||
from gramps.plugins.lib.libplaceimport import PlaceImport
|
||||
from gramps.gen.display.place import displayer as _pd
|
||||
|
||||
@@ -273,6 +274,8 @@ TOKEN__PHOTO = 132
|
||||
TOKEN__LINK = 133
|
||||
TOKEN__PRIM = 134
|
||||
TOKEN__JUST = 135
|
||||
TOKEN__TEXT = 136
|
||||
TOKEN__DATE = 137
|
||||
|
||||
TOKENS = {
|
||||
"HEAD" : TOKEN_HEAD, "MEDI" : TOKEN_MEDI,
|
||||
@@ -364,7 +367,7 @@ TOKENS = {
|
||||
"_WITN" : TOKEN__WITN, "_WTN" : TOKEN__WTN,
|
||||
"_CHUR" : TOKEN_IGNORE,"RELA" : TOKEN_RELA,
|
||||
"_DETAIL" : TOKEN_IGNORE,"_PREF" : TOKEN__PRIMARY,
|
||||
"_LKD" : TOKEN__LKD, "_DATE" : TOKEN_IGNORE,
|
||||
"_LKD" : TOKEN__LKD, "_DATE" : TOKEN__DATE,
|
||||
"_SCBK" : TOKEN_IGNORE,"_TYPE" : TOKEN_TYPE,
|
||||
"_PRIM" : TOKEN__PRIM, "_SSHOW" : TOKEN_IGNORE,
|
||||
"_PAREN" : TOKEN_IGNORE,"BLOB" : TOKEN_BLOB,
|
||||
@@ -382,7 +385,7 @@ TOKENS = {
|
||||
"_ADPN" : TOKEN__ADPN, "_FSFTID" : TOKEN__FSFTID,
|
||||
"_LINK" : TOKEN__LINK, "_PHOTO" : TOKEN__PHOTO,
|
||||
"_JUST" : TOKEN__JUST, # FTM Citation Quality Justification
|
||||
"FAX" : TOKEN_FAX,
|
||||
"FAX" : TOKEN_FAX, "_TEXT" : TOKEN__TEXT,
|
||||
}
|
||||
|
||||
ADOPT_NONE = 0
|
||||
@@ -636,8 +639,8 @@ for __val, __key in PERSONALCONSTANTATTRIBUTES.items():
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
HMONTH = [
|
||||
"", "ELUL", "TSH", "CSH", "KSL", "TVT", "SHV", "ADR",
|
||||
"ADS", "NSN", "IYR", "SVN", "TMZ", "AAV", "ELL" ]
|
||||
"", "TSH", "CSH", "KSL", "TVT", "SHV", "ADR",
|
||||
"ADS", "NSN", "IYR", "SVN", "TMZ", "AAV", "ELL"]
|
||||
|
||||
FMONTH = [
|
||||
"", "VEND", "BRUM", "FRIM", "NIVO", "PLUV", "VENT",
|
||||
@@ -1058,6 +1061,7 @@ class GedLine:
|
||||
_MAP_DATA = {
|
||||
TOKEN_UNKNOWN : GedLine.calc_unknown,
|
||||
TOKEN_DATE : GedLine.calc_date,
|
||||
TOKEN__DATE : GedLine.calc_date,
|
||||
TOKEN_SEX : GedLine.calc_sex,
|
||||
TOKEN_NOTE : GedLine.calc_note,
|
||||
TOKEN_NCHI : GedLine.calc_nchi,
|
||||
@@ -2549,7 +2553,9 @@ class GedcomParser(UpdateCallback):
|
||||
TOKEN_TITL : self.__obje_title,
|
||||
TOKEN_FILE : self.__obje_file, # de-facto extension
|
||||
TOKEN_TEXT : self.__obje_text, # FTM extension
|
||||
TOKEN__TEXT : self.__obje_text, # FTM 2017 extension
|
||||
TOKEN_DATE : self.__obje_date, # FTM extension
|
||||
TOKEN__DATE : self.__obje_date, # FTM 2017 extension
|
||||
TOKEN_NOTE : self.__obje_note,
|
||||
TOKEN_RNOTE : self.__obje_note,
|
||||
TOKEN_SOUR : self.__obje_sour,
|
||||
@@ -4121,6 +4127,9 @@ class GedcomParser(UpdateCallback):
|
||||
@param state: The current state
|
||||
@type state: CurrentState
|
||||
"""
|
||||
if self.is_ftw:
|
||||
self.__person_resi(line, state)
|
||||
return
|
||||
free_form = line.data
|
||||
|
||||
sub_state = CurrentState(level=state.level + 1)
|
||||
@@ -4132,6 +4141,26 @@ class GedcomParser(UpdateCallback):
|
||||
self.__merge_address(free_form, sub_state.addr, line, state)
|
||||
state.person.add_address(sub_state.addr)
|
||||
|
||||
def __person_resi(self, line, state):
|
||||
"""
|
||||
Parses GEDCOM ADDR tag, subordinate to the INDI tag, when sourced by
|
||||
FTM. We treat this as a RESI event, because FTM puts standard event
|
||||
details below the ADDR line.
|
||||
|
||||
n ADDR <ADDRESS_LINE> {0:1}
|
||||
+1 <<EVENT_DETAIL>> {0:1} p.*
|
||||
|
||||
@param line: The current line in GedLine format
|
||||
@type line: GedLine
|
||||
@param state: The current state
|
||||
@type state: CurrentState
|
||||
"""
|
||||
self.backoff = True # reprocess the current ADDR line
|
||||
line.level += 1 # as if it was next level down
|
||||
event_ref = self.__build_event_pair(state, EventType.RESIDENCE,
|
||||
self.event_parse_tbl, '')
|
||||
state.person.add_event_ref(event_ref)
|
||||
|
||||
def __person_phon(self, line, state):
|
||||
"""
|
||||
n PHON <PHONE_NUMBER> {0:3}
|
||||
@@ -5055,6 +5084,8 @@ class GedcomParser(UpdateCallback):
|
||||
event.set_description('')
|
||||
else:
|
||||
state.family.type.set(FamilyRelType.MARRIED)
|
||||
if descr == "Y":
|
||||
event.set_description('')
|
||||
|
||||
self.dbase.commit_event(event, self.trans)
|
||||
event_ref.ref = event.handle
|
||||
@@ -5259,12 +5290,20 @@ class GedcomParser(UpdateCallback):
|
||||
|
||||
def __family_attr(self, line, state):
|
||||
"""
|
||||
Parses an TOKEN that Gramps recognizes as an Attribute
|
||||
@param line: The current line in GedLine format
|
||||
@type line: GedLine
|
||||
@param state: The current state
|
||||
@type state: CurrentState
|
||||
"""
|
||||
sub_state = CurrentState()
|
||||
sub_state.person = state.person
|
||||
sub_state.attr = line.data
|
||||
sub_state.level = state.level + 1
|
||||
state.family.add_attribute(line.data)
|
||||
self.__parse_level(sub_state, self.person_attr_parse_tbl,
|
||||
self.__ignore)
|
||||
state.msg += sub_state.msg
|
||||
|
||||
def __family_cust_attr(self, line, state):
|
||||
"""
|
||||
@@ -5343,11 +5382,21 @@ class GedcomParser(UpdateCallback):
|
||||
# The following code that detects URL is an older v5.5 usage; the
|
||||
# modern option is to use the EMAIL tag.
|
||||
if isinstance(sub_state.form, str) and sub_state.form == "url":
|
||||
url = Url()
|
||||
url.set_path(sub_state.filename)
|
||||
url.set_description(sub_state.title)
|
||||
url.set_type(UrlType.WEB_HOME)
|
||||
pri_obj.add_url(url)
|
||||
if isinstance(pri_obj, UrlBase):
|
||||
url = Url()
|
||||
url.set_path(sub_state.filename)
|
||||
url.set_description(sub_state.title)
|
||||
url.set_type(UrlType.WEB_HOME)
|
||||
pri_obj.add_url(url)
|
||||
else: # some primary objects (Event) son't have spot for URL
|
||||
new_note = Note(sub_state.filename)
|
||||
new_note.set_gramps_id(self.nid_map[""])
|
||||
new_note.set_handle(create_id())
|
||||
new_note.set_type(OBJ_NOTETYPE.get(type(pri_obj).__name__,
|
||||
NoteType.GENERAL))
|
||||
self.dbase.commit_note(new_note, self.trans, new_note.change)
|
||||
pri_obj.add_note(new_note.get_handle())
|
||||
|
||||
else:
|
||||
# to allow import of references to URLs (especially for import from
|
||||
# geni.com), do not try to find the file if it is blatently a URL
|
||||
|
||||
@@ -446,13 +446,13 @@ class AscendPerson(_StopRecurse, _PersonSeen):
|
||||
# Recursively call the function. It is okay if the handle is None,
|
||||
# since routine handles a handle of None
|
||||
|
||||
self.__fill(index*2, generation+1, mx_fill-1)
|
||||
self.__fill(generation+1, index*2, mx_fill-1)
|
||||
if mx_fill > 1: # marriage of parents
|
||||
self.add_marriage((generation+1, index*2), None, None)
|
||||
if not self.can_recurse():
|
||||
self.continue_recursion()
|
||||
return
|
||||
self.__fill((index*2)+1, generation+1, mx_fill-1)
|
||||
self.__fill(generation+1, (index*2)+1, mx_fill-1)
|
||||
|
||||
def __iterate(self, person_handle, generation, index):
|
||||
"""
|
||||
|
||||
@@ -669,7 +669,7 @@ class TitleBox(BoxBase):
|
||||
return
|
||||
#fix me. width should be the printable area
|
||||
self.width = PT2CM(self.doc.string_width(self.font, self.text))
|
||||
self.height = PT2CM(self.font.get_size() * 1.2)
|
||||
self.height = PT2CM(self.font.get_size() * 2)
|
||||
|
||||
def _get_names(self, persons, name_displayer):
|
||||
""" A helper function that receives a list of persons and
|
||||
|
||||
@@ -194,7 +194,10 @@ class PlaceSelection(ManagedWindow, OsmGps):
|
||||
self.oldvalue)
|
||||
)
|
||||
for place in self.places:
|
||||
p = (place[0].value, place[1], place[2], place[3])
|
||||
if isinstance(place[0], str):
|
||||
p = (place[0], place[1], place[2], place[3])
|
||||
else:
|
||||
p = (place[0].value, place[1], place[2], place[3])
|
||||
self.plist.append(p)
|
||||
# here, we could add value from geography names services ...
|
||||
|
||||
|
||||
@@ -131,6 +131,7 @@ class IndivCompleteReport(Report):
|
||||
filter_option = options.menu.get_option_by_name('filter')
|
||||
self.filter = filter_option.get_filter()
|
||||
self.bibli = None
|
||||
self.names_notes_list = []
|
||||
|
||||
self.section_list = menu.get_option_by_name('sections').get_selected()
|
||||
|
||||
@@ -220,6 +221,10 @@ class IndivCompleteReport(Report):
|
||||
def write_note(self):
|
||||
notelist = self.person.get_note_list()
|
||||
notelist += self.family_notes_list
|
||||
if self.names_notes_list:
|
||||
for note_handle in self.names_notes_list:
|
||||
if note_handle not in notelist:
|
||||
notelist += [note_handle]
|
||||
if not notelist:
|
||||
return
|
||||
self.doc.start_table('note','IDS-IndTable')
|
||||
@@ -308,7 +313,8 @@ class IndivCompleteReport(Report):
|
||||
|
||||
def write_alt_names(self):
|
||||
|
||||
if len(self.person.get_alternate_names()) < 1:
|
||||
alt_names = self.person.get_alternate_names()
|
||||
if len(alt_names) < 1:
|
||||
return
|
||||
|
||||
self.doc.start_table("altnames","IDS-IndTable")
|
||||
@@ -319,7 +325,8 @@ class IndivCompleteReport(Report):
|
||||
self.doc.end_cell()
|
||||
self.doc.end_row()
|
||||
|
||||
for name in self.person.get_alternate_names():
|
||||
for name in alt_names:
|
||||
self.names_notes_list += name.get_note_list()
|
||||
name_type = self._(self._get_type(name.get_type()))
|
||||
self.doc.start_row()
|
||||
self.write_cell(name_type)
|
||||
|
||||
@@ -63,7 +63,7 @@ class TagReport(Report):
|
||||
def __init__(self, database, options, user):
|
||||
"""
|
||||
Create the TagReport object that produces the report.
|
||||
|
||||
|
||||
The arguments are:
|
||||
|
||||
database - the GRAMPS database instance
|
||||
@@ -72,7 +72,7 @@ class TagReport(Report):
|
||||
|
||||
This report needs the following parameters (class variables)
|
||||
that come in the options class.
|
||||
|
||||
|
||||
tag - The tag each object must match to be included.
|
||||
name_format - Preferred format to display names of people
|
||||
incl_private - Whether to include private data
|
||||
@@ -86,7 +86,7 @@ class TagReport(Report):
|
||||
if not self.tag:
|
||||
raise ReportError(_('Tag Report'),
|
||||
_('You must first create a tag before running this report.'))
|
||||
|
||||
|
||||
self.set_locale(menu.get_option_by_name('trans').get_value())
|
||||
|
||||
stdoptions.run_name_format_option(self, menu)
|
||||
@@ -98,7 +98,7 @@ class TagReport(Report):
|
||||
mark = IndexMark(title, INDEX_TYPE_TOC, 1)
|
||||
self.doc.write_text(title, mark)
|
||||
self.doc.end_paragraph()
|
||||
|
||||
|
||||
self.write_people()
|
||||
self.write_families()
|
||||
self.write_events()
|
||||
@@ -115,10 +115,10 @@ class TagReport(Report):
|
||||
filter = FilterClass()
|
||||
filter.add_rule(rules.person.HasTag([self.tag]))
|
||||
ind_list = filter.apply(self.database, plist)
|
||||
|
||||
|
||||
if not ind_list:
|
||||
return
|
||||
|
||||
|
||||
self.doc.start_paragraph("TR-Heading")
|
||||
header = self._("People")
|
||||
mark = IndexMark(header, INDEX_TYPE_TOC, 2)
|
||||
@@ -126,9 +126,9 @@ class TagReport(Report):
|
||||
self.doc.end_paragraph()
|
||||
|
||||
self.doc.start_table('PeopleTable','TR-Table')
|
||||
|
||||
|
||||
self.doc.start_row()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal-Bold')
|
||||
self.doc.write_text(self._("Id"))
|
||||
@@ -140,26 +140,26 @@ class TagReport(Report):
|
||||
self.doc.write_text(self._("Name"))
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal-Bold')
|
||||
self.doc.write_text(self._("Birth"))
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal-Bold')
|
||||
self.doc.write_text(self._("Death"))
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.end_row()
|
||||
|
||||
for person_handle in ind_list:
|
||||
person = self.database.get_person_from_handle(person_handle)
|
||||
|
||||
self.doc.start_row()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal')
|
||||
self.doc.write_text(person.get_gramps_id())
|
||||
@@ -173,7 +173,7 @@ class TagReport(Report):
|
||||
self.doc.write_text(name, mark)
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal')
|
||||
birth_ref = person.get_birth_ref()
|
||||
@@ -182,7 +182,7 @@ class TagReport(Report):
|
||||
self.doc.write_text(get_date( event ))
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal')
|
||||
death_ref = person.get_death_ref()
|
||||
@@ -191,21 +191,21 @@ class TagReport(Report):
|
||||
self.doc.write_text(get_date( event ))
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.end_row()
|
||||
|
||||
|
||||
self.doc.end_table()
|
||||
|
||||
|
||||
def write_families(self):
|
||||
flist = self.database.iter_family_handles()
|
||||
FilterClass = GenericFilterFactory('Family')
|
||||
filter = FilterClass()
|
||||
filter.add_rule(rules.family.HasTag([self.tag]))
|
||||
fam_list = filter.apply(self.database, flist)
|
||||
|
||||
|
||||
if not fam_list:
|
||||
return
|
||||
|
||||
|
||||
self.doc.start_paragraph("TR-Heading")
|
||||
header = self._("Families")
|
||||
mark = IndexMark(header,INDEX_TYPE_TOC, 2)
|
||||
@@ -213,9 +213,9 @@ class TagReport(Report):
|
||||
self.doc.end_paragraph()
|
||||
|
||||
self.doc.start_table('FamilyTable','TR-Table')
|
||||
|
||||
|
||||
self.doc.start_row()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal-Bold')
|
||||
self.doc.write_text(self._("Id"))
|
||||
@@ -227,26 +227,26 @@ class TagReport(Report):
|
||||
self.doc.write_text(self._("Father"))
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal-Bold')
|
||||
self.doc.write_text(self._("Mother"))
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal-Bold')
|
||||
self.doc.write_text(self._("Relationship"))
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.end_row()
|
||||
|
||||
for family_handle in fam_list:
|
||||
family = self.database.get_family_from_handle(family_handle)
|
||||
|
||||
|
||||
self.doc.start_row()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal')
|
||||
self.doc.write_text(family.get_gramps_id())
|
||||
@@ -262,7 +262,7 @@ class TagReport(Report):
|
||||
self.doc.write_text(self._name_display.display(father), mark)
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal')
|
||||
mother_handle = family.get_mother_handle()
|
||||
@@ -272,16 +272,16 @@ class TagReport(Report):
|
||||
self.doc.write_text(self._name_display.display(mother), mark)
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal')
|
||||
relation = family.get_relationship()
|
||||
self.doc.write_text(str(relation) )
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.end_row()
|
||||
|
||||
|
||||
self.doc.end_table()
|
||||
|
||||
def write_events(self):
|
||||
@@ -290,10 +290,10 @@ class TagReport(Report):
|
||||
filter = FilterClass()
|
||||
filter.add_rule(rules.event.HasTag([self.tag]))
|
||||
event_list = filter.apply(self.database, elist)
|
||||
|
||||
|
||||
if not event_list:
|
||||
return
|
||||
|
||||
|
||||
self.doc.start_paragraph("TR-Heading")
|
||||
header = self._("Events")
|
||||
mark = IndexMark(header, INDEX_TYPE_TOC, 2)
|
||||
@@ -301,9 +301,9 @@ class TagReport(Report):
|
||||
self.doc.end_paragraph()
|
||||
|
||||
self.doc.start_table('EventTable','TR-Table')
|
||||
|
||||
|
||||
self.doc.start_row()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal-Bold')
|
||||
self.doc.write_text(self._("Id"))
|
||||
@@ -315,32 +315,32 @@ class TagReport(Report):
|
||||
self.doc.write_text(self._("Type"))
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal-Bold')
|
||||
self.doc.write_text(self._("Participants"))
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal-Bold')
|
||||
self.doc.write_text(self._("Date"))
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.end_row()
|
||||
|
||||
for event_handle in event_list:
|
||||
event = self.database.get_event_from_handle(event_handle)
|
||||
|
||||
|
||||
self.doc.start_row()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal')
|
||||
self.doc.write_text(event.get_gramps_id())
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
self.doc.end_cell()
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal')
|
||||
self.doc.write_text(str(event.get_type()))
|
||||
@@ -432,7 +432,7 @@ class TagReport(Report):
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal')
|
||||
self.doc.write_text(place.get_name())
|
||||
self.doc.write_text(place.get_name().get_value())
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
@@ -452,10 +452,10 @@ class TagReport(Report):
|
||||
filter = FilterClass()
|
||||
filter.add_rule(rules.note.HasTag([self.tag]))
|
||||
note_list = filter.apply(self.database, nlist)
|
||||
|
||||
|
||||
if not note_list:
|
||||
return
|
||||
|
||||
|
||||
self.doc.start_paragraph("TR-Heading")
|
||||
header = self._("Notes")
|
||||
mark = IndexMark(header, INDEX_TYPE_TOC, 2)
|
||||
@@ -463,9 +463,9 @@ class TagReport(Report):
|
||||
self.doc.end_paragraph()
|
||||
|
||||
self.doc.start_table('NoteTable','TR-Table')
|
||||
|
||||
|
||||
self.doc.start_row()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal-Bold')
|
||||
self.doc.write_text(self._("Id"))
|
||||
@@ -477,33 +477,33 @@ class TagReport(Report):
|
||||
self.doc.write_text(self._("Type"))
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell', 2)
|
||||
self.doc.start_paragraph('TR-Normal-Bold')
|
||||
self.doc.write_text(self._("Text"))
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.end_row()
|
||||
|
||||
for note_handle in note_list:
|
||||
note = self.database.get_note_from_handle(note_handle)
|
||||
|
||||
|
||||
self.doc.start_row()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal')
|
||||
self.doc.write_text(note.get_gramps_id())
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
self.doc.end_cell()
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal')
|
||||
type = note.get_type()
|
||||
self.doc.write_text(str(type))
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell', 2)
|
||||
self.doc.write_styled_note(note.get_styledtext(),
|
||||
note.get_format(), 'TR-Note',
|
||||
@@ -511,9 +511,9 @@ class TagReport(Report):
|
||||
== NoteType.HTML_CODE)
|
||||
)
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.end_row()
|
||||
|
||||
|
||||
self.doc.end_table()
|
||||
|
||||
def write_media(self):
|
||||
@@ -522,10 +522,10 @@ class TagReport(Report):
|
||||
filter = FilterClass()
|
||||
filter.add_rule(rules.media.HasTag([self.tag]))
|
||||
media_list = filter.apply(self.database, mlist)
|
||||
|
||||
|
||||
if not media_list:
|
||||
return
|
||||
|
||||
|
||||
self.doc.start_paragraph("TR-Heading")
|
||||
header = self._("Media")
|
||||
mark = IndexMark(header, INDEX_TYPE_TOC, 2)
|
||||
@@ -533,9 +533,9 @@ class TagReport(Report):
|
||||
self.doc.end_paragraph()
|
||||
|
||||
self.doc.start_table('MediaTable','TR-Table')
|
||||
|
||||
|
||||
self.doc.start_row()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal-Bold')
|
||||
self.doc.write_text(self._("Id"))
|
||||
@@ -547,46 +547,46 @@ class TagReport(Report):
|
||||
self.doc.write_text(self._("Title"))
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal-Bold')
|
||||
self.doc.write_text(self._("Type"))
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal-Bold')
|
||||
self.doc.write_text(self._("Date"))
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.end_row()
|
||||
|
||||
for media_handle in media_list:
|
||||
media = self.database.get_object_from_handle(media_handle)
|
||||
|
||||
self.doc.start_row()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal')
|
||||
self.doc.write_text(media.get_gramps_id())
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
self.doc.end_cell()
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal')
|
||||
title = media.get_description()
|
||||
self.doc.write_text(str(title))
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal')
|
||||
mime_type = media.get_mime_type()
|
||||
self.doc.write_text(str(mime_type))
|
||||
self.doc.end_paragraph()
|
||||
self.doc.end_cell()
|
||||
|
||||
|
||||
self.doc.start_cell('TR-TableCell')
|
||||
self.doc.start_paragraph('TR-Normal')
|
||||
date = get_date(media)
|
||||
@@ -596,7 +596,7 @@ class TagReport(Report):
|
||||
self.doc.end_cell()
|
||||
|
||||
self.doc.end_row()
|
||||
|
||||
|
||||
self.doc.end_table()
|
||||
|
||||
def write_repositories(self):
|
||||
@@ -855,7 +855,7 @@ class TagOptions(MenuReportOptions):
|
||||
def __init__(self, name, dbase):
|
||||
self.__db = dbase
|
||||
MenuReportOptions.__init__(self, name, dbase)
|
||||
|
||||
|
||||
def add_menu_options(self, menu):
|
||||
"""
|
||||
Add options to the menu for the tag report.
|
||||
@@ -900,7 +900,7 @@ class TagOptions(MenuReportOptions):
|
||||
p.set_alignment(PARA_ALIGN_CENTER)
|
||||
p.set_description(_("The style used for the title of the page."))
|
||||
default_style.add_paragraph_style("TR-Title", p)
|
||||
|
||||
|
||||
font = FontStyle()
|
||||
font.set(face=FONT_SANS_SERIF, size=14, italic=1)
|
||||
para = ParagraphStyle()
|
||||
@@ -910,7 +910,7 @@ class TagOptions(MenuReportOptions):
|
||||
para.set_bottom_margin(0.25)
|
||||
para.set_description(_('The style used for the section headers.'))
|
||||
default_style.add_paragraph_style("TR-Heading", para)
|
||||
|
||||
|
||||
font = FontStyle()
|
||||
font.set_size(12)
|
||||
p = ParagraphStyle()
|
||||
@@ -920,7 +920,7 @@ class TagOptions(MenuReportOptions):
|
||||
p.set_bottom_margin(ReportUtils.pt2cm(3))
|
||||
p.set_description(_('The basic style used for the text display.'))
|
||||
default_style.add_paragraph_style("TR-Normal", p)
|
||||
|
||||
|
||||
font = FontStyle()
|
||||
font.set_size(12)
|
||||
font.set_bold(True)
|
||||
@@ -931,14 +931,14 @@ class TagOptions(MenuReportOptions):
|
||||
p.set_bottom_margin(ReportUtils.pt2cm(3))
|
||||
p.set_description(_('The basic style used for table headings.'))
|
||||
default_style.add_paragraph_style("TR-Normal-Bold", p)
|
||||
|
||||
|
||||
para = ParagraphStyle()
|
||||
p.set(first_indent=-0.75, lmargin=.75)
|
||||
para.set_top_margin(ReportUtils.pt2cm(3))
|
||||
para.set_bottom_margin(ReportUtils.pt2cm(3))
|
||||
para.set_description(_('The basic style used for the note display.'))
|
||||
default_style.add_paragraph_style("TR-Note",para)
|
||||
|
||||
|
||||
#Table Styles
|
||||
cell = TableCellStyle()
|
||||
default_style.add_cell_style('TR-TableCell', cell)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">6</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="title">
|
||||
<property name="visible">True</property>
|
||||
|
||||
@@ -313,13 +313,18 @@ class GeoClose(GeoGraphyView):
|
||||
all handling of visibility is now in rebuild_trees, see that for more
|
||||
information.
|
||||
"""
|
||||
active = self.get_active()
|
||||
person = self.dbstate.db.get_person_from_handle(active)
|
||||
self.lifeway_layer.clear_ways()
|
||||
if person is None:
|
||||
self.goto_handle(None)
|
||||
if not self.dbstate.open:
|
||||
return
|
||||
active = self.get_active()
|
||||
if active:
|
||||
person = self.dbstate.db.get_person_from_handle(active)
|
||||
if person is None:
|
||||
self.goto_handle(None)
|
||||
else:
|
||||
self.goto_handle(handle=person)
|
||||
else:
|
||||
self.goto_handle(handle=person)
|
||||
self.goto_handle(None)
|
||||
|
||||
def draw(self, menu, marks, color, reference):
|
||||
"""
|
||||
|
||||
@@ -188,6 +188,8 @@ class GeoEvents(GeoGraphyView):
|
||||
all handling of visibility is now in rebuild_trees, see that for more
|
||||
information.
|
||||
"""
|
||||
if not self.dbstate.open:
|
||||
return
|
||||
active = self.uistate.get_active('Event')
|
||||
if active:
|
||||
self._createmap(active)
|
||||
|
||||
@@ -304,6 +304,9 @@ class GeoFamClose(GeoGraphyView):
|
||||
all handling of visibility is now in rebuild_trees, see that for more
|
||||
information.
|
||||
"""
|
||||
self.lifeway_layer.clear_ways()
|
||||
if not self.dbstate.open:
|
||||
return
|
||||
active = self.get_active()
|
||||
family = self.dbstate.db.get_family_from_handle(active)
|
||||
self.goto_handle(handle=family)
|
||||
|
||||
@@ -178,6 +178,8 @@ class GeoFamily(GeoGraphyView):
|
||||
all handling of visibility is now in rebuild_trees, see that for more
|
||||
information.
|
||||
"""
|
||||
if not self.dbstate.open:
|
||||
return
|
||||
if self.uistate.get_active('Family'):
|
||||
self._createmap(self.uistate.get_active('Family'))
|
||||
else:
|
||||
|
||||
@@ -215,6 +215,8 @@ class GeoPerson(GeoGraphyView):
|
||||
all handling of visibility is now in rebuild_trees, see that for more
|
||||
information.
|
||||
"""
|
||||
if not self.dbstate.open:
|
||||
return
|
||||
active = self.get_active()
|
||||
self._createmap(active)
|
||||
|
||||
|
||||
@@ -189,6 +189,8 @@ class GeoPlaces(GeoGraphyView):
|
||||
all handling of visibility is now in rebuild_trees, see that for more
|
||||
information.
|
||||
"""
|
||||
if not self.dbstate.open:
|
||||
return
|
||||
active = self.uistate.get_active('Place')
|
||||
if active:
|
||||
self._createmap(active)
|
||||
|
||||
@@ -306,15 +306,6 @@ class RelationshipView(NavigationView):
|
||||
self.child = None
|
||||
|
||||
self.scroll = Gtk.ScrolledWindow()
|
||||
|
||||
st_cont = self.scroll.get_style_context()
|
||||
col = st_cont.lookup_color('base_color')
|
||||
if col[0]:
|
||||
self.color = col[1]
|
||||
else:
|
||||
self.color = Gdk.RGBA()
|
||||
self.color.parse("White")
|
||||
|
||||
self.scroll.set_policy(Gtk.PolicyType.AUTOMATIC,
|
||||
Gtk.PolicyType.AUTOMATIC)
|
||||
self.scroll.show()
|
||||
@@ -575,9 +566,7 @@ class RelationshipView(NavigationView):
|
||||
|
||||
grid.attach(eventbox, 0, 0, 2, 1)
|
||||
|
||||
eventbox = Gtk.EventBox()
|
||||
if self.use_shade:
|
||||
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
|
||||
eventbox = widgets.ShadeBox(self.use_shade)
|
||||
grid.attach(eventbox, 1, 1, 1, 1)
|
||||
subgrid = Gtk.Grid()
|
||||
subgrid.set_column_spacing(12)
|
||||
@@ -874,9 +863,7 @@ class RelationshipView(NavigationView):
|
||||
box = self.get_people_box(family.get_father_handle(),
|
||||
family.get_mother_handle(),
|
||||
post_msg=childmsg)
|
||||
eventbox = Gtk.EventBox()
|
||||
if self.use_shade:
|
||||
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
|
||||
eventbox = widgets.ShadeBox(self.use_shade)
|
||||
eventbox.add(box)
|
||||
self.child.attach(eventbox, _PDATA_START, self.row,
|
||||
_PDATA_STOP-_PDATA_START, 1)
|
||||
@@ -928,9 +915,7 @@ class RelationshipView(NavigationView):
|
||||
else :
|
||||
childmsg = _(" (only child)")
|
||||
box = self.get_people_box(post_msg=childmsg)
|
||||
eventbox = Gtk.EventBox()
|
||||
if self.use_shade:
|
||||
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
|
||||
eventbox = widgets.ShadeBox(self.use_shade)
|
||||
eventbox.add(box)
|
||||
self.child.attach(eventbox, _PDATA_START, self.row,
|
||||
_PDATA_STOP-_PDATA_START, 1)
|
||||
@@ -958,9 +943,7 @@ class RelationshipView(NavigationView):
|
||||
child_should_be_linked = (child_handle != active)
|
||||
self.write_child(vbox, child_handle, i, child_should_be_linked)
|
||||
i += 1
|
||||
eventbox = Gtk.EventBox()
|
||||
if self.use_shade:
|
||||
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
|
||||
eventbox = widgets.ShadeBox(self.use_shade)
|
||||
eventbox.add(vbox)
|
||||
self.child.attach(eventbox, _CDATA_START-1, self.row,
|
||||
_CDATA_STOP-_CDATA_START+1, 1)
|
||||
@@ -980,9 +963,6 @@ class RelationshipView(NavigationView):
|
||||
name = self.get_name(handle, True)
|
||||
link_label = widgets.LinkLabel(name, self._button_press,
|
||||
handle, theme=self.theme)
|
||||
if self.use_shade:
|
||||
link_label.override_background_color(Gtk.StateType.NORMAL,
|
||||
self.color)
|
||||
if self._config.get('preferences.releditbtn'):
|
||||
button = widgets.IconButton(self.edit_button_press,
|
||||
handle)
|
||||
@@ -1025,7 +1005,7 @@ class RelationshipView(NavigationView):
|
||||
_PLABEL_STOP-_PLABEL_START, 1)
|
||||
|
||||
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
||||
eventbox = Gtk.EventBox()
|
||||
eventbox = widgets.ShadeBox(self.use_shade)
|
||||
if handle:
|
||||
name = self.get_name(handle, True)
|
||||
person = self.dbstate.db.get_person_from_handle(handle)
|
||||
@@ -1039,8 +1019,6 @@ class RelationshipView(NavigationView):
|
||||
emph = False
|
||||
link_label = widgets.LinkLabel(name, self._button_press,
|
||||
handle, emph, theme=self.theme)
|
||||
if self.use_shade:
|
||||
link_label.override_background_color(Gtk.StateType.NORMAL, self.color)
|
||||
if self._config.get('preferences.releditbtn'):
|
||||
button = widgets.IconButton(self.edit_button_press, handle)
|
||||
button.set_tooltip_text(_('Edit %s') % name[0])
|
||||
@@ -1059,8 +1037,6 @@ class RelationshipView(NavigationView):
|
||||
if value:
|
||||
vbox.pack_start(widgets.MarkupLabel(value), True, True, 0)
|
||||
|
||||
if self.use_shade:
|
||||
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
|
||||
eventbox.add(vbox)
|
||||
|
||||
self.child.attach(eventbox, _PDATA_START, self.row,
|
||||
@@ -1160,9 +1136,6 @@ class RelationshipView(NavigationView):
|
||||
name = self.get_name(handle, True)
|
||||
link_label = widgets.LinkLabel(name, link_func, handle, emph,
|
||||
theme=self.theme)
|
||||
|
||||
if self.use_shade:
|
||||
link_label.override_background_color(Gtk.StateType.NORMAL, self.color)
|
||||
link_label.set_padding(3, 0)
|
||||
if child_should_be_linked and self._config.get(
|
||||
'preferences.releditbtn'):
|
||||
@@ -1379,9 +1352,7 @@ class RelationshipView(NavigationView):
|
||||
else :
|
||||
childmsg = _(" (no children)")
|
||||
box = self.get_people_box(handle, post_msg=childmsg)
|
||||
eventbox = Gtk.EventBox()
|
||||
if self.use_shade:
|
||||
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
|
||||
eventbox = widgets.ShadeBox(self.use_shade)
|
||||
eventbox.add(box)
|
||||
self.child.attach(eventbox, _PDATA_START, self.row,
|
||||
_PDATA_STOP-_PDATA_START, 1)
|
||||
@@ -1426,9 +1397,7 @@ class RelationshipView(NavigationView):
|
||||
else :
|
||||
childmsg = _(" (no children)")
|
||||
box = self.get_people_box(post_msg=childmsg)
|
||||
eventbox = Gtk.EventBox()
|
||||
if self.use_shade:
|
||||
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
|
||||
eventbox = widgets.ShadeBox(self.use_shade)
|
||||
eventbox.add(box)
|
||||
self.child.attach(eventbox, _PDATA_START, self.row,
|
||||
_PDATA_STOP-_PDATA_START, 1)
|
||||
@@ -1456,9 +1425,7 @@ class RelationshipView(NavigationView):
|
||||
i += 1
|
||||
|
||||
self.row += 1
|
||||
eventbox = Gtk.EventBox()
|
||||
if self.use_shade:
|
||||
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
|
||||
eventbox = widgets.ShadeBox(self.use_shade)
|
||||
eventbox.add(vbox)
|
||||
self.child.attach(eventbox, _CDATA_START-1, self.row,
|
||||
_CDATA_STOP-_CDATA_START+1, 1)
|
||||
|
||||
@@ -1612,7 +1612,7 @@ class BasePage(object):
|
||||
'<a href="' + URL_HOMEPAGE + '">' ,
|
||||
'html_end' : '</a>' ,
|
||||
'version' : VERSION }
|
||||
if date is not None:
|
||||
if date is not None and date > 0:
|
||||
msg += "<br />"
|
||||
last_modif = datetime.datetime.fromtimestamp(date).strftime('%Y-%m-%d %H:%M:%S')
|
||||
msg += _('Last change was the %(date)s') % { 'date' : last_modif }
|
||||
|
||||
+1
-1
@@ -18,6 +18,6 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
VERSION_TUPLE = (4, 2, 5)
|
||||
VERSION_TUPLE = (4, 2, 9)
|
||||
VERSION = '.'.join(map(str,VERSION_TUPLE))
|
||||
major_version = "%s.%s" % (VERSION_TUPLE[0], VERSION_TUPLE[1])
|
||||
|
||||
+4
-4
@@ -7,7 +7,7 @@
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>Gramps</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>Gramps-4.2.4, (C) 1997-2016 The Gramps Team http://www.gramps-project.org</string>
|
||||
<string>Gramps-4.2.8, (C) 1997-2018 The Gramps Team http://www.gramps-project.org</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>gramps.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
@@ -17,13 +17,13 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.2.4</string>
|
||||
<string>4.2.8</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>Gramps-4.2.4-1</string>
|
||||
<string>Gramps-4.2.8-1</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright 1997 - 2016 The Gramps Team, GNU General Public License.</string>
|
||||
<string>Copyright 1997 - 2017 The Gramps Team, GNU General Public License.</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.5</string>
|
||||
<key>GtkOSXLaunchScriptFile</key>
|
||||
|
||||
+13
-13
@@ -19,7 +19,7 @@
|
||||
(gtk_accel_path "<Actions>/Events/Backward/Back" "<Alt>Left")
|
||||
; (gtk_accel_path "<Actions>/ToolWindow/rebuild_refmap" "")
|
||||
; (gtk_accel_path "<Actions>/ToolWindow/Database-Processing" "")
|
||||
(gtk_accel_path "<Actions>/Events/Bookmark/EditBook" "<Shift><Meta>b")
|
||||
(gtk_accel_path "<Actions>/Events/Bookmark/EditBook" "<Shift><Meta>d")
|
||||
(gtk_accel_path "<Actions>/People Tree View/PersonEdit/Remove" "<Meta>Delete")
|
||||
(gtk_accel_path "<Actions>/Notes/Forward/Forward" "<Alt>Right")
|
||||
(gtk_accel_path "<Actions>/Undo/Undo" "<Meta>z")
|
||||
@@ -29,7 +29,7 @@
|
||||
(gtk_accel_path "<Actions>/Media/ChangeOrder/Remove" "<Meta>Delete")
|
||||
; (gtk_accel_path "<Actions>/FileWindow/HelpMenu" "")
|
||||
(gtk_accel_path "<Actions>/Place View/Bookmark/AddBook" "<Meta>d")
|
||||
(gtk_accel_path "<Actions>/Repositories/Bookmark/EditBook" "<Shift><Meta>b")
|
||||
(gtk_accel_path "<Actions>/Repositories/Bookmark/EditBook" "<Shift><Meta>d")
|
||||
; (gtk_accel_path "<Actions>/ReportWindow/book" "")
|
||||
; (gtk_accel_path "<Actions>/FileWindow/FileMenu" "")
|
||||
(gtk_accel_path "<Actions>/Person View/Backward/Back" "<Alt>Left")
|
||||
@@ -49,7 +49,7 @@
|
||||
(gtk_accel_path "<Actions>/Place Tree View/ChangeOrder/Add" "<Alt><Meta>i")
|
||||
; (gtk_accel_path "<Actions>/ReportWindow/number_of_ancestors" "")
|
||||
(gtk_accel_path "<Actions>/Families/ChangeOrder/Add" "<Alt><Meta>i")
|
||||
(gtk_accel_path "<Actions>/Person View/Bookmark/EditBook" "<Shift><Meta>b")
|
||||
(gtk_accel_path "<Actions>/Person View/Bookmark/EditBook" "<Shift><Meta>d")
|
||||
(gtk_accel_path "<Actions>/Relationships/Bookmark/AddBook" "<Meta>d")
|
||||
; (gtk_accel_path "<Actions>/ReportWindow/familylines_graph" "")
|
||||
(gtk_accel_path "<Actions>/Person View/Forward/Forward" "<Alt>Right")
|
||||
@@ -59,9 +59,9 @@
|
||||
; (gtk_accel_path "<Actions>/ToolWindow/relcalc" "")
|
||||
(gtk_accel_path "<Actions>/AllMainWindow/Export" "<Meta>e")
|
||||
(gtk_accel_path "<Actions>/Pedigree/Backward/Back" "<Alt>Left")
|
||||
(gtk_accel_path "<Actions>/Relationships/Bookmark/EditBook" "<Shift><Meta>b")
|
||||
(gtk_accel_path "<Actions>/Relationships/Bookmark/EditBook" "<Shift><Meta>d")
|
||||
; (gtk_accel_path "<Actions>/ToolWindow/reorder_ids" "")
|
||||
(gtk_accel_path "<Actions>/Place Tree View/Bookmark/EditBook" "<Shift><Meta>b")
|
||||
(gtk_accel_path "<Actions>/Place Tree View/Bookmark/EditBook" "<Shift><Meta>d")
|
||||
; (gtk_accel_path "<Actions>/RecentFiles/RecentMenu0" "")
|
||||
(gtk_accel_path "<Actions>/Person View/PersonAll/Edit" "<Meta>Return")
|
||||
; (gtk_accel_path "<Actions>/FileWindow/MailingLists" "")
|
||||
@@ -87,7 +87,7 @@
|
||||
; (gtk_accel_path "<Actions>/ToolWindow/dupfind" "")
|
||||
; (gtk_accel_path "<Actions>/MainWindow/EditMenu" "")
|
||||
(gtk_accel_path "<Actions>/UndoHistory/UndoHistory" "<Meta>h")
|
||||
(gtk_accel_path "<Actions>/Sources/Bookmark/EditBook" "<Shift><Meta>b")
|
||||
(gtk_accel_path "<Actions>/Sources/Bookmark/EditBook" "<Shift><Meta>d")
|
||||
; (gtk_accel_path "<Actions>/FileWindow/ReportBug" "")
|
||||
(gtk_accel_path "<Actions>/AllMainWindow/<CONTROL>Insert" "<Alt><Meta>i")
|
||||
(gtk_accel_path "<Actions>/Notes/Bookmark/AddBook" "<Meta>d")
|
||||
@@ -117,7 +117,7 @@
|
||||
(gtk_accel_path "<Actions>/AllMainWindow/<CONTROL>BackSpace" "<Meta>BackSpace")
|
||||
; (gtk_accel_path "<Actions>/ToolWindow/Utilities" "")
|
||||
; (gtk_accel_path "<Actions>/AllMainWindow/WindowsMenu" "")
|
||||
(gtk_accel_path "<Actions>/Families/Bookmark/EditBook" "<Shift><Meta>b")
|
||||
(gtk_accel_path "<Actions>/Families/Bookmark/EditBook" "<Shift><Meta>d")
|
||||
; (gtk_accel_path "<Actions>/AllMainWindow/F9" "F9")
|
||||
; (gtk_accel_path "<Actions>/AllMainWindow/F8" "F8")
|
||||
; (gtk_accel_path "<Actions>/AllMainWindow/F7" "F7")
|
||||
@@ -127,7 +127,7 @@
|
||||
; (gtk_accel_path "<Actions>/AllMainWindow/F4" "F4")
|
||||
; (gtk_accel_path "<Actions>/AllMainWindow/F3" "F3")
|
||||
; (gtk_accel_path "<Actions>/AllMainWindow/F2" "F2")
|
||||
(gtk_accel_path "<Actions>/Notes/Bookmark/EditBook" "<Shift><Meta>b")
|
||||
(gtk_accel_path "<Actions>/Notes/Bookmark/EditBook" "<Shift><Meta>d")
|
||||
(gtk_accel_path "<Actions>/Sources/ChangeOrder/Add" "<Alt><Meta>i")
|
||||
; (gtk_accel_path "<Actions>/ReportWindow/Books" "")
|
||||
; (gtk_accel_path "<Actions>/FileWindow/About" "")
|
||||
@@ -135,7 +135,7 @@
|
||||
; (gtk_accel_path "<Actions>/ReportWindow/endofline_report" "")
|
||||
(gtk_accel_path "<Actions>/People Tree View/PersonEdit/Add" "<Alt><Meta>i")
|
||||
; (gtk_accel_path "<Actions>/ToolWindow/dbrowse" "")
|
||||
(gtk_accel_path "<Actions>/Pedigree/Bookmark/EditBook" "<Shift><Meta>b")
|
||||
(gtk_accel_path "<Actions>/Pedigree/Bookmark/EditBook" "<Shift><Meta>d")
|
||||
; (gtk_accel_path "<Actions>/ToolWindow/soundgen" "")
|
||||
; (gtk_accel_path "<Actions>/FileWindow/ExtraPlugins" "")
|
||||
; (gtk_accel_path "<Actions>/AllMainWindow/ReportsMenu" "")
|
||||
@@ -158,7 +158,7 @@
|
||||
(gtk_accel_path "<Actions>/Notes/ChangeOrder/Add" "<Alt><Meta>i")
|
||||
; (gtk_accel_path "<Actions>/ReportWindow/calendar" "")
|
||||
; (gtk_accel_path "<Actions>/FileWindow/Fullscreen" "F11")
|
||||
(gtk_accel_path "<Actions>/Fan Chart/Bookmark/EditBook" "<Shift><Meta>b")
|
||||
(gtk_accel_path "<Actions>/Fan Chart/Bookmark/EditBook" "<Shift><Meta>d")
|
||||
; (gtk_accel_path "<Actions>/ReportWindow/navwebpage" "")
|
||||
(gtk_accel_path "<Actions>/Repositories/Bookmark/AddBook" "<Meta>d")
|
||||
(gtk_accel_path "<Actions>/Families/ChangeOrder/Remove" "<Meta>Delete")
|
||||
@@ -170,11 +170,11 @@
|
||||
; (gtk_accel_path "<Actions>/FileWindow/TipOfDay" "")
|
||||
(gtk_accel_path "<Actions>/Media/ChangeOrder/Add" "<Alt><Meta>i")
|
||||
(gtk_accel_path "<Actions>/FileWindow/Quit" "<Meta>q")
|
||||
(gtk_accel_path "<Actions>/People Tree View/Bookmark/EditBook" "<Shift><Meta>b")
|
||||
(gtk_accel_path "<Actions>/People Tree View/Bookmark/EditBook" "<Shift><Meta>d")
|
||||
(gtk_accel_path "<Actions>/Place Tree View/Backward/Back" "<Alt>Left")
|
||||
(gtk_accel_path "<Actions>/FileWindow/Open" "<Meta>o")
|
||||
(gtk_accel_path "<Actions>/Place View/Bookmark/EditBook" "<Shift><Meta>b")
|
||||
(gtk_accel_path "<Actions>/Media/Bookmark/EditBook" "<Shift><Meta>b")
|
||||
(gtk_accel_path "<Actions>/Place View/Bookmark/EditBook" "<Shift><Meta>d")
|
||||
(gtk_accel_path "<Actions>/Media/Bookmark/EditBook" "<Shift><Meta>d")
|
||||
(gtk_accel_path "<Actions>/MainWindow/ConfigView" "<Shift><Meta>c")
|
||||
(gtk_accel_path "<Actions>/People Tree View/Backward/Back" "<Alt>Left")
|
||||
; (gtk_accel_path "<Actions>/FileWindow/KeyBindings" "")
|
||||
|
||||
+12
-5
@@ -13,7 +13,7 @@
|
||||
|
||||
<plist>${project}/Info.plist</plist>
|
||||
<!-- Build gramps-launcher with:
|
||||
gcc -L$PREFIX `python-config -\-cflags -\-ldflags` \
|
||||
gcc -L$PREFIX/lib `python-config -\-cflags -\-ldflags` \
|
||||
-o $PREFIX/bin/gramps-launcher \
|
||||
path/to/gtk-mac-bundler/examples/python-launcher.c
|
||||
with the obvious substitution.
|
||||
@@ -40,10 +40,6 @@
|
||||
${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/printbackends/*.so
|
||||
</binary>
|
||||
|
||||
<binary>
|
||||
${prefix}/lib/pango/${pkg:pango:pango_module_version}/modules/*.so
|
||||
</binary>
|
||||
|
||||
<binary recurse="True">
|
||||
${prefix}/lib/python3.4/*.so
|
||||
</binary>
|
||||
@@ -235,4 +231,15 @@
|
||||
${project}/settings.ini
|
||||
</data>
|
||||
|
||||
<data>
|
||||
${prefix}/share/doc/gramps/*
|
||||
</data>
|
||||
|
||||
<data>
|
||||
${prefix}/share/doc/gramps/example/gedcom/sample.ged
|
||||
</data>
|
||||
|
||||
<data>
|
||||
${prefix}/share/doc/gramps/example/gramps/*
|
||||
</data>
|
||||
</app-bundle>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user