Compare commits

..
118 Commits
Author SHA1 Message Date
SNoiraud d48dcc9c5f FR10850 V1: Refresh button in the gramplet bar.
Fixes #10850

This is the first method to avoid reloading gramplet automaticaly.
2018-10-31 20:30:44 +01:00
prculley 263a082afe Merge in changes from Gramps50 2018-10-29 09:32:35 -05:00
Richard ClayandNick Hall dd9ddab849 In personsidebarfilter, search on each part of name
Instead of requiring that the entire search string matches a single one of the Person's names, the function will require that each word in the search string matches any of the Person's name fields.

Fixes #7950
2018-10-20 21:30:20 +01:00
Malte RenkenandNick Hall cfa278886b RelGraphReport: Add an option to omit "irrelevant" family nodes 2018-10-12 20:58:04 +01:00
MJBMZandNick Hall 1c430a6b91 Replace rounded corners checkbox by dropdown
It now allows rounded corners to be set more explicitly for
different genders (None/Male/Female/Both).
2018-10-12 20:25:51 +01:00
jose1711andNick Hall b0eb712933 Do not use hyphen for living persons in hourglass graph 2018-10-12 19:36:42 +01:00
Jgon6andNick Hall 51a7ad9483 Include death anniversaries as an option in the birthdays report
Added the optional ability to list the anniversry of peoples deaths in
the birthday and anniversary report

