Add possibility to select the dialect of CSV export

You can also select a delimiter from a list
This commit is contained in:
SNoiraud 2021-12-17 13:55:02 +01:00 committed by Nick Hall
parent 0d131a0c5c
commit 3b2d845992
8 changed files with 194 additions and 5 deletions

View File

@ -158,6 +158,9 @@ register('behavior.welcome', 100)
register('behavior.web-search-url', 'http://google.com/#&q=%(text)s')
register('behavior.addons-url', "https://raw.githubusercontent.com/gramps-project/addons/master/gramps52")
register('csv.dialect', 'excel')
register('csv.delimiter', ',')
register('database.backend', 'sqlite')
register('database.compress-backup', True)
register('database.backup-path', USER_HOME)

View File

@ -30,9 +30,14 @@ import csv
# gramps modules
#
#-------------------------------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.gen.config import config
from .tabbeddoc import *
from ...constfunc import win
_ = glocale.translation.gettext
class CSVTab(TabbedDoc):
def __init__(self, columns):
@ -51,7 +56,12 @@ class CSVTab(TabbedDoc):
self.f = open(self.filename, "w", newline='',
encoding='utf_8_sig' if win() else 'utf_8')
self.writer = csv.writer(self.f)
my_dialect = config.get('csv.dialect')
my_delimiter = config.get('csv.delimiter')
if my_dialect == _("Custom"):
self.writer = csv.writer(self.f, delimiter=my_delimiter)
else:
self.writer = csv.writer(self.f, dialect=my_dialect)
def close(self):
assert(self.f)

156
gramps/gui/csvdialect.py Normal file
View File

@ -0,0 +1,156 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2021- 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.
#
# gui/columnorder.py
"""
Handle the csv format when exporting views
"""
# -------------------------------------------------------------------------
#
# python modules
#
# -------------------------------------------------------------------------
import logging
import csv
# -------------------------------------------------------------------------
#
# GTK modules
#
# -------------------------------------------------------------------------
from gi.repository import Gtk
# -------------------------------------------------------------------------
#
# Gramps modules
#
# -------------------------------------------------------------------------
from gramps.gen.config import config
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
# -------------------------------------------------------------------------
#
# set up logging
#
# -------------------------------------------------------------------------
__LOG = logging.getLogger(".CsvDialect")
CSV_DELIMITERS = {
',': ',',
';': ';',
':': ':',
'|': '|',
'\t': _('Tab', 'character'),
}
class CsvDialect(Gtk.Box):
"""
Use a custom format for csv export views
"""
def __init__(self):
"""
Used to set the csv dialect.
We add the possibility to add a custom model where we
can change the delimiter.
"""
Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)
hbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
hbox.set_spacing(10)
hbox.pack_start(Gtk.Label(label=_('Choose your dialect')), False,
False, 0)
comment = Gtk.Label(label=_('Changes are immediate.\n'
'This is used when exporting views'
' in CSV format.'))
comment.set_justify(Gtk.Justification.LEFT)
hbox.pack_start(comment, False, False, 0)
hbox.pack_start(Gtk.Label(label=' '), False, True, 0)
self.pack_start(hbox, True, True, 0)
self.dialect = config.get('csv.dialect')
self.delimiter = config.get('csv.delimiter')
self.dialects = csv.list_dialects()
self.dialects.append(_("Custom"))
self.buttons = []
button = None
self.entry = Gtk.ComboBox()
for dialect in self.dialects:
title = dialect
button = Gtk.RadioButton.new_with_mnemonic_from_widget(button,
title)
button.connect("toggled", self.on_toggled, self.entry)
self.buttons.append(button)
hbox.pack_start(button, False, True, 0)
if dialect == self.dialect:
button.set_active(True)
lwidget = Gtk.Label(label=_("Delimiter:"))
hbox.pack_start(lwidget, False, False, 0)
store = Gtk.ListStore(str, str)
default = 0
for index, (key, value) in enumerate(CSV_DELIMITERS.items()):
store.append((key, value))
if key == self.delimiter:
default = index
self.entry.set_model(store)
cell = Gtk.CellRendererText()
self.entry.pack_start(cell, True)
self.entry.add_attribute(cell, 'text', 1)
self.entry.set_active(default)
self.entry.set_hexpand(False)
self.entry.connect('changed', self.on_changed)
hbox.pack_start(self.entry, False, True, 0)
if self.dialect == _("Custom"):
self.entry.set_sensitive(True)
else:
self.entry.set_sensitive(False)
def on_changed(self, obj):
"""
called when a button state change
save is immediate
"""
sep_iter = obj.get_active_iter()
if sep_iter is not None:
model = obj.get_model()
sep = model[sep_iter][0]
config.set('csv.delimiter', sep)
def on_toggled(self, obj, entry):
"""
called when a button state change
save is immediate
"""
if obj.get_active():
button = obj.get_label()
config.set('csv.dialect', button)
if button == _("Custom"):
entry.set_sensitive(True)
else:
entry.set_sensitive(False)

