Compare commits
232 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 06b7ce677d | |||
| 764cd996b1 | |||
| caaa5db54d | |||
| 03a6c5e296 | |||
| 7ebe10090d | |||
| 6f0a8ffa32 | |||
| 7727813c13 | |||
| 84c7359f8e | |||
| e19d519d25 | |||
| 8b11e650f7 | |||
| 20d4b5119c | |||
| e4e27b5bc0 | |||
| 82e4ddd543 | |||
| 5dcdd4a850 | |||
| 3268b07b8b | |||
| eebc60a9ba | |||
| a8e24f2917 | |||
| 0abce8dfaf | |||
| 945f1a5000 | |||
| bea4df1cfd | |||
| 28135d51e9 | |||
| 6b572212b7 | |||
| 89bada596d | |||
| 35ca071220 | |||
| ecd7637d27 | |||
| 7effc7980b | |||
| e5f908301e | |||
| 13a58dc924 | |||
| 63e89186ce | |||
| 855709e2c8 | |||
| c195e5b0bb | |||
| 91c7356567 | |||
| 02e6aedc25 | |||
| 0b2c7c757f | |||
| 417d85a353 | |||
| 459eb37cf2 | |||
| ed267ca5e5 | |||
| 9e1c81d979 | |||
| 96e55f91bf | |||
| ddecdb854e | |||
| 380c3a5764 | |||
| 2f215e34a6 | |||
| b92dbe2ab5 | |||
| 109e64f657 | |||
| 51bedcd46c | |||
| 6214d3c1f3 | |||
| 976cabd837 | |||
| e6844424ae | |||
| a6f631a542 | |||
| 71248be3e5 | |||
| 8222308239 | |||
| da7c2927a1 | |||
| 9823168d15 | |||
| 73f772232d | |||
| 7929e56fae | |||
| ed5f72fc04 | |||
| 8a2ad56f61 | |||
| 192fa328c2 | |||
| 82c275d18d | |||
| 6c0c2c17f8 | |||
| 6eafbadeb1 | |||
| bb562ed630 | |||
| 0e89688da9 | |||
| 114f129d38 | |||
| b781ba8e03 | |||
| 71040c0fd1 | |||
| fc0c0f474e | |||
| e3934bc72d | |||
| 0f7246f9ee | |||
| 91dbfb82f3 | |||
| 1764c1dcd2 | |||
| 2fd1ee8520 | |||
| 2267c90317 | |||
| fd75bf0e75 | |||
| b63524b99b | |||
| 225f6e545f | |||
| cc3ef70997 | |||
| 828060d2eb | |||
| 39dcc537b6 | |||
| 6dfbe59255 | |||
| 7a82cf5104 | |||
| 18f3824eca | |||
| 4b27a56186 | |||
| 423d27e5a1 | |||
| 6fe6455251 | |||
| 645262992d | |||
| 023ccd5086 | |||
| fa265e2a83 | |||
| f4c30c462b | |||
| e140572cf4 | |||
| 38a0d10be7 | |||
| f0f3a5b037 | |||
| ada6a11ed7 | |||
| 0fbbbb6ebc | |||
| f24e3c712d | |||
| af4e34c760 | |||
| c851640a4f | |||
| a198f6821a | |||
| f2e39009af | |||
| 9655a977ad | |||
| 2a700850d2 | |||
| 1cc0271270 | |||
| d99a28d1a2 | |||
| be5fbc730c | |||
| 7e1b2f9de1 | |||
| f252e02b15 | |||
| 9e98aa0c25 | |||
| 198a707f5b | |||
| e2b46f886b | |||
| a78bad62c2 | |||
| ba36caa2bd | |||
| a1dba65495 | |||
| f02e7f2580 | |||
| c81336ae20 | |||
| 0ce396d2c1 | |||
| 2abc7c8475 | |||
| 0f001bf131 | |||
| 77a5b1ab74 | |||
| 04e39b96b0 | |||
| d2dbe4427d | |||
| ce1c01f963 | |||
| 20231f676f | |||
| 69d2600bc4 | |||
| d526161eaa | |||
| 243580fb35 | |||
| 0e268858e6 | |||
| 77b71e1396 | |||
| 9d13689751 | |||
| dcf5132124 | |||
| 8e6b423f26 | |||
| 604f745338 | |||
| 97e29dade6 | |||
| 90fbb2fdf7 | |||
| 8f910a8750 | |||
| 4697de789c | |||
| 0a0d77d6db | |||
| 7bd67f88a2 | |||
| e5725f28c3 | |||
| 6baf023ed9 | |||
| 68d50ae0e9 | |||
| eb30461eb5 | |||
| f732f907fe | |||
| 6c4be7c5b2 | |||
| 662ee802cb | |||
| 525c08d14f | |||
| ca709909cc | |||
| 56078f14b8 | |||
| 2361294b5e | |||
| 61b159608f | |||
| 1e4f8227ab | |||
| 7d9df26da5 | |||
| 5c96c5054b | |||
| 366fdb34f9 | |||
| db4977c244 | |||
| 7f10ab796e | |||
| 7004ce9033 | |||
| 6154ebad23 | |||
| 8f7a645ece | |||
| 49538415b5 | |||
| 0195805a3b | |||
| 6d4843d3ac | |||
| b46c4c6e80 | |||
| 230b192532 | |||
| 7810d946b4 | |||
| f251a99e6f | |||
| 3de9ff5dae | |||
| 69a3b4b27d | |||
| 421d38eb89 | |||
| 1c65ab29aa | |||
| dd3700c85f | |||
| 99c683f8e2 | |||
| d5bc201cb4 | |||
| 55492a7573 | |||
| e4dc6a57fb | |||
| e197ebe0d6 | |||
| c4b7cda610 | |||
| 26f09455d5 | |||
| 28e61a34b0 | |||
| 4fa115870e | |||
| edaba13fac | |||
| 55a09b5ed3 | |||
| 5f3ee3befe | |||
| 300d520cb0 | |||
| c34398cbef | |||
| fe01effd25 | |||
| d4f3b0fa4f | |||
| 99b9de2a5f | |||
| 3e5dbd4e5b | |||
| f0641d505c | |||
| afd2f9e9c3 | |||
| fe13612018 | |||
| 0b277c4bb2 | |||
| 2078bcc17c | |||
| 199f81a832 | |||
| 3bf7c1df0a | |||
| 5a2b0ce910 | |||
| a4b1518a04 | |||
| 2a1367ca51 | |||
| aa9463c09b | |||
| 3a8a8b94bc | |||
| 7f2b854632 | |||
| e0fb0efbea | |||
| 2a03ca499b | |||
| cb299b606d | |||
| ab26f6fcc1 | |||
| bbdd9c54a2 | |||
| 9a1a5b7c5d | |||
| 59b8837a3a | |||
| 404f9b72ce | |||
| 6bb0f12d28 | |||
| b9a77a9b9f | |||
| 94f108807f | |||
| c4e86a732c | |||
| 438f4269a3 | |||
| 099def6fd0 | |||
| 043396b7b9 | |||
| f3effea730 | |||
| a35ad26696 | |||
| 69fc354f06 | |||
| 9f42185379 | |||
| 21cf42b077 | |||
| b08ed4c698 | |||
| 5edc980642 | |||
| bf9b4ea7a1 | |||
| f63246417c | |||
| d0c2654a41 | |||
| d630052347 | |||
| 6ef5008b6d | |||
| 4fe8eb7981 | |||
| 4b4e10c229 | |||
| 557f94503f | |||
| 4640a6f107 |
@@ -1,3 +1,78 @@
|
||||
2013-05-22
|
||||
Version 3.4.5 of Gramps! "We have also developed a tomato which can eject itself when an accident is imminent", a maintenance release.
|
||||
* problem after upgrading to 3.4.4 from 3.3.1
|
||||
* ability to keep custom filename on output
|
||||
* book report: sub reports forget/overwrite their settings when trying to re-configure them
|
||||
* end of line report options window - changing output format cause change active tab to "Report Options"
|
||||
* various updated translations: de, es, fr, nb, nl, pl, sk
|
||||
|
||||
2013-05-15
|
||||
Version 3.4.4 of Gramps! "The Ministry of Silly Names", a maintenance release.
|
||||
* infinite recursion bug in narrative web generation
|
||||
* protection on family trees when using version 3.4 and 4.0 on the same PC (road to 4.0)
|
||||
* merging notes of media with citations now works
|
||||
* crash during Calculate Preview of a filtered XML export
|
||||
* fix annoying errors on navigation related to citations gramplet and tag object.
|
||||
* listing the Family Trees can corrupt them.
|
||||
* various fix around handling Gedcom file format
|
||||
* fix citations and sources import on ProGen format
|
||||
* better date handling and better alternate translation support on some textual reports according to locale under windows
|
||||
* avoid Errors when setting wrong value as markup for invalid dates (Preferences)
|
||||
* fix paragraph layout on PDF format or print output
|
||||
* New: New-Zealand holidays
|
||||
* Polish and backport code on XML import (road to 4.0)
|
||||
* Regular expression rules now use search rather than match, fix design issues on regex filter rules
|
||||
* Disable/Enable indent spouse on descendants tree
|
||||
* fix regular expressions on Place filter rule
|
||||
* consistency on cli arguments (road to 4.0)
|
||||
* fix call of non-existant process on references proxy, enhanced tests on proxy filter
|
||||
* fix NarWeb creation via cli for some non-english locales
|
||||
* Various updated translations: ca, de, fr, it, nl, pt_BR, ru, sv, uk
|
||||
|
||||
2013-03-19
|
||||
Version 3.4.3 of Gramps! "Whenever life gets you down, Mrs. Brown", a maintenance release.
|
||||
* Sorting (both in the main display window, and particularly in Narrative Web output) now uses PyICU (if that module is available). Inclusion of PyICU is 'strongly recommended'. This resolves a number of bugs particularly related to sorting of non-Latin characters, and sorting on MS Windows and Mac OS X. Some changes have been made in Narrative Web to support contractions for alphabetic indices.
|
||||
* The automatic Addon checking and download now works once again (the location used in Gramps 3.4.2 and before had been changed, so the the automatic process was no longer working).
|
||||
* Import from Pro-Gen has been updated (at last) to take account of the change to Citations (in 3.4.0)
|
||||
* Import and Export of address fields in GEDCOM has been improved so that the round-trip works properly.
|
||||
* GEDCOM Repositories not imported correctly from FTM for Windows and Heredis.
|
||||
* Fixes to a number of errors in filtering notes.
|
||||
* Fix some errors in determining whether someone is alive (e.g. for filtering out alive people).
|
||||
* Make availability of GraphViz settings depend on output format
|
||||
* Improve the descriptions and tooltip for GraphViz aspect ratio option
|
||||
* Fixed update problems with citation bottombar gramplet (bug #6336)
|
||||
* Fixed Open Document Text output in Book report (bug #6457)
|
||||
* A number of changes to Narrative Web:
|
||||
** Media objects attached to Marriage events and Sources are not included in Narrative Web Site
|
||||
** restructure the families index so families are indexed under both spouses, and the family name is normalised
|
||||
** separate out Families section in individual and families pages so individual page links to the family page and family page links to both people
|
||||
** normalise links to families so the link is only displayed if the family page is present, and the gid is included when appropriate
|
||||
** remove highlighting of media subregions except in the media pages (it was confusing and not very well implemented)
|
||||
** include people whose surname is absent in the individual, surname and families indexes
|
||||
** html_escape names and surnames
|
||||
** always display media thumbnails for first image in Gallery list (in some cases they were suppressed if they had been displayed at the top of the page)
|
||||
** change partner and parent columns in families index to improve the layout of the HTML and put the comma between multiple partners in the right place
|
||||
** use event description (where present) instead of just event type in back references
|
||||
** fix bug in the way obj_dict and bkref_dict were initialised
|
||||
** fix missing document.png for missing media
|
||||
** fixed problems that bibliography ignores media attached to citations, so if that is the only 'interesting' thing about the citation, the citation media is not output
|
||||
** Replaced person link routine with one that takes into account whether there is a page for the person.
|
||||
** Included repository reference media type and call number in the 'Repositories' section of the relevant source instead of the Repository page.
|
||||
** Implemented a generalised back reference function to display the 'References' section of all pages. This recursively displays references till one is found for which a page exists.
|
||||
** Removed list of people and families from heading of the event pages as these are now in the 'References' section.
|
||||
** Fixed bug "0005968: Narrated Web Site not copying Source Citations files such as jpg or pdf docs to web site
|
||||
** Fixed bug "0005946 GRAMPS failed to insert jpeg image into proper place for an event" by displaying a thumbnail for citation media in the 'Source References' section (with a link to the media page)
|
||||
** Tidy up media pages - remove unused parameters, use list of media items generated in first pass. Should fix bugs 2365, 5905 and 6009.
|
||||
** Tidy up sources pages - fix numbering of repositories, remove unused parameters, fix title of individual source pages
|
||||
** Bug: reset NarrWeb navigation menu layout when style sheet doesn't support it
|
||||
** Change Source Pages to use the list of sources generated by the first pass that finds objects to be output, and simplify references section on the Source page to use the references passed to it.
|
||||
** Fix option to suppress Gramps ID (bug #6237)
|
||||
* a number of technical changes to Narrative Web
|
||||
** Removed a lot of redundant code and parameters (mainly connected with the old way of determining the objects to be included in the report).
|
||||
** Movement of some large chunks of code within the source file and some initial work towards GEPS 022: Narrative Website Refactor. Functionality should be unchanged.
|
||||
** Moved routines for calculating objects to be output so they can be part of default list building classes.
|
||||
* Various updated translations: da, de, es, fr, it, nb, nl, pt_BR, pt_PT, sv, uk
|
||||
|
||||
2012-10-28
|
||||
Version 3.4.2 -- the "We're all individuals!" bug fix release.
|
||||
* Some fixes on NarrativeWeb report
|
||||
|
||||
@@ -30,7 +30,15 @@ The following packages are *STRONGLY RECOMMENDED* to be installed:
|
||||
Obtain it from: http://www.graphviz.org
|
||||
pyexiv2 Enables Gramps to manage Exif metadata embedded in your
|
||||
media. Gramps needs version 0.1.3 or greater.
|
||||
Obtain it from: http://tilloy.net/dev/pyexiv2/download.html
|
||||
Obtain it from: http://tilloy.net/dev/pyexiv2/download.html
|
||||
PyICU Improves localised sorting in Gramps. In particular, this
|
||||
applies to sorting in the various views and in the Narrative
|
||||
Web output. It is particularly helpful for non-Latin
|
||||
characters, for non-English locales and on MS Windows and
|
||||
Mac OS X platforms. If it is not available, sorting is done
|
||||
through built-in libraries. PyICU is fairly widely available
|
||||
through the package managers of distributions. The home page
|
||||
is http://pyicu.osafoundation.org/
|
||||
|
||||
The following packages are optional
|
||||
python gtkspell Enable spell checking in the notes, gtkspell contains the
|
||||
|
||||
+3
-3
@@ -5,16 +5,16 @@ dnl May need to run automake && aclocal first
|
||||
|
||||
AC_PREREQ(2.57)
|
||||
dnl NOTE: arg to macro below becomes the "VERSION"
|
||||
AC_INIT(gramps, 3.4.2, [gramps-bugs@lists.sourceforge.net])
|
||||
AC_INIT(gramps, 3.4.5, [gramps-bugs@lists.sourceforge.net])
|
||||
AC_CONFIG_SRCDIR(configure.in)
|
||||
AM_INIT_AUTOMAKE([1.6.3 foreign])
|
||||
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
dnl RELEASE=0.SVN$(svnversion -n .)
|
||||
RELEASE=0.SVN$(svnversion -n .)
|
||||
dnl RELEASE=0beta
|
||||
dnl RELEASE=0rc1
|
||||
RELEASE=1
|
||||
dnl RELEASE=1
|
||||
|
||||
VERSIONSTRING=$VERSION
|
||||
if test x"$RELEASE" != "x"
|
||||
|
||||
+11
-1
@@ -1,4 +1,4 @@
|
||||
.TH gramps 1 "@VERSION@" "January 2008" "@VERSION@"
|
||||
.TH gramps 1 "@VERSION@" "December 2012" "@VERSION@"
|
||||
.SH NAME
|
||||
gramps \- Genealogical Research and Analysis Management Programming System.
|
||||
|
||||
@@ -113,6 +113,16 @@ i.e. \fB\-i\fR \fIFILE1\fR \fB\-i\fR \fIFILE2\fR
|
||||
and \fB\-i\fR \fIFILE2\fR \fB\-i\fR \fIFILE1\fR might produce different
|
||||
gramps IDs in the resulting database.
|
||||
|
||||
.TP
|
||||
.BI \-e,\-\^\-export= " FILE"
|
||||
Export data into \fIFILE\fR. For \fBgramps\-xml\fR, \fBgedcom\fR,
|
||||
\fBwft\fR, \fBgramps\-pkg\fR, and \fBgeneweb\fR, the \fIFILE\fR is
|
||||
the name of the resulting file.
|
||||
.br
|
||||
|
||||
When more than one output file is given, each has to be preceded
|
||||
by \fB\-e\fR flag. The files are written one by one, in the specified order.
|
||||
|
||||
.TP
|
||||
.BI \-a,\-\^\-action= " ACTION"
|
||||
Perform \fIACTION\fR on the imported data. This is done after all imports
|
||||
|
||||
Vendored
+1
@@ -12,6 +12,7 @@ Recommends: python-webkit
|
||||
Enable html rendering for Geographic view and Web view. If both
|
||||
are installed webkit will be used. python-gtkmozembed may be more
|
||||
stable.
|
||||
Recommends: python-pyicu
|
||||
Suggests: ttf-freefont
|
||||
Allows more fonts in reports
|
||||
Suggests: python-gtkspell python-enchant
|
||||
|
||||
Vendored
+3
-3
@@ -10,11 +10,11 @@ XS-Python-Version: >=2.5
|
||||
|
||||
Package: gramps
|
||||
Architecture: all
|
||||
Depends: ${python:Depends}, librsvg2-common, python-gtk2, python-pyexiv2, xdg-utils, graphviz, python-osmgpsmap ${misc:Depends}
|
||||
Depends: ${python:Depends}, librsvg2-common, python-gtk2, xdg-utils, graphviz, python-osmgpsmap ${misc:Depends}
|
||||
Replaces: gramps-manual, gramps-extending-doc
|
||||
Conflicts: gramps-manual, gramps-extending-doc, gramps-common, python-gtk-1.2
|
||||
Recommends:
|
||||
Suggests: ttf-freefont, python-enchant, python-gtkspell
|
||||
Recommends: python-pyicu
|
||||
Suggests: ttf-freefont, python-enchant, python-gtkspell, python-pyexiv2
|
||||
Description: Genealogical research program
|
||||
GRAMPS is an Open Source genealogy program written in Python, using
|
||||
the GTK/GNOME interface. It is an extremely flexible program fitting
|
||||
|
||||
+4
-4
@@ -7,7 +7,7 @@
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>Gramps</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>Gramps 3.4.1-1, (C) 1997-2012 The Gramps Team http://www.gramps-project.org</string>
|
||||
<string>Gramps 3.4.4-1, (C) 1997-2013 The Gramps Team http://www.gramps-project.org</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>gramps.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
@@ -17,15 +17,15 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.4.1-1</string>
|
||||
<string>3.4.4-1</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Gramps</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>3.4.1-1</string>
|
||||
<string>3.4.4-1</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright 1997 - 2012 The Gramps Team, GNU General Public License.</string>
|
||||
<string>Copyright 1997 - 2013 The Gramps Team, GNU General Public License.</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.5</string>
|
||||
</dict>
|
||||
|
||||
+24
-8
@@ -38,7 +38,11 @@
|
||||
</binary>
|
||||
|
||||
<binary>
|
||||
${prefix}/lib/pango/${pkg:pango:pango_module_version}/modules/pango-basic-fc.so
|
||||
${prefix}/lib/pango/${pkg:pango:pango_module_version}/modules/
|
||||
</binary>
|
||||
|
||||
<binary>
|
||||
${prefix}/lib/libpython2.7.dylib
|
||||
</binary>
|
||||
|
||||
<!-- Copy in libpyglib, which will pull in other dependencies we need -->
|
||||
@@ -63,11 +67,7 @@
|
||||
</binary>
|
||||
|
||||
<binary>
|
||||
${prefix}/lib/libgtkmacintegration.0.dylib
|
||||
</binary>
|
||||
|
||||
<binary>
|
||||
${prefix}/lib/libart_lgpl_2.2.dylib
|
||||
${prefix}/lib/libgtkmacintegration.2.dylib
|
||||
</binary>
|
||||
|
||||
<binary>
|
||||
@@ -134,7 +134,23 @@
|
||||
</data>
|
||||
|
||||
<data>
|
||||
${prefix}/share/gramps/
|
||||
${prefix}/etc/pango/
|
||||
</data>
|
||||
|
||||
<data recurse="True">
|
||||
${prefix}/share/gramps/*.py
|
||||
</data>
|
||||
|
||||
<data recurse="True">
|
||||
${prefix}/share/gramps/*.glade
|
||||
</data>
|
||||
|
||||
<data recurse="True">
|
||||
${prefix}/share/gramps/*.xml
|
||||
</data>
|
||||
|
||||
<data>
|
||||
${prefix}/share/gramps/images/
|
||||
</data>
|
||||
|
||||
<!--data>
|
||||
@@ -154,7 +170,7 @@
|
||||
</data>
|
||||
|
||||
<data>
|
||||
${prefix}/lib/graphviz/config6
|
||||
${prefix}/lib/graphviz/config*
|
||||
</data>
|
||||
|
||||
<!-- Copy in the themes data. You may want to trim this to save space
|
||||
|
||||
@@ -21,6 +21,8 @@ export GTK_EXE_PREFIX="$bundle_res"
|
||||
export GTK_PATH="$bundle_res"
|
||||
|
||||
export PANGO_RC_FILE="$bundle_etc/pango/pangorc"
|
||||
export PANGO_SYSCONFDIR="$bundle_etc"
|
||||
export PANGO_LIBDIR="$bundle_lib"
|
||||
export GDK_PIXBUF_MODULE_FILE="$bundle_etc/gtk-2.0/gdk-pixbuf.loaders"
|
||||
export GTK_IM_MODULE_FILE="$bundle_etc/gtk-2.0/gtk.immodules"
|
||||
export GTK2_RC_FILES="$bundle_etc/gtk-2.0/gtkrc"
|
||||
|
||||
+36
-28
@@ -14,7 +14,7 @@
|
||||
<repository type="tarball" name="xdg-utils"
|
||||
href="http://portland.freedesktop.org/download/"/>
|
||||
<repository type="svn" name="gramps"
|
||||
href="https://gramps.svn.sourceforge.net/svnroot/"/>
|
||||
href="http://svn.code.sf.net/p/gramps/code/"/>
|
||||
<repository type="svn" name="gramps-addons"
|
||||
href="https://gramps-addons.svn.sourceforge.net/svnroot/gramps-addons/"/>
|
||||
<repository type="tarball" name="oracle"
|
||||
@@ -31,6 +31,8 @@
|
||||
href="http://exiv2.org/"/>
|
||||
<repository type="tarball" name="pythonware"
|
||||
href="http://effbot.org/downloads/"/>
|
||||
<repository type='tarball' name='icu'
|
||||
href='http://download.icu-project.org/files/'/>
|
||||
|
||||
<!--
|
||||
Special instructions:
|
||||
@@ -58,35 +60,35 @@ ige-mac-bundler gtk-osx-build/projects/gramps/gramps.bundle
|
||||
|
||||
|
||||
<include href="https://raw.github.com/jralls/gtk-osx-build/master/modulesets-stable/gtk-osx.modules"/>
|
||||
<!--include href="/Users/john/GTK-OSX/gtk-osx-build/modulesets-stable/gtk-osx.modules"/-->
|
||||
<!--include href="/Users/john/Development/GTK-OSX/gtk-osx-build/modulesets-stable/gtk-osx.modules"/-->
|
||||
|
||||
|
||||
<autotools id="gramps" autogen-sh="configure">
|
||||
<branch module="gramps/gramps-3.4.1.tar.gz" version="3.4.1"
|
||||
<branch module="gramps/gramps-3.4.4.tar.gz" version="3.4.4"
|
||||
repo="sourceforge">
|
||||
</branch>
|
||||
<dependencies>
|
||||
<dep package="meta-gtk-osx-python"/>
|
||||
<dep package="pyWebKitGtk"/>
|
||||
<dep package="librsvg2"/>
|
||||
<!--dep package="pyWebKitGtk"/-->
|
||||
<dep package="librsvg"/>
|
||||
<dep package="pygoocanvas"/>
|
||||
<dep package="shared-mime-info"/>
|
||||
<dep package="hunspell"/>
|
||||
<dep package="pygtk-extras"/>
|
||||
<dep package="osmgpsmap-py"/>
|
||||
<dep package="graphviz"/>
|
||||
<dep package="pyexiv2"/>
|
||||
<dep package="pyicu"/>
|
||||
</dependencies>
|
||||
<after>
|
||||
<dep package="pyexiv2"/>
|
||||
</after>
|
||||
</autotools>
|
||||
|
||||
<autotools id="gramps-svn" >
|
||||
<branch module="gramps" revision="maintenance/gramps34" repo="gramps"/>
|
||||
<autotools id="gramps-34" >
|
||||
<branch module="code" revision="maintenance/gramps34" repo="gramps" />
|
||||
<dependencies>
|
||||
<dep package="meta-gtk-osx-python"/>
|
||||
<dep package="librsvg2"/>
|
||||
<dep package="librsvg"/>
|
||||
<dep package="pygoocanvas"/>
|
||||
<dep package="shared-mime-info"/>
|
||||
<dep package="hunspell"/>
|
||||
@@ -117,26 +119,16 @@ ige-mac-bundler gtk-osx-build/projects/gramps/gramps.bundle
|
||||
</dependencies>
|
||||
</autotools>
|
||||
|
||||
<!-- Later versions of librsvg2 require libxml2-2.7, available only in
|
||||
Snow Leopard -->
|
||||
<autotools id="librsvg2" >
|
||||
<branch module="librsvg/2.22/librsvg-2.22.3.tar.bz2" version="2.22.3"
|
||||
repo="ftp.gnome.org"/>
|
||||
<dependencies>
|
||||
<dep package="libgsf"/>
|
||||
<dep package="libart_lgpl"/><!-- goffice.modules -->
|
||||
</dependencies>
|
||||
</autotools>
|
||||
|
||||
<autotools id="goocanvas">
|
||||
<branch module="goocanvas/0.15/goocanvas-0.15.tar.bz2" version="0.15"
|
||||
repo="ftp.gnome.org"/>
|
||||
<!-- goocanvas 2.0 is for Gtk+-3.0. Go figure. -->
|
||||
<autotools id="goocanvas" autogen-sh="configure">
|
||||
<branch module="goocanvas/1.0/goocanvas-1.0.0.tar.bz2" version="1.0.0"
|
||||
repo="ftp.gnome.org" hash="sha256:1c072ef88567cad241fb4addee26e9bd96741b1503ff736d1c152fa6d865711e"/>
|
||||
<dependencies>
|
||||
<dep package="gtk+"/>
|
||||
</dependencies>
|
||||
</autotools>
|
||||
|
||||
<autotools id="pygoocanvas" version="0.14.1">
|
||||
<autotools id="pygoocanvas" version="0.14.1" autogen-sh="configure">
|
||||
<branch module="pygoocanvas/0.14/pygoocanvas-0.14.1.tar.gz" version="0.14.1"
|
||||
repo="ftp.gnome.org">
|
||||
</branch>
|
||||
@@ -148,15 +140,15 @@ ige-mac-bundler gtk-osx-build/projects/gramps/gramps.bundle
|
||||
|
||||
<distutils id="pyxdg">
|
||||
<branch repo="pyxdg" module="pyxdg-0.17.tar.gz" version="0.17"
|
||||
hash="sha256:fbc87711922b2dd6ceb23ee041f1f96da9b7dbb6971df03a3081b439def069ce"
|
||||
md5sum="a086de99cc536095684d87f15594e4db" size="37372"/>
|
||||
hash="sha256:fbc87711922b2dd6ceb23ee041f1f96da9b7dbb6971df03a3081b439def069ce" size="37372"/>
|
||||
</distutils>
|
||||
|
||||
<autotools id="xdg-utils">
|
||||
<branch module="xdg-utils-1.0.2.tgz" version="1.0.2" repo="xdg-utils"/>
|
||||
</autotools>
|
||||
|
||||
<autotools id="osmgpsmap">
|
||||
<autotools id="osmgpsmap" autogenargs="--disable-introspection"
|
||||
autogen-sh="configure">
|
||||
<branch module="osm-gps-map/osm-gps-map-0.7.3.tar.gz" repo="stowers"
|
||||
version="0.7.3"/>
|
||||
<dependencies>
|
||||
@@ -176,9 +168,11 @@ ige-mac-bundler gtk-osx-build/projects/gramps/gramps.bundle
|
||||
</dependencies>
|
||||
</distutils>
|
||||
|
||||
<autotools id="graphviz" autogenargs="--disable-sharp --disable-guile --disable-java --disable-lua --disable-ocaml --disable-perl --disable-php --disable-r --disable-ruby --disable-tcl">
|
||||
<autotools id="graphviz" autogen-sh="configure"
|
||||
autogenargs="--disable-sharp --disable-guile --disable-java --disable-lua --disable-ocaml --disable-perl --disable-php --disable-r --disable-ruby --disable-tcl --without-x --with-pangocairo --with-included-ltdl=yes">
|
||||
<branch module="graphviz-2.28.0.tar.gz" version="2.28.0" repo="graphviz"/>
|
||||
<dependencies>
|
||||
<dep package="librsvg"/>
|
||||
<dep package="pango"/>
|
||||
<dep package="zlib"/>
|
||||
</dependencies>
|
||||
@@ -214,4 +208,18 @@ ige-mac-bundler gtk-osx-build/projects/gramps/gramps.bundle
|
||||
<branch module="Imaging-1.1.7.tar.gz" version="1.1.7" repo="pythonware"/>
|
||||
</distutils>
|
||||
|
||||
<autotools id='icu' autogen-sh='source/configure'
|
||||
makeargs='CFLAGS="$CFLAGS -DU_CHARSET_IS_UTF8=1 -DU_USING_ICU_NAMESPACE=0"'>
|
||||
<branch repo='icu' version='50.1.2' checkoutdir='icu'
|
||||
module='icu4c/50.1.2/icu4c-50_1_2-src.tgz'/>
|
||||
</autotools>
|
||||
|
||||
<distutils id='pyicu'>
|
||||
<branch version='1.5' repo='pymodules'
|
||||
module='P/PyICU/PyICU-1.5.tar.gz'/>
|
||||
<dependencies>
|
||||
<dep package='icu'/>
|
||||
</dependencies>
|
||||
</distutils>
|
||||
|
||||
</moduleset>
|
||||
|
||||
+1867
-1597
File diff suppressed because it is too large
Load Diff
+1577
-1351
File diff suppressed because it is too large
Load Diff
+7651
-7887
File diff suppressed because it is too large
Load Diff
@@ -57,7 +57,12 @@ import constfunc
|
||||
if not constfunc.win():
|
||||
LANG = locale.getlocale(locale.LC_TIME)[0]
|
||||
else:
|
||||
LANG = locale.getdefaultlocale(locale.LC_TIME)[0]
|
||||
if 'LC_TIME' in os.environ:
|
||||
LANG = os.environ['LC_TIME']
|
||||
elif 'LANG' in os.environ:
|
||||
LANG = os.environ['LANG']
|
||||
else:
|
||||
LANG = locale.getdefaultlocale(locale.LC_TIME)[0]
|
||||
|
||||
# If LANG contains ".UTF-8" use only the part to the left of "."
|
||||
# Otherwise some date handler will not load.
|
||||
|
||||
@@ -176,4 +176,4 @@ class DateDisplayNb(DateDisplay):
|
||||
# Register classes
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
register_datehandler(('nb_NO', 'nb', 'norsk', 'Norwegian'), DateParserNb, DateDisplayNb)
|
||||
register_datehandler(('nb_NO', 'nb', 'nn_NO', 'nn', 'norsk', 'Norwegian'), DateParserNb, DateDisplayNb)
|
||||
|
||||
@@ -0,0 +1,360 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2004-2006 Donald N. Allingham
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
# $Id: _Date_uk.py 18361 2011-10-23 03:13:50Z paul-franklin $
|
||||
|
||||
"""
|
||||
Ukrainian-specific classes for parsing and displaying dates.
|
||||
"""
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Python modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import re
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GRAMPS modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gen.lib import Date
|
||||
from _DateParser import DateParser
|
||||
from _DateDisplay import DateDisplay
|
||||
from _DateHandler import register_datehandler
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Ukrainian parser
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class DateParserUK(DateParser):
|
||||
"""
|
||||
Convert a text string into a Date object. If the date cannot be
|
||||
converted, the text string is assigned.
|
||||
"""
|
||||
|
||||
month_to_int = DateParser.month_to_int
|
||||
|
||||
# the genitive
|
||||
month_to_int[u"січня"] = 1
|
||||
month_to_int[u"лютого"] = 2
|
||||
month_to_int[u"березня"] = 3
|
||||
month_to_int[u"квітня"] = 4
|
||||
month_to_int[u"травня"] = 5
|
||||
month_to_int[u"червня"] = 6
|
||||
month_to_int[u"липня"] = 7
|
||||
month_to_int[u"серпня"] = 8
|
||||
month_to_int[u"вересня"] = 9
|
||||
month_to_int[u"жовтня"] = 10
|
||||
month_to_int[u"листопада"] = 11
|
||||
month_to_int[u"грудня"] = 12
|
||||
|
||||
# some short variants of the months
|
||||
month_to_int[u"січ."] = 1
|
||||
month_to_int[u"січ"] = 1
|
||||
month_to_int[u"лют."] = 2
|
||||
month_to_int[u"лют"] = 2
|
||||
month_to_int[u"бер."] = 3
|
||||
month_to_int[u"бер"] = 3
|
||||
month_to_int[u"квіт."] = 4
|
||||
month_to_int[u"квіт"] = 4
|
||||
month_to_int[u"трав."] = 5
|
||||
month_to_int[u"трав"] = 5
|
||||
month_to_int[u"черв."] = 6
|
||||
month_to_int[u"черв"] = 6
|
||||
month_to_int[u"лип."] = 7
|
||||
month_to_int[u"лип"] = 7
|
||||
month_to_int[u"серп."] = 8
|
||||
month_to_int[u"серп"] = 8
|
||||
month_to_int[u"вер."] = 9
|
||||
month_to_int[u"вер"] = 9
|
||||
month_to_int[u"жовт."] = 10
|
||||
month_to_int[u"жовт"] = 10
|
||||
month_to_int[u"лист."] = 11
|
||||
month_to_int[u"лист"] = 11
|
||||
month_to_int[u"груд."] = 12
|
||||
month_to_int[u"груд"] = 12
|
||||
|
||||
|
||||
# modifiers before the date
|
||||
modifier_to_int = {
|
||||
u'перед' : Date.MOD_BEFORE,
|
||||
u'до' : Date.MOD_BEFORE,
|
||||
u'раніше' : Date.MOD_BEFORE,
|
||||
|
||||
u'після' : Date.MOD_AFTER,
|
||||
u'п.' : Date.MOD_AFTER,
|
||||
u'за' : Date.MOD_AFTER,
|
||||
|
||||
u'приблизно': Date.MOD_ABOUT,
|
||||
u'прибл.' : Date.MOD_ABOUT,
|
||||
u'приб.' : Date.MOD_ABOUT,
|
||||
u'близько' : Date.MOD_ABOUT,
|
||||
u'бл.' : Date.MOD_ABOUT,
|
||||
u'біля' : Date.MOD_ABOUT,
|
||||
}
|
||||
|
||||
hebrew_to_int = {
|
||||
u"тішрі" : 1, u"хешвен" : 2, u"кіслев" : 3,
|
||||
u"тевет" : 4, u"шват" : 5, u"адар" : 6,
|
||||
u"адара" : 7, u"нісан" : 8, u"іяр" : 9,
|
||||
u"сиван" : 10, u"таммуз" : 11, u"ав" : 12,
|
||||
u"елул" : 13,
|
||||
#alternative spelling
|
||||
u"мархешван": 2, u"ве адар" : 7,
|
||||
#GEDCOM months
|
||||
u"tsh" : 1, u"csh": 5, u"ksl": 3, u"tvt": 4, u"shv": 5, u"adr": 6,
|
||||
u"ads" : 7, u"nsn": 8, u"iyr": 9, u"svn":10, u"tmz":11, u"aav":12,
|
||||
u"ell":13,
|
||||
}
|
||||
|
||||
french_to_int = {
|
||||
u'вандем’єр' : 1, u'брюмер' : 2,
|
||||
u'фрімер' : 3, u'нівоз' : 4,
|
||||
u'плювіоз' : 5, u'вентоз' : 6,
|
||||
u'жерміналь' : 7, u'флореаль' : 8,
|
||||
u'преріаль' : 9, u'мессідор' : 10,
|
||||
u'термідор' : 11, u'фрюктідор': 12,
|
||||
u'додатковий' : 13,
|
||||
#short
|
||||
u'ванд' : 1, u'брюм' : 2,
|
||||
u'фрім' : 3, u'нів' : 4,
|
||||
u'плюв' : 5, u'вент' : 6,
|
||||
u'жерм' : 7, u'флор' : 8,
|
||||
u'прер' : 9, u'месс' : 10,
|
||||
u'терм' : 11, u'фрюкт': 12,
|
||||
u'дод' : 13,
|
||||
#GEDCOM months
|
||||
u'vend' : 1, u'brum' : 2,
|
||||
u'frim' : 3, u'nivo' : 4,
|
||||
u'pluv' : 5, u'vent' : 6,
|
||||
u'germ' : 7, u'flor' : 8,
|
||||
u'prai' : 9, u'mess' : 10,
|
||||
u'ther' : 11, u'fruc' : 12,
|
||||
u'comp' : 13,
|
||||
}
|
||||
|
||||
islamic_to_int = {
|
||||
u"мухаррам" : 1, u"мухаррем" : 1,
|
||||
u"сафар" : 2, u"рабі-аль-авваль" : 3,
|
||||
u"рабі-ассані" : 4,
|
||||
u"джумада-аль-уля" : 5, u"джумада-аль-авваль" : 5,
|
||||
u"джумада-аль-ахіра" : 6, u"джумада-ас-сані" : 6,
|
||||
u"раджаб" : 7, u"шаабан" : 8,
|
||||
u"рамадан" : 9, u"рамазан" : 9,
|
||||
u"шавваль" : 10, u"зуль-каада" : 11,
|
||||
u"зуль-хіджжа" : 12,
|
||||
}
|
||||
|
||||
persian_to_int = {
|
||||
u"фарвардін" : 1, u"ордібехешт" : 2,
|
||||
u"хордад" : 3, u"тир" : 4,
|
||||
u"мордад" : 5, u"шахрівар" : 6,
|
||||
u"мехр" : 7, u"абан" : 8,
|
||||
u"азар" : 9, u"дей" : 10,
|
||||
u"бахман" : 11, u"есфанд" : 12,
|
||||
}
|
||||
|
||||
bce = [u'до нашої ери', u'до н. е.', u'до н.е.']
|
||||
|
||||
calendar_to_int = {
|
||||
u'григоріанський' : Date.CAL_GREGORIAN,
|
||||
u'г' : Date.CAL_GREGORIAN,
|
||||
u'юліанський' : Date.CAL_JULIAN,
|
||||
u'ю' : Date.CAL_JULIAN,
|
||||
u'єврейський' : Date.CAL_HEBREW,
|
||||
u'є' : Date.CAL_HEBREW,
|
||||
u'ісламський' : Date.CAL_ISLAMIC,
|
||||
u'і' : Date.CAL_ISLAMIC,
|
||||
u'французький' : Date.CAL_FRENCH,
|
||||
u'французький республіканський': Date.CAL_FRENCH,
|
||||
u'французький революційний' : Date.CAL_FRENCH,
|
||||
u'ф' : Date.CAL_FRENCH,
|
||||
u'іранський' : Date.CAL_PERSIAN,
|
||||
u'перський' : Date.CAL_PERSIAN,
|
||||
u'п' : Date.CAL_PERSIAN,
|
||||
u'шведський' : Date.CAL_SWEDISH,
|
||||
u'ш' : Date.CAL_SWEDISH,
|
||||
}
|
||||
|
||||
quality_to_int = {
|
||||
u'за оцінкою' : Date.QUAL_ESTIMATED,
|
||||
u'за оц.' : Date.QUAL_ESTIMATED,
|
||||
u'оцінено' : Date.QUAL_ESTIMATED,
|
||||
u'орієнтовно' : Date.QUAL_ESTIMATED,
|
||||
u'приблизно' : Date.QUAL_ESTIMATED,
|
||||
u'прибл.' : Date.QUAL_ESTIMATED,
|
||||
u'підраховано' : Date.QUAL_CALCULATED,
|
||||
u'підрах.' : Date.QUAL_CALCULATED,
|
||||
u'розраховано' : Date.QUAL_CALCULATED,
|
||||
u'розрахунково' : Date.QUAL_CALCULATED,
|
||||
u'розрах.' : Date.QUAL_CALCULATED,
|
||||
}
|
||||
|
||||
def init_strings(self):
|
||||
"""
|
||||
This method compiles regular expression strings for matching dates.
|
||||
|
||||
See DateParser.init_strings()
|
||||
"""
|
||||
DateParser.init_strings(self)
|
||||
|
||||
_span_1 = [u'з', u'від']
|
||||
# b.c.e. pattern also have "до" so skip "до н."
|
||||
_span_2 = [u'по', u'до?!\sн\.']
|
||||
self._span = re.compile("(%s)\s+(?P<start>.+)\s+(%s)\s+(?P<stop>.+)" %
|
||||
('|'.join(_span_1), '|'.join(_span_2)),
|
||||
re.IGNORECASE)
|
||||
_range_1 = [u'між']
|
||||
_range_2 = [u'і', u'та']
|
||||
self._range = re.compile("(%s)\s+(?P<start>.+)\s+(%s)\s+(?P<stop>.+)" %
|
||||
('|'.join(_range_1), '|'.join(_range_2)),
|
||||
re.IGNORECASE)
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Ukrainian displayer
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class DateDisplayUK(DateDisplay):
|
||||
"""
|
||||
Ukrainian language date display class.
|
||||
"""
|
||||
|
||||
# the months as the noun or as the genitive???
|
||||
|
||||
# as the genitive:
|
||||
long_months = (
|
||||
u"", u"січня", u"лютого", u"березня", u"квітня",
|
||||
u"травня", u"червня", u"липня", u"серпня",
|
||||
u"вересня", u"жовтня", u"листопада", u"грудня"
|
||||
)
|
||||
|
||||
# as the noun:
|
||||
# long_months = (
|
||||
# u"", u"січень", u"лютий", u"березень", u"квітень",
|
||||
# u"травень", u"червень", u"липень", u"серпень",
|
||||
# u"вересень", u"жовтень", u"листопад", u"грудень"
|
||||
# )
|
||||
|
||||
short_months = (
|
||||
u"", u"січ.", u"лют.", u"бер.", u"квіт.", u"трав.", u"черв.",
|
||||
u"лип.", u"серп.", u"вер.", u"жовт.", u"лист.", u"груд."
|
||||
)
|
||||
|
||||
hebrew = (
|
||||
u"", u"тішрі", u"хешвен", u"кіслев", u"тевет", u"шват",
|
||||
u"адар", u"адара", u"нісан", u"іяр", u"сиван", u"таммуз",
|
||||
u"ав", u"елул"
|
||||
)
|
||||
|
||||
french = (
|
||||
u'', u'вандем’єр', u'брюмер', u'фрімер', u'нівоз',
|
||||
u'плювіоз', u'вентоз', u'жерміналь', u'флореаль',
|
||||
u'преріаль', u'мессідор', u'термідор', u'фрюктідор',
|
||||
u'додатковий'
|
||||
)
|
||||
|
||||
persian = (
|
||||
u"", u"фарвардін", u"ордібехешт", u"хордад", u"тир",
|
||||
u"мордад", u"шахрівар", u"мехр", u"абан",
|
||||
u"азар", u"дей", u"бахман", u"есфанд"
|
||||
)
|
||||
|
||||
islamic = (
|
||||
u"", u"мухаррам", u"сафар", u"рабі-аль-авваль",
|
||||
u"рабі-ассані", u"джумада-аль-уля", u"джумада-аль-ахіра",
|
||||
u"раджаб", u"шаабан", u"рамадан", u"шавваль", u"зуль-каада",
|
||||
u"зуль-хіджжа",
|
||||
)
|
||||
|
||||
# Replace the previous "Numerical" by a string which
|
||||
# do have an explicit meaning: "System default (format)"
|
||||
import GrampsLocale
|
||||
_locale_tformat = GrampsLocale.tformat
|
||||
_locale_tformat = _locale_tformat.replace('%d', "д")
|
||||
_locale_tformat = _locale_tformat.replace('%m', "м")
|
||||
_locale_tformat = _locale_tformat.replace('%Y', "р")
|
||||
|
||||
formats = (
|
||||
"рррр-мм-дд (ISO)", #0
|
||||
"стандартний для системи (" + _locale_tformat + ")", #1
|
||||
"місяць день, рік", #2
|
||||
"міс. дд, рррр", #3
|
||||
"день місяць рік", #4
|
||||
"дд міс. рррр" #5
|
||||
)
|
||||
|
||||
calendar = (
|
||||
u"", u"юліанський", u"єврейський", u"французький республіканський",
|
||||
u"іранський", u"ісламський", u"шведський"
|
||||
)
|
||||
|
||||
_mod_str = (u"", u"до ", u"після ", u"близько ", u"", u"", u"")
|
||||
|
||||
_qual_str = (u"", u"орієнтовно ", u"розрахунково ")
|
||||
|
||||
_bce_str = u"%s до н.е."
|
||||
|
||||
def display(self, date):
|
||||
"""
|
||||
Return a text string representing the date.
|
||||
"""
|
||||
mod = date.get_modifier()
|
||||
cal = date.get_calendar()
|
||||
qual = date.get_quality()
|
||||
start = date.get_start_date()
|
||||
newyear = date.get_new_year()
|
||||
|
||||
qual_str = self._qual_str[qual]
|
||||
|
||||
if mod == Date.MOD_TEXTONLY:
|
||||
return date.get_text()
|
||||
elif start == Date.EMPTY:
|
||||
return ""
|
||||
elif mod == Date.MOD_SPAN:
|
||||
d1 = self.display_cal[cal](start)
|
||||
d2 = self.display_cal[cal](date.get_stop_date())
|
||||
scal = self.format_extras(cal, newyear)
|
||||
return "%sз %s %s %s%s" % (qual_str, d1, u'по', d2,
|
||||
scal)
|
||||
elif mod == Date.MOD_RANGE:
|
||||
d1 = self.display_cal[cal](start)
|
||||
d2 = self.display_cal[cal](date.get_stop_date())
|
||||
scal = self.format_extras(cal, newyear)
|
||||
return "%s%s %s %s %s%s" % (qual_str, u'між', d1, u'та',
|
||||
d2, scal)
|
||||
else:
|
||||
text = self.display_cal[date.get_calendar()](start)
|
||||
scal = self.format_extras(cal, newyear)
|
||||
return "%s%s%s%s" % (qual_str, self._mod_str[mod],
|
||||
text, scal)
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Register classes
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
register_datehandler(('uk_UA', 'uk', 'ukrainian', 'Ukrainian'), DateParserUK, DateDisplayUK)
|
||||
@@ -23,6 +23,12 @@
|
||||
"""
|
||||
Class handling language-specific selection for date parser and displayer.
|
||||
"""
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# set up logging
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import logging
|
||||
|
||||
# import prerequisites for localized handlers
|
||||
from _DateHandler import (LANG, LANG_SHORT, LANG_TO_PARSER, LANG_TO_DISPLAY,
|
||||
@@ -57,7 +63,7 @@ try:
|
||||
else:
|
||||
parser = LANG_TO_PARSER[LANG_SHORT]()
|
||||
except:
|
||||
print "Date parser for", LANG, "not available, using default"
|
||||
logging.warning(_("Date parser for '%s' not available, using default") % LANG)
|
||||
parser = LANG_TO_PARSER["C"]()
|
||||
|
||||
# Initialize global displayer
|
||||
@@ -73,7 +79,7 @@ try:
|
||||
else:
|
||||
displayer = LANG_TO_DISPLAY[LANG_SHORT](val)
|
||||
except:
|
||||
print "Date displayer for", LANG, "not available, using default"
|
||||
logging.warning(_("Date displayer for '%s' not available, using default") % LANG)
|
||||
displayer = LANG_TO_DISPLAY["C"](val)
|
||||
|
||||
|
||||
|
||||
@@ -357,7 +357,8 @@ class ExportAssistant(gtk.Assistant, ManagedWindow.ManagedWindow) :
|
||||
filename = filechooser.get_filename()
|
||||
folder = filechooser.get_current_folder()
|
||||
#the file must be valid, not a folder, and folder must be valid
|
||||
if filename and filename.strip and Utils.find_folder(filename) == '' \
|
||||
if filename and os.path.basename(filename.strip()) \
|
||||
and Utils.find_folder(filename) == '' \
|
||||
and folder and Utils.find_folder(folder):
|
||||
#this page of the assistant is complete
|
||||
self.set_page_complete(filechooser, True)
|
||||
|
||||
@@ -52,6 +52,7 @@ class HasCitation(Rule):
|
||||
name = _('Citations matching parameters')
|
||||
category = _('General filters')
|
||||
description = _("Matches citations with particular parameters")
|
||||
allow_regex = True
|
||||
|
||||
def prepare(self, db):
|
||||
self.date = None
|
||||
|
||||
@@ -50,8 +50,8 @@ class HasData(Rule):
|
||||
description = _("Matches events with data of a particular value")
|
||||
category = _('General filters')
|
||||
|
||||
def __init__(self, list):
|
||||
Rule.__init__(self, list)
|
||||
def __init__(self, list, use_regex=False):
|
||||
Rule.__init__(self, list, use_regex)
|
||||
|
||||
self.event_type = self.list[0]
|
||||
self.date = self.list[1]
|
||||
|
||||
@@ -52,6 +52,7 @@ class HasMedia(Rule):
|
||||
name = _('Media objects matching parameters')
|
||||
description = _("Matches media objects with particular parameters")
|
||||
category = _('General filters')
|
||||
allow_regex = True
|
||||
|
||||
def prepare(self,db):
|
||||
self.date = None
|
||||
|
||||
@@ -47,8 +47,8 @@ class MatchesRegexpOf(Rule):
|
||||
"which matches a regular expression")
|
||||
category = _('General filters')
|
||||
|
||||
def __init__(self, list):
|
||||
Rule.__init__(self, list)
|
||||
def __init__(self, list, use_regex=False):
|
||||
Rule.__init__(self, list, use_regex)
|
||||
|
||||
try:
|
||||
self.match = re.compile(list[0], re.I|re.U|re.L)
|
||||
@@ -58,6 +58,6 @@ class MatchesRegexpOf(Rule):
|
||||
def apply(self, db, note):
|
||||
""" Apply the filter """
|
||||
text = note.get()
|
||||
if self.match.match(text) is not None:
|
||||
if self.match.search(text) is not None:
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -49,8 +49,8 @@ class HasBirth(Rule):
|
||||
description = _("Matches people with birth data of a particular value")
|
||||
category = _('Event filters')
|
||||
|
||||
def __init__(self,list):
|
||||
Rule.__init__(self,list)
|
||||
def __init__(self, list, use_regex=False):
|
||||
Rule.__init__(self, list, use_regex)
|
||||
if self.list[0]:
|
||||
self.date = DateHandler.parser.parse(self.list[0])
|
||||
else:
|
||||
|
||||
@@ -51,8 +51,8 @@ class HasCommonAncestorWithFilterMatch(HasCommonAncestorWith):
|
||||
"with anybody matched by a filter")
|
||||
category = _("Ancestral filters")
|
||||
|
||||
def __init__(self, list):
|
||||
HasCommonAncestorWith.__init__(self, list)
|
||||
def __init__(self, list, use_regex=False):
|
||||
HasCommonAncestorWith.__init__(self, list, use_regex)
|
||||
self.ancestor_cache = {}
|
||||
|
||||
def prepare(self, db):
|
||||
|
||||
@@ -49,8 +49,8 @@ class HasDeath(Rule):
|
||||
description = _("Matches people with death data of a particular value")
|
||||
category = _('Event filters')
|
||||
|
||||
def __init__(self,list):
|
||||
Rule.__init__(self,list)
|
||||
def __init__(self, list, use_regex=False):
|
||||
Rule.__init__(self, list, use_regex)
|
||||
if self.list[0]:
|
||||
self.date = DateHandler.parser.parse(self.list[0])
|
||||
else:
|
||||
|
||||
@@ -43,10 +43,10 @@ class HavePhotos(HasGalleryBase):
|
||||
name = _('People with <count> media')
|
||||
description = _("Matches people with a certain number of items in the gallery")
|
||||
|
||||
def __init__(self, arg):
|
||||
def __init__(self, arg, use_regex=False):
|
||||
# Upgrade from pre 3.1 HasPhotos filter, use defaults that correspond
|
||||
# Previous filter had 0 arguments
|
||||
if len(arg) == 0:
|
||||
HasGalleryBase.__init__(self, ["0", 'greater than'])
|
||||
HasGalleryBase.__init__(self, ["0", 'greater than'], use_regex)
|
||||
else:
|
||||
HasGalleryBase.__init__(self, arg)
|
||||
HasGalleryBase.__init__(self, arg, use_regex)
|
||||
|
||||
@@ -110,31 +110,31 @@ class HasNameOf(Rule):
|
||||
valpatr = 1
|
||||
if self.regular_expression:
|
||||
try:
|
||||
if self.firstn and not re.match(self.firstn, name.get_first_name(), re.I|re.U|re.L):
|
||||
if self.firstn and not re.search(self.firstn, name.get_first_name(), re.I|re.U|re.L):
|
||||
val = 0
|
||||
elif self.lastn and not re.match(self.lastn, name.get_surname(), re.I|re.U|re.L):
|
||||
elif self.lastn and not re.search(self.lastn, name.get_surname(), re.I|re.U|re.L):
|
||||
val = 0
|
||||
elif self.suffix and not re.match(self.suffix, name.get_suffix(), re.I|re.U|re.L):
|
||||
elif self.suffix and not re.search(self.suffix, name.get_suffix(), re.I|re.U|re.L):
|
||||
val = 0
|
||||
elif self.title and not re.match(self.title, name.get_title(), re.I|re.U|re.L):
|
||||
elif self.title and not re.search(self.title, name.get_title(), re.I|re.U|re.L):
|
||||
val = 0
|
||||
elif self.calln and not re.match(self.calln, name.get_call_name(), re.I|re.U|re.L):
|
||||
elif self.calln and not re.search(self.calln, name.get_call_name(), re.I|re.U|re.L):
|
||||
val = 0
|
||||
elif self.nick and not re.match(self.nick, name.get_nick_name(), re.I|re.U|re.L):
|
||||
elif self.nick and not re.search(self.nick, name.get_nick_name(), re.I|re.U|re.L):
|
||||
val = 0
|
||||
elif self.famnick and not re.match(self.famnick, name.get_family_nick_name(), re.I|re.U|re.L):
|
||||
elif self.famnick and not re.search(self.famnick, name.get_family_nick_name(), re.I|re.U|re.L):
|
||||
val = 0
|
||||
else:
|
||||
#obtain surnames
|
||||
for surn in name.get_surname_list():
|
||||
if self.prefix and re.match(self.prefix, surn.get_prefix(), re.I|re.U|re.L):
|
||||
if self.prefix and re.search(self.prefix, surn.get_prefix(), re.I|re.U|re.L):
|
||||
valpref = 1
|
||||
if self.surn and re.match(self.surn, surn.get_surname(), re.I|re.U|re.L):
|
||||
if self.surn and re.search(self.surn, surn.get_surname(), re.I|re.U|re.L):
|
||||
valsurn = 1
|
||||
if self.con and re.match(self.con, surn.get_connector(), re.I|re.U|re.L):
|
||||
if self.con and re.search(self.con, surn.get_connector(), re.I|re.U|re.L):
|
||||
valcon = 1
|
||||
if self.patr and surn.get_origintype().value == NameOriginType.PATRONYMIC \
|
||||
and re.match(self.patr, surn.get_surname(), re.I|re.U|re.L):
|
||||
and re.search(self.patr, surn.get_surname(), re.I|re.U|re.L):
|
||||
valpatr = 1
|
||||
except re.error:
|
||||
#indicate error in the pattern by matching everyone
|
||||
|
||||
@@ -41,8 +41,8 @@ class HasTextMatchingRegexpOf(HasTextMatchingSubstringOf):
|
||||
parameter.
|
||||
|
||||
"""
|
||||
def __init__(self,list):
|
||||
HasTextMatchingSubstringOf.__init__(self,list)
|
||||
def __init__(self, list, use_regex=False):
|
||||
HasTextMatchingSubstringOf.__init__(self, list, use_regex)
|
||||
|
||||
def prepare(self,db):
|
||||
self.db = db
|
||||
|
||||
@@ -50,10 +50,6 @@ class IsAncestorOfFilterMatch(IsAncestorOf):
|
||||
description = _("Matches people that are ancestors "
|
||||
"of anybody matched by a filter")
|
||||
|
||||
|
||||
def __init__(self,list):
|
||||
IsAncestorOf.__init__(self,list)
|
||||
|
||||
def prepare(self,db):
|
||||
self.db = db
|
||||
self.map = set()
|
||||
|
||||
@@ -50,10 +50,6 @@ class IsDescendantOfFilterMatch(IsDescendantOf):
|
||||
description = _("Matches people that are descendants "
|
||||
"of anybody matched by a filter")
|
||||
|
||||
|
||||
# def __init__(self,list):
|
||||
# IsDescendantOf.__init__(self,list)
|
||||
|
||||
def prepare(self,db):
|
||||
self.db = db
|
||||
self.map = set()
|
||||
|
||||
@@ -49,8 +49,8 @@ class RegExpName(Rule):
|
||||
description = _("Matches people's names with a specified regular expression")
|
||||
category = _('General filters')
|
||||
|
||||
def __init__(self, list):
|
||||
Rule.__init__(self, list)
|
||||
def __init__(self, list, use_regex=False):
|
||||
Rule.__init__(self, list, use_regex)
|
||||
|
||||
try:
|
||||
self.match = re.compile(list[0],re.I|re.U|re.L)
|
||||
@@ -62,7 +62,7 @@ class RegExpName(Rule):
|
||||
for name in [person.get_primary_name()] + person.get_alternate_names():
|
||||
for field in [name.first_name, name.get_surname(), name.suffix,
|
||||
name.title, name.nick, name.famnick, name.call]:
|
||||
if self.match.match(field):
|
||||
if self.match.search(field):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@@ -35,6 +35,7 @@ from gen.ggettext import gettext as _
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from Filters.Rules._Rule import Rule
|
||||
from gen.lib import Location
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@@ -58,6 +59,7 @@ class HasPlace(Rule):
|
||||
name = _('Places matching parameters')
|
||||
description = _("Matches places with particular parameters")
|
||||
category = _('General filters')
|
||||
allow_regex = True
|
||||
|
||||
def apply(self, db, place):
|
||||
if not self.match_substring(0, place.get_title()):
|
||||
@@ -76,9 +78,9 @@ class HasPlace(Rule):
|
||||
return False
|
||||
|
||||
def apply_location(self, loc):
|
||||
# Empty locaiton does not match anything
|
||||
if not loc:
|
||||
return False
|
||||
# Allow regular expressions to match empty fields
|
||||
loc = Location()
|
||||
|
||||
if not self.match_substring(1, loc.get_street()):
|
||||
return False
|
||||
|
||||
@@ -52,6 +52,7 @@ class HasRepo(Rule):
|
||||
name = _('Repositories matching parameters')
|
||||
description = _("Matches Repositories with particular parameters")
|
||||
category = _('General filters')
|
||||
allow_regex = True
|
||||
|
||||
def prepare(self, dummy_db):
|
||||
if self.list[1]:
|
||||
|
||||
@@ -53,6 +53,7 @@ class HasCitationBase(Rule):
|
||||
name = _('Citations matching parameters')
|
||||
description = _("Matches citations with particular parameters")
|
||||
category = _('Citation/source filters')
|
||||
allow_regex = True
|
||||
|
||||
def prepare(self, db):
|
||||
self.date = None
|
||||
|
||||
@@ -54,6 +54,7 @@ class HasEventBase(Rule):
|
||||
name = _('Events matching parameters')
|
||||
description = _("Matches events with particular parameters")
|
||||
category = _('Event filters')
|
||||
allow_regex = True
|
||||
|
||||
def prepare(self, db):
|
||||
self.date = None
|
||||
|
||||
@@ -49,13 +49,13 @@ class HasNoteBase(Rule):
|
||||
description = _("Matches objects that have a certain number of notes")
|
||||
category = _('General filters')
|
||||
|
||||
def __init__(self, arg):
|
||||
def __init__(self, arg, use_regex=False):
|
||||
# Upgrade from pre 3.1 HasNote filter, use defaults that correspond
|
||||
# Previous filter had 0 arguments
|
||||
if len(arg) == 0:
|
||||
Rule.__init__(self, ["0", 'greater than'])
|
||||
Rule.__init__(self, ["0", 'greater than'], use_regex)
|
||||
else:
|
||||
Rule.__init__(self, arg)
|
||||
Rule.__init__(self, arg, use_regex)
|
||||
|
||||
def prepare(self, db):
|
||||
# things we want to do just once, not for every handle
|
||||
|
||||
@@ -47,8 +47,8 @@ class HasNoteRegexBase(Rule):
|
||||
"matching a regular expression")
|
||||
category = _('General filters')
|
||||
|
||||
def __init__(self, list):
|
||||
Rule.__init__(self, list)
|
||||
def __init__(self, list, use_regex=False):
|
||||
Rule.__init__(self, list, use_regex)
|
||||
|
||||
try:
|
||||
self.match = re.compile(list[0],re.I|re.U|re.L)
|
||||
@@ -60,6 +60,6 @@ class HasNoteRegexBase(Rule):
|
||||
for notehandle in notelist:
|
||||
note = db.get_note_from_handle(notehandle)
|
||||
n = note.get()
|
||||
if self.match.match(n) is not None:
|
||||
if self.match.search(n) is not None:
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -51,6 +51,7 @@ class HasSourceBase(Rule):
|
||||
name = _('Sources matching parameters')
|
||||
description = _("Matches sources with particular parameters")
|
||||
category = _('Citation/source filters')
|
||||
allow_regex = True
|
||||
|
||||
def apply(self,db,source):
|
||||
if not self.match_substring(0,source.get_title()):
|
||||
|
||||
@@ -40,8 +40,8 @@ class HasTextMatchingRegexpOf(HasTextMatchingSubstringOf):
|
||||
"""
|
||||
Wrap HasTextMatchingSubstringOf to enable the regex_match parameter.
|
||||
"""
|
||||
def __init__(self, list):
|
||||
HasTextMatchingSubstringOf.__init__(self, list)
|
||||
def __init__(self, list, use_regex=False):
|
||||
HasTextMatchingSubstringOf.__init__(self, list, use_regex)
|
||||
|
||||
# FIXME: This needs to be written for an arbitrary object
|
||||
# if possible
|
||||
|
||||
@@ -51,8 +51,8 @@ class RegExpIdBase(Rule):
|
||||
"the regular expression")
|
||||
category = _('General filters')
|
||||
|
||||
def __init__(self, list):
|
||||
Rule.__init__(self, list)
|
||||
def __init__(self, list, use_regex=False):
|
||||
Rule.__init__(self, list, use_regex)
|
||||
|
||||
try:
|
||||
self.match = re.compile(list[0], re.I|re.U|re.L)
|
||||
@@ -60,4 +60,4 @@ class RegExpIdBase(Rule):
|
||||
self.match = re.compile('')
|
||||
|
||||
def apply(self, db, obj):
|
||||
return self.match.match(obj.gramps_id) is not None
|
||||
return self.match.search(obj.gramps_id) is not None
|
||||
|
||||
@@ -53,6 +53,7 @@ class Rule(object):
|
||||
name = ''
|
||||
category = _('Miscellaneous filters')
|
||||
description = _('No description')
|
||||
allow_regex = False
|
||||
|
||||
def __init__(self, arg, use_regex=False):
|
||||
self.list = []
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
# Python modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gen.ggettext import gettext as _
|
||||
from gen.ggettext import sgettext as _
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@@ -94,7 +94,7 @@ class CitationSidebarFilter(SidebarFilter):
|
||||
self.add_text_entry(_('ID'), self.filter_id)
|
||||
self.add_text_entry(_('Volume/Page'), self.filter_page)
|
||||
self.add_text_entry(_('Date'), self.filter_date)
|
||||
self.add_entry(_('Confidence'), self.filter_conf)
|
||||
self.add_entry(_('Minimum Confidence|Min. Conf.'), self.filter_conf)
|
||||
self.add_text_entry(_('Note'), self.filter_note)
|
||||
self.add_filter_entry(_('Custom filter'), self.generic)
|
||||
self.add_entry(None, self.filter_regex)
|
||||
|
||||
@@ -135,8 +135,8 @@ class FilterList(object):
|
||||
f.write(' comment="%s"' % self.fix(comment))
|
||||
f.write('>\n')
|
||||
for rule in the_filter.get_rules():
|
||||
f.write(' <rule class="%s">\n'
|
||||
% rule.__class__.__name__)
|
||||
f.write(' <rule class="%s" use_regex="%s">\n'
|
||||
% (rule.__class__.__name__, rule.use_regex))
|
||||
for value in rule.values():
|
||||
f.write(' <arg value="%s"/>\n' % self.fix(value))
|
||||
f.write(' </rule>\n')
|
||||
|
||||
@@ -52,6 +52,7 @@ class FilterParser(handler.ContentHandler):
|
||||
self.a = []
|
||||
self.cname = None
|
||||
self.namespace = 'Person'
|
||||
self.use_regex = False
|
||||
|
||||
def setDocumentLocator(self, locator):
|
||||
self.locator = locator
|
||||
@@ -82,6 +83,10 @@ class FilterParser(handler.ContentHandler):
|
||||
self.f.set_comment(attrs['comment'])
|
||||
self.gfilter_list.add(self.namespace, self.f)
|
||||
elif tag == "rule":
|
||||
if attrs.has_key('use_regex'):
|
||||
self.use_regex = attrs['use_regex'] == 'True'
|
||||
else:
|
||||
self.use_regex = False
|
||||
save_name = attrs['class']
|
||||
if save_name in old_names_2_class:
|
||||
self.r = old_names_2_class[save_name]
|
||||
@@ -115,7 +120,7 @@ class FilterParser(handler.ContentHandler):
|
||||
"Trying to load with subset of arguments.") %\
|
||||
self.f.get_name()
|
||||
nargs = len(self.r.labels)
|
||||
rule = self.r(self.a[0:nargs])
|
||||
rule = self.r(self.a[0:nargs], self.use_regex)
|
||||
self.f.add_rule(rule)
|
||||
else:
|
||||
if len(self.r.labels) > len(self.a):
|
||||
@@ -124,7 +129,7 @@ class FilterParser(handler.ContentHandler):
|
||||
"will be upgraded.") %\
|
||||
self.f.get_name()
|
||||
try:
|
||||
rule = self.r(self.a)
|
||||
rule = self.r(self.a, self.use_regex)
|
||||
except AssertionError, msg:
|
||||
print msg
|
||||
print _("ERROR: filter %s could not be correctly loaded. "
|
||||
|
||||
@@ -107,6 +107,12 @@ class QuestionDialog(object):
|
||||
if response == gtk.RESPONSE_ACCEPT:
|
||||
task()
|
||||
|
||||
from GrampsDisplay import url as display_url
|
||||
def on_activate_link(label, uri):
|
||||
# see aboutdialog.py _show_url()
|
||||
display_url(uri)
|
||||
return True
|
||||
|
||||
class QuestionDialog2(object):
|
||||
def __init__(self, msg1, msg2, label_msg1, label_msg2, parent=None):
|
||||
self.xml = Glade(toplevel='questiondialog')
|
||||
@@ -120,6 +126,8 @@ class QuestionDialog2(object):
|
||||
label1.set_use_markup(True)
|
||||
|
||||
label2 = self.xml.get_object('qd_label2')
|
||||
# see https://github.com/emesene/emesene/issues/723
|
||||
label2.connect('activate-link', on_activate_link)
|
||||
label2.set_text(msg2)
|
||||
label2.set_use_markup(True)
|
||||
|
||||
@@ -217,6 +225,11 @@ class WarningDialog(gtk.MessageDialog):
|
||||
buttons=gtk.BUTTONS_CLOSE)
|
||||
self.set_markup('<span weight="bold" size="larger">%s</span>' % msg1)
|
||||
self.format_secondary_markup(msg2)
|
||||
# FIXME: Hyper-links in the secondary text display as underlined text,
|
||||
# but clicking on the link fails with
|
||||
# GtkWarning: Unable to show 'http://www.gramps-project.org/wiki/index.php?title=How_to_make_a_backup': Operation not supported
|
||||
# self.connect('activate-link'... fails with
|
||||
# <WarningDialog object at 0x4880300 (GtkMessageDialog at 0x5686010)>: unknown signal name: activate-link
|
||||
self.set_icon(ICON)
|
||||
self.set_title("%s - Gramps" % msg1)
|
||||
self.show()
|
||||
|
||||
+8
-2
@@ -29,6 +29,13 @@ Classes for relationships.
|
||||
#-------------------------------------------------------------------------
|
||||
import os
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# set up logging
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import logging
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GRAMPS modules
|
||||
@@ -1843,8 +1850,7 @@ def get_relationship_calculator(reinit=False):
|
||||
break
|
||||
if not relation_translation_found and \
|
||||
len(PluginRegister.get_instance().relcalc_plugins()):
|
||||
print (("No translation available for language '%s'. " +
|
||||
"Using 'english' instead.") % enlang)
|
||||
logging.warning(_("Family relationship translator not available for language '%s'. Using 'english' instead.") % enlang)
|
||||
return __RELCALC_CLASS()
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
+6
-3
@@ -49,7 +49,10 @@ from constfunc import mac
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
if "GRAMPSI18N" in os.environ:
|
||||
LOCALEDIR = os.environ["GRAMPSI18N"]
|
||||
if os.path.exists(os.environ["GRAMPSI18N"]):
|
||||
LOCALEDIR = os.environ["GRAMPSI18N"]
|
||||
else:
|
||||
LOCALEDIR = None
|
||||
elif os.path.exists( os.path.join(const.ROOT_DIR, "lang") ):
|
||||
LOCALEDIR = os.path.join(const.ROOT_DIR, "lang")
|
||||
elif os.path.exists(os.path.join(const.PREFIXDIR, "share/locale")):
|
||||
@@ -219,8 +222,8 @@ def setup_windows_gettext():
|
||||
return
|
||||
|
||||
# No complete/working translation found
|
||||
logging.warning("Translation might not be complete/not working for",\
|
||||
locale.getlocale()[0])
|
||||
logging.warning("Translation might not be complete, "
|
||||
"not working for your locale")
|
||||
|
||||
|
||||
def get_localedomain():
|
||||
|
||||
+88
-24
@@ -277,29 +277,81 @@ def encodingdefs():
|
||||
|
||||
conv_unicode_tosrtkey_ongtk: convert a unicode object to sortkey usable
|
||||
string when gtk is loaded or utf-8 is default python encoding
|
||||
|
||||
COLLATE_LANG: Language and sub-locale used for collation
|
||||
"""
|
||||
pass
|
||||
|
||||
if constfunc.win():
|
||||
# python encoding is ascii, but C functions need to receive the
|
||||
# windows codeset, so convert over to it
|
||||
conv_utf8_tosrtkey = lambda x: locale.strxfrm(x.decode("utf-8").encode(
|
||||
codeset))
|
||||
conv_unicode_tosrtkey = lambda x: locale.strxfrm(x.encode(codeset))
|
||||
#when gtk is imported the python defaultencoding is utf-8,
|
||||
#so no need to specify it
|
||||
conv_utf8_tosrtkey_ongtk = lambda x: locale.strxfrm(unicode(x).encode(
|
||||
codeset))
|
||||
conv_unicode_tosrtkey_ongtk = lambda x: locale.strxfrm(x.encode(codeset,'replace'))
|
||||
else:
|
||||
# on unix C functions need to receive utf-8. Default conversion would
|
||||
# use ascii, so it is needed to be explicit about the resulting encoding
|
||||
conv_utf8_tosrtkey = lambda x: locale.strxfrm(x)
|
||||
conv_unicode_tosrtkey = lambda x: locale.strxfrm(x.encode("utf-8"))
|
||||
# when gtk loaded, default encoding (sys.getdefaultencoding ) is utf-8,
|
||||
# so default conversion happens with utf-8
|
||||
conv_utf8_tosrtkey_ongtk = lambda x: locale.strxfrm(x)
|
||||
conv_unicode_tosrtkey_ongtk = lambda x: locale.strxfrm(x)
|
||||
try:
|
||||
import PyICU
|
||||
if os.environ.has_key("LC_COLLATE"):
|
||||
collation = os.environ['LC_COLLATE']
|
||||
else:
|
||||
collation = os.environ["LANG"]
|
||||
language_and_country = collation.rsplit('.', 1)[0]
|
||||
if language_and_country in PyICU.Collator.getAvailableLocales().keys():
|
||||
COLLATE_LANG = language_and_country
|
||||
else:
|
||||
language = collation.rsplit('_', 1)[0]
|
||||
if language in PyICU.Collator.getAvailableLocales().keys():
|
||||
LOG.warn(_('The language and country combination "%s" '
|
||||
'is not supported by ICU, '
|
||||
'but language %s is supported and will be used' %
|
||||
(language_and_country, language)))
|
||||
COLLATE_LANG = language
|
||||
else:
|
||||
LOG.warn(_('Neither the language and country combination '
|
||||
'"%s" nor language %s is supported by ICU: using en_GB' %
|
||||
(language_and_country, language)))
|
||||
COLLATE_LANG = "en_GB"
|
||||
|
||||
collator = PyICU.Collator.createInstance(PyICU.Locale(COLLATE_LANG))
|
||||
# on ICU, the functions need to receive unicode
|
||||
conv_utf8_tosrtkey = lambda x: collator.getCollationKey(
|
||||
x.decode("UTF-8")).getByteArray()
|
||||
conv_unicode_tosrtkey = lambda x: collator.getCollationKey(
|
||||
x).getByteArray()
|
||||
conv_utf8_tosrtkey_ongtk = lambda x: collator.getCollationKey(
|
||||
x.decode("UTF-8")).getByteArray()
|
||||
conv_unicode_tosrtkey_ongtk = lambda x: collator.getCollationKey(
|
||||
x).getByteArray()
|
||||
except:
|
||||
LOG.warn(_("PyICU not available: sorting may be incorrect"))
|
||||
COLLATE_LANG = locale.getlocale()[0]
|
||||
if constfunc.win():
|
||||
# python encoding is ascii, but C functions need to receive the
|
||||
# windows codeset, so convert over to it
|
||||
conv_utf8_tosrtkey = lambda x: locale.strxfrm(x.decode("utf-8").encode(
|
||||
codeset))
|
||||
conv_unicode_tosrtkey = lambda x: locale.strxfrm(x.encode(codeset))
|
||||
#when gtk is imported the python defaultencoding is utf-8,
|
||||
#so no need to specify it
|
||||
conv_utf8_tosrtkey_ongtk = lambda x: locale.strxfrm(unicode(x).encode(
|
||||
codeset))
|
||||
conv_unicode_tosrtkey_ongtk = lambda x: locale.strxfrm(x.encode(codeset,'replace'))
|
||||
elif constfunc.mac():
|
||||
# On mac strxfrm seems to be broken such that better results are
|
||||
# obtained by applying strxfrm to each character individually, rather
|
||||
# than applying the function to the whole string. See in particular
|
||||
# greek names at bug 5645
|
||||
|
||||
# on mac C functions need to receive utf-8. Default conversion would
|
||||
# use ascii, so it is needed to be explicit about the resulting encoding
|
||||
conv_utf8_tosrtkey = lambda x: map(locale.strxfrm, x)
|
||||
conv_unicode_tosrtkey = lambda x: map(locale.strxfrm, x.encode("utf-8"))
|
||||
# when gtk loaded, default encoding (sys.getdefaultencoding ) is utf-8,
|
||||
# so default conversion happens with utf-8
|
||||
conv_utf8_tosrtkey_ongtk = lambda x: map(locale.strxfrm, x)
|
||||
conv_unicode_tosrtkey_ongtk = lambda x: map(locale.strxfrm, x.encode("utf-8"))
|
||||
else:
|
||||
# on unix C functions need to receive utf-8. Default conversion would
|
||||
# use ascii, so it is needed to be explicit about the resulting encoding
|
||||
conv_utf8_tosrtkey = lambda x: locale.strxfrm(x)
|
||||
conv_unicode_tosrtkey = lambda x: locale.strxfrm(x.encode("utf-8"))
|
||||
# when gtk loaded, default encoding (sys.getdefaultencoding ) is utf-8,
|
||||
# so default conversion happens with utf-8
|
||||
conv_utf8_tosrtkey_ongtk = lambda x: locale.strxfrm(x)
|
||||
conv_unicode_tosrtkey_ongtk = lambda x: locale.strxfrm(x.encode("utf-8"))
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@@ -667,13 +719,25 @@ class ProbablyAlive(object):
|
||||
if mother_handle == person.handle and father_handle:
|
||||
father = self.db.get_person_from_handle(father_handle)
|
||||
date1, date2, explain, other = self.probably_alive_range(father, is_spouse=True)
|
||||
if date1 and date2:
|
||||
return date1, date2, _("a spouse, ") + explain, other
|
||||
if date1 and date1.get_year() != 0:
|
||||
return (gen.lib.Date().copy_ymd(date1.get_year() - self.AVG_GENERATION_GAP),
|
||||
gen.lib.Date().copy_ymd(date1.get_year() - self.AVG_GENERATION_GAP + self.MAX_AGE_PROB_ALIVE),
|
||||
_("a spouse, ") + explain, other)
|
||||
elif date2 and date2.get_year() != 0:
|
||||
return (gen.lib.Date().copy_ymd(date2.get_year() + self.AVG_GENERATION_GAP - self.MAX_AGE_PROB_ALIVE),
|
||||
gen.lib.Date().copy_ymd(date2.get_year() + self.AVG_GENERATION_GAP),
|
||||
_("a spouse, ") + explain, other)
|
||||
elif father_handle == person.handle and mother_handle:
|
||||
mother = self.db.get_person_from_handle(mother_handle)
|
||||
date1, date2, explain, other = self.probably_alive_range(mother, is_spouse=True)
|
||||
if date1 and date2:
|
||||
return date1, date2, _("a spouse, ") + explain, other
|
||||
if date1 and date1.get_year() != 0:
|
||||
return (gen.lib.Date().copy_ymd(date1.get_year() - self.AVG_GENERATION_GAP),
|
||||
gen.lib.Date().copy_ymd(date1.get_year() - self.AVG_GENERATION_GAP + self.MAX_AGE_PROB_ALIVE),
|
||||
_("a spouse, ") + explain, other)
|
||||
elif date2 and date2.get_year() != 0:
|
||||
return (gen.lib.Date().copy_ymd(date2.get_year() + self.AVG_GENERATION_GAP - self.MAX_AGE_PROB_ALIVE),
|
||||
gen.lib.Date().copy_ymd(date2.get_year() + self.AVG_GENERATION_GAP),
|
||||
_("a spouse, ") + explain, other)
|
||||
# Let's check the family events and see if we find something
|
||||
for ref in family.get_event_ref_list():
|
||||
if ref:
|
||||
|
||||
+24
-6
@@ -162,6 +162,7 @@ class ArgHandler(object):
|
||||
self.actions = parser.actions
|
||||
self.list = parser.list
|
||||
self.list_more = parser.list_more
|
||||
self.list_table = parser.list_table
|
||||
self.open_gui = parser.open_gui
|
||||
self.imp_db_path = None
|
||||
self.dbman = CLIDbManager(self.dbstate)
|
||||
@@ -369,12 +370,8 @@ class ArgHandler(object):
|
||||
if not self.check_db(db_path, self.force_unlock):
|
||||
sys.exit(0)
|
||||
# Add the file to the recent items
|
||||
path = os.path.join(db_path, "name.txt")
|
||||
try:
|
||||
ifile = open(path)
|
||||
title = ifile.readline().strip()
|
||||
ifile.close()
|
||||
except:
|
||||
title = self.dbstate.db.get_dbname()
|
||||
if not title:
|
||||
title = db_path
|
||||
RecentFiles.recent_files(db_path, title)
|
||||
self.open = db_path
|
||||
@@ -423,6 +420,27 @@ class ArgHandler(object):
|
||||
encode(sys.getfilesystemencoding())
|
||||
sys.exit(0)
|
||||
|
||||
if self.list_table:
|
||||
print _('Gramps Family Trees:').encode(sys.getfilesystemencoding())
|
||||
summary_list = self.dbman.family_tree_summary()
|
||||
print _("Family Tree").encode(sys.getfilesystemencoding()),
|
||||
for key in sorted(summary_list[0]):
|
||||
if key != _("Family tree"):
|
||||
print "\t ",
|
||||
print key.encode(sys.getfilesystemencoding()),
|
||||
print
|
||||
for summary in sorted(summary_list,
|
||||
key=lambda sum: sum[_("Family tree")].lower()):
|
||||
print '"%s"'.\
|
||||
encode(sys.getfilesystemencoding()) % summary[_("Family tree")],
|
||||
for item in sorted(summary):
|
||||
if item != _("Family tree"):
|
||||
print "\t ",
|
||||
print ('"%s"' % summary[item]).\
|
||||
encode(sys.getfilesystemencoding()),
|
||||
print
|
||||
sys.exit(0)
|
||||
|
||||
self.__open_action()
|
||||
self.__import_action()
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ Application options
|
||||
-d, --debug=LOGGER_NAME Enable debug logs
|
||||
-l List Family Trees
|
||||
-L List Family Trees in Detail
|
||||
-t List Family Trees, tab delimited
|
||||
-u, --force-unlock Force unlock of family tree
|
||||
-s, --show Show config settings
|
||||
-c, --config=[config.setting[:value]] Set config setting(s) and start Gramps
|
||||
@@ -174,6 +175,7 @@ class ArgParser(object):
|
||||
self.imp_db_path = None
|
||||
self.list = False
|
||||
self.list_more = False
|
||||
self.list_table = False
|
||||
self.help = False
|
||||
self.usage = False
|
||||
self.force_unlock = False
|
||||
@@ -289,6 +291,8 @@ class ArgParser(object):
|
||||
self.list = True
|
||||
elif option in ('-L'):
|
||||
self.list_more = True
|
||||
elif option in ('-t'):
|
||||
self.list_table = True
|
||||
elif option in ('-s','--show'):
|
||||
print "Gramps config settings from %s:" % \
|
||||
config.config.filename.encode(sys.getfilesystemencoding())
|
||||
@@ -343,7 +347,8 @@ class ArgParser(object):
|
||||
del options[ind]
|
||||
|
||||
if len(options) > 0 and self.open is None and self.imports == [] \
|
||||
and not (self.list or self.list_more or self.help or self.runqml):
|
||||
and not (self.list or self.list_more or self.list_table or
|
||||
self.help or self.runqml):
|
||||
# Extract and convert to unicode the arguments in the list.
|
||||
# The % operator replaces the list elements with repr() of
|
||||
# the list elements, which is OK for latin characters
|
||||
@@ -370,7 +375,7 @@ class ArgParser(object):
|
||||
#errors in argument parsing ==> give cli error, no gui needed
|
||||
return False
|
||||
|
||||
if self.list or self.list_more or self.help:
|
||||
if self.list or self.list_more or self.list_table or self.help:
|
||||
return False
|
||||
|
||||
if self.open_gui:
|
||||
|
||||
+53
-20
@@ -46,6 +46,8 @@ from gen.ggettext import gettext as _
|
||||
#-------------------------------------------------------------------------
|
||||
import logging
|
||||
LOG = logging.getLogger(".clidbman")
|
||||
from gen.db.dbconst import DBLOGNAME
|
||||
_LOG = logging.getLogger(DBLOGNAME)
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@@ -127,67 +129,91 @@ class CLIDbManager(object):
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_dbdir_summary(self, file_name):
|
||||
def get_dbdir_summary(self, dirpath, name):
|
||||
"""
|
||||
Returns (people_count, version_number) of current DB.
|
||||
Returns ("Unknown", "Unknown") if invalid DB or other error.
|
||||
Returns (people_count, bsddb_version, schema_version) of
|
||||
current DB.
|
||||
Returns ("Unknown", "Unknown", "Unknown") if invalid DB or other error.
|
||||
"""
|
||||
if config.get('preferences.use-bsddb3'):
|
||||
from bsddb3 import dbshelve, db
|
||||
else:
|
||||
from bsddb import dbshelve, db
|
||||
|
||||
from gen.db import META, PERSON_TBL
|
||||
from gen.db.dbconst import BDBVERSFN
|
||||
|
||||
bdbversion_file = os.path.join(dirpath, BDBVERSFN)
|
||||
if os.path.isfile(bdbversion_file):
|
||||
vers_file = open(bdbversion_file)
|
||||
bsddb_version = vers_file.readline().strip()
|
||||
else:
|
||||
return "Unknown", "Unknown", "Unknown"
|
||||
|
||||
current_bsddb_version = str(db.version())
|
||||
if bsddb_version != current_bsddb_version:
|
||||
return "Unknown", bsddb_version, "Unknown"
|
||||
|
||||
env = db.DBEnv()
|
||||
flags = db.DB_CREATE | db.DB_PRIVATE |\
|
||||
db.DB_INIT_MPOOL | db.DB_INIT_LOCK |\
|
||||
db.DB_INIT_LOG | db.DB_INIT_TXN | db.DB_THREAD
|
||||
db.DB_INIT_MPOOL |\
|
||||
db.DB_INIT_LOG | db.DB_INIT_TXN
|
||||
try:
|
||||
env.open(file_name, flags)
|
||||
except:
|
||||
return "Unknown", "Unknown"
|
||||
env.open(dirpath, flags)
|
||||
except Exception as msg:
|
||||
LOG.warning("Error opening db environment for '%s': %s" %
|
||||
(name, str(msg)))
|
||||
try:
|
||||
env.close()
|
||||
except Exception as msg:
|
||||
LOG.warning("Error closing db environment for '%s': %s" %
|
||||
(name, str(msg)))
|
||||
return "Unknown", bsddb_version, "Unknown"
|
||||
dbmap1 = dbshelve.DBShelf(env)
|
||||
fname = os.path.join(file_name, META + ".db")
|
||||
fname = os.path.join(dirpath, META + ".db")
|
||||
try:
|
||||
dbmap1.open(fname, META, db.DB_HASH, db.DB_RDONLY)
|
||||
except:
|
||||
return "Unknown", "Unknown"
|
||||
version = dbmap1.get('version', default=None)
|
||||
env.close()
|
||||
return "Unknown", bsddb_version, "Unknown"
|
||||
schema_version = dbmap1.get('version', default=None)
|
||||
dbmap1.close()
|
||||
dbmap2 = dbshelve.DBShelf(env)
|
||||
fname = os.path.join(file_name, PERSON_TBL + ".db")
|
||||
fname = os.path.join(dirpath, PERSON_TBL + ".db")
|
||||
try:
|
||||
dbmap2.open(fname, PERSON_TBL, db.DB_HASH, db.DB_RDONLY)
|
||||
except:
|
||||
env.close()
|
||||
return "Unknown", "Unknown"
|
||||
return "Unknown", bsddb_version, schema_version
|
||||
count = len(dbmap2)
|
||||
dbmap2.close()
|
||||
env.close()
|
||||
return (count, version)
|
||||
return (count, bsddb_version, schema_version)
|
||||
|
||||
def family_tree_summary(self):
|
||||
"""
|
||||
Return a list of dictionaries of the known family trees.
|
||||
"""
|
||||
# make the default directory if it does not exist
|
||||
list = []
|
||||
summary_list = []
|
||||
for item in self.current_names:
|
||||
(name, dirpath, path_name, last,
|
||||
tval, enable, stock_id) = item
|
||||
count, version = self.get_dbdir_summary(dirpath)
|
||||
count, bsddb_version, schema_version = self.get_dbdir_summary(dirpath, name)
|
||||
retval = {}
|
||||
retval[_("Number of people")] = count
|
||||
if enable:
|
||||
retval[_("Locked?")] = _("yes")
|
||||
else:
|
||||
retval[_("Locked?")] = _("no")
|
||||
retval[_("DB version")] = version
|
||||
retval[_("Bsddb version")] = bsddb_version
|
||||
retval[_("Schema version")] = schema_version
|
||||
retval[_("Family tree")] = name.encode(sys.getfilesystemencoding())
|
||||
retval[_("Path")] = dirpath
|
||||
retval[_("Last accessed")] = time.strftime('%x %X',
|
||||
time.localtime(tval))
|
||||
list.append( retval )
|
||||
return list
|
||||
summary_list.append( retval )
|
||||
return summary_list
|
||||
|
||||
def _populate_cli(self):
|
||||
""" Get the list of current names in the database dir
|
||||
@@ -203,7 +229,9 @@ class CLIDbManager(object):
|
||||
dirpath = os.path.join(dbdir, dpath)
|
||||
path_name = os.path.join(dirpath, NAME_FILE)
|
||||
if os.path.isfile(path_name):
|
||||
name = file(path_name).readline().strip()
|
||||
f = open(path_name)
|
||||
name = f.readline().strip()
|
||||
f.close()
|
||||
|
||||
(tval, last) = time_val(dirpath)
|
||||
(enable, stock_id) = self.icon_values(dirpath, self.active,
|
||||
@@ -319,6 +347,11 @@ class CLIDbManager(object):
|
||||
self.__start_cursor(_("Importing data..."))
|
||||
dbclass = gen.db.DbBsddb
|
||||
dbase = dbclass()
|
||||
from gen.db.dbconst import BDBVERSFN
|
||||
versionpath = os.path.join(name, BDBVERSFN)
|
||||
_LOG.debug("Write bsddb version %s" % str(dbase.version()))
|
||||
with open(versionpath, "w") as version_file:
|
||||
version_file.write(str(dbase.version()))
|
||||
dbase.load(new_path, callback)
|
||||
|
||||
import_function = plugin.get_import_function()
|
||||
|
||||
@@ -154,9 +154,27 @@ class CLIDbLoader(object):
|
||||
try:
|
||||
self.dbstate.db.load(filename, self._pulse_progress, mode)
|
||||
self.dbstate.db.set_save_path(filename)
|
||||
except gen.db.exceptions.DbEnvironmentError, msg:
|
||||
self.dbstate.no_database()
|
||||
self._errordialog( _("Cannot open database"), str(msg))
|
||||
except gen.db.exceptions.BsddbUpgradeRequiredError, msg:
|
||||
self.dbstate.no_database()
|
||||
self._errordialog( _("Cannot open database"), str(msg))
|
||||
except gen.db.exceptions.BsddbDowngradeError, msg:
|
||||
self.dbstate.no_database()
|
||||
self._errordialog( _("Cannot open database"), str(msg))
|
||||
except gen.db.exceptions.BsddbDowngradeRequiredError, msg:
|
||||
self.dbstate.no_database()
|
||||
self._errordialog( _("Cannot open database"), str(msg))
|
||||
except gen.db.exceptions.DbUpgradeRequiredError, msg:
|
||||
self.dbstate.no_database()
|
||||
self._errordialog( _("Cannot open database"), str(msg))
|
||||
except gen.db.exceptions.PythonUpgradeRequiredError, msg:
|
||||
self.dbstate.no_database()
|
||||
self._errordialog( _("Cannot open database"), str(msg))
|
||||
except gen.db.exceptions.PythonDowngradeError, msg:
|
||||
self.dbstate.no_database()
|
||||
self._errordialog( _("Cannot open database"), str(msg))
|
||||
except gen.db.exceptions.DbVersionError, msg:
|
||||
self.dbstate.no_database()
|
||||
self._errordialog( _("Cannot open database"), str(msg))
|
||||
|
||||
@@ -486,6 +486,7 @@ class CommandLineReport(object):
|
||||
print (_("Use '%(notranslate)s' to see valid values.") %
|
||||
{'notranslate' : "show=off"}).encode(sys.getfilesystemencoding())
|
||||
|
||||
self.paper = paper_sizes[0] # make sure one exists
|
||||
for paper in paper_sizes:
|
||||
if paper.get_name() == self.options_dict['papers']:
|
||||
self.paper = paper
|
||||
|
||||
@@ -151,6 +151,7 @@ register('behavior.surname-guessing', 0)
|
||||
register('behavior.use-tips', False)
|
||||
register('behavior.welcome', 100)
|
||||
register('behavior.web-search-url', 'http://google.com/#&q=%(text)s')
|
||||
register('behavior.addons-url', "http://svn.code.sf.net/p/gramps-addons/code/branches/gramps34/")
|
||||
|
||||
register('export.proxy-order', [
|
||||
["privacy", 0],
|
||||
|
||||
+4
-4
@@ -43,10 +43,10 @@ from gen.ggettext import sgettext as _
|
||||
#-------------------------------------------------------------------------
|
||||
PROGRAM_NAME = "Gramps"
|
||||
if "@VERSIONSTRING@" == "@" + "VERSIONSTRING" + "@":
|
||||
VERSION = "3.4.2"
|
||||
VERSION = "3.4.5"
|
||||
else:
|
||||
VERSION = "@VERSIONSTRING@"
|
||||
VERSION_TUPLE = (3, 4, 2)
|
||||
VERSION_TUPLE = (3, 4, 5)
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@@ -199,7 +199,7 @@ else:
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
COPYRIGHT_MSG = u"\u00A9 2001-2006 Donald N. Allingham\n" \
|
||||
u"\u00A9 2007-2012 The Gramps Developers"
|
||||
u"\u00A9 2007-2013 The Gramps Developers"
|
||||
COMMENTS = _("Gramps (Genealogical Research and Analysis "
|
||||
"Management Programming System) is a personal "
|
||||
"genealogy program.")
|
||||
@@ -301,6 +301,6 @@ LONGOPTS = [
|
||||
"qml",
|
||||
]
|
||||
|
||||
SHORTOPTS = "O:C:i:e:f:a:p:d:c:lLhuv?s"
|
||||
SHORTOPTS = "O:C:i:e:f:a:p:d:c:lLthuv?s"
|
||||
|
||||
GRAMPS_UUID = uuid.UUID('516cd010-5a41-470f-99f8-eb22f1098ad6')
|
||||
|
||||
+3
-2
@@ -1014,7 +1014,8 @@ class DbReadBase(object):
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def load(self, name, callback, mode=None, upgrade=False):
|
||||
def load(self, name, callback, mode=None, force_schema_upgrade=False,
|
||||
force_bsddb_upgrade=False):
|
||||
"""
|
||||
Open the specified database.
|
||||
"""
|
||||
@@ -1399,7 +1400,7 @@ class DbWriteBase(DbReadBase):
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def need_upgrade(self):
|
||||
def need_schema_upgrade(self):
|
||||
"""
|
||||
Return True if database needs to be upgraded
|
||||
"""
|
||||
|
||||
@@ -197,8 +197,8 @@ if __name__ == "__main__":
|
||||
x = db.DBEnv()
|
||||
print "3"
|
||||
x.open('/tmp', db.DB_CREATE | db.DB_PRIVATE |\
|
||||
db.DB_INIT_MPOOL | db.DB_INIT_LOCK |\
|
||||
db.DB_INIT_LOG | db.DB_INIT_TXN | db.DB_THREAD)
|
||||
db.DB_INIT_MPOOL |\
|
||||
db.DB_INIT_LOG | db.DB_INIT_TXN)
|
||||
print "4"
|
||||
d = dbshelve.DBShelf(x)
|
||||
print "5"
|
||||
|
||||
+153
-20
@@ -71,13 +71,23 @@ class DbVersionError(Exception):
|
||||
Error used to report that a file could not be read because it is written
|
||||
in an unsupported version of the file format.
|
||||
"""
|
||||
def __init__(self):
|
||||
def __init__(self, tree_vers, min_vers, max_vers):
|
||||
Exception.__init__(self)
|
||||
self.tree_vers = tree_vers
|
||||
self.min_vers = min_vers
|
||||
self.max_vers = max_vers
|
||||
|
||||
def __str__(self):
|
||||
return _("The database version is not supported by this version of "
|
||||
"Gramps.\nPlease upgrade to the corresponding version or use "
|
||||
"XML for porting data between different database versions.")
|
||||
return _('The schema version is not supported by this version of '
|
||||
'Gramps.\n\n'
|
||||
'This Family Tree is schema version %(tree_vers)s, and this '
|
||||
'version of Gramps supports versions %(min_vers)s to '
|
||||
'%(max_vers)s\n\n'
|
||||
'Please upgrade to the corresponding version or use '
|
||||
'XML for porting data between different schema versions.') %\
|
||||
{'tree_vers': self.tree_vers,
|
||||
'min_vers': self.min_vers,
|
||||
'max_vers': self.max_vers}
|
||||
|
||||
class BsddbDowngradeError(Exception):
|
||||
"""
|
||||
@@ -90,19 +100,70 @@ class BsddbDowngradeError(Exception):
|
||||
self.bdb_version = str(bdb_version)
|
||||
|
||||
def __str__(self):
|
||||
return _('Gramps stores its data in a Berkeley Database. '
|
||||
'The family tree you try to load was created with version '
|
||||
'%(env_version)s of the Berkeley DB. However, the Gramps '
|
||||
'version in use right now employs version %(bdb_version)s '
|
||||
'of the Berkeley DB. So you are trying to load data created '
|
||||
'in a newer format into an older program; this is bound to '
|
||||
'fail. The right approach in this case is to use XML export '
|
||||
'and import. So try to open the family tree on that computer '
|
||||
'with that software that created the family tree, export it '
|
||||
'to XML and load that XML into the version of Gramps you '
|
||||
'intend to use.') % {'env_version': self.env_version,
|
||||
return _('The Family Tree you are trying to load is in the Bsddb '
|
||||
'version %(env_version)s format. This version of Gramps uses '
|
||||
'Bsddb version %(bdb_version)s. So you are trying to load '
|
||||
'data created in a newer format into an older program, and '
|
||||
'this is bound to fail.\n\n'
|
||||
'You should start your <b>newer</b> version of Gramps and '
|
||||
'<a href="http://www.gramps-project.org/wiki/index.php?title=How_to_make_a_backup">'
|
||||
'make a backup</a> of your Family Tree. You can then import '
|
||||
'this backup into this version of Gramps.') % \
|
||||
{'env_version': self.env_version,
|
||||
'bdb_version': self.bdb_version}
|
||||
|
||||
class BsddbDowngradeRequiredError(Exception):
|
||||
"""
|
||||
Error used to report that the Berkeley database used to create the family
|
||||
tree is of a version that is newer than the current version, but it may be
|
||||
possible to open the tree, because the difference is only a point upgrade
|
||||
(i.e. a difference in the last digit of the version tuple).
|
||||
"""
|
||||
def __init__(self, env_version, bdb_version):
|
||||
Exception.__init__(self)
|
||||
self.env_version = str(env_version)
|
||||
self.bdb_version = str(bdb_version)
|
||||
|
||||
def __str__(self):
|
||||
return _('The Family Tree you are trying to load is in the Bsddb '
|
||||
'version %(env_version)s format. This version of Gramps uses '
|
||||
'Bsddb version %(bdb_version)s. So you are trying to load '
|
||||
'data created in a newer format into an older program. In '
|
||||
'this particular case, the difference is very small, so it '
|
||||
'may work.\n\n'
|
||||
'If you have not already made a backup of your Family Tree, '
|
||||
'then you should start your <b>newer</b> version of Gramps and '
|
||||
'<a href="http://www.gramps-project.org/wiki/index.php?title=How_to_make_a_backup">'
|
||||
'make a backup</a> of your Family Tree.') % \
|
||||
{'env_version': self.env_version,
|
||||
'bdb_version': self.bdb_version}
|
||||
|
||||
class BsddbUpgradeRequiredError(Exception):
|
||||
"""
|
||||
Error used to report that the Berkeley database used to create the family
|
||||
tree is of a version that is too new to be supported by the current version.
|
||||
"""
|
||||
def __init__(self, env_version, bsddb_version):
|
||||
Exception.__init__(self)
|
||||
self.env_version = str(env_version)
|
||||
self.bsddb_version = str(bsddb_version)
|
||||
|
||||
def __str__(self):
|
||||
return _('The Family Tree you are trying to load is in the Bsddb '
|
||||
'version %(env_version)s format. This version of Gramps uses '
|
||||
'Bsddb version %(bdb_version)s. Therefore you cannot load '
|
||||
'this Family Tree without upgrading the Bsddb version of the '
|
||||
'Family Tree.\n\n'
|
||||
'Opening the Family Tree with this version of Gramps might '
|
||||
'irretrievably corrupt your Family Tree. You are strongly '
|
||||
'advised to backup your Family Tree.\n\n'
|
||||
'If you have not already made a backup of your Family Tree, '
|
||||
'then you should start your <b>old</b> version of Gramps and '
|
||||
'<a href="http://www.gramps-project.org/wiki/index.php?title=How_to_make_a_backup">'
|
||||
'make a backup</a> of your Family Tree.') % \
|
||||
{'env_version': self.env_version,
|
||||
'bdb_version': self.bsddb_version}
|
||||
|
||||
class DbEnvironmentError(Exception):
|
||||
"""
|
||||
Error used to report that the database 'environment' could not be opened.
|
||||
@@ -132,11 +193,83 @@ class DbUpgradeRequiredError(Exception):
|
||||
Error used to report that a database needs to be upgraded before it can be
|
||||
used.
|
||||
"""
|
||||
def __init__(self):
|
||||
def __init__(self, oldschema, newschema):
|
||||
Exception.__init__(self)
|
||||
self.oldschema = oldschema
|
||||
self.newschema = newschema
|
||||
|
||||
def __str__(self):
|
||||
return _("You cannot open this database without upgrading it.\n"
|
||||
"If you upgrade then you won't be able to use previous "
|
||||
"versions of Gramps.\n"
|
||||
"You might want to make a backup copy first.")
|
||||
return _('The Family Tree you are trying to load is in the schema '
|
||||
'version %(oldschema)s format. This version of Gramps uses '
|
||||
'schema version %(newschema)s. Therefore you cannot load this '
|
||||
'Family Tree without upgrading the schema version of the '
|
||||
'Family Tree.\n\n'
|
||||
'If you upgrade then you won\'t be able to use the previous '
|
||||
'version of Gramps, even if you subsequently '
|
||||
'<a href="http://www.gramps-project.org/wiki/index.php?title=Gramps_4.0_Wiki_Manual_-_Manage_Family_Trees#Backing_up_a_Family_Tree">backup</a> '
|
||||
'or <a href="http://www.gramps-project.org/wiki/index.php?title=Gramps_4.0_Wiki_Manual_-_Manage_Family_Trees#Export_into_Gramps_formats">export</a> '
|
||||
'your upgraded Family Tree.\n\n'
|
||||
'Upgrading is a difficult task which could irretrievably '
|
||||
'corrupt your Family Tree if it is interrupted or fails.\n\n'
|
||||
'If you have not already made a backup of your Family Tree, '
|
||||
'then you should start your <b>old</b> version of Gramps and '
|
||||
'<a href="http://www.gramps-project.org/wiki/index.php?title=How_to_make_a_backup">make a backup</a> '
|
||||
'of your Family Tree.') % \
|
||||
{'oldschema': self.oldschema,
|
||||
'newschema': self.newschema}
|
||||
|
||||
class PythonDowngradeError(Exception):
|
||||
"""
|
||||
Error used to report that the Python version used to create the family tree
|
||||
(i.e. Python3) is of a version that is newer than the current version
|
||||
(i.e.Python2), so the Family Tree cannot be opened
|
||||
"""
|
||||
def __init__(self, db_python_version, current_python_version):
|
||||
Exception.__init__(self)
|
||||
self.db_python_version = str(db_python_version)
|
||||
self.current_python_version = str(current_python_version)
|
||||
|
||||
def __str__(self):
|
||||
return _('The Family Tree you are trying to load was created with '
|
||||
'Python version %(db_python_version)s. This version of Gramps '
|
||||
'uses Python version %(current_python_version)s. So you are '
|
||||
'trying to load '
|
||||
'data created in a newer format into an older program, and '
|
||||
'this is bound to fail.\n\n'
|
||||
'You should start your <b>newer</b> version of Gramps and '
|
||||
'<a href="http://www.gramps-project.org/wiki/index.php?title=How_to_make_a_backup">'
|
||||
'make a backup</a> of your Family Tree. You can then import '
|
||||
'this backup into this version of Gramps.') % \
|
||||
{'db_python_version': self.db_python_version,
|
||||
'current_python_version': self.current_python_version}
|
||||
|
||||
class PythonUpgradeRequiredError(Exception):
|
||||
"""
|
||||
Error used to report that the Python version used to create the family tree
|
||||
(i.e. Python2) is earlier than the current Python version (i.e. Python3), so
|
||||
the Family Tree needs to be upgraded..
|
||||
"""
|
||||
def __init__(self, db_python_version, current_python_version):
|
||||
Exception.__init__(self)
|
||||
self.db_python_version = str(db_python_version)
|
||||
self.current_python_version = str(current_python_version)
|
||||
|
||||
def __str__(self):
|
||||
return _('The Family Tree you are trying to load is in the Python '
|
||||
'version %(db_python_version)s format. This version of Gramps '
|
||||
'uses Python version %(current_python_version)s. Therefore '
|
||||
'you cannot load this Family Tree without upgrading the '
|
||||
'Python version of the Family Tree.\n\n'
|
||||
'If you upgrade then you won\'t be able to use the previous '
|
||||
'version of Gramps, even if you subsequently '
|
||||
'<a href="http://www.gramps-project.org/wiki/index.php?title=Gramps_4.0_Wiki_Manual_-_Manage_Family_Trees#Backing_up_a_Family_Tree">backup</a> '
|
||||
'or <a href="http://www.gramps-project.org/wiki/index.php?title=Gramps_4.0_Wiki_Manual_-_Manage_Family_Trees#Export_into_Gramps_formats">export</a> '
|
||||
'your upgraded Family Tree.\n\n'
|
||||
'Upgrading is a difficult task which could irretrievably '
|
||||
'corrupt your Family Tree if it is interrupted or fails.\n\n'
|
||||
'If you have not already made a backup of your Family Tree, '
|
||||
'then you should start your <b>old</b> version of Gramps and '
|
||||
'<a href="http://www.gramps-project.org/wiki/index.php?title=How_to_make_a_backup">make a backup</a> '
|
||||
'of your Family Tree.') % \
|
||||
{'db_python_version': self.db_python_version,
|
||||
'current_python_version': self.current_python_version}
|
||||
|
||||
+2
-1
@@ -709,6 +709,7 @@ class DbBsddbRead(DbReadBase, Callback):
|
||||
return self.get_from_handle(handle, Tag, self.tag_map)
|
||||
|
||||
def __get_obj_from_gramps_id(self, val, tbl, class_, prim_tbl):
|
||||
if isinstance(tbl, dict): return None ## trying to get object too early
|
||||
try:
|
||||
data = tbl.get(str(val), txn=self.txn)
|
||||
if data is not None:
|
||||
@@ -1751,7 +1752,7 @@ class DbBsddbRead(DbReadBase, Callback):
|
||||
filepath = os.path.join(self.path, "name.txt")
|
||||
try:
|
||||
name_file = open(filepath, "r")
|
||||
name = name_file.read()
|
||||
name = name_file.readline().strip()
|
||||
name_file.close()
|
||||
except (OSError, IOError), msg:
|
||||
self.__log_error()
|
||||
|
||||
@@ -211,7 +211,7 @@ class DbTest(object):
|
||||
"commit_source",
|
||||
"commit_tag",
|
||||
"delete_primary_from_reference_map",
|
||||
"need_upgrade",
|
||||
"need_schema_upgrade",
|
||||
"rebuild_secondary",
|
||||
"reindex_reference_map",
|
||||
"remove_event",
|
||||
|
||||
+183
-40
@@ -40,7 +40,7 @@ import locale
|
||||
import bisect
|
||||
from functools import wraps
|
||||
import logging
|
||||
from sys import maxint
|
||||
from sys import maxint, getfilesystemencoding, version_info
|
||||
|
||||
from gen.ggettext import gettext as _
|
||||
import config
|
||||
@@ -59,7 +59,7 @@ from gen.lib import (GenderStats, Person, Family, Event, Place, Source,
|
||||
from gen.db import (DbBsddbRead, DbWriteBase, BSDDBTxn,
|
||||
DbTxn, BsddbBaseCursor, BsddbDowngradeError, DbVersionError,
|
||||
DbEnvironmentError, DbUpgradeRequiredError, find_surname,
|
||||
find_surname_name, DbUndoBSDDB as DbUndo)
|
||||
find_surname_name, DbUndoBSDDB as DbUndo, exceptions)
|
||||
from gen.db.dbconst import *
|
||||
from gen.utils.callback import Callback
|
||||
from gen.updatecallback import UpdateCallback
|
||||
@@ -232,6 +232,7 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
|
||||
self.has_changed = False
|
||||
self.brief_name = None
|
||||
self.update_env_version = False
|
||||
self.update_python_version = False
|
||||
|
||||
def catch_db_error(func):
|
||||
"""
|
||||
@@ -357,34 +358,150 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
|
||||
with BSDDBTxn(self.env, self.metadata) as txn:
|
||||
txn.put('mediapath', path)
|
||||
|
||||
def __check_bdb_version(self, name):
|
||||
"""Older version of Berkeley DB can't read data created by a newer
|
||||
version."""
|
||||
def __make_zip_backup(self, dirname):
|
||||
import zipfile
|
||||
title = self.get_dbname()
|
||||
|
||||
if not os.access(dirname, os.W_OK):
|
||||
_LOG.warning("Can't write technical DB backup for %s" % title)
|
||||
return
|
||||
(grampsdb_path, db_code) = os.path.split(dirname)
|
||||
dotgramps_path = os.path.dirname(grampsdb_path)
|
||||
zipname = title + time.strftime("_%Y-%m-%d_%H-%M-%S") + ".zip"
|
||||
zipname = zipname.encode(getfilesystemencoding())
|
||||
zippath = os.path.join(dotgramps_path, zipname)
|
||||
myzip = zipfile.ZipFile(zippath, 'w')
|
||||
for filename in os.listdir(dirname):
|
||||
pathname = os.path.join(dirname, filename)
|
||||
myzip.write(pathname, os.path.join(db_code, filename))
|
||||
myzip.close()
|
||||
_LOG.warning("If upgrade and loading the Family Tree works, you can "
|
||||
"delete the zip file at %s" %
|
||||
zippath)
|
||||
|
||||
def __check_bdb_version(self, name, force_bsddb_upgrade=False,
|
||||
force_bsddb_downgrade=False):
|
||||
"""
|
||||
Older version of Berkeley DB can't read data created by a newer
|
||||
version.
|
||||
name: Directory path of the database files
|
||||
force_bsddb_upgrade: whether the user has requested that the database be
|
||||
upgraded
|
||||
"""
|
||||
bdb_version = db.version()
|
||||
env_version = (0, 0, 0)
|
||||
versionpath = os.path.join(self.path, BDBVERSFN)
|
||||
try:
|
||||
# Compare the current version of the database (bsddb_version) with the
|
||||
# version of the database code (env_version). If it is a downgrade,
|
||||
# raise an exception because we can't do anything. If they are the same,
|
||||
# return. If it is an upgrade, raise an exception unless the user has
|
||||
# already told us we can upgrade.
|
||||
if os.path.isfile(versionpath):
|
||||
with open(versionpath, "r") as version_file:
|
||||
env_version = version_file.read().strip()
|
||||
env_version = tuple(map(int, env_version[1:-1].split(', ')))
|
||||
except:
|
||||
# Just assume that the Berkeley DB version is OK.
|
||||
pass
|
||||
if (env_version[0] > bdb_version[0]) or \
|
||||
bsddb_version = version_file.read().strip()
|
||||
env_version = tuple(map(int, bsddb_version[1:-1].split(', ')))
|
||||
else:
|
||||
# bsddb version is unknown
|
||||
bsddb_version = "Unknown"
|
||||
env_version = "Unknown"
|
||||
# _LOG.debug("db version %s, program version %s" % (bsddb_version, bdb_version))
|
||||
|
||||
if env_version == "Unknown" or \
|
||||
(env_version[0] < bdb_version[0]) or \
|
||||
(env_version[0] == bdb_version[0] and
|
||||
env_version[1] < bdb_version[1]) or \
|
||||
(env_version[0] == bdb_version[0] and
|
||||
env_version[1] == bdb_version[1] and
|
||||
env_version[2] < bdb_version[2]):
|
||||
# an upgrade is needed
|
||||
if not force_bsddb_upgrade:
|
||||
_LOG.debug("Bsddb upgrade required from %s to %s" %
|
||||
(bsddb_version, str(bdb_version)))
|
||||
clear_lock_file(name)
|
||||
raise exceptions.BsddbUpgradeRequiredError(bsddb_version,
|
||||
str(bdb_version))
|
||||
if not self.readonly:
|
||||
_LOG.warning("Bsddb upgrade requested from %s to %s" %
|
||||
(bsddb_version, str(bdb_version)))
|
||||
self.update_env_version = True
|
||||
# Make a backup of the database files anyway
|
||||
self.__make_zip_backup(name)
|
||||
elif (env_version[0] > bdb_version[0]) or \
|
||||
(env_version[0] == bdb_version[0] and
|
||||
env_version[1] > bdb_version[1]):
|
||||
clear_lock_file(name)
|
||||
raise BsddbDowngradeError(env_version, bdb_version)
|
||||
elif env_version != bdb_version and not self.readonly:
|
||||
self.update_env_version = True
|
||||
elif (env_version[0] == bdb_version[0] and
|
||||
env_version[1] == bdb_version[1] and
|
||||
env_version[2] > bdb_version[2]):
|
||||
# A down-grade may be possible
|
||||
if not force_bsddb_downgrade:
|
||||
_LOG.debug("Bsddb downgrade required from %s to %s" %
|
||||
(bsddb_version, str(bdb_version)))
|
||||
clear_lock_file(name)
|
||||
raise exceptions.BsddbDowngradeRequiredError(bsddb_version,
|
||||
str(bdb_version))
|
||||
# Try to do a down-grade
|
||||
if not self.readonly:
|
||||
_LOG.warning("Bsddb downgrade requested from %s to %s" %
|
||||
(bsddb_version, str(bdb_version)))
|
||||
self.update_env_version = True
|
||||
# Make a backup of the database files anyway
|
||||
self.__make_zip_backup(name)
|
||||
elif env_version == bdb_version:
|
||||
# Bsddb version is OK
|
||||
pass
|
||||
else:
|
||||
# This can't happen
|
||||
raise "Comparison between Bsddb version failed"
|
||||
|
||||
def __check_python_version(self, name, force_python_upgrade=False):
|
||||
"""
|
||||
The 'pickle' format (may) change with each Python version, see
|
||||
http://docs.python.org/3.2/library/pickle.html#pickle. Code commits
|
||||
21777 and 21778 ensure that when going from python2 to python3, the old
|
||||
format can be read. However, once the data has been written in the
|
||||
python3 format, it will not be possible to go back to pyton2. This check
|
||||
test whether we are changing python versions. If going from 2 to 3 it
|
||||
warns the user, and allows it if he confirms. When going from 3 to 3, an
|
||||
error is raised. Because code for python2 did not write the Python
|
||||
version file, if the file is absent, python2 is assumed.
|
||||
"""
|
||||
current_python_version = version_info[0]
|
||||
versionpath = os.path.join(self.path, "pythonversion.txt")
|
||||
if os.path.isfile(versionpath):
|
||||
with open(versionpath, "r") as version_file:
|
||||
db_python_version = int(version_file.read().strip())
|
||||
else:
|
||||
db_python_version = 2
|
||||
|
||||
if db_python_version == 3 and current_python_version == 2:
|
||||
clear_lock_file(name)
|
||||
raise exceptions.PythonDowngradeError(db_python_version,
|
||||
current_python_version)
|
||||
elif db_python_version == 2 and current_python_version > 2:
|
||||
if not force_python_upgrade:
|
||||
_LOG.debug("Python upgrade required from %s to %s" %
|
||||
(db_python_version, current_python_version))
|
||||
clear_lock_file(name)
|
||||
raise exceptions.PythonUpgradeRequiredError(db_python_version,
|
||||
current_python_version)
|
||||
# Try to do an upgrade
|
||||
if not self.readonly:
|
||||
_LOG.warning("Python upgrade requested from %s to %s" %
|
||||
(db_python_version, current_python_version))
|
||||
self.update_python_version = True
|
||||
# Make a backup of the database files anyway
|
||||
self.__make_zip_backup(name)
|
||||
elif db_python_version == 2 and current_python_version == 2:
|
||||
pass
|
||||
|
||||
@catch_db_error
|
||||
def version_supported(self):
|
||||
dbversion = self.metadata.get('version', default=0)
|
||||
return ((dbversion <= _DBVERSION) and (dbversion >= _MINVERSION))
|
||||
|
||||
@catch_db_error
|
||||
def need_upgrade(self):
|
||||
def need_schema_upgrade(self):
|
||||
dbversion = self.metadata.get('version', default=0)
|
||||
return not self.readonly and dbversion < _DBVERSION
|
||||
|
||||
@@ -410,7 +527,9 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
|
||||
return False
|
||||
|
||||
@catch_db_error
|
||||
def load(self, name, callback, mode=DBMODE_W, upgrade=False):
|
||||
def load(self, name, callback, mode=DBMODE_W, force_schema_upgrade=False,
|
||||
force_bsddb_upgrade=False, force_bsddb_downgrade=False,
|
||||
force_python_upgrade=False):
|
||||
|
||||
if self.__check_readonly(name):
|
||||
mode = DBMODE_R
|
||||
@@ -430,7 +549,14 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
|
||||
self.path = self.full_name
|
||||
self.brief_name = os.path.basename(name)
|
||||
|
||||
self.__check_bdb_version(name)
|
||||
# If we re-enter load with force_python_upgrade True, then we have
|
||||
# already checked the bsddb version, and then checked python version,
|
||||
# and are agreeing on the upgrade
|
||||
if not force_python_upgrade:
|
||||
self.__check_bdb_version(name, force_bsddb_upgrade,
|
||||
force_bsddb_downgrade)
|
||||
|
||||
self.__check_python_version(name, force_python_upgrade)
|
||||
|
||||
# Set up database environment
|
||||
self.env = db.DBEnv()
|
||||
@@ -452,8 +578,8 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
|
||||
|
||||
# The DB_PRIVATE flag must go if we ever move to multi-user setup
|
||||
env_flags = db.DB_CREATE | db.DB_PRIVATE |\
|
||||
db.DB_INIT_MPOOL | db.DB_INIT_LOCK |\
|
||||
db.DB_INIT_LOG | db.DB_INIT_TXN | db.DB_THREAD
|
||||
db.DB_INIT_MPOOL |\
|
||||
db.DB_INIT_LOG | db.DB_INIT_TXN
|
||||
|
||||
# As opposed to before, we always try recovery on databases
|
||||
env_flags |= db.DB_RECOVER
|
||||
@@ -482,8 +608,9 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
|
||||
# If we cannot work with this DB version,
|
||||
# it makes no sense to go further
|
||||
if not self.version_supported():
|
||||
tree_vers = self.metadata.get(b'version', default=0)
|
||||
self.__close_early()
|
||||
raise DbVersionError()
|
||||
raise DbVersionError(tree_vers, _MINVERSION, _DBVERSION)
|
||||
|
||||
self.__load_metadata()
|
||||
gstats = self.metadata.get('gender_stats', default=None)
|
||||
@@ -530,17 +657,36 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
|
||||
self.name_group = self.__open_db(self.full_name, NAME_GROUP,
|
||||
db.DB_HASH, db.DB_DUP)
|
||||
|
||||
# We have now successfully opened the database, so if the BSDDB version
|
||||
# has changed, we update the DBSDB version file.
|
||||
|
||||
if self.update_env_version:
|
||||
versionpath = os.path.join(name, BDBVERSFN)
|
||||
with open(versionpath, "w") as version_file:
|
||||
version_file.write(str(db.version()))
|
||||
_LOG.debug("Updated BDBVERSFN file to %s" % str(db.version()))
|
||||
|
||||
if self.update_python_version:
|
||||
versionpath = os.path.join(name, "pythonversion.txt")
|
||||
with open(versionpath, "w") as version_file:
|
||||
version_file.write(str(version_info[0]))
|
||||
_LOG.debug("Updated python version file to %s" % str(version_info[0]))
|
||||
|
||||
# Here we take care of any changes in the tables related to new code.
|
||||
# If secondary indices change, then they should removed
|
||||
# or rebuilt by upgrade as well. In any case, the
|
||||
# self.secondary_connected flag should be set accordingly.
|
||||
if self.need_upgrade():
|
||||
if upgrade == True:
|
||||
if self.need_schema_upgrade():
|
||||
oldschema = self.metadata.get('version', default=0)
|
||||
newschema = _DBVERSION
|
||||
_LOG.debug("Schema upgrade required from %s to %s" %
|
||||
(oldschema, newschema))
|
||||
if force_schema_upgrade == True:
|
||||
self.gramps_upgrade(callback)
|
||||
else:
|
||||
self.__close_early()
|
||||
clear_lock_file(name)
|
||||
raise DbUpgradeRequiredError()
|
||||
raise DbUpgradeRequiredError(oldschema, newschema)
|
||||
|
||||
if callback:
|
||||
callback(50)
|
||||
@@ -1073,11 +1219,6 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
|
||||
self.transaction_abort(self.transaction)
|
||||
self.env.txn_checkpoint()
|
||||
|
||||
lockstats = self.env.lock_stat()
|
||||
_LOG.debug("lock occupancy: %d%%, locked object occupancy: %d%%" % (
|
||||
round(lockstats['maxnlocks']*100/lockstats['maxlocks']),
|
||||
round(lockstats['maxnobjects']*100/lockstats['maxobjects'])))
|
||||
|
||||
self.__close_metadata()
|
||||
self.name_group.close()
|
||||
self.surnames.close()
|
||||
@@ -1147,15 +1288,6 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
|
||||
self.undo_history_callback = None
|
||||
self.undodb = None
|
||||
|
||||
if self.update_env_version:
|
||||
versionpath = os.path.join(self.path, BDBVERSFN)
|
||||
try:
|
||||
with open(versionpath, "w") as version_file:
|
||||
version_file.write(str(db.version()))
|
||||
except:
|
||||
# Storing the version of Berkeley Db is not really vital.
|
||||
pass
|
||||
|
||||
try:
|
||||
clear_lock_file(self.get_save_path())
|
||||
except IOError:
|
||||
@@ -1964,8 +2096,8 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
|
||||
|
||||
# The DB_PRIVATE flag must go if we ever move to multi-user setup
|
||||
env_flags = db.DB_CREATE | db.DB_PRIVATE |\
|
||||
db.DB_INIT_MPOOL | db.DB_INIT_LOCK |\
|
||||
db.DB_INIT_LOG | db.DB_INIT_TXN | db.DB_THREAD
|
||||
db.DB_INIT_MPOOL |\
|
||||
db.DB_INIT_LOG | db.DB_INIT_TXN
|
||||
|
||||
# As opposed to before, we always try recovery on databases
|
||||
env_flags |= db.DB_RECOVER
|
||||
@@ -1978,9 +2110,20 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
|
||||
|
||||
self.metadata = self.__open_shelf(full_name, META)
|
||||
|
||||
_LOG.debug("Write schema version %s" % _DBVERSION)
|
||||
with BSDDBTxn(self.env, self.metadata) as txn:
|
||||
txn.put('version', _DBVERSION)
|
||||
|
||||
versionpath = os.path.join(name, BDBVERSFN)
|
||||
_LOG.debug("Write bsddb version %s" % str(db.version()))
|
||||
with open(versionpath, "w") as version_file:
|
||||
version_file.write(str(db.version()))
|
||||
|
||||
versionpath = os.path.join(name, "pythonversion.txt")
|
||||
_LOG.debug("Write python version file to %s" % str(version_info[0]))
|
||||
with open(versionpath, "w") as version_file:
|
||||
version_file.write(str(version_info[0]))
|
||||
|
||||
self.metadata.close()
|
||||
self.env.close()
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ class MediaObject(CitationBase, NoteBase, DateBase, AttributeBase,
|
||||
refer notes.
|
||||
:rtype: list
|
||||
"""
|
||||
return self.attribute_list + self.citation_list
|
||||
return self.attribute_list
|
||||
|
||||
def get_referenced_handles(self):
|
||||
"""
|
||||
|
||||
@@ -390,7 +390,8 @@ class Person(CitationBase, NoteBase, AttributeBase, MediaBase,
|
||||
self.address_list +
|
||||
self.attribute_list +
|
||||
self.lds_ord_list +
|
||||
self.person_ref_list
|
||||
self.person_ref_list +
|
||||
self.event_ref_list
|
||||
)
|
||||
|
||||
def get_note_child_list(self):
|
||||
|
||||
@@ -365,7 +365,7 @@ class Gramplet(object):
|
||||
"""
|
||||
import gobject
|
||||
self._pause = True
|
||||
if self._idle_id == 0:
|
||||
if self._idle_id != 0:
|
||||
gobject.source_remove(self._idle_id)
|
||||
self._idle_id = 0
|
||||
|
||||
|
||||
@@ -78,9 +78,9 @@ _PAGEDIR = [ { 'name' : _("Bottom, left"), 'value' :"BL" },
|
||||
{ 'name' : _("Left, bottom"), 'value' :"LB" },
|
||||
{ 'name' : _("Left, top"), 'value' :"LT" } ]
|
||||
|
||||
_RATIO = [ { 'name' : _("Minimal size"), 'value': "compress" },
|
||||
{ 'name' : _("Fill the given area"), 'value': "fill" },
|
||||
{ 'name' : _("Use optimal number of pages"), 'value': "expand" } ]
|
||||
_RATIO = [ { 'name' : _("Compress to minimal size"), 'value': "compress" },
|
||||
{ 'name' : _("Fill the given area"), 'value': "fill" },
|
||||
{ 'name' : _("Expand uniformly"), 'value': "expand" } ]
|
||||
|
||||
_NOTELOC = [ { 'name' : _("Top"), 'value' : "t" },
|
||||
{ 'name' : _("Bottom"), 'value' : "b" }]
|
||||
@@ -116,6 +116,7 @@ class GVOptions():
|
||||
self.h_pages = None
|
||||
self.v_pages = None
|
||||
self.page_dir = None
|
||||
self.dpi = None
|
||||
|
||||
def add_menu_options(self, menu):
|
||||
"""
|
||||
@@ -191,16 +192,29 @@ class GVOptions():
|
||||
aspect_ratio = EnumeratedListOption(_("Aspect ratio"), "fill")
|
||||
for item in _RATIO:
|
||||
aspect_ratio.add_item(item["value"], item["name"])
|
||||
aspect_ratio.set_help(_("Affects greatly how the graph is layed out "
|
||||
"on the page."))
|
||||
help_text = _('Affects node spacing and scaling of the graph.\n'
|
||||
'If the graph is smaller than the print area:\n'
|
||||
' Compress will not change the node spacing. \n'
|
||||
' Fill will increase the node spacing to fit the print area in '
|
||||
'both width and height.\n'
|
||||
' Expand will increase the node spacing uniformly to preserve '
|
||||
'the aspect ratio.\n'
|
||||
'If the graph is larger than the print area:\n'
|
||||
' Compress will shrink the graph to achieve tight packing at the '
|
||||
'expense of symmetry.\n'
|
||||
' Fill will shrink the graph to fit the print area after first '
|
||||
'increasing the node spacing.\n'
|
||||
' Expand will shrink the graph uniformly to fit the print area.')
|
||||
aspect_ratio.set_help(help_text)
|
||||
menu.add_option(category, "ratio", aspect_ratio)
|
||||
|
||||
dpi = NumberOption(_("DPI"), 75, 20, 1200)
|
||||
dpi.set_help(_( "Dots per inch. When creating images such as "
|
||||
".gif or .png files for the web, try numbers "
|
||||
"such as 100 or 300 DPI. When creating PostScript "
|
||||
"or PDF files, use 72 DPI."))
|
||||
"such as 100 or 300 DPI. PostScript and PDF files "
|
||||
"always use 72 DPI."))
|
||||
menu.add_option(category, "dpi", dpi)
|
||||
self.dpi = dpi
|
||||
|
||||
nodesep = NumberOption(_("Node spacing"), 0.20, 0.01, 5.00, 0.01)
|
||||
nodesep.set_help(_( "The minimum amount of free space, in inches, "
|
||||
|
||||
@@ -31,6 +31,13 @@ Option class representing an enumerated list of possible values.
|
||||
#-------------------------------------------------------------------------
|
||||
from gen.plug.menu import Option
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# set up logging
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import logging
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# EnumeratedListOption class
|
||||
@@ -113,5 +120,5 @@ class EnumeratedListOption(Option):
|
||||
if value in (v for v, d in self.__items):
|
||||
Option.set_value(self, value)
|
||||
else:
|
||||
print "Value '%s' not found for option '%s'" % (str(value),
|
||||
self.get_label())
|
||||
logging.warning(_("Value '%(val)s' not found for option '%(opt)s'") %
|
||||
{'val' : str(value), 'opt' : self.get_label()})
|
||||
|
||||
@@ -109,7 +109,8 @@ class Bibliography(object):
|
||||
MODE_PAGE = 2**1
|
||||
MODE_CONF = 2**2
|
||||
MODE_NOTE = 2**3
|
||||
MODE_ALL = MODE_DATE | MODE_PAGE | MODE_CONF | MODE_NOTE
|
||||
MODE_MEDIA = 2**4
|
||||
MODE_ALL = MODE_DATE | MODE_PAGE | MODE_CONF | MODE_NOTE | MODE_MEDIA
|
||||
|
||||
def __init__(self, mode=MODE_ALL):
|
||||
"""
|
||||
@@ -123,6 +124,7 @@ class Bibliography(object):
|
||||
MODE_PAGE
|
||||
MODE_CONF
|
||||
MODE_NOTE
|
||||
MODE_MEDIA
|
||||
MODE_ALL
|
||||
|
||||
If you only care about pages, set "mode=MODE_PAGE".
|
||||
@@ -218,6 +220,9 @@ class Bibliography(object):
|
||||
if ( self.mode & self.MODE_NOTE ) == self.MODE_NOTE:
|
||||
if len(source_ref.get_note_list()) != 0:
|
||||
return True
|
||||
if ( self.mode & self.MODE_MEDIA ) == self.MODE_MEDIA:
|
||||
if len(source_ref.get_media_list()) != 0:
|
||||
return True
|
||||
# Can't find anything interesting.
|
||||
return False
|
||||
|
||||
@@ -258,5 +263,13 @@ class Bibliography(object):
|
||||
for notehandle in nl1:
|
||||
if notehandle not in nl2:
|
||||
return False
|
||||
if ( self.mode & self.MODE_MEDIA ) == self.MODE_MEDIA:
|
||||
nl1 = source_ref1.get_media_list()
|
||||
nl2 = source_ref2.get_media_list()
|
||||
if len(nl1) != len(nl2):
|
||||
return False
|
||||
for mediahandle in nl1:
|
||||
if mediahandle not in nl2:
|
||||
return False
|
||||
# Can't find anything different. They must be equal.
|
||||
return True
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# Copyright (C) 2004-2007 Donald N. Allingham
|
||||
# Copyright (C) 2008,2011 Gary Burton
|
||||
# Copyright (C) 2010 Jakim Friant
|
||||
# Copyright (C) 2011 Paul Franklin
|
||||
# Copyright (C) 2011-2013 Paul Franklin
|
||||
#
|
||||
# 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
|
||||
@@ -83,6 +83,7 @@ class OptionList(_options.OptionList):
|
||||
self.margins = [2.54, 2.54, 2.54, 2.54]
|
||||
self.format_name = None
|
||||
self.css_filename = None
|
||||
self.output = None
|
||||
|
||||
def set_style_name(self, style_name):
|
||||
"""
|
||||
@@ -234,6 +235,22 @@ class OptionList(_options.OptionList):
|
||||
"""
|
||||
return self.format_name
|
||||
|
||||
def set_output(self, output):
|
||||
"""
|
||||
Set the output for the OptionList.
|
||||
@param output: name of the output to set.
|
||||
@type output: str
|
||||
"""
|
||||
self.output = output
|
||||
|
||||
def get_output(self):
|
||||
"""
|
||||
Return the output of the OptionList.
|
||||
@returns: returns the output name
|
||||
@rtype: str
|
||||
"""
|
||||
return self.output
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Collection of option lists
|
||||
@@ -445,6 +462,9 @@ class OptionListCollection(_options.OptionListCollection):
|
||||
if option_list.get_style_name():
|
||||
f.write(' <style name="%s"/>\n' %
|
||||
escxml(option_list.get_style_name()) )
|
||||
if option_list.get_output():
|
||||
f.write(' <output name="%s"/>\n' %
|
||||
escxml(os.path.basename(option_list.get_output())) )
|
||||
|
||||
def parse(self):
|
||||
"""
|
||||
@@ -529,6 +549,9 @@ class OptionParser(_options.OptionParser):
|
||||
self.collection.set_last_margin(pos, value)
|
||||
else:
|
||||
self.option_list.set_margin(pos, value)
|
||||
elif tag == 'output':
|
||||
if not self.common:
|
||||
self.option_list.set_output(attrs['name'])
|
||||
else:
|
||||
# Tag is not report-specific, so we let the base class handle it.
|
||||
_options.OptionParser.startElement(self, tag, attrs)
|
||||
@@ -615,6 +638,8 @@ class OptionHandler(_options.OptionHandler):
|
||||
self.paper_name = self.saved_option_list.get_paper_name()
|
||||
if self.saved_option_list.get_format_name():
|
||||
self.format_name = self.saved_option_list.get_format_name()
|
||||
if self.saved_option_list.get_output():
|
||||
self.output = self.saved_option_list.get_output()
|
||||
|
||||
def save_options(self):
|
||||
"""
|
||||
@@ -636,6 +661,7 @@ class OptionHandler(_options.OptionHandler):
|
||||
def save_common_options(self):
|
||||
# First we save common options
|
||||
self.saved_option_list.set_style_name(self.style_name)
|
||||
self.saved_option_list.set_output(self.output)
|
||||
self.saved_option_list.set_orientation(self.orientation)
|
||||
self.saved_option_list.set_custom_paper_size(self.custom_paper_size)
|
||||
self.saved_option_list.set_margins(self.margins)
|
||||
|
||||
+106
-7
@@ -139,9 +139,22 @@ class FilterProxyDb(ProxyDbBase):
|
||||
If no such Source exists, None is returned.
|
||||
"""
|
||||
source = self.db.get_source_from_handle(handle)
|
||||
# Filter notes out
|
||||
|
||||
self.sanitize_notebase(source)
|
||||
if source:
|
||||
# Filter notes out
|
||||
self.sanitize_notebase(source)
|
||||
|
||||
media_ref_list = source.get_media_list()
|
||||
for media_ref in media_ref_list:
|
||||
self.sanitize_notebase(media_ref)
|
||||
attributes = media_ref.get_attribute_list()
|
||||
for attribute in attributes:
|
||||
self.sanitize_notebase(attribute)
|
||||
|
||||
repo_ref_list = source.get_reporef_list()
|
||||
for repo_ref in repo_ref_list:
|
||||
self.sanitize_notebase(repo_ref)
|
||||
|
||||
return source
|
||||
|
||||
def get_citation_from_handle(self, handle):
|
||||
@@ -151,7 +164,6 @@ class FilterProxyDb(ProxyDbBase):
|
||||
"""
|
||||
citation = self.db.get_citation_from_handle(handle)
|
||||
# Filter notes out
|
||||
|
||||
self.sanitize_notebase(citation)
|
||||
return citation
|
||||
|
||||
@@ -161,8 +173,15 @@ class FilterProxyDb(ProxyDbBase):
|
||||
If no such Object exists, None is returned.
|
||||
"""
|
||||
media = self.db.get_object_from_handle(handle)
|
||||
# Filter notes out
|
||||
self.sanitize_notebase(media)
|
||||
|
||||
if media:
|
||||
# Filter notes out
|
||||
self.sanitize_notebase(media)
|
||||
|
||||
attributes = media.get_attribute_list()
|
||||
for attr in attributes:
|
||||
self.sanitize_notebase(attr)
|
||||
|
||||
return media
|
||||
|
||||
def get_place_from_handle(self, handle):
|
||||
@@ -171,8 +190,18 @@ class FilterProxyDb(ProxyDbBase):
|
||||
If no such Place exists, None is returned.
|
||||
"""
|
||||
place = self.db.get_place_from_handle(handle)
|
||||
# Filter notes out
|
||||
self.sanitize_notebase(place)
|
||||
|
||||
if place:
|
||||
# Filter notes out
|
||||
self.sanitize_notebase(place)
|
||||
|
||||
media_ref_list = place.get_media_list()
|
||||
for media_ref in media_ref_list:
|
||||
self.sanitize_notebase(media_ref)
|
||||
attributes = media_ref.get_attribute_list()
|
||||
for attribute in attributes:
|
||||
self.sanitize_notebase(attribute)
|
||||
|
||||
return place
|
||||
|
||||
def get_event_from_handle(self, handle):
|
||||
@@ -212,7 +241,33 @@ class FilterProxyDb(ProxyDbBase):
|
||||
family.set_child_ref_list(clist)
|
||||
|
||||
# Filter notes out
|
||||
for cref in clist:
|
||||
self.sanitize_notebase(cref)
|
||||
|
||||
self.sanitize_notebase(family)
|
||||
|
||||
attributes = family.get_attribute_list()
|
||||
for attr in attributes:
|
||||
self.sanitize_notebase(attr)
|
||||
|
||||
event_ref_list = family.get_event_ref_list()
|
||||
for event_ref in event_ref_list:
|
||||
self.sanitize_notebase(event_ref)
|
||||
attributes = event_ref.get_attribute_list()
|
||||
for attribute in attributes:
|
||||
self.sanitize_notebase(attribute)
|
||||
|
||||
media_ref_list = family.get_media_list()
|
||||
for media_ref in media_ref_list:
|
||||
self.sanitize_notebase(media_ref)
|
||||
attributes = media_ref.get_attribute_list()
|
||||
for attribute in attributes:
|
||||
self.sanitize_notebase(attribute)
|
||||
|
||||
lds_ord_list = family.get_lds_ord_list()
|
||||
for lds_ord in lds_ord_list:
|
||||
self.sanitize_notebase(lds_ord)
|
||||
|
||||
return family
|
||||
else:
|
||||
return None
|
||||
@@ -246,6 +301,8 @@ class FilterProxyDb(ProxyDbBase):
|
||||
person = self.db.get_person_from_gramps_id(val)
|
||||
if person:
|
||||
return self.get_person_from_handle(person.get_handle())
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_family_from_gramps_id(self, val):
|
||||
"""
|
||||
@@ -255,6 +312,8 @@ class FilterProxyDb(ProxyDbBase):
|
||||
family = self.db.get_family_from_gramps_id(val)
|
||||
if family:
|
||||
return self.get_family_from_handle(family.get_handle())
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_event_from_gramps_id(self, val):
|
||||
"""
|
||||
@@ -264,6 +323,8 @@ class FilterProxyDb(ProxyDbBase):
|
||||
event = self.db.get_event_from_gramps_id(val)
|
||||
if event:
|
||||
return self.get_event_from_handle(event.get_handle())
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_place_from_gramps_id(self, val):
|
||||
"""
|
||||
@@ -273,6 +334,8 @@ class FilterProxyDb(ProxyDbBase):
|
||||
place = self.db.get_place_from_gramps_id(val)
|
||||
if place:
|
||||
return self.get_place_from_handle(place.get_handle())
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_source_from_gramps_id(self, val):
|
||||
"""
|
||||
@@ -282,6 +345,8 @@ class FilterProxyDb(ProxyDbBase):
|
||||
source = self.db.get_source_from_gramps_id(val)
|
||||
if source:
|
||||
return self.get_source_from_handle(source.get_handle())
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_citation_from_gramps_id(self, val):
|
||||
"""
|
||||
@@ -291,6 +356,8 @@ class FilterProxyDb(ProxyDbBase):
|
||||
citation = self.db.get_citation_from_gramps_id(val)
|
||||
if citation:
|
||||
return self.get_citation_from_handle(citation.get_handle())
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_object_from_gramps_id(self, val):
|
||||
"""
|
||||
@@ -300,6 +367,8 @@ class FilterProxyDb(ProxyDbBase):
|
||||
media = self.db.get_object_from_gramps_id(val)
|
||||
if media:
|
||||
return self.get_object_from_handle(media.get_handle())
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_repository_from_gramps_id(self, val):
|
||||
"""
|
||||
@@ -309,6 +378,8 @@ class FilterProxyDb(ProxyDbBase):
|
||||
repository = self.db.get_repository_from_gramps_id(val)
|
||||
if repository:
|
||||
return self.get_repository_from_handle(repository.get_handle())
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_note_from_gramps_id(self, val):
|
||||
"""
|
||||
@@ -318,6 +389,8 @@ class FilterProxyDb(ProxyDbBase):
|
||||
note = self.db.get_note_from_gramps_id(val)
|
||||
if note:
|
||||
return self.get_note_from_handle(note.get_handle())
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_person_handles(self, sort_handles=False):
|
||||
"""
|
||||
@@ -500,3 +573,29 @@ class FilterProxyDb(ProxyDbBase):
|
||||
self.sanitize_notebase(name)
|
||||
|
||||
self.sanitize_addressbase(person)
|
||||
|
||||
attributes = person.get_attribute_list()
|
||||
for attr in attributes:
|
||||
self.sanitize_notebase(attr)
|
||||
|
||||
event_ref_list = person.get_event_ref_list()
|
||||
for event_ref in event_ref_list:
|
||||
self.sanitize_notebase(event_ref)
|
||||
attributes = event_ref.get_attribute_list()
|
||||
for attribute in attributes:
|
||||
self.sanitize_notebase(attribute)
|
||||
|
||||
media_ref_list = person.get_media_list()
|
||||
for media_ref in media_ref_list:
|
||||
self.sanitize_notebase(media_ref)
|
||||
attributes = media_ref.get_attribute_list()
|
||||
for attribute in attributes:
|
||||
self.sanitize_notebase(attribute)
|
||||
|
||||
lds_ord_list = person.get_lds_ord_list()
|
||||
for lds_ord in lds_ord_list:
|
||||
self.sanitize_notebase(lds_ord)
|
||||
|
||||
person_ref_list = person.get_person_ref_list()
|
||||
for person_ref in person_ref_list:
|
||||
self.sanitize_notebase(person_ref)
|
||||
|
||||
@@ -232,9 +232,10 @@ class ReferencedBySelectionProxyDb(ProxyDbBase):
|
||||
self.process_attributes(event)
|
||||
|
||||
place_handle = event.get_place_handle()
|
||||
place = self.db.get_place_from_handle(place_handle)
|
||||
if place:
|
||||
self.process_place(place)
|
||||
if place_handle:
|
||||
place = self.db.get_place_from_handle(place_handle)
|
||||
if place:
|
||||
self.process_place(place)
|
||||
|
||||
def process_place(self, place):
|
||||
"""
|
||||
@@ -307,22 +308,29 @@ class ReferencedBySelectionProxyDb(ProxyDbBase):
|
||||
self.process_attributes(media)
|
||||
self.process_notes(media)
|
||||
|
||||
def process_notes(self, original_obj):
|
||||
def process_note(self, note):
|
||||
"""
|
||||
Follow the note object and find all of the primary objects
|
||||
that it references.
|
||||
"""
|
||||
if note is None or note.handle in self.referenced["Note"]:
|
||||
return
|
||||
self.referenced["Note"].add(note.handle)
|
||||
for tag in note.text.get_tags():
|
||||
if tag.name == 'Link':
|
||||
if tag.value.startswith("gramps://"):
|
||||
obj_class, prop, value = tag.value[9:].split("/")
|
||||
if obj_class == "Media": # bug6493
|
||||
obj_class = "MediaObject"
|
||||
if prop == "handle":
|
||||
self.process_object(obj_class, value)
|
||||
|
||||
def process_notes(self, original_obj):
|
||||
""" Find all of the primary objects referred to """
|
||||
for note_handle in original_obj.get_note_list():
|
||||
if note_handle and note_handle not in self.referenced["Note"]:
|
||||
if note_handle:
|
||||
note = self.db.get_note_from_handle(note_handle)
|
||||
if note:
|
||||
self.referenced["Note"].add(note_handle)
|
||||
for tag in note.text.get_tags():
|
||||
if tag.name == 'Link':
|
||||
if tag.value.startswith("gramps://"):
|
||||
obj_class, prop, value = tag.value[9:].split("/")
|
||||
if prop == "handle":
|
||||
self.process_object(obj_class, value)
|
||||
self.process_note(note)
|
||||
|
||||
# --------------------------------------------
|
||||
|
||||
@@ -396,9 +404,10 @@ class ReferencedBySelectionProxyDb(ProxyDbBase):
|
||||
self.process_family(fam)
|
||||
|
||||
place_handle = lds_ord.get_place_handle()
|
||||
place = self.db.get_place_from_handle(place_handle)
|
||||
if place:
|
||||
self.process_place(place)
|
||||
if place_handle:
|
||||
place = self.db.get_place_from_handle(place_handle)
|
||||
if place:
|
||||
self.process_place(place)
|
||||
|
||||
self.process_citation_ref_list(lds_ord)
|
||||
self.process_notes(lds_ord)
|
||||
|
||||
@@ -48,6 +48,7 @@ SOURCEKEY = 'source'
|
||||
CITATIONKEY = 'citation'
|
||||
REPOKEY = 'repository'
|
||||
NOTEKEY = 'note'
|
||||
TAGKEY = 'tag'
|
||||
|
||||
ADD = '-add'
|
||||
UPDATE = '-update'
|
||||
@@ -55,7 +56,7 @@ DELETE = '-delete'
|
||||
REBUILD = '-rebuild'
|
||||
|
||||
KEYS = [PERSONKEY, FAMILYKEY, EVENTKEY, PLACEKEY, MEDIAKEY, SOURCEKEY,
|
||||
CITATIONKEY, REPOKEY, NOTEKEY]
|
||||
CITATIONKEY, REPOKEY, NOTEKEY, TAGKEY]
|
||||
|
||||
METHODS = [ADD, UPDATE, DELETE, REBUILD]
|
||||
METHODS_LIST = [ADD, UPDATE, DELETE]
|
||||
@@ -70,6 +71,7 @@ SOURCECLASS = 'Source'
|
||||
CITATIONCLASS = 'Citation'
|
||||
REPOCLASS = 'Repository'
|
||||
NOTECLASS = 'Note'
|
||||
TAGCLASS = 'Tag'
|
||||
|
||||
CLASS2KEY = {
|
||||
PERSONCLASS: PERSONKEY,
|
||||
@@ -80,7 +82,8 @@ CLASS2KEY = {
|
||||
SOURCECLASS: SOURCEKEY,
|
||||
CITATIONCLASS: CITATIONKEY,
|
||||
REPOCLASS: REPOKEY,
|
||||
NOTECLASS: NOTEKEY
|
||||
NOTECLASS: NOTEKEY,
|
||||
TAGCLASS: TAGKEY
|
||||
}
|
||||
|
||||
def _return(*args):
|
||||
@@ -123,6 +126,7 @@ class CallbackManager(object):
|
||||
CITATIONKEY: [],
|
||||
REPOKEY: [],
|
||||
NOTEKEY: [],
|
||||
TAGKEY: [],
|
||||
}
|
||||
#no custom callbacks to do
|
||||
self.custom_signal_keys = []
|
||||
@@ -206,6 +210,7 @@ class CallbackManager(object):
|
||||
CITATIONKEY: [],
|
||||
REPOKEY: [],
|
||||
NOTEKEY: [],
|
||||
TAGKEY: [],
|
||||
}
|
||||
|
||||
def register_callbacks(self, callbackdict):
|
||||
@@ -343,6 +348,7 @@ def directhandledict(baseobj):
|
||||
CITATIONKEY: [],
|
||||
REPOKEY: [],
|
||||
NOTEKEY: [],
|
||||
TAGKEY: [],
|
||||
}
|
||||
for classn, handle in baseobj.get_referenced_handles():
|
||||
handles[CLASS2KEY[classn]].append(handle)
|
||||
@@ -363,6 +369,7 @@ def handledict(baseobj):
|
||||
CITATIONKEY: [],
|
||||
REPOKEY: [],
|
||||
NOTEKEY: [],
|
||||
TAGKEY: [],
|
||||
}
|
||||
for classn, handle in baseobj.get_referenced_handles_recursively():
|
||||
handles[CLASS2KEY[classn]].append(handle)
|
||||
|
||||
@@ -290,6 +290,12 @@ class ConfigManager(object):
|
||||
####################### Now, let's test and set:
|
||||
if (name in self.default and
|
||||
setting in self.default[name]):
|
||||
if isinstance(self.default[name][setting], bool):
|
||||
#make sure 0 and 1 are False and True
|
||||
if value == 0:
|
||||
value = False
|
||||
elif value == 1:
|
||||
value = True
|
||||
if self.check_type(self.default[name][setting], value):
|
||||
self.data[name][setting] = value
|
||||
else:
|
||||
@@ -492,7 +498,7 @@ class ConfigManager(object):
|
||||
(section, setting))
|
||||
# Check value to see if right type:
|
||||
if self.has_default(key):
|
||||
if not self.check_type(self.get_default(key), value):
|
||||
if not self.check_type(self.get_default(key), value):
|
||||
raise AttributeError("attempting to set '%s' to wrong type "
|
||||
"'%s'; should be '%s'" %
|
||||
(key, type(value),
|
||||
@@ -511,17 +517,17 @@ class ConfigManager(object):
|
||||
|
||||
def check_type(self, value1, value2):
|
||||
"""
|
||||
Check if value1 and value2 are different types.
|
||||
"""
|
||||
type1 = type(value1)
|
||||
Check if value1 and value2 are different types.
|
||||
"""
|
||||
type1 = type(value1)
|
||||
type2 = type(value2)
|
||||
if type1 == type2:
|
||||
return True
|
||||
elif (isinstance(value1, basestring) and
|
||||
isinstance(value2, basestring)):
|
||||
elif (isinstance(value1, basestring) and
|
||||
isinstance(value2, basestring)):
|
||||
return True
|
||||
elif (type1 in [int, float, long] and
|
||||
type2 in [int, float, long]):
|
||||
type2 in [int, float, long]):
|
||||
return True
|
||||
else:
|
||||
else:
|
||||
return False
|
||||
|
||||
+3
-1
@@ -62,7 +62,9 @@ import constfunc
|
||||
"""Setup basic logging support."""
|
||||
|
||||
# Setup a formatter
|
||||
form = logging.Formatter(fmt="%(relativeCreated)d: %(levelname)s: %(filename)s: line %(lineno)d: %(message)s")
|
||||
form = logging.Formatter(fmt="%(asctime)s.%(msecs).03d: %(levelname)s: "
|
||||
"%(filename)s: line %(lineno)d: %(message)s",
|
||||
datefmt='%Y-%m-%d %H:%M:%S')
|
||||
|
||||
# Create the log handlers
|
||||
if constfunc.win():
|
||||
|
||||
+46
-8
@@ -219,6 +219,27 @@ class ConfigureDialog(ManagedWindow.ManagedWindow):
|
||||
"""
|
||||
self.__config.set(constant, unicode(obj.get_text()))
|
||||
|
||||
def update_markup_entry(self, obj, constant):
|
||||
"""
|
||||
:param obj: an object with get_text method
|
||||
:param constant: the config setting to which the text value must be
|
||||
saved
|
||||
"""
|
||||
try:
|
||||
obj.get_text() % 'test_markup'
|
||||
except TypeError:
|
||||
print("WARNING: ignoring invalid value for '%s'" % constant)
|
||||
ErrorDialog(_("Invalid or incomplete format definition."),
|
||||
obj.get_text())
|
||||
obj.set_text('<b>%s</b>')
|
||||
except ValueError:
|
||||
print("WARNING: ignoring invalid value for '%s'" % constant)
|
||||
ErrorDialog(_("Invalid or incomplete format definition."),
|
||||
obj.get_text())
|
||||
obj.set_text('<b>%s</b>')
|
||||
|
||||
self.__config.set(constant, unicode(obj.get_text()))
|
||||
|
||||
def update_color(self, obj, constant, color_hex_label):
|
||||
color = obj.get_color()
|
||||
hexval = "#%02x%02x%02x" % (color.red/256,
|
||||
@@ -307,7 +328,7 @@ class ConfigureDialog(ManagedWindow.ManagedWindow):
|
||||
table.attach(hbox, 2, 3, index, index+1, yoptions=0)
|
||||
|
||||
def add_entry(self, table, label, index, constant, callback=None,
|
||||
config=None):
|
||||
config=None, col_attach=0):
|
||||
if not config:
|
||||
config = self.__config
|
||||
if not callback:
|
||||
@@ -316,12 +337,12 @@ class ConfigureDialog(ManagedWindow.ManagedWindow):
|
||||
entry = gtk.Entry()
|
||||
entry.set_text(config.get(constant))
|
||||
entry.connect('changed', callback, constant)
|
||||
table.attach(lwidget, 0, 1, index, index+1, yoptions=0,
|
||||
table.attach(lwidget, col_attach, col_attach+1, index, index+1, yoptions=0,
|
||||
xoptions=gtk.FILL)
|
||||
table.attach(entry, 1, 2, index, index+1, yoptions=0)
|
||||
table.attach(entry, col_attach+1, col_attach+2, index, index+1, yoptions=0)
|
||||
|
||||
def add_pos_int_entry(self, table, label, index, constant, callback=None,
|
||||
config=None, col_attach=1):
|
||||
config=None, col_attach=1, helptext=''):
|
||||
""" entry field for positive integers
|
||||
"""
|
||||
if not config:
|
||||
@@ -329,6 +350,7 @@ class ConfigureDialog(ManagedWindow.ManagedWindow):
|
||||
lwidget = BasicLabel("%s: " % label)
|
||||
entry = gtk.Entry()
|
||||
entry.set_text(str(config.get(constant)))
|
||||
entry.set_tooltip_markup(helptext)
|
||||
if callback:
|
||||
entry.connect('changed', callback, constant)
|
||||
table.attach(lwidget, col_attach, col_attach+1, index, index+1,
|
||||
@@ -1034,12 +1056,26 @@ class GrampsPreferences(ConfigureDialog):
|
||||
6, 'behavior.avg-generation-gap', self.update_int_entry)
|
||||
self.add_pos_int_entry(table,
|
||||
_('Markup for invalid date format'),
|
||||
7, 'preferences.invalid-date-format', self.update_entry)
|
||||
7, 'preferences.invalid-date-format',
|
||||
self.update_markup_entry,
|
||||
helptext = _('Convenience markups are:\n'
|
||||
'<b><b>Bold</b></b>\n'
|
||||
'<big><big>Makes font relatively larger</big></big>\n'
|
||||
'<i><i>Italic</i></i>\n'
|
||||
'<s><s>Strikethrough</s></s>\n'
|
||||
'<sub><sub>Subscript</sub></sub>\n'
|
||||
'<sup><sup>Superscript</sup></sup>\n'
|
||||
'<small><small>Makes font relatively smaller</small></small>\n'
|
||||
'<tt><tt>Monospace font</tt></tt>\n'
|
||||
'<u><u>Underline</u></u>\n\n'
|
||||
'For example: <u><b>%s</b></u>\n'
|
||||
'will display <u><b>Underlined bold date</b></u>\n')
|
||||
)
|
||||
|
||||
return _('Dates'), table
|
||||
|
||||
def add_behavior_panel(self, configdialog):
|
||||
table = gtk.Table(3, 6)
|
||||
table = gtk.Table(2, 8)
|
||||
table.set_border_width(12)
|
||||
table.set_col_spacings(6)
|
||||
table.set_row_spacings(6)
|
||||
@@ -1097,16 +1133,18 @@ class GrampsPreferences(ConfigureDialog):
|
||||
table.attach(lwidget, 1, 2, 7, 8, yoptions=0)
|
||||
table.attach(self.whattype_box, 2, 3, 7, 8, yoptions=0)
|
||||
|
||||
self.add_entry(table, _('Where to check'), 8, 'behavior.addons-url', col_attach=1)
|
||||
|
||||
checkbutton = gtk.CheckButton(
|
||||
_("Do not ask about previously notified addons"))
|
||||
checkbutton.set_active(config.get('behavior.do-not-show-previously-seen-updates'))
|
||||
checkbutton.connect("toggled", self.toggle_hide_previous_addons)
|
||||
|
||||
table.attach(checkbutton, 0, 3, 8, 9, yoptions=0)
|
||||
table.attach(checkbutton, 1, 2, 9, 10, yoptions=0)
|
||||
button = gtk.Button(_("Check now"))
|
||||
button.connect("clicked", lambda obj: \
|
||||
self.uistate.viewmanager.check_for_updates(force=True))
|
||||
table.attach(button, 3, 4, 8, 9, yoptions=0)
|
||||
table.attach(button, 3, 4, 9, 10, yoptions=0)
|
||||
|
||||
return _('General'), table
|
||||
|
||||
|
||||
+72
-12
@@ -295,29 +295,89 @@ class DbLoader(CLIDbLoader):
|
||||
|
||||
self._begin_progress()
|
||||
|
||||
force_schema_upgrade = False
|
||||
force_bsddb_upgrade = False
|
||||
force_bsddb_downgrade = False
|
||||
force_python_upgrade = False
|
||||
try:
|
||||
try:
|
||||
self.dbstate.db.load(filename, self._pulse_progress,
|
||||
mode, upgrade=False)
|
||||
except gen.db.exceptions.DbUpgradeRequiredError, msg:
|
||||
if QuestionDialog2(_("Need to upgrade database!"),
|
||||
str(msg),
|
||||
_("Upgrade now"),
|
||||
_("Cancel")).run():
|
||||
while True:
|
||||
try:
|
||||
self.dbstate.db.load(filename, self._pulse_progress,
|
||||
mode, upgrade=True)
|
||||
mode, force_schema_upgrade,
|
||||
force_bsddb_upgrade,
|
||||
force_bsddb_downgrade,
|
||||
force_python_upgrade)
|
||||
self.dbstate.db.set_save_path(filename)
|
||||
else:
|
||||
self.dbstate.no_database()
|
||||
break
|
||||
except gen.db.exceptions.DbUpgradeRequiredError, msg:
|
||||
if QuestionDialog2(_("Are you sure you want to upgrade "
|
||||
"this Family Tree?"),
|
||||
str(msg),
|
||||
_("I have made a backup,\n"
|
||||
"please upgrade my Family Tree"),
|
||||
_("Cancel"), self.uistate.window).run():
|
||||
force_schema_upgrade = True
|
||||
force_bsddb_upgrade = False
|
||||
force_bsddb_downgrade = False
|
||||
force_python_upgrade = False
|
||||
else:
|
||||
self.dbstate.no_database()
|
||||
break
|
||||
except gen.db.exceptions.BsddbUpgradeRequiredError, msg:
|
||||
if QuestionDialog2(_("Are you sure you want to upgrade "
|
||||
"this Family Tree?"),
|
||||
str(msg),
|
||||
_("I have made a backup,\n"
|
||||
"please upgrade my Family Tree"),
|
||||
_("Cancel"), self.uistate.window).run():
|
||||
force_schema_upgrade = False
|
||||
force_bsddb_upgrade = True
|
||||
force_bsddb_downgrade = False
|
||||
force_python_upgrade = False
|
||||
else:
|
||||
self.dbstate.no_database()
|
||||
break
|
||||
except gen.db.exceptions.BsddbDowngradeRequiredError, msg:
|
||||
if QuestionDialog2(_("Are you sure you want to downgrade "
|
||||
"this Family Tree?"),
|
||||
str(msg),
|
||||
_("I have made a backup,\n"
|
||||
"please downgrade my Family Tree"),
|
||||
_("Cancel"), self.uistate.window).run():
|
||||
force_schema_upgrade = False
|
||||
force_bsddb_upgrade = False
|
||||
force_bsddb_downgrade = True
|
||||
force_python_upgrade = False
|
||||
else:
|
||||
self.dbstate.no_database()
|
||||
break
|
||||
except gen.db.exceptions.PythonUpgradeRequiredError, msg:
|
||||
if QuestionDialog2(_("Are you sure you want to upgrade "
|
||||
"this Family Tree?"),
|
||||
str(msg),
|
||||
_("I have made a backup,\n"
|
||||
"please upgrade my Family Tree"),
|
||||
_("Cancel"), self.uistate.window).run():
|
||||
force_schema_upgrade = False
|
||||
force_bsddb_upgrade = False
|
||||
force_bsddb_downgrade = False
|
||||
force_python_upgrade = True
|
||||
else:
|
||||
self.dbstate.no_database()
|
||||
break
|
||||
# Get here is there is an exception the while loop does not handle
|
||||
except gen.db.exceptions.BsddbDowngradeError, msg:
|
||||
self.dbstate.no_database()
|
||||
self._errordialog( _("Cannot open database"), str(msg))
|
||||
self._warn( _("Cannot open database"), str(msg))
|
||||
except gen.db.exceptions.DbVersionError, msg:
|
||||
self.dbstate.no_database()
|
||||
self._errordialog( _("Cannot open database"), str(msg))
|
||||
except gen.db.exceptions.DbEnvironmentError, msg:
|
||||
self.dbstate.no_database()
|
||||
self._errordialog( _("Cannot open database"), str(msg))
|
||||
except gen.db.exceptions.PythonDowngradeError, msg:
|
||||
self.dbstate.no_database()
|
||||
self._warn( _("Cannot open database"), str(msg))
|
||||
except OSError, msg:
|
||||
self.dbstate.no_database()
|
||||
self._errordialog(
|
||||
|
||||
@@ -172,7 +172,7 @@ class BackRefList(EmbeddedList):
|
||||
"edited, and opening a citation editor "
|
||||
"(which also allows the source "
|
||||
"to be edited), would create ambiguity "
|
||||
"by opening two editor on the same source. "
|
||||
"by opening two editors on the same source. "
|
||||
"\n\n"
|
||||
"To edit the citation, close the source "
|
||||
"editor and open an editor for the citation "
|
||||
|
||||
@@ -610,7 +610,7 @@ class EditPerson(EditPrimary):
|
||||
menu.set_title(_("Media Object"))
|
||||
obj = self.db.get_object_from_handle(photo.get_reference_handle())
|
||||
if obj:
|
||||
gui.utilsadd_menuitem(menu, _("View"), photo,
|
||||
gui.utils.add_menuitem(menu, _("View"), photo,
|
||||
self._popup_view_photo)
|
||||
gui.utils.add_menuitem(menu, _("Edit Object Properties"), photo,
|
||||
self._popup_change_description)
|
||||
|
||||
+28
-4
@@ -482,7 +482,6 @@ class EditRule(ManagedWindow.ManagedWindow):
|
||||
arglist = class_obj.labels
|
||||
vallist = []
|
||||
tlist = []
|
||||
self.page.append((class_obj, vallist, tlist))
|
||||
pos = 0
|
||||
l2 = gtk.Label(class_obj.name)
|
||||
l2.set_alignment(0, 0.5)
|
||||
@@ -557,6 +556,26 @@ class EditRule(ManagedWindow.ManagedWindow):
|
||||
table.attach(l, 1, 2, pos, pos+1, gtk.FILL, 0, 5, 5)
|
||||
table.attach(t, 2, 3, pos, pos+1, gtk.EXPAND|gtk.FILL, 0, 5, 5)
|
||||
pos += 1
|
||||
|
||||
use_regex = None
|
||||
if class_obj.allow_regex:
|
||||
use_regex = gtk.CheckButton(_('Use regular expressions'))
|
||||
tip = _('Interpret the contents of string fields as regular '
|
||||
'expressions.\n'
|
||||
'A decimal point will match any character. '
|
||||
'A question mark will match zero or one occurences '
|
||||
'of the previous character or group. '
|
||||
'An asterisk will match zero or more occurences. '
|
||||
'A plus sign will match one or more occurences. '
|
||||
'Use parentheses to group expressions. '
|
||||
'Specify alternatives using a vertical bar. '
|
||||
'A caret will match the start of a line. '
|
||||
'A dollar sign will match the end of a line.')
|
||||
use_regex.set_tooltip_text(tip)
|
||||
table.attach(use_regex, 2, 3, pos, pos+1, gtk.FILL, 0, 5, 5)
|
||||
|
||||
self.page.append((class_obj, vallist, tlist, use_regex))
|
||||
|
||||
# put the table into a scrollable area:
|
||||
scrolled_win = gtk.ScrolledWindow()
|
||||
scrolled_win.add_with_viewport(table)
|
||||
@@ -612,10 +631,12 @@ class EditRule(ManagedWindow.ManagedWindow):
|
||||
page = self.class2page[self.active_rule.__class__]
|
||||
self.notebook.set_current_page(page)
|
||||
self.display_values(self.active_rule.__class__)
|
||||
(class_obj, vallist, tlist) = self.page[page]
|
||||
(class_obj, vallist, tlist, use_regex) = self.page[page]
|
||||
r = self.active_rule.values()
|
||||
for i in range(0, min(len(tlist), len(r))):
|
||||
tlist[i].set_text(r[i])
|
||||
if class_obj.allow_regex:
|
||||
use_regex.set_active(self.active_rule.use_regex)
|
||||
|
||||
self.selection.connect('changed', self.on_node_selected)
|
||||
self.rname.connect('button-press-event', self._button_press)
|
||||
@@ -699,9 +720,12 @@ class EditRule(ManagedWindow.ManagedWindow):
|
||||
|
||||
try:
|
||||
page = self.notebook.get_current_page()
|
||||
(class_obj, vallist, tlist) = self.page[page]
|
||||
(class_obj, vallist, tlist, use_regex) = self.page[page]
|
||||
value_list = [unicode(sclass.get_text()) for sclass in tlist]
|
||||
new_rule = class_obj(value_list)
|
||||
if class_obj.allow_regex:
|
||||
new_rule = class_obj(value_list, use_regex.get_active())
|
||||
else:
|
||||
new_rule = class_obj(value_list)
|
||||
|
||||
self.update_rule(self.active_rule, new_rule)
|
||||
self.close()
|
||||
|
||||
@@ -126,7 +126,10 @@ class GrampsBar(gtk.Notebook):
|
||||
filename = self.configfile
|
||||
if filename and os.path.exists(filename):
|
||||
cp = ConfigParser.ConfigParser()
|
||||
cp.read(filename)
|
||||
try:
|
||||
cp.read(filename)
|
||||
except:
|
||||
pass
|
||||
for sec in cp.sections():
|
||||
if sec == "Bar Options":
|
||||
if "visible" in cp.options(sec):
|
||||
|
||||
+28
-23
@@ -163,7 +163,7 @@ class GuiStringOption(gtk.Entry):
|
||||
"""
|
||||
This class displays an option that is a simple one-line string.
|
||||
"""
|
||||
def __init__(self, option, dbstate, uistate, track):
|
||||
def __init__(self, option, dbstate, uistate, track, override):
|
||||
"""
|
||||
@param option: The option to display.
|
||||
@type option: gen.plug.menu.StringOption
|
||||
@@ -225,7 +225,7 @@ class GuiColorOption(gtk.ColorButton):
|
||||
"""
|
||||
This class displays an option that allows the selection of a colour.
|
||||
"""
|
||||
def __init__(self, option, dbstate, uistate, track):
|
||||
def __init__(self, option, dbstate, uistate, track, override):
|
||||
self.__option = option
|
||||
value = self.__option.get_value()
|
||||
gtk.ColorButton.__init__( self, gtk.gdk.color_parse(value) )
|
||||
@@ -278,7 +278,7 @@ class GuiNumberOption(gtk.SpinButton):
|
||||
This class displays an option that is a simple number with defined maximum
|
||||
and minimum values.
|
||||
"""
|
||||
def __init__(self, option, dbstate, uistate, track):
|
||||
def __init__(self, option, dbstate, uistate, track, override):
|
||||
self.__option = option
|
||||
|
||||
decimals = 0
|
||||
@@ -350,7 +350,7 @@ class GuiTextOption(gtk.ScrolledWindow):
|
||||
"""
|
||||
This class displays an option that is a multi-line string.
|
||||
"""
|
||||
def __init__(self, option, dbstate, uistate, track):
|
||||
def __init__(self, option, dbstate, uistate, track, override):
|
||||
self.__option = option
|
||||
gtk.ScrolledWindow.__init__(self)
|
||||
self.set_shadow_type(gtk.SHADOW_IN)
|
||||
@@ -433,7 +433,7 @@ class GuiBooleanOption(gtk.CheckButton):
|
||||
"""
|
||||
This class displays an option that is a boolean (True or False).
|
||||
"""
|
||||
def __init__(self, option, dbstate, uistate, track):
|
||||
def __init__(self, option, dbstate, uistate, track, override):
|
||||
self.__option = option
|
||||
gtk.CheckButton.__init__(self, self.__option.get_label())
|
||||
self.set_active(self.__option.get_value())
|
||||
@@ -489,7 +489,7 @@ class GuiEnumeratedListOption(gtk.HBox):
|
||||
This class displays an option that provides a finite number of values.
|
||||
Each possible value is assigned a value and a description.
|
||||
"""
|
||||
def __init__(self, option, dbstate, uistate, track):
|
||||
def __init__(self, option, dbstate, uistate, track, override):
|
||||
gtk.HBox.__init__(self)
|
||||
evtBox = gtk.EventBox()
|
||||
self.__option = option
|
||||
@@ -582,7 +582,7 @@ class GuiPersonOption(gtk.HBox):
|
||||
This class displays an option that allows a person from the
|
||||
database to be selected.
|
||||
"""
|
||||
def __init__(self, option, dbstate, uistate, track):
|
||||
def __init__(self, option, dbstate, uistate, track, override):
|
||||
"""
|
||||
@param option: The option to display.
|
||||
@type option: gen.plug.menu.PersonOption
|
||||
@@ -612,11 +612,12 @@ class GuiPersonOption(gtk.HBox):
|
||||
person_handle = self.__uistate.get_active('Person')
|
||||
person = self.__dbstate.db.get_person_from_handle(person_handle)
|
||||
|
||||
if not person:
|
||||
if override or not person:
|
||||
# Pick up the stored option value if there is one
|
||||
person = self.__db.get_person_from_gramps_id(gid)
|
||||
|
||||
if not person:
|
||||
# If all else fails, get the default person to avoid bad values
|
||||
person = self.__db.get_default_person()
|
||||
|
||||
self.__update_person(person)
|
||||
@@ -703,7 +704,7 @@ class GuiFamilyOption(gtk.HBox):
|
||||
This class displays an option that allows a family from the
|
||||
database to be selected.
|
||||
"""
|
||||
def __init__(self, option, dbstate, uistate, track):
|
||||
def __init__(self, option, dbstate, uistate, track, override):
|
||||
"""
|
||||
@param option: The option to display.
|
||||
@type option: gen.plug.menu.FamilyOption
|
||||
@@ -727,7 +728,7 @@ class GuiFamilyOption(gtk.HBox):
|
||||
self.pack_start(pevt, False)
|
||||
self.pack_end(family_button, False)
|
||||
|
||||
self.__initialize_family()
|
||||
self.__initialize_family(override)
|
||||
|
||||
self.valuekey = self.__option.connect('value-changed', self.__value_changed)
|
||||
|
||||
@@ -737,10 +738,10 @@ class GuiFamilyOption(gtk.HBox):
|
||||
pevt.set_tooltip_text(self.__option.get_help())
|
||||
family_button.set_tooltip_text(_('Select a different family'))
|
||||
|
||||
def __initialize_family(self):
|
||||
def __initialize_family(self, override):
|
||||
"""
|
||||
Find a family to initialize the option with. If there is no saved
|
||||
family option, use the active family. If there ris no active
|
||||
family option, use the active family. If there is no active
|
||||
family, try to find a family that the user is likely interested in.
|
||||
"""
|
||||
family_list = []
|
||||
@@ -749,7 +750,7 @@ class GuiFamilyOption(gtk.HBox):
|
||||
|
||||
# Use the active family if one is selected
|
||||
family = self.__uistate.get_active('Family')
|
||||
if family:
|
||||
if family and not override:
|
||||
family_list = [family]
|
||||
else:
|
||||
# Use the stored option value
|
||||
@@ -886,7 +887,7 @@ class GuiNoteOption(gtk.HBox):
|
||||
This class displays an option that allows a note from the
|
||||
database to be selected.
|
||||
"""
|
||||
def __init__(self, option, dbstate, uistate, track):
|
||||
def __init__(self, option, dbstate, uistate, track, override):
|
||||
"""
|
||||
@param option: The option to display.
|
||||
@type option: gen.plug.menu.NoteOption
|
||||
@@ -990,7 +991,7 @@ class GuiMediaOption(gtk.HBox):
|
||||
This class displays an option that allows a media object from the
|
||||
database to be selected.
|
||||
"""
|
||||
def __init__(self, option, dbstate, uistate, track):
|
||||
def __init__(self, option, dbstate, uistate, track, override):
|
||||
"""
|
||||
@param option: The option to display.
|
||||
@type option: gen.plug.menu.MediaOption
|
||||
@@ -1091,7 +1092,7 @@ class GuiPersonListOption(gtk.HBox):
|
||||
This class displays a widget that allows multiple people from the
|
||||
database to be selected.
|
||||
"""
|
||||
def __init__(self, option, dbstate, uistate, track):
|
||||
def __init__(self, option, dbstate, uistate, track, override):
|
||||
"""
|
||||
@param option: The option to display.
|
||||
@type option: gen.plug.menu.PersonListOption
|
||||
@@ -1268,7 +1269,7 @@ class GuiPlaceListOption(gtk.HBox):
|
||||
This class displays a widget that allows multiple places from the
|
||||
database to be selected.
|
||||
"""
|
||||
def __init__(self, option, dbstate, uistate, track):
|
||||
def __init__(self, option, dbstate, uistate, track, override):
|
||||
"""
|
||||
@param option: The option to display.
|
||||
@type option: gen.plug.menu.PlaceListOption
|
||||
@@ -1412,7 +1413,7 @@ class GuiSurnameColorOption(gtk.HBox):
|
||||
selected from the database, and to assign a colour (not necessarily
|
||||
unique) to each one.
|
||||
"""
|
||||
def __init__(self, option, dbstate, uistate, track):
|
||||
def __init__(self, option, dbstate, uistate, track, override):
|
||||
"""
|
||||
@param option: The option to display.
|
||||
@type option: gen.plug.menu.SurnameColorOption
|
||||
@@ -1603,7 +1604,7 @@ class GuiDestinationOption(gtk.HBox):
|
||||
This class displays an option that allows the user to select a
|
||||
DestinationOption.
|
||||
"""
|
||||
def __init__(self, option, dbstate, uistate, track):
|
||||
def __init__(self, option, dbstate, uistate, track, override):
|
||||
"""
|
||||
@param option: The option to display.
|
||||
@type option: gen.plug.menu.DestinationOption
|
||||
@@ -1732,7 +1733,7 @@ class GuiStyleOption(GuiEnumeratedListOption):
|
||||
"""
|
||||
This class displays a StyleOption.
|
||||
"""
|
||||
def __init__(self, option, dbstate, uistate, track):
|
||||
def __init__(self, option, dbstate, uistate, track, override):
|
||||
"""
|
||||
@param option: The option to display.
|
||||
@type option: gen.plug.menu.StyleOption
|
||||
@@ -1772,7 +1773,7 @@ class GuiBooleanListOption(gtk.HBox):
|
||||
This class displays an option that provides a list of check boxes.
|
||||
Each possible value is assigned a value and a description.
|
||||
"""
|
||||
def __init__(self, option, dbstate, uistate, track):
|
||||
def __init__(self, option, dbstate, uistate, track, override):
|
||||
gtk.HBox.__init__(self)
|
||||
self.__option = option
|
||||
self.__cbutton = []
|
||||
@@ -1884,10 +1885,14 @@ _OPTIONS = (
|
||||
)
|
||||
del menu
|
||||
|
||||
def make_gui_option(option, dbstate, uistate, track):
|
||||
def make_gui_option(option, dbstate, uistate, track, override=False):
|
||||
"""
|
||||
Stand-alone function so that Options can be used in other
|
||||
ways, too. Takes an Option and returns a GuiOption.
|
||||
|
||||
override: if True will override the GuiOption's normal behavior
|
||||
(in a GuiOption-dependant fashion, for instance in a GuiPersonOption
|
||||
it will force the use of the options's value to set the GuiOption)
|
||||
"""
|
||||
|
||||
label, widget = True, None
|
||||
@@ -1904,7 +1909,7 @@ def make_gui_option(option, dbstate, uistate, track):
|
||||
"can't make GuiOption: unknown option type: '%s'" % option)
|
||||
|
||||
if widget:
|
||||
widget = widget(option, dbstate, uistate, track)
|
||||
widget = widget(option, dbstate, uistate, track, override)
|
||||
|
||||
return widget, label
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#
|
||||
# Copyright (C) 2007 Brian G. Matherly
|
||||
# Copyright (C) 2010 Jakim Friant
|
||||
# Copyright (C) 2012-2013 Paul Franklin
|
||||
#
|
||||
# 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
|
||||
@@ -66,6 +67,7 @@ class DocReportDialog(ReportDialog):
|
||||
self.style_name = "default"
|
||||
self.firstpage_added = False
|
||||
self.CSS = PLUGMAN.process_plugin_data('WEBSTUFF')
|
||||
self.dbname = dbstate.db.get_dbname()
|
||||
ReportDialog.__init__(self, dbstate, uistate, option_class,
|
||||
name, trans_name)
|
||||
|
||||
@@ -75,7 +77,7 @@ class DocReportDialog(ReportDialog):
|
||||
|
||||
def init_interface(self):
|
||||
ReportDialog.init_interface(self)
|
||||
self.doc_type_changed(self.format_menu)
|
||||
self.doc_type_changed(self.format_menu, preserve_tab=False)
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@@ -101,7 +103,7 @@ class DocReportDialog(ReportDialog):
|
||||
|
||||
self.options.set_document(self.doc)
|
||||
|
||||
def doc_type_changed(self, obj):
|
||||
def doc_type_changed(self, obj, preserve_tab=True):
|
||||
"""This routine is called when the user selects a new file
|
||||
formats for the report. It adjust the various dialog sections
|
||||
to reflect the appropriate values for the currently selected
|
||||
@@ -117,6 +119,7 @@ class DocReportDialog(ReportDialog):
|
||||
# Is this to be a printed report or an electronic report
|
||||
# (i.e. a set of web pages)
|
||||
|
||||
old_page = self.notebook.get_current_page()
|
||||
if self.firstpage_added:
|
||||
self.notebook.remove_page(0)
|
||||
if docgen_plugin.get_paper_used():
|
||||
@@ -129,6 +132,8 @@ class DocReportDialog(ReportDialog):
|
||||
self.html_label.set_use_markup(True)
|
||||
self.notebook.insert_page(self.html_table, self.html_label, 0)
|
||||
self.html_table.show_all()
|
||||
if preserve_tab:
|
||||
self.notebook.set_current_page(old_page)
|
||||
self.firstpage_added = True
|
||||
|
||||
ext_val = docgen_plugin.get_extension()
|
||||
@@ -174,7 +179,11 @@ class DocReportDialog(ReportDialog):
|
||||
ext = ""
|
||||
else:
|
||||
spath = self.get_default_directory()
|
||||
base = "%s.%s" % (self.raw_name, ext)
|
||||
default_name = self.dbname + "_" + self.raw_name
|
||||
if self.options.get_output():
|
||||
base = os.path.basename(self.options.get_output())
|
||||
else:
|
||||
base = "%s.%s" % (default_name, ext)
|
||||
spath = os.path.normpath(os.path.join(spath, base))
|
||||
self.target_fileentry.set_filename(spath)
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
# Copyright (C) 2009 Gary Burton
|
||||
# Contribution 2009 by Bob Ham <rah@bash.sh>
|
||||
# Copyright (C) 2010 Jakim Friant
|
||||
# Copyright (C) 2012-2013 Paul Franklin
|
||||
#
|
||||
# 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
|
||||
@@ -115,6 +116,7 @@ class GraphvizReportDialog(ReportDialog):
|
||||
more information."""
|
||||
self.category = CATEGORY_GRAPHVIZ
|
||||
self.__gvoptions = graphdoc.GVOptions()
|
||||
self.dbname = dbstate.db.get_dbname()
|
||||
ReportDialog.__init__(self, dbstate, uistate, opt,
|
||||
name, translated_name)
|
||||
|
||||
@@ -140,6 +142,7 @@ class GraphvizReportDialog(ReportDialog):
|
||||
def init_interface(self):
|
||||
ReportDialog.init_interface(self)
|
||||
self.doc_type_changed(self.format_menu)
|
||||
self.notebook.set_current_page(1) # don't start on "Paper Options"
|
||||
|
||||
def setup_format_frame(self):
|
||||
"""Set up the format frame of the dialog."""
|
||||
@@ -165,7 +168,11 @@ class GraphvizReportDialog(ReportDialog):
|
||||
ext = ""
|
||||
else:
|
||||
spath = self.get_default_directory()
|
||||
base = "%s%s" % (self.raw_name, ext)
|
||||
default_name = self.dbname + "_" + self.raw_name
|
||||
if self.options.get_output():
|
||||
base = os.path.basename(self.options.get_output())
|
||||
else:
|
||||
base = "%s%s" % (default_name, ext)
|
||||
spath = os.path.normpath(os.path.join(spath, base))
|
||||
self.target_fileentry.set_filename(spath)
|
||||
|
||||
@@ -206,6 +213,24 @@ class GraphvizReportDialog(ReportDialog):
|
||||
fname = spath
|
||||
self.target_fileentry.set_filename(fname)
|
||||
|
||||
format_str = obj.get_format_str()
|
||||
if format_str in ['gvpdf', 'gspdf', 'ps']:
|
||||
# Always use 72 DPI for PostScript and PDF files.
|
||||
self.__gvoptions.dpi.set_value(72)
|
||||
self.__gvoptions.dpi.set_available(False)
|
||||
else:
|
||||
self.__gvoptions.dpi.set_available(True)
|
||||
|
||||
if format_str in ['gspdf', 'dot']:
|
||||
# Multiple pages only valid for dot and PDF via GhostsScript.
|
||||
self.__gvoptions.h_pages.set_available(True)
|
||||
self.__gvoptions.v_pages.set_available(True)
|
||||
else:
|
||||
self.__gvoptions.h_pages.set_value(1)
|
||||
self.__gvoptions.v_pages.set_value(1)
|
||||
self.__gvoptions.h_pages.set_available(False)
|
||||
self.__gvoptions.v_pages.set_available(False)
|
||||
|
||||
def make_document(self):
|
||||
"""Create a document of the type requested by the user.
|
||||
"""
|
||||
|
||||
+8
-1
@@ -96,6 +96,10 @@ class CLIDialog:
|
||||
pass
|
||||
def set_size_request(self, width, height):
|
||||
pass
|
||||
def set_transient_for(self, window):
|
||||
pass
|
||||
def set_modal(self, flag):
|
||||
pass
|
||||
def show_all(self):
|
||||
pass
|
||||
def destroy(self):
|
||||
@@ -128,7 +132,7 @@ class ProgressMeter(object):
|
||||
MODE_ACTIVITY = 1
|
||||
|
||||
def __init__(self, title, header='', can_cancel=False,
|
||||
cancel_callback=None, message_area=False):
|
||||
cancel_callback=None, message_area=False, parent=None):
|
||||
"""
|
||||
Specify the title and the current pass header.
|
||||
"""
|
||||
@@ -158,6 +162,9 @@ class ProgressMeter(object):
|
||||
self.__dialog.vbox.set_spacing(10)
|
||||
self.__dialog.vbox.set_border_width(24)
|
||||
self.__dialog.set_size_request(400, 125)
|
||||
if parent:
|
||||
self.__dialog.set_transient_for(parent)
|
||||
self.__dialog.set_modal(True)
|
||||
|
||||
tlbl = gtk.Label('<span size="larger" weight="bold">%s</span>' % title)
|
||||
tlbl.set_use_markup(True)
|
||||
|
||||
+15
-10
@@ -104,7 +104,7 @@ from gen.utils.configmanager import safe_eval
|
||||
#-------------------------------------------------------------------------
|
||||
if constfunc.is_quartz():
|
||||
try:
|
||||
import gtk_osxapplication as QuartzApp
|
||||
import gtkosx_application as QuartzApp
|
||||
_GTKOSXAPPLICATION = True
|
||||
except:
|
||||
_GTKOSXAPPLICATION = False
|
||||
@@ -227,7 +227,6 @@ UIDEFAULT = '''<ui>
|
||||
WIKI_HELP_PAGE_FAQ = '%s_-_FAQ' % const.URL_MANUAL_PAGE
|
||||
WIKI_HELP_PAGE_KEY = '%s_-_Keybindings' % const.URL_MANUAL_PAGE
|
||||
WIKI_HELP_PAGE_MAN = '%s' % const.URL_MANUAL_PAGE
|
||||
ADDONS_URL = "http://gramps-addons.svn.sourceforge.net/viewvc/gramps-addons/branches/gramps34/"
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@@ -301,7 +300,7 @@ class ViewManager(CLIManager):
|
||||
"""
|
||||
CLIManager.__init__(self, dbstate, False)
|
||||
if _GTKOSXAPPLICATION:
|
||||
self.macapp = QuartzApp.OSXApplication()
|
||||
self.macapp = QuartzApp.Application()
|
||||
|
||||
self.view_category_order = view_category_order
|
||||
|
||||
@@ -357,7 +356,7 @@ class ViewManager(CLIManager):
|
||||
elif howoften == 4: # always
|
||||
update = True
|
||||
if update:
|
||||
import urllib, locale
|
||||
import urllib2, locale
|
||||
LOG.debug("Checking for updated addons...")
|
||||
langs = []
|
||||
lang = locale.getlocale()[0] # not None
|
||||
@@ -370,10 +369,10 @@ class ViewManager(CLIManager):
|
||||
# now we have a list of languages to try:
|
||||
fp = None
|
||||
for lang in langs:
|
||||
URL = "%s/listings/addons-%s.txt" % (ADDONS_URL, lang)
|
||||
URL = "%s/listings/addons-%s.txt" % (config.get("behavior.addons-url"), lang)
|
||||
LOG.debug(" trying: %s" % URL)
|
||||
try:
|
||||
fp = urllib.urlopen(URL)
|
||||
fp = urllib2.urlopen(URL, timeout=10) # wait up to 10 seconds
|
||||
except: # some error
|
||||
LOG.debug(" IOError!")
|
||||
fp = None
|
||||
@@ -407,7 +406,7 @@ class ViewManager(CLIManager):
|
||||
plugin_dict["i"] not in config.get('behavior.previously-seen-updates')):
|
||||
addon_update_list.append((_("Updated"),
|
||||
"%s/download/%s" %
|
||||
(ADDONS_URL,
|
||||
(config.get("behavior.addons-url"),
|
||||
plugin_dict["z"]),
|
||||
plugin_dict))
|
||||
else:
|
||||
@@ -419,14 +418,20 @@ class ViewManager(CLIManager):
|
||||
plugin_dict["i"] not in config.get('behavior.previously-seen-updates')):
|
||||
addon_update_list.append((_("New"),
|
||||
"%s/download/%s" %
|
||||
(ADDONS_URL,
|
||||
(config.get("behavior.addons-url"),
|
||||
plugin_dict["z"]),
|
||||
plugin_dict))
|
||||
config.set("behavior.last-check-for-updates",
|
||||
datetime.date.today().strftime("%Y/%m/%d"))
|
||||
count += 1
|
||||
if fp:
|
||||
fp.close()
|
||||
else:
|
||||
from QuestionDialog import OkDialog
|
||||
OkDialog(_("Checking Addons Failed"),
|
||||
_("The addon repository appears to be unavailable. Please try again later."),
|
||||
self.window)
|
||||
if fp:
|
||||
fp.close()
|
||||
return
|
||||
LOG.debug("Done checking!")
|
||||
# List of translated strings used here
|
||||
# Dead code for l10n
|
||||
|
||||
@@ -107,8 +107,8 @@ class FlatNodeMap(object):
|
||||
the path, and a dictionary mapping hndl to index.
|
||||
To obtain index given a path, method real_index() is available
|
||||
|
||||
..Note: If a string sortkey is used, apply conv_unicode_tosrtkey_ongtk
|
||||
on it , so as to have localized sort
|
||||
..Note: conv_unicode_tosrtkey_ongtk is applied to the underlying sort key,
|
||||
so as to have localized sort
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
@@ -381,6 +381,9 @@ class FlatBaseModel(gtk.GenericTreeModel):
|
||||
"""
|
||||
The base class for all flat treeview models.
|
||||
It keeps a FlatNodeMap, and obtains data from database as needed
|
||||
|
||||
..Note: conv_unicode_tosrtkey_ongtk is applied to the underlying sort key,
|
||||
so as to have localized sort
|
||||
"""
|
||||
|
||||
def __init__(self, db, scol=0, order=gtk.SORT_ASCENDING,
|
||||
@@ -399,9 +402,9 @@ class FlatBaseModel(gtk.GenericTreeModel):
|
||||
self.sort_map = [ f for f in sort_map if f[0]]
|
||||
#we need the model col, that corresponds with scol
|
||||
col = self.sort_map[scol][1]
|
||||
self.sort_func = self.smap[col]
|
||||
else:
|
||||
self.sort_func = self.smap[scol]
|
||||
col = scol
|
||||
self.sort_func = lambda x: conv_unicode_tosrtkey_ongtk(self.smap[col](x))
|
||||
self.sort_col = scol
|
||||
self.skip = skip
|
||||
self._in_build = False
|
||||
@@ -505,15 +508,11 @@ class FlatBaseModel(gtk.GenericTreeModel):
|
||||
Return the (sort_key, handle) list of all data that can maximally
|
||||
be shown.
|
||||
This list is sorted ascending, via localized string sort.
|
||||
conv_unicode_tosrtkey_ongtk which uses strxfrm, which is apparently
|
||||
broken in Win ?? --> they should fix base lib, we need strxfrm, fix it
|
||||
in the Utils module.
|
||||
"""
|
||||
# use cursor as a context manager
|
||||
with self.gen_cursor() as cursor:
|
||||
#loop over database and store the sort field, and the handle
|
||||
return sorted((map(conv_unicode_tosrtkey_ongtk,
|
||||
self.sort_func(data)), key) for key, data in cursor)
|
||||
return sorted((self.sort_func(data), key) for key, data in cursor)
|
||||
|
||||
def _rebuild_search(self, ignore=None):
|
||||
""" function called when view must be build, given a search text
|
||||
@@ -582,8 +581,7 @@ class FlatBaseModel(gtk.GenericTreeModel):
|
||||
if self.node_map.get_path(handle) is not None:
|
||||
return # row is already displayed
|
||||
data = self.map(handle)
|
||||
insert_val = (map(conv_unicode_tosrtkey_ongtk, self.sort_func(data)),
|
||||
handle)
|
||||
insert_val = (self.sort_func(data), handle)
|
||||
if not self.search or \
|
||||
(self.search and self.search.match(handle, self.db)):
|
||||
#row needs to be added to the model
|
||||
@@ -616,8 +614,7 @@ class FlatBaseModel(gtk.GenericTreeModel):
|
||||
return # row is not currently displayed
|
||||
self.clear_cache(handle)
|
||||
oldsortkey = self.node_map.get_sortkey(handle)
|
||||
newsortkey = map(conv_unicode_tosrtkey_ongtk, self.sort_func(self.map(
|
||||
handle)))
|
||||
newsortkey = self.sort_func(self.map(handle))
|
||||
if oldsortkey is None or oldsortkey != newsortkey:
|
||||
#or the changed object is not present in the view due to filtering
|
||||
#or the order of the object must change.
|
||||
|
||||
@@ -88,7 +88,7 @@ class Node(object):
|
||||
def __init__(self, ref, parent, sortkey, handle, secondary):
|
||||
self.name = sortkey
|
||||
if sortkey:
|
||||
self.sortkey = map(conv_unicode_tosrtkey_ongtk, sortkey)
|
||||
self.sortkey = conv_unicode_tosrtkey_ongtk(sortkey)
|
||||
else:
|
||||
self.sortkey = None
|
||||
self.ref = ref
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user