Compare commits
118
Commits
v5.0.1
..
FR10850_V1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d48dcc9c5f | ||
|
|
263a082afe | ||
|
|
dd9ddab849 | ||
|
|
cfa278886b | ||
|
|
1c430a6b91 | ||
|
|
b0eb712933 | ||
|
|
51a7ad9483 | ||
|
|
d6e9d62fad | ||
|
|
3bac4a1036 | ||
|
|
1995a7068c | ||
|
|
5dc06d023d | ||
|
|
d98a1857dc | ||
|
|
7da8811327 | ||
|
|
15db2dd603 | ||
|
|
97b15322d4 | ||
|
|
824bf7e40f | ||
|
|
56fa261ef2 | ||
|
|
1efab19f1e | ||
|
|
51e294f748 | ||
|
|
cb65fd93ca | ||
|
|
5b9600d835 | ||
|
|
cf80d17040 | ||
|
|
d4f906f22d | ||
|
|
d189e334d8 | ||
|
|
a48a94d872 | ||
|
|
8e5dc220dc | ||
|
|
dca2f610dc | ||
|
|
3d1833e307 | ||
|
|
aa221cc3c7 | ||
|
|
51b7d1c420 | ||
|
|
674d286f87 | ||
|
|
0161c4b917 | ||
|
|
de31a42fc8 | ||
|
|
9c508de5fd | ||
|
|
1b00d95ce4 | ||
|
|
78870decb8 | ||
|
|
1a5696eb2c | ||
|
|
269d38da2c | ||
|
|
99f77b0a88 | ||
|
|
264fdda4d0 | ||
|
|
8092b88ad4 | ||
|
|
3251e2ae88 | ||
|
|
f718c5f8b4 | ||
|
|
a96a446b47 | ||
|
|
5658411acf | ||
|
|
a4403d719e | ||
|
|
8597a10c40 | ||
|
|
d0c0045dc1 | ||
|
|
868abdc0d9 | ||
|
|
ebf88bf5c5 | ||
|
|
c3814a4e42 | ||
|
|
52fe365919 | ||
|
|
bc39dda9e7 | ||
|
|
257275f169 | ||
|
|
9e61809b17 | ||
|
|
9e2b935db1 | ||
|
|
9a386574d8 | ||
|
|
90bdb0a840 | ||
|
|
ae322dbdc8 | ||
|
|
208feceb03 | ||
|
|
32dd3a2e14 | ||
|
|
0ae51c9522 | ||
|
|
59bd9f040d | ||
|
|
df00dd1f32 | ||
|
|
ca49b56774 | ||
|
|
19f8c3561c | ||
|
|
79ff9bc216 | ||
|
|
b54672d28d | ||
|
|
6b42d71158 | ||
|
|
ac593d814d | ||
|
|
617e2212c8 | ||
|
|
ad15ef7961 | ||
|
|
406faa5603 | ||
|
|
4e0d562208 | ||
|
|
43ef686622 | ||
|
|
d59fe6b2af | ||
|
|
d677a1a785 | ||
|
|
be776d6a31 | ||
|
|
1482fedb9c | ||
|
|
00f8df60ce | ||
|
|
f31caf1ea4 | ||
|
|
8ebb4d35fa | ||
|
|
c5f2717623 | ||
|
|
e5d5cfbd3a | ||
|
|
bd5f6e4711 | ||
|
|
e15deff4ed | ||
|
|
9d906c29a2 | ||
|
|
6577d43e4e | ||
|
|
1a065485e3 | ||
|
|
009783a59a | ||
|
|
1b4f70c808 | ||
|
|
dd4a727521 | ||
|
|
ebb7111f25 | ||
|
|
86fd14613e | ||
|
|
5276461239 | ||
|
|
40f47bc22d | ||
|
|
8150403ccb | ||
|
|
b43d94ab16 | ||
|
|
849290a3b7 | ||
|
|
0b617e9fd6 | ||
|
|
6eb435142e | ||
|
|
e14ea777d5 | ||
|
|
46d73a16a0 | ||
|
|
4d2b918d39 | ||
|
|
4acfdcce52 | ||
|
|
f3b3eec211 | ||
|
|
a840566e02 | ||
|
|
f6a2199f68 | ||
|
|
dfc9dde32d | ||
|
|
50f93f54ec | ||
|
|
9cb1d96725 | ||
|
|
40013dccc3 | ||
|
|
24af1b8420 | ||
|
|
213d656df4 | ||
|
|
c09b4e96d2 | ||
|
|
a80875e00c | ||
|
|
bbdedb5097 | ||
|
|
dd0671b111 |
@@ -23,5 +23,8 @@ test/data
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
|
||||
# Glade temp files
|
||||
*~
|
||||
|
||||
+6
-6
@@ -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 ast�s and bytecode. This is loaded to
|
||||
# manipulate and analyze python ast�s 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
|
||||
|
||||
@@ -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
@@ -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 *
|
||||
|
||||
@@ -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
|
||||
------------------------------------------------
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
+195
-188
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -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 "Help > Gramps Mailing Lists".</_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>
|
||||
|
||||
|
||||
@@ -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 "Maggie"</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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'])
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
@@ -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])
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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]:
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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"
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user