Make interface similar to XML import

svn: r17491
This commit is contained in:
Michiel Nauta 2011-05-13 20:44:10 +00:00
parent 1b0ddbed83
commit 7c9e338295

View File

@ -61,15 +61,17 @@ from QuestionDialog import ErrorDialog
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
def importData(database, filename, cb_progress=None): def importData(database, filename, cb_progress=None):
"""Function called by Gramps to import data on persons in VCard format.""" """Function called by Gramps to import data on persons in VCard format."""
parser = VCardParser(database, filename) parser = VCardParser(database)
try: try:
return parser.parse_vCard_file() with OpenFileOrStdin(filename) as filehandle:
parser.parse(filehandle)
except EnvironmentError, msg: except EnvironmentError, msg:
ErrorDialog(_("%s could not be opened\n") % filename, str(msg)) ErrorDialog(_("%s could not be opened\n") % filename, str(msg))
return return
except Errors.GrampsImportError, msg: except Errors.GrampsImportError, msg:
ErrorDialog(_("%s could not be opened\n") % filename, str(msg)) ErrorDialog(_("%s could not be opened\n") % filename, str(msg))
return return
return None # This module doesn't provide info about what got imported.
def splitof_nameprefix(name): def splitof_nameprefix(name):
@ -164,7 +166,7 @@ class VCardParser(object):
@staticmethod @staticmethod
def count_escapes(strng): def count_escapes(strng):
"""Count the number of escape characters at the end of a string""" """Count the number of escape characters at the end of a string."""
count = 0 count = 0
for char in reversed(strng): for char in reversed(strng):
if char != VCardParser.ESCAPE_CHAR: if char != VCardParser.ESCAPE_CHAR:
@ -183,104 +185,106 @@ class VCardParser(object):
strng_parts[i] += sep + appendix strng_parts[i] += sep + appendix
return strng_parts return strng_parts
def __init__(self, dbase, filename): def __init__(self, dbase):
self.database = dbase self.database = dbase
self.filename = filename
self.formatted_name = '' self.formatted_name = ''
self.name_parts = '' self.name_parts = ''
self.filehandle = None
self.next_line = None self.next_line = None
self.trans = None self.trans = None
self.version = None self.version = None
self.person = None self.person = None
def get_next_line(self): def __get_next_line(self, filehandle):
""" """
Read and return the line with the next property of the VCard. Read and return the line with the next property of the VCard.
Also if it spans multiple lines (RFC 2425 sec.5.8.1). Also if it spans multiple lines (RFC 2425 sec.5.8.1).
""" """
line = self.next_line line = self.next_line
self.next_line = self.filehandle.readline() self.next_line = filehandle.readline()
while self.next_line and self.next_line[0] in self.LINE_CONTINUATION: while self.next_line and self.next_line[0] in self.LINE_CONTINUATION:
line = line.rstrip("\n") line = line.rstrip("\n")
#TODO perhaps next lines superflous because of rU open parameter? #TODO perhaps next lines superflous because of rU open parameter?
if len(line) > 0 and line[-1] == "\r": if len(line) > 0 and line[-1] == "\r":
line = line[:-1] line = line[:-1]
line += self.next_line[1:] line += self.next_line[1:]
self.next_line = self.filehandle.readline() self.next_line = filehandle.readline()
if line: if line:
line = line.strip() line = line.strip()
else: else:
line = None line = None
return line return line
def parse_vCard_file(self): def parse(self, filehandle):
"""Read each line of the input file and act accordingly.""" """
Prepare the database and parse the input file.
:param filehandle: open file handle positioned at start of the file
"""
tym = time.time() tym = time.time()
self.person = None self.person = None
self.database.disable_signals()
with DbTxn(_("vCard import"), self.database, batch=True) as self.trans: with DbTxn(_("vCard import"), self.database, batch=True) as self.trans:
self.database.disable_signals() self._parse_vCard_file(filehandle)
with OpenFileOrStdin(self.filename) as self.filehandle: self.database.enable_signals()
self.next_line = self.filehandle.readline() self.database.request_rebuild()
while True:
line = self.get_next_line()
if line is None:
break
if line == "":
continue
if line.find(":") == -1:
continue
line_parts = self.name_value_split(line)
if not line_parts:
continue
# No check for escaped ; because only fields[0] is used.
fields = line_parts[0].split(";")
property_name = fields[0].upper()
if property_name == "BEGIN":
self.next_person()
elif property_name == "END":
self.finish_person()
elif property_name == "VERSION":
self.check_version(fields, line_parts[1])
elif property_name == "FN":
self.add_formatted_name(fields, line_parts[1])
elif property_name == "N":
self.add_name_parts(fields, line_parts[1])
elif property_name == "NICKNAME":
self.add_nicknames(fields, line_parts[1])
elif property_name == "SORT-STRING":
self.add_sortas(fields, line_parts[1])
elif property_name == "ADR":
self.add_address(fields, line_parts[1])
elif property_name == "TEL":
self.add_phone(fields, line_parts[1])
elif property_name == "BDAY":
self.add_birthday(fields, line_parts[1])
elif property_name == "ROLE":
self.add_occupation(fields, line_parts[1])
elif property_name == "URL":
self.add_url(fields, line_parts[1])
elif property_name == "EMAIL":
self.add_email(fields, line_parts[1])
elif property_name == "PRODID":
# Included cause VCards made by Gramps have this prop.
pass
else:
LOG.warn("Token >%s< unknown. line skipped: %s" %
(fields[0],line))
self.database.enable_signals()
tym = time.time() - tym tym = time.time() - tym
msg = ngettext('Import Complete: %d second', msg = ngettext('Import Complete: %d second',
'Import Complete: %d seconds', tym ) % tym 'Import Complete: %d seconds', tym ) % tym
LOG.debug(msg) LOG.debug(msg)
self.database.request_rebuild() def _parse_vCard_file(self, filehandle):
return None """Read each line of the input file and act accordingly."""
self.next_line = filehandle.readline()
while True:
line = self.__get_next_line(filehandle)
if line is None:
break
if line == "":
continue
if line.find(":") == -1:
continue
line_parts = self.name_value_split(line)
if not line_parts:
continue
# No check for escaped ; because only fields[0] is used.
fields = line_parts[0].split(";")
property_name = fields[0].upper()
if property_name == "BEGIN":
self.next_person()
elif property_name == "END":
self.finish_person()
elif property_name == "VERSION":
self.check_version(fields, line_parts[1])
elif property_name == "FN":
self.add_formatted_name(fields, line_parts[1])
elif property_name == "N":
self.add_name_parts(fields, line_parts[1])
elif property_name == "NICKNAME":
self.add_nicknames(fields, line_parts[1])
elif property_name == "SORT-STRING":
self.add_sortas(fields, line_parts[1])
elif property_name == "ADR":
self.add_address(fields, line_parts[1])
elif property_name == "TEL":
self.add_phone(fields, line_parts[1])
elif property_name == "BDAY":
self.add_birthday(fields, line_parts[1])
elif property_name == "ROLE":
self.add_occupation(fields, line_parts[1])
elif property_name == "URL":
self.add_url(fields, line_parts[1])
elif property_name == "EMAIL":
self.add_email(fields, line_parts[1])
elif property_name == "PRODID":
# Included cause VCards made by Gramps have this prop.
pass
else:
LOG.warn("Token >%s< unknown. line skipped: %s" %
(fields[0],line))
def finish_person(self): def finish_person(self):
"""All info has been collected, write to database.""" """All info has been collected, write to database."""