Anki/ankiqt/ui/modelproperties.py
2010-11-29 04:56:45 +09:00

296 lines
10 KiB
Python

# Copyright: Damien Elmes <anki@ichi2.net>
# License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys, re
import ankiqt.forms
import anki
from anki.models import FieldModel, CardModel
from ankiqt import ui
tabs = ("General",
"Cards")
class ModelProperties(QDialog):
def __init__(self, parent, deck, model, main=None, onFinish=None):
QDialog.__init__(self, parent, Qt.Window)
if not main:
main = parent
self.parent = main
self.deck = deck
self.origModTime = self.deck.modified
self.m = model
self.needRebuild = False
self.onFinish = onFinish
self.dialog = ankiqt.forms.modelproperties.Ui_ModelProperties()
self.dialog.setupUi(self)
self.connect(self.dialog.buttonBox, SIGNAL("helpRequested()"),
self.helpRequested)
self.readData()
self.setupCards()
self.show()
self.undoName = _("Model Properties")
self.deck.setUndoStart(self.undoName)
self.exec_()
def readData(self):
# properties section
self.dialog.name.setText(self.m.name)
self.dialog.spacing.setText(str(self.m.spacing))
self.dialog.initialSpacing.setText(str(self.m.initialSpacing/60))
self.dialog.mediaURL.setText(unicode(self.m.features))
# Cards
##########################################################################
def setupCards(self):
self.cardOrdinalUpdatedIds = []
self.ignoreCardUpdate = False
self.currentCard = None
self.updateCards()
self.readCurrentCard()
self.connect(self.dialog.cardList, SIGNAL("currentRowChanged(int)"),
self.cardRowChanged)
self.connect(self.dialog.cardAdd, SIGNAL("clicked()"),
self.addCard)
self.connect(self.dialog.cardDelete, SIGNAL("clicked()"),
self.deleteCard)
self.connect(self.dialog.cardToggle, SIGNAL("clicked()"),
self.toggleCard)
self.connect(self.dialog.cardUp, SIGNAL("clicked()"),
self.moveCardUp)
self.connect(self.dialog.cardDown, SIGNAL("clicked()"),
self.moveCardDown)
self.connect(self.dialog.cardRename, SIGNAL("clicked()"),
self.renameCard)
def renameCard(self):
self.needRebuild = True
self.updateCards()
def updateCards(self, row = None):
oldRow = self.dialog.cardList.currentRow()
if oldRow == -1:
oldRow = 0
self.dialog.cardList.clear()
n = 1
for card in self.m.cardModels:
if card.active:
status=""
else:
status=_("; disabled")
label = _("%(name)s: used %(cards)d times%(status)s") % {
'num': n,
'name': card.name,
'status': status,
'cards': self.deck.cardModelUseCount(card),
}
item = QListWidgetItem(label)
self.dialog.cardList.addItem(item)
n += 1
count = self.dialog.cardList.count()
if row != None:
self.dialog.cardList.setCurrentRow(row)
else:
while (count > 0 and oldRow > (count - 1)):
oldRow -= 1
self.dialog.cardList.setCurrentRow(oldRow)
self.enableCardMoveButtons()
def cardRowChanged(self):
if self.ignoreCardUpdate:
return
self.saveCurrentCard()
self.readCurrentCard()
def readCurrentCard(self):
if not len(self.m.cardModels):
self.dialog.cardToggle.setEnabled(False)
self.dialog.cardDelete.setEnabled(False)
self.dialog.cardUp.setEnabled(False)
self.dialog.cardDown.setEnabled(False)
return
else:
self.dialog.cardToggle.setEnabled(True)
self.dialog.cardDelete.setEnabled(True)
self.currentCard = self.m.cardModels[self.dialog.cardList.currentRow()]
card = self.currentCard
self.updateToggleButtonText(card)
def enableCardMoveButtons(self):
row = self.dialog.cardList.currentRow()
if row < 1:
self.dialog.cardUp.setEnabled(False)
else:
self.dialog.cardUp.setEnabled(True)
if row == -1 or row >= (self.dialog.cardList.count() - 1):
self.dialog.cardDown.setEnabled(False)
else:
self.dialog.cardDown.setEnabled(True)
def updateToggleButtonText(self, card):
if card.active:
self.dialog.cardToggle.setText(_("Disa&ble"))
else:
self.dialog.cardToggle.setText(_("Ena&ble"))
def saveCurrentCard(self):
if not self.currentCard:
return
card = self.currentCard
self.ignoreCardUpdate = True
self.updateCards()
self.ignoreCardUpdate = False
def updateField(self, obj, field, value):
if getattr(obj, field) != value:
setattr(obj, field, value)
self.m.setModified()
self.deck.setModified()
return True
return False
def addCard(self):
cards = len(self.m.cardModels)
name = _("Name_%d") % (cards+1)
cm = CardModel(name=name)
self.m.addCardModel(cm)
self.updateCards()
self.dialog.cardList.setCurrentRow(len(self.m.cardModels)-1)
def deleteCard(self):
row = self.dialog.cardList.currentRow()
if row == -1:
return
if len (self.m.cardModels) < 2:
ui.utils.showWarning(
_("Please add a new template first."),
parent=self)
return
card = self.m.cardModels[row]
count = self.deck.cardModelUseCount(card)
if count:
if not ui.utils.askUser(
_("This template is used by %d cards. If you delete it,\n"
"all the cards will be deleted too. If you just\n"
"want to prevent the creation of future cards with\n"
"this template, please use the 'disable' button\n"
"instead.\n\nReally delete these cards?") % count,
parent=self):
return
self.deck.deleteCardModel(self.m, card)
self.updateCards()
def toggleCard(self):
row = self.dialog.cardList.currentRow()
if row == -1:
return
card = self.m.cardModels[row]
active = 0
for c in self.m.cardModels:
if c.active:
active += 1
if active < 2 and card.active:
ui.utils.showWarning(
_("Please enable a different template first."),
parent=self)
return
card.active = not card.active
self.updateToggleButtonText(card)
self.updateCards()
self.m.setModified()
self.deck.setModified()
def moveCardUp(self):
row = self.dialog.cardList.currentRow()
if row == -1:
return
if row == 0:
return
card = self.m.cardModels[row]
tCard = self.m.cardModels[row - 1]
self.m.cardModels.remove(card)
self.m.cardModels.insert(row - 1, card)
if card.id not in self.cardOrdinalUpdatedIds:
self.cardOrdinalUpdatedIds.append(card.id)
if tCard.id not in self.cardOrdinalUpdatedIds:
self.cardOrdinalUpdatedIds.append(tCard.id)
self.ignoreCardUpdate = True
self.updateCards(row - 1)
self.ignoreCardUpdate = False
def moveCardDown(self):
row = self.dialog.cardList.currentRow()
if row == -1:
return
if row == len(self.m.cardModels) - 1:
return
card = self.m.cardModels[row]
tCard = self.m.cardModels[row + 1]
self.m.cardModels.remove(card)
self.m.cardModels.insert(row + 1, card)
if card.id not in self.cardOrdinalUpdatedIds:
self.cardOrdinalUpdatedIds.append(card.id)
if tCard.id not in self.cardOrdinalUpdatedIds:
self.cardOrdinalUpdatedIds.append(tCard.id)
self.ignoreCardUpdate = True
self.updateCards(row + 1)
self.ignoreCardUpdate = False
def helpRequested(self):
idx = self.dialog.tabWidget.currentIndex()
QDesktopServices.openUrl(QUrl(ankiqt.appWiki +
"ModelProperties#" +
tabs[idx]))
# Cleanup
##########################################################################
def reject(self):
"Save user settings on close."
# update properties
self.deck.startProgress()
mname = unicode(self.dialog.name.text())
if not mname:
mname = _("Model")
self.updateField(self.m, 'name', mname)
self.updateField(self.m, 'tags', mname)
url = unicode(self.dialog.mediaURL.text())
if url:
if not re.match("^(http|https|ftp)://", url, re.I):
url = "http://" + url
if not url.endswith("/"):
url += "/"
self.updateField(self.m, 'features', url)
try:
self.updateField(self.m, 'spacing',
float(self.dialog.spacing.text()))
self.updateField(self.m, 'initialSpacing',
float(self.dialog.initialSpacing.text())*60)
except ValueError:
pass
# before field, or it's overwritten
self.saveCurrentCard()
# if changed, reset deck
reset = False
if len(self.cardOrdinalUpdatedIds) > 0:
self.deck.rebuildCardOrdinals(self.cardOrdinalUpdatedIds)
self.m.setModified()
self.deck.setModified()
if self.origModTime != self.deck.modified:
self.deck.updateTagsForModel(self.m)
reset = True
if self.needRebuild:
# need to generate q/a templates
self.deck.updateCardsFromModel(self.m)
reset = True
if reset:
ankiqt.mw.reset()
if self.onFinish:
self.onFinish()
self.deck.setUndoEnd(self.undoName)
# check again
self.deck.finishProgress()
QDialog.reject(self)