Resolves #3540
2018-10-12 19:19:59 +01:00
Jgon6andNick Hall d6e9d62fad Add an option to show years in the birthday report
Added an option to the birthday report that allows for the year of birth
(or in the case of a wedding it's year) to be printed in the report.

Resolves #5948
2018-10-12 19:19:59 +01:00
Jgon6andNick Hall 3bac4a1036 Added symbols to the birthdays report showing the type of event
Issue #3540
2018-10-12 19:19:59 +01:00
Jgon6andNick Hall 1995a7068c Birthday report dead indicator now user defineable
Fixed the birthday report so the dead icon is able to be set within the
options window
2018-10-12 19:19:59 +01:00
Jgon6andNick Hall 5dc06d023d Indicate if a person is dead in the birthdays report
Added a text option to have a string that will show after a persons name
in the birthday and anniversary report. This works for both birthdays
and anniversaries.

Issue #3540
2018-10-12 19:19:43 +01:00
SNoiraudandNick Hall d98a1857dc Make relationships optional in narrative web
Fixes #10454
2018-10-12 18:46:39 +01:00
Paul Franklin 7da8811327 Setting the year as an ordinal number in Croatian
With this commit, the "master" version of the Statistics Chart
report will show a year as an ordinal number in Croatian.

So our translators will have until 5.1.0 is released to translate
the two new strings, in all the supported gramps languages.

Issue #10822
2018-10-07 23:45:40 -07:00
prculleyandNick Hall 15db2dd603 Disable OSX specific menu items, added in 'Gramps' menu 2018-10-07 16:49:12 +01:00
prculleyandNick Hall 97b15322d4 Add config option to use Toolbar Text 2018-10-07 16:49:12 +01:00
prculleyandNick Hall 824bf7e40f Geps044 - Replace deprecated Gtk.UIManager, Gtk.Actions etc. 2018-10-07 16:49:12 +01:00
milotypeandNick Hall 56fa261ef2 Better typography in graph reports
Replace hyphen with en-dash.
2018-10-07 16:16:19 +01:00
Robin van der VlietandSam Manzi 1efab19f1e Esperanto Translation Update eo.po (#660)
Made a lot of corrections and other stylistic improvements to the Esperanto file.
2018-09-27 11:21:15 +10:00
prculley 51e294f748 Fix up bad translation files after merge 2018-08-09 10:54:12 -05:00
Leonhaeuserandprculley cb65fd93ca Reviewed German translation Thanks to bmendl 2018-08-09 10:35:49 -05:00
niemematandprculley 5b9600d835 Fix translation in Finnish 2018-08-09 10:35:15 -05:00
John Rallsandprculley cf80d17040 File copy doesn't work if the glob can match directories. 2018-08-09 10:35:14 -05:00
John Rallsandprculley d4f906f22d Install the docs/gramps directory in the bundle.
Fixes bug #10705.
2018-08-09 10:35:14 -05:00
niemematandprculley d189e334d8 Fix and updated translation in Finnish 2018-08-09 10:35:14 -05:00
Ross Gammonandprculley a48a94d872 Update the Debian changelog after the 5.0.0 release 2018-08-09 10:35:13 -05:00
John Rallsandprculley 8e5dc220dc Release Gramps-5.0.0 on Mac. 2018-08-09 10:35:13 -05:00
Nick Hallandprculley dca2f610dc Bump to 5.0.1 2018-08-09 10:34:31 -05:00
Nick Hallandprculley 3d1833e307 Release Gramps 5.0.0 2018-08-09 10:33:57 -05:00
Nick Hallandprculley aa221cc3c7 Update Changelog and NEWS files 2018-08-09 10:33:19 -05:00
Nick Hallandprculley 51b7d1c420 Update translation template for new release 2018-08-09 10:30:58 -05:00
niemematandprculley 674d286f87 Fix translation in Finnish 2018-08-09 10:30:58 -05:00
John Rallsandprculley 0161c4b917 Correct binary test logic for primary mask.
state & get_primary_mask(another) tested (state & (primary | other)),
which will be true if state matches *either* primary *or* other, but
what is wanted in a not-negated test is state matching all bits of
(primary | other). match_primary_mask does that.

On the other hand there are also cases of "not state & (primary | other)".
no_match_primary_mask handles that, returning true if state matches none
 of the bits in (primary | other).

Fixes #10646.
2018-08-09 10:30:57 -05:00
prculley de31a42fc8 Fix BaseSelector to avoid long delay before display on large trees
Fixes #10634
2018-08-09 10:30:57 -05:00
SNoiraudandprculley 9c508de5fd Export options > Gui alignment issue
Fixes #10576
2018-08-09 10:30:57 -05:00
niemematandprculley 1b00d95ce4 New fix translation in Finnish 2018-08-09 10:30:57 -05:00
Espen Bergandprculley 78870decb8 Revised Norwegian bokmål 2018-08-09 10:30:56 -05:00
Espen Bergandprculley 1a5696eb2c Revised Norwegian bokmål 2018-08-09 10:30:24 -05:00
niemematandprculley 269d38da2c Fix translation in Finnish 2018-08-09 10:27:26 -05:00
Nick Hallandprculley 99f77b0a88 Fix dialog button order on non-Mac systems
Resolves #10585.
2018-08-09 10:27:25 -05:00
De Tranandprculley 264fdda4d0 Fix and update Vietnamese translation
Resolves #10681.
2018-08-09 10:27:24 -05:00
Sveinn í Felliandprculley 8092b88ad4 Update Icelandic translation 2018-08-09 10:12:17 -05:00
jose1711andprculley 3251e2ae88 Fix and update Slovak translation 2018-08-09 10:09:53 -05:00
jose1711andprculley f718c5f8b4 Fix typo in translation 2018-08-09 10:09:53 -05:00
niemematandprculley a96a446b47 Fix translation in Finnish 2018-08-09 10:09:53 -05:00
niemematandprculley 5658411acf Fix translation in Finnish 2018-08-09 10:09:53 -05:00
niemematandprculley a4403d719e Fix translation in Finnish 2018-08-09 10:09:52 -05:00
Luigi Toscanoandprculley 8597a10c40 Update Italian translation 2018-08-09 10:09:52 -05:00
Nick Hallandprculley d0c0045dc1 Update English (British) translation 2018-08-09 10:09:52 -05:00
De Tranandprculley 868abdc0d9 Update Vietnamese translation 2018-08-09 10:08:37 -05:00
Kaj Mikkelsenandprculley ebf88bf5c5 Update Danish translation 2018-08-09 10:08:35 -05:00
Lajos Nemesériandprculley c3814a4e42 Update Hungarian translation 2018-08-09 10:07:53 -05:00
John Ralls 52fe365919 Switch included moduleset to gitlab.gnome.org.
Fixes bug #10733.
2018-08-09 07:21:18 -07:00
prculley bc39dda9e7 Use msgcat merged po files instead of git merge versions 2018-07-13 07:35:36 -05:00
prculley 257275f169 Merge from gramps50 2018-07-12 11:10:22 -05:00
Espen Berg 9e61809b17 Received revised Norsk Nynorsk from Sigmund Lorentsen 2018-05-01 2018-05-17 21:30:15 +02:00
Espen Berg 9e2b935db1 revised Norwegian bokmål 2018-05-17 21:28:34 +02:00
Nick Hall 9a386574d8 Revert "Clone event w/o references (2nd pass, part B)"
This reverts commit 208feceb03.

Changes requested in the PR not made.  Such a change requires
discussion on the list first.
2018-05-12 23:09:27 +01:00
Nick Hall 90bdb0a840 Revert "Embedded Clone Event w. references (2nd pass, part A)"
This reverts commit ae322dbdc8.

Changes requested in the PR not made.  Such a change requires
discussion on the list first.
2018-05-12 22:59:52 +01:00
Alois Poettker ae322dbdc8 Embedded Clone Event w. references (2nd pass, part A) 2018-04-23 11:00:26 +02:00
Alois Poettker 208feceb03 Clone event w/o references (2nd pass, part B)
Feature request #9604

This functionality in the Event list doubles an event with all the tags, citations, media, attributes and notes, but without the references. Its like an event addition, but with default values.
2018-04-23 11:00:26 +02:00
Paulo Henrique MoraesandSam Manzi 32dd3a2e14 [pt_BR]Translation updates and corrections (#582)
- Portuguese (Brazil)
2018-03-15 11:26:59 +11:00
Jgon6andNick Hall 0ae51c9522 Changed behavior of "Look up with Map Services"
Removed the section that looked up by city, and country from the Map
Services lookup for Google and Open Street Map.

Resolves #9486
2018-03-03 17:35:51 +00:00
Nick Hall 59bd9f040d Merge branch 'gramps50' 2018-03-03 17:29:32 +00:00
Paulo Henrique MoraesandGitHub df00dd1f32 Brazilian portuguese update 2018-02-23 14:58:38 -03:00
niememat ca49b56774 Update finnish translation 2018-02-20 18:22:28 +02:00
Nick Hall 19f8c3561c Merge branch 'gramps50' 2018-02-09 00:13:43 +00:00
Serge NoiraudandGitHub 79ff9bc216 Geocoding: associate a lat/lon to a place name (#515)
* Geocoding: associate a lat/lon to a place name

Fixes #09642

* Some cleanup

* update README.md

* Remove url from message dialog
2018-01-18 09:11:51 +01:00
prculleyandNick Hall b54672d28d Leak (Uncollected Objects); allow user to cancel long screen update 2018-01-08 19:22:27 +00:00
mb06csandGitHub 6b42d71158 endoflinereport.py: sort generation during output 2018-01-06 13:32:43 +01:00
Paweł TomkielandNick Hall ac593d814d fixing polish places translations 2018-01-04 23:07:42 +00:00
Nick Hall 617e2212c8 new gramps.pot translation template 2018-01-04 22:59:31 +00:00
Nick Hall ad15ef7961 Merge branch 'gramps50' 2018-01-03 21:32:14 +00:00
niememat 406faa5603 Update finnish translation 2017-11-25 10:44:45 +02:00
Serge NoiraudandGitHub 4e0d562208 Various Feature Requests in Narrative Web (#468)
Issue #06772
2017-11-23 09:40:52 +01:00
Serge NoiraudandGitHub 43ef686622 Narrative Web Feature requests : (#466)
Sort "Surname" web page by given name and birth date.
Surname list doesn't use default name format

Fixes #05315, #08067
2017-11-23 09:39:12 +01:00
Serge NoiraudandGitHub d59fe6b2af Display Lat/Lon optionally on places list page (#467)
Fixes #05382
2017-11-23 09:37:47 +01:00
Serge NoiraudandGitHub d677a1a785 Add extra page to narrativeweb. (#465)
Fixes #02630
2017-11-23 09:36:13 +01:00
Leonhaeuser be776d6a31 updated German date handler: added some missing Latin month names and some old German month names 2017-10-05 21:34:23 +02:00
Nick Hall 1482fedb9c Merge branch 'gramps50' 2017-09-23 17:08:52 +01:00
Sam Manzi 00f8df60ce Revert "Tidy up mocking code (#438)[First commit]"
This reverts commit 8ebb4d35fa.
2017-09-23 07:50:48 +10:00
Jonathan BiegertandPaul Franklin f31caf1ea4 enable Graphviz node port selection, optionable (p.r. 456)
This enables the headport and tailport attributes for all edges in
the Graphviz file. The default (off) value makes the arrows between
persons and/or family nodes attach their ends to the respective node
at any position. When this option is selected, the position facing
the node on the other side of the arrow is always chosen.
2017-09-17 17:20:23 -07:00
Nick HallandSam Manzi 8ebb4d35fa Tidy up mocking code (#438)[First commit] 2017-09-17 11:03:39 +10:00
Serge NoiraudandSam Manzi c5f2717623 Gramps 'Views' are not named in the window header (#448)
Resolves #001675
2017-09-12 10:05:46 +10:00
Serge NoiraudandSam Manzi e5d5cfbd3a Allow Home person to be set in Relationship and Pedigree view (#446)
Resolves #0001970
2017-09-01 10:41:24 +10:00
Sebastian SchubertandNick Hall bd5f6e4711 example.gramps: add some non-primary participants to events
The following additional participants were added:
Death of Garner, Anderson:
* Page, Elizabeth (Witness)
* Farmer, Miranda Keziah (Witness)
* Page, David (Informant)

Birth of Thornton, James Arthur:
* Jankowski, Margaret Jane "Maggie" (Witness)
* Garner, Raymond E. (Informant)

Marriage of Garner, Lewis Anderson and Martel, Luella Jacques:
* Garner, Robert W. (Witness)
* Martel, Henry (Witness)
* Page, Robert (Clergy)
* Blanco, L. J. (Clergy)
2017-08-08 12:41:54 +01:00
Leonhaeuser e15deff4ed synced with gramps 50 2017-08-03 20:46:41 +02:00
romjerome 9d906c29a2 update french translation 2017-08-01 12:20:05 +02:00
romjerome 6577d43e4e merge forward (working release steps on gramps42) 2017-08-01 12:03:46 +02:00
Alois PoettkerandNick Hall 1a065485e3 Extend Pro-Gen importer II
Adapted to Pro-Gen test fix, expanded functionality and fixed
minor bugs.
2017-07-27 19:05:52 +01:00
schooncandNick Hall 009783a59a Add pycharm dir to .gitignore 2017-07-27 18:23:55 +01:00
Nick Hall 1b4f70c808 Fix permissions on leak gramplet 2017-07-27 18:18:53 +01:00
niememat dd4a727521 Update finnish translation 2017-07-27 09:48:08 +03:00
Paul CulleyandSam Manzi ebb7111f25 An improved Leak (Uncollected Objects) Gramplet (#345)
* Improved leak detector (debugging tool)

* Fix DummyDb so it garbage collector can reclaim it after close

* Fix leak gramplet so pop-ups use correct transient parent
2017-07-27 12:15:38 +10:00
Nick Hall 86fd14613e Merge branch 'gramps50' 2017-07-25 21:45:37 +01:00
Alois PoettkerandNick Hall 5276461239 Tidy up code 2017-07-18 18:25:29 +01:00
Alois PoettkerandNick Hall 40f47bc22d Delete multiple events 2017-07-18 18:20:55 +01:00
Nick Hall 8150403ccb Revert "Simplify import plugin unit tests"
This works with python 3.6 but not with 3.4.

This reverts commit b43d94ab16.
2017-07-18 16:57:55 +01:00
Nick Hall b43d94ab16 Simplify import plugin unit tests 2017-07-18 16:15:01 +01:00
Nick Hall 849290a3b7 Fix Pro-Gen unit test 2017-07-18 00:06:30 +01:00
Leonhaeuser 0b617e9fd6 update German translation
Fix #0010131
2017-07-15 00:23:00 +02:00
Lajos Nemesériandromjerome 6eb435142e Update Hungarian translation 2017-07-08 13:34:34 +02:00
Alois PoettkerandNick Hall e14ea777d5 Extend Pro-Gen importer functionality 2017-07-02 23:16:10 +01:00
Paul Franklin 46d73a16a0 add verify.py rules: match same birth or death date as marriage date
Issue #2583
2017-07-02 13:37:17 -07:00
Fedik 4d2b918d39 Update Ukrainian translation 2017-07-02 17:23:56 +03:00
romjerome 4acfdcce52 update french translation 2017-06-30 09:20:12 +02:00
arnaullvandNick Hall f3b3eec211 Updated catalan translation to latest template 2017-06-26 22:06:29 +01:00
niememat a840566e02 Update fix finnish translation 2017-06-24 19:33:00 +03:00
Nick Hall f6a2199f68 Merge branch 'gramps50' 2017-06-22 17:47:33 +01:00
Nick Hall dfc9dde32d Merge branch 'gramps50' 2017-06-15 16:44:15 +01:00
Zdeněk Hataš 50f93f54ec czech translation update 2017-06-05 11:49:50 +02:00
Nick Hall 9cb1d96725 Merge branch 'gramps50' 2017-06-03 22:20:03 +01:00
Nick Hall 40013dccc3 Merge branch 'gramps50' 2017-06-02 23:53:56 +01:00
Serge NoiraudandGitHub 24af1b8420 8200: Person Relatives Tab should use the type from the relationship (#396)
* 8200: Person Relatives Tab should use the type from the relationship

* 8200: Flag variables as there are now two variables.
2017-06-02 20:07:31 +02:00
Serge NoiraudandGitHub 213d656df4 10049: tabs reorganization in narrative web. (#406) 2017-06-02 13:20:21 +02:00
Nick Hall c09b4e96d2 Remove trailing whitespace 2017-05-23 19:52:19 +01:00
Nick Hall a80875e00c Update Travis for gramps51 2017-05-23 19:51:24 +01:00
Nick Hall bbdedb5097 Update a few missed version numbers 2017-05-23 19:49:23 +01:00
Nick Hall dd0671b111 Bump all version numbers to 5.1 2017-05-23 18:30:29 +01:00
233 changed files with 105975 additions and 73353 deletions
+3
View File
@@ -23,5 +23,8 @@ test/data
Thumbs.db
ehthumbs.db
# IDE
.idea/
# Glade temp files
*~
+6 -6
View File
@@ -72,7 +72,7 @@ install:
# by the automatic git checkout.
# Download Sean Ross-Ross's Pure Python module containing a framework to
# manipulate and analyze python asts and bytecode. This is loaded to
# manipulate and analyze python asts and bytecode. This is loaded to
# /home/travis/build/gramps-project/gramps/meta
# FIXME: This should be loaded from the release directory at
# https://pypi.python.org/pypi/meta
@@ -95,11 +95,11 @@ before_script:
# set GRAMPS_RESOURCES for locale, data,image and documentation
- export GRAMPS_RESOURCES=.
# Install addons
- mkdir -p ~/.gramps/gramps50/plugins/
- wget https://github.com/gramps-project/addons/raw/master/gramps50/download/CliMerge.addon.tgz
- tar -C ~/.gramps/gramps50/plugins -xzf CliMerge.addon.tgz
- wget https://github.com/gramps-project/addons/raw/master/gramps50/download/ExportRaw.addon.tgz
- tar -C ~/.gramps/gramps50/plugins -xzf ExportRaw.addon.tgz
- mkdir -p ~/.gramps/gramps51/plugins/
- wget https://github.com/gramps-project/addons/raw/master/gramps51/download/CliMerge.addon.tgz
- tar -C ~/.gramps/gramps51/plugins -xzf CliMerge.addon.tgz
- wget https://github.com/gramps-project/addons/raw/master/gramps51/download/ExportRaw.addon.tgz
- tar -C ~/.gramps/gramps51/plugins -xzf ExportRaw.addon.tgz
script:
# Ignore the virtualenv entirely. Use nosetests3, python3 (3.4.0) and coverage
+236 -739
View File
@@ -1,746 +1,243 @@
2018-12-20 Paul Culley <paulr2787@gmail.com>
2018-07-24 Nick Hall <nick-h@gramps-project.org>
* gramps/gui/configure.py, gramps/gui/display.py,
gramps/gui/glade/book.glade, gramps/gui/glade/styleeditor.glade,
gramps/gui/plug/report/_bookdialog.py,
gramps/gui/plug/report/_styleeditor.py,
gramps/gui/selectors/selectperson.py,
gramps/gui/selectors/selectrepository.py,
gramps/gui/widgets/grampletpane.py,
gramps/gui/widgets/reorderfam.py,
gramps/plugins/tool/mediamanager.py,
gramps/plugins/tool/relcalc.glade, gramps/plugins/tool/relcalc.py,
po/ar.po, po/bg.po, po/br.po, po/ca.po, po/cs.po, po/da.po,
po/de.po, po/el.po, po/en_GB.po, po/eo.po, po/es.po, po/fi.po,
po/fr.po, po/ga.po, po/gramps.pot, po/he.po, po/hr.po, po/hu.po,
po/is.po, po/it.po, po/ja.po, po/lt.po, po/mk.po, po/nb.po,
po/nl.po, po/nn.po, po/pl.po, po/pt_BR.po, po/pt_PT.po, po/ro.po,
po/ru.po, po/sk.po, po/sl.po, po/sq.po, po/sr.po, po/sr_Latn.po,
po/sv.po, po/ta.po, po/tr.po, po/uk.po, po/vi.po, po/zh_CN.po,
po/zh_HK.po, po/zh_TW.po: Help issues for bug 9042 (#738) * Media Manager: add help button and remove '...' Issue #9042 * Edit/Preferences: add Help button Issue #9042 * Style Editor, Document Styles dialog: add help buttons Issue #9042 * Fix Select Person dialog Help button URL Issue #9042 * Fix Select Repository dialog Help button URL Issue #9042 * Relationship Calculator: Add help button Issue #9042 * Reorder Relationships dialog; add Help button Issue #9042 * Generate Book Dialog; Fix Help URL Issue #9042 * Manage Book dialog; add help button Issue #9042 * Fix Detached Gramplets Help button URL when 'help_url' not in .gpr Issue #9042 * Fix help URLs when they contain illegal characters and to match
wiki section targetID algorithm Issue #9042
2018-12-20 prculley <paulr2787@gmail.com>
* po/hu.po: Updated Hungarian translation
2018-12-20 milotype <43657314+milotype@users.noreply.github.com>
* gramps/gen/datehandler/_date_hr.py, po/hr.po: Croatian
localisation updates (#741) * Update/Completion Croatian translation This is a big update. The croatian translation is now 100% complete.
Translated all missing strings, made lots of corrections, improved
consistency in the wording, tested thoroughly. Also, it will work
with the updated datehandler file "_date_hr.py", which i'll be
updating simultaneously. * Croatian Datehandler update Made changes to fit croatian specific date handling. Also because
i've updated the hr.po file. I've tested it with the present
"_datedisplay.py" of the maintainance/gramps50 branch. Basically it would be great, if next to the obligatory "display_iso"
format, only two more formats would show up in the croatian
drop-down menus: "dd_dformat01" (numerical) and "dd_dformat04".
Other formats are unneeded. 9. 5. 2018. => ordinal numbers, all separated by spaces 9. svibnja 2018. => ordinal numbers and genitiv month's form, all
separated by spaces
2018-12-20 Nick Hall <nick-h@gramps-project.org>
* gramps/gen/db/generic.py: Fix contents of enclosed_by secondary
dbapi column (#742) The enclosed_by column should contain the first value in the list
instead of the last. Resolves #10907.
2018-12-18 Leonhaeuser <mirko@leonhaeuser.de>
* po/de.po: update German translation
2018-12-15 SNoiraud <serge.noiraud@laposte.net>
* gramps/plugins/mapservices/googlemap.py: Google maps URL problem Fixes #10772
2018-12-09 prculley <paulr2787@gmail.com>
* gramps/gen/plug/docbackend/docbackend.py: Fix ODT reports with
links when run in non-English languages Fixes #10911
2018-12-06 prculley <paulr2787@gmail.com>
* gramps/gui/plug/report/_reportdialog.py: Allow addon Reports to
specify a help button URL for options dialog Fixes #10910
2018-12-01 Nick Hall <nick-h@gramps-project.org>
* gramps/plugins/db/dbapi/dbapi.py, gramps/plugins/tool/rebuild.py:
Fix Rebuild Secondary Indexes tool for dbapi backends For dbapi backends, this tool will update the secondary columns that
are used for indexing. Resolves #10757.
2018-11-15 prculley <paulr2787@gmail.com>
* gramps/plugins/db/dbapi/dbapi.py: Fix dbapi set_name_group_mapping
to properly close transaction Fixes #10730
2018-10-24 prculley <paulr2787@gmail.com>
* gramps/gen/datehandler/_date_ru.py: Fix Russian date handler crash
when Russian .po isn't present Fixes #10855
2018-12-04 Leonhaeuser <mirko@leonhaeuser.de>
* po/de.po: update German translation
2018-12-04 vantu5z <vantu5z@mail.ru>
* po/ru.po: update Russian translation
2018-11-29 niememat <niememat@gmail.com>
* po/fi.po: Update finnish translation
2018-11-28 Paul Culley <paulr2787@gmail.com>
* gramps/gui/plug/quick/_quicktable.py: Fix Quickview for missing
table data on some Gtk Versions (#593) Issue #10448 Issue #7867
2018-11-28 Paul Culley <paulr2787@gmail.com>
* gramps/cli/arghandler.py, gramps/gui/grampsgui.py: Fix startup
messages with bad filename (#720) Fixes #10885
2018-11-28 Paul Culley <paulr2787@gmail.com>
* gramps/gui/selectors/selectplace.py,
gramps/gui/views/treemodels/placemodel.py,
gramps/plugins/lib/libplaceview.py: Restrict Place view Name col to
the primary name (#673) while allowing searchbar to find alt and primary names related to Issue #9276 while allowing searchbar to find alt and primary names. Currently, the Place View and Place Selector name column shows a
comma separated list of the primary and alt names for a place. With
the advent of GeoNames and Gov data, the alt names lists are getting
populated with (sometimes long) lists of (sometimes duplicated)
names. This doesn't look very good in the view. I've gotten a couple
of email complaints about this. The Name column was originally extended (for Gramps50) to include
alt names to allow the use of the top search bar (enabled when
sidebar is turned off via 'View/Sidebar'), to perform a search
through all the alt names as well as primary name.
https://gramps-project.org/bugs/view.php?id=9276 This PR creates a new (hidden) column in the place model containing
the full name list, and reverts the 'Name' column to the primary
name. It also modifies the PlaceSelector and PlaceView classes to
cause the search bar to use the new (hidden) column.
2018-11-28 Paul Culley <paulr2787@gmail.com>
* gramps/gui/filters/sidebar/_personsidebarfilter.py: Fix Person
Sidebarfilter when using 'Event' and Reg expressions (#729) Fixes #10659
2018-11-28 Paul Culley <paulr2787@gmail.com>
* gramps/plugins/tool/finddupes.py: Fix Find Duplicate People;
exception when deleting someone shown (#728) outside of the tool Fixes #10875
2018-11-28 Paul Culley <paulr2787@gmail.com>
* data/tests/exp_sample_ged.ged,
gramps/plugins/export/exportgedcom.py,
gramps/plugins/test/exports_test.py: Gedcom export, upgrade OBJE
handling to Gedcom 5.5.1 style (#702) Fixes #10797
2018-11-28 Paul Culley <paulr2787@gmail.com>
* data/tests/imp_sample_csv.gramps,
gramps/plugins/importer/importcsv.py: Fix CSV import to set marriage
event role to family (#725) Fixes #9952
2018-11-28 Paul Culley <paulr2787@gmail.com>
* data/tips.xml.in, po/ar.po, po/bg.po, po/br.po, po/ca.po,
po/cs.po, po/da.po, po/de.po, po/el.po, po/en_GB.po, po/eo.po,
po/es.po, po/fi.po, po/fr.po, po/ga.po, po/gramps.pot, po/he.po,
po/hr.po, po/hu.po, po/is.po, po/it.po, po/ja.po, po/lt.po,
po/mk.po, po/nb.po, po/nl.po, po/nn.po, po/pl.po, po/pt_BR.po,
po/pt_PT.po, po/ro.po, po/ru.po, po/sk.po, po/sl.po, po/sq.po,
po/sr.po, po/sr_Latn.po, po/sv.po, po/ta.po, po/tr.po, po/uk.po,
po/vi.po, po/zh_CN.po, po/zh_HK.po, po/zh_TW.po: Update gramps
bugtracker URL in all po files (#710) Fixes #10543
2018-11-28 Serge Noiraud <Serge.Noiraud@laposte.net>
* data/css/Web_Basic-Ash.css, data/css/Web_Basic-Blue.css,
data/css/Web_Basic-Cypress.css, data/css/Web_Basic-Lilac.css,
data/css/Web_Basic-Peach.css, data/css/Web_Basic-Spruce.css,
data/css/Web_Mainz.css, data/css/Web_Nebraska.css: Narrative Web :
thumbnails bad alignment. (#691) * Narrative Web : thumbnails bad alignment. Fixes #10854 also solves the following problems in the Nebraska style sheet : 1 - float parameter has no value "center" 2 - "[" instead of ";" at end of line 1100 * overlapping with long titles
2018-11-28 Paul Culley <paulr2787@gmail.com>
* gramps/gui/views/treemodels/citationlistmodel.py: Fix typo in
CitationListModel for sort change (#730)
2018-11-28 Serge Noiraud <Serge.Noiraud@laposte.net>
* gramps/plugins/gramplet/todo.py: Fix Adding "ToDo" note crash when
no active object (#685) * Fix Adding "ToDo" note crash when no active object Fixes #10795 * Better message when no active object. * resolve conflict: Fixes #10795
2018-11-28 Paul Culley <paulr2787@gmail.com>
* gramps/gui/views/treemodels/citationbasemodel.py,
gramps/gui/views/treemodels/citationlistmodel.py: Fix Citation List
view Source Last Changed Column to sort properly (#723) Fixes #10893
2018-11-28 pmraps <43935667+pmraps@users.noreply.github.com>
* po/pt_PT.po: some pt_PT.po translation changes (#703) * some header changes * more changes
2018-11-28 Paul Culley <paulr2787@gmail.com>
* gramps/gui/viewmanager.py: Fix for re-entrant main window close
when user hits 'x' again (#724) Fixes #10897
2018-11-28 Paul Culley <paulr2787@gmail.com>
* gramps/gui/managedwindow.py: Fix exception when closing early
editor in tree of editors (#706) Fixes #10876
2018-11-28 Serge Noiraud <Serge.Noiraud@laposte.net>
* gramps/plugins/webreport/basepage.py: Narrative Web: thumbnails
problems in some cases. (#722) Fixes #10890
2018-11-27 Paul Culley <paulr2787@gmail.com>
* gramps/gui/plug/report/_bookdialog.py: Fix 'Generate Book' dialog
for crash on 'x' close (#726) Fixes #10901
2018-11-27 Paul Culley <paulr2787@gmail.com>
* gramps/plugins/gramplet/todo.py: Fix ToDo Gramplet for multiple
attempts to edit a note (#719) Fixes #10645
2018-11-27 Paul Culley <paulr2787@gmail.com>
* gramps/gui/widgets/grampletpane.py: Fix Dashboard for multiple
copies of a Gramplet (#718) * Fix Dashboard for multiple copies of a Gramplet Fixes #10650 * Fix Dashboard to recall minimized or undocked Gramplets
2018-11-27 Paul Culley <paulr2787@gmail.com>
* gramps/gui/displaystate.py: Fix Statusbar update to avoid
intermittent exception on closed db (#716) Fixes #10882
2018-11-27 Paul Culley <paulr2787@gmail.com>
* gramps/gen/filters/_filterparser.py: Fix FilterParser for much
older 3.x custom_filters.xml files (#715) Fixes #8075 Fixes #10669 Fixes #10516
2018-11-27 Paul Culley <paulr2787@gmail.com>
* gramps/gen/filters/rules/person/_isduplicatedancestorof.py: Fix
IsDuplicatedAncestorOf filter rule to avoid crash on tree loop
(#714) Fixes #10685
2018-11-28 Serge Noiraud <Serge.Noiraud@laposte.net>
* gramps/plugins/webreport/person.py,
gramps/plugins/webreport/place.py: Narrative web : use latest
version from openlayers. (#713) Fixes #10884
2018-11-27 Paul Culley <paulr2787@gmail.com>
* gramps/gui/editors/editlink.py: Fix StyledTextEditor EditLink for
root text changed to zero length (#709) in the background Fixes #9750
2018-11-27 Paul Culley <paulr2787@gmail.com>
* gramps/gen/simple/_simpleaccess.py: Fix AgeOnDate and some reports
using SimpleAccess for missing surname (#708) Fixes #9958 Fixes #9800
2018-11-27 Paul Culley <paulr2787@gmail.com>
* gramps/gen/filters/rules/_rule.py: Fix crash when a filter with
loop in definition is defined (#707) Fixes #10621
2018-11-27 Paul Culley <paulr2787@gmail.com>
* gramps/gen/proxy/referencedbyselection.py,
gramps/plugins/gramplet/citations.py: Fix HandleErrors related to
LDS (#697) * Fix ReferencedBySelection proxy for 'None' LDS Parents Fixes #10865 * Fix HandleError in Citations Gramplet for lds place missing
2018-11-27 Paul Culley <paulr2787@gmail.com>
* gramps/plugins/lib/libplaceview.py: Change PlaceView drag from
whole row to just icon during drag (#695) Fixes #10863
2018-11-27 Paul Culley <paulr2787@gmail.com>
* gramps/gui/editors/displaytabs/embeddedlist.py: Add drag Icon to
drags from DisplayTabs Gramplet lists (#694) Fixes #10859
2018-11-27 Paul Culley <paulr2787@gmail.com>
* gramps/gui/glade/baseselector.glade,
gramps/gui/glade/dbman.glade,
gramps/gui/plug/report/_bookdialog.py,
gramps/gui/selectors/baseselector.py,
gramps/gui/selectors/selectcitation.py,
gramps/gui/selectors/selectevent.py,
gramps/gui/selectors/selectfamily.py,
gramps/gui/selectors/selectnote.py,
gramps/gui/selectors/selectobject.py,
gramps/gui/selectors/selectperson.py,
gramps/gui/selectors/selectplace.py,
gramps/gui/selectors/selectrepository.py,
gramps/gui/selectors/selectsource.py,
gramps/plugins/tool/testcasegenerator.py: Fix dialogs for 'Help'
button closes the dialog, and non-functional 'Help' (#727) * Fix Family Tree manager for 'Help' button closes dialog Fixes #10589 * Fix selectors for 'Help' button closes dialog Fixes #10589 * Fix 'Generate Book' dialog for 'Help' button closes dialog Fixes #10589 * Fix TestcaseGenerator for 'Help' button closes dialog Fixes #10589 * Fix Selectors to enable the 'Help' buttons to actually work Fixes #10589
2018-10-26 prculley <paulr2787@gmail.com>
* gramps/gui/editors/editfamily.py: Avoid HandleError when dragging
an Added Family from EditFamily Fixes #10858
2018-10-26 prculley <paulr2787@gmail.com>
* gramps/gui/editors/editperson.py: Avoid HandleError when dragging
an Added Person from EditPerson Fixes #10857
2018-10-20 prculley <paulr2787@gmail.com>
* gramps/gui/clipboard.py: Fix Clipboard rows cannot be sorted via
drag/drop Fixes #10849
2018-10-19 prculley <paulr2787@gmail.com>
* gramps/gen/config.py, gramps/gui/dbloader.py,
gramps/gui/plug/export/_exportassistant.py,
gramps/gui/views/listview.py: Better default directory choices for
import/export Use recent-export-dir as default for Export View instead of the
console default directory, which can be where program resides (on
Windows), or other inappropriate place. Use USER_HOME for default directory on 'Export' (recent-export-dir)
if first run (default settings) rather than default directory, which
can be where program resides (on Windows), or other inappropriate
place. Use USER_HOME for default directory on 'Import' (recent-import-dir)
if first run (default settings) rather than recent file which is
generally set to the grampsdb path. Fixes #10802
2018-10-16 SNoiraud <serge.noiraud@laposte.net>
* gramps/plugins/docgen/htmldoc.py: Records Report: call name not
underlined in HTML Fixes #10816
2018-11-20 Christophe <khrys63@gmail.com>
* po/fr.po: Fix French translation
2018-10-14 prculley <paulr2787@gmail.com>
* gramps/gui/widgets/interactivesearchbox.py: Fix InteractiveSearch
for find before model is populated Fixes #10844
2018-10-07 prculley <paulr2787@gmail.com>
* gramps/plugins/export/exportgedcom.py: Fix Gedcom export for
incorrect escaping with @#DFRENCH R@ Fixes #10833
2018-10-06 prculley <paulr2787@gmail.com>
* gramps/plugins/textreport/detancestralreport.py,
gramps/plugins/textreport/detdescendantreport.py,
gramps/plugins/textreport/indivcomplete.py,
gramps/plugins/webreport/basepage.py: Fix reports for shared event
attribute and note errors Fixes #10720
2018-10-02 prculley <paulr2787@gmail.com>
* gramps/gui/widgets/fanchart.py,
gramps/gui/widgets/fanchartdesc.py: Fix Fan and Descendant Fan
charts in Quadrant and Half Circle modes The Descendant Fan chart
had several bugs: 1) a bug that affected the centering of the chart for these modes 2) the chart was drawn in the wrong quadrant 3) the centering of the chart for printing was incorrect (the legend was off the page some of the time). 4) the sizing of the chart for printing was incorrect (for very small charts of one generation, the legend would overwrite the chart). The Fan Chart for the quadrant view: 1) the centering of the chart for printing was incorrect (the legend was off the page some of the time). Fixes #10817
2018-09-30 Robin van der Vliet <info@robinvandervliet.com>
* gramps/plugins/rel/rel_nl.py: Fixed issues in the Dutch
relationship calculator Fixed some issues in the Dutch relationship calculator and also
extended the ordinal and removed lists till 50, just like the
English lists. * Replaced huge lists by reusable lists. * Fixed bug in which uncles/aunts, nephews/nieces (niblings), siblings and cousins with an unknown gender show up as female. * Fixed some misspellings: drieëntwingste > drieëntwinTIgste vierentwingste > vierentwinTIgste edelovergrootOUD > edelovergroot edeloudvergroot > edeloudOvergroot
2018-11-15 Pär Ekholm <pelle.ekh@koping.net>
* po/sv.po: Update Swedish translation
2018-11-18 niememat <niememat@gmail.com>
* po/fi.po: Fix translation in Finnish
2018-11-10 niememat <niememat@gmail.com>
* po/fi.po: Update finnish translation
2018-11-09 vantu5z <vantu5z@mail.ru>
* po/ru.po: update Russian translation
2018-09-28 SNoiraud <serge.noiraud@laposte.net>
* data/css/Web_Basic-Ash.css, data/css/Web_Basic-Blue.css,
data/css/Web_Basic-Cypress.css, data/css/Web_Basic-Lilac.css,
data/css/Web_Basic-Peach.css, data/css/Web_Basic-Spruce.css,
data/css/Web_Horizontal-Menus.css, data/css/Web_Mainz.css,
data/css/Web_Nebraska.css, gramps/plugins/webreport/basepage.py:
NarrativeWeb fixes Space between place, description and the event note when there are
many sources. Change the css order between print and screen. The
chosen theme can erase prior values. Add a width for the source
column in all themes. Fixes #10810
2018-10-17 niememat <niememat@gmail.com>
* po/fi.po: Fix translation in Finnish
2018-10-07 Paul Franklin <pf.98052@gmail.com>
* gramps/plugins/drawreport/statisticschart.py,
gramps/plugins/graph/gvfamilylines.py,
gramps/plugins/graph/gvrelgraph.py,
gramps/plugins/webreport/webcal.py: Setting the year as an ordinal
number in Croatian With this commit, two more reports now show a year as an ordinal
number in Croatian, and a year I missed before in webcal.py is now
fixed. This commit also reverts the Croatian ordinal year fix in the
gramps50 statisticschart.py since upon reflection I feel it would be
better done in master, since then our translators will have until
5.1.0 is released to do the two new strings the fix requires. Issue #10822
2018-10-07 Paul Franklin <pf.98052@gmail.com>
* gramps/plugins/textreport/indivcomplete.py: name-note is not being
cleared in Complete Individual report I ran gramps with a fresh copy of the example.gramps tree, then ran
the Complete Individual report. The options which matter are
"Entire Database" and "Include Notes" but I also included the
gramps-ID since that speeds up my work. Then I noticed that hundreds of names at the end of the output file
all had the same note (N0001), whose text said it referred to a
specific person. So I looked higher and the note inclusion started with I0044, the
default person. It was real for him but not for the next person
after him, or all the people after her. I introduced the problem when I fixed 10033, in d6a97cf90e. Note that this bug is independent of the CIR fix in p.r. 676 and
still happens even after that pull request is applied.
2018-10-04 prculley <paulr2787@gmail.com>
* gramps/gui/columnorder.py, gramps/gui/views/listview.py: Fix View
Column sizing so last column size setting is maintained Fixes #10800
2018-08-06 prculley <paulr2787@gmail.com>
* gramps/gui/views/listview.py: Fix view so column widths are
preserved when using filters Fixes #10725
2018-08-29 vantu5z <vantu5z@mail.ru>
* po/ru.po: update Russian translation
2018-10-04 Paul Franklin <pf.98052@gmail.com>
* gramps/gen/display/place.py: fix typo in cbac98894bfa7e1969625efceccc19c4d5374a7e
2018-10-04 Paul Franklin <pf.98052@gmail.com>
* gramps/plugins/lib/libnarrate.py,
gramps/plugins/textreport/detancestralreport.py,
gramps/plugins/textreport/detdescendantreport.py: fix the
place-format option in DDR and DAR The place-format option was added to the Detailed Descendant and
Detailed Ancestor text reports in
cbac98894bfa7e1969625efceccc19c4d5374a7e But those two reports use the Narrator class to show many of their
places (and dates), and that class was not modified to use the
user's custom place format. So if a user had created a custom place format and ran either of
those two reports, their places would be shown inconsistently. This
commit fixes that. (The non-detailed ancestor text report also uses Narrator to show
its places but that report has not had the place-format option added
to it, so this commit doesn't touch it.)
2018-10-04 Paul Franklin <pf.98052@gmail.com>
* gramps/plugins/drawreport/fanchart.py,
gramps/plugins/drawreport/statisticschart.py,
gramps/plugins/drawreport/timeline.py, po/hr.po: Setting the year as
an ordinal number in Croatian With this commit, three more reports now show a year as an ordinal
number in Croatian. Issue #10822
2018-05-09 prculley <paulr2787@gmail.com>
* gramps/plugins/db/bsddb/read.py: Fix bsddb for person sort with
empty Surname list Fixes #10078, #10577
2018-10-01 Paul Franklin <pf.98052@gmail.com>
* gramps/plugins/drawreport/calendarreport.py,
gramps/plugins/textreport/birthdayreport.py,
gramps/plugins/webreport/webcal.py, po/hr.po: Setting the year as an
ordinal number in Croatian When I started investigating 10822, I saw some Croatian dates didn't
seem to be working in 5.0.0, to my surprise. I believe I fixed that
in the previous commit. With this commit, the three reports now show a year as an ordinal
number in Croatian, so I consider 10822 fixed. If there are any additional problems displaying Croatian, please
file additional bug reports ("one bug, one report"). Fixes #10822
2018-10-01 Paul Franklin <pf.98052@gmail.com>
* gramps/gen/datehandler/_date_hr.py,
gramps/gen/datehandler/_datedisplay.py, po/hr.po: Setting the year
as an ordinal number in Croatian When I started investigating 10822 I saw some Croatian dates didn't
seem to be working in 5.0.0, to my surprise. There seems to have
been some kind of regression from 4.2.8. But the Croatian translation for gramps hasn't been updated in about
three years -- except by non-Croatians. So I don't know why some
"translated" strings which control how dates are displayed were
disabled (marked as "fuzzy") in this:
6c67053e1fa22405bde0fae38e81de7ace222d41 Also, I saw some code in the 4.2.8 Croatian date handler which was
not in the 5.0.0 Croatian date handler -- somehow. So I believe this commit fixes the Croatian date handler. Issue #10822
2018-09-30 Serge Noiraud <Serge.Noiraud@laposte.net>
* gramps/plugins/webreport/webcal.py: Webcal: link problems in some
cases (#661) * Webcal: link problems in some cases Year 2016 is highlighted by default instead of current year. Fixes #10801 * Webcal: Missing links when muliyear unselected
2018-09-29 Serge Noiraud <Serge.Noiraud@laposte.net>
* gramps/plugins/view/geoclose.py: Geoclose: exception when a family
has no father (#662)
2018-09-26 Paul Franklin <pf.98052@gmail.com>
* gramps/plugins/drawreport/descendtree.py: Report plugin krasch Load data.gramps, start with the default person (I0037, Edwin
Michael Smith), run Family Descendant Tree, choose "Start with the
parent(s) of the selected first", hit OK: .../descendtree.py", line 881, in start family2 = self.database.get_family_from_handle(family2_h) ... Or start with I0057 (Anna Louise Smith), run Family Descendant Tree,
choose "Start with the parent(s) ...", hit OK: .../descendtree.py", line 773, in start family2 = self.database.get_family_from_handle(family2_h) ... Fixes #10811
2018-09-26 Paul Franklin <pf.98052@gmail.com>
* gramps/gen/datehandler/_date_is.py,
gramps/gen/datehandler/_datedisplay.py: [unhandled exception parsing
"future dates" in some locales] There is already a check in the MonitoredDate class for years which
are more than one year in the future, so such a date is already
going to be shown in red. But some locales use the "datetime" library to parse typed-in dates
and that has a maximum year of datetime.MAXYEAR, 9999 currently, so
dates greater than that produce a ValueError. Besides adding checks for that, I have also made it so that locales
which don't need that library don't use it. Fixes #10815
2018-09-24 Paul Franklin <pf.98052@gmail.com>
* gramps/gen/datehandler/_date_nb.py: Julian/Gregorian calendar
issue when entering only year as date when running gramps in Norwegian Fixes #10687
2018-09-23 Serge Noiraud <Serge.Noiraud@laposte.net>
* gramps/plugins/webreport/basepage.py: Events difficult to read
(screen and mobile) (#658)
2018-09-17 Paul Franklin <pf.98052@gmail.com>
* gramps/gen/plug/report/stdoptions.py,
gramps/plugins/textreport/placereport.py: fix typo in cf42e5a4b847e6881f180cd1b776fb02234768be and
cbac98894bfa7e1969625efceccc19c4d5374a7e Fixes #10782
2018-09-08 Leonhaeuser <mirko@leonhaeuser.de>
* po/de.po: update German translation
2018-09-06 niememat <niememat@gmail.com>
* po/fi.po: New update for Finnish translation
2018-09-06 niememat <niememat@gmail.com>
* po/fi.po: Update finnish translation
2018-09-05 Paul Culley <paulr2787@gmail.com>
* gramps/plugins/gramplet/statsgramplet.py: Fix and restore
Statistics Gramplet to 4.2.x status (#653) Fixes #10754 A bit of history. bug 2060 was filed a long time ago (2008), and a
patch was added to close it in 2016. I believe that the bug had
already been patched by then, although I cannot be sure. The patch
caused the Gramplet to update anytime the active-changed signal
occurred on a person view. I suspect that this caused a fair amount
of overhead on very large dbs as the entire person list was
rescanned. In any event, Doug Blank recently removed the original scan code, as
well as some useful functionality. And left behind a bug where a
value was always zero. The users email list had some complaints
about the lost functionality, and I also saw some recent complaints
that the gender statistics were incorrect. Turns out that the db's
genderstats data was incorrect, probably due to crashes after db
updates. The Genderstats don't get saved until db closes normally.
In addition, running the Genderstats rebuild tool, did not
immediately appear to correct the situation, Gramps had to be
restarted to show the updated results. I added the original statistics code back into the Gramplet,
suitably updated for 5.0.x. So the Gramplet no longer depends on dbs
genderstats, it scans for it now on its own. I removed the update on active-changed function, so overhead is only
present on actual db updates (which have their own signals). I
tested that the add, edit, and delete person changes do properly
cause the statistics to update now. So the active-changed signal is
not necessary.
2018-09-04 Paul Culley <paulr2787@gmail.com>
* gramps/plugins/test/tools_test.py, gramps/plugins/tool/check.py:
Fix Check and Repair to deal with bad references empty handle string
(#657) Fixes #10783 Check and Repair tool doesn't fix bad references when the reference
handle is an empty string. Found when rewriting the backlinks scan
on same tool. I assumed that the prior checks had already corrected
any bad forward references, and did not put in a test for them in my
new code. The Travis test failed and when I debugged, I found that
the tool had an exception on a handle that consisted of an empty
string. Its interesting to note that when I changed the code, a lot more
citation and source references were fixed in the test.
2018-09-04 Paul Culley <paulr2787@gmail.com>
* gramps/plugins/tool/check.py: Speed up Check and Repair, backlinks
check stage. (#656) Fixes #10618 * Speed up Check and Repair, backlinks check stage. * Fix Check and repair; backlinks scan to deal with bad references
which should have been fixed in earlier checks!
2018-09-03 Paul Culley <paulr2787@gmail.com>
* gramps/gen/config.py, gramps/gen/datehandler/_date_ar.py,
gramps/gen/datehandler/_date_bg.py,
gramps/gen/datehandler/_date_ca.py,
gramps/gen/datehandler/_date_da.py,
gramps/gen/datehandler/_date_de.py,
gramps/gen/datehandler/_date_el.py,
gramps/gen/datehandler/_date_es.py,
gramps/gen/datehandler/_date_fi.py,
gramps/gen/datehandler/_date_hr.py,
gramps/gen/datehandler/_date_hu.py,
gramps/gen/datehandler/_date_is.py,
gramps/gen/datehandler/_date_it.py,
gramps/gen/datehandler/_date_ja.py,
gramps/gen/datehandler/_date_lt.py,
gramps/gen/datehandler/_date_nb.py,
gramps/gen/datehandler/_date_nl.py,
gramps/gen/datehandler/_date_pl.py,
gramps/gen/datehandler/_date_pt.py,
gramps/gen/datehandler/_date_ru.py,
gramps/gen/datehandler/_date_sk.py,
gramps/gen/datehandler/_date_sl.py,
gramps/gen/datehandler/_date_sr.py,
gramps/gen/datehandler/_date_sv.py,
gramps/gen/datehandler/_date_uk.py,
gramps/gen/datehandler/_date_zh_CN.py,
gramps/gen/datehandler/_date_zh_TW.py,
gramps/gen/datehandler/_dateparser.py, gramps/gen/display/name.py,
gramps/gen/filters/rules/_changedsincebase.py,
gramps/gen/lib/place.py, gramps/gen/mime/_winmime.py,
gramps/gen/soundex.py, gramps/gen/utils/db.py, gramps/gui/dbman.py,
gramps/gui/editors/editlink.py, gramps/plugins/docgen/latexdoc.py,
gramps/plugins/docgen/rtfdoc.py,
gramps/plugins/export/test/exportvcard_test.py,
gramps/plugins/importer/importgeneweb.py,
gramps/plugins/importer/importxml.py,
gramps/plugins/importer/test/importvcard_test.py,
gramps/plugins/tool/reorderids.py, setup.py,
windows/nonAIO/builder/build_GrampsWin32.py,
windows/nonAIO/builder/check_gtk_install.py,
windows/nonAIO/builder/make_launcher.py,
windows/nonAIO/check_gtk_install.py: Fix strings containing
deprecated illegal escape sequences (#648) Python 3.6 and above has deprecated illegal string escape sequences.
Escape sequences are preceded by a '\' and valid ones are "\n\t\r"
etc. Illegal ones are not in the list
https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals.Previous to Python 3.6 these illegal sequences were ignored and the
'\' was left in place. Pylint has been noting these for a while now. This PR corrects these sequences in Gramps. I used find . -name "*.py" | xargs -t -n 1 python3 -Wd -m py_compile 2>&1 |
grep Depre to locate the failing strings.
2018-09-04 Ivan <vantu5z@mail.ru>
* gramps/plugins/gramplet/whatsnext.py: [Whatsnext] check if db is
open (#651) Fixes #10732
2018-09-03 Paul Culley <paulr2787@gmail.com>
* gramps/gui/viewmanager.py,
gramps/plugins/gramplet/statsgramplet.py,
gramps/plugins/quickview/filterbyname.py,
gramps/plugins/textreport/summary.py,
gramps/plugins/webreport/statistics.py: Fix usage of posixpath;
should be os.path for os independence (#650) Fixes #10740
2018-09-03 Paul Culley <paulr2787@gmail.com>
* gramps/gen/utils/file.py: Fix generate_checksum routine to avoid
MemoryError crash (#649) with very large files and 32-bit OS Issue #10690
2018-09-03 Paul Culley <paulr2787@gmail.com>
* gramps/gui/views/bookmarks.py: Fix corrupted Bookmarks that can
happen after Gramps crash (#655) Fixes #10759
2018-09-03 Paul Culley <paulr2787@gmail.com>
* gramps/gen/merge/mergefamilyquery.py: Fix Merge Family when same
parent is missing from both families (#654) Fixes #10760
2018-09-03 Paul Culley <paulr2787@gmail.com>
* gramps/gui/views/pageview.py: Fix <ctrl>c in view to get selected
item to clipboard (#652) Fixes #10682
2018-09-03 Paul Culley <paulr2787@gmail.com>
* gramps/plugins/gramplet/quickviewgramplet.py: Fix Quickview
Gramplet so updates work when changing active (#642) Fixes #10713
2018-09-03 Paul Culley <paulr2787@gmail.com>
* gramps/gui/editors/editplaceref.py: Fix place reference editor for
bad cut/paste on set_latlongitude (#644) Fixes #10719
2018-09-03 Paul Culley <paulr2787@gmail.com>
* gramps/plugins/tool/findloop.py: Fix Find Database Loop Tool (bad
import of _collections) (#643) Fixes #10722
2018-09-03 niememat <niememat@gmail.com>
* po/fi.po: Fix translation in Finnish
2018-08-25 Bernard Banko <beernarrd@gmail.com>
* po/sl.po: Slovenian translation fixed to allow building mo
2018-08-25 Bernard Banko <beernarrd@gmail.com>
* po/sl.po: Slovenian translation updated
2018-08-18 niememat <niememat@gmail.com>
* po/fi.po: Fix translation in Finnish
2018-08-11 niememat <niememat@gmail.com>
* po/fi.po: Fix translation in Finnish
2018-08-09 John Ralls <jralls@ceridwen.us>
* mac/gramps.modules: Switch included moduleset to gitlab.gnome.org. Fixes bug #10733.
2018-08-08 Leonhaeuser <mirko@leonhaeuser.de>
* po/de.po: Reviewed German translation Thanks to bmendl
2018-08-08 niememat <niememat@gmail.com>
* po/fi.po: Fix translation in Finnish
2018-08-05 John Ralls <jralls@ceridwen.us>
* mac/gramps.bundle: File copy doesn't work if the glob can match
directories.
2018-08-04 John Ralls <jralls@ceridwen.us>
* mac/gramps.bundle: Install the docs/gramps directory in the
bundle. Fixes bug #10705.
2018-08-05 niememat <niememat@gmail.com>
* po/fi.po: Fix and updated translation in Finnish
2018-07-25 Ross Gammon <rossgammon@mail.dk>
* debian/changelog: Update the Debian changelog after the 5.0.0
release
2018-07-25 John Ralls <jralls@ceridwen.us>
* mac/Info.plist, mac/gramps.modules: Release Gramps-5.0.0 on Mac.
* setup.py: Update development status for new release
2018-07-24 Nick Hall <nick-h@gramps-project.org>
* gramps/gen/const.py, gramps/version.py: Bump to 5.0.1
* po/gramps.pot: Update translation template for new release
2018-07-22 niememat <niememat@gmail.com>
* po/fi.po: Fix translation in Finnish
2018-07-01 John Ralls <jralls@ceridwen.us>
* gramps/gui/clipboard.py,
gramps/gui/editors/displaytabs/buttontab.py,
gramps/gui/editors/displaytabs/surnametab.py,
gramps/gui/filters/_searchbar.py,
gramps/gui/filters/sidebar/_sidebarfilter.py, gramps/gui/utils.py,
gramps/gui/views/navigationview.py,
gramps/gui/widgets/grampletpane.py,
gramps/gui/widgets/interactivesearchbox.py,
gramps/gui/widgets/multitreeview.py,
gramps/gui/widgets/styledtexteditor.py: Correct binary test logic
for primary mask. state & get_primary_mask(another) tested (state & (primary |
other)), which will be true if state matches *either* primary *or*
other, but what is wanted in a not-negated test is state matching
all bits of (primary | other). match_primary_mask does that. On the other hand there are also cases of "not state & (primary |
other)". no_match_primary_mask handles that, returning true if
state matches none of the bits in (primary | other). Fixes #10646.
2018-06-21 prculley <paulr2787@gmail.com>
* gramps/gui/glade/baseselector.glade,
gramps/gui/selectors/baseselector.py: Fix BaseSelector to avoid long
delay before display on large trees Fixes #10634
2018-05-06 SNoiraud <serge.noiraud@laposte.net>
* gramps/gui/plug/export/_exportoptions.py: Export options > Gui
alignment issue Fixes #10576
2018-07-22 niememat <niememat@gmail.com>
* po/fi.po: New fix translation in Finnish
2018-07-22 Espen Berg <espenbe@gmail.com>
* po/nb.po: Revised Norwegian bokmål
2018-07-22 Espen Berg <espenbe@gmail.com>
* po/nb.po: Revised Norwegian bokmål
2018-07-22 niememat <niememat@gmail.com>
* po/fi.po: Fix translation in Finnish
2018-07-21 Nick Hall <nick-h@gramps-project.org>
* gramps/gui/glade/editplace.glade,
gramps/gui/glade/editplaceref.glade: Fix dialog button order on
non-Mac systems Resolves #10585.
2018-07-21 De Tran <trande@gmail.com>
* po/vi.po: Fix and update Vietnamese translation Resolves #10681.
2018-07-21 Sveinn í Felli <sv1@fellsnet.is>
* po/is.po: Update Icelandic translation
2018-05-10 jose1711 <jose1711@gmail.com>
* po/sk.po: Fix and update Slovak translation
2018-05-11 jose1711 <jose1711@gmail.com>
* gramps/plugins/rel/rel_cs.py: Fix typo in translation
2018-07-20 niememat <niememat@gmail.com>
* po/fi.po: Fix translation in Finnish
2018-07-20 niememat <niememat@gmail.com>
* po/fi.po: Fix translation in Finnish
2018-07-18 niememat <niememat@gmail.com>
* po/fi.po: Fix translation in Finnish
2018-07-15 Luigi Toscano <luigi.toscano@tiscali.it>
* po/it.po: Update Italian translation
2018-07-13 Nick Hall <nick-h@gramps-project.org>
* po/en_GB.po: Update English (British) translation
2018-07-13 De Tran <trande@gmail.com>
* po/vi.po: Update Vietnamese translation
2018-07-13 Kaj Mikkelsen <kmi@vgdata.dk>
* po/da.po: Update Danish translation
2018-07-13 Lajos Nemeséri <nemeseril@gmail.com>
* po/hu.po: Update Hungarian translation
2018-07-07 Fedik <getthesite@gmail.com>
* po/uk.po: Update Ukrainian translation for Gramps
2018-07-05 RossGammon <upstream@the-gammons.net>
* debian/changelog, debian/copyright,
debian/patches/hardcoded_path_person_rules_test.patch,
debian/patches/series: Update Debian directory after Gramps
5.0.0-rc1 release. (#634)
2018-07-02 Leonhaeuser <mirko@leonhaeuser.de>
* po/de.po: Fix not matching translation csv import/export
2018-07-02 Zdeněk Hataš <zdenek.hatas@gmail.com>
* po/cs.po: Update Czech translation
2018-07-02 Pier Luigi Cinquantini <plcinquantini@gmail.com>
* po/eo.po: Update Esperanto translation
2018-07-01 niememat <niememat@gmail.com>
* po/fi.po: Fix translation in Finnish
2018-06-30 Paulo Henrique Paiva de Moraes <paulohpmoraes@gmail.com>
* po/pt_BR.po: Update Brazilian Portuguese translation
2018-06-30 vantu5z <vantu5z@mail.ru>
* po/ru.po: update Russian translation substantially just merge with
latest template
2018-06-29 Nick Hall <nick-h@gramps-project.org>
* po/ar.po, po/bg.po, po/br.po, po/ca.po, po/cs.po, po/da.po,
po/de.po, po/el.po, po/en_GB.po, po/eo.po, po/es.po, po/fi.po,
po/fr.po, po/ga.po, po/he.po, po/hr.po, po/hu.po, po/is.po,
po/it.po, po/ja.po, po/lt.po, po/mk.po, po/nb.po, po/nl.po,
po/nn.po, po/pl.po, po/pt_BR.po, po/pt_PT.po, po/ro.po, po/sk.po,
po/sl.po, po/sq.po, po/sr.po, po/sr_Latn.po, po/sv.po, po/ta.po,
po/tr.po, po/uk.po, po/vi.po, po/zh_CN.po, po/zh_HK.po, po/zh_TW.po:
Merge translation files with the latest template
2018-06-21 Paul Culley <paulr2787@gmail.com>
* gramps/gui/filters/sidebar/_sidebarfilter.py: Fix Custom filter
update when created via sidebar (#630) Fixes #10620 Adding a filter via the sidebar editor originally only updated the
current view, other associated views did not see the new filter.
First noticed in People views. This causes the 'filters-changed' to
be emitted which updates all associated view.
2018-06-21 Paul Culley <paulr2787@gmail.com>
* gramps/gui/widgets/grampletpane.py: Fix Gramplet configure
(View/Configure) for large options (#629) When a Gramplet uses a BooleanListOption with a lot of entries,
along with other options, all the options take on the size of the
large BooleanListOption, which doesn't work well at all.
2018-06-22 Serge Noiraud <Serge.Noiraud@laposte.net>
* gramps/plugins/drawreport/statisticschart.py: Statistics Charts
crashes with IndexError (#627) Fixes #010626 In statistics charts, get_month is only localized and the calendar
is unused. If we have an Extra (Sansculottides) month in the french
republican calendar (index 13), we have this IndexError because the
gregorian calendar is always used and contains only 12 values.
2018-06-10 John Ralls <jralls@ceridwen.us>
* mac/gramps.accel: [Mac] Change accel for Undo History. So that it doesn't conflict with a system binding for hiding the
window. Fixes #10619.
2018-06-09 Paul Culley <paulr2787@gmail.com>
* gramps/gui/plug/_guioptions.py: Fix Family Lines/Family Colors
picker for bad transient parent (#625) Fixes #10623
2018-06-09 Paul Culley <paulr2787@gmail.com>
* gramps/gen/db/utils.py: Fix import_as_dict to utilize user
gramps_id prefixes (#626) Issue #10622 Found when comparing dbs with large prefixes 'I%05d'; using database
differences or import_merge addons.
2018-06-09 Paul Culley <paulr2787@gmail.com>
* gramps/plugins/db/bsddb/write.py: Fix error when opening bsddb db
in read-only mode (#624) Fixes #10615 BSDDB had errors when trying to open in read-only mode.
2018-06-09 Paul Culley <paulr2787@gmail.com>
* gramps/gen/db/generic.py: Fix dbapi dbs for closeing read-only db
crash (#623) Fixes #10613 The sqlite (and other dbapi dbs) tried to save their metadata on a
close operation, which doesn't work for read-only dbs.
2018-06-09 Paul Culley <paulr2787@gmail.com>
* gramps/gui/viewmanager.py: Fix menus when operating with read-only
db (#622) Fixes #10614 An earlier attempt to deal with closed dbs messed up the read-only
ActionGroup settings. This corrects that situation.
2018-06-02 Sam Manzi <manzi.sam@gmail.com>
* gramps/gen/proxy/living.py: Fix Name formats to show all parts
(#608) Fixes #10420 Allows reports to use the name format specified by the user.
2018-06-01 Paul Culley <paulr2787@gmail.com>
* gramps/gui/dbloader.py, gramps/gui/plug/_guioptions.py,
gramps/gui/viewmanager.py: Fix dialogs for crash when canceling via
'x' (#620) * Fix import dialog for crash when canceling via 'x' Fixes #10607 * Fix 'Make Backup' dialog for crash on 'x' close Issue #10607 * Fix Family Lines/Family Colors/add dialog crash on close with 'x' Issue #10607
2018-05-28 niememat <niememat@gmail.com>
* po/fi.po: Fix translation in Finnish
2018-05-20 John Ralls <jralls@ceridwen.us>
* mac/Info.plist, mac/gramps.modules: Release 5.0.0-rc1 on Mac.
2018-05-20 John Ralls <jralls@ceridwen.us>
* mac/gramps.modules: Remove obsolete omeat-python-modules
dependencies.
2018-05-20 prculley <paulr2787@gmail.com>
* Bump to v5.0.0-rc2
+1 -3
View File
@@ -1,5 +1,5 @@
include ChangeLog
include AUTHORS
include ChangeLog
include COPYING
include FAQ
include Gramps.py
@@ -10,11 +10,9 @@ include RELEASE_NOTES
include TODO
include CONTRIBUTING
include TestPlan.txt
recursive-include bash *
recursive-include data *
recursive-include debian *
recursive-include docs *
recursive-include example *
recursive-include gramps *
recursive-include help *
recursive-include images *
+8 -1675
View File
File diff suppressed because it is too large Load Diff
+13 -1
View File
@@ -11,7 +11,7 @@ Requirements
The following packages **MUST** be installed in order for Gramps to work:
* **Python** 3.2 or greater - The programming language used by Gramps. https://www.python.org/
* **GTK** 3.10 or greater - A cross-platform widget toolkit for creating graphical user interfaces. http://www.gtk.org/
* **GTK** 3.12 or greater - A cross-platform widget toolkit for creating graphical user interfaces. http://www.gtk.org/
* **pygobject** 3.12 or greater - Python Bindings for GLib/GObject/GIO/GTK+ https://wiki.gnome.org/Projects/PyGObject
The following three packages with GObject Introspection bindings (the gi packages)
@@ -103,6 +103,18 @@ The following packages are optional:
More font support in the reports
* **geocodeglib**
A library use to associate a geographical position (latitude, longitude)
to a place name. This is used if you already have osmgpsmap installed.
If installed, when you add or link a place from the map, you have a red line
at the end of the table for selection.
Debian, Ubuntu, ... : gir1.2-geocodeglib-1.0
Fedora, Redhat, ... : geocode-glib
openSUSE : geocode-glib
ArchLinux : geocode-glib
...
Optional packages required by Third-party Addons
------------------------------------------------
+2 -2
View File
@@ -109,7 +109,6 @@ p#description {
a {
color: black;
text-decoration: none;
word-wrap: break-word;
}
a[href]:hover, a[href]:active {
text-decoration: underline;
@@ -451,7 +450,8 @@ div#families table.attrlist td.ColumnType {
----------------------------------------------------- */
#indivgallery .thumbnail {
float: left;
width: 130px;
max-width: 130px;
max-height: 150px;
font-size: smaller;
text-align: center;
margin: 0.8em 0.5em;
+1 -1
View File
@@ -1093,6 +1093,7 @@ div.Residence table.infolist tr td {
margin: 0;
float: left;
width: 130px;
height: 150px;
text-align: center;
}
#indivgallery div.thumbnail a {
@@ -1101,7 +1102,6 @@ div.Residence table.infolist tr td {
padding: 0;
text-decoration: none;
cursor: pointer;
word-wrap: break-word;
}
#indivgallery div.thumbnail a img {
padding: 0;
+2 -2
View File
@@ -109,7 +109,6 @@ p#description {
a {
color: black;
text-decoration: none;
word-wrap: break-word;
}
a[href]:hover, a[href]:active {
background-color: #9DBF9D;
@@ -501,7 +500,8 @@ div#families table.attrlist td.ColumnType {
----------------------------------------------------- */
#indivgallery .thumbnail {
float: left;
width: 130px;
max-width: 130px;
max-height: 150px;
font-size: smaller;
text-align: center;
margin: 0.8em 0.5em;
+2 -2
View File
@@ -110,7 +110,6 @@ p#description {
a {
color: black;
text-decoration: none;
word-wrap: break-word;
}
a[href]:hover, a[href]:active {
background-color: #E0E0E9
@@ -494,7 +493,8 @@ div#families table.attrlist td.ColumnType {
----------------------------------------------------- */
#indivgallery .thumbnail {
float: left;
width: 130px;
max-width: 130px;
max-height: 150px;
font-size: smaller;
text-align: center;
margin: 0.8em 0.5em;
+2 -2
View File
@@ -110,7 +110,6 @@ p#description {
a {
color: #36220B;
text-decoration: none;
word-wrap: break-word;
}
a[href]:hover, a[href]:active {
background-color: #FFE09F
@@ -494,7 +493,8 @@ div#families table.attrlist td.ColumnType {
----------------------------------------------------- */
#indivgallery .thumbnail {
float: left;
width: 130px;
max-width: 130px;
max-height: 150px;
font-size: smaller;
text-align: center;
margin: 0.8em 0.5em;
+2 -2
View File
@@ -110,7 +110,6 @@ p#description {
a {
color: black;
text-decoration: none;
word-wrap: break-word;
}
a[href]:hover, a[href]:active {
background-color: #EAEEF4
@@ -494,7 +493,8 @@ div#families table.attrlist td.ColumnType {
----------------------------------------------------- */
#indivgallery .thumbnail {
float: left;
width: 130px;
max-width: 130px;
max-height: 150px;
font-size: smaller;
text-align: center;
margin: 0.8em 0.5em;
+3 -2
View File
@@ -119,7 +119,6 @@ h4 {
a {
color: #7D5925;
text-decoration: none;
word-wrap: break-word;
}
a[href]:hover, a[href]:active {
background-color: #FFFFE7;
@@ -437,7 +436,8 @@ div#families table.fixed_subtables table.eventlist th:last-child {
}
#indivgallery .thumbnail {
float: left;
width: 130px;
max-width: 130px;
max-height: 150px;
font-size: smaller;
text-align: center;
margin: 0.5em;
@@ -533,6 +533,7 @@ div#map_canvas {
table.calendar {
table-layout: fixed;
empty-cells: show;
width: 950px;
margin: 0px auto;
background: url(../images/Web_Mainz_Mid.png) #FFF2C6 repeat;
}
+3 -3
View File
@@ -736,7 +736,7 @@ table.download {
width:100%;
}
table.download img {
float:none;
float:center;
}
table.download thead tr th {
text-align:center;
@@ -933,6 +933,7 @@ div#Addresses table.infolist tr td a, div#Addresses table.infolist tr td p a {
margin:0;
float:left;
width:130px;
height:150px;
text-align:center;
}
#indivgallery .thumbnail a {
@@ -940,7 +941,6 @@ div#Addresses table.infolist tr td a, div#Addresses table.infolist tr td p a {
margin:0;
padding:0;
background:none;
word-wrap: break-word;
}
#indivgallery .thumbnail a img {
margin:0;
@@ -1097,7 +1097,7 @@ div#pedigree {
margin-right: 10px;
}
#footer p#copyright img {
margin-right: 10px;
margin-right: 10px[
}
#user_footer {
width: 70%;
+722 -501
View File
File diff suppressed because it is too large Load Diff
+9 -13
View File
@@ -1,12 +1,12 @@
0 HEAD
1 SOUR Gramps
2 VERS 5.0.1
2 VERS 5.0.0-alpha2
2 NAME Gramps
1 DATE 7 NOV 2018
2 TIME 16:03:33
1 DATE 1 SEP 2017
2 TIME 12:10:38
1 SUBM @SUBM@
1 FILE C:\Users\prc\AppData\Roaming\gramps\temp\exp_sample_ged.ged
1 COPR Copyright (c) 2018 Alex Roitman,,,.
1 COPR Copyright (c) 2017 Alex Roitman,,,.
1 GEDC
2 VERS 5.5.1
2 FORM LINEAGE-LINKED
@@ -786,7 +786,11 @@
3 ADOP BOTH
1 FAMC @F0005@
2 PEDI adopted
1 OBJE @O0000@
1 OBJE
2 FORM jpeg
2 TITL Michael O'Toole 2015-11
2 FILE c:\grampsaio64-5.0.0\share\gramps\tests\O0.jpg
2 NOTE @N0019@
1 NOTE @N0007@
1 CHAN
2 DATE 18 JUN 2016
@@ -1419,12 +1423,4 @@
0 @N0017@ NOTE A citation Note Source text
0 @N0018@ NOTE Another Citation Note
0 @N0019@ NOTE A bad photo for sure
0 @O0000@ OBJE
1 FILE c:\users\prc\workspace\grampsm\main\data\tests\O0.jpg
2 FORM jpeg
2 TITL Michael O'Toole 2015-11
1 NOTE @N0019@
1 CHAN
2 DATE 29 OCT 2016
3 TIME 15:23:37
0 TRLR
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -57,7 +57,7 @@
<_tip number="29"><b>Show All Checkbutton</b><br/>When adding an existing person as a spouse, the list of people shown is filtered to display only people who could realistically fit the role (based on dates in the database). In case Gramps is wrong in making this choice, you can override the filter by checking the Show All checkbutton.</_tip>
<_tip number="31"><b>Improving Gramps</b><br/>Users are encouraged to request enhancements to Gramps. Requesting an enhancement can be done either through the gramps-users or gramps-devel mailing lists, or by going to https://gramps-project.org/bugs/ and creating a Feature Request. Filing a Feature Request is preferred but it can be good to discuss your ideas on the email lists.</_tip>
<_tip number="31"><b>Improving Gramps</b><br/>Users are encouraged to request enhancements to Gramps. Requesting an enhancement can be done either through the gramps-users or gramps-devel mailing lists, or by going to http://bugs.gramps-project.org and creating a Feature Request. Filing a Feature Request is preferred but it can be good to discuss your ideas on the email lists.</_tip>
<_tip number="32"><b>Gramps Mailing Lists</b><br/>Want answers to your questions about Gramps? Check out the gramps-users email list. Many helpful people are on the list, so you're likely to get an answer quickly. If you have questions related to the development of Gramps, try the gramps-devel list. You can see the lists by selecting &quot;Help &gt; Gramps Mailing Lists&quot;.</_tip>
@@ -91,7 +91,7 @@
<_tip number="49"><b>Making a Genealogy Website</b><br/>You can easily export your family tree to a web page. Select the entire database, family lines or selected individuals to a collection of web pages ready for upload to the World Wide Web.</_tip>
<_tip number="50"><b>Reporting Bugs in Gramps</b><br/>The best way to report a bug in Gramps is to use the Gramps bug tracking system at https://gramps-project.org/bugs/</_tip>
<_tip number="50"><b>Reporting Bugs in Gramps</b><br/>The best way to report a bug in Gramps is to use the Gramps bug tracking system at http://bugs.gramps-project.org</_tip>
<_tip number="51"><b>The Gramps Homepage</b><br/>The Gramps homepage is at http://gramps-project.org/</_tip>
+38 -13
View File
@@ -3,7 +3,7 @@
"http://gramps-project.org/xml/1.7.1/grampsxml.dtd">
<database xmlns="http://gramps-project.org/xml/1.7.1/">
<header>
<created date="2018-03-08" version="5.0.0"/>
<created date="2017-08-08" version="5.1.0"/>
<researcher>
<resname>Alex Roitman,,,</resname>
</researcher>
@@ -951,7 +951,7 @@
<place hlink="_L3WJQCD3US67V2CNZT"/>
<description>Birth of Garner, Anderson</description>
</event>
<event handle="_a5af0eb7dfb557da07e" change="1284030599" id="E0179">
<event handle="_a5af0eb7dfb557da07e" change="1502187535" id="E0179">
<type>Death</type>
<dateval val="1887-04-07"/>
<place hlink="_AKFKQC2N4SM243HCTN"/>
@@ -6262,7 +6262,7 @@
<dateval val="1842-06-28"/>
<description>Death of Moreno, Joseph McDowell</description>
</event>
<event handle="_a5af0ec45b25c630e03" change="1284030608" id="E1179">
<event handle="_a5af0ec45b25c630e03" change="1502187451" id="E1179">
<type>Birth</type>
<dateval val="1911-07-12"/>
<description>Birth of Thornton, James Arthur</description>
@@ -15003,7 +15003,7 @@
<type>Marriage</type>
<description>Marriage of Johnson, Henry and Sparks, Catherine</description>
</event>
<event handle="_a5af0ed5df832ee65c1" change="1328026859" id="E2815">
<event handle="_a5af0ed5df832ee65c1" change="1502187371" id="E2815">
<type>Marriage</type>
<dateval val="1875-04-01"/>
<place hlink="_RF5KQCNJRQY8OGTX2H"/>
@@ -18649,7 +18649,7 @@
<parentin hlink="_F4CKQCJZ24JRE9Z889"/>
<citationref hlink="_c140d2472c91aad494f"/>
</person>
<person handle="_14LKQCYZJEAXTS3XX" change="1185438865" id="I1376">
<person handle="_14LKQCYZJEAXTS3XX" change="1502187492" id="I1376">
<gender>F</gender>
<name type="Birth Name">
<first>Elizabeth</first>
@@ -18657,6 +18657,7 @@
</name>
<eventref hlink="_a5af0ebb003796f79a0" role="Primary"/>
<eventref hlink="_a5af0ebb0143dab99ff" role="Primary"/>
<eventref hlink="_a5af0eb7dfb557da07e" role="Witness"/>
<childof hlink="_5IUJQCRJY47YQ8PU7N"/>
<parentin hlink="_I4LKQCOAGPFH4R90A7"/>
<citationref hlink="_c140d24731407d57b3c"/>
@@ -19904,7 +19905,7 @@
<childof hlink="_IO5KQC6H0Q6Y517LR9"/>
<citationref hlink="_c140d24a1fd2319b703"/>
</person>
<person handle="_35WJQC1B7T7NPV8OLV" change="1284030051" id="I0106">
<person handle="_35WJQC1B7T7NPV8OLV" change="1502187260" id="I0106">
<gender>M</gender>
<name type="Birth Name">
<first>Robert W.</first>
@@ -19913,6 +19914,11 @@
<eventref hlink="_a5af0eb74ac73f86aa7" role="Primary"/>
<eventref hlink="_a5af0eb74ba358391ae" role="Primary"/>
<eventref hlink="_a5af0eb74c852f7c633" role="Primary"/>
<eventref hlink="_a5af0ed5df832ee65c1" role="Witness">
<attribute type="Age" value="23">
<citationref hlink="_c140dafeb317af2fd79"/>
</attribute>
</eventref>
<childof hlink="_X3WJQCSF48F6809142"/>
<parentin hlink="_8OUJQCUVZ0XML7BQLF"/>
<citationref hlink="_c140d24a27e19bb381a"/>
@@ -21991,13 +21997,14 @@
<childof hlink="_GCDKQCHI74ZPMI5GDJ"/>
<citationref hlink="_c140d24f3f8704aa41b"/>
</person>
<person handle="_6G0KQC2UXYC66XDDC2" change="1185438865" id="I0363">
<person handle="_6G0KQC2UXYC66XDDC2" change="1502187537" id="I0363">
<gender>F</gender>
<name type="Birth Name">
<first>Miranda Keziah</first>
<surname>Farmer</surname>
</name>
<eventref hlink="_a5af0ec7a76244d962d" role="Primary"/>
<eventref hlink="_a5af0eb7dfb557da07e" role="Witness"/>
<childof hlink="_8NVJQCGMJTCL7E6ZDV"/>
<citationref hlink="_c140d24f439709d3118"/>
</person>
@@ -22989,7 +22996,7 @@
<parentin hlink="_FBVJQCFBI50TW78O49"/>
<citationref hlink="_c140d2522702664ec52"/>
</person>
<person handle="_8CLKQCT97PJOGREJ7W" change="1185438865" id="I1387">
<person handle="_8CLKQCT97PJOGREJ7W" change="1502187387" id="I1387">
<gender>M</gender>
<name type="Birth Name">
<first>Robert</first>
@@ -22997,6 +23004,11 @@
</name>
<eventref hlink="_a5af0ebb3737a6ad088" role="Primary"/>
<eventref hlink="_a5af0ebb39b441e9607" role="Primary"/>
<eventref hlink="_a5af0ed5df832ee65c1" role="Clergy">
<attribute type="Age" value="23">
<citationref hlink="_c140dafeb317af2fd79"/>
</attribute>
</eventref>
<childof hlink="_5IUJQCRJY47YQ8PU7N"/>
<parentin hlink="_H6LKQCWVIFNRNGHFVH"/>
<citationref hlink="_c140d2522d804491375"/>
@@ -23803,7 +23815,7 @@
<childof hlink="_5DBKQCVAB0XMBEW8R9"/>
<citationref hlink="_c140d25425874b0b827"/>
</person>
<person handle="_9HUJQC6ONNW8SMSKGQ" change="1185438865" id="I0038">
<person handle="_9HUJQC6ONNW8SMSKGQ" change="1502187526" id="I0038">
<gender>M</gender>
<name type="Birth Name">
<first>David</first>
@@ -23812,6 +23824,7 @@
<eventref hlink="_a5af0ec7eb514c52fbf" role="Primary"/>
<eventref hlink="_a5af0ec7ec844213b55" role="Primary"/>
<eventref hlink="_a5af0ec7ed61c743fc8" role="Primary"/>
<eventref hlink="_a5af0eb7dfb557da07e" role="Informant"/>
<childof hlink="_5IUJQCRJY47YQ8PU7N"/>
<parentin hlink="_3HUJQCK4DH582YUTZG"/>
<citationref hlink="_c140d2542c764516f13"/>
@@ -24506,7 +24519,7 @@
<parentin hlink="_8NVJQCGMJTCL7E6ZDV"/>
<citationref hlink="_c140d2560004fad8df6"/>
</person>
<person handle="_ANLKQCQSQNE5LDZMRC" change="1185438865" id="I1402">
<person handle="_ANLKQCQSQNE5LDZMRC" change="1502187434" id="I1402">
<gender>F</gender>
<name type="Birth Name">
<first>Margaret Jane &quot;Maggie&quot;</first>
@@ -24514,6 +24527,7 @@
</name>
<eventref hlink="_a5af0ebb7d47a006ee2" role="Primary"/>
<eventref hlink="_a5af0ebb7e54e14970f" role="Primary"/>
<eventref hlink="_a5af0ec45b25c630e03" role="Witness"/>
<childof hlink="_VDLKQCQQ1ADTJG1D1F"/>
<parentin hlink="_SNLKQCD0VNJ627062Y"/>
<citationref hlink="_c140d25607213be35da"/>
@@ -24882,13 +24896,18 @@
<parentin hlink="_JFYJQCG2KLRQN835JD"/>
<citationref hlink="_c140d256e3403ba129d"/>
</person>
<person handle="_B3BKQCSV0G3NKSKWDX" change="1185438865" id="I0880">
<person handle="_B3BKQCSV0G3NKSKWDX" change="1502187344" id="I0880">
<gender>F</gender>
<name type="Birth Name">
<first>L. J.</first>
<surname>Blanco</surname>
</name>
<eventref hlink="_a5af0ed2cf617169903" role="Primary"/>
<eventref hlink="_a5af0ed5df832ee65c1" role="Clergy">
<attribute type="Age" value="23">
<citationref hlink="_c140dafeb317af2fd79"/>
</attribute>
</eventref>
<childof hlink="_1BVJQCNTFAGS8273LJ"/>
<citationref hlink="_c140d256ec4306a51ca"/>
</person>
@@ -31930,7 +31949,7 @@
<childof hlink="_UDMKQC5D3A2PXPUGNC"/>
<citationref hlink="_c140d266ec93334f40f"/>
</person>
<person handle="_MG5KQC6ZKSVO4A63G2" change="1328026883" id="I0624">
<person handle="_MG5KQC6ZKSVO4A63G2" change="1502187451" id="I0624">
<gender>M</gender>
<name type="Birth Name">
<first>Raymond E.</first>
@@ -31938,6 +31957,7 @@
</name>
<eventref hlink="_a5af0ece8bd1125a1a9" role="Primary"/>
<eventref hlink="_a5af0ece8d15511ddf9" role="Primary"/>
<eventref hlink="_a5af0ec45b25c630e03" role="Informant"/>
<childof hlink="_9OUJQCBOHW9UEK9CNV"/>
<citationref hlink="_c140d266f0d5d178784"/>
</person>
@@ -32336,7 +32356,7 @@
<parentin hlink="_F4CKQCJZ24JRE9Z889"/>
<citationref hlink="_c140d267ccb7aef0cd0"/>
</person>
<person handle="_N4DKQCPEMZ7OO62O7J" change="1185438865" id="I0975">
<person handle="_N4DKQCPEMZ7OO62O7J" change="1502187308" id="I0975">
<gender>M</gender>
<name type="Birth Name">
<first>Henry</first>
@@ -32345,6 +32365,11 @@
<eventref hlink="_a5af0ed483738d4ed1e" role="Primary"/>
<eventref hlink="_a5af0ed484a144d229b" role="Primary"/>
<eventref hlink="_a5af0ed48605fb6b9eb" role="Primary"/>
<eventref hlink="_a5af0ed5df832ee65c1" role="Witness">
<attribute type="Age" value="23">
<citationref hlink="_c140dafeb317af2fd79"/>
</attribute>
</eventref>
<parentin hlink="_7PUJQC4PPS4EDIVMYE"/>
<citationref hlink="_c140d267d2128356d8e"/>
</person>
+1 -1
View File
@@ -382,7 +382,7 @@ class ArgHandler:
self.open = db_path
self.__open_action()
else:
sys.exit(_("Error: cannot open '%s'") % self.open_gui)
sys.exit(1)
return db_path
# if not open_gui, parse any command line args. We can only have one
+7 -3
View File
@@ -155,7 +155,7 @@ register('behavior.translator-needed', True)
register('behavior.use-tips', False)
register('behavior.welcome', 100)
register('behavior.web-search-url', 'http://google.com/#&q=%(text)s')
register('behavior.addons-url', "https://raw.githubusercontent.com/gramps-project/addons/master/gramps50")
register('behavior.addons-url', "https://raw.githubusercontent.com/gramps-project/addons/master/gramps51")
register('database.backend', 'bsddb')
register('database.compress-backup', True)
@@ -196,6 +196,7 @@ register('interface.view-categories',
register('interface.filter', False)
register('interface.fullscreen', False)
register('interface.grampletbar-close', False)
register('interface.grampletbar-refresh', False)
register('interface.ignore-gexiv2', False)
register('interface.ignore-pil', False)
register('interface.ignore-osmgpsmap', False)
@@ -217,17 +218,20 @@ register('interface.sidebar-text', True)
register('interface.size-checked', False)
register('interface.statusbar', 1)
register('interface.toolbar-on', True)
register('interface.toolbar-text', False)
register('interface.view', True)
register('interface.surname-box-height', 150)
register('interface.treemodel-cache-size', 1000)
register('paths.recent-export-dir', USER_HOME)
register('paths.recent-export-dir', '')
register('paths.recent-file', '')
register('paths.recent-import-dir', USER_HOME)
register('paths.recent-import-dir', '')
register('paths.report-directory', USER_HOME)
register('paths.website-directory', USER_HOME)
register('paths.website-cms-uri', '')
register('paths.website-cal-uri', '')
register('paths.website-extra-page-uri', '')
register('paths.website-extra-page-name', '')
register('paths.quick-backup-directory', USER_HOME)
register('paths.quick-backup-filename',
"%(filename)s_%(year)d-%(month)02d-%(day)02d.%(extension)s")
+2 -1
View File
@@ -138,7 +138,8 @@ sys.path.insert(0, ROOT_DIR)
git_revision = get_git_revision(ROOT_DIR).replace('\n', '')
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"
#
# Glade files
+11 -10
View File
@@ -22,7 +22,6 @@
#
# Croatian version 2008 by Josip
# Croatian version 2018 by Milo
"""
Croatian-specific classes for parsing and displaying dates.
@@ -52,15 +51,13 @@ from ._datehandler import register_datehandler
#-------------------------------------------------------------------------
class DateParserHR(DateParser):
modifier_to_int = {
'prije' : Date.MOD_BEFORE,
'prije' : Date.MOD_BEFORE,
'pr. ' : Date.MOD_BEFORE,
'poslije' : Date.MOD_AFTER,
'po. ' : Date.MOD_AFTER,
'nakon' : Date.MOD_AFTER,
'na. ' : Date.MOD_AFTER,
'oko' : Date.MOD_ABOUT,
'okolo' : Date.MOD_ABOUT,
'ok. ' : Date.MOD_ABOUT,
'poslije' : Date.MOD_AFTER,
'po. ' : Date.MOD_AFTER,
'okolo' : Date.MOD_ABOUT,
'ok. ' : Date.MOD_ABOUT,
}
quality_to_int = {
@@ -78,6 +75,10 @@ class DateParserHR(DateParser):
compiles regular expression strings for matching dates
"""
DateParser.init_strings(self)
#~ DateParser.calendar_to_int.update({
#~ 'персидский' : Date.CAL_PERSIAN,
#~ 'п' : Date.CAL_PERSIAN,
#~ })
# match 'Day. MONTH year.' format with or without dots
self._text2 = re.compile(r'(\d+)?\.?\s*?%s\.?\s*((\d+)(/\d+)?)?\s*\.?$'
@@ -146,5 +147,5 @@ class DateDisplayHR(DateDisplay):
#
#-------------------------------------------------------------------------
register_datehandler(
('hr_HR', 'hr', 'HR', 'croatian', 'Croatian', 'hrvatski', ('%d. %m. %Y.',)),
('hr_HR', 'hr', 'HR', 'croatian', 'Croatian', 'hrvatski', ('%d.%m.%Y.',)),
DateParserHR, DateDisplayHR)
-10
View File
@@ -132,11 +132,6 @@ class DateDisplayRU(DateDisplay):
inflect, long_months)
elif date_val[1] == 0: # month is zero but day is not (see 8477)
return self.display_iso(date_val)
elif not hasattr(long_months[date_val[1]], 'f'): # not a Lexeme
return "{day:d} {long_month} {year}".format(
day = date_val[0],
long_month = long_months[date_val[1]],
year = year)
else:
return "{day:d} {long_month.f[Р]} {year}".format(
day = date_val[0],
@@ -156,11 +151,6 @@ class DateDisplayRU(DateDisplay):
inflect, short_months)
elif date_val[1] == 0: # month is zero but day is not (see 8477)
return self.display_iso(date_val)
elif not hasattr(short_months[date_val[1]], 'f'): # not a Lexeme
return "{day:d} {short_month} {year}".format(
day = date_val[0],
short_month = short_months[date_val[1]],
year = year)
else:
return "{day:d} {short_month.f[Р]} {year}".format(
day = date_val[0],
+2 -1
View File
@@ -216,8 +216,9 @@ class DummyDb(M_A_M_B("NewBaseClass", (DbReadBase, Callback, object,), {})):
"""
Create a new DummyDb instance.
"""
DbReadBase.__init__(self)
Callback.__init__(self)
self.basedb = None
self.__feature = {} # {"feature": VALUE, ...}
self.db_is_open = False
self.readonly = True
self.name_formats = []
-1
View File
@@ -2461,5 +2461,4 @@ class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback):
enclosed_by = ""
for placeref in place.get_placeref_list():
enclosed_by = placeref.ref
break
return enclosed_by
-3
View File
@@ -62,9 +62,6 @@ class FilterParser(handler.ContentHandler):
self.namespace = attrs['type']
else:
self.namespace = "generic"
if self.namespace == 'MediaObject':
# deals with older custom filters
self.namespace = 'Media'
elif tag == "filter":
self.f = GenericFilterFactory(self.namespace)()
self.f.set_name(attrs['name'])
+1 -7
View File
@@ -28,11 +28,9 @@ Base class for filter rules.
# Standard Python modules
#
#-------------------------------------------------------------------------
import re
from ...errors import FilterError
from ...const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
import re
#-------------------------------------------------------------------------
#
@@ -90,10 +88,6 @@ class Rule:
self.match_substring = self.match_regex
self.prepare(db, user)
self.nrprepare += 1
if self.nrprepare > 20: # more references to a filter than expected
raise FilterError(_("The filter definition contains a loop."),
_("One rule references another which eventually"
" references the first."))
def prepare(self, db, user):
"""prepare so the rule can be executed efficiently"""
@@ -72,15 +72,18 @@ class IsDuplicatedAncestorOf(Rule):
f_id = fam.get_father_handle()
m_id = fam.get_mother_handle()
if m_id:
self.go_deeper(db, db.get_person_from_handle(m_id))
self.mother_side(db, db.get_person_from_handle(m_id))
if f_id:
self.go_deeper(db, db.get_person_from_handle(f_id))
self.father_side(db, db.get_person_from_handle(f_id))
def go_deeper(self, db, person):
def mother_side(self, db, person):
if person and person.handle in self.map:
self.map2.add((person.handle))
self.map.add((person.handle))
self.init_ancestor_list(db, person)
def father_side(self, db, person):
if person and person.handle in self.map:
self.map2.add((person.handle))
# the following keeps from scanning same parts of tree multiple
# times and avoids crash on tree loops.
return
self.map.add((person.handle))
self.init_ancestor_list(db, person)
+6 -2
View File
@@ -34,6 +34,7 @@ LOG = logging.getLogger(".Gramplets")
#
#------------------------------------------------------------------------
from ..const import GRAMPS_LOCALE as glocale
from gramps.gen.config import config
_ = glocale.translation.gettext
class Gramplet:
@@ -296,12 +297,15 @@ class Gramplet:
not self.gui.force_update):
self.dirty = True
if self.dbstate.is_open():
#print " %s is not active" % self.gui.gname
#print(" %s is not active" % self.gui.gname)
self.update_has_data()
else:
self.set_has_data(False)
return
#print " %s is UPDATING" % self.gui.gname
#print(" %s is UPDATING" % self.gui.gname)
if (config.get('interface.grampletbar-refresh') and
self.gui.view.navigation_type() != None): # dashboard has no navtype
return # Don't update the gramplet if we are in manual refresh
self.dirty = False
LOG.debug("gramplet updater: %s: running" % self.gui.title)
if self._idle_id != 0:
+2 -2
View File
@@ -206,7 +206,7 @@ class DocBackend:
if not self.STYLETYPE_MAP or \
self.CLASSMAP != tagtype.__class__.__name__ :
self.CLASSMAP = tagtype.__class__.__name__
self.CLASSMAP == tagtype.__class__.__name__
self.STYLETYPE_MAP[tagtype.BOLD] = self.BOLD
self.STYLETYPE_MAP[tagtype.ITALIC] = self.ITALIC
self.STYLETYPE_MAP[tagtype.UNDERLINE] = self.UNDERLINE
@@ -217,7 +217,7 @@ class DocBackend:
self.STYLETYPE_MAP[tagtype.SUPERSCRIPT] = self.SUPERSCRIPT
self.STYLETYPE_MAP[tagtype.LINK] = self.LINK
if s_tag.name == tagtype.LINK:
if s_tag.name == 'Link':
return self.format_link(s_tag.value)
typeval = int(s_tag.name)
s_tagvalue = s_tag.value
+14
View File
@@ -8,6 +8,7 @@
# Copyright (C) 2007 Brian G. Matherly
# Copyright (C) 2009 Benny Malengier
# Copyright (C) 2009 Gary Burton
# Copyright (C) 2017 Jonathan Biegert <azrdev@qrdn.de>
# Copyright (C) 2017 Mindaugas Baranauskas
# Copyright (C) 2017 Paul Culley
#
@@ -72,6 +73,11 @@ _RANKDIR = [{'name' : _("Vertical (↓)"), 'value' : "TB"},
{'name' : _("Horizontal (→)"), 'value' : "LR"},
{'name' : _("Horizontal (←)"), 'value' : "RL"}]
_NODE_PORTS = {"TB" : ("n", "s"),
"BT" : ("s", "n"),
"LR" : ("w", "e"),
"RL" : ("e", "w")}
_PAGEDIR = [{'name' : _("Bottom, left"), 'value' : "BL"},
{'name' : _("Bottom, right"), 'value' : "BR"},
{'name' : _("Top, left"), 'value' : "TL"},
@@ -183,6 +189,10 @@ class GVOptions:
spline.set_help(_("How the lines between objects will be drawn."))
menu.add_option(category, "spline", spline)
node_ports = BooleanOption(_("Alternate line attachment"), False)
node_ports.set_help(_("Whether lines attach to nodes differently"))
menu.add_option(category, "node_ports", node_ports)
# the page direction option only makes sense when the
# number of horizontal and/or vertical pages is > 1,
# so we need to remember these 3 controls for later
@@ -409,6 +419,7 @@ class GVDocBase(BaseDoc, GVDoc):
self.vpages = get_option('v_pages').get_value()
self.usesubgraphs = get_option('usesubgraphs').get_value()
self.spline = get_option('spline').get_value()
self.node_ports = get_option('node_ports').get_value()
paper_size = paper_style.get_size()
@@ -456,6 +467,9 @@ class GVDocBase(BaseDoc, GVDoc):
' splines="%s";\n' % self.spline +
'\n' +
' edge [len=0.5 style=solid fontsize=%d];\n' % self.fontsize)
if self.node_ports:
self.write(' edge [headport=%s tailport=%s];\n'
% _NODE_PORTS[self.rankdir])
if self.fontfamily:
self.write(' node [style=filled fontname="%s" fontsize=%d];\n'
+3 -4
View File
@@ -427,10 +427,9 @@ class ReferencedBySelectionProxyDb(ProxyDbBase):
def process_lds_ord(self, lds_ord):
""" Find all of the primary objects referred to """
fam_handle = lds_ord.get_family_handle()
if fam_handle:
fam = self.db.get_family_from_handle(fam_handle)
if fam:
self.queue_object("Family", fam_handle)
fam = self.db.get_family_from_handle(fam_handle)
if fam:
self.queue_object("Family", fam_handle)
place_handle = lds_ord.get_place_handle()
if place_handle:
+1 -2
View File
@@ -787,8 +787,7 @@ class SimpleAccess:
with self.dbase.get_person_cursor() as cursor:
# data[3] is primary_name; data[3][5][0][0] is surname
slist = sorted((data[3][5][0][0] if data[3][5] else '', key)
for key, data in cursor)
slist = sorted((data[3][5][0][0], key) for key, data in cursor)
for info in slist:
obj = self.dbase.get_person_from_handle(info[1])
+2 -2
View File
@@ -459,12 +459,12 @@ def run():
if argpars.need_gui():
LOG.debug("A GUI is needed, set it up")
try:
from .gui.grampsgui import startgtkloop
from .gui.grampsgui import startgramps
# no DISPLAY is a RuntimeError in an older pygtk (e.g. F14's 2.17)
except RuntimeError as msg:
error += [(_("Configuration error:"), str(msg))]
return error
startgtkloop(error, argpars)
startgramps(error, argpars)
else:
# CLI use of Gramps
argpars.print_help()
-45
View File
@@ -1,45 +0,0 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2015 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.
#
"""
A replacement ActionGroup that correctly loads named icons from an icon theme.
"""
from gi.repository import Gtk
class ActionGroup(Gtk.ActionGroup):
def add_actions(self, action_list, **kwargs):
Gtk.ActionGroup.add_actions(self, action_list, **kwargs)
self.fix_icon_name(action_list)
def add_toggle_actions(self, action_list, **kwargs):
Gtk.ActionGroup.add_toggle_actions(self, action_list, **kwargs)
self.fix_icon_name(action_list)
def add_radio_actions(self, action_list, **kwargs):
Gtk.ActionGroup.add_radio_actions(self, action_list, **kwargs)
self.fix_icon_name(action_list)
def fix_icon_name(self, action_list):
for action_tuple in action_list:
if action_tuple[1]:
action = self.get_action(action_tuple[0])
action.set_icon_name(action_tuple[1])
+3 -3
View File
@@ -1293,9 +1293,9 @@ class ClipboardListView:
data = [_ob.__class__.DRAG_TARGET.drag_type, _ob, None,
_ob._type, _ob._value, _ob._dbid, _ob._dbname]
contains = model_contains(model, data)
if (contains and not
if (contains and
((context.action if hasattr(context, "action") else
context.get_actions()) & Gdk.DragAction.MOVE)):
context.get_actions()) != Gdk.DragAction.MOVE)):
continue
drop_info = widget.get_dest_row_at_pos(x, y)
if drop_info:
@@ -1314,7 +1314,7 @@ class ClipboardListView:
# 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.get_actions()) == Gdk.DragAction.MOVE):
context.finish(True, True, time)
# remember time for double drop workaround.
+14 -10
View File
@@ -49,7 +49,7 @@ from gi.repository import Pango
#-------------------------------------------------------------------------
from gramps.gen.config import config
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.gen.const import HOME_DIR, URL_WIKISTRING, URL_MANUAL_PAGE
from gramps.gen.const import HOME_DIR, URL_WIKISTRING
from gramps.gen.datehandler import get_date_formats
from gramps.gen.display.name import displayer as _nd
from gramps.gen.display.name import NameDisplayError
@@ -64,7 +64,6 @@ from .managedwindow import ManagedWindow
from .widgets import MarkupLabel, BasicLabel
from .dialog import ErrorDialog, QuestionDialog2, OkDialog
from .editors.editplaceformat import EditPlaceFormat
from .display import display_help
from .glade import Glade
from gramps.gen.plug.utils import available_updates
from .plug import PluginWindows
@@ -92,9 +91,6 @@ COL_NAME = 1
COL_FMT = 2
COL_EXPL = 3
WIKI_HELP_PAGE = URL_MANUAL_PAGE + "_-_Settings"
WIKI_HELP_SEC = _('Preferences')
#-------------------------------------------------------------------------
#
#
@@ -208,8 +204,6 @@ class ConfigureDialog(ManagedWindow):
self.panel.append_page(widget, MarkupLabel(labeltitle))
def done(self, obj, value):
if value == Gtk.ResponseType.HELP:
return
if self.__on_close:
self.__on_close()
self.close()
@@ -529,9 +523,6 @@ class GrampsPreferences(ConfigureDialog):
ConfigureDialog.__init__(self, uistate, dbstate, page_funcs,
GrampsPreferences, config,
on_close=update_constants)
help_btn = self.window.add_button(_('_Help'), Gtk.ResponseType.HELP)
help_btn.connect(
'clicked', lambda x: display_help(WIKI_HELP_PAGE, WIKI_HELP_SEC))
self.setup_configs('interface.grampspreferences', 700, 450)
def add_researcher_panel(self, configdialog):
@@ -993,6 +984,12 @@ class GrampsPreferences(ConfigureDialog):
"""
self.uistate.emit('grampletbar-close-changed')
def cb_grampletbar_refresh(self, obj):
"""
Gramplet bar refresh button preference callback
"""
self.uistate.emit('grampletbar-refresh-changed')
def add_formats_panel(self, configdialog):
row = 0
grid = Gtk.Grid()
@@ -1194,6 +1191,13 @@ class GrampsPreferences(ConfigureDialog):
row, 'interface.grampletbar-close', stop=3,
extra_callback=self.cb_grampletbar_close)
row += 1
# Gramplet bar refresh button:
self.add_checkbox(grid,
_("Enable manual refresh for the active gramplet"),
row, 'interface.grampletbar-refresh', stop=3,
extra_callback=self.cb_grampletbar_refresh)
row += 1
return _('Display'), grid
def auto_title_changed(self, obj):
+28 -1
View File
@@ -303,6 +303,27 @@ class DbLoader(CLIDbLoader):
self._end_progress()
return True
#-------------------------------------------------------------------------
#
# default dir selection
#
#-------------------------------------------------------------------------
def get_default_dir():
# Suggested folder: try last open file, last import, last export,
# then home.
default_dir = os.path.dirname(config.get('paths.recent-file'))
if default_dir:
default_dir += os.path.sep
if len(default_dir)<=1:
default_dir = config.get('paths.recent-import-dir')
if len(default_dir)<=1:
default_dir = config.get('paths.recent-export-dir')
if len(default_dir)<=1:
default_dir = '~/'
else:
default_dir = "~/"
return default_dir
#-------------------------------------------------------------------------
#
# FileChooser filters: what to show in the file chooser
@@ -453,7 +474,13 @@ class GrampsImportFileDialog(ManagedWindow):
(box, type_selector) = format_maker()
import_dialog.set_extra_widget(box)
import_dialog.set_current_folder(config.get('paths.recent-import-dir'))
# Suggested folder: try last open file, import, then last export,
# then home.
default_dir = config.get('paths.recent-import-dir')
if len(default_dir)<=1:
default_dir = get_default_dir()
import_dialog.set_current_folder(default_dir)
while True:
# the import_dialog.run() makes it modal, so any change to that
# line would require the ManagedWindow.__init__ to be changed also
+2 -3
View File
@@ -26,7 +26,6 @@
import os
import webbrowser
import sys
from urllib.parse import quote
#------------------------------------------------------------------------
#
# Gramps modules
@@ -66,9 +65,9 @@ def display_help(webpage='', section=''):
if not webpage:
link = URL_WIKISTRING + URL_MANUAL_PAGE + EXTENSION
else:
link = URL_WIKISTRING + quote(webpage) + EXTENSION
link = URL_WIKISTRING + webpage + EXTENSION
if section:
link += '#' + quote(section.replace(' ', '_')).replace('%', '.')
link = link + '#' + section
display_url(link)
def display_url(link, uistate=None):
+58 -36
View File
@@ -28,6 +28,7 @@
#-------------------------------------------------------------------------
import os
from io import StringIO
import html
#-------------------------------------------------------------------------
#
@@ -65,6 +66,7 @@ from .glade import Glade
from gramps.gen.utils.db import navigation_label
from .widgets.progressdialog import ProgressMonitor, GtkProgressDialog
from .dialog import ErrorDialog
from .uimanager import ActionGroup
DISABLED = -1
@@ -246,14 +248,34 @@ class History(Callback):
#
#-------------------------------------------------------------------------
_RCT_TOP = '<ui><menubar name="MenuBar"><menu action="FileMenu"><menu action="OpenRecent">'
_RCT_BTM = '</menu></menu></menubar></ui>'
_RCT_TOP = '<placeholder id="OpenRecentMenu">'
_RCT_MENU = '''
<item>
<attribute name="action">win.%s</attribute>
<attribute name="label" translatable="no">%s</attribute>
</item>'''
_RCT_BTM = '\n </placeholder>\n'
_RCT_BAR_TOP = ('<object class="GtkMenu" id="OpenBtnMenu">\n'
'<property name="visible">True</property>\n'
'<property name="can_focus">False</property>')
_RCT_BAR = '''
<child>
<object class="GtkMenuItem">
<property name="action-name">win.%s</property>
<property name="label" translatable="yes">%s</property>
<property name="use_underline">False</property>
<property name="visible">True</property>
</object>
</child>'''
_RCT_BAR_BTM = '\n</object>\n'
from gramps.gen.recentfiles import RecentFiles
class RecentDocsMenu:
def __init__(self, uistate, state, fileopen):
self.action_group = Gtk.ActionGroup(name='RecentFiles')
self.ui_xml = []
self.action_group = ActionGroup('RecentFiles')
self.active = DISABLED
self.uistate = uistate
self.uimanager = uistate.uimanager
@@ -268,55 +290,52 @@ class RecentDocsMenu:
ErrorDialog(_('Cannot load database'), str(err),
parent=self.uistate.window)
def build(self):
buf = StringIO()
buf.write(_RCT_TOP)
def build(self, update_menu=True):
gramps_rf = RecentFiles()
count = 0
if self.active != DISABLED:
self.uimanager.remove_ui(self.active)
self.uimanager.remove_ui(self.ui_xml)
self.uimanager.remove_action_group(self.action_group)
self.action_group = Gtk.ActionGroup(name='RecentFiles')
self.active = DISABLED
actions = []
actionlist = []
menu = _RCT_TOP
bar = _RCT_BAR_TOP
rfiles = gramps_rf.gramps_recent_files
rfiles.sort(key=lambda x: x.get_time(), reverse=True)
new_menu = Gtk.Menu()
#new_menu = Gtk.Menu()
#new_menu.set_tooltip_text(_("Connect to a recent database"))
for item in rfiles:
try:
title = item.get_name()
title = html.escape(item.get_name())
filename = os.path.basename(item.get_path())
action_id = "RecentMenu%d" % count
buf.write('<menuitem action="%s"/>' % action_id)
actions.append((action_id, None, title, None, None,
make_callback(item, self.load)))
mitem = Gtk.MenuItem(label=title, use_underline=False)
mitem.connect('activate', make_callback(item, self.load))
mitem.show()
new_menu.append(mitem)
# add the menuitem for this file
menu += _RCT_MENU % (action_id, title)
# add the action for this file
actionlist.append((action_id, make_callback(item, self.load)))
# add the toolbar menuitem
bar += _RCT_BAR % (action_id, title)
except RuntimeError:
# ignore no longer existing files
_LOG.info("Ignoring the RecentItem %s (%s)" % (title, filename))
count += 1
buf.write(_RCT_BTM)
self.action_group.add_actions(actions)
self.uimanager.insert_action_group(self.action_group, 1)
self.active = self.uimanager.add_ui_from_string(buf.getvalue())
self.uimanager.ensure_update()
buf.close()
if len(rfiles) > 0:
new_menu.show()
self.uistate.set_open_recent_menu(new_menu)
menu += _RCT_BTM
bar += _RCT_BAR_BTM
self.ui_xml = [menu, bar]
self.action_group.add_actions(actionlist)
self.uimanager.insert_action_group(self.action_group)
self.active = self.uimanager.add_ui_from_string(self.ui_xml)
if update_menu:
self.uimanager.update_menu()
def make_callback(val, func):
return lambda x: func(val)
return lambda x, y: func(val)
from .logger import RotateHandler
@@ -379,6 +398,7 @@ class DisplayState(Callback):
'nameformat-changed' : None,
'placeformat-changed' : None,
'grampletbar-close-changed' : None,
'grampletbar-refresh-changed' : None,
'update-available' : (list, ),
'autobackup' : None,
}
@@ -621,17 +641,19 @@ class DisplayState(Callback):
self.status.pop(self.status_id)
if active_handle and dbstate.is_open():
if active_handle:
name, obj = navigation_label(dbstate.db, nav_type, active_handle)
# Append relationship to default person if funtionality is enabled.
if nav_type == 'Person' and config.get('interface.statusbar') > 1:
if active_handle != dbstate.db.get_default_handle():
msg = self.display_relationship(dbstate, active_handle)
if msg:
name = '%s (%s)' % (name, msg.strip())
else:
name = _('No active object')
# Append relationship to default person if funtionality is enabled.
if nav_type == 'Person' and active_handle \
and config.get('interface.statusbar') > 1:
if active_handle != dbstate.db.get_default_handle():
msg = self.display_relationship(dbstate, active_handle)
if msg:
name = '%s (%s)' % (name, msg.strip())
if not name:
name = self.NAV2MES[nav_type]
@@ -211,7 +211,6 @@ class EmbeddedList(ButtonTab):
self.tree.drag_source_set_target_list(tglist)
self.tree.connect('drag_data_get', self.drag_data_get)
self.tree.connect_after('drag-begin', self.after_drag_begin)
if not self.dbstate.db.readonly:
self.tree.connect('drag_data_received', self.drag_data_received)
self.tree.connect('drag_motion', self.tree_drag_motion)
@@ -283,12 +282,6 @@ class EmbeddedList(ButtonTab):
"""
pass
def after_drag_begin(self, widget, drag_context):
"""
We want to show the icon during drag instead of the long row entry
"""
Gtk.drag_set_icon_name(drag_context, self.get_icon_name(), 0, 0)
def handle_extra_type(self, objtype, obj):
pass
+2 -3
View File
@@ -387,11 +387,12 @@ class EditFamily(EditPrimary):
return Family()
def _local_init(self):
self.build_interface()
self.added = self.obj.handle is None
if self.added:
self.obj.handle = create_id()
self.build_interface()
self.load_data()
def _connect_db_signals(self):
@@ -557,8 +558,6 @@ class EditFamily(EditPrimary):
self.fbutton_del.connect('clicked', self.del_father_clicked)
self.fbutton_add.connect('clicked', self.add_father_clicked)
if self.added:
return # avoids crash on drag because not in db yet
#allow for a context menu
self.set_contexteventbox(self.top.get_object("eventboxtop"))
#allow for drag of the family object from eventboxtop
+1 -1
View File
@@ -74,7 +74,7 @@ class EditLink(ManagedWindow):
self.simple_access = SimpleAccess(self.dbstate.db)
self.callback = callback
ManagedWindow.__init__(self, uistate, track, url, modal=True)
ManagedWindow.__init__(self, uistate, track, url)
self._local_init()
self._connect_signals()
+3 -2
View File
@@ -180,7 +180,6 @@ class EditNote(EditPrimary):
self.set_window(win, None, self.get_menu_title())
self.setup_configs('interface.note', 700, 500)
vboxnote = self.top.get_object('vbox131')
notebook = self.top.get_object('note_notebook')
#recreate start page as GrampsTab
@@ -271,7 +270,9 @@ class EditNote(EditPrimary):
# create a formatting toolbar
if not self.dbstate.db.readonly:
vbox = self.top.get_object('container')
vbox.pack_start(self.texteditor.get_toolbar(), False, False, 0)
toolbar, self.action_group = self.texteditor.create_toolbar(
self.uistate.uimanager, self.window)
vbox.pack_start(toolbar, False, False, 0)
self.texteditor.set_transient_parent(self.window)
# setup initial values for textview and textbuffer
+29 -26
View File
@@ -250,8 +250,7 @@ class EditPerson(EditPrimary):
self.eventbox.connect('button-press-event',
self._image_button_press)
# allow to initiate a drag-and-drop with this person if it has a handle
if self.added:
return # Avoid HandleError if dragging an objet not in db yet
#if self.obj.get_handle():
tglist = Gtk.TargetList.new([])
tglist.add(DdTargets.PERSON_LINK.atom_drag_type,
DdTargets.PERSON_LINK.target_flags,
@@ -677,33 +676,33 @@ class EditPerson(EditPrimary):
EditMediaRef(self.dbstate, self.uistate, self.track,
media_obj, media_ref, self.load_photo)
def _top_contextmenu(self):
def _top_contextmenu(self, prefix):
"""
Override from base class, the menuitems and actiongroups for the top
of context menu.
"""
self.all_action = Gtk.ActionGroup(name="/PersonAll")
self.home_action = Gtk.ActionGroup(name="/PersonHome")
self.track_ref_for_deletion("all_action")
self.track_ref_for_deletion("home_action")
if self.added:
# Don't add items if not a real person yet
return '', []
self.all_action.add_actions([
('ActivePerson', None, _("Make Active Person"),
None, None, self._make_active),
])
self.home_action.add_actions([
('HomePerson', 'go-home', _("Make Home Person"),
None, None, self._make_home_person),
])
_actions = [('ActivePerson', self._make_active),
('HomePerson', self._make_home_person)]
self.all_action.set_visible(not self.added)
self.home_action.set_visible(not self.added)
ui_top_cm = (
'''
<item>
<attribute name="action">{prefix}.ActivePerson</attribute>
<attribute name="label" translatable="yes">Make Active Person'''
'''</attribute>
</item>
<item>
<attribute name="action">{prefix}.HomePerson</attribute>
<attribute name="label" translatable="yes">Make Home Person'''
'''</attribute>
</item>
'''.format(prefix=prefix))
ui_top_cm = '''
<menuitem action="ActivePerson"/>
<menuitem action="HomePerson"/>'''
return ui_top_cm, [self.all_action, self.home_action]
return ui_top_cm, _actions
def _top_drag_data_get(self, widget, context, sel_data, info, time):
if info == DdTargets.PERSON_LINK.app_id:
@@ -714,17 +713,21 @@ class EditPerson(EditPrimary):
"""
Override base class, make inactive home action if not needed.
"""
if self.added:
return
home_action = self.uistate.uimanager.get_action(self.action_group,
'HomePerson')
if (self.dbstate.db.get_default_person() and
self.obj.get_handle() ==
self.dbstate.db.get_default_person().get_handle()):
self.home_action.set_sensitive(False)
home_action.set_enabled(False)
else:
self.home_action.set_sensitive(True)
home_action.set_enabled(True)
def _make_active(self, obj):
def _make_active(self, obj, value):
self.uistate.set_active(self.obj.get_handle(), 'Person')
def _make_home_person(self, obj):
def _make_home_person(self, obj, value):
handle = self.obj.get_handle()
if handle:
self.dbstate.db.set_default_person_handle(handle)
+45 -25
View File
@@ -32,6 +32,7 @@ import abc
#
#-------------------------------------------------------------------------
from gi.repository import Gtk
from gi.repository.Gio import SimpleActionGroup
#-------------------------------------------------------------------------
#
@@ -49,6 +50,8 @@ from ..display import display_help
from ..dialog import SaveDialog
from gramps.gen.lib import PrimaryObject
from ..dbguielement import DbGUIElement
from ..uimanager import ActionGroup
class EditPrimary(ManagedWindow, DbGUIElement, metaclass=abc.ABCMeta):
@@ -75,6 +78,7 @@ class EditPrimary(ManagedWindow, DbGUIElement, metaclass=abc.ABCMeta):
self.get_from_gramps_id = get_from_gramps_id
self.contexteventbox = None
self.__tabs = []
self.action_group = None
ManagedWindow.__init__(self, uistate, track, obj)
DbGUIElement.__init__(self, self.db)
@@ -184,6 +188,8 @@ class EditPrimary(ManagedWindow, DbGUIElement, metaclass=abc.ABCMeta):
self.dbstate.disconnect(self.dbstate_connect_key)
self._cleanup_connects()
self._cleanup_on_exit()
if self.action_group:
self.uistate.uimanager.remove_action_group(self.action_group)
self.get_from_handle = None
self.get_from_gramps_id = None
ManagedWindow.close(self)
@@ -283,48 +289,62 @@ class EditPrimary(ManagedWindow, DbGUIElement, metaclass=abc.ABCMeta):
return False
#build the possible popup menu
self._build_popup_ui()
menu_model = self._build_popup_ui()
if not menu_model:
return False
#set or unset sensitivity in popup
self._post_build_popup_ui()
menu = self.popupmanager.get_widget('/Popup')
if menu:
menu.popup(None, None, None, None, event.button, event.time)
return True
menu = Gtk.Menu.new_from_model(menu_model)
menu.attach_to_widget(obj, None)
menu.show_all()
if Gtk.MINOR_VERSION < 22:
# ToDo The following is reported to work poorly with Wayland
menu.popup(None, None, None, None,
event.button, event.time)
else:
menu.popup_at_pointer(event)
return True
return False
def _build_popup_ui(self):
"""
Create actions and ui of context menu
If you don't need a popup, override this and return None
"""
from ..plug.quick import create_quickreport_menu
self.popupmanager = Gtk.UIManager()
#add custom actions
(ui_top, action_groups) = self._top_contextmenu()
for action in action_groups :
self.popupmanager.insert_action_group(action, -1)
prefix = str(id(self))
#get custom ui and actions
(ui_top, actions) = self._top_contextmenu(prefix)
#see which quick reports are available now:
ui_qr = ''
if self.QR_CATEGORY > -1 :
(ui_qr, reportactions) = create_quickreport_menu(self.QR_CATEGORY,
self.dbstate, self.uistate,
self.obj, track=self.track)
self.report_action = Gtk.ActionGroup(name="/PersonReport")
self.report_action.add_actions(reportactions)
self.report_action.set_visible(True)
self.popupmanager.insert_action_group(self.report_action, -1)
(ui_qr, reportactions) = create_quickreport_menu(
self.QR_CATEGORY, self.dbstate, self.uistate,
self.obj, prefix, track=self.track)
actions.extend(reportactions)
popupui = '''
<ui>
<popup name="Popup">''' + ui_top + '''
<separator/>''' + ui_qr + '''
</popup>
</ui>'''
popupui = '''<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id="Popup">''' + ui_top + '''
<section>
''' + ui_qr + '''
</section>
</menu>
</interface>'''
self.popupmanager.add_ui_from_string(popupui)
builder = Gtk.Builder.new_from_string(popupui, -1)
def _top_contextmenu(self):
self.action_group = ActionGroup('EditPopup' + prefix, actions,
prefix)
act_grp = SimpleActionGroup()
self.window.insert_action_group(prefix, act_grp)
self.window.set_application(self.uistate.uimanager.app)
self.uistate.uimanager.insert_action_group(self.action_group, act_grp)
return builder.get_object('Popup')
def _top_contextmenu(self, prefix):
"""
Derived class can create a ui with menuitems and corresponding list of
actiongroups
@@ -186,8 +186,10 @@ class PersonSidebarFilter(SidebarFilter):
# if the name is not empty, choose either the regular expression
# version or the normal text match
if name:
rule = RegExpName([name], use_regex=regex)
generic_filter.add_rule(rule)
name_parts = name.split(sep=" ")
for name_part in name_parts:
rule = RegExpName([name_part], use_regex=regex)
generic_filter.add_rule(rule)
# if the id is not empty, choose either the regular expression
# version or the normal text match
@@ -206,7 +208,7 @@ class PersonSidebarFilter(SidebarFilter):
# Build an event filter if needed
if etype:
rule = HasEvent([etype, '', '', '', '', '1'], use_regex=regex)
rule = HasEvent([etype, '', '', '', '', True], use_regex=regex)
generic_filter.add_rule(rule)
# Build birth event filter if needed
+1 -1
View File
@@ -65,7 +65,6 @@
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
<property name="secondary">True</property>
</packing>
</child>
</object>
@@ -162,6 +161,7 @@
<action-widgets>
<action-widget response="-6">cancelbutton1</action-widget>
<action-widget response="-5">okbutton1</action-widget>
<action-widget response="-11">help</action-widget>
</action-widgets>
</object>
</interface>
-17
View File
@@ -493,23 +493,6 @@
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button14">
<property name="label" translatable="yes">_Help</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<signal name="clicked" handler="on_book_help_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
<property name="secondary">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
+1 -1
View File
@@ -159,7 +159,6 @@
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
<property name="secondary">True</property>
</packing>
</child>
</object>
@@ -376,6 +375,7 @@
<action-widgets>
<action-widget response="-7">cancel_btn</action-widget>
<action-widget response="-5">connect_btn</action-widget>
<action-widget response="-11">help_btn</action-widget>
</action-widgets>
</object>
</interface>
-32
View File
@@ -116,22 +116,6 @@
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="help_btn">
<property name="label">gtk-help</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_help_btn_style_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
<property name="secondary">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
@@ -1767,22 +1751,6 @@
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="help_btn_styles">
<property name="label">gtk-help</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_help_btn_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
<property name="secondary">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
+454 -75
View File
@@ -3,6 +3,7 @@
#
# Copyright (C) 2000-2006 Donald N. Allingham
# Copyright (C) 2009 Benny Malengier
# Copyright (C) 2018 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
@@ -50,7 +51,369 @@ _ = glocale.translation.gettext
MIN_PYGOBJECT_VERSION = (3, 12, 0)
PYGOBJ_ERR = False
MIN_GTK_VERSION = (3, 10)
MIN_GTK_VERSION = (3, 12)
UIDEFAULT = (
'''<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id="menubar"><section id="menubar-update">
<submenu id='m1'>
<attribute name="label" translatable="yes">_Family Trees</attribute>
<section id="ftree">
<item>
<attribute name="action">win.Open</attribute>
<attribute name="label" translatable="yes">'''
'''_Manage Family Trees</attribute>
</item>
<submenu>
<attribute name="action">win.OpenRecent</attribute>
<attribute name="label" translatable="yes">Open _Recent</attribute>
<placeholder id="OpenRecentMenu">
</placeholder>
</submenu>
<item groups='RO'>
<attribute name="action">win.Close</attribute>
<attribute name="label" translatable="yes">_Close</attribute>
</item>
</section>
<section groups='RO RW'>
<item groups='RW'>
<attribute name="action">win.Import</attribute>
<attribute name="label" translatable="yes">_Import...</attribute>
</item>
<item>
<attribute name="action">win.Export</attribute>
<attribute name="label" translatable="yes">_Export...</attribute>
</item>
<placeholder id="LocalExport">
</placeholder>
<item>
<attribute name="action">win.Backup</attribute>
<attribute name="label" translatable="yes">Make Backup...</attribute>
</item>
</section>
<section>
<item groups='RO'>
<attribute name="action">win.Abandon</attribute>
<attribute name="label" translatable="yes">'''
'''_Abandon Changes and Quit</attribute>
</item>
<placeholder groups='OSX' id='osxquit'>
<item>
<attribute name="action">app.quit</attribute>
<attribute name="label" translatable="yes">_Quit</attribute>
</item>
</placeholder>
</section>
</submenu>
<submenu id='m2' groups='RW'>
<attribute name="label" translatable="yes">_Add</attribute>
<section>
<item>
<attribute name="action">win.PersonAdd</attribute>
<attribute name="label" translatable="yes">Person</attribute>
</item>
</section>
<section>
<item>
<attribute name="action">win.FamilyAdd</attribute>
<attribute name="label" translatable="yes">Family</attribute>
</item>
</section>
<section>
<item>
<attribute name="action">win.EventAdd</attribute>
<attribute name="label" translatable="yes">Event</attribute>
</item>
</section>
<section>
<item>
<attribute name="action">win.PlaceAdd</attribute>
<attribute name="label" translatable="yes">Place</attribute>
</item>
<item>
<attribute name="action">win.SourceAdd</attribute>
<attribute name="label" translatable="yes">Source</attribute>
</item>
<item>
<attribute name="action">win.CitationAdd</attribute>
<attribute name="label" translatable="yes">Citation</attribute>
</item>
<item>
<attribute name="action">win.RepositoryAdd</attribute>
<attribute name="label" translatable="yes">Repository</attribute>
</item>
<item>
<attribute name="action">win.MediaAdd</attribute>
<attribute name="label" translatable="yes">Media</attribute>
</item>
<item>
<attribute name="action">win.NoteAdd</attribute>
<attribute name="label" translatable="yes">Note</attribute>
</item>
</section>
</submenu>
<submenu id='m3'>
<attribute name="label" translatable="yes">_Edit</attribute>
<section groups='RW'>
<placeholder id="undo">
</placeholder>
<placeholder id="redo">
</placeholder>
<item>
<attribute name="action">win.UndoHistory</attribute>
<attribute name="label" translatable="yes">Undo History</attribute>
</item>
</section>
<section id='CommonEdit' groups='RW'>
</section>
<section id='TagMenu' groups='RW'>
</section>
<section groups='RW'>
<item>
<attribute name="action">win.Clipboard</attribute>
<attribute name="label" translatable="yes">Clip_board</attribute>
</item>
</section>
<section>
<placeholder groups='OSX' id='osxpref'>
<item>
<attribute name="action">app.preferences</attribute>
<attribute name="label" translatable="yes">'''
'''_Preferences...</attribute>
</item>
</placeholder>
<placeholder id='otheredit'>
</placeholder>
</section>
</submenu>
<submenu id='m4'>
<attribute name="label" translatable="yes">_View</attribute>
<section>
<item>
<attribute name="action">win.ConfigView</attribute>
<attribute name="label" translatable="yes">_Configure...</attribute>
</item>
<item>
<attribute name="action">win.Navigator</attribute>
<attribute name="label" translatable="yes">_Navigator</attribute>
</item>
<item>
<attribute name="action">win.Toolbar</attribute>
<attribute name="label" translatable="yes">_Toolbar</attribute>
</item>
<placeholder id='Bars'>
</placeholder>
<item>
<attribute name="action">win.Fullscreen</attribute>
<attribute name="label" translatable="yes">F_ull Screen</attribute>
</item>
</section>
<section id="ViewsInCatagory">
</section>
</submenu>
<submenu id="m5" groups='RO'>
<attribute name="label" translatable="yes">_Go</attribute>
<placeholder id="CommonGo">
</placeholder>
<section id="CommonHistory">
</section>
</submenu>
<submenu id='m6' groups='RW'>
<attribute name="label" translatable="yes">_Bookmarks</attribute>
<section id="AddEditBook">
</section>
<section id="GoToBook">
</section>
</submenu>
<submenu id='m7' groups='RO'>
<attribute name="label" translatable="yes">_Reports</attribute>
<section>
<item>
<attribute name="action">win.Books</attribute>
<attribute name="label" translatable="yes">Books...</attribute>
</item>
</section>
<section id="P_ReportsMenu">
</section>
</submenu>
<submenu id='m8' groups='RW'>
<attribute name="label" translatable="yes">_Tools</attribute>
<section id="P_ToolsMenu">
</section>
</submenu>
<submenu id='m9' groups='RO'>
<attribute name="label" translatable="yes">_Windows</attribute>
<section id="WinMenu">
</section>
</submenu>
<submenu id='m10'>
<attribute name="label" translatable="yes">_Help</attribute>
<section>
<item>
<attribute name="action">win.UserManual</attribute>
<attribute name="label" translatable="yes">_User Manual</attribute>
</item>
<item>
<attribute name="action">win.FAQ</attribute>
<attribute name="label" translatable="yes">_FAQ</attribute>
</item>
<item>
<attribute name="action">win.KeyBindings</attribute>
<attribute name="label" translatable="yes">_Key Bindings</attribute>
</item>
<item>
<attribute name="action">win.TipOfDay</attribute>
<attribute name="label" translatable="yes">Tip of the Day</attribute>
</item>
<item>
<attribute name="action">win.PluginStatus</attribute>
<attribute name="label" translatable="yes">'''
'''_Plugin Manager</attribute>
</item>
</section>
<section>
<item>
<attribute name="action">win.HomePage</attribute>
<attribute name="label" translatable="yes">'''
'''Gramps _Home Page</attribute>
</item>
<item>
<attribute name="action">win.MailingLists</attribute>
<attribute name="label" translatable="yes">'''
'''Gramps _Mailing Lists</attribute>
</item>
<item>
<attribute name="action">win.ReportBug</attribute>
<attribute name="label" translatable="yes">_Report a Bug</attribute>
</item>
<item>
<attribute name="action">win.ExtraPlugins</attribute>
<attribute name="label" translatable="yes">'''
'''_Extra Reports/Tools</attribute>
</item>
</section>
<section groups='OSX'>
<item>
<attribute name="action">app.about</attribute>
<attribute name="label" translatable="yes">_About</attribute>
</item>
</section>
</submenu>
</section></menu>
<object class="GtkMenu" id="OpenBtnMenu">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<object class="GtkToolbar" id="ToolBar">
<property name="hexpand">1</property>
<property name="toolbar-style">GTK_TOOLBAR_ICONS</property>
<style>
<class name="primary-toolbar"/>
</style>
<child>
<object class="GtkToolButton">
<property name="icon-name">gramps</property>
<property name="action-name">win.Open</property>
<property name="tooltip_text" translatable="yes">'''
'''Manage databases</property>
<property name="label" translatable="yes">_Family Trees</property>
<property name="use-underline">True</property>
</object>
<packing>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkToolItem">
<child>
<object class="GtkMenuButton">
<property name="tooltip_text" translatable="yes">'''
'''Connect to a recent database</property>
<property name="popup">OpenBtnMenu</property>
<property name="relief">GTK_RELIEF_NONE</property>
</object>
</child>
</object>
</child>
<placeholder id='CommonNavigation'>
</placeholder>
<placeholder id='BarCommonEdit'>
</placeholder>
<placeholder id='TagTool'>
</placeholder>
<child groups='RW'>
<object class="GtkToolButton" id="Clipboard">
<property name="icon-name">edit-paste</property>
<property name="action-name">win.Clipboard</property>
<property name="tooltip_text" translatable="yes">'''
'''Open the Clipboard dialog</property>
<property name="label" translatable="yes">Clip_board</property>
<property name="use-underline">True</property>
</object>
<packing>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkSeparatorToolItem"/>
</child>
<child>
<object class="GtkToolButton" id="ConfigView">
<property name="icon-name">gramps-config</property>
<property name="action-name">win.ConfigView</property>
<property name="tooltip_text" translatable="yes">'''
'''Configure the active view</property>
<property name="label" translatable="yes">_Configure...</property>
<property name="use-underline">True</property>
</object>
<packing>
<property name="homogeneous">False</property>
</packing>
</child>
<placeholder id='ViewsInCategoryBar'>
</placeholder>
<child>
<object class="GtkSeparatorToolItem" id="sep"/>
</child>
<placeholder id="MoreButtons">
</placeholder>
<child groups='RO'>
<object class="GtkToolButton" id="Reports">
<property name="icon-name">gramps-reports</property>
<property name="action-name">win.Reports</property>
<property name="tooltip_text" translatable="yes">'''
'''Open the reports dialog</property>
<property name="label" translatable="yes">_Reports</property>
<property name="use-underline">True</property>
</object>
<packing>
<property name="homogeneous">False</property>
</packing>
</child>
<child groups='RW'>
<object class="GtkToolButton" id="Tools">
<property name="icon-name">gramps-tools</property>
<property name="action-name">win.Tools</property>
<property name="tooltip_text" translatable="yes">'''
'''Open the tools dialog</property>
<property name="label" translatable="yes">_Tools</property>
<property name="use-underline">True</property>
</object>
<packing>
<property name="homogeneous">False</property>
</packing>
</child>
<placeholder id='AfterTools'>
</placeholder>
</object>
<menu id="Popup">
</menu>
</interface>
''')
try:
#import gnome introspection, part of pygobject
@@ -235,9 +598,8 @@ class Gramps:
process. It may spawn several windows and control several databases.
"""
def __init__(self, argparser):
def __init__(self, argparser, app):
from gramps.gen.dbstate import DbState
from . import viewmanager
from .viewmanager import ViewManager
from gramps.cli.arghandler import ArgHandler
from .tipofday import TipOfDay
@@ -248,7 +610,7 @@ class Gramps:
theme.append_search_path(IMAGE_DIR)
dbstate = DbState()
self._vm = ViewManager(dbstate,
self._vm = ViewManager(app, dbstate,
config.get("interface.view-categories"))
if (lin()
@@ -256,7 +618,7 @@ class Gramps:
and not gettext.find(GTK_GETTEXT_DOMAIN)):
_display_gtk_gettext_message(parent=self._vm.window)
#_display_welcome_message(parent=self._vm.window)
_display_welcome_message(parent=self._vm.window)
_display_translator_message(parent=self._vm.window)
@@ -303,77 +665,24 @@ class Gramps:
#
#-------------------------------------------------------------------------
def __startgramps(errors, argparser):
def startgramps(errors, argparser):
"""
Main startup function started via GObject.timeout_add
First action inside the gtk loop
"""
try:
from .dialog import ErrorDialog
#handle first existing errors in GUI fashion
if errors:
for error in errors:
ErrorDialog(error[0], error[1]) # TODO no-parent
Gtk.main_quit()
sys.exit(1)
if argparser.errors:
for error in argparser.errors:
ErrorDialog(error[0], error[1]) # TODO no-parent
Gtk.main_quit()
sys.exit(1)
# add gui logger
from .logger import RotateHandler, GtkHandler
form = logging.Formatter(
fmt="%(relativeCreated)d: %(levelname)s: "
"%(filename)s: line %(lineno)d: %(message)s")
# Create the log handlers
rot_h = RotateHandler(capacity=20)
rot_h.setFormatter(form)
# Only error and critical log records should
# trigger the GUI handler.
gtkh = GtkHandler(rotate_handler=rot_h)
gtkh.setFormatter(form)
gtkh.setLevel(logging.ERROR)
logger = logging.getLogger()
logger.addHandler(rot_h)
logger.addHandler(gtkh)
except:
#make sure there is a clean exit if there is an error in above steps
quit_now = True
exit_code = 1
LOG.error(_("\nGramps failed to start. "
"Please report a bug about this.\n"
"This could be because of an error "
"in a (third party) View on startup.\n"
"To use another view, don't load a Family Tree, "
"change view, and then load your Family Tree.\n"
"You can also change manually "
"the startup view in the gramps.ini file \n"
"by changing the last-view parameter.\n"
), exc_info=True)
# start Gramps, errors stop the gtk loop
app = GrampsApplication(errors, argparser)
try:
quit_now = False
exit_code = 0
if has_display():
Gramps(argparser)
else:
if app.run():
print(_("Gramps terminated because of no DISPLAY"))
quit_now = True
exit_code = 1
except SystemExit as err:
quit_now = True
if err.code:
exit_code = err.code
if isinstance(err.code, str):
LOG.error(err.code, exc_info=False)
else:
LOG.error("Gramps terminated with exit code: %d.", err.code,
exc_info=False)
LOG.error("Gramps terminated with exit code: %d.", err.code,
exc_info=True)
except OSError as err:
quit_now = True
exit_code = err.errno or 1
@@ -398,18 +707,88 @@ def __startgramps(errors, argparser):
), exc_info=True)
if quit_now:
#stop gtk loop and quit
Gtk.main_quit()
app.quit()
sys.exit(exit_code)
#function finished, return False to stop the timeout_add function calls
return False
def startgtkloop(errors, argparser):
"""
We start the gtk loop and run the function to start up Gramps
"""
GLib.timeout_add(100, __startgramps, errors, argparser, priority=100)
if os.path.exists(os.path.join(DATA_DIR, "gramps.accel")):
Gtk.AccelMap.load(os.path.join(DATA_DIR, "gramps.accel"))
Gtk.main()
# we do the following import here to avoid the Gtk require version warning
from .uimanager import UIManager
from gramps.gen.constfunc import is_quartz
class GrampsApplication(Gtk.Application):
def __init__(self, errors, argparser):
super().__init__(application_id="org.gramps-project.Gramps")
self.window = None
self.errors = errors
self.argparser = argparser
def do_startup(self):
Gtk.Application.do_startup(self)
self.uimanager = UIManager(self, UIDEFAULT)
if not is_quartz():
self.uimanager.show_groups = ['OSX']
self.uimanager.update_menu(init=True)
if os.path.exists(os.path.join(DATA_DIR, "gramps.accel")):
self.uimanager.load_accels(os.path.join(DATA_DIR, "gramps.accel"))
try:
from .dialog import ErrorDialog
#handle first existing errors in GUI fashion
if self.errors:
for error in self.errors:
ErrorDialog(error[0], error[1]) # TODO no-parent
Gtk.main_quit()
sys.exit(1)
if self.argparser.errors:
for error in self.argparser.errors:
ErrorDialog(error[0], error[1]) # TODO no-parent
Gtk.main_quit()
sys.exit(1)
# add gui logger
from .logger import RotateHandler, GtkHandler
form = logging.Formatter(
fmt="%(relativeCreated)d: %(levelname)s: "
"%(filename)s: line %(lineno)d: %(message)s")
# Create the log handlers
rot_h = RotateHandler(capacity=20)
rot_h.setFormatter(form)
# Only error and critical log records should
# trigger the GUI handler.
gtkh = GtkHandler(rotate_handler=rot_h)
gtkh.setFormatter(form)
gtkh.setLevel(logging.ERROR)
logger = logging.getLogger()
logger.addHandler(rot_h)
logger.addHandler(gtkh)
except:
#make sure there is a clean exit if error in above steps
exit_code = 1
LOG.error(_("\nGramps failed to start. "
"Please report a bug about this.\n"
"This could be because of an error "
"in a (third party) View on startup.\n"
"To use another view, don't load a Family Tree, "
"change view, and then load your Family Tree.\n"
"You can also change manually "
"the startup view in the gramps.ini file \n"
"by changing the last-view parameter.\n"
), exc_info=True)
#stop gtk loop and quit
self.quit()
sys.exit(exit_code)
def do_activate(self):
# We only allow a single window and raise any existing ones
if not self.window:
# Windows are associated with the application
# when the last one is closed the application shuts down
Gramps(self.argparser, self)
else:
print('Gramps is already running.')
self.window.present()
+26 -24
View File
@@ -31,7 +31,7 @@ the create/deletion of dialog windows.
#-------------------------------------------------------------------------
import os
from io import StringIO
import html
#-------------------------------------------------------------------------
#
# GNOME/GTK
@@ -49,6 +49,7 @@ from gramps.gen.const import GLADE_FILE, ICON
from gramps.gen.errors import WindowActiveError
from gramps.gen.config import config
from gramps.gen.constfunc import is_quartz
from .uimanager import ActionGroup
from .glade import Glade
#-------------------------------------------------------------------------
@@ -57,8 +58,8 @@ from .glade import Glade
#
#-------------------------------------------------------------------------
_win_top = '<ui><menubar name="MenuBar"><menu action="WindowsMenu">'
_win_btm = '</menu></menubar></ui>'
_win_top = '<section id="WinMenu">\n'
_win_btm = '</section>\n'
DISABLED = -1
#-----------------------------------------------------------------------
@@ -108,7 +109,7 @@ class GrampsWindowManager:
self.uimanager = uimanager
self.window_tree = []
self.id2item = {}
self.action_group = Gtk.ActionGroup(name='WindowManger')
self.action_group = ActionGroup(name='WindowManger')
self.active = DISABLED
self.ui = _win_top + _win_btm
@@ -125,9 +126,9 @@ class GrampsWindowManager:
"""
Enables the UI and action groups
"""
self.uimanager.insert_action_group(self.action_group, 1)
self.active = self.uimanager.add_ui_from_string(self.ui)
self.uimanager.ensure_update()
self.uimanager.insert_action_group(self.action_group)
self.active = self.uimanager.add_ui_from_string([self.ui])
self.uimanager.update_menu()
def get_item_from_track(self, track):
# Recursively find an item given track sequence
@@ -270,31 +271,35 @@ class GrampsWindowManager:
def call_back_factory(self, item):
if not isinstance(item, list):
def func(obj):
def func(*obj):
if item.window_id and self.id2item.get(item.window_id):
self.id2item[item.window_id]._present()
else:
def func(obj):
def func(*obj):
pass
return func
def generate_id(self, item):
return str(item.window_id)
return 'wm/' + str(item.window_id)
def display_menu_list(self, data, action_data, mlist):
menuitem = ('<item>\n'
'<attribute name="action">win.%s</attribute>\n'
'<attribute name="label" translatable="yes">'
'%s...</attribute>\n'
'</item>\n')
if isinstance(mlist, (list, tuple)):
i = mlist[0]
idval = self.generate_id(i)
data.write('<menu action="M:%s">' % idval)
action_data.append(("M:"+idval, None, i.submenu_label,
None, None, None))
data.write('<submenu>\n<attribute name="label"'
' translatable="yes">%s</attribute>\n' %
html.escape(i.submenu_label))
else:
i = mlist
idval = self.generate_id(i)
data.write('<menuitem action="%s"/>' % idval)
action_data.append((idval, None, i.menu_label, None, None,
self.call_back_factory(i)))
data.write(menuitem % (idval, html.escape(i.menu_label)))
action_data.append((idval, self.call_back_factory(i)))
if isinstance(mlist, (list, tuple)) and (len(mlist) > 1):
for i in mlist[1:]:
@@ -302,20 +307,17 @@ class GrampsWindowManager:
self.display_menu_list(data, action_data, i)
else:
idval = self.generate_id(i)
data.write('<menuitem action="%s"/>'
% self.generate_id(i))
action_data.append((idval, None, i.menu_label,
None, None,
self.call_back_factory(i)))
data.write(menuitem % (idval, html.escape(i.menu_label)))
action_data.append((idval, self.call_back_factory(i)))
if isinstance(mlist, (list, tuple)):
data.write('</menu>')
data.write('</submenu>\n')
def build_windows_menu(self):
if self.active != DISABLED:
self.uimanager.remove_ui(self.active)
self.uimanager.remove_action_group(self.action_group)
self.action_group = Gtk.ActionGroup(name='WindowManger')
self.action_group = ActionGroup(name='WindowManger')
action_data = []
data = StringIO()
@@ -576,8 +578,8 @@ class ManagedWindow:
self.opened = False
self._save_position(save_config=False) # the next line will save it
self._save_size()
self.uistate.gwm.close_track(self.track)
self.clean_up()
self.uistate.gwm.close_track(self.track)
# put a previously modal window back to modal, now that we are closing
if self.other_modal_window:
self.other_modal_window.set_modal(True)
+49 -31
View File
@@ -38,22 +38,21 @@ from gi.repository import Gdk
#-------------------------------------------------------------------------
from gramps.gen.plug import (START, END)
from .pluginmanager import GuiPluginManager
from .actiongroup import ActionGroup
from .uimanager import ActionGroup
#-------------------------------------------------------------------------
#
# Constants
#
#-------------------------------------------------------------------------
UICATEGORY = '''<ui>
<menubar name="MenuBar">
<menu action="ViewMenu">
<placeholder name="ViewsInCategory">%s
</placeholder>
</menu>
</menubar>
</ui>
'''
UICATEGORY = ''' <section id="ViewsInCatagory">
%s
</section>
'''
UICATAGORYBAR = ''' <placeholder id='ViewsInCategoryBar'>
%s
</placeholder>
'''
CATEGORY_ICON = {
'Dashboard': 'gramps-gramplet',
@@ -88,7 +87,6 @@ class Navigator:
self.active_view = None
self.ui_category = {}
self.view_toggle_actions = {}
self.cat_view_group = None
self.merge_ids = []
@@ -139,13 +137,35 @@ class Navigator:
"""
Load the sidebar plugins.
"""
menuitem = '''
<item>
<attribute name="action">win.ViewInCatagory</attribute>
<attribute name="label" translatable="yes">%s</attribute>
<attribute name="target">%d %d</attribute>
</item>
'''
baritem = '''
<child>
<object class="GtkToggleToolButton" id="bar%d">
<property name="action-name">win.ViewInCatagory</property>
<property name="action-target">'%d %d'</property>
<property name="icon-name">%s</property>
<property name="tooltip_text" translatable="yes">%s</property>
<property name="label" translatable="yes">%s</property>
</object>
<packing>
<property name="homogeneous">False</property>
</packing>
</child>
'''
plugman = GuiPluginManager.get_instance()
categories = []
views = {}
for cat_num, cat_views in enumerate(self.viewmanager.get_views()):
uimenuitems = ''
self.view_toggle_actions[cat_num] = []
uibaritems = ''
for view_num, page in enumerate(cat_views):
if view_num == 0:
@@ -156,26 +176,26 @@ class Navigator:
cat_icon = 'gramps-view'
categories.append([cat_num, cat_name, cat_icon])
pageid = 'page_%i_%i' % (cat_num, view_num)
uimenuitems += '\n<menuitem action="%s"/>' % pageid
# id, stock, button text, UI, tooltip, page
if view_num < 9:
modifier = "<PRIMARY><ALT>%d" % ((view_num % 9) + 1)
else:
modifier = ""
accel = "<PRIMARY><ALT>%d" % ((view_num % 9) + 1)
self.viewmanager.uimanager.app.set_accels_for_action(
"win.ViewInCatagory('%d %d')" % (cat_num, view_num),
[accel])
uimenuitems += menuitem % (page[0].name, cat_num, view_num)
stock_icon = page[0].stock_icon
if stock_icon is None:
stock_icon = cat_icon
self.view_toggle_actions[cat_num].append((pageid,
stock_icon,
page[0].name, modifier, page[0].name, view_num))
uibaritems += baritem % (view_num, cat_num, view_num,
stock_icon, page[0].name,
page[0].name)
views[cat_num].append((view_num, page[0].name, stock_icon))
if len(cat_views) > 1:
#allow for switching views in a category
self.ui_category[cat_num] = UICATEGORY % uimenuitems
self.ui_category[cat_num] = [UICATEGORY % uimenuitems,
UICATAGORYBAR % uibaritems]
for pdata in plugman.get_reg_sidebars():
module = plugman.load_plugin(pdata)
@@ -229,12 +249,10 @@ class Navigator:
list(map(uimanager.remove_ui, self.merge_ids))
if cat_num in self.ui_category:
self.cat_view_group = ActionGroup(name='viewmenu')
self.cat_view_group.add_radio_actions(
self.view_toggle_actions[cat_num], value=view_num,
on_change=self.cb_view_clicked, user_data=cat_num)
self.cat_view_group.set_sensitive(True)
uimanager.insert_action_group(self.cat_view_group, 1)
action = ('ViewInCatagory', self.cb_view_clicked, '',
str(cat_num) + ' ' + str(view_num))
self.cat_view_group = ActionGroup('viewmenu', [action])
uimanager.insert_action_group(self.cat_view_group)
mergeid = uimanager.add_ui_from_string(self.ui_category[cat_num])
self.merge_ids.append(mergeid)
@@ -245,12 +263,12 @@ class Navigator:
return
sidebar.view_changed(cat_num, view_num)
def cb_view_clicked(self, radioaction, current, cat_num):
def cb_view_clicked(self, radioaction, value):
"""
Called when a view is selected from the menu.
"""
view_num = radioaction.get_current_value()
self.viewmanager.goto_page(cat_num, view_num)
cat_num, view_num = value.get_string().split()
self.viewmanager.goto_page(int(cat_num), int(view_num))
def __menu_button_pressed(self, button, event):
"""
+6 -1
View File
@@ -55,7 +55,7 @@ from gi.repository import GdkPixbuf
#
#-------------------------------------------------------------------------
from gramps.gen.const import ICON, SPLASH, GRAMPS_LOCALE as glocale
from gramps.gen.const import USER_HOME, ICON, SPLASH, GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
from gramps.gen.config import config
from ...pluginmanager import GuiPluginManager
@@ -558,7 +558,12 @@ class ExportAssistant(ManagedWindow, Gtk.Assistant):
ix = self.get_selected_format_index()
ext = self.map_exporters[ix].get_extension()
# Suggested folder: try last export, then last import, then home.
default_dir = config.get('paths.recent-export-dir')
if len(default_dir)<=1:
default_dir = config.get('paths.recent-import-dir')
if len(default_dir)<=1:
default_dir = USER_HOME
if ext == 'gramps':
new_filename = os.path.join(default_dir,'data.gramps')
+31 -28
View File
@@ -63,6 +63,12 @@ from gramps.gen.plug import (CATEGORY_QR_PERSON, CATEGORY_QR_FAMILY, CATEGORY_QR
from ._textbufdoc import TextBufDoc
from gramps.gen.simple import make_basic_stylesheet
MENUITEM = ('<item>\n'
'<attribute name="action">{prefix}.{action}</attribute>\n'
'<attribute name="label" translatable="yes">'
'{label}</attribute>\n'
'</item>\n')
def flatten(L):
"""
Flattens a possibly nested list. Removes None results, too.
@@ -77,7 +83,7 @@ def flatten(L):
retval.append(L)
return retval
def create_web_connect_menu(dbstate, uistate, nav_group, handle):
def create_web_connect_menu(dbstate, uistate, nav_group, handle, prefix):
"""
This functions querries the registered web connects. It collects
the connects of the requested category, which must be one of
@@ -88,12 +94,12 @@ def create_web_connect_menu(dbstate, uistate, nav_group, handle):
handle as input method. A tuple is returned, containing the ui
string of the menu, and its associated actions.
"""
top = ("<placeholder id='WebConnect'><submenu>\n"
'<attribute name="label" translatable="yes">'
'Web Connection</attribute>\n')
actions = []
ofile = StringIO()
ofile.write('<menu action="WebConnect">')
actions.append(('WebConnect', None, _("Web Connect"), None, None, None))
menu = Gtk.Menu()
menu.show()
ofile.write(top)
#select the web connects to show
showlst = []
pmgr = GuiPluginManager.get_instance()
@@ -109,16 +115,17 @@ def create_web_connect_menu(dbstate, uistate, nav_group, handle):
connections.sort(key=lambda plug: plug.name)
actions = []
for connect in connections:
ofile.write('<menuitem action="%s"/>' % connect.key)
actions.append((connect.key, None, connect.name, None, None,
connect(dbstate, uistate, nav_group, handle)))
ofile.write('</menu>')
retval = [ofile.getvalue()]
retval.extend(actions)
return retval
action = connect.key.replace(' ', '-')
ofile.write(MENUITEM.format(prefix=prefix, action=action,
label=connect.name))
callback = connect(dbstate, uistate, nav_group, handle)
actions.append((action,
lambda x, y: callback(x)))
ofile.write('</submenu></placeholder>\n')
return (ofile.getvalue(), actions)
def create_quickreport_menu(category, dbstate, uistate, handle, track=[]):
def create_quickreport_menu(category, dbstate, uistate, handle, prefix, track=[]):
""" This functions querries the registered quick reports with
quick_report_list of _PluginMgr.py
It collects the reports of the requested category, which must be one of
@@ -132,39 +139,35 @@ def create_quickreport_menu(category, dbstate, uistate, handle, track=[]):
A tuple is returned, containing the ui string of the quick report menu,
and its associated actions
"""
top = ("<submenu>\n"
'<attribute name="label" translatable="yes">'
'Quick View</attribute>\n')
actions = []
ofile = StringIO()
ofile.write('<menu action="QuickReport">')
actions.append(('QuickReport', None, _("Quick View"), None, None, None))
menu = Gtk.Menu()
menu.show()
ofile.write(top)
#select the reports to show
showlst = []
pmgr = GuiPluginManager.get_instance()
for pdata in pmgr.get_reg_quick_reports():
if pdata.supported and pdata.category == category :
#add tuple function, translated name, name, status
showlst.append(pdata)
showlst.sort(key=lambda x: x.name)
for pdata in showlst:
new_key = pdata.id.replace(' ', '-')
ofile.write('<menuitem action="%s"/>' % new_key)
actions.append((new_key, None, pdata.name, None, None,
make_quick_report_callback(pdata, category, dbstate,
uistate, handle, track=track)))
ofile.write('</menu>')
ofile.write(MENUITEM.format(prefix=prefix, action=new_key,
label=pdata.name))
actions.append((new_key, make_quick_report_callback(
pdata, category, dbstate, uistate, handle, track=track)))
ofile.write('</submenu>\n')
return (ofile.getvalue(), actions)
def make_quick_report_callback(pdata, category, dbstate, uistate, handle,
track=[]):
return lambda x: run_report(dbstate, uistate, category, handle, pdata,
track=track)
return lambda x, y: run_report(dbstate, uistate, category, handle, pdata,
track=track)
def get_quick_report_list(qv_category=None):
"""
-4
View File
@@ -344,7 +344,6 @@ class QuickTable(SimpleTable):
self.simpledoc = document
buffer = self.simpledoc.doc.buffer
text_view = self.simpledoc.doc.text_view
text_view.set_sensitive(False)
model_index = 1 # start after index
if self._sort_col:
sort_index = self._columns.index(self._sort_col)
@@ -429,6 +428,3 @@ class QuickTable(SimpleTable):
text_view.show_all()
self.simpledoc.paragraph("")
self.simpledoc.paragraph("")
while Gtk.events_pending():
Gtk.main_iteration()
text_view.set_sensitive(True)
+2 -18
View File
@@ -59,8 +59,6 @@ from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
from ...listmodel import ListModel
from gramps.gen.errors import FilterError, ReportError
from gramps.gen.const import URL_MANUAL_PAGE
from ...display import display_help
from ...pluginmanager import GuiPluginManager
from ...dialog import WarningDialog, ErrorDialog, QuestionDialog2
from gramps.gen.plug.menu import PersonOption, FamilyOption
@@ -87,10 +85,6 @@ _UNSUPPORTED = _("Unsupported")
_RETURN = Gdk.keyval_from_name("Return")
_KP_ENTER = Gdk.keyval_from_name("KP_Enter")
WIKI_HELP_PAGE = URL_MANUAL_PAGE + "_-_Reports_-_part_3"
WIKI_HELP_SEC = _('Books')
GENERATE_WIKI_HELP_SEC = _('Generate_Book_dialog')
#------------------------------------------------------------------------
#
# Private Functions
@@ -179,7 +173,6 @@ class BookListDisplay:
"on_booklist_ok_clicked" : self.on_booklist_ok_clicked,
"on_booklist_delete_clicked" : self.on_booklist_delete_clicked,
"on_book_ok_clicked" : self.do_nothing,
"on_book_help_clicked" : self.do_nothing,
"destroy_passed_object" : self.do_nothing,
"on_setup_clicked" : self.do_nothing,
"on_down_clicked" : self.do_nothing,
@@ -349,8 +342,6 @@ class BookSelector(ManagedWindow):
"on_save_clicked" : self.on_save_clicked,
"on_open_clicked" : self.on_open_clicked,
"on_edit_clicked" : self.on_edit_clicked,
"on_book_help_clicked" : lambda x: display_help(WIKI_HELP_PAGE,
WIKI_HELP_SEC),
"on_book_ok_clicked" : self.on_book_ok_clicked,
"destroy_passed_object" : self.on_close_clicked,
@@ -938,10 +929,7 @@ class BookDialog(DocReportDialog):
'book', self.title, track=track)
self.options.options_dict['bookname'] = self.book.get_name()
while True:
response = self.window.run()
if response != Gtk.ResponseType.HELP:
break
response = self.window.run()
if response == Gtk.ResponseType.OK:
handler = self.options.handler
if self.book.get_paper_name() != handler.get_paper_name():
@@ -963,8 +951,7 @@ class BookDialog(DocReportDialog):
self.make_book()
except (IOError, OSError) as msg:
ErrorDialog(str(msg), parent=self.window)
if response != Gtk.ResponseType.DELETE_EVENT: # already closed
self.close()
self.close()
def setup_style_frame(self):
pass
@@ -987,9 +974,6 @@ class BookDialog(DocReportDialog):
whether the document requires table support, etc."""
self.format_menu = _BookFormatComboBox(active)
def on_help_clicked(self, *obj):
display_help(WIKI_HELP_PAGE, GENERATE_WIKI_HELP_SEC)
def make_document(self):
"""Create a document of the type requested by the user."""
user = User(uistate=self.uistate)
+1 -4
View File
@@ -581,10 +581,7 @@ class ReportDialog(ManagedWindow):
pass
def on_help_clicked(self, *obj):
from ...display import display_help, display_url
if hasattr(self.options, 'help_url'):
display_url(self.options.help_url)
return
from ...display import display_help
display_help(URL_REPORT_PAGE, self.report_name.replace(" ", "_"))
def on_style_edit_clicked(self, *obj):
-10
View File
@@ -58,10 +58,6 @@ from ...listmodel import ListModel
from ...managedwindow import ManagedWindow
from ...glade import Glade
from ...dialog import ErrorDialog
from ...display import display_help
from gramps.gen.const import URL_MANUAL_PAGE
WIKI_HELP_PAGE = URL_MANUAL_PAGE + "_-_Settings"
#------------------------------------------------------------------------
#
@@ -104,11 +100,8 @@ class StyleListDisplay(ManagedWindow):
"on_button_press" : self.on_button_press,
"on_edit_clicked" : self.on_edit_clicked,
"on_cancel_clicked" : self.__cancel,
"on_help_btn_clicked" : lambda x: display_help(
WIKI_HELP_PAGE, _('manual|Document_Styles_dialog')),
"on_cancel_style_clicked" : dummy_callback,
"on_save_style_clicked" : dummy_callback,
"on_help_btn_style_clicked" : dummy_callback,
})
self.list = ListModel(self.top.get_object("list"),
@@ -237,15 +230,12 @@ class StyleEditor(ManagedWindow):
self.top.connect_signals({
"on_save_style_clicked" : self.on_save_style_clicked,
"on_cancel_style_clicked" : self.__cancel,
"on_help_btn_style_clicked" : lambda x: display_help(
WIKI_HELP_PAGE, _('manual|Style_editor_dialog')),
"on_cancel_clicked" : dummy_callback,
"on_ok_clicked" : dummy_callback,
"on_add_clicked" : dummy_callback,
"on_delete_clicked" : dummy_callback,
"on_button_press" : dummy_callback,
"on_edit_clicked" : dummy_callback,
"on_help_btn_clicked" : dummy_callback,
})
self.pname = self.top.get_object('pname')
-9
View File
@@ -36,8 +36,6 @@ from ..managedwindow import ManagedWindow
from ..filters import SearchBar
from ..glade import Glade
from ..widgets.interactivesearchbox import InteractiveSearchBox
from ..display import display_help
from gramps.gen.const import URL_MANUAL_PAGE
#-------------------------------------------------------------------------
#
@@ -88,9 +86,6 @@ class BaseSelector(ManagedWindow):
self.tree.set_headers_clickable(True)
self.tree.connect('row-activated', self._on_row_activated)
self.tree.grab_focus()
self.define_help_button(
self.glade.get_object('help'), self.WIKI_HELP_PAGE,
self.WIKI_HELP_SEC)
# connect to signal for custom interactive-search
self.searchbox = InteractiveSearchBox(self.tree)
@@ -363,7 +358,3 @@ class BaseSelector(ManagedWindow):
def close(self, *obj):
ManagedWindow.close(self)
self._cleanup_on_exit()
def define_help_button(self, button, webpage='', section=''):
""" Setup to deal with help button """
button.connect('clicked', lambda x: display_help(webpage, section))
+3 -3
View File
@@ -39,6 +39,7 @@ from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.sgettext
from ..views.treemodels import CitationTreeModel
from .baseselector import BaseSelector
from ..display import display_help
from gramps.gen.const import URL_MANUAL_SECT2
#-------------------------------------------------------------------------
@@ -46,6 +47,8 @@ from gramps.gen.const import URL_MANUAL_SECT2
# Constants
#
#-------------------------------------------------------------------------
WIKI_HELP_PAGE = URL_MANUAL_SECT2
WIKI_HELP_SEC = _('manual|Select_Source_or_Citation_selector')
#-------------------------------------------------------------------------
#
@@ -81,6 +84,3 @@ class SelectCitation(BaseSelector):
return self.db.get_source_from_handle(handle)
else:
return self.db.get_citation_from_handle(handle)
WIKI_HELP_PAGE = URL_MANUAL_SECT2
WIKI_HELP_SEC = _('manual|Select_Source_or_Citation_selector')
+3 -3
View File
@@ -34,6 +34,7 @@ from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.sgettext
from ..views.treemodels import EventModel
from .baseselector import BaseSelector
from ..display import display_help
from gramps.gen.const import URL_MANUAL_SECT1
#-------------------------------------------------------------------------
@@ -41,6 +42,8 @@ from gramps.gen.const import URL_MANUAL_SECT1
# Constants
#
#-------------------------------------------------------------------------
WIKI_HELP_PAGE = URL_MANUAL_SECT1
WIKI_HELP_SEC = _('manual|Select_Event_selector')
#-------------------------------------------------------------------------
#
@@ -74,6 +77,3 @@ class SelectEvent(BaseSelector):
def get_from_handle_func(self):
return self.db.get_event_from_handle
WIKI_HELP_PAGE = URL_MANUAL_SECT1
WIKI_HELP_SEC = _('manual|Select_Event_selector')
+3 -3
View File
@@ -34,6 +34,7 @@ from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.sgettext
from ..views.treemodels import FamilyModel
from .baseselector import BaseSelector
from ..display import display_help
from gramps.gen.const import URL_MANUAL_PAGE
#-------------------------------------------------------------------------
@@ -41,6 +42,8 @@ from gramps.gen.const import URL_MANUAL_PAGE
# Constants
#
#-------------------------------------------------------------------------
WIKI_HELP_PAGE = '%s_-_Categories' % URL_MANUAL_PAGE
WIKI_HELP_SEC = _('manual|Select_Family_selector')
#-------------------------------------------------------------------------
#
@@ -71,6 +74,3 @@ class SelectFamily(BaseSelector):
def get_from_handle_func(self):
return self.db.get_family_from_handle
WIKI_HELP_PAGE = '%s_-_Categories' % URL_MANUAL_PAGE
WIKI_HELP_SEC = _('manual|Select_Family_selector')
+3 -3
View File
@@ -37,6 +37,7 @@ from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.sgettext
from ..views.treemodels import NoteModel
from .baseselector import BaseSelector
from ..display import display_help
from gramps.gen.const import URL_MANUAL_SECT1
#-------------------------------------------------------------------------
@@ -44,6 +45,8 @@ from gramps.gen.const import URL_MANUAL_SECT1
# Constants
#
#-------------------------------------------------------------------------
WIKI_HELP_PAGE = URL_MANUAL_SECT1
WIKI_HELP_SEC = _('manual|Select_Note_selector')
#-------------------------------------------------------------------------
#
@@ -77,6 +80,3 @@ class SelectNote(BaseSelector):
def get_from_handle_func(self):
return self.db.get_note_from_handle
WIKI_HELP_PAGE = URL_MANUAL_SECT1
WIKI_HELP_SEC = _('manual|Select_Note_selector')
+3 -3
View File
@@ -48,6 +48,7 @@ from gramps.gen.utils.file import media_path_full
from gramps.gen.utils.thumbnails import get_thumbnail_image
from ..views.treemodels import MediaModel
from .baseselector import BaseSelector
from ..display import display_help
from gramps.gen.const import URL_MANUAL_SECT1
#-------------------------------------------------------------------------
@@ -55,6 +56,8 @@ from gramps.gen.const import URL_MANUAL_SECT1
# Constants
#
#-------------------------------------------------------------------------
WIKI_HELP_PAGE = URL_MANUAL_SECT1
WIKI_HELP_SEC = _('manual|Select_Media_Object_selector')
#-------------------------------------------------------------------------
#
@@ -103,6 +106,3 @@ class SelectObject(BaseSelector):
pix = get_thumbnail_image(media_path_full(self.db, obj.get_path()))
self.preview.set_from_pixbuf(pix)
gc.collect()
WIKI_HELP_PAGE = URL_MANUAL_SECT1
WIKI_HELP_SEC = _('manual|Select_Media_Object_selector')
+12 -9
View File
@@ -36,6 +36,7 @@ from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.sgettext
from ..views.treemodels import PeopleBaseModel, PersonTreeModel
from .baseselector import BaseSelector
from ..display import display_help
from gramps.gen.const import URL_MANUAL_SECT1
#-------------------------------------------------------------------------
@@ -44,6 +45,17 @@ from gramps.gen.const import URL_MANUAL_SECT1
#
#-------------------------------------------------------------------------
# This dialog changes depending on the string pass for the title.
# https://gramps-project.org/wiki/index.php?title=Gramps_4.2_Wiki_Manual_-_Entering_and_editing_data:_detailed_-_part_1#Select_Child_selector
# https://gramps-project.org/wiki/index.php?title=Gramps_4.2_Wiki_Manual_-_Entering_and_editing_data:_detailed_-_part_1#Select_Father_selector
# https://gramps-project.org/wiki/index.php?title=Gramps_4.2_Wiki_Manual_-_Entering_and_editing_data:_detailed_-_part_1#Select_Mother_selector
WIKI_HELP_PAGE = URL_MANUAL_SECT1
WIKI_HELP_SEC = _('manual|Select_Child_selector')
WIKI_HELP_PAGE2 = URL_MANUAL_SECT1
WIKI_HELP_SEC2 = _('manual|Select_Father_selector')
WIKI_HELP_PAGE3 = URL_MANUAL_SECT1
WIKI_HELP_SEC3 = _('manual|Select_Mother_selector')
#-------------------------------------------------------------------------
#
@@ -59,15 +71,6 @@ class SelectPerson(BaseSelector):
# instead of the default defined for get_window_title()
if title is not None:
self.title = title
self.WIKI_HELP_PAGE = URL_MANUAL_SECT1
if title == _("Select Father"):
self.WIKI_HELP_SEC = _('manual|Select_Father_selector')
elif title == _("Select Mother"):
self.WIKI_HELP_SEC = _('manual|Select_Mother_selector')
elif title == _("Select Child"):
self.WIKI_HELP_SEC = _('manual|Select_Child_selector')
else:
self.WIKI_HELP_SEC = _('manual|Select_Person_selector')
BaseSelector.__init__(self, dbstate, uistate, track, filter,
skip, show_search_bar, default)
+3 -15
View File
@@ -35,6 +35,7 @@ from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.sgettext
from ..views.treemodels.placemodel import PlaceTreeModel
from .baseselector import BaseSelector
from ..display import display_help
from gramps.gen.const import URL_MANUAL_SECT2
#-------------------------------------------------------------------------
@@ -42,6 +43,8 @@ from gramps.gen.const import URL_MANUAL_SECT2
# Constants
#
#-------------------------------------------------------------------------
WIKI_HELP_PAGE = URL_MANUAL_SECT2
WIKI_HELP_SEC = _('manual|Select_Place_selector')
#-------------------------------------------------------------------------
#
@@ -73,18 +76,3 @@ class SelectPlace(BaseSelector):
def get_from_handle_func(self):
return self.db.get_place_from_handle
def setup_filter(self):
"""Build the default filters and add them to the filter menu.
This overrides the baseselector method because we use the hidden
COL_SEARCH (11) that has alt names as well as primary name for name
searching"""
cols = [(pair[3],
pair[1] if pair[1] else 11,
pair[0] in self.exact_search())
for pair in self.column_order() if pair[0]
]
self.search_bar.setup_filter(cols)
WIKI_HELP_PAGE = URL_MANUAL_SECT2
WIKI_HELP_SEC = _('manual|Select_Place_selector')
+3 -3
View File
@@ -34,6 +34,7 @@ from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.sgettext
from ..views.treemodels import RepositoryModel
from .baseselector import BaseSelector
from ..display import display_help
from gramps.gen.const import URL_MANUAL_SECT2
#-------------------------------------------------------------------------
@@ -41,6 +42,8 @@ from gramps.gen.const import URL_MANUAL_SECT2
# Constants
#
#-------------------------------------------------------------------------
WIKI_HELP_PAGE = URL_MANUAL_SECT2
WIKI_HELP_SEC = _('manual|Repositories')
#-------------------------------------------------------------------------
#
@@ -70,6 +73,3 @@ class SelectRepository(BaseSelector):
def get_from_handle_func(self):
return self.db.get_repository_from_handle
WIKI_HELP_PAGE = URL_MANUAL_SECT2
WIKI_HELP_SEC = _('manual|Select_Repository_selector')
+4 -4
View File
@@ -34,13 +34,16 @@ from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.sgettext
from ..views.treemodels import SourceModel
from .baseselector import BaseSelector
from gramps.gen.const import URL_MANUAL_SECT2
from ..display import display_help
from gramps.gen.const import URL_MANUAL_PAGE
#-------------------------------------------------------------------------
#
# Constants
#
#-------------------------------------------------------------------------
# WIKI_HELP_PAGE = '%s_-_xxx' % URL_MANUAL_PAGE # FIXME
# WIKI_HELP_SEC = _('manual|xxxx') # FIXME
#-------------------------------------------------------------------------
#
@@ -71,6 +74,3 @@ class SelectSource(BaseSelector):
def get_from_handle_func(self):
return self.db.get_source_from_handle
WIKI_HELP_PAGE = URL_MANUAL_SECT2
WIKI_HELP_SEC = _('manual|Select_Source_selector')
+517
View File
@@ -0,0 +1,517 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2018 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
# 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.
#
"""
A replacement UIManager and ActionGroup.
"""
import copy
import sys
from ..gen.config import config
import logging
import xml.etree.ElementTree as ET
from gi.repository import GLib, Gio, Gtk
from ..gen.config import config
LOG = logging.getLogger('gui.uimanager')
ACTION_NAME = 0 # tuple index for action name
ACTION_CB = 1 # tuple index for action callback
ACTION_ACC = 2 # tuple index for action accelerator
ACTION_ST = 3 # tuple index for action state
class ActionGroup():
""" This class represents a group of actions that con be manipulated
together.
"""
def __init__(self, name, actionlist=None, prefix='win'):
"""
@param name: the action group name, used to match to the 'groups'
attribute in the ui xml.
@type name: string
@type actionlist: list
@param actionlist: the list of actions to add
The list contains tuples with the following contents:
string: Action Name
method: signal callback function.
None if just adding an accelerator
string: accelerator ex: '<Primary>Enter' or '' for no accelerator.
optional for non-stateful actions.
state: initial state for stateful actions.
'True' or 'False': the action is interpreted as a checkbox.
'None': non stateful action (optional)
'string': the action is interpreted as a Radio button
@type prefix: str
@param prefix: the prefix used by this group. If not provided, 'win'
is assumed.
"""
self.name = name
self.actionlist = actionlist if actionlist else []
self.prefix = prefix + '.'
self.act_group = None
self.sensitive = True
def add_actions(self, actionlist):
""" Add a list of actions to the current list
@type actionlist: list
@param actionlist: the list of actions to add
"""
self.actionlist.extend(actionlist)
class UIManager():
"""
This is Gramps UIManager, it is designed to replace the deprecated Gtk
UIManager. The replacement is not exact, but performs similar
functions, in some case with the same method names and parameters.
It is designed to be a singleton. The menu portion of this is responsible
only for Gramps main window menus and toolbar.
This was implemented to extend Gtk.Builder functions to allow editing
(merging) of the original builder XML with additional XML fragments during
operations. This allows changing of the menus and toolbar when the tree is
loaded, views are changed etc.
The ActionGroup portions can also be used by other windows. Other windows
needing menus or toolbars can create them via Gtk.Builder.
"""
def __init__(self, app, initial_xml):
"""
@param app: Gramps Gtk.Application reference
@type app: Gtk.Application
@param initial_xml: Initial (primary) XML string for Gramps menus and
toolbar
@type changexml: string
The xml is basically Gtk Builder xml, in particular the various menu
and toolbar elements. It is possible to add other elements as well.
The xml this supports has been extended in two ways;
1) there is an added "groups=" attribute to elements. This
attribute associates the element with one or more named ActionGroups
for making the element visible or not. If 'groups' is missing, the
element will be shown as long as enclosing elements are shown. The
element will be shown if the group is present and considered visible
by the uimanager. If more than one group is needed, they should be
separated by a space.
2) there is an added <placeholder> tag supported; this is used to mark
a place where merged UI XML can be inserted. During the update_menu
processing, elements enclosed in this tag pair are promoted to the
level of the placeholder tag, and the placeholder tag is removed.
Note that any elements can be merged (replaced) by the
add_ui_from_string method, not just placeholders. This works by
matching the "id=" attribute on the element, and replacing the
original element with the one from the add method.
Note that when added elements are removed by the remove_ui method, they
are replaced by the containing xml (with the 'id=') only, so don't put
anything inside of the containing xml to start with as it will be lost
during editing.
"""
self.app = app # the Gtk.Application of Gramps
self.et_xml = ET.fromstring(initial_xml)
self.builder = None
self.toolbar = None
self.action_groups = [] # current list of action groups
self.show_groups = [] # groups to show at the moment
self.accel_dict = {} # used to store accel overrides from file
def update_menu(self, init=False):
""" This updates the menus and toolbar when there is a change in the
ui; any addition or removal or set_visible operation needs to call
this. It is best to make the call only once, at the end, if multiple
changes are to be made.
It starts with the ET xml stored in self, cleans it up to meet the
Gtk.Builder specifications, and then updates the ui.
@param init: When True, this is first call and we set the builder
toolbar and menu to the application.
When False, we update the menus and toolbar
@type init: bool
"""
def iterator(parents):
""" This recursively goes through the ET xml and deals with the
'groups' attribute and <placeholder> tags, which are not valid for
builder. Empty submenus are also removed.
Groups processing removes elements that are not shown, as well as
the 'groups' attribute itself.
<placeholder> tags are removed and their enclosed elements are
promoted to the level of the placeholder.
@param parents: the current element to recursively process
@type parents: ET element
"""
indx = 0
while indx < len(parents):
child = parents[indx]
if len(child) >= 1:
# Recurse until we have a stand-alone child
iterator(child)
if((len(child) == 1 and child.tag == "submenu") or
(len(child) == 0 and child.tag == "section")):
# remove empty submenus and sections
# print('del', child.tag, child.attrib)
del parents[indx]
continue
# print(child.attrib)
groups = child.get('groups')
if not groups:
indx += 1
continue
del child.attrib['groups']
for group in groups.split(' '):
if group in self.show_groups:
indx += 1
break
else:
#print('del', child.tag, child.attrib, parents.tag,
# parents.attrib)
del parents[indx]
break
# The following looks for 'placeholder' elements and if found,
# promotes any children to the same level as the placeholder.
# this allows the user to insert elements without using a section.
indx = 0
while indx < len(parents):
if parents[indx].tag == "placeholder":
subtree = parents[indx]
#print('placholder del', parents[indx].tag,
# parents[indx].attrib, parents.tag, parents.attrib)
del parents[indx]
for child in subtree:
parents.insert(indx, child)
indx += 1
else:
indx += 1
if self.builder:
toolbar = self.builder.get_object("ToolBar") # previous toolbar
# need to copy the tree so we can preserve original for later edits.
editable = copy.deepcopy(self.et_xml)
iterator(editable) # clean up tree to builder specifications
xml_str = ET.tostring(editable, encoding="unicode")
#print(xml_str)
self.builder = Gtk.Builder.new_from_string(xml_str, -1)
if init:
self.app.menubar = self.builder.get_object("menubar")
self.app.set_menubar(self.app.menubar)
return
# The following is the only way I have found to update the menus.
# app.set_menubar can apparently only be used once, before
# ApplicationWindow creation, further uses do NOT cause the menus to
# update.
self.app.menubar.remove_all()
section = self.builder.get_object('menubar-update')
self.app.menubar.append_section(None, section)
# the following updates the toolbar from the new builder
toolbar_parent = toolbar.get_parent()
tb_show = toolbar.get_visible()
toolbar_parent.remove(toolbar)
toolbar = self.builder.get_object("ToolBar") # new toolbar
if config.get('interface.toolbar-text'):
toolbar.set_style(Gtk.ToolbarStyle.BOTH)
toolbar_parent.pack_start(toolbar, False, True, 0)
if tb_show:
toolbar.show_all()
else:
toolbar.hide()
#print('*** Update ui')
def add_ui_from_string(self, changexml):
""" This performs a merge operation on the xml elements that have
matching 'id's between the current ui xml and change xml strings.
The 'changexml' is a list of xml fragment strings used to replace
matching elements in the current xml.
There MUST one and only one matching id in the orig xml.
@param changexml: list of xml fragments to merge into main
@type changexml: list
@return: changexml
"""
try:
for xml in changexml:
if not xml:
# allow an xml fragment to be an empty string
continue
update = ET.fromstring(xml)
el_id = update.attrib['id']
# find the parent of the id'd element in original xml
parent = self.et_xml.find(".//*[@id='%s'].." % el_id)
if parent:
# we found it, now delete original, inset updated
for indx in range(len(parent)):
if parent[indx].get('id') == el_id:
del parent[indx]
parent.insert(indx, update)
else:
# updated item not present in original, just add it
# This allow addition of popups etc.
self.et_xml.append(update)
#results = ET.tostring(self.et_xml, encoding="unicode")
#print(results)
#print ('*** Add ui')
return changexml
except:
# the following is only here to assist debug
print('*****', sys.exc_info())
print(xml)
print(changexml)
assert False
def remove_ui(self, change_xml):
""" This removes the 'change_xml' from the current ui xml. It works on
any element with matching 'id', the actual element remains but any
children are removed.
The 'change_xml' is a list of xml strings originally used to replace
matching elements in the current ui xml.
@param change_xml: list of xml fragments to remove from main
@type change_xml: list
"""
# if not change_xml:
# import pydevd
# pydevd.settrace()
for xml in change_xml:
if not xml:
continue
update = ET.fromstring(xml)
el_id = update.attrib['id']
# find parent of id'd element
element = self.et_xml.find(".//*[@id='%s']" % el_id)
if element: # element may have already been deleted
for dummy in range(len(element)):
del element[0]
#results = ET.tostring(self.et_xml, encoding="unicode")
#print(results)
#print ('*** Remove ui')
return
def get_widget(self, obj):
""" Get the object from the builder.
@param obj: the widget to get
@type obj: string
@return: the object
"""
return self.builder.get_object(obj)
def insert_action_group(self, group, gio_group=None):
"""
This inserts (actually overwrites any matching actions) the action
group's actions to the app.
By default (with no gio_group), the action group is added to the main
Gramps window and the group assumes a 'win' prefix.
If not using the main window, the window MUST have the 'application'
property set for the accels to work. In this case the actiongroups
must be created like the following:
# create Gramps ActionGroup
self.action_group = ActionGroup('name', actions, 'prefix')
# create Gio action group
act_grp = SimpleActionGroup()
# associate window with Gio group and its prefix
window.insert_action_group('prefix', act_grp)
# make the window 'application' aware
window.set_application(uimanager.app)
# tell the uimanager about the groups.
uimanager.insert_action_group(self.action_group, act_grp)
@param group: the action group
@type group: ActionGroup
@param gio_group: the Gio action group associated with a window.
@type gio_group: Gio.SimpleActionGroup
"""
try:
assert isinstance(group.actionlist, list)
if gio_group:
window_group = group.act_group = gio_group
elif group.act_group:
window_group = group.act_group
else:
window_group = group.act_group = self.app.window
for item in group.actionlist:
# deal with accelerator overrides from a file
accel = self.accel_dict.get(group.prefix + item[ACTION_NAME])
if accel:
self.app.set_accels_for_action(
group.prefix + item[ACTION_NAME], [accel])
elif len(item) > 2 and item[ACTION_ACC]:
# deal with accelerators defined in the group
accels = self.app.get_actions_for_accel(item[ACTION_ACC])
if accels:
# diagnostic printout; a duplicate accelerator may be
# a problem if both are valid for the same window at
# the same time. If the actions are for a different
# window, this is not an error. Here we assume a
# different prefix is used for different windows.
for accel in accels:
if group.prefix in accel:
LOG.warning('**Duplicate Accelerator %s',
item[ACTION_ACC])
self.app.set_accels_for_action(
group.prefix + item[ACTION_NAME], [item[ACTION_ACC]])
if len(item) <= 3:
# Normal stateless actions
action = Gio.SimpleAction.new(item[ACTION_NAME], None)
if item[ACTION_CB]: # in case we have only accelerator
action.connect("activate", item[ACTION_CB])
elif isinstance(item[ACTION_ST], str):
# Radio Actions
action = Gio.SimpleAction.new_stateful(
item[ACTION_NAME], GLib.VariantType.new("s"),
GLib.Variant("s", item[ACTION_ST]))
action.connect("change-state", item[ACTION_CB])
elif isinstance(item[ACTION_ST], bool):
# Checkbox actions
action = Gio.SimpleAction.new_stateful(
item[ACTION_NAME], None,
GLib.Variant.new_boolean(item[ACTION_ST]))
action.connect("change-state", item[ACTION_CB])
window_group.add_action(action)
self.action_groups.append(group)
# if action sensitivity was set prior to actually inserting into
# UIManager, we need to do it now that we have the action
if not group.sensitive:
self.set_actions_sensitive(group, False)
except:
# the following is only to assist in debug
print(group.name, item)
assert False
def remove_action_group(self, group):
""" This removes the ActionGroup from the UIManager
@param group: the action group
@type group: ActionGroup
"""
if group.act_group:
window_group = group.act_group
else:
window_group = self.app.window
for item in group.actionlist:
window_group.remove_action(item[ACTION_NAME])
self.app.set_accels_for_action(group.prefix + item[ACTION_NAME],
[])
self.action_groups.remove(group)
def get_action_groups(self):
""" This returns a list of action Groups installed into the UIManager.
@return: list of groups
"""
return self.action_groups
def set_actions_sensitive(self, group, value):
""" This sets an ActionGroup enabled or disabled. A disabled action
will be greyed out in the UI.
@param group: the action group
@type group: ActionGroup
@param value: the state of the group
@type value: bool
"""
if group.act_group:
for item in group.actionlist:
action = group.act_group.lookup_action(item[ACTION_NAME])
if action:
# We check in case the group has not been inserted into
# UIManager yet
action.set_enabled(value)
group.sensitive = value
def get_actions_sensitive(self, group):
""" This gets an ActionGroup sensitive setting. A disabled action
will be greyed out in the UI.
We assume that the first action represents the group.
@param group: the action group
@type group: ActionGroup
@return: the state of the group
"""
item = group.actionlist[0]
action = group.act_group.lookup_action(item[ACTION_NAME])
return action.get_enabled()
def set_actions_visible(self, group, value):
""" This sets an ActionGroup visible and enabled or invisible and
disabled. Make sure that the menuitems or sections and toolbar items
have the 'groups=' xml attribute matching the group name for this to
work correctly.
@param group: the action group
@type group: ActionGroup
@param value: the state of the group
@type value: bool
"""
self.set_actions_sensitive(group, value)
if value:
if group.name not in self.show_groups:
self.show_groups.append(group.name)
else:
if group.name in self.show_groups:
self.show_groups.remove(group.name)
def get_action(self, group, actionname):
""" Return a single action from the group.
@param group: the action group
@type group: ActionGroup
@param actionname: the action name
@type actionname: string
@return: Gio.Action
"""
return group.act_group.lookup_action(actionname)
def dump_all_accels(self):
''' A function used diagnostically to see what accels are present.
This will only dump the current accel set, if other non-open windows
or views have accels, you will need to open them and run this again
and manually merge the result files. The results are in a
'gramps.accel' file located in the current working directory.'''
out_dict = {}
for group in self.action_groups:
for item in group.actionlist:
act = group.prefix + item[ACTION_NAME]
accels = self.app.get_accels_for_action(
group.prefix + item[ACTION_NAME])
out_dict[act] = accels[0] if accels else ''
import json
with open('gramps.accel', 'w', ) as hndl:
accels = json.dumps(out_dict, indent=0).replace('\n"', '\n# "')
hndl.write(accels)
def load_accels(self, filename):
""" This function loads accels from a file such as created by
dump_all_accels. The file contents is basically a Python dict
definition. As such it contains a line for each dict element.
These elements can be commented out with '#' at the beginning of the
line.
If used, this file overrides the accels defined in other Gramps code.
As such it must be loaded before any insert_action_group calls.
"""
import ast
with open(filename, 'r') as hndl:
accels = hndl.read()
self.accel_dict = ast.literal_eval(accels)
+281 -559
View File
File diff suppressed because it is too large Load Diff
+23 -19
View File
@@ -28,6 +28,7 @@
#-------------------------------------------------------------------------
from abc import ABCMeta, abstractmethod
from io import StringIO
import html
#-------------------------------------------------------------------------
#
@@ -51,6 +52,7 @@ from gi.repository import Gtk
from ..display import display_help
from ..listmodel import ListModel
from ..managedwindow import ManagedWindow
from ..uimanager import ActionGroup
from gramps.gen.utils.db import navigation_label
from gramps.gen.const import URL_MANUAL_PAGE
from gramps.gen.const import GRAMPS_LOCALE as glocale
@@ -72,9 +74,6 @@ WIKI_HELP_SEC = _('manual|Bookmarks')
#
#-------------------------------------------------------------------------
TOP = '''<ui><menubar name="MenuBar"><menu action="BookMenu">'''
BTM = '''</menu></menubar></ui>'''
DISABLED = -1
class Bookmarks(metaclass=ABCMeta):
@@ -94,7 +93,7 @@ class Bookmarks(metaclass=ABCMeta):
if self.dbstate.is_open():
self.update_bookmarks()
self.active = DISABLED
self.action_group = Gtk.ActionGroup(name='Bookmarks')
self.action_group = ActionGroup(name='Bookmarks')
if self.dbstate.is_open():
self.connect_signals()
self.dbstate.connect('database-changed', self.db_changed)
@@ -130,7 +129,8 @@ class Bookmarks(metaclass=ABCMeta):
"""
Redraw the display.
"""
self.redraw()
# used by navigationview; other updates follow
self.redraw(update_menu=False)
def undisplay(self):
"""
@@ -139,8 +139,7 @@ class Bookmarks(metaclass=ABCMeta):
if self.active != DISABLED:
self.uistate.uimanager.remove_ui(self.active)
self.uistate.uimanager.remove_action_group(self.action_group)
self.action_group = Gtk.ActionGroup(name='Bookmarks')
self.uistate.uimanager.ensure_update()
self.action_group = ActionGroup(name='Bookmarks')
self.active = DISABLED
def redraw_and_report_change(self):
@@ -148,10 +147,14 @@ class Bookmarks(metaclass=ABCMeta):
self.dbstate.db.report_bm_change()
self.redraw()
def redraw(self):
def redraw(self, update_menu=True):
"""Create the pulldown menu."""
menuitem = ('<item>\n'
'<attribute name="action">win.%s</attribute>\n'
'<attribute name="label" translatable="yes">'
'%s</attribute>\n'
'</item>\n')
text = StringIO()
text.write(TOP)
self.undisplay()
@@ -160,27 +163,28 @@ class Bookmarks(metaclass=ABCMeta):
bad_bookmarks = [] # list of bad bookmarks
if self.dbstate.is_open() and len(self.bookmarks.get()) > 0:
text.write('<placeholder name="GoToBook">')
text.write('<section id="GoToBook">\n')
for item in self.bookmarks.get():
try:
label, dummy_obj = self.make_label(item)
func = self.callback(item)
action_id = "BM:%s" % item
actions.append((action_id, None, label, None, None, func))
text.write('<menuitem action="%s"/>' % action_id)
action_id = "BM.%s" % item
actions.append((action_id, func))
text.write(menuitem % (action_id, html.escape(label)))
count += 1
except AttributeError:
pass
except HandleError:
# if bookmark contains handle to something missing now
bad_bookmarks.append(item)
text.write('</placeholder>')
text.write('</section>\n')
text.write(BTM)
self.action_group.add_actions(actions)
self.uistate.uimanager.insert_action_group(self.action_group, 1)
self.active = self.uistate.uimanager.add_ui_from_string(text.getvalue())
self.uistate.uimanager.ensure_update()
self.uistate.uimanager.insert_action_group(self.action_group)
self.active = self.uistate.uimanager.add_ui_from_string(
[text.getvalue()])
if update_menu:
self.uistate.uimanager.update_menu()
text.close()
# Clean up any bad bookmarks (can happen if Gramps crashes;
# modified bookmarks set is saved only on normal Gramps close)
@@ -547,4 +551,4 @@ def make_callback(handle, function):
"""
Build a unique call to the function with the associated handle.
"""
return lambda x: function(handle)
return lambda x, y: function(handle)
+73 -78
View File
@@ -30,7 +30,6 @@ Provide the base classes for GRAMPS' DataView classes
#
#----------------------------------------------------------------
from abc import abstractmethod
import os
import pickle
import time
import logging
@@ -56,7 +55,7 @@ from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.sgettext
from .pageview import PageView
from .navigationview import NavigationView
from ..actiongroup import ActionGroup
from ..uimanager import ActionGroup
from ..columnorder import ColumnOrder
from gramps.gen.config import config
from gramps.gen.errors import WindowActiveError, FilterError, HandleError
@@ -65,6 +64,7 @@ from ..widgets.menuitem import add_menuitem
from gramps.gen.const import CUSTOM_FILTERS
from gramps.gen.utils.debug import profile
from gramps.gen.utils.string import data_recover_msg
from gramps.gen.plug import CATEGORY_QR_PERSON
from ..dialog import QuestionDialog, QuestionDialog2, ErrorDialog
from ..editors import FilterEditor
from ..ddtargets import DdTargets
@@ -123,6 +123,8 @@ class ListView(NavigationView):
self.generic_filter = None
dbstate.connect('database-changed', self.change_db)
self.connect_signals()
self.at_popup_action = None
self.at_popup_menu = None
def no_database(self):
## TODO GTK3: This is never called!! Dbguielement disconnects
@@ -207,24 +209,19 @@ class ListView(NavigationView):
NavigationView.define_actions(self)
self.edit_action = ActionGroup(name=self.title + '/ChangeOrder')
self.edit_action = ActionGroup(name=self.title + '/Edits')
self.edit_action.add_actions([
('Add', 'list-add', _("_Add..."), "<PRIMARY>Insert",
self.ADD_MSG, self.add),
('Remove', 'list-remove', _("_Delete"), "<PRIMARY>Delete",
self.DEL_MSG, self.remove),
('Merge', 'gramps-merge', _('_Merge...'), None,
self.MERGE_MSG, self.merge),
('ExportTab', None, _('Export View...'), None, None,
self.export),
])
('Add', self.add, '<Primary>Insert'),
('Remove', self.remove, '<Primary>Delete'),
('PRIMARY-BackSpace', self.remove, '<PRIMARY>BackSpace'),
('Merge', self.merge), ])
self._add_action_group(self.edit_action)
self._add_action('Edit', 'gtk-edit', _("action|_Edit..."),
accel="<PRIMARY>Return",
tip=self.EDIT_MSG,
callback=self.edit)
self.action_list.extend([
('ExportTab', self.export),
('Edit', self.edit, '<Primary>Return'),
('PRIMARY-J', self.jump, '<PRIMARY>J'),
('FilterEdit', self.filter_editor)])
def build_columns(self, preserve_col=True):
"""
@@ -298,7 +295,7 @@ class ListView(NavigationView):
Called when the page is displayed.
"""
NavigationView.set_active(self)
self.uistate.viewmanager.tags.tag_enable()
self.uistate.viewmanager.tags.tag_enable(update_menu=False)
self.uistate.show_filter_results(self.dbstate,
self.model.displayed(),
self.model.total())
@@ -310,9 +307,6 @@ class ListView(NavigationView):
NavigationView.set_inactive(self)
self.uistate.viewmanager.tags.tag_disable()
def __build_tree(self):
profile(self._build_tree)
def build_tree(self, force_sidebar=False, preserve_col=True):
if self.active:
cput0 = time.clock()
@@ -379,7 +373,7 @@ class ListView(NavigationView):
"""
return 'gramps-tree-list'
def filter_editor(self, obj):
def filter_editor(self, *obj):
try:
FilterEditor(self.FILTER_TYPE , CUSTOM_FILTERS,
self.dbstate, self.uistate)
@@ -448,7 +442,7 @@ class ListView(NavigationView):
self.uistate.push_message(self.dbstate,
_("Active object not visible"))
def add_bookmark(self, obj):
def add_bookmark(self, *obj):
mlist = []
self.selection.selected_foreach(self.blist, mlist)
@@ -858,6 +852,7 @@ class ListView(NavigationView):
"""
if not self.dbstate.is_open():
return False
menu = self.uimanager.get_widget('Popup')
if event.type == Gdk.EventType._2BUTTON_PRESS and event.button == 1:
if self.model.get_flags() & Gtk.TreeModelFlags.LIST_ONLY:
self.edit(obj)
@@ -873,49 +868,54 @@ class ListView(NavigationView):
else:
self.edit(obj)
return True
elif is_right_click(event):
menu = self.uistate.uimanager.get_widget('/Popup')
if menu:
# Quick Reports
qr_menu = self.uistate.uimanager.\
get_widget('/Popup/QuickReport')
if qr_menu and self.QR_CATEGORY > -1 :
(ui, qr_actions) = create_quickreport_menu(
self.QR_CATEGORY,
self.dbstate,
self.uistate,
self.first_selected())
self.__build_menu(qr_menu, qr_actions)
elif is_right_click(event) and menu:
prefix = 'win'
self.at_popup_menu = []
actions = []
# Quick Reports
if self.QR_CATEGORY > -1:
(qr_ui, qr_actions) = create_quickreport_menu(
self.QR_CATEGORY, self.dbstate, self.uistate,
self.first_selected(), prefix)
if self.get_active() and qr_actions:
actions.extend(qr_actions)
qr_ui = ("<placeholder id='QuickReport'>%s</placeholder>" %
qr_ui)
self.at_popup_menu.append(qr_ui)
# Web Connects
web_menu = self.uistate.uimanager.\
get_widget('/Popup/WebConnect')
if web_menu:
web_actions = create_web_connect_menu(
self.dbstate,
self.uistate,
self.navigation_type(),
self.first_selected())
self.__build_menu(web_menu, web_actions)
# Web Connects
if self.QR_CATEGORY == CATEGORY_QR_PERSON:
(web_ui, web_actions) = create_web_connect_menu(
self.dbstate, self.uistate, self.navigation_type(),
self.first_selected(), prefix)
if self.get_active() and web_actions:
actions.extend(web_actions)
self.at_popup_menu.append(web_ui)
menu.popup(None, None, None, None, event.button, event.time)
return True
if self.at_popup_action:
self.uimanager.remove_ui(self.at_popup_menu)
self.uimanager.remove_action_group(self.at_popup_action)
self.at_popup_action = ActionGroup('AtPopupActions',
actions)
self.uimanager.insert_action_group(self.at_popup_action)
self.at_popup_menu = self.uimanager.add_ui_from_string(
self.at_popup_menu)
self.uimanager.update_menu()
menu = self.uimanager.get_widget('Popup')
popup_menu = Gtk.Menu.new_from_model(menu)
popup_menu.attach_to_widget(obj, None)
popup_menu.show_all()
if Gtk.MINOR_VERSION < 22:
# ToDo The following is reported to work poorly with Wayland
popup_menu.popup(None, None, None, None,
event.button, event.time)
else:
popup_menu.popup_at_pointer(event)
return True
return False
def __build_menu(self, menu, actions):
"""
Build a submenu for quick reports and web connects
"""
if self.get_active() and len(actions) > 1:
sub_menu = Gtk.Menu()
for action in actions[1:]:
add_menuitem(sub_menu, action[2], None, action[5])
menu.set_submenu(sub_menu)
menu.show()
else:
menu.hide()
def _key_press(self, obj, event):
"""
Called when a key is pressed on a listview
@@ -1009,9 +1009,6 @@ class ListView(NavigationView):
return True
return False
def key_delete(self):
self.remove(None)
def change_page(self):
"""
Called when a page is changed.
@@ -1021,8 +1018,9 @@ class ListView(NavigationView):
self.uistate.show_filter_results(self.dbstate,
self.model.displayed(),
self.model.total())
self.edit_action.set_visible(True)
self.edit_action.set_sensitive(not self.dbstate.db.readonly)
self.uimanager.set_actions_visible(self.edit_action, True)
self.uimanager.set_actions_sensitive(self.edit_action,
not self.dbstate.db.readonly)
def on_delete(self):
"""
@@ -1052,7 +1050,7 @@ class ListView(NavigationView):
####################################################################
# Export data
####################################################################
def export(self, obj):
def export(self, *obj):
chooser = Gtk.FileChooserDialog(
_("Export View as Spreadsheet"),
self.uistate.window,
@@ -1072,8 +1070,6 @@ class ListView(NavigationView):
combobox.set_active(0)
box.show_all()
chooser.set_extra_widget(box)
default_dir = config.get('paths.recent-export-dir')
chooser.set_current_folder(default_dir)
while True:
value = chooser.run()
@@ -1086,7 +1082,6 @@ class ListView(NavigationView):
else:
chooser.destroy()
return
config.set('paths.recent-export-dir', os.path.split(fn)[0])
self.write_tabbed_file(fn, fl)
def write_tabbed_file(self, name, type):
@@ -1157,25 +1152,25 @@ class ListView(NavigationView):
# Template functions
####################################################################
@abstractmethod
def edit(self, obj, data=None):
def edit(self, *obj):
"""
Template function to allow the editing of the selected object
"""
@abstractmethod
def remove(self, handle, data=None):
def remove(self, *obj):
"""
Template function to allow the removal of an object by its handle
"""
@abstractmethod
def add(self, obj, data=None):
def add(self, *obj):
"""
Template function to allow the adding of a new object
"""
@abstractmethod
def merge(self, obj, data=None):
def merge(self, *obj):
"""
Template function to allow the merger of two objects.
"""
@@ -1186,7 +1181,7 @@ class ListView(NavigationView):
Template function to allow the removal of an object by its handle
"""
def open_all_nodes(self, obj):
def open_all_nodes(self, *obj):
"""
Method for Treeviews to open all groups
obj: for use of method in event callback
@@ -1199,14 +1194,14 @@ class ListView(NavigationView):
self.uistate.set_busy_cursor(False)
self.uistate.modify_statusbar(self.dbstate)
def close_all_nodes(self, obj):
def close_all_nodes(self, *obj):
"""
Method for Treeviews to close all groups
obj: for use of method in event callback
"""
self.list.collapse_all()
def open_branch(self, obj):
def open_branch(self, *obj):
"""
Expand the selected branches and all children.
obj: for use of method in event callback
@@ -1221,7 +1216,7 @@ class ListView(NavigationView):
self.uistate.set_busy_cursor(False)
self.uistate.modify_statusbar(self.dbstate)
def close_branch(self, obj):
def close_branch(self, *obj):
"""
Collapse the selected branches.
:param obj: not used, present only to allow the use of the method in
+69 -74
View File
@@ -29,6 +29,7 @@ Provide the base classes for GRAMPS' DataView classes
#
#----------------------------------------------------------------
from abc import abstractmethod
import html
import logging
_LOG = logging.getLogger('.navigationview')
@@ -49,7 +50,7 @@ from gi.repository import Gtk
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.sgettext
from .pageview import PageView
from ..actiongroup import ActionGroup
from ..uimanager import ActionGroup
from gramps.gen.utils.db import navigation_label
from gramps.gen.constfunc import mod_key
from ..utils import match_primary_mask
@@ -57,19 +58,9 @@ from ..utils import match_primary_mask
DISABLED = -1
MRU_SIZE = 10
MRU_TOP = [
'<ui>'
'<menubar name="MenuBar">'
'<menu action="GoMenu">'
'<placeholder name="CommonHistory">'
]
MRU_TOP = '<section id="CommonHistory">'
MRU_BTM = '</section>'
MRU_BTM = [
'</placeholder>'
'</menu>'
'</menubar>'
'</ui>'
]
#------------------------------------------------------------------------------
#
# NavigationView
@@ -94,6 +85,7 @@ class NavigationView(PageView):
self.mru_signal = None
self.nav_group = nav_group
self.mru_active = DISABLED
self.uimanager = uistate.uimanager
self.uistate.register(state, self.navigation_type(), self.nav_group)
@@ -122,8 +114,8 @@ class NavigationView(PageView):
"""
PageView.disable_action_group(self)
self.fwd_action.set_visible(False)
self.back_action.set_visible(False)
self.uimanager.set_actions_visible(self.fwd_action, False)
self.uimanager.set_actions_visible(self.back_action, False)
def enable_action_group(self, obj):
"""
@@ -133,20 +125,25 @@ class NavigationView(PageView):
"""
PageView.enable_action_group(self, obj)
self.fwd_action.set_visible(True)
self.back_action.set_visible(True)
self.uimanager.set_actions_visible(self.fwd_action, True)
self.uimanager.set_actions_visible(self.back_action, True)
hobj = self.get_history()
self.fwd_action.set_sensitive(not hobj.at_end())
self.back_action.set_sensitive(not hobj.at_front())
self.uimanager.set_actions_sensitive(self.fwd_action,
not hobj.at_end())
self.uimanager.set_actions_sensitive(self.back_action,
not hobj.at_front())
def change_page(self):
"""
Called when the page changes.
"""
hobj = self.get_history()
self.fwd_action.set_sensitive(not hobj.at_end())
self.back_action.set_sensitive(not hobj.at_front())
self.other_action.set_sensitive(not self.dbstate.db.readonly)
self.uimanager.set_actions_sensitive(self.fwd_action,
not hobj.at_end())
self.uimanager.set_actions_sensitive(self.back_action,
not hobj.at_front())
self.uimanager.set_actions_sensitive(self.other_action,
not self.dbstate.db.readonly)
self.uistate.modify_statusbar(self.dbstate)
def set_active(self):
@@ -159,7 +156,7 @@ class NavigationView(PageView):
hobj = self.get_history()
self.active_signal = hobj.connect('active-changed', self.goto_active)
self.mru_signal = hobj.connect('mru-changed', self.update_mru_menu)
self.update_mru_menu(hobj.mru)
self.update_mru_menu(hobj.mru, update_menu=False)
self.goto_active(None)
@@ -199,8 +196,10 @@ class NavigationView(PageView):
self.goto_handle(active_handle)
hobj = self.get_history()
self.fwd_action.set_sensitive(not hobj.at_end())
self.back_action.set_sensitive(not hobj.at_front())
self.uimanager.set_actions_sensitive(self.fwd_action,
not hobj.at_end())
self.uimanager.set_actions_sensitive(self.back_action,
not hobj.at_front())
def get_active(self):
"""
@@ -238,7 +237,7 @@ class NavigationView(PageView):
####################################################################
# BOOKMARKS
####################################################################
def add_bookmark(self, obj):
def add_bookmark(self, *obj):
"""
Add a bookmark to the list.
"""
@@ -259,7 +258,7 @@ class NavigationView(PageView):
"no one was selected."),
parent=self.uistate.window)
def edit_bookmarks(self, obj):
def edit_bookmarks(self, *obj):
"""
Call the bookmark editor.
"""
@@ -271,12 +270,8 @@ class NavigationView(PageView):
"""
self.book_action = ActionGroup(name=self.title + '/Bookmark')
self.book_action.add_actions([
('AddBook', 'gramps-bookmark-new', _('_Add Bookmark'),
'<PRIMARY>d', None, self.add_bookmark),
('EditBook', 'gramps-bookmark-edit',
_("%(title)s...") % {'title': _("Organize Bookmarks")},
'<shift><PRIMARY>D', None,
self.edit_bookmarks),
('AddBook', self.add_bookmark, '<PRIMARY>d'),
('EditBook', self.edit_bookmarks, '<shift><PRIMARY>D'),
])
self._add_action_group(self.book_action)
@@ -290,35 +285,25 @@ class NavigationView(PageView):
"""
# add the Forward action group to handle the Forward button
self.fwd_action = ActionGroup(name=self.title + '/Forward')
self.fwd_action.add_actions([
('Forward', 'go-next', _("_Forward"),
"%sRight" % mod_key(), _("Go to the next object in the history"),
self.fwd_clicked)
])
self.fwd_action.add_actions([('Forward', self.fwd_clicked,
"%sRight" % mod_key())])
# add the Backward action group to handle the Forward button
self.back_action = ActionGroup(name=self.title + '/Backward')
self.back_action.add_actions([
('Back', 'go-previous', _("_Back"),
"%sLeft" % mod_key(), _("Go to the previous object in the history"),
self.back_clicked)
])
self.back_action.add_actions([('Back', self.back_clicked,
"%sLeft" % mod_key())])
self._add_action('HomePerson', 'go-home', _("_Home"),
accel="%sHome" % mod_key(),
tip=_("Go to the default person"), callback=self.home)
self._add_action('HomePerson', self.home, "%sHome" % mod_key())
self.other_action = ActionGroup(name=self.title + '/PersonOther')
self.other_action.add_actions([
('SetActive', 'go-home', _("Set _Home Person"), None,
None, self.set_default_person),
])
('SetActive', self.set_default_person)])
self._add_action_group(self.back_action)
self._add_action_group(self.fwd_action)
self._add_action_group(self.other_action)
def set_default_person(self, obj):
def set_default_person(self, *obj):
"""
Set the default person.
"""
@@ -326,7 +311,7 @@ class NavigationView(PageView):
if active:
self.dbstate.db.set_default_person_handle(active)
def home(self, obj):
def home(self, *obj):
"""
Move to the default person.
"""
@@ -342,7 +327,7 @@ class NavigationView(PageView):
"via the menu Edit ->Set Home Person."),
parent=self.uistate.window)
def jump(self):
def jump(self, *obj):
"""
A dialog to move to a Gramps ID entered by the user.
"""
@@ -383,7 +368,7 @@ class NavigationView(PageView):
"""
pass
def fwd_clicked(self, obj):
def fwd_clicked(self, *obj):
"""
Move forward one object in the history.
"""
@@ -392,11 +377,12 @@ class NavigationView(PageView):
if not hobj.at_end():
hobj.forward()
self.uistate.modify_statusbar(self.dbstate)
self.fwd_action.set_sensitive(not hobj.at_end())
self.back_action.set_sensitive(True)
self.uimanager.set_actions_sensitive(self.fwd_action,
not hobj.at_end())
self.uimanager.set_actions_sensitive(self.back_action, True)
hobj.lock = False
def back_clicked(self, obj):
def back_clicked(self, *obj):
"""
Move backward one object in the history.
"""
@@ -405,8 +391,9 @@ class NavigationView(PageView):
if not hobj.at_front():
hobj.back()
self.uistate.modify_statusbar(self.dbstate)
self.back_action.set_sensitive(not hobj.at_front())
self.fwd_action.set_sensitive(True)
self.uimanager.set_actions_sensitive(self.back_action,
not hobj.at_front())
self.uimanager.set_actions_sensitive(self.fwd_action, True)
hobj.lock = False
####################################################################
@@ -418,44 +405,52 @@ class NavigationView(PageView):
Remove the UI and action groups for the MRU list.
"""
if self.mru_active != DISABLED:
self.uistate.uimanager.remove_ui(self.mru_active)
self.uistate.uimanager.remove_action_group(self.mru_action)
self.uimanager.remove_ui(self.mru_active)
self.uimanager.remove_action_group(self.mru_action)
self.mru_active = DISABLED
def mru_enable(self):
def mru_enable(self, update_menu=False):
"""
Enables the UI and action groups for the MRU list.
"""
if self.mru_active == DISABLED:
self.uistate.uimanager.insert_action_group(self.mru_action, 1)
self.mru_active = self.uistate.uimanager.add_ui_from_string(self.mru_ui)
self.uistate.uimanager.ensure_update()
self.uimanager.insert_action_group(self.mru_action)
self.mru_active = self.uimanager.add_ui_from_string(self.mru_ui)
if update_menu:
self.uimanager.update_menu()
def update_mru_menu(self, items):
def update_mru_menu(self, items, update_menu=True):
"""
Builds the UI and action group for the MRU list.
"""
menuitem = ''' <item>
<attribute name="action">win.%s%02d</attribute>
<attribute name="label" translatable="yes">%s</attribute>
</item>
'''
menus = ''
self.mru_disable()
nav_type = self.navigation_type()
hobj = self.get_history()
menu_len = min(len(items) - 1, MRU_SIZE)
entry = '<menuitem action="%s%02d"/>'
data = [entry % (nav_type, index) for index in range(0, menu_len)]
self.mru_ui = "".join(MRU_TOP) + "".join(data) + "".join(MRU_BTM)
for index in range(0, menu_len):
name, obj = navigation_label(self.dbstate.db, nav_type,
items[index])
menus += menuitem % (nav_type, index, html.escape(name))
self.mru_ui = [MRU_TOP + menus + MRU_BTM]
mitems = items[-MRU_SIZE - 1:-1] # Ignore current handle
mitems.reverse()
data = []
for index, handle in enumerate(mitems):
name, obj = navigation_label(self.dbstate.db, nav_type, handle)
data.append(('%s%02d'%(nav_type, index), None, name,
"%s%d" % (mod_key(), index), None,
make_callback(hobj.push, handle)))
data.append(('%s%02d'%(nav_type, index),
make_callback(hobj.push, handle),
"%s%d" % (mod_key(), index)))
self.mru_action = ActionGroup(name=self.title + '/MRU')
self.mru_action.add_actions(data)
self.mru_enable()
self.mru_enable(update_menu)
####################################################################
# Template functions
@@ -503,4 +498,4 @@ def make_callback(func, handle):
"""
Generates a callback function based off the passed arguments
"""
return lambda x: func(handle)
return lambda x, y: func(handle)
+32 -49
View File
@@ -51,7 +51,7 @@ from ..dbguielement import DbGUIElement
from ..widgets.grampletbar import GrampletBar
from ..configure import ConfigureDialog
from gramps.gen.config import config
from ..actiongroup import ActionGroup
from ..uimanager import ActionGroup
#------------------------------------------------------------------------------
#
@@ -97,25 +97,24 @@ class PageView(DbGUIElement, metaclass=ABCMeta):
self.uistate = uistate
self.action_list = []
self.action_toggle_list = []
self.action_toolmenu_list = []
self.action_toolmenu = {} #easy access to toolmenuaction and proxies
self.action_group = None
self.additional_action_groups = []
self.additional_uis = []
self.ui_def = '''<ui>
<menubar name="MenuBar">
<menu action="ViewMenu">
<placeholder name="Bars">
<menuitem action="Sidebar"/>
<menuitem action="Bottombar"/>
</placeholder>
</menu>
</menubar>
</ui>'''
self.ui_def = ['''
<placeholder id="Bars">
<item>
<attribute name="action">win.Sidebar</attribute>
<attribute name="label" translatable="yes">_Sidebar</attribute>
</item>
<item>
<attribute name="action">win.Bottombar</attribute>
<attribute name="label" translatable="yes">_Bottombar</attribute>
</item>
</placeholder>
''']
self.dirty = True
self.active = False
self._dirty_on_change_inactive = True
self.func_list = {}
if isinstance(self.pdata.category, tuple):
self.category, self.translated_category = self.pdata.category
@@ -201,24 +200,24 @@ class PageView(DbGUIElement, metaclass=ABCMeta):
"""
self._config.set(setting, widget.get_position())
def __sidebar_toggled(self, action):
def __sidebar_toggled(self, action, value):
"""
Called when the sidebar is toggled.
"""
active = action.get_active()
if active:
action.set_state(value) # change GUI
if value.get_boolean():
self.sidebar.show()
self.sidebar_toggled(True)
else:
self.sidebar.hide()
self.sidebar_toggled(False)
def __bottombar_toggled(self, action):
def __bottombar_toggled(self, action, value):
"""
Called when the bottombar is toggled.
"""
active = action.get_active()
if active:
action.set_state(value) # change GUI
if value.get_boolean():
self.bottombar.show()
else:
self.bottombar.hide()
@@ -312,12 +311,6 @@ class PageView(DbGUIElement, metaclass=ABCMeta):
return True
return False
def call_function(self, key):
"""
Calls the function associated with the key value
"""
self.func_list.get(key)()
def post(self):
"""
Called after a page is created.
@@ -332,6 +325,9 @@ class PageView(DbGUIElement, metaclass=ABCMeta):
self.sidebar.set_active()
self.bottombar.set_active()
self.active = True
new_title = "%s - %s - Gramps" % (self.dbstate.db.get_dbname(),
self.get_title())
self.uistate.window.set_title(new_title)
if self.dirty:
self.uistate.set_busy_cursor(True)
self.build_tree()
@@ -370,14 +366,15 @@ class PageView(DbGUIElement, metaclass=ABCMeta):
Turns off the visibility of the View's action group, if defined
"""
if self.action_group:
self.action_group.set_visible(False)
self.uistate.uimanager.set_actions_visible(self.action_group,
False)
def enable_action_group(self, obj):
"""
Turns on the visibility of the View's action group, if defined
"""
if self.action_group:
self.action_group.set_visible(True)
self.uistate.uimanager.set_actions_visible(self.action_group, True)
def get_stock(self):
"""
@@ -435,11 +432,9 @@ class PageView(DbGUIElement, metaclass=ABCMeta):
View. The user typically defines self.action_list and
self.action_toggle_list in this function.
"""
self._add_toggle_action('Sidebar', None, _('_Sidebar'),
"<shift><PRIMARY>R", None, self.__sidebar_toggled,
self._add_toggle_action('Sidebar', self.__sidebar_toggled, '',
self.sidebar.get_property('visible'))
self._add_toggle_action('Bottombar', None, _('_Bottombar'),
"<shift><PRIMARY>B", None, self.__bottombar_toggled,
self._add_toggle_action('Bottombar', self.__bottombar_toggled, '',
self.bottombar.get_property('visible'))
def __build_action_group(self):
@@ -452,31 +447,19 @@ class PageView(DbGUIElement, metaclass=ABCMeta):
if len(self.action_list) > 0:
self.action_group.add_actions(self.action_list)
if len(self.action_toggle_list) > 0:
self.action_group.add_toggle_actions(self.action_toggle_list)
self.action_group.add_actions(self.action_toggle_list)
def _add_action(self, name, icon_name, label, accel=None, tip=None,
callback=None):
def _add_action(self, name, callback=None, accel=None):
"""
Add an action to the action list for the current view.
"""
self.action_list.append((name, icon_name, label, accel, tip,
callback))
self.action_list.append((name, callback, accel))
def _add_toggle_action(self, name, icon_name, label, accel=None,
tip=None, callback=None, value=False):
def _add_toggle_action(self, name, callback=None, accel= None, value=False):
"""
Add a toggle action to the action list for the current view.
"""
self.action_toggle_list.append((name, icon_name, label, accel,
tip, callback, value))
def _add_toolmenu_action(self, name, label, tooltip, callback,
arrowtooltip):
"""
Add a menu action to the action list for the current view.
"""
self.action_toolmenu_list.append((name, label, tooltip, callback,
arrowtooltip))
self.action_toggle_list.append((name, callback, accel, value))
def get_actions(self):
"""
+80 -46
View File
@@ -50,7 +50,7 @@ from gramps.gen.const import URL_MANUAL_PAGE
from ..display import display_help
from ..dialog import ErrorDialog, QuestionDialog2
import gramps.gui.widgets.progressdialog as progressdlg
from ..actiongroup import ActionGroup
from ..uimanager import ActionGroup
from ..managedwindow import ManagedWindow
#-------------------------------------------------------------------------
@@ -58,29 +58,54 @@ from ..managedwindow import ManagedWindow
# Constants
#
#-------------------------------------------------------------------------
TAG_1 = '''<ui>
<menubar name="MenuBar">
<menu action="EditMenu">
<placeholder name="TagMenu">
<menu action="Tag">
'''
TAG_1 = '''
<section id='TagMenu' groups='RW'>
<submenu>
<attribute name="label" translatable="yes">Tag</attribute>
%s
</submenu>
</section>
'''
TAG_2 = '''
</menu>
</placeholder>
</menu>
</menubar>
<toolbar name="ToolBar">
<placeholder name="TagTool">
<toolitem action="TagButton"/>
TAG_2 = (
''' <placeholder id='TagTool' groups='RW'>
<child groups='RO'>
<object class="GtkToolButton" id="TagButton">
<property name="icon-name">gramps-tag</property>
<property name="action-name">win.TagButton</property>
<property name="tooltip_text" translatable="yes">'''
'''Tag selected rows</property>
<property name="label" translatable="yes">Tag</property>
</object>
<packing>
<property name="homogeneous">False</property>
</packing>
</child>
</placeholder>
</toolbar>
<popup name="TagPopup">
'''
''')
TAG_3 = '''
</popup>
</ui>'''
<menu id='TagPopup' groups='RW'>
%s
</menu>'''
TAG_MENU = (
'''<section>
<item>
<attribute name="action">win.NewTag</attribute>
<attribute name="label" translatable="yes">'''
'''New Tag...</attribute>
</item>
<item>
<attribute name="action">win.OrganizeTags</attribute>
<attribute name="label" translatable="yes">'''
'''Organize Tags...</attribute>
</item>
</section>
<section>
%s
</section>
''')
WIKI_HELP_PAGE = '%s_-_Filters' % \
URL_MANUAL_PAGE
@@ -119,13 +144,14 @@ class Tags(DbGUIElement):
self._build_tag_menu()
def tag_enable(self):
def tag_enable(self, update_menu=True):
"""
Enables the UI and action groups for the tag menu.
"""
self.uistate.uimanager.insert_action_group(self.tag_action, 1)
self.uistate.uimanager.insert_action_group(self.tag_action)
self.tag_id = self.uistate.uimanager.add_ui_from_string(self.tag_ui)
self.uistate.uimanager.ensure_update()
if update_menu:
self.uistate.uimanager.update_menu()
def tag_disable(self):
"""
@@ -134,7 +160,6 @@ class Tags(DbGUIElement):
if self.tag_id is not None:
self.uistate.uimanager.remove_ui(self.tag_id)
self.uistate.uimanager.remove_action_group(self.tag_action)
self.uistate.uimanager.ensure_update()
self.tag_id = None
def _db_changed(self, db):
@@ -209,46 +234,55 @@ class Tags(DbGUIElement):
actions = []
if not self.dbstate.is_open():
self.tag_ui = ''
self.tag_ui = ['']
self.tag_action = ActionGroup(name='Tag')
return
tag_menu = '<menuitem action="NewTag"/>'
tag_menu += '<menuitem action="OrganizeTags"/>'
tag_menu += '<separator/>'
tag_menu = ''
menuitem = '''
<item>
<attribute name="action">win.TAG_%s</attribute>
<attribute name="label" translatable="yes">%s</attribute>
</item>'''
for tag_name, handle in self.__tag_list:
tag_menu += '<menuitem action="TAG_%s"/>' % handle
actions.append(('TAG_%s' % handle, None, tag_name, None, None,
make_callback(self.tag_selected_rows, handle)))
tag_menu += menuitem % (handle, tag_name)
actions.append(('TAG_%s' % handle,
make_callback(self.tag_selected_rows, handle)))
tag_menu = TAG_MENU % tag_menu
self.tag_ui = TAG_1 + tag_menu + TAG_2 + tag_menu + TAG_3
self.tag_ui = [TAG_1 % tag_menu, TAG_2, TAG_3 % tag_menu]
actions.append(('Tag', 'gramps-tag', _('Tag'), None, None, None))
actions.append(('NewTag', 'gramps-tag-new', _('New Tag...'), None, None,
self.cb_new_tag))
actions.append(('OrganizeTags', None, _('Organize Tags...'), None, None,
self.cb_organize_tags))
actions.append(('TagButton', 'gramps-tag', _('Tag'), None,
_('Tag selected rows'), self.cb_tag_button))
actions.append(('NewTag', self.cb_new_tag))
actions.append(('OrganizeTags', self.cb_organize_tags))
actions.append(('TagButton', self.cb_tag_button))
self.tag_action = ActionGroup(name='Tag')
self.tag_action.add_actions(actions)
def cb_tag_button(self, action):
def cb_tag_button(self, *args):
"""
Display the popup menu when the toolbar button is clicked.
"""
menu = self.uistate.uimanager.get_widget('/TagPopup')
button = self.uistate.uimanager.get_widget('/ToolBar/TagTool/TagButton')
menu.popup(None, None, cb_menu_position, button, 0, 0)
menu = self.uistate.uimanager.get_widget('TagPopup')
button = self.uistate.uimanager.get_widget('TagButton')
popup_menu = Gtk.Menu.new_from_model(menu)
popup_menu.attach_to_widget(button, None)
popup_menu.show_all()
if Gtk.MINOR_VERSION < 22:
# ToDo The following is reported to work poorly with Wayland
popup_menu.popup(None, None, cb_menu_position, button, 0, 0)
else:
popup_menu.popup_at_widget(button, Gdk.Gravity.SOUTH,
Gdk.Gravity.NORTH_WEST, None)
def cb_organize_tags(self, action):
def cb_organize_tags(self, *action):
"""
Display the Organize Tags dialog.
"""
OrganizeTagsDialog(self.db, self.uistate, [])
def cb_new_tag(self, action):
def cb_new_tag(self, *action):
"""
Create a new tag and tag the selected objects.
"""
@@ -304,7 +338,7 @@ def make_callback(func, tag_handle):
"""
Generates a callback function based off the passed arguments
"""
return lambda x: func(tag_handle)
return lambda x, y: func(tag_handle)
#-------------------------------------------------------------------------
#
@@ -266,18 +266,6 @@ class CitationBaseModel:
self.set_cached_value(source_handle, "SRC_CHAN", value)
return value
def citation_src_sort_change(self, data):
source_handle = data[COLUMN_SOURCE]
cached, value = self.get_cached_value(source_handle, "SRC_CHAN")
if not cached:
try:
source = self.db.get_source_from_handle(source_handle)
value = "%012x" % source.change
except:
value = ''
self.set_cached_value(source_handle, "SRC_CHAN", value)
return value
# Fields access when 'data' is a Source
def source_src_title(self, data):
@@ -91,7 +91,7 @@ class CitationListModel(CitationBaseModel, FlatBaseModel):
self.citation_src_abbr,
self.citation_src_pinfo,
self.citation_src_private,
self.citation_src_sort_change,
self.citation_src_chan,
self.citation_tag_color
]
FlatBaseModel.__init__(self, db, uistate, scol, order, search=search,
+4 -11
View File
@@ -81,8 +81,7 @@ class PlaceBaseModel:
self.column_private,
self.column_tags,
self.column_change,
self.column_tag_color,
self.search_name,
self.column_tag_color
]
self.smap = [
self.column_name,
@@ -95,8 +94,7 @@ class PlaceBaseModel:
self.column_private,
self.column_tags,
self.sort_change,
self.column_tag_color,
self.search_name,
self.column_tag_color
]
def destroy(self):
@@ -129,13 +127,8 @@ class PlaceBaseModel:
return value
def column_name(self, data):
""" Return the primary name """
return data[6][0]
def search_name(self, data):
""" The search name includes all alt names to enable finding by alt name
"""
return ','.join([data[6][0]] + [name[0] for name in data[7]])
# need for spacing on the french translation
return _(',').join([data[6][0]] + [name[0] for name in data[7]])
def column_longitude(self, data):
if not data[3]:
-4
View File
@@ -34,16 +34,12 @@ from .monitoredwidgets import *
from .selectionwidget import SelectionWidget, Region
from .shadebox import *
from .shortlistcomboentry import *
from .springseparator import *
from .statusbar import Statusbar
from .styledtextbuffer import *
from .styledtexteditor import *
from .toolcomboentry import *
from .undoablebuffer import *
from .undoableentry import *
from .undoablestyledbuffer import *
from .validatedcomboentry import *
from .validatedmaskedentry import *
from .valueaction import *
from .valuetoolitem import *
from .placewithin import *
+2 -5
View File
@@ -1252,12 +1252,9 @@ class FanChartWidget(FanChartBaseWidget):
self.center_xy = self.center_xy_from_delta()
cr.translate(*self.center_xy)
else: # printing
if self.form == FORM_QUADRANT:
self.center_xy = self.CENTER + PIXELS_PER_GENERATION, halfdist
else:
self.center_xy = halfdist + PIXELS_PER_GENERATION, halfdist
self.center_xy = halfdist, halfdist
cr.scale(scale, scale)
cr.translate(*self.center_xy)
cr.translate(halfdist, halfdist)
cr.save()
cr.rotate(math.radians(self.rotate_value))
+8 -9
View File
@@ -94,7 +94,7 @@ class FanChartDescWidget(FanChartBaseWidget):
"""
Interactive Fan Chart Widget.
"""
CENTER = 60 # we require a larger center as CENTER includes the 1st partner
CENTER = 50 # we require a larger center as CENTER includes the 1st partner
def __init__(self, dbstate, uistate, callback_popup=None):
"""
@@ -152,7 +152,7 @@ class FanChartDescWidget(FanChartBaseWidget):
elif self.form == FORM_HALFCIRCLE:
self.rootangle_rad = [math.radians(90), math.radians(90 + 180)]
elif self.form == FORM_QUADRANT:
self.rootangle_rad = [math.radians(180), math.radians(270)]
self.rootangle_rad = [math.radians(90), math.radians(90 + 90)]
self.handle2desc = {}
self.famhandle2desc = {}
@@ -361,10 +361,12 @@ class FanChartDescWidget(FanChartBaseWidget):
"""
Compute the half radius of the circle
"""
return self.get_radiusinout_for_generation(self.nrgen())[1]
radius = PIXELS_PER_GEN_SMALL * N_GEN_SMALL + PIXELS_PER_GEN_LARGE \
* ( self.nrgen() - N_GEN_SMALL ) + self.CENTER
return radius
def get_radiusinout_for_generation(self,generation):
radius_first_gen = 14 # fudged to make inner circle a bit tighter
radius_first_gen = self.CENTER - (1-PIXELS_PER_GENPERSON_RATIO) * PIXELS_PER_GEN_SMALL
if generation < N_GEN_SMALL:
radius_start = PIXELS_PER_GEN_SMALL * generation + radius_first_gen
return (radius_start,radius_start + PIXELS_PER_GEN_SMALL)
@@ -433,12 +435,9 @@ class FanChartDescWidget(FanChartBaseWidget):
self.center_xy = self.center_xy_from_delta()
cr.translate(*self.center_xy)
else: # printing
if self.form == FORM_QUADRANT:
self.center_xy = self.CENTER, halfdist
else:
self.center_xy = halfdist, halfdist
self.center_xy = halfdist, halfdist
cr.scale(scale, scale)
cr.translate(*self.center_xy)
cr.translate(halfdist, halfdist)
cr.save()
# Draw center person:
+31 -1
View File
@@ -104,6 +104,16 @@ class GrampletBar(Gtk.Notebook):
self.set_show_border(False)
self.set_scrollable(True)
image = Gtk.Image(stock=Gtk.STOCK_REFRESH)
refresh_button = Gtk.Button(image=image)
refresh_button.set_relief(Gtk.ReliefStyle.NONE)
refresh_button.connect('clicked', self.__refresh_clicked)
self.set_action_widget(refresh_button, Gtk.PackType.START)
if config.get('interface.grampletbar-refresh'):
refresh_button.show()
else:
refresh_button.hide()
book_button = Gtk.Button()
# Arrow is too small unless in a box
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
@@ -142,6 +152,7 @@ class GrampletBar(Gtk.Notebook):
self.set_current_page(config_settings[1])
uistate.connect('grampletbar-close-changed', self.cb_close_changed)
uistate.connect('grampletbar-refresh-changed', self.cb_refresh_changed)
# Connect after gramplets added to prevent making them active
self.connect('switch-page', self.__switch_page)
@@ -404,6 +415,16 @@ class GrampletBar(Gtk.Notebook):
tablabel = self.get_tab_label(gramplet)
tablabel.use_close(config.get('interface.grampletbar-close'))
def cb_refresh_changed(self):
"""
Refresh button preference changed.
"""
button = self.get_action_widget(Gtk.PackType.START)
if config.get('interface.grampletbar-refresh'):
button.show()
else:
button.hide()
def __delete_clicked(self, button, gramplet):
"""
Called when the delete button is clicked.
@@ -476,6 +497,15 @@ class GrampletBar(Gtk.Notebook):
gramplet.detached_window.close()
gramplet.detached_window = None
def __refresh_clicked(self, button):
"""
Called when the drop-down button is clicked.
"""
for gramplet in self.get_children():
if gramplet and gramplet.pui:
if gramplet.pui.active:
gramplet.pui.main()
def __button_clicked(self, button):
"""
Called when the drop-down button is clicked.
@@ -743,7 +773,7 @@ class TabLabel(Gtk.Box):
def use_close(self, use_close):
"""
Display the cose button according to user preference.
Display the close button according to user preference.
"""
if use_close:
self.closebtn.show()
+92 -41
View File
@@ -34,6 +34,7 @@ from gi.repository import Pango
import time
import os
import configparser
from gramps.gen.config import config
import logging
@@ -49,7 +50,7 @@ from gramps.gen.const import URL_MANUAL_PAGE, VERSION_DIR, COLON
from ..editors import EditPerson, EditFamily
from ..managedwindow import ManagedWindow
from ..utils import is_right_click, match_primary_mask, get_link_color
from .menuitem import add_menuitem
from ..uimanager import ActionGroup
from ..plug import make_gui_option
from ..plug.quick import run_quick_report_by_name
from ..display import display_help, display_url
@@ -189,6 +190,13 @@ def logical_true(value):
"""
return value in ["True", True, 1, "1"]
def make_callback(func, arg):
"""
Generates a callback function based off the passed arguments
"""
return lambda x, y: func(arg)
class LinkTag(Gtk.TextTag):
"""
Class for keeping track of link data.
@@ -235,6 +243,8 @@ class GrampletWindow(ManagedWindow):
self.setup_configs('interface.' + cfg_name,
gramplet.detached_width, gramplet.detached_height)
self.window.add_button(_('_Help'), Gtk.ResponseType.HELP)
if config.get('interface.grampletbar-refresh'):
self.window.add_button(_('Refresh'), Gtk.ResponseType.APPLY)
# add gramplet:
if self.gramplet.pui:
self.gramplet.pui.active = True
@@ -267,6 +277,8 @@ class GrampletWindow(ManagedWindow):
else:
display_help(WIKI_HELP_PAGE,
self.gramplet.tname.replace(" ", "_"))
elif response == Gtk.ResponseType.APPLY:
self.refresh()
def build_menu_names(self, obj):
"""
@@ -274,6 +286,12 @@ class GrampletWindow(ManagedWindow):
"""
return (self.title, 'Gramplet')
def refresh(self):
"""
Refresh the detached gramplet
"""
self.gramplet.pui.main() # refresh
def get_title(self):
"""
Returns the window title.
@@ -365,8 +383,6 @@ class GuiGramplet:
self.gstate = kwargs.get("state", "maximized")
self.data = kwargs.get("data", [])
self.help_url = kwargs.get("help_url", WIKI_HELP_PAGE)
if self.help_url == 'None':
self.help_url = None # to fix up the config file vers of None
##########
self.use_markup = False
self.pui = None # user code
@@ -1001,6 +1017,8 @@ class GrampletPane(Gtk.ScrolledWindow):
self.pageview = pageview
self.pane = self
self._popup_xy = None
self.at_popup_action = None
self.at_popup_menu = None
user_gramplets = self.load_gramplets()
# build the GUI:
msg = _("Right click to add gramplets")
@@ -1154,7 +1172,7 @@ class GrampletPane(Gtk.ScrolledWindow):
retval = []
filename = self.configfile
if filename and os.path.exists(filename):
cp = configparser.ConfigParser(strict=False)
cp = configparser.ConfigParser()
try:
cp.read(filename, encoding='utf-8')
except Exception as err:
@@ -1218,10 +1236,12 @@ class GrampletPane(Gtk.ScrolledWindow):
for key in base_opts:
if key in gramplet.__dict__:
base_opts[key] = gramplet.__dict__[key]
base_opts['state'] = gramplet.gstate
fp.write("[%s]\n" % gramplet.title) # section
fp.write("[%s]\n" % gramplet.gname)
for key in base_opts:
if key == "content": continue
elif key == "title":
if gramplet.title_override:
fp.write("title=%s\n" % base_opts[key])
elif key == "tname": continue
elif key == "column": continue
elif key == "row": continue
@@ -1247,7 +1267,6 @@ class GrampletPane(Gtk.ScrolledWindow):
for key in base_opts:
if key in gramplet.__dict__:
base_opts[key] = gramplet.__dict__[key]
base_opts['state'] = gramplet.gstate
fp.write("[%s]\n" % gramplet.title)
for key in base_opts:
if key == "content": continue
@@ -1267,7 +1286,7 @@ class GrampletPane(Gtk.ScrolledWindow):
fp.write("data[%d]=%s\n" % (cnt, item))
cnt += 1
else:
fp.write("%s=%s\n" % (key, base_opts[key]))
fp.write("%s=%s\n\n" % (key, base_opts[key]))
except IOError as err:
LOG.warning("Failed to open %s because $s; gramplets not saved",
@@ -1350,8 +1369,7 @@ class GrampletPane(Gtk.ScrolledWindow):
self.place_gramplets(recolumn=True)
self.show()
def restore_gramplet(self, obj):
name = obj.get_child().get_label()
def restore_gramplet(self, name):
############### First kind: from current session
for gramplet in self.closed_gramplets:
if gramplet.title == name:
@@ -1393,8 +1411,7 @@ class GrampletPane(Gtk.ScrolledWindow):
else:
self.drop_widget(self, gramplet, 0, 0, 0)
def add_gramplet(self, obj):
tname = obj.get_child().get_label()
def add_gramplet(self, tname):
all_opts = get_gramplet_options_by_tname(tname)
name = all_opts["name"]
if all_opts is None:
@@ -1438,39 +1455,73 @@ class GrampletPane(Gtk.ScrolledWindow):
LOG.warning("Can't make gramplet of type '%s'.", name)
def _button_press(self, obj, event):
ui_def = (
''' <menu id="Popup">
<submenu>
<attribute name="action">win.AddGramplet</attribute>
<attribute name="label" translatable="yes">Add a gramplet</attribute>
%s
</submenu>
<submenu>
<attribute name="action">win.RestoreGramplet</attribute>
<attribute name="label" translatable="yes">'''
'''Restore a gramplet</attribute>
%s
</submenu>
</menu>
''')
menuitem = ('<item>\n'
'<attribute name="action">win.%s</attribute>\n'
'<attribute name="label" translatable="yes">'
'%s</attribute>\n'
'</item>\n')
if is_right_click(event):
self._popup_xy = (event.x, event.y)
uiman = self.uistate.uimanager
ag_menu = uiman.get_widget('/GrampletPopup/AddGramplet')
if ag_menu:
qr_menu = ag_menu.get_submenu()
qr_menu = Gtk.Menu()
names = [gplug.name for gplug in PLUGMAN.get_reg_gramplets()
if gplug.navtypes == []
or 'Dashboard' in gplug.navtypes]
names.sort()
actions = []
r_menuitems = ''
a_menuitems = ''
names = [gplug.name for gplug in PLUGMAN.get_reg_gramplets()
if gplug.navtypes == []
or 'Dashboard' in gplug.navtypes]
names.sort()
for name in names:
action_name = name.replace(' ', '-')
a_menuitems += menuitem % (action_name, name)
actions.append((action_name,
make_callback(self.add_gramplet, name)))
names = [gramplet.title for gramplet in self.closed_gramplets]
names.extend(opts["title"] for opts in self.closed_opts)
names.sort()
if len(names) > 0:
for name in names:
add_menuitem(qr_menu, name, None,
self.add_gramplet)
ag_menu.set_submenu(qr_menu)
rg_menu = uiman.get_widget('/GrampletPopup/RestoreGramplet')
if rg_menu:
qr_menu = rg_menu.get_submenu()
if qr_menu is not None:
rg_menu.set_submenu(None)
names = [gramplet.title for gramplet in self.closed_gramplets]
names.extend(opts["title"] for opts in self.closed_opts)
names.sort()
if len(names) > 0:
qr_menu = Gtk.Menu()
for name in names:
add_menuitem(qr_menu, name, None,
self.restore_gramplet)
rg_menu.set_submenu(qr_menu)
self.menu = uiman.get_widget('/GrampletPopup')
if self.menu:
#GTK3 does not show the popup, workaround: menu as attribute
self.menu.popup(None, None, None, None, event.button, event.time)
action_name = name.replace(' ', '-')
r_menuitems += menuitem % (action_name, name)
actions.append((action_name,
make_callback(self.restore_gramplet,
name)))
if self.at_popup_action:
uiman.remove_ui(self.at_popup_menu)
uiman.remove_action_group(self.at_popup_action)
self.at_popup_action = ActionGroup('AtPopupActions',
actions)
uiman.insert_action_group(self.at_popup_action)
self.at_popup_menu = uiman.add_ui_from_string([
ui_def % (a_menuitems, r_menuitems)])
uiman.update_menu()
menu = uiman.get_widget('Popup')
popup_menu = Gtk.Menu.new_from_model(menu)
popup_menu.attach_to_widget(obj, None)
popup_menu.show_all()
if Gtk.MINOR_VERSION < 22:
# ToDo The following is reported to work poorly with Wayland
popup_menu.popup(None, None, None, None,
event.button, event.time)
else:
popup_menu.popup_at_pointer(event)
return True
return False
@@ -239,8 +239,6 @@ class InteractiveSearchBox:
return
model = self._treeview.get_model()
if not model:
return
selection = self._treeview.get_selection()
# disable flush timeout while searching
if self._entry_flush_timeout:
+1 -14
View File
@@ -46,23 +46,11 @@ _LOG = logging.getLogger("gui.widgets.reorderfam")
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.sgettext
from gramps.gen.db import DbTxn
from gramps.gen.const import URL_MANUAL_PAGE
from ..listmodel import ListModel
from ..display import display_help
from ..managedwindow import ManagedWindow
from ..glade import Glade
from gramps.gen.display.name import displayer as name_displayer
#-------------------------------------------------------------------------
#
# Constants
#
#-------------------------------------------------------------------------
WIKI_HELP_PAGE = URL_MANUAL_PAGE + "_-_Categories"
WIKI_HELP_SEC = _('manual|Reorder_Relationships_dialog')
#-------------------------------------------------------------------------
#
# Reorder class
@@ -105,8 +93,7 @@ class Reorder(ManagedWindow):
xml.get_object('ok').connect('clicked', self.ok_clicked)
xml.get_object('cancel').connect('clicked', self.cancel_clicked)
xml.get_object('help').connect(
'clicked', lambda x: display_help(WIKI_HELP_PAGE, WIKI_HELP_SEC))
fup = xml.get_object('fup')
fup.connect('clicked', self.fup_clicked)
fup.set_sensitive(fenable)
+4 -1
View File
@@ -70,7 +70,10 @@ class ShortlistComboEntry(ValidatedComboEntry):
"""
__gtype_name__ = "ShortlistComboEntry"
def __init__(self, items, shortlist=True, validator=None):
def __init__(self):
pass
def init(self, items, shortlist=True, validator=None):
if not items:
raise ValueError
-76
View File
@@ -1,76 +0,0 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2008 Zsolt Foldvari
#
# 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.
#
"Separator classes used for Toolbar."
__all__ = ["SpringSeparatorAction", "SpringSeparatorToolItem"]
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
import logging
_LOG = logging.getLogger(".widgets.springseparator")
#-------------------------------------------------------------------------
#
# GTK modules
#
#-------------------------------------------------------------------------
from gi.repository import Gtk
#-------------------------------------------------------------------------
#
# SpringSeparatorToolItem class
#
#-------------------------------------------------------------------------
class SpringSeparatorToolItem(Gtk.SeparatorToolItem):
"""Custom separator toolitem.
Its only purpose is to push following tool items to the right end
of the toolbar.
"""
__gtype_name__ = "SpringSeparatorToolItem"
def __init__(self):
Gtk.SeparatorToolItem.__init__(self)
self.set_draw(False)
self.set_expand(True)
#-------------------------------------------------------------------------
#
# SpringSeparatorAction class
#
#-------------------------------------------------------------------------
class SpringSeparatorAction(Gtk.Action):
"""Custom Action to hold a SpringSeparatorToolItem."""
__gtype_name__ = "SpringSeparatorAction"
def __init__(self, name, label, tooltip, stock_id):
Gtk.Action.__init__(self, name=name, label=label,
tooltip=tooltip, stock_id=stock_id)
## TODO GTK3, How to connect these? Used in styledtexteditor
##SpringSeparatorToolItem.set_related_action(SpringSeparatorAction)
##deprecated: SpringSeparatorAction.set_tool_item_type(SpringSeparatorToolItem)
+236 -183
View File
@@ -43,6 +43,8 @@ from gi.repository import GObject
from gi.repository import Gdk
from gi.repository import Gtk
from gi.repository import Pango
from gi.repository.Gio import SimpleActionGroup
from gi.repository.GLib import Variant
#-------------------------------------------------------------------------
#
@@ -55,15 +57,12 @@ from .styledtextbuffer import (ALLOWED_STYLES,
MATCH_FLAVOR, MATCH_STRING,
LinkTag)
from .undoablestyledbuffer import UndoableStyledBuffer
from .valueaction import ValueAction
from .toolcomboentry import ToolComboEntry
from .springseparator import SpringSeparatorAction
from ..spell import Spell
from ..display import display_url
from ..utils import SystemFonts, match_primary_mask, get_link_color
from gramps.gen.config import config
from gramps.gen.constfunc import has_display, mac
from ..actiongroup import ActionGroup
from ..uimanager import ActionGroup
#-------------------------------------------------------------------------
#
@@ -75,33 +74,141 @@ if has_display():
HAND_CURSOR = Gdk.Cursor.new_for_display(display, Gdk.CursorType.HAND2)
REGULAR_CURSOR = Gdk.Cursor.new_for_display(display, Gdk.CursorType.XTERM)
FORMAT_TOOLBAR = '''
<ui>
<toolbar name="ToolBar">
<toolitem action="%d"/>
<toolitem action="%d"/>
<toolitem action="%d"/>
<toolitem action="%d"/>
<toolitem action="%d"/>
<toolitem action="Undo"/>
<toolitem action="Redo"/>
<toolitem action="%d"/>
<toolitem action="%d"/>
<toolitem action="%d"/>
<toolitem action="spring"/>
<toolitem action="clear"/>
</toolbar>
</ui>
''' % (StyledTextTagType.ITALIC,
StyledTextTagType.BOLD,
StyledTextTagType.UNDERLINE,
StyledTextTagType.FONTFACE,
StyledTextTagType.FONTSIZE,
StyledTextTagType.FONTCOLOR,
StyledTextTagType.HIGHLIGHT,
StyledTextTagType.LINK,
)
FORMAT_TOOLBAR = (
'''<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkToolbar" id="ToolBar">
<property name="hexpand">True</property>
<property name="toolbar-style">GTK_TOOLBAR_ICONS</property>
<style>
<class name="primary-toolbar"/>
</style>
<child>
<object class="GtkToggleToolButton">
<property name="icon-name">format-text-italic</property>
<property name="action-name">ste.ITALIC</property>
<property name="tooltip_text" translatable="yes">Italic</property>
</object>
<packing>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="icon-name">format-text-bold</property>
<property name="action-name">ste.BOLD</property>
<property name="tooltip_text" translatable="yes">Bold</property>
</object>
<packing>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkToggleToolButton">
<property name="icon-name">format-text-underline</property>
<property name="action-name">ste.UNDERLINE</property>
<property name="tooltip_text" translatable="yes">Underline</property>
</object>
<packing>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkToolItem">
<property name="tooltip_text" translatable="yes">Font family</property>
<child>
<object class="ShortlistComboEntry" id="Fontface"></object>
</child>
</object>
</child>
<child>
<object class="GtkToolItem">
<property name="tooltip_text" translatable="yes">Font size</property>
<child>
<object class="ShortlistComboEntry" id="Fontsize"></object>
</child>
</object>
</child>
<child>
<object class="GtkToolButton">
<property name="icon-name">edit-undo</property>
<property name="action-name">ste.STUndo</property>
<property name="tooltip_text" translatable="yes">Undo</property>
<property name="label" translatable="yes">Undo</property>
</object>
<packing>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkToolButton">
<property name="icon-name">edit-redo</property>
<property name="action-name">ste.STRedo</property>
<property name="tooltip_text" translatable="yes">Redo</property>
<property name="label" translatable="yes">Redo</property>
</object>
<packing>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkToolButton">
<property name="icon-name">gramps-font-color</property>
<property name="action-name">ste.FONTCOLOR</property>
<property name="tooltip_text" translatable="yes">Font Color</property>
<property name="label" translatable="yes">Font Color</property>
</object>
<packing>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkToolButton">
<property name="icon-name">gramps-font-bgcolor</property>
<property name="action-name">ste.HIGHLIGHT</property>
<property name="tooltip_text" translatable="yes">'''
'''Background Color</property>
<property name="label" translatable="yes">Background Color</property>
</object>
<packing>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkToolButton">
<property name="icon-name">go-jump</property>
<property name="action-name">ste.LINK</property>
<property name="tooltip_text" translatable="yes">Link</property>
<property name="label" translatable="yes">Link</property>
</object>
<packing>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkSeparatorToolItem">
<property name="draw">False</property>
<property name="hexpand">True</property>
</object>
<packing>
<property name="expand">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton">
<property name="icon-name">edit-clear</property>
<property name="action-name">ste.CLEAR</property>
<property name="tooltip_text" translatable="yes">'''
'''Clear Markup</property>
<property name="label" translatable="yes">Clear Markup</property>
</object>
<packing>
<property name="homogeneous">False</property>
</packing>
</child>
</object>
</interface>
''')
FONT_SIZES = [8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22,
24, 26, 28, 32, 36, 40, 48, 56, 64, 72]
@@ -182,6 +289,7 @@ class StyledTextEditor(Gtk.TextView):
self.undo_disabled = self.textbuffer.undo_disabled # see bug 7097
self.textbuffer.connect('style-changed', self._on_buffer_style_changed)
self.textbuffer.connect('changed', self._on_buffer_changed)
self.undo_action = self.redo_action = None
Gtk.TextView.__init__(self)
self.set_buffer(self.textbuffer)
@@ -194,9 +302,9 @@ class StyledTextEditor(Gtk.TextView):
self._init_url_match()
self.url_match = None
self.toolbar = self._create_toolbar()
self.spellcheck = Spell(self)
self._internal_style_change = False
self.uimanager = None
self._connect_signals()
@@ -236,30 +344,6 @@ class StyledTextEditor(Gtk.TextView):
window.set_cursor(REGULAR_CURSOR)
self.url_match = None
def on_key_press_event(self, widget, event):
"""Signal handler.
Handle formatting shortcuts.
"""
if ((Gdk.keyval_name(event.keyval) == 'Z') and
match_primary_mask(event.get_state(), Gdk.ModifierType.SHIFT_MASK)):
self.redo()
return True
elif ((Gdk.keyval_name(event.keyval) == 'z') and
match_primary_mask(event.get_state())):
self.undo()
return True
else:
for accel, accel_name in self.action_accels.items():
key, mod = Gtk.accelerator_parse(accel)
if ((event.keyval == key) and (event.get_state() & mod)):
action_name = accel_name
action = self.action_group.get_action(action_name)
action.activate()
return True
return False
def on_insert_at_cursor(self, widget, string):
"""Signal handler. for debugging only."""
_LOG.debug("Textview insert '%s'" % string)
@@ -423,14 +507,13 @@ class StyledTextEditor(Gtk.TextView):
Reset the undoable buffer
"""
self.textbuffer.reset()
self.undo_action.set_sensitive(False)
self.redo_action.set_sensitive(False)
self.undo_action.set_enabled(False)
self.redo_action.set_enabled(False)
# private methods
def _connect_signals(self):
"""Connect to several signals of the super class Gtk.TextView."""
self.connect('key-press-event', self.on_key_press_event)
self.connect('insert-at-cursor', self.on_insert_at_cursor)
self.connect('delete-from-cursor', self.on_delete_from_cursor)
self.connect('paste-clipboard', self.on_paste_clipboard)
@@ -439,104 +522,74 @@ class StyledTextEditor(Gtk.TextView):
self.connect('button-release-event', self.on_button_release_event)
self.connect('populate-popup', self.on_populate_popup)
def _create_toolbar(self):
def create_toolbar(self, uimanager, window):
"""
Create a formatting toolbar.
:returns: toolbar containing text formatting toolitems.
:rtype: Gtk.Toolbar
"""
self.uimanager = uimanager
# build the toolbar
builder = Gtk.Builder.new_from_string(FORMAT_TOOLBAR, -1)
# define the actions...
# ...first the toggle actions, which have a ToggleToolButton as proxy
format_toggle_actions = [
(str(StyledTextTagType.ITALIC), 'format-text-italic', None, None,
_('Italic'), self._on_toggle_action_activate),
(str(StyledTextTagType.BOLD), 'format-text-bold', None, None,
_('Bold'), self._on_toggle_action_activate),
(str(StyledTextTagType.UNDERLINE), 'format-text-underline', None,
None, _('Underline'), self._on_toggle_action_activate),
_actions = [
('ITALIC', self._on_toggle_action_activate, '<PRIMARY>i', False),
('BOLD', self._on_toggle_action_activate, '<PRIMARY>b', False),
('UNDERLINE', self._on_toggle_action_activate, '<PRIMARY>u',
False),
('FONTCOLOR', self._on_action_activate),
('HIGHLIGHT', self._on_action_activate),
('LINK', self._on_link_activate),
('CLEAR', self._format_clear_cb),
('STUndo', self.undo, '<primary>z'),
('STRedo', self.redo, '<primary><shift>z'),
]
self.toggle_actions = [action[0] for action in format_toggle_actions]
# ...then the normal actions, which have a ToolButton as proxy
format_actions = [
(str(StyledTextTagType.FONTCOLOR), 'gramps-font-color',
_('Font Color'), None, _('Font Color'), self._on_action_activate),
(str(StyledTextTagType.HIGHLIGHT), 'gramps-font-bgcolor',
_('Background Color'), None, _('Background Color'),
self._on_action_activate),
(str(StyledTextTagType.LINK), 'go-jump', _('Link'), None,
_('Link'), self._on_link_activate),
('clear', 'edit-clear', _('Clear Markup'), None,
_('Clear Markup'), self._format_clear_cb),
]
# ...last the custom actions, which have custom proxies
default = StyledTextTagType.STYLE_DEFAULT[StyledTextTagType.FONTFACE]
# the following are done manually rather than using actions
fonts = SystemFonts()
fontface_action = ValueAction(str(StyledTextTagType.FONTFACE),
_("Font family"),
default,
ToolComboEntry,
fonts.get_system_fonts(),
False, #editable
True, #shortlist
None) # validator
fontface_action.connect('changed', self._on_valueaction_changed)
fontface = builder.get_object('Fontface')
fontface.init(fonts.get_system_fonts(), shortlist=True, validator=None)
fontface.set_entry_editable(False)
fontface.connect('changed', make_cb(
self._on_valueaction_changed, StyledTextTagType.FONTFACE))
# set initial value
default = StyledTextTagType.STYLE_DEFAULT[StyledTextTagType.FONTFACE]
self.fontface = fontface.get_child()
self.fontface.set_text(str(default))
fontface.show()
items = FONT_SIZES
fontsize = builder.get_object('Fontsize')
fontsize.init(items, shortlist=False, validator=is_valid_fontsize)
fontsize.set_entry_editable(True)
fontsize.connect('changed', make_cb(
self._on_valueaction_changed, StyledTextTagType.FONTSIZE))
# set initial value
default = StyledTextTagType.STYLE_DEFAULT[StyledTextTagType.FONTSIZE]
fontsize_action = ValueAction(str(StyledTextTagType.FONTSIZE),
_("Font size"),
default,
ToolComboEntry,
items,
True, #editable
False, #shortlist
is_valid_fontsize) #validator
fontsize_action.connect('changed', self._on_valueaction_changed)
spring = SpringSeparatorAction("spring", "", "", None)
# action accelerators
self.action_accels = {
'<PRIMARY>i': str(StyledTextTagType.ITALIC),
'<PRIMARY>b': str(StyledTextTagType.BOLD),
'<PRIMARY>u': str(StyledTextTagType.UNDERLINE),
}
self.fontsize = fontsize.get_child()
self.fontsize.set_text(str(default))
fontsize.show()
# create the action group and insert all the actions
self.action_group = ActionGroup(name='Format')
self.action_group.add_toggle_actions(format_toggle_actions)
self.undo_action = Gtk.Action(name="Undo", label=_('Undo'),
tooltip=_('Undo'))
self.undo_action.set_icon_name('edit-undo')
self.undo_action.connect('activate', self.undo)
self.redo_action = Gtk.Action.new(name="Redo", label=_('Redo'),
tooltip=_('Redo'))
self.redo_action.set_icon_name('edit-redo')
self.redo_action.connect('activate', self.redo)
self.action_group.add_action(self.undo_action)
self.action_group.add_action(self.redo_action)
self.action_group.add_actions(format_actions)
self.action_group.add_action(fontface_action)
self.action_group.add_action(fontsize_action)
self.action_group.add_action(spring)
self.action_group = ActionGroup('Format', _actions, 'ste')
act_grp = SimpleActionGroup()
window.insert_action_group('ste', act_grp)
window.set_application(uimanager.app)
uimanager.insert_action_group(self.action_group, act_grp)
# define the toolbar and create the proxies via ensure_update()
uimanager = Gtk.UIManager()
uimanager.insert_action_group(self.action_group, 0)
uimanager.add_ui_from_string(FORMAT_TOOLBAR)
uimanager.ensure_update()
self.undo_action = uimanager.get_action(self.action_group, "STUndo")
self.redo_action = uimanager.get_action(self.action_group, "STRedo")
# allow undo/redo to see actions if editable.
self.textbuffer.connect('changed', self._on_buffer_changed)
# undo/redo are initially greyed out, until something is changed
self.undo_action.set_enabled(False)
self.redo_action.set_enabled(False)
# get the toolbar and set it's style
toolbar = uimanager.get_widget('/ToolBar')
toolbar.set_style(Gtk.ToolbarStyle.ICONS)
self.undo_action.set_sensitive(False)
self.redo_action.set_sensitive(False)
toolbar = builder.get_object('ToolBar')
return toolbar
return toolbar, self.action_group
def set_transient_parent(self, parent=None):
self.transient_parent = parent
@@ -582,21 +635,22 @@ class StyledTextEditor(Gtk.TextView):
# Callback functions
def _on_toggle_action_activate(self, action):
def _on_toggle_action_activate(self, action, value):
"""
Toggle a style.
Toggle styles are e.g. 'bold', 'italic', 'underline'.
"""
action.set_state(value)
if self._internal_style_change:
return
style = int(action.get_name())
value = action.get_active()
_LOG.debug("applying style '%d' with value '%s'" % (style, str(value)))
self.textbuffer.apply_style(style, value)
style = action.get_name()
value = value.get_boolean()
_LOG.debug("applying style '%s' with value '%s'" % (style, str(value)))
self.textbuffer.apply_style(getattr(StyledTextTagType, style), value)
def _on_link_activate(self, action):
def _on_link_activate(self, action, value):
"""
Create a link of a selected region of text.
"""
@@ -633,10 +687,9 @@ class StyledTextEditor(Gtk.TextView):
else:
tag.data = uri
def _on_action_activate(self, action):
def _on_action_activate(self, action, value):
"""Apply a format set from a Gtk.Action type of action."""
style = int(action.get_name())
style = getattr(StyledTextTagType, action.get_name())
current_value = self.textbuffer.get_style_at_cursor(style)
if style == StyledTextTagType.FONTCOLOR:
@@ -668,14 +721,12 @@ class StyledTextEditor(Gtk.TextView):
(style, str(value)))
self.textbuffer.apply_style(style, value)
def _on_valueaction_changed(self, action):
"""Apply a format set by a ValueAction type of action."""
def _on_valueaction_changed(self, obj, style):
"""Apply a format set by a ShortListComboEntry."""
if self._internal_style_change:
return
style = int(action.get_name())
value = action.get_value()
value = obj.get_active_data()
try:
value = StyledTextTagType.STYLE_TYPE[style](value)
_LOG.debug("applying style '%d' with value '%s'" %
@@ -685,7 +736,7 @@ class StyledTextEditor(Gtk.TextView):
_LOG.debug("unable to convert '%s' to '%s'" %
(value, StyledTextTagType.STYLE_TYPE[style]))
def _format_clear_cb(self, action):
def _format_clear_cb(self, action, value):
"""
Remove all formats from the selection or from all.
@@ -709,24 +760,27 @@ class StyledTextEditor(Gtk.TextView):
def _on_buffer_changed(self, buffer):
"""synchronize the undo/redo buttons with what is possible"""
self.undo_action.set_sensitive(self.textbuffer.can_undo)
self.redo_action.set_sensitive(self.textbuffer.can_redo)
if self.undo_action:
self.undo_action.set_enabled(self.textbuffer.can_undo)
self.redo_action.set_enabled(self.textbuffer.can_redo)
def _on_buffer_style_changed(self, buffer, changed_styles):
"""Synchronize actions as the format changes at the buffer's cursor."""
if not self.uimanager:
return # never initialized a toolbar, not editable
types = [StyledTextTagType.ITALIC, StyledTextTagType.BOLD,
StyledTextTagType.UNDERLINE]
self._internal_style_change = True
for style, style_value in changed_styles.items():
if str(style) in self.toggle_actions:
action = self.action_group.get_action(str(style))
self._internal_style_change = True
action.set_active(style_value)
self._internal_style_change = False
if ((style == StyledTextTagType.FONTFACE) or
(style == StyledTextTagType.FONTSIZE)):
action = self.action_group.get_action(str(style))
self._internal_style_change = True
action.set_value(style_value)
self._internal_style_change = False
if style in types:
action = self.uimanager.get_action(
self.action_group, str(StyledTextTagType(style)).upper())
action.change_state(Variant.new_boolean(style_value))
elif (style == StyledTextTagType.FONTFACE):
self.fontface.set_text(style_value)
elif style == StyledTextTagType.FONTSIZE:
self.fontsize.set_text(str(style_value))
self._internal_style_change = False
def _spell_change_cb(self, menuitem, spellcheck):
"""Set spell checker spellcheck according to user selection."""
@@ -818,20 +872,17 @@ class StyledTextEditor(Gtk.TextView):
start, end = self.textbuffer.get_bounds()
return self.textbuffer.get_text(start, end, True)
def get_toolbar(self):
"""
Get the formatting toolbar of the editor.
:returns: toolbar widget to use as formatting GUI.
:rtype: Gtk.Toolbar
"""
return self.toolbar
def undo(self, obj=None):
def undo(self, *obj):
self.textbuffer.undo()
def redo(self, obj=None):
def redo(self, *obj):
self.textbuffer.redo()
#-------------------------------------------------------------------------
#
# Module functions
#
#-------------------------------------------------------------------------
def uri_dialog(self, uri, callback):
"""
@@ -851,12 +902,14 @@ def uri_dialog(self, uri, callback):
uri = "gramps://%s/handle/%s" % (object_class, handle)
EditLink(obj.dbstate, obj.uistate, obj.track, uri, callback)
#-------------------------------------------------------------------------
#
# Module functions
#
#-------------------------------------------------------------------------
def is_valid_fontsize(size):
"""Validator function for font size selector widget."""
return (size > 0) and (size < 73)
def make_cb(func, value):
"""
Generates a callback function based off the passed arguments
"""
return lambda x: func(x, value)
-78
View File
@@ -1,78 +0,0 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2008 Zsolt Foldvari
#
# 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.
#
"ToolComboEntry class."
__all__ = ["ToolComboEntry"]
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
import logging
_LOG = logging.getLogger(".widgets.toolcomboentry")
#-------------------------------------------------------------------------
#
# GTK modules
#
#-------------------------------------------------------------------------
#from gi.repository import GObject
from gi.repository import Gtk
#-------------------------------------------------------------------------
#
# Gramps modules
#
#-------------------------------------------------------------------------
from .valuetoolitem import ValueToolItem
from .shortlistcomboentry import ShortlistComboEntry
#-------------------------------------------------------------------------
#
# ToolComboEntry class
#
#-------------------------------------------------------------------------
class ToolComboEntry(ValueToolItem):
"""Tool bar item containing a ShortlistComboEntry widget."""
__gtype_name__ = "ToolComboEntry"
def _create_widget(self, items, editable, shortlist=True, validator=None):
self.set_border_width(2)
self.set_homogeneous(False)
self.set_expand(False)
combo = ShortlistComboEntry(items, shortlist, validator)
if (Gtk.MAJOR_VERSION, Gtk.MINOR_VERSION) < (3, 20):
combo.set_focus_on_click(False)
else:
Gtk.Widget.set_focus_on_click(combo, False)
combo.set_entry_editable(editable)
combo.show()
self.add(combo)
combo.connect('changed', self._on_widget_changed)
def set_value(self, value):
self.get_child().set_active_data(value)
def get_value(self):
return self.get_child().get_active_data()
+5 -1
View File
@@ -65,7 +65,8 @@ class ValidatedComboEntry(Gtk.ComboBox):
__gtype_name__ = "ValidatedComboEntry"
def __init__(self, datatype, model=None, column=-1, validator=None, width=-1):
Gtk.ComboBox.__init__(self, model=model)
Gtk.ComboBox.__init__(self)
self.set_model(model)
self._entry = Gtk.Entry()
self._entry.set_width_chars(width)
@@ -201,6 +202,9 @@ class ValidatedComboEntry(Gtk.ComboBox):
self._internal_change = True
new_iter = self._is_in_model(new_data)
if new_iter is None:
if self.get_active_iter() is None:
# allows response when changing between two non-model values
self.set_active(0)
self.set_active(-1)
else:
self.set_active_iter(new_iter)
-169
View File
@@ -1,169 +0,0 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2008 Zsolt Foldvari
#
# 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.
#
"ValueAction class."
__all__ = ["ValueAction"]
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
import logging
_LOG = logging.getLogger(".widgets.valueaction")
#-------------------------------------------------------------------------
#
# GTK modules
#
#-------------------------------------------------------------------------
from gi.repository import GObject
from gi.repository import Gtk
#-------------------------------------------------------------------------
#
# Gramps modules
#
#-------------------------------------------------------------------------
from .valuetoolitem import ValueToolItem
#-------------------------------------------------------------------------
#
# ValueAction class
#
#-------------------------------------------------------------------------
class ValueAction(Gtk.Action):
"""
Value action class.
(A ValueAction with menu item doesn't make any sense.)
"""
__gtype_name__ = "ValueAction"
__gsignals__ = {
'changed': (GObject.SignalFlags.RUN_FIRST,
None, #return value
()), # arguments
}
def __init__(self, name, tooltip, default, itemtype, *args):
"""
Create a new ValueAction instance.
:param name: the name of the action
:type name: str
:param tooltip: tooltip string
:type tooltip: str
:param default: default value for the action, it will set the type of
the action and thus the type of all the connected
proxies.
:type default: set by itemtype
:param itemtype: default tool item class
:type itemtype: :class:`.ValueToolItem` subclass
:param args: arguments to be passed to the default toolitem class
at creation. see: :meth:`do_create_tool_item`
:type args: list
"""
Gtk.Action.__init__(self, name=name, label='', tooltip=tooltip,
stock_id=None)
self._value = default
self._data_type = type(default)
# have to be remembered, because we can't access
# GtkAction->toolbar_item_type later.
self._default_toolitem_type = itemtype
##TODO GTK3: following is deprecated, must be replaced by
## itemtype.set_related_action(ValueAction) in calling class?
## self.set_tool_item_type(itemtype)
self._args_for_toolitem = args
self._handlers = {}
def do_changed(self):
"""
Default signal handler for 'changed' signal.
Synchronize all the proxies with the active value.
"""
for proxy in self.get_proxies():
proxy.handler_block(self._handlers[proxy])
proxy.set_value(self._value)
proxy.handler_unblock(self._handlers[proxy])
def do_create_tool_item(self):
"""
Create a 'default' toolbar item widget.
Override the default method, to be able to pass the required
parameters to the proxy's constructor.
This method is called from Gtk.UIManager.ensure_update(), when a
'toolitem' is found in the UI definition with a name refering to a
ValueAction. Thus, to use the action via the UIManager a 'default'
toolitem type has to be set with the Gtk.Action.set_tool_item_type()
method, before invoking the Gtk.UIManager.ensure_update() method.
Widgets other than the default type has to be created and added
manually with the Gtk.Action.connect_proxy() method.
:returns: a toolbar item connected to the action.
:rtype: :class:`.ValueToolItem` subclass
"""
proxy = self._default_toolitem_type(self._data_type,
self._args_for_toolitem)
self.connect_proxy(proxy)
return proxy
def _on_proxy_changed(self, proxy):
"""Signal handler for the proxies' 'changed' signal."""
value = proxy.get_value()
if value is not None:
self.set_value(value)
def connect_proxy(self, proxy):
"""
Connect a widget to an action object as a proxy.
:param proxy: widget to be connected
:type proxy: :class:`.ValueToolItem` subclass
"""
if not isinstance(proxy, ValueToolItem):
raise TypeError
# do this before connecting, so that we don't call the handler
proxy.set_value(self._value)
self._handlers[proxy] = proxy.connect('changed', self._on_proxy_changed)
# if this is called the proxy will appear on the proxy list twice. why?
#Gtk.Action.connect_proxy(self, proxy)
def set_value(self, value):
"""Set value to action."""
if not isinstance(value, self._data_type):
raise TypeError
self._value = value
self.emit('changed')
def get_value(self):
"""Get the value from the action."""
return self._value
-92
View File
@@ -1,92 +0,0 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2008 Zsolt Foldvari
#
# 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.
#
"ValueToolItem class."
__all__ = ["ValueToolItem"]
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
import logging
_LOG = logging.getLogger(".widgets.valuetoolitem")
#-------------------------------------------------------------------------
#
# GTK modules
#
#-------------------------------------------------------------------------
from gi.repository import GObject
from gi.repository import Gtk
#-------------------------------------------------------------------------
#
# ValueToolItem class
#
#-------------------------------------------------------------------------
class ValueToolItem(Gtk.ToolItem):
"""ValueToolItem is an abstract toolbar proxy for ValueAction.
For each kind of widget a separete tool item proxy has to be
subclassed from this ValueToolItem.
"""
__gtype_name__ = "ValueToolItem"
__gsignals__ = {
'changed': (GObject.SignalFlags.RUN_FIRST,
None, #return value
()), # arguments
}
def __init__(self, data_type, args):
Gtk.ToolItem.__init__(self)
self._data_type = data_type
self._create_widget(*args)
def _on_widget_changed(self, widget):
self.emit('changed')
def _create_widget(self, args):
"""Create the apropriate widget for the actual proxy."""
raise NotImplementedError
def set_value(self, value):
"""Set new value for the proxied widget.
The method is responsible converting the data type between action and
widget.
"""
raise NotImplementedError
def get_value(self):
"""Get value from the proxied widget.
The method is responsible converting the data type between action and
widget.
"""
raise NotImplementedError
+1 -1
View File
@@ -27,7 +27,7 @@ plg.name = _("BSDDB")
plg.name_accell = _("_BSDDB Database")
plg.description = _("Berkeley Software Distribution Database Backend")
plg.version = '1.0'
plg.gramps_target_version = "5.0"
plg.gramps_target_version = "5.1"
plg.status = STABLE
plg.fname = 'bsddb.py'
plg.ptype = DATABASE
+2 -22
View File
@@ -572,7 +572,6 @@ class DBAPI(DbGeneric):
"""
Set the default grouping name for a surname.
"""
self._txn_begin()
self.dbapi.execute("SELECT 1 FROM name_group WHERE name = ?",
[name])
row = self.dbapi.fetchone()
@@ -583,7 +582,6 @@ class DBAPI(DbGeneric):
self.dbapi.execute(
"INSERT INTO name_group (name, grouping) VALUES (?, ?)",
[name, grouping])
self._txn_commit()
def _commit_base(self, obj, obj_key, trans, change_time):
"""
@@ -813,33 +811,15 @@ class DBAPI(DbGeneric):
ref_class_name])
callback(5)
def rebuild_secondary(self, callback=None):
def rebuild_secondary(self, update):
"""
Rebuild secondary indices
"""
if self.readonly:
return
# First, expand blob to individual fields:
self._txn_begin()
index = 1
for obj_type in ('Person', 'Family', 'Event', 'Place', 'Repository',
'Source', 'Citation', 'Media', 'Note', 'Tag'):
for handle in self.method('get_%s_handles', obj_type)():
obj = self.method('get_%s_from_handle', obj_type)(handle)
self._update_secondary_values(obj)
if callback:
callback(index)
index += 1
self._txn_commit()
if callback:
callback(11)
self._update_secondary_values()
# Next, rebuild stats:
gstats = self.get_gender_stats()
self.genderStats = GenderStats(gstats)
if callback:
callback(12)
def _has_handle(self, obj_key, handle):
table = KEY_TO_NAME_MAP[obj_key]
+1 -1
View File
@@ -27,7 +27,7 @@ register(DATABASE,
name_accell=_('_SQLite Database'),
description=_('SQLite Database'),
version='1.0.0',
gramps_target_version='5.0',
gramps_target_version='5.1',
status=STABLE,
fname='sqlite.py',
databaseclass='SQLite',
+1 -1
View File
@@ -21,7 +21,7 @@ from gramps.gen.plug._pluginreg import newplugin, STABLE
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
MODULE_VERSION="5.0"
MODULE_VERSION="5.1"
#------------------------------------------------------------------------
#
-14
View File
@@ -337,20 +337,6 @@ class HtmlDoc(BaseDoc, TextDoc):
self._empty = 0
self.__write_text(text, mark, links=links)
def write_markup(self, text, s_tags, mark=None):
"""
Overwrite base method
Writes the text in the current paragraph. Should only be used after a
start_paragraph and before an end_paragraph.
@param text: text to write. The text is assumed to be _not_ escaped
@param s_tags: assumed to be list of styledtexttags to apply to the
text
@param mark: IndexMark to use for indexing
"""
markuptext = self._backend.add_markup_from_styled(text, s_tags)
self.__write_text(markuptext, mark=mark, markup=True)
def write_title(self):
"""
Add title field to header

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