Make interface similar to XML import
svn: r17491
This commit is contained in:
parent
1b0ddbed83
commit
7c9e338295
@ -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."""
|
||||||
|
Loading…
Reference in New Issue
Block a user