View File

@ -58,6 +58,7 @@ from .pageview import PageView
from .navigationview import NavigationView
from ..uimanager import ActionGroup
from ..columnorder import ColumnOrder
from ..csvdialect import CsvDialect
from gramps.gen.config import config
from gramps.gen.db import DbTxn
from gramps.gen.errors import WindowActiveError, FilterError, HandleError
@ -1348,4 +1349,6 @@ class ListView(NavigationView):
self.get_column_widths(),
self.set_column_order,
tree=not flat)
return [columnpage]
def csvdialect(configdialog):
return _('CSV Dialect'), CsvDialect()
return [columnpage, csvdialect]

View File

@ -33,7 +33,9 @@ plg = newplugin()
plg.id = 'ex_csv'
plg.name = _("Comma Separated Values Spreadsheet (CSV)")
plg.name_accell = _("Comma _Separated Values Spreadsheet (CSV)")
plg.description = _("CSV is a common spreadsheet format.")
plg.description = _("CSV is a common spreadsheet format."
"\nYou can change this behavior in the 'Configure active"
" view' of any list-based view")
plg.version = '1.0'
plg.gramps_target_version = MODULE_VERSION
plg.status = STABLE

View File

@ -51,6 +51,7 @@ LOG = logging.getLogger(".ExportCSV")
# Gramps modules
#
#-------------------------------------------------------------------------
from gramps.gen.config import config
from gramps.gen.lib import EventType, Person
from gramps.gen.lib.eventroletype import EventRoleType
from gramps.gui.plug.export import WriterOptionBox
@ -256,7 +257,12 @@ class CSVWriter:
self.fp = open(self.filename, "w",
encoding='utf_8_sig' if win() else 'utf_8',
newline='')
self.g = csv.writer(self.fp)
my_dialect = config.get('csv.dialect')
my_delimiter = config.get('csv.delimiter')
if my_dialect == _("Custom"):
self.g = csv.writer(self.fp, delimiter=my_delimiter)
else:
self.g = csv.writer(self.fp, dialect=my_dialect)
except IOError as msg:
msg2 = _("Could not create %s") % self.filename
self.user.notify_error(msg2,str(msg))

View File

@ -269,8 +269,16 @@ class CSVParser:
def read_csv(self, filehandle):
"Read the data from the file and return it as a list."
my_dialect = config.get('csv.dialect')
my_delimiter = config.get('csv.delimiter')
try:
data = [[r.strip() for r in row] for row in csv.reader(filehandle)]
if my_dialect == _("Custom"):
data = [[r.strip() for r in row]
for row in csv.reader(filehandle,
delimiter=my_delimiter)]
else:
data = [[r.strip() for r in row]
for row in csv.reader(filehandle, dialect=my_dialect)]
except csv.Error as err:
self.user.notify_error(_('format error: line %(line)d: %(zero)s') % {
'line' : csv.reader.line_num, 'zero' : err } )

View File

@ -383,6 +383,7 @@ gramps/gui/autocomp.py
gramps/gui/clipboard.py
gramps/gui/columnorder.py
gramps/gui/configure.py
gramps/gui/csvdialect.py
gramps/gui/dbloader.py
gramps/gui/dbman.py
gramps/gui/dialog.py