update import dialog; skip when mapping not required

This commit is contained in:
Damien Elmes 2012-02-26 07:03:07 +09:00
parent e09bb3573f
commit 562f33635c
3 changed files with 123 additions and 118 deletions

View file

@ -5,34 +5,33 @@ import os, copy, time, sys, re, traceback
from aqt.qt import * from aqt.qt import *
import anki import anki
import anki.importing as importing import anki.importing as importing
from aqt.ui.utils import getOnlyText from aqt.utils import getOnlyText, getFile, showText
from anki.errors import * from anki.errors import *
import aqt.forms import aqt.forms, aqt.modelchooser
from aqt import ui
class ChangeMap(QDialog): class ChangeMap(QDialog):
def __init__(self, parent, model, current): def __init__(self, mw, model, current):
QDialog.__init__(self, parent, Qt.Window) QDialog.__init__(self, mw, Qt.Window)
self.parent = parent self.mw = mw
self.model = model self.model = model
self.dialog = aqt.forms.changemap.Ui_ChangeMap() self.frm = aqt.forms.changemap.Ui_ChangeMap()
self.dialog.setupUi(self) self.frm.setupUi(self)
n = 0 n = 0
setCurrent = False setCurrent = False
for field in self.model.fieldModels: for field in self.model.fieldModels:
item = QListWidgetItem(_("Map to %s") % field.name) item = QListWidgetItem(_("Map to %s") % field.name)
self.dialog.fields.addItem(item) self.frm.fields.addItem(item)
if current and current.name == field.name: if current and current.name == field.name:
setCurrent = True setCurrent = True
self.dialog.fields.setCurrentRow(n) self.frm.fields.setCurrentRow(n)
n += 1 n += 1
self.dialog.fields.addItem(QListWidgetItem(_("Map to Tags"))) self.frm.fields.addItem(QListWidgetItem(_("Map to Tags")))
self.dialog.fields.addItem(QListWidgetItem(_("Discard field"))) self.frm.fields.addItem(QListWidgetItem(_("Discard field")))
if not setCurrent: if not setCurrent:
if current == 0: if current == 0:
self.dialog.fields.setCurrentRow(n) self.frm.fields.setCurrentRow(n)
else: else:
self.dialog.fields.setCurrentRow(n+1) self.frm.fields.setCurrentRow(n+1)
self.field = None self.field = None
def getField(self): def getField(self):
@ -40,28 +39,28 @@ class ChangeMap(QDialog):
return self.field return self.field
def accept(self): def accept(self):
row = self.dialog.fields.currentRow() row = self.frm.fields.currentRow()
if row < len(self.model.fieldModels): if row < len(self.model.fieldModels):
self.field = self.model.fieldModels[row] self.field = self.model.fieldModels[row]
elif row == self.dialog.fields.count() - 1: elif row == self.frm.fields.count() - 1:
self.field = None self.field = None
else: else:
self.field = 0 self.field = 0
QDialog.accept(self) QDialog.accept(self)
class UpdateMap(QDialog): class UpdateMap(QDialog):
def __init__(self, parent, numFields, fieldModels): def __init__(self, mw, numFields, fieldModels):
QDialog.__init__(self, parent, Qt.Window) QDialog.__init__(self, mw, Qt.Window)
self.parent = parent self.mw = mw
self.fieldModels = fieldModels self.fieldModels = fieldModels
self.dialog = aqt.forms.importup.Ui_Dialog() self.frm = aqt.forms.importup.Ui_Dialog()
self.dialog.setupUi(self) self.frm.setupUi(self)
self.connect(self.dialog.buttonBox.button(QDialogButtonBox.Help), self.connect(self.frm.buttonBox.button(QDialogButtonBox.Help),
SIGNAL("clicked()"), self.helpRequested) SIGNAL("clicked()"), self.helpRequested)
for i in range(numFields): for i in range(numFields):
self.dialog.fileField.addItem("Field %d" % (i+1)) self.frm.fileField.addItem("Field %d" % (i+1))
for m in fieldModels: for m in fieldModels:
self.dialog.colField.addItem(m.name) self.frm.colField.addItem(m.name)
self.exec_() self.exec_()
def helpRequested(self): def helpRequested(self):
@ -69,71 +68,52 @@ class UpdateMap(QDialog):
def accept(self): def accept(self):
self.updateKey = ( self.updateKey = (
self.dialog.fileField.currentIndex(), self.frm.fileField.currentIndex(),
self.fieldModels[self.dialog.colField.currentIndex()].id) self.fieldModels[self.frm.colField.currentIndex()].id)
QDialog.accept(self) QDialog.accept(self)
class ImportDialog(QDialog): class ImportDialog(QDialog):
def __init__(self, parent): def __init__(self, mw, importer):
QDialog.__init__(self, parent, Qt.Window) QDialog.__init__(self, mw, Qt.Window)
self.parent = parent self.mw = mw
self.dialog = aqt.forms.importing.Ui_ImportDialog() self.frm = aqt.forms.importing.Ui_ImportDialog()
self.dialog.setupUi(self) self.frm.setupUi(self)
self.connect(self.dialog.buttonBox.button(QDialogButtonBox.Help), self.connect(self.frm.buttonBox.button(QDialogButtonBox.Help),
SIGNAL("clicked()"), self.helpRequested) SIGNAL("clicked()"), self.helpRequested)
self.setupMappingFrame() self.setupMappingFrame()
self.setupOptions() self.setupOptions()
self.getFile()
if self.importer.needMapper:
self.modelChooser.show()
else:
self.modelChooser.hide()
self.frm.groupBox.setShown(False)
self.frm.mappingGroup.setTitle("")
self.frm.autoDetect.setShown(self.importer.needDelimiter)
if not self.file: if not self.file:
return return
self.dialog.groupBox.setTitle(os.path.basename(self.file)) self.frm.groupBox.setTitle(os.path.basename(self.file))
self.maybePreview() self.maybePreview()
self.connect(self.dialog.autoDetect, SIGNAL("clicked()"), self.connect(self.frm.autoDetect, SIGNAL("clicked()"),
self.onDelimiter) self.onDelimiter)
self.updateDelimiterButtonText() self.updateDelimiterButtonText()
self.exec_() self.exec_()
def setupOptions(self): def setupOptions(self):
self.model = self.parent.col.currentModel self.model = self.mw.col.models.current()
self.modelChooser = ui.modelchooser.ModelChooser(self, self.modelChooser = aqt.modelchooser.ModelChooser(
self.parent, self.mw, self.frm.modelArea)
self.parent.col, self.connect(self.frm.importButton, SIGNAL("clicked()"),
self.modelChanged)
self.dialog.modelArea.setLayout(self.modelChooser)
self.connect(self.dialog.importButton, SIGNAL("clicked()"),
self.doImport) self.doImport)
self.connect(self.dialog.updateButton, SIGNAL("clicked()"), self.connect(self.frm.updateButton, SIGNAL("clicked()"),
self.doUpdate) self.doUpdate)
def getFile(self):
key = ";;".join([x[0] for x in importing.Importers])
file = ui.utils.getFile(self.parent, _("Import"), "import", key)
if not file:
self.file = None
return
self.file = unicode(file)
ext = os.path.splitext(self.file)[1]
self.importer = None
for i in importing.Importers:
for mext in re.findall("[( ]?\*\.(.+?)[) ]", i[0]):
if ext == "." + mext:
self.importer = i
break
if not self.importer:
self.importer = importing.Importers[0]
self.importerFunc = self.importer[1]
if self.importerFunc.needMapper:
self.modelChooser.show()
else:
self.modelChooser.hide()
self.dialog.groupBox.setShown(False)
self.dialog.mappingGroup.setTitle("")
self.dialog.autoDetect.setShown(self.importerFunc.needDelimiter)
def maybePreview(self): def maybePreview(self):
if self.file and self.model: if self.file and self.importer.needMapper:
self.dialog.status.setText("") self.frm.status.setText("")
self.showMapping() self.showMapping()
else: else:
self.hideMapping() self.hideMapping()
@ -157,7 +137,7 @@ you can enter it here. Use \\t to represent tab."""),
self.updateDelimiterButtonText() self.updateDelimiterButtonText()
def updateDelimiterButtonText(self): def updateDelimiterButtonText(self):
if not self.importerFunc.needDelimiter: if not self.importer.needDelimiter:
return return
if self.importer.delimiter: if self.importer.delimiter:
d = self.importer.delimiter d = self.importer.delimiter
@ -179,7 +159,7 @@ you can enter it here. Use \\t to represent tab."""),
txt = _("Manual &delimiter: %s") % d txt = _("Manual &delimiter: %s") % d
else: else:
txt = _("Auto-detected &delimiter: %s") % d txt = _("Auto-detected &delimiter: %s") % d
self.dialog.autoDetect.setText(txt) self.frm.autoDetect.setText(txt)
def doUpdate(self): def doUpdate(self):
f = UpdateMap(self, f = UpdateMap(self,
@ -192,76 +172,69 @@ you can enter it here. Use \\t to represent tab."""),
self.doImport(True) self.doImport(True)
def doImport(self, update=False): def doImport(self, update=False):
self.dialog.status.setText(_("Importing...")) self.frm.status.setText(_("Importing..."))
t = time.time() t = time.time()
self.importer.mapping = self.mapping self.importer.mapping = self.mapping
try: try:
n = _("Import") n = _("Import")
self.parent.col.setUndoStart(n) self.mw.col.setUndoStart(n)
try: try:
self.importer.doImport() self.importer.run()
except ImportFormatError, e:
msg = _("Importing failed.\n")
msg += e.data['info']
self.dialog.status.setText(msg)
return
except Exception, e: except Exception, e:
msg = _("Import failed.\n") msg = _("Import failed.\n")
msg += unicode(traceback.format_exc(), "ascii", "replace") msg += unicode(traceback.format_exc(), "ascii", "replace")
self.dialog.status.setText(msg) self.frm.status.setText(msg)
return return
finally: finally:
self.parent.col.finishProgress() self.mw.col.finishProgress()
self.parent.col.setUndoEnd(n) self.mw.col.setUndoEnd(n)
txt = ( txt = (
_("Importing complete. %(num)d notes imported from %(file)s.\n") % _("Importing complete. %(num)d notes imported from %(file)s.\n") %
{"num": self.importer.total, "file": os.path.basename(self.file)}) {"num": self.importer.total, "file": os.path.basename(self.file)})
self.dialog.groupBox.setShown(False) self.frm.groupBox.setShown(False)
self.dialog.buttonBox.button(QDialogButtonBox.Close).setFocus() self.frm.buttonBox.button(QDialogButtonBox.Close).setFocus()
if self.importer.log: if self.importer.log:
txt += _("Log of import:\n") + "\n".join(self.importer.log) txt += _("Log of import:\n") + "\n".join(self.importer.log)
self.dialog.status.setText(txt) self.frm.status.setText(txt)
self.file = None self.file = None
self.maybePreview() self.maybePreview()
self.parent.col.db.flush() self.mw.col.db.flush()
self.parent.reset() self.mw.reset()
self.modelChooser.deinit() self.modelChooser.deinit()
def setupMappingFrame(self): def setupMappingFrame(self):
# qt seems to have a bug with adding/removing from a grid, so we add # qt seems to have a bug with adding/removing from a grid, so we add
# to a separate object and add/remove that instead # to a separate object and add/remove that instead
self.frame = QFrame(self.dialog.mappingArea) self.frame = QFrame(self.frm.mappingArea)
self.dialog.mappingArea.setWidget(self.frame) self.frm.mappingArea.setWidget(self.frame)
self.mapbox = QVBoxLayout(self.frame) self.mapbox = QVBoxLayout(self.frame)
self.mapbox.setContentsMargins(0,0,0,0) self.mapbox.setContentsMargins(0,0,0,0)
self.mapwidget = None self.mapwidget = None
def hideMapping(self): def hideMapping(self):
self.dialog.mappingGroup.hide() self.frm.mappingGroup.hide()
def showMapping(self, keepMapping=False, hook=None): def showMapping(self, keepMapping=False, hook=None):
# first, check that we can read the file # first, check that we can read the file
try: try:
self.importer = self.importerFunc(self.parent.col, self.file) self.importer = self.importer(self.mw.col, self.file)
if hook: if hook:
hook() hook()
if not keepMapping: if not keepMapping:
self.mapping = self.importer.mapping self.mapping = self.importer.mapping
except ImportFormatError, e: except Exception, e:
self.dialog.status.setText( self.frm.status.setText(
_("Unable to read file.\n\n%(info)s") % { _("Unable to read file.\n\n%s") % unicode(
'type': e.data.get('type', ""), traceback.format_exc(), "ascii", "replace"))
'info': e.data.get('info', ""),
})
self.file = None self.file = None
self.maybePreview() self.maybePreview()
return return
self.dialog.mappingGroup.show() self.frm.mappingGroup.show()
if self.importer.fields(): if self.importer.fields():
self.dialog.mappingArea.show() self.frm.mappingArea.show()
else: else:
self.dialog.mappingArea.hide() self.frm.mappingArea.hide()
self.dialog.updateButton.hide() self.frm.updateButton.hide()
return return
# set up the mapping grid # set up the mapping grid
if self.mapwidget: if self.mapwidget:
@ -290,7 +263,7 @@ you can enter it here. Use \\t to represent tab."""),
lambda s=self,n=num: s.changeMappingNum(n)) lambda s=self,n=num: s.changeMappingNum(n))
def changeMappingNum(self, n): def changeMappingNum(self, n):
f = ChangeMap(self.parent, self.model, self.mapping[n]).getField() f = ChangeMap(self.mw, self.model, self.mapping[n]).getField()
try: try:
# make sure we don't have it twice # make sure we don't have it twice
index = self.mapping.index(f) index = self.mapping.index(f)
@ -312,3 +285,41 @@ you can enter it here. Use \\t to represent tab."""),
def helpRequested(self): def helpRequested(self):
openHelp("FileImport") openHelp("FileImport")
def onImport(mw):
filt = ";;".join([x[0] for x in importing.Importers])
file = getFile(mw, _("Import"), None, key="import",
filter=filt)
if not file:
return
file = unicode(file)
ext = os.path.splitext(file)[1]
importer = None
done = False
for i in importing.Importers:
if done:
break
for mext in re.findall("[( ]?\*\.(.+?)[) ]", i[0]):
if ext == "." + mext:
importer = i[1]
done = True
break
if not importer:
# if no matches, assume TSV
importer = importing.Importers[0][1]
importer = importer(mw.col, file)
# need to show import dialog?
if importer.needMapper:
diag = ImportDialog(mw, importer)
self.modelChooser.show()
else:
try:
mw.progress.start(immediate=True)
importer.run()
mw.progress.finish()
except Exception, e:
msg = _("Import failed.\n")
msg += unicode(traceback.format_exc(), "ascii", "replace")
showText(msg)
else:
showText("\n".join(importer.log))

View file

@ -204,7 +204,7 @@ Are you sure?"""):
# maybe sync (will load DB) # maybe sync (will load DB)
self.onSync(auto=True) self.onSync(auto=True)
runHook("profileLoaded") runHook("profileLoaded")
self.onExport() self.onImport()
def unloadProfile(self, browser=True): def unloadProfile(self, browser=True):
if not self.pm.profile: if not self.pm.profile:
@ -704,18 +704,8 @@ Debug info:\n%s""") % traceback.format_exc(), help="DeckErrors")
########################################################################## ##########################################################################
def onImport(self): def onImport(self):
return showInfo("not yet implemented") import aqt.importing
if self.col is None: aqt.importing.onImport(self)
self.onNew(prompt=_("""\
Importing copies cards to the current deck,
and since you have no deck open, we need to
create a new deck first.
Please choose a new deck name:"""))
if not self.col:
return
if self.col.path:
aqt.importing.ImportDialog(self)
def onExport(self): def onExport(self):
import aqt.exporting import aqt.exporting

View file

@ -227,7 +227,7 @@ def getFile(parent, title, cb, filter="*.*", dir=None, key=None):
d.setDirectory(dir) d.setDirectory(dir)
d.setWindowTitle(title) d.setWindowTitle(title)
d.setNameFilter(filter) d.setNameFilter(filter)
d.show() ret = []
def accept(): def accept():
# work around an osx crash # work around an osx crash
aqt.mw.app.processEvents() aqt.mw.app.processEvents()
@ -235,8 +235,12 @@ def getFile(parent, title, cb, filter="*.*", dir=None, key=None):
if dirkey: if dirkey:
dir = os.path.dirname(file) dir = os.path.dirname(file)
aqt.mw.pm.profile[dirkey] = dir aqt.mw.pm.profile[dirkey] = dir
cb(file) if cb:
cb(file)
ret.append(file)
d.connect(d, SIGNAL("accepted()"), accept) d.connect(d, SIGNAL("accepted()"), accept)
d.exec_()
return ret and ret[0]
def getSaveFile(parent, title, dir, key, ext): def getSaveFile(parent, title, dir, key, ext):
"Ask the user for a file to save. Use DIR as config variable." "Ask the user for a file to save. Use DIR as config variable."