model changing

This commit is contained in:
Damien Elmes 2011-04-14 01:45:45 +09:00
parent 8865ca6131
commit 139048ad3f
3 changed files with 147 additions and 115 deletions

View file

@ -13,7 +13,7 @@ from anki.utils import fmtTimeSpan, parseTags, hasTag, addTags, delTags, \
ids2str, stripHTMLMedia ids2str, stripHTMLMedia
from aqt.utils import saveGeom, restoreGeom, saveSplitter, restoreSplitter, \ from aqt.utils import saveGeom, restoreGeom, saveSplitter, restoreSplitter, \
saveHeader, restoreHeader, saveState, restoreState, applyStyles, getTag, \ saveHeader, restoreHeader, saveState, restoreState, applyStyles, getTag, \
showInfo showInfo, askUser
from anki.errors import * from anki.errors import *
from anki.db import * from anki.db import *
from anki.hooks import runHook, addHook, removeHook from anki.hooks import runHook, addHook, removeHook
@ -708,6 +708,18 @@ where id in %s""" % ids2str(
"select id from cards where fid in (%s)" % "select id from cards where fid in (%s)" %
",".join([str(s) for s in self.selectedFacts()])) ",".join([str(s) for s in self.selectedFacts()]))
def oneModelFacts(self):
sf = self.selectedFacts()
if not sf:
return
mods = self.deck.db.scalar("""
select count(distinct mid) from facts
where id in %s""" % ids2str(sf))
if mods > 1:
showInfo(_("Please select cards from only one model."))
return
return sf
def resetDeck(self): def resetDeck(self):
"Signal the queue needs rebuilding." "Signal the queue needs rebuilding."
# for operations that change models we'll need to reset immediately, # for operations that change models we'll need to reset immediately,
@ -718,7 +730,14 @@ where id in %s""" % ids2str(
###################################################################### ######################################################################
def genCards(self): def genCards(self):
GenCards(self) fids = self.oneModelFacts()
if fids:
GenCards(self, fids)
def onChangeModel(self):
fids = self.oneModelFacts()
if fids:
ChangeModel(self, fids)
def cram(self): def cram(self):
self.close() self.close()
@ -828,30 +847,6 @@ where id in %s""" % ids2str(
self.deck.setUndoEnd(n) self.deck.setUndoEnd(n)
self.resetDeck() self.resetDeck()
# Model changing
######################################################################
def onChangeModel(self):
sf = self.selectedFacts()
mods = self.deck.db.column0("""
select distinct modelId from facts
where id in %s""" % ids2str(sf))
if not len(mods) == 1:
ui.utils.showInfo(
_("Can only change one model at a time."),
parent=self)
return
d = ChangeModelDialog(self, self.card.fact.model,
self.card.cardModel)
d.exec_()
if d.ret:
n = _("Change Model")
self.deck.setUndoStart(n)
self.deck.changeModel(sf, *d.ret)
self.deck.setUndoEnd(n)
self.onSearch()
self.resetDeck()
# Edit: selection # Edit: selection
###################################################################### ######################################################################
@ -1106,11 +1101,10 @@ select fm.id, fm.name from fieldmodels fm""")
class GenCards(QDialog): class GenCards(QDialog):
def __init__(self, browser): def __init__(self, browser, fids):
self.browser = browser
if not self.canShow():
return
QDialog.__init__(self, browser) QDialog.__init__(self, browser)
self.browser = browser
self.fids = fids
self.form = aqt.forms.addcardmodels.Ui_Dialog() self.form = aqt.forms.addcardmodels.Ui_Dialog()
self.form.setupUi(self) self.form.setupUi(self)
self.connect(self.form.buttonBox, SIGNAL("helpRequested()"), self.connect(self.form.buttonBox, SIGNAL("helpRequested()"),
@ -1118,19 +1112,6 @@ class GenCards(QDialog):
restoreGeom(self, "addCardModels") restoreGeom(self, "addCardModels")
self.getSelection() self.getSelection()
def canShow(self):
b = self.browser
self.fids = b.selectedFacts()
if not self.fids:
return
mods = b.deck.db.scalar("""
select count(distinct mid) from facts
where id in %s""" % ids2str(self.fids))
if mods > 1:
showInfo(_("Please select cards from only one model."))
return
return True
def getSelection(self): def getSelection(self):
# get cards to enable # get cards to enable
f = self.browser.deck.getFact(self.fids[0]) f = self.browser.deck.getFact(self.fids[0])
@ -1146,7 +1127,7 @@ where id in %s""" % ids2str(self.fids))
else: else:
mode = QItemSelectionModel.Deselect mode = QItemSelectionModel.Deselect
self.form.list.selectionModel().select(idx, mode) self.form.list.selectionModel().select(idx, mode)
self.show() self.exec_()
def accept(self): def accept(self):
tplates = [] tplates = []
@ -1176,54 +1157,57 @@ where id in %s""" % ids2str(self.fids))
# Change model dialog # Change model dialog
###################################################################### ######################################################################
class ChangeModelDialog(QDialog): class ChangeModel(QDialog):
def __init__(self, parent, oldModel, oldTemplate): def __init__(self, browser, fids):
QDialog.__init__(self, parent, Qt.Window) QDialog.__init__(self, browser)
self.parent = parent self.browser = browser
self.origModel = self.parent.deck.currentModel self.fids = fids
self.oldModel = oldModel self.oldModel = browser.card.fact().model()
self.oldTemplate = oldTemplate
self.form = aqt.forms.changemodel.Ui_Dialog() self.form = aqt.forms.changemodel.Ui_Dialog()
self.form.setupUi(self) self.form.setupUi(self)
self.setup()
restoreGeom(self, "changeModel")
addHook("reset", self.onReset)
self.exec_()
def setup(self):
# maps # maps
self.fieldMapWidget = None self.flayout = QHBoxLayout()
self.fieldMapLayout = QHBoxLayout() self.flayout.setMargin(0)
self.form.fieldMap.setLayout(self.fieldMapLayout) self.fwidg = None
self.templateMapWidget = None self.form.fieldMap.setLayout(self.flayout)
self.templateMapLayout = QHBoxLayout() self.tlayout = QHBoxLayout()
self.form.templateMap.setLayout(self.templateMapLayout) self.tlayout.setMargin(0)
self.twidg = None
self.form.templateMap.setLayout(self.tlayout)
# model chooser # model chooser
self.parent.deck.currentModel = oldModel import aqt.modelchooser
self.oldCurrentModel = self.browser.deck.conf['currentModelId']
self.browser.deck.conf['currentModelId'] = self.oldModel.id
self.form.oldModelLabel.setText(self.oldModel.name) self.form.oldModelLabel.setText(self.oldModel.name)
self.modelChooser = ui.modelchooser.ModelChooser(self, self.modelChooser = aqt.modelchooser.ModelChooser(
self.parent, self.browser.mw, self.form.modelChooserWidget, cards=False, label=False)
self.parent.deck,
self.modelChanged,
cards=False,
label=False)
self.form.modelChooserWidget.setLayout(self.modelChooser)
self.modelChooser.models.setFocus() self.modelChooser.models.setFocus()
self.connect(self.form.buttonBox, SIGNAL("helpRequested()"), self.connect(self.form.buttonBox, SIGNAL("helpRequested()"),
self.onHelp) self.onHelp)
restoreGeom(self, "changeModel")
self.modelChanged(self.oldModel) self.modelChanged(self.oldModel)
self.ret = None
self.pauseUpdate = False self.pauseUpdate = False
def onReset(self):
self.modelChanged(self.browser.deck.currentModel())
def modelChanged(self, model): def modelChanged(self, model):
self.targetModel = model self.targetModel = model
# just changing template?
self.form.fieldMap.setEnabled(self.targetModel != self.oldModel)
self.rebuildTemplateMap() self.rebuildTemplateMap()
self.rebuildFieldMap() self.rebuildFieldMap()
def rebuildTemplateMap(self, key=None, attr=None): def rebuildTemplateMap(self, key=None, attr=None):
if not key: if not key:
key = "template" key = "t"
attr = "cardModels" attr = "templates"
map = getattr(self, key + "MapWidget") map = getattr(self, key + "widg")
lay = getattr(self, key + "MapLayout") lay = getattr(self, key + "layout")
src = getattr(self.oldModel, attr) src = getattr(self.oldModel, attr)
dst = getattr(self.targetModel, attr) dst = getattr(self.targetModel, attr)
if map: if map:
@ -1233,11 +1217,11 @@ class ChangeModelDialog(QDialog):
map = QWidget() map = QWidget()
l = QGridLayout() l = QGridLayout()
combos = [] combos = []
targets = [x.name for x in dst] + [_("Nothing")] targets = [x['name'] for x in dst] + [_("Nothing")]
qtargets = QStringList(targets) qtargets = QStringList(targets)
indices = {} indices = {}
for i, x in enumerate(src): for i, x in enumerate(src):
l.addWidget(QLabel(_("Change %s to:") % x.name), i, 0) l.addWidget(QLabel(_("Change %s to:") % x['name']), i, 0)
cb = QComboBox() cb = QComboBox()
cb.addItems(qtargets) cb.addItems(qtargets)
idx = min(i, len(targets)-1) idx = min(i, len(targets)-1)
@ -1249,20 +1233,20 @@ class ChangeModelDialog(QDialog):
l.addWidget(cb, i, 1) l.addWidget(cb, i, 1)
map.setLayout(l) map.setLayout(l)
lay.addWidget(map) lay.addWidget(map)
setattr(self, key + "MapWidget", map) setattr(self, key + "widg", map)
setattr(self, key + "MapLayout", lay) setattr(self, key + "layout", lay)
setattr(self, key + "Combos", combos) setattr(self, key + "combos", combos)
setattr(self, key + "Indices", indices) setattr(self, key + "indices", indices)
def rebuildFieldMap(self): def rebuildFieldMap(self):
return self.rebuildTemplateMap(key="field", attr="fieldModels") return self.rebuildTemplateMap(key="f", attr="fields")
def onComboChanged(self, i, cb, key): def onComboChanged(self, i, cb, key):
indices = getattr(self, key + "Indices") indices = getattr(self, key + "indices")
if self.pauseUpdate: if self.pauseUpdate:
indices[cb] = i indices[cb] = i
return return
combos = getattr(self, key + "Combos") combos = getattr(self, key + "combos")
if i == cb.count() - 1: if i == cb.count() - 1:
# set to 'nothing' # set to 'nothing'
return return
@ -1279,55 +1263,56 @@ class ChangeModelDialog(QDialog):
def getTemplateMap(self, old=None, combos=None, new=None): def getTemplateMap(self, old=None, combos=None, new=None):
if not old: if not old:
old = self.oldModel.cardModels old = self.oldModel.templates
combos = self.templateCombos combos = self.tcombos
new = self.targetModel.cardModels new = self.targetModel.templates
map = {} map = {}
for i, f in enumerate(old): for i, f in enumerate(old):
idx = combos[i].currentIndex() idx = combos[i].currentIndex()
if idx == len(new): if idx == len(new):
# ignore # ignore
map[f] = None map[f['ord']] = None
else: else:
f2 = new[idx] f2 = new[idx]
if f2 in map.values(): map[f['ord']] = f2['ord']
return None
map[f] = f2
return map return map
def getFieldMap(self): def getFieldMap(self):
return self.getTemplateMap( return self.getTemplateMap(
old=self.oldModel.fieldModels, old=self.oldModel.fields,
combos=self.fieldCombos, combos=self.fcombos,
new=self.targetModel.fieldModels) new=self.targetModel.fields)
def cleanup(self):
removeHook("reset", self.onReset)
self.oldCurrentModel = self.browser.deck.conf['currentModelId']
self.modelChooser.cleanup()
saveGeom(self, "changeModel")
def reject(self): def reject(self):
self.parent.deck.currentModel = self.origModel self.cleanup()
self.modelChooser.deinit()
return QDialog.reject(self) return QDialog.reject(self)
def accept(self): def accept(self):
saveGeom(self, "changeModel")
self.parent.deck.currentModel = self.origModel
# check maps # check maps
fmap = self.getFieldMap() fmap = self.getFieldMap()
cmap = self.getTemplateMap() cmap = self.getTemplateMap()
if not cmap or (self.targetModel != self.oldModel and if any(True for c in cmap.values() if c is None):
not fmap): if not askUser(_("""\
ui.utils.showInfo( Any cards with templates mapped to nothing will be deleted. \
_("Targets must be unique."), parent=self) If a fact has no remaining cards, it will be lost. \
return Are you sure you want to continue?""")):
if [c for c in cmap.values() if not c]:
if not ui.utils.askUser(_("""\
Any cards with templates mapped to nothing will be deleted.
If a fact has no remaining cards, it will be lost.
Are you sure you want to continue?"""), parent=self):
return return
self.modelChooser.deinit() self.browser.mw.checkpoint(_("Change Model"))
if self.targetModel == self.oldModel: b = self.browser
self.ret = (self.targetModel, None, cmap) b.mw.progress.start()
return QDialog.accept(self) b.model.beginReset()
self.ret = (self.targetModel, fmap, cmap) self.oldModel.changeModel(self.fids, self.targetModel, fmap, cmap)
b.onSearch(reset=False)
b.model.endReset()
b.mw.progress.finish()
b.resetDeck()
self.cleanup()
return QDialog.accept(self) return QDialog.accept(self)
def onHelp(self): def onHelp(self):

View file

@ -444,6 +444,9 @@
<property name="text"> <property name="text">
<string>Change &amp;Model...</string> <string>Change &amp;Model...</string>
</property> </property>
<property name="shortcut">
<string>Ctrl+Shift+M</string>
</property>
</action> </action>
<action name="actionSelectFacts"> <action name="actionSelectFacts">
<property name="text"> <property name="text">

View file

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>294</width> <width>362</width>
<height>331</height> <height>391</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -65,7 +65,7 @@
</layout> </layout>
</item> </item>
<item> <item>
<widget class="QGroupBox" name="templateMap"> <widget class="QGroupBox" name="tgroup">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding"> <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch> <horstretch>0</horstretch>
@ -75,10 +75,32 @@
<property name="title"> <property name="title">
<string>Templates</string> <string>Templates</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="templateMap">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>330</width>
<height>120</height>
</rect>
</property>
</widget>
</widget>
</item>
</layout>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QGroupBox" name="fieldMap"> <widget class="QGroupBox" name="fgroup">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding"> <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch> <horstretch>0</horstretch>
@ -88,6 +110,28 @@
<property name="title"> <property name="title">
<string>Fields</string> <string>Fields</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QScrollArea" name="scrollArea_2">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="fieldMap">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>330</width>
<height>119</height>
</rect>
</property>
</widget>
</widget>
</item>
</layout>
</widget> </widget>
</item> </item>
<item> <item>