New tool to suppress leading and trailing spaces.
This tool is looking for place names with leading or/and trailing spaces. It also looks for in the first name and surname. For each entry which contains leading or trailing spaces, a row is added in a treeview. You can see where the spaces are for each row as the name is underlined. If you double click on the row, you can edit the Place or the Person. Fixes #10824
This commit is contained in:
parent
6bca4083cb
commit
77124496e8
235
gramps/plugins/tool/removespaces.glade
Normal file
235
gramps/plugins/tool/removespaces.glade
Normal file
@ -0,0 +1,235 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.10"/>
|
||||
<object class="GtkDialog" id="removespaces">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="default_width">650</property>
|
||||
<property name="default_height">400</property>
|
||||
<property name="type_hint">dialog</property>
|
||||
<signal name="delete-event" handler="on_delete_event" swapped="no"/>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child internal-child="vbox">
|
||||
<object class="GtkBox" id="dialog-vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child internal-child="action_area">
|
||||
<object class="GtkButtonBox" id="dialog-action_area1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="layout_style">end</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="helpbutton1">
|
||||
<property name="label">gtk-help</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="on_help_clicked" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="close">
|
||||
<property name="label">gtk-close</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="image_position">right</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="destroy_passed_object" swapped="yes"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">6</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="title">
|
||||
<property name="height_request">1</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="double_buffered">False</property>
|
||||
<property name="justify">center</property>
|
||||
<property name="ellipsize">start</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="padding">5</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="vbox2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">2</property>
|
||||
<property name="margin_bottom">2</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">5</property>
|
||||
<property name="homogeneous">True</property>
|
||||
<property name="baseline_position">top</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label_1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">label</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolledwindow1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="treeview_1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection" id="treeview-selection1"/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label_2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">label</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolledwindow2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="treeview_2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection" id="treeview-selection2"/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<action-widgets>
|
||||
<action-widget response="0">close</action-widget>
|
||||
</action-widgets>
|
||||
</object>
|
||||
</interface>
|
315
gramps/plugins/tool/removespaces.py
Normal file
315
gramps/plugins/tool/removespaces.py
Normal file
@ -0,0 +1,315 @@
|
||||
#
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2007-2009 Stephane Charette
|
||||
# Copyright (C) 2019- Serge Noiraud
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
"Find possible leading and/or trailing spaces in places name and people"
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# GNOME/GTK modules
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GObject
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Gramps modules
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
from gramps.gen.const import URL_MANUAL_PAGE
|
||||
from gramps.gui.plug import tool
|
||||
from gramps.gui.editors import (EditPlace, EditPerson)
|
||||
from gramps.gen.errors import WindowActiveError
|
||||
from gramps.gui.managedwindow import ManagedWindow
|
||||
from gramps.gui.utils import ProgressMeter
|
||||
from gramps.gui.display import display_help
|
||||
from gramps.gui.glade import Glade
|
||||
from gramps.gen.const import GRAMPS_LOCALE as glocale
|
||||
_ = glocale.translation.sgettext
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Constants
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
WIKI_HELP_PAGE = '%s_-_Tools' % URL_MANUAL_PAGE
|
||||
WIKI_HELP_SEC = _('manual|Remove_leading_and_trailing_spaces')
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# RemoveSpaces class
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
class RemoveSpaces(ManagedWindow):
|
||||
"""
|
||||
Find leading and trailing spaces in Place names and person names
|
||||
"""
|
||||
def __init__(self, dbstate, user, options_class, name, callback=None):
|
||||
uistate = user.uistate
|
||||
dummy_opt = options_class
|
||||
dummy_nme = name
|
||||
dummy_cb = callback
|
||||
|
||||
self.title = _('Clean input data')
|
||||
ManagedWindow.__init__(self, uistate, [], self.__class__)
|
||||
self.dbstate = dbstate
|
||||
self.uistate = uistate
|
||||
self.db = dbstate.db
|
||||
|
||||
top_dialog = Glade()
|
||||
|
||||
top_dialog.connect_signals({
|
||||
"destroy_passed_object" : self.close,
|
||||
"on_help_clicked" : self.on_help_clicked,
|
||||
"on_delete_event" : self.close,
|
||||
})
|
||||
|
||||
window = top_dialog.toplevel
|
||||
title = top_dialog.get_object("title")
|
||||
self.set_window(window, title, self.title)
|
||||
tip = _('Search leading and/or trailing spaces for persons'
|
||||
' and places. Search comma in coordinates fields.\n'
|
||||
'Double click on a row to edit its content.')
|
||||
title.set_tooltip_text(tip)
|
||||
|
||||
# start the progress indicator
|
||||
self.progress = ProgressMeter(self.title, _('Starting'),
|
||||
parent=uistate.window)
|
||||
steps = self.db.get_number_of_people() + self.db.get_number_of_places()
|
||||
self.progress.set_pass(_('Looking for possible fields with leading or'
|
||||
' trailing spaces'), steps)
|
||||
|
||||
self.model_1 = Gtk.ListStore(
|
||||
GObject.TYPE_STRING, # 0==handle
|
||||
GObject.TYPE_STRING, # 1==firstname
|
||||
GObject.TYPE_STRING, # 2==surname
|
||||
GObject.TYPE_STRING, # 3==alternate name
|
||||
GObject.TYPE_STRING, # 4==group_as
|
||||
)
|
||||
self.model_1.set_sort_column_id(
|
||||
Gtk.TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, 1)
|
||||
|
||||
self.label_1 = top_dialog.get_object("label_1")
|
||||
self.label_1.set_text(_('Person'))
|
||||
self.treeview_1 = top_dialog.get_object("treeview_1")
|
||||
self.treeview_1.set_model(self.model_1)
|
||||
col1 = Gtk.TreeViewColumn(_('handle'),
|
||||
Gtk.CellRendererText(), text=0)
|
||||
renderer1 = Gtk.CellRendererText()
|
||||
renderer1.set_property('underline-set', True)
|
||||
renderer1.set_property('underline', 2) # 2=double underline
|
||||
col2 = Gtk.TreeViewColumn(_('firstname'), renderer1, text=1)
|
||||
renderer2 = Gtk.CellRendererText()
|
||||
renderer2.set_property('underline-set', True)
|
||||
renderer2.set_property('underline', 2) # 2=double underline
|
||||
col3 = Gtk.TreeViewColumn(_('surname'), renderer2, text=2)
|
||||
renderer3 = Gtk.CellRendererText()
|
||||
renderer3.set_property('underline-set', True)
|
||||
renderer3.set_property('underline', 2) # 2=double underline
|
||||
col4 = Gtk.TreeViewColumn(_('alternate name'), renderer3, text=3)
|
||||
renderer4 = Gtk.CellRendererText()
|
||||
renderer4.set_property('underline-set', True)
|
||||
renderer4.set_property('underline', 2) # 2=double underline
|
||||
col5 = Gtk.TreeViewColumn(_('group as'), renderer4, text=4)
|
||||
col1.set_resizable(True)
|
||||
col1.set_visible(False)
|
||||
col2.set_resizable(True)
|
||||
col3.set_resizable(True)
|
||||
col4.set_resizable(True)
|
||||
col5.set_resizable(True)
|
||||
col1.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
|
||||
col2.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
|
||||
col3.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
|
||||
col4.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
|
||||
col5.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
|
||||
self.treeview_1.append_column(col1)
|
||||
self.treeview_1.append_column(col2)
|
||||
self.treeview_1.append_column(col3)
|
||||
self.treeview_1.append_column(col4)
|
||||
self.treeview_1.append_column(col5)
|
||||
self.treeselection = self.treeview_1.get_selection()
|
||||
self.treeview_1.connect('row-activated', self.rowactivated_cb1)
|
||||
|
||||
self.model_2 = Gtk.ListStore(
|
||||
GObject.TYPE_STRING, # 0==handle
|
||||
GObject.TYPE_STRING, # 1==name
|
||||
GObject.TYPE_STRING, # 2==latitude
|
||||
GObject.TYPE_STRING) # 3==longitude
|
||||
self.model_2.set_sort_column_id(
|
||||
Gtk.TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, 1)
|
||||
|
||||
self.label_2 = top_dialog.get_object("label_2")
|
||||
self.label_2.set_text(_('Place'))
|
||||
self.treeview_2 = top_dialog.get_object("treeview_2")
|
||||
self.treeview_2.set_model(self.model_2)
|
||||
col1 = Gtk.TreeViewColumn(_('handle'),
|
||||
Gtk.CellRendererText(), text=0)
|
||||
renderer5 = Gtk.CellRendererText()
|
||||
renderer5.set_property('underline-set', True)
|
||||
renderer5.set_property('underline', 2) # 2=double underline
|
||||
col2 = Gtk.TreeViewColumn(_('name'), renderer5, text=1)
|
||||
renderer6 = Gtk.CellRendererText()
|
||||
renderer6.set_property('underline-set', True)
|
||||
renderer6.set_property('underline', 2) # 2=double underline
|
||||
col3 = Gtk.TreeViewColumn(_('latitude'), renderer6, text=2)
|
||||
renderer7 = Gtk.CellRendererText()
|
||||
renderer7.set_property('underline-set', True)
|
||||
renderer7.set_property('underline', 2) # 2=double underline
|
||||
col4 = Gtk.TreeViewColumn(_('longitude'), renderer7, text=3)
|
||||
col1.set_resizable(True)
|
||||
col1.set_visible(False)
|
||||
col2.set_resizable(True)
|
||||
col3.set_resizable(True)
|
||||
col4.set_resizable(True)
|
||||
col1.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
|
||||
col2.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
|
||||
col3.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
|
||||
col4.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
|
||||
self.treeview_2.append_column(col1)
|
||||
self.treeview_2.append_column(col2)
|
||||
self.treeview_2.append_column(col3)
|
||||
self.treeview_2.append_column(col4)
|
||||
self.treeselection = self.treeview_2.get_selection()
|
||||
self.treeview_2.connect('row-activated', self.rowactivated_cb2)
|
||||
|
||||
self.places()
|
||||
self.people()
|
||||
|
||||
# close the progress bar
|
||||
self.progress.close()
|
||||
|
||||
self.show()
|
||||
|
||||
def places(self):
|
||||
"""
|
||||
For all places in the database, if the name contains leading or
|
||||
trailing spaces.
|
||||
"""
|
||||
for place_handle in self.db.get_place_handles():
|
||||
self.progress.step()
|
||||
place = self.db.get_place_from_handle(place_handle)
|
||||
place_name = place.get_name()
|
||||
pname = place_name.get_value()
|
||||
found = False
|
||||
if pname != pname.strip():
|
||||
found = True
|
||||
plat = place.get_latitude()
|
||||
if plat != plat.strip():
|
||||
found = True
|
||||
if plat.find(',') != -1:
|
||||
found = True
|
||||
plon = place.get_longitude()
|
||||
if plon != plon.strip():
|
||||
found = True
|
||||
if plon.find(',') != -1:
|
||||
found = True
|
||||
if found:
|
||||
value = (place_handle, pname, plat, plon)
|
||||
self.model_2.append(value)
|
||||
return True
|
||||
|
||||
def people(self):
|
||||
"""
|
||||
For all persons in the database, if the name contains leading or
|
||||
trailing spaces. Works for alternate names and group_as.
|
||||
"""
|
||||
for person_handle in self.db.get_person_handles():
|
||||
self.progress.step()
|
||||
person = self.db.get_person_from_handle(person_handle)
|
||||
primary_name = person.get_primary_name()
|
||||
fname = primary_name.get_first_name()
|
||||
found = False
|
||||
if fname != fname.strip():
|
||||
found = True
|
||||
sname = primary_name.get_primary_surname().get_surname()
|
||||
if sname != sname.strip():
|
||||
found = True
|
||||
paname = ""
|
||||
for name in primary_name.get_surname_list():
|
||||
aname = name.get_surname()
|
||||
if aname != sname and aname != aname.strip():
|
||||
found = True
|
||||
if paname != "":
|
||||
paname += ', '
|
||||
paname += aname
|
||||
groupas = primary_name.group_as
|
||||
if groupas != groupas.strip():
|
||||
found = True
|
||||
if found:
|
||||
value = (person_handle, fname, sname, paname, groupas)
|
||||
self.model_1.append(value)
|
||||
return True
|
||||
|
||||
def rowactivated_cb1(self, treeview, path, column):
|
||||
"""
|
||||
Called when a Person row is activated.
|
||||
"""
|
||||
dummy_tv = treeview
|
||||
dummy_col = column
|
||||
iter_ = self.model_1.get_iter(path)
|
||||
handle = self.model_1.get_value(iter_, 0)
|
||||
person = self.dbstate.db.get_person_from_handle(handle)
|
||||
if person:
|
||||
try:
|
||||
EditPerson(self.dbstate, self.uistate, [], person)
|
||||
except WindowActiveError:
|
||||
pass
|
||||
return True
|
||||
return False
|
||||
|
||||
def rowactivated_cb2(self, treeview, path, column):
|
||||
"""
|
||||
Called when a Place row is activated.
|
||||
"""
|
||||
dummy_tv = treeview
|
||||
dummy_col = column
|
||||
iter_ = self.model_2.get_iter(path)
|
||||
handle = self.model_2.get_value(iter_, 0)
|
||||
place = self.dbstate.db.get_place_from_handle(handle)
|
||||
if place:
|
||||
try:
|
||||
EditPlace(self.dbstate, self.uistate, [], place)
|
||||
except WindowActiveError:
|
||||
pass
|
||||
return True
|
||||
return False
|
||||
|
||||
def on_help_clicked(self, _obj):
|
||||
"""
|
||||
Display the relevant portion of Gramps manual.
|
||||
"""
|
||||
display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC)
|
||||
|
||||
def close(self, *obj):
|
||||
ManagedWindow.close(self, *obj)
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# RemoveSpacesOptions
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
class RemoveSpacesOptions(tool.ToolOptions):
|
||||
"""
|
||||
Defines options and provides handling interface.
|
||||
"""
|
||||
def __init__(self, name, person_id=None):
|
||||
""" Initialize the options class """
|
||||
tool.ToolOptions.__init__(self, name, person_id)
|
@ -476,3 +476,28 @@ toolclass = 'FindLoop',
|
||||
optionclass = 'FindLoopOptions',
|
||||
tool_modes = [TOOL_MODE_GUI]
|
||||
)
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Remove leading and trailing spaces for places name
|
||||
# Remove leading and trailing spaces for surname and first names
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
register(TOOL,
|
||||
id = 'removespaces',
|
||||
name = _("Clean input data"),
|
||||
description = _("Searches the entire database, looking for "
|
||||
"trailing or leading spaces for places and people."
|
||||
" Search comma in coordinates fields in places."),
|
||||
version = '1.0',
|
||||
gramps_target_version = MODULE_VERSION,
|
||||
status = STABLE,
|
||||
fname = 'removespaces.py',
|
||||
authors = ["Serge Noiraud"],
|
||||
authors_email = ["serge.noiraud@free.fr"],
|
||||
category = TOOL_UTILS,
|
||||
toolclass = 'RemoveSpaces',
|
||||
optionclass = 'RemoveSpacesOptions',
|
||||
tool_modes = [TOOL_MODE_GUI]
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user