Пример #1
0
 def nextCard(self):
     elapsed = self.mw.col.timeboxReached()
     if elapsed:
         part1 = ngettext("%d card studied in", "%d cards studied in", elapsed[1]) % elapsed[1]
         mins = int(round(elapsed[0]/60))
         part2 = ngettext("%s minute.", "%s minutes.", mins) % mins
         fin = _("Finish")
         diag = askUserDialog("%s %s" % (part1, part2),
                          [_("Continue"), fin])
         diag.setIcon(QMessageBox.Information)
         if diag.run() == fin:
             return self.mw.moveToState("deckBrowser")
         self.mw.col.startTimebox()
     if self.cardQueue:
         # undone/edited cards to show
         c = self.cardQueue.pop()
         c.startTimer()
         self.hadCardQueue = True
     else:
         if self.hadCardQueue:
             # the undone/edited cards may be sitting in the regular queue;
             # need to reset
             self.mw.col.reset()
             self.hadCardQueue = False
         c = self.mw.col.sched.getCard()
     self.card = c
     clearAudioQueue()
     if not c:
         self.mw.moveToState("overview")
         return
     if self._reps is None or self._reps % 100 == 0:
         # we recycle the webview periodically so webkit can free memory
         self._initWeb()
     else:
         self._showQuestion()
Пример #2
0
 def nextCard(self):
     if self.cardQueue:
         # undone/edited cards to show
         c = self.cardQueue.pop()
         c.startTimer()
         self.hadCardQueue = True
     else:
         if self.hadCardQueue:
             # the undone/edited cards may be sitting in the regular queue;
             # need to reset
             self.mw.col.reset()
             self.hadCardQueue = False
         c = self.mw.col.sched.getCard()
     self.card = c
     clearAudioQueue()
     if not c:
         self.mw.moveToState("overview")
         return
     if self._reps is None or self._reps % 100 == 0:
         # we recycle the webview periodically so webkit can free memory
         self._initWeb()
     else:
         self._showQuestion()
     elapsed = self.mw.col.timeboxReached()
     if elapsed:
         part1 = ngettext("%d card studied in", "%d cards studied in", elapsed[1]) % elapsed[1]
         part2 = ngettext("%s minute.", "%s minutes.", elapsed[0]/60) % (elapsed[0]/60)
         tooltip("%s %s" % (part1, part2), period=5000)
         self.mw.col.startTimebox()
Пример #3
0
    def _dueInfo(self, tot, num):
        i = []
        self._line(i, _("Total"), ngettext("%d review", "%d reviews", tot) % tot)
        self._line(i, _("Average"), self._avgDay(
            tot, num, _("reviews")))
        tomorrow = self.col.db.scalar("""
select count() from cards where did in %s and queue in (2,3)
and due = ?""" % self._limit(), self.col.sched.today+1)
        tomorrow = ngettext("%d card", "%d cards", tomorrow) % tomorrow
        self._line(i, _("Due tomorrow"), tomorrow)
        return self._lineTbl(i)
Пример #4
0
    def fixIntegrity(self):
        "Fix possible problems and rebuild caches."
        problems = []
        self.save()
        oldSize = os.stat(self.path)[stat.ST_SIZE]
        if self.db.scalar("pragma integrity_check") != "ok":
            return (_("Collection is corrupt. Please see the manual."), False)
        # note types with a missing model
        ids = self.db.list("""
select id from notes where mid not in """ + ids2str(self.models.ids()))
        if ids:
            print self.db.list("select distinct mid from notes where id in " + ids2str(ids))
            problems.append(
                ngettext("Deleted %d note with missing note type.",
                         "Deleted %d notes with missing note type.", len(ids))
                         % len(ids))
            self.remNotes(ids)
        # delete any notes with missing cards
        ids = self.db.list("""
select id from notes where id not in (select distinct nid from cards)""")
        if ids:
            cnt = len(ids)
            problems.append(
                ngettext("Deleted %d note with no cards.",
                         "Deleted %d notes with no cards.", cnt) % cnt)
            self._remNotes(ids)
        # tags
        self.tags.registerNotes()
        # field cache
        for m in self.models.all():
            self.updateFieldCache(self.models.nids(m))
        # new card position
        self.conf['nextPos'] = self.db.scalar(
            "select max(due)+1 from cards where type = 0") or 0
        # reviews should have a reasonable due #
        ids = self.db.list(
            "select id from cards where queue = 2 and due > 10000")
        if ids:
            problems.append("Reviews had incorrect due date.")
            self.db.execute(
                "update cards set due = 0, mod = ?, usn = ? where id in %s"
                % ids2str(ids), intTime(), self.usn())
        # and finally, optimize
        self.optimize()
        newSize = os.stat(self.path)[stat.ST_SIZE]
        txt = _("Database rebuilt and optimized.")
        ok = not problems
        problems.append(txt)
        self.save()
        return ("\n".join(problems), ok)
Пример #5
0
 def accept(self):
     file = getSaveFile(
         self, _("Export"), "export",
         self.exporter.key, self.exporter.ext)
     self.hide()
     if file:
         self.exporter.includeSched = (
             self.frm.includeSched.isChecked())
         self.exporter.includeMedia = (
             self.frm.includeMedia.isChecked())
         self.exporter.includeTags = (
             self.frm.includeTags.isChecked())
         if not self.frm.deck.currentIndex():
             self.exporter.did = None
         else:
             name = self.decks[self.frm.deck.currentIndex()]
             self.exporter.did = self.col.decks.id(name)
         self.mw.progress.start(immediate=True)
         try:
             f = open(file, "wb")
             f.close()
         except (OSError, IOError), e:
             showWarning(_("Couldn't save file: %s") % unicode(e))
         else:
             os.unlink(file)
             self.exporter.exportInto(file)
             tooltip(ngettext("%d card exported.", "%d cards exported.", \
                             self.exporter.count) % self.exporter.count)
         finally:
Пример #6
0
 def onDelete():
     saveGeom(diag, "emptyCards")
     QDialog.accept(diag)
     self.checkpoint(_("Delete Empty"))
     self.col.remCards(cids)
     tooltip(ngettext("%d card deleted.", "%d cards deleted.", len(cids)) % len(cids))
     self.reset()
Пример #7
0
    def _introductionGraph(self, data, days, title):
        if not data:
            return ""
        d = data
        conf = dict(
            xaxis=dict(tickDecimals=0, max=0.5),
            yaxes=[dict(min=0), dict(position="right",min=0)])
        if days is not None:
            conf['xaxis']['min'] = -days+0.5
        def plot(id, data, ylabel, ylabel2):
            return self._graph(
                id, data=data, conf=conf, ylabel=ylabel, ylabel2=ylabel2)
        # graph
        (repdata, repsum) = self._splitRepData(d, ((1, colLearn, ""),))
        txt = self._title(
            title, _("The number of new cards you have added."))
        txt += plot("intro", repdata, ylabel=_("Cards"), ylabel2=_("Cumulative Cards"))
        # total and per day average
        tot = sum([i[1] for i in d])
        period = self._periodDays()
        if not period:
            # base off date of earliest added card
            period = self._deckAge('add')
        i = []
        self._line(i, _("Total"), ngettext("%d card", "%d cards", tot) % tot)
        self._line(i, _("Average"), self._avgDay(tot, period, _("cards")))
        txt += self._lineTbl(i)

        return txt
Пример #8
0
 def updateTopArea(self):
     cnt = self.mw.col.models.useCount(self.model)
     self.topAreaForm.changesLabel.setText(ngettext(
         "Changes below will affect the %(cnt)d note that uses this card type.",
         "Changes below will affect the %(cnt)d notes that use this card type.",
         cnt) % dict(cnt=cnt))
     self.updateCardNames()
Пример #9
0
def replaceWithApkg(mw, file, backup):
    # unload collection, which will also trigger a backup
    mw.unloadCollection()
    # overwrite collection
    z = zipfile.ZipFile(file)
    try:
        z.extract("collection.anki2", mw.pm.profileFolder())
    except:
        showWarning(_("The provided file is not a valid .apkg file."))
        return
    # because users don't have a backup of media, it's safer to import new
    # data and rely on them running a media db check to get rid of any
    # unwanted media. in the future we might also want to deduplicate this
    # step
    d = os.path.join(mw.pm.profileFolder(), "collection.media")
    for n, (cStr, file) in enumerate(
            json.loads(z.read("media").decode("utf8")).items()):
        mw.progress.update(ngettext("Processed %d media file",
                                    "Processed %d media files", n) % n)
        size = z.getinfo(cStr).file_size
        dest = os.path.join(d, file)
        # if we have a matching file size
        if os.path.exists(dest) and size == os.stat(dest).st_size:
            continue
        data = z.read(cStr)
        open(dest, "wb").write(data)
    z.close()
    # reload
    mw.loadCollection()
    if backup:
        mw.col.modSchema(check=False)
    mw.progress.finish()
Пример #10
0
    def introductionGraph(self):
        start, days, chunk = self.get_start_end_chunk()
        data = self._added(days, chunk)
        if not data:
            return ""
        conf = dict(
            xaxis=dict(tickDecimals=0, max=0.5),
            yaxes=[dict(min=0), dict(position="right", min=0)])
        if days is not None:
            # pylint: disable=invalid-unary-operand-type
            conf['xaxis']['min'] = -days+0.5
        def plot(id, data, ylabel, ylabel2):
            return self._graph(
                id, data=data, conf=conf, xunit=chunk, ylabel=ylabel, ylabel2=ylabel2)
        # graph
        repdata, repsum = self._splitRepData(data, ((1, colLearn, ""),))
        txt = self._title(
            _("Added"), _("The number of new cards you have added."))
        txt += plot("intro", repdata, ylabel=_("Cards"), ylabel2=_("Cumulative Cards"))
        # total and per day average
        tot = sum([i[1] for i in data])
        period = self._periodDays()
        if not period:
            # base off date of earliest added card
            period = self._deckAge('add')
        i = []
        self._line(i, _("Total"), ngettext("%d card", "%d cards", tot) % tot)
        self._line(i, _("Average"), self._avgDay(tot, period, _("cards")))
        txt += self._lineTbl(i)

        return txt
Пример #11
0
 def onDelete(self):
     self.mw.checkpoint(_("Delete"))
     cnt = len(self.card.note().cards())
     self.mw.col.remNotes([self.card.note().id])
     self.mw.reset()
     tooltip(ngettext(
         "Note and its %d card deleted.",
         "Note and its %d cards deleted.",
         cnt) % cnt)
Пример #12
0
    def _renderStats(self):
        cards, thetime = self.mw.col.db.first("""
select count(), sum(time)/1000 from revlog
where id > ?""", (self.mw.col.sched.dayCutoff-86400)*1000)
        cards = cards or 0
        thetime = thetime or 0
        msgp1 = ngettext("%d card", "%d cards", cards) % cards
        buf = _("Studied %(a)s in %(b)s today.") % dict(a=msgp1, b=fmtTimeSpan(thetime))
        return buf
Пример #13
0
def onResetTimes(browser):

    # Make sure user selected something.
    if not browser.form.tableView.selectionModel().hasSelection():
        showWarning("Please select at least one card to reset creation date.", parent=browser)
        return
 
    # Preprocess cards, collecting note IDs.
    (card_cnt, nids) = identifyNotes(browser.selectedCards())
    
    # debug
    #showInfo(("Processed %s cards leading to %s notes") % (card_cnt, len(nids)))
    
    # Prompt for date.
    todaystr = time.strftime('%Y/%m/%d', time.localtime())
    (s, ret) = getText("Enter a date as YYYY/MM/DD to set as the creation time, or 'today' for current date (%s):" % todaystr, parent=browser)

    if (not s) or (not ret):
        return
    
    # Generate a random MM:HH:SS. This will help prevent the same timestamp from
    # being used if this addon is executed multiple times with the same date.
    random_time = ("%s:%s:%s") % (random.randint(0, 23), random.randint(0, 59), random.randint(0, 59))

    # Don't want random? Uncomment the following line and specify any time you 
    # want in the format HH:MM:SS where HH is 00-24:
    #random_time = "15:01:01"

    
    if s == 'today':
        desttime = time.mktime(time.strptime(("%s %s") % (todaystr, random_time), '%Y/%m/%d %H:%M:%S'))
    else:
        try:
            desttime = time.mktime(time.strptime(("%s %s") % (s, random_time), '%Y/%m/%d %H:%M:%S'))
        except ValueError:
            showWarning("Sorry, I didn't understand that date.  Please enter 'today' or a date in YYYY/MM/DD format", parent=browser)
            return
   
    # This mimics anki/utils.py timestampID function (which calls intTime for
    # seconds since epoch and multiplies those seconds by 1000).
    desttime = desttime * 1000
    
    # debug
    # showInfo(("desttime %s") % desttime)

    # Force a full sync if collection isn't already marked for one. This is
    # apparently because we are changing the key column of the table.
    # (Per Damien on 2013/01/07: http://groups.google.com/group/anki-users/msg/3c8910e10f6fd0ac?hl=en )
    mw.col.modSchema(check=True)
    
    # Do it.
    resetCreationTimes(nids, desttime)
        
    # Done.
    mw.reset()
    tooltip(ngettext("Creation time reset for %d note.", "Creation time reset for %d notes.", len(nids)) % len(nids))
Пример #14
0
 def _nextDueMsg(self):
     line = []
     rev = self.revTomorrow() + self.lrnTomorrow()
     if rev:
         line.append(
             ngettext("There will be <b>%s review</b>.",
                      "There will be <b>%s reviews</b>.", rev) % rev)
     new = self.newTomorrow()
     if new:
         line.append(
             ngettext("There will be <b>%d new</b> card.",
                      "There will be <b>%d new</b> cards.", new) % new)
     if line:
         line.insert(0, _("At this time tomorrow:"))
         buf = "<br>".join(line)
     else:
         buf = _("No cards are due tomorrow.")
     buf = '<style>b { color: #00f; }</style>' + buf
     return buf
Пример #15
0
def _importNotes(self):
    # build guid -> (id,mod,mid) hash & map of existing note ids
    self._notes = {}
    existing = {}
    for id, guid, mod, mid in self.dst.db.execute(
        "select id, guid, mod, mid from notes"):
        self._notes[guid] = (id, mod, mid)
        existing[id] = True
    # we may need to rewrite the guid if the model schemas don't match,
    # so we need to keep track of the changes for the card import stage
    self._changedGuids = {}
    # iterate over source collection
    add = []
    dirty = []
    usn = self.dst.usn()
    dupes = 0
    for note in self.src.db.execute(
        "select * from notes"):
        # turn the db result into a mutable list
        note = list(note)
        shouldAdd = self._uniquifyNote(note)
        if shouldAdd:
            # ensure id is unique
            while note[0] in existing:
                note[0] += 999
            existing[note[0]] = True
            # bump usn
            note[4] = usn
            # update media references in case of dupes
            note[6] = self._mungeMedia(note[MID], note[6])
            add.append(note)
            dirty.append(note[0])
            # note we have the added the guid
            self._notes[note[GUID]] = (note[0], note[3], note[MID])
        else:
            dupes += 1

            # update existing note
            newer = note[3] > mod
            if self.allowUpdate and self._mid(mid) == mid and newer:
                localNid = self._notes[note[GUID]][0]
                note[0] = localNid
                note[4] = usn
                add.append(note)
                dirty.append(note[0])

    if dupes:
        self.log.append(_("Already in collection: %s.") % (ngettext(
            "%d note", "%d notes", dupes) % dupes))
    # add to col
    self.dst.db.executemany(
        "insert or replace into notes values (?,?,?,?,?,?,?,?,?,?,?)",
        add)
    self.dst.updateFieldCache(dirty)
    self.dst.tags.registerNotes(dirty)
    def todayStats(self):
        """
        Copy and paste from CollectionStats.todayStats(self)
        Two changes made
        """
        #DeckInformation ... changed formatting
        b = ""
        #DeckInformation ... changed to use our deck limit
        lim = "cid in (select id from cards where did in %s)" % self.deck_limit
        if lim:
            lim = " and " + lim
        cards, thetime, failed, lrn, rev, relrn, filt = self.col.db.first("""
select count(), sum(time)/1000,
sum(case when ease = 1 then 1 else 0 end), /* failed */
sum(case when type = 0 then 1 else 0 end), /* learning */
sum(case when type = 1 then 1 else 0 end), /* review */
sum(case when type = 2 then 1 else 0 end), /* relearn */
sum(case when type = 3 then 1 else 0 end) /* filter */
from revlog where id > ? """ + lim, (self.col.sched.dayCutoff - 86400) * 1000)
        cards = cards or 0
        thetime = thetime or 0
        failed = failed or 0
        lrn = lrn or 0
        rev = rev or 0
        relrn = relrn or 0
        filt = filt or 0
        # studied
        def bold(s):
            return "<b>" + unicode(s) + "</b>"

        msgp1 = ngettext("<!--studied-->%d card", "<!--studied-->%d cards", cards) % cards
        b += _("Studied %(a)s in %(b)s today.") % dict(
            a=bold(msgp1), b=bold(fmtTimeSpan(thetime, unit=1)))
        # again/pass count
        b += "<br>" + _("Again count: %s") % bold(failed)
        if cards:
            b += " " + _("(%s correct)") % bold(
                "%0.1f%%" % ((1 - failed / float(cards)) * 100))
            # type breakdown
        b += "<br>"
        b += (_("Learn: %(a)s, Review: %(b)s, Relearn: %(c)s, Filtered: %(d)s")
              % dict(a=bold(lrn), b=bold(rev), c=bold(relrn), d=bold(filt)))
        # mature today
        mcnt, msum = self.col.db.first("""
select count(), sum(case when ease = 1 then 0 else 1 end) from revlog
where lastIvl >= 21 and id > ?""" + lim, (self.col.sched.dayCutoff - 86400) * 1000)
        b += "<br>"
        if mcnt:
            b += _("Correct answers on mature cards: %(a)d/%(b)d (%(c).1f%%)") % dict(
                a=msum, b=mcnt, c=(msum / float(mcnt) * 100))
        else:
            b += _("No mature cards were studied today.")
        return b
Пример #17
0
 def setChildren(self):
     if not askUser(
         _("Set all decks below %s to this option group?") %
         self.deck['name']):
         return
     for did in self.childDids:
         deck = self.mw.col.decks.get(did)
         deck['conf'] = self.deck['conf']
         self.mw.col.decks.save(deck)
     
     tooltip(ngettext("%d deck updated.", "%d decks updated.", \
                     len(self.childDids)) % len(self.childDids))
def todayStats_old(self):
    """We need to overwrite the entire method to change the mature ivl"""
    b = self._title(_("Today"))
    # studied today
    lim = self._revlogLimit()
    if lim:
        lim = " and " + lim
    cards, thetime, failed, lrn, rev, relrn, filt = self.col.db.first("""
select count(), sum(time)/1000,
sum(case when ease = 1 then 1 else 0 end), /* failed */
sum(case when type = 0 then 1 else 0 end), /* learning */
sum(case when type = 1 then 1 else 0 end), /* review */
sum(case when type = 2 then 1 else 0 end), /* relearn */
sum(case when type = 3 then 1 else 0 end) /* filter */
from revlog where id > ? """+lim, (self.col.sched.dayCutoff-86400)*1000)
    cards = cards or 0
    thetime = thetime or 0
    failed = failed or 0
    lrn = lrn or 0
    rev = rev or 0
    relrn = relrn or 0
    filt = filt or 0
    # studied
    if anki_version.startswith("2.0."):
        def bold(s):
            return "<b>"+unicode(s)+"</b>"
    else:
        def bold(s):
            return "<b>"+str(s)+"</b>"
    msgp1 = ngettext("<!--studied-->%d card", "<!--studied-->%d cards", cards) % cards
    b += _("Studied %(a)s in %(b)s today.") % dict(
        a=bold(msgp1), b=bold(fmtTimeSpan(thetime, unit=1)))
    # again/pass count
    b += "<br>" + _("Again count: %s") % bold(failed)
    if cards:
        b += " " + _("(%s correct)") % bold(
            "%0.1f%%" %((1-failed/float(cards))*100))
    # type breakdown
    b += "<br>"
    b += (_("Learn: %(a)s, Review: %(b)s, Relearn: %(c)s, Filtered: %(d)s")
          % dict(a=bold(lrn), b=bold(rev), c=bold(relrn), d=bold(filt)))
    # mature today
    mcnt, msum = self.col.db.first("""
select count(), sum(case when ease = 1 then 0 else 1 end) from revlog
where lastIvl >= %d and id > ?""" % MATURE_IVL +lim, (self.col.sched.dayCutoff-86400)*1000)
    b += "<br>"
    if mcnt:
        b += _("Correct answers on mature cards: %(a)d/%(b)d (%(c).1f%%)") % dict(
            a=msum, b=mcnt, c=(msum / float(mcnt) * 100))
    else:
        b += _("No mature cards were studied today.")
    return b
Пример #19
0
    def updateModelsList(self, notetypes):
        row = self.form.modelsList.currentRow()
        if row == -1:
            row = 0
        self.form.modelsList.clear()

        self.models = notetypes
        for m in self.models:
            mUse = m.use_count
            mUse = ngettext("%d note", "%d notes", mUse) % mUse
            item = QListWidgetItem("%s [%s]" % (m.name, mUse))
            self.form.modelsList.addItem(item)
        self.form.modelsList.setCurrentRow(row)
Пример #20
0
 def setChildren(self):
     if not askUser(
             _("Set all decks below %s to this option group?") %
             self.deck['name']):
         return
     for did in self.childDids:
         deck = self.mw.col.decks.get(did)
         if deck['dyn']:
             continue
         deck['conf'] = self.deck['conf']
         self.mw.col.decks.save(deck)
     tooltip(ngettext("%d deck updated.", "%d decks updated.", \
                     len(self.childDids)) % len(self.childDids))
Пример #21
0
 def onDelete(self):
     if len(self.model["flds"]) < 2:
         return showWarning(_("Notes require at least one field."))
     count = self.mm.useCount(self.model)
     c = ngettext("%d note", "%d notes", count) % count
     if not askUser(_("Delete field from %s?") % c):
         return
     if not self.change_tracker.mark_schema():
         return
     f = self.model["flds"][self.form.fieldList.currentRow()]
     self.mm.remove_field(self.model, f)
     self.fillFields()
     self.form.fieldList.setCurrentRow(0)
Пример #22
0
 def updateModelsList(self):
     row = self.form.modelsList.currentRow()
     if row == -1:
         row = 0
     self.models = self.col.models.all()
     self.models.sort(key=itemgetter("name"))
     self.form.modelsList.clear()
     for m in self.models:
         mUse = self.mm.useCount(m)
         mUse = ngettext("%d note", "%d notes", mUse) % mUse
         item = QListWidgetItem("%s [%s]" % (m["name"], mUse))
         self.form.modelsList.addItem(item)
     self.form.modelsList.setCurrentRow(row)
Пример #23
0
 def onDelete(self):
     # need to check state because the shortcut is global to the main
     # window
     if self.mw.state != "review" or not self.card:
         return
     self.mw.checkpoint(_("Delete"))
     cnt = len(self.card.note().cards())
     self.mw.col.remNotes([self.card.note().id])
     self.mw.reset()
     tooltip(ngettext(
         "Note and its %d card deleted.",
         "Note and its %d cards deleted.",
         cnt) % cnt)
Пример #24
0
 def onDelete(self):
     # need to check state because the shortcut is global to the main
     # window
     if self.mw.state != "review" or not self.card:
         return
     self.mw.checkpoint(_("Delete"))
     cnt = len(self.card.note().cards())
     self.mw.col.remNotes([self.card.note().id])
     self.mw.reset()
     tooltip(ngettext(
         "Note and its %d card deleted.",
         "Note and its %d cards deleted.",
         cnt) % cnt)
Пример #25
0
 def onDelete(self):
     selected = self.selectedAddons()
     if not selected:
         return
     if not askUser(
             ngettext("Delete the %(num)d selected add-on?",
                      "Delete the %(num)d selected add-ons?", len(selected))
             % dict(num=len(selected))):
         return
     for dir in selected:
         self.mgr.deleteAddon(dir)
     self.form.addonList.clearSelection()
     self.redrawAddons()
Пример #26
0
 def onDelete(self):
     selected = self.selectedAddons()
     if not selected:
         return
     if not askUser(ngettext("Delete the %(num)d selected add-on?",
                             "Delete the %(num)d selected add-ons?",
                             len(selected)) %
                            dict(num=len(selected))):
         return
     for dir in selected:
         self.mgr.deleteAddon(dir)
     self.form.addonList.clearSelection()
     self.redrawAddons()
Пример #27
0
 def onDelete(self):
     if len(self.model['flds']) < 2:
         return showWarning(_("Notes require at least one field."))
     c = self.mm.useCount(self.model)
     c = ngettext("%d note", "%d notes", c) % c
     if not askUser(_("Delete field from %s?") % c):
         return
     f = self.model['flds'][self.form.fieldList.currentRow()]
     self.mw.progress.start()
     self.mm.remField(self.model, f)
     self.mw.progress.finish()
     self.fillFields()
     self.form.fieldList.setCurrentRow(0)
Пример #28
0
 def updateModelsList(self):
     row = self.form.modelsList.currentRow()
     if row == -1:
         row = 0
     self.models = self.col.models.all()
     self.models.sort(key=itemgetter("name"))
     self.form.modelsList.clear()
     for m in self.models:
         mUse = self.mm.useCount(m)
         mUse = ngettext("%d note", "%d notes", mUse) % mUse
         item = QListWidgetItem("%s [%s]" % (m['name'], mUse))
         self.form.modelsList.addItem(item)
     self.form.modelsList.setCurrentRow(row)
Пример #29
0
    def updateModelsList(self,
                         notetypes: List[NoteTypeNameIDUseCount]) -> None:
        row = self.form.modelsList.currentRow()
        if row == -1:
            row = 0
        self.form.modelsList.clear()

        self.models = notetypes
        for m in self.models:
            mUse = ngettext("%d note", "%d notes", m.use_count) % m.use_count
            item = QListWidgetItem("%s [%s]" % (m.name, mUse))
            self.form.modelsList.addItem(item)
        self.form.modelsList.setCurrentRow(row)
Пример #30
0
 def _ansInfo(self,
              totd,
              studied,
              first,
              unit,
              convHours=False,
              total=None):
     if not totd:
         return
     tot = totd[-1][1]
     period = self._periodDays()
     if not period:
         # base off earliest repetition date
         lim = self._revlogLimit()
         if lim:
             lim = " where " + lim
         t = self.col.db.scalar(
             "select id from revlog %s order by id limit 1" % lim)
         if not t:
             period = 1
         else:
             period = max(
                 1,
                 int(1 + ((self.col.sched.dayCutoff - (t / 1000)) / 86400)))
     i = []
     self._line(
         i,
         _("Days studied"),
         _("<b>%(pct)d%%</b> (%(x)s of %(y)s)") %
         dict(x=studied, y=period, pct=studied / float(period) * 100),
         bold=False)
     if convHours:
         tunit = _("hours")
     else:
         tunit = unit
     self._line(i, _("Total"),
                _("%(tot)s %(unit)s") % dict(unit=tunit, tot=int(tot)))
     if convHours:
         # convert to minutes
         tot *= 60
     self._line(i, _("Average for days studied"),
                self._avgDay(tot, studied, unit))
     self._line(i, _("If you studied every day"),
                self._avgDay(tot, period, unit))
     if total and tot:
         perMin = total / float(tot)
         perMin = ngettext("%d card/minute", "%d cards/minute",
                           perMin) % perMin
         self._line(i, _("Average answer time"),
                    "%0.1fs (%s)" % ((tot * 60) / total, perMin))
     return self._lineTbl(i), int(tot)
Пример #31
0
 def nextCard(self):
     elapsed = self.mw.col.timeboxReached()
     if elapsed:
         part1 = ngettext("%d card studied in", "%d cards studied in", elapsed[1]) % elapsed[1]
         mins = int(round(elapsed[0]/60))
         part2 = ngettext("%s minute.", "%s minutes.", mins) % mins
         fin = _("Finish")
         diag = askUserDialog("%s %s" % (part1, part2),
                          [_("Continue"), fin])
         diag.setIcon(QMessageBox.Information)
         if diag.run() == fin:
             return self.mw.moveToState("deckBrowser")
         self.mw.col.startTimebox()
     if self.cardQueue:
         # undone/edited cards to show
         c = self.cardQueue.pop()
         c.startTimer()
         self.hadCardQueue = True
     else:
         if self.hadCardQueue:
             # the undone/edited cards may be sitting in the regular queue;
             # need to reset
             self.mw.col.reset()
             self.hadCardQueue = False
         c = self.mw.col.sched.getCard()
         if c and self.card and self.card.id == c.id:
             # if previously dropped card
             self.card=None
             return self.nextCard()
     self.card = c
     clearAudioQueue()
     if not c:
         return self.mw.moveToState("overview")
     if self._reps is None or self._reps % 100 == 0:
         # we recycle the webview periodically so webkit can free memory
         self._initWeb()
     else:
         self._showQuestion()
Пример #32
0
 def onAddCard(self):
     cnt = self.mw.col.models.useCount(self.model)
     txt = ngettext("This will create %d card. Proceed?",
                    "This will create %d cards. Proceed?", cnt) % cnt
     if not askUser(txt):
         return
     name = self._newCardName()
     t = self.mm.newTemplate(name)
     old = self.card.template()
     t['qfmt'] = old['qfmt']
     t['afmt'] = old['afmt']
     self.mm.addTemplate(self.model, t)
     self.ord = len(self.cards)
     self.redraw()
Пример #33
0
        def on_done(fut):
            card_cnt = fut.result()

            template = self.current_template()
            cards = ngettext("%d card", "%d cards", card_cnt) % card_cnt
            msg = _("Delete the '%(a)s' card type, and its %(b)s?") % dict(
                a=template["name"], b=cards)
            if not askUser(msg):
                return

            if not self.change_tracker.mark_schema():
                return

            self.onRemoveInner(template)
Пример #34
0
 def onAddCard(self):
     cnt = self.mw.col.models.useCount(self.model)
     txt = ngettext("This will create %d card. Proceed?",
                    "This will create %d cards. Proceed?", cnt) % cnt
     if not askUser(txt):
         return
     name = self._newCardName()
     t = self.mm.newTemplate(name)
     old = self.card.template()
     t['qfmt'] = old['qfmt']
     t['afmt'] = old['afmt']
     self.mm.addTemplate(self.model, t)
     self.ord = len(self.cards)
     self.redraw()
Пример #35
0
    def onCheckMediaDB(self):
        self.progress.start(immediate=True)
        (nohave, unused, warnings) = self.col.media.check()
        self.progress.finish()
        # generate report
        report = ""
        if warnings:
            report += "\n".join(warnings) + "\n"
        if unused:
            numberOfUnusedFilesLabel = len(unused)
            if report:
                report += "\n\n\n"
            report += (ngettext(
                "%d file found in media folder not used by any cards:",
                "%d files found in media folder not used by any cards:",
                numberOfUnusedFilesLabel,
            ) % numberOfUnusedFilesLabel)
            report += "\n" + "\n".join(unused)
        if nohave:
            if report:
                report += "\n\n\n"
            report += _("Used on cards but missing from media folder:")
            report += "\n" + "\n".join(nohave)
        if not report:
            tooltip(_("No unused or missing files found."))
            return
        # show report and offer to delete
        diag = QDialog(self)
        diag.setWindowTitle("Anki")
        layout = QVBoxLayout(diag)
        diag.setLayout(layout)
        text = QTextEdit()
        text.setReadOnly(True)
        text.setPlainText(report)
        layout.addWidget(text)
        box = QDialogButtonBox(QDialogButtonBox.Close)
        layout.addWidget(box)
        if unused:
            b = QPushButton(_("Delete Unused Files"))
            b.setAutoDefault(False)
            box.addButton(b, QDialogButtonBox.ActionRole)
            b.clicked.connect(
                lambda c, u=unused, d=diag: self.deleteUnused(u, d))

        box.rejected.connect(diag.reject)
        diag.setMinimumHeight(400)
        diag.setMinimumWidth(500)
        restoreGeom(diag, "checkmediadb")
        diag.exec_()
        saveGeom(diag, "checkmediadb")
Пример #36
0
    def _renderStats(self):
        cards, thetime = self.mw.col.db.first(
            """
select count(), sum(time)/1000 from revlog
where id > ?""",
            (self.mw.col.sched.dayCutoff - 86400) * 1000,
        )
        cards = cards or 0
        thetime = thetime or 0
        msgp1 = (ngettext("<!--studied-->%d card", "<!--studied-->%d cards",
                          cards) % cards)
        buf = _("Studied %(a)s %(b)s today.") % dict(
            a=msgp1, b=fmtTimeSpan(thetime, unit=1, inTime=True))
        return buf
Пример #37
0
    def foreignNotes(self):

        # Load file and parse it by minidom
        self.loadSource(self.file)

        # Migrating content / time consuming part
        # addItemToCards is called for each sm element
        self.logger('Parsing started.')
        self.parse()
        self.logger('Parsing done.')

        # Return imported cards
        self.total = len(self.notes)
        self.log.append(ngettext("%d card imported.", "%d cards imported.", self.total) % self.total)
        return self.notes
Пример #38
0
 def onDelete(self):
     note = self.card.note()
     numCards = len(note.cards())
     if numCards > 1:
         r = askUser("Really delete this note? It has %i cards." % numCards,
                     defaultno=True, title="Delete note?")
         if not r:
             return
     self.mw.checkpoint(_("Delete"))
     self.mw.col.remNotes([self.card.note().id])
     tooltip(ngettext(
         "Note and its %d card deleted.",
         "Note and its %d cards deleted.",
         numCards) % numCards)
     self.accept()
Пример #39
0
 def onDelete(self):
     note = self.card.note()
     numCards = len(note.cards())
     if numCards > 1:
         r = askUser("Really delete this note? It has %i cards." % numCards,
                     defaultno=True,
                     title="Delete note?")
         if not r:
             return
     self.mw.checkpoint(_("Delete"))
     self.mw.col.remNotes([self.card.note().id])
     tooltip(
         ngettext("Note and its %d card deleted.",
                  "Note and its %d cards deleted.", numCards) % numCards)
     self.accept()
Пример #40
0
    def onRemove(self):
        if len(self.model['tmpls']) < 2:
            return showInfo(_("At least one card type is required."))
        idx = self.ord
        cards = self.mm.tmplUseCount(self.model, idx)
        cards = ngettext("%d card", "%d cards", cards) % cards
        msg = (_("Delete the '%(a)s' card type, and its %(b)s?") %
            dict(a=self.model['tmpls'][idx]['name'], b=cards))
        if not askUser(msg):
            return
        if not self.mm.remTemplate(self.model, self.cards[idx].template()):
            return showWarning(_("""\
Removing this card type would cause one or more notes to be deleted. \
Please create a new card type first."""))
        self.redraw()
Пример #41
0
    def onRemove(self):
        if len(self.model['tmpls']) < 2:
            return showInfo(_("At least one card type is required."))
        idx = self.ord
        cards = self.mm.tmplUseCount(self.model, idx)
        cards = ngettext("%d card", "%d cards", cards) % cards
        msg = (_("Delete the '%(a)s' card type, and its %(b)s?") %
            dict(a=self.model['tmpls'][idx]['name'], b=cards))
        if not askUser(msg):
            return
        if not self.mm.remTemplate(self.model, self.cards[idx].template()):
            return showWarning(_("""\
Removing this card type would cause one or more notes to be deleted. \
Please create a new card type first."""))
        self.redraw()
Пример #42
0
 def onAddCard(self):
     """Ask for confirmation and create a copy of current card as the last template"""
     cnt = self.mw.col.models.useCount(self.model)
     txt = ngettext("This will create %d card. Proceed?",
                    "This will create %d cards. Proceed?", cnt) % cnt
     if not askUser(txt):
         return
     name = self._newCardName()
     t = self.mm.newTemplate(name)
     old = self.card.template()
     t['qfmt'] = old['qfmt']
     t['afmt'] = old['afmt']
     self.mm.addTemplate(self.model, t)
     self.ord = len(self.cards)
     self.redraw()
Пример #43
0
    def foreignNotes(self):

        # Load file and parse it by minidom
        self.loadSource(self.file)

        # Migrating content / time consuming part
        # addItemToCards is called for each sm element
        self.logger('Parsing started.')
        self.parse()
        self.logger('Parsing done.')

        # Return imported cards
        self.total = len(self.notes)
        self.log.append(ngettext("%d card imported.", "%d cards imported.", self.total) % self.total)
        return self.notes
Пример #44
0
 def onConfChange(self, idx):
     if self.ignoreConfChange:
         return
     if self.conf:
         self.saveConf()
     conf = self.confList[idx]
     self.deck['conf'] = conf['id']
     self.loadConf()
     cnt = 0
     for d in self.mw.col.decks.all():
         if d['dyn']:
             continue
         if d['conf'] == conf['id']:
             cnt += 1
     self.form.count.setText(ngettext("%d deck uses this options group", \
             "%d decks use this options group", cnt) % cnt)
Пример #45
0
    def _dueInfo(self, tot: int, num: int) -> str:
        i: List[str] = []
        self._line(
            i, _("Total"), self.col.tr(TR.STATISTICS_REVIEWS, reviews=tot),
        )
        self._line(i, _("Average"), self._avgDay(tot, num, _("reviews")))
        tomorrow = self.col.db.scalar(
            f"""
select count() from cards where did in %s and queue in ({QUEUE_TYPE_REV},{QUEUE_TYPE_DAY_LEARN_RELEARN})
and due = ?"""
            % self._limit(),
            self.col.sched.today + 1,
        )
        tomorrow = ngettext("%d card", "%d cards", tomorrow) % tomorrow
        self._line(i, _("Due tomorrow"), tomorrow)
        return self._lineTbl(i)
Пример #46
0
 def onConfChange(self, idx):
     if self.ignoreConfChange:
         return
     if self.conf:
         self.saveConf()
     conf = self.confList[idx]
     self.deck['conf'] = conf['id']
     self.loadConf()
     cnt = 0
     for d in self.mw.col.decks.all():
         if d['dyn']:
             continue
         if d['conf'] == conf['id']:
             cnt += 1
     self.form.count.setText(ngettext("%d deck uses this options group", \
             "%d decks use this options group", cnt) % cnt)
Пример #47
0
 def _ansInfo(self, totd, studied, first, unit, convHours=False, total=None):
     if not totd:
         return
     tot = totd[-1][1]
     period = self._periodDays()
     if not period:
         # base off earliest repetition date
         lim = self._revlogLimit()
         if lim:
             lim = " where " + lim
         t = self.col.db.scalar("select id from revlog %s order by id limit 1" % lim)
         if not t:
             period = 1
         else:
             period = max(
                 1, int(1+((self.col.sched.dayCutoff - (t/1000)) / 86400)))
     i = []
     self._line(i, _("Days studied"),
                _("<b>%(pct)d%%</b> (%(x)s of %(y)s)") % dict(
                    x=studied, y=period, pct=studied/float(period)*100),
                bold=False)
     if convHours:
         tunit = _("hours")
     else:
         tunit = unit
     self._line(i, _("Total"), _("%(tot)s %(unit)s") % dict(
         unit=tunit, tot=int(tot)))
     if convHours:
         # convert to minutes
         tot *= 60
     self._line(i, _("Average for days studied"), self._avgDay(
         tot, studied, unit))
     if studied != period:
         # don't display if you did study every day
         self._line(i, _("If you studied every day"), self._avgDay(
             tot, period, unit))
     if total and tot:
         perMin = total / float(tot)
         perMin = round(perMin, 1)
         perMin = ngettext("%d card/minute", "%.01f cards/minute", perMin) % perMin
         # don't round down to zero
         if float(perMin.split(' ')[0]) < 0.1:
             perMin = ''.join(["<", _("%.01f cards/minute")]) % 0.1
         self._line(
             i, _("Average answer time"),
             _("%(a)0.1fs (%(b)s)") % dict(a=(tot*60)/total, b=perMin))
     return self._lineTbl(i), int(tot)
Пример #48
0
def _replaceWithApkg(mw, file, backup):
    mw.progress.start(immediate=True)

    z = zipfile.ZipFile(file)

    # v2 scheduler?
    colname = "collection.anki21"
    try:

        z.getinfo(colname)
    except KeyError:
        colname = "collection.anki2"

    try:
        with z.open(colname) as source, \
                open(mw.pm.collectionPath(), "wb") as target:
            shutil.copyfileobj(source, target)
    except:
        mw.progress.finish()
        showWarning(_("The provided file is not a valid .apkg file."))
        return
    # because users don't have a backup of media, it's safer to import new
    # data and rely on them running a media db check to get rid of any
    # unwanted media. in the future we might also want to deduplicate this
    # step
    d = os.path.join(mw.pm.profileFolder(), "collection.media")
    for n, (cStr, file) in enumerate(
            json.loads(z.read("media").decode("utf8")).items()):
        mw.progress.update(
            ngettext("Processed %d media file", "Processed %d media files", n)
            % n)
        size = z.getinfo(cStr).file_size
        dest = os.path.join(d, unicodedata.normalize("NFC", file))
        # if we have a matching file size
        if os.path.exists(dest) and size == os.stat(dest).st_size:
            continue
        data = z.read(cStr)
        open(dest, "wb").write(data)
    z.close()
    # reload
    if not mw.loadCollection():
        mw.progress.finish()
        return
    if backup:
        mw.col.modSchema(check=False)
    mw.progress.finish()
Пример #49
0
def onAddCard(self):
    """Ask for confirmation and create a copy of current card as the last template"""
    # only differenc, add a new element in newTemplatesData
    cnt = self.mw.col.models.useCount(self.model)
    txt = ngettext("This will create %d card. Proceed?",
                   "This will create %d cards. Proceed?", cnt) % cnt
    if not askUser(txt):
        return
    name = self._newCardName()
    t = self.mm.newTemplate(name)
    old = self.card.template()
    t['qfmt'] = old['qfmt']
    t['afmt'] = old['afmt']
    self.mm.addTemplate(self.model, t)
    self.newTemplatesData.append({"old idx":self.newTemplatesData[self.ord]["old idx"],
                            "is new": True})#new
    self.ord = len(self.cards)
    self.redraw()
Пример #50
0
    def buildCard(self, text):
        config = mw.addonManager.getConfig(__name__)
        if config:
            MODEL = config['model']
            target_fields = config['target_fields']
            Deck = config['Deck']
        else:
            msg = """
            AnkiClips:
            The add-on missed the configuration file.
            If you would not get the right feeds,
            please reinstall this add-on."""
            utils.showWarning(msg)

        # get deck and model
        deck = mw.col.decks.get(mw.col.decks.id(Deck))
        model = mw.col.models.byName(MODEL)

        # assign model to deck
        mw.col.decks.select(deck['id'])
        mw.col.decks.get(deck)['mid'] = model['id']
        mw.col.decks.save(deck)

        # assign deck to model
        mw.col.models.setCurrent(model)
        mw.col.models.current()['did'] = deck['id']
        mw.col.models.save(model)

        # iterate notes
        adds = 0
        for key in text.keys():
            note = mw.col.newNote()
            note["audio"] = "[sound:" + key + ".mp3]"
            note["text"] = text[key]
            mw.col.addNote(note)
            adds += 1

        mw.col.reset()
        mw.reset()

        # show result
        msg = ngettext("%d note added", "%d notes added", adds) % adds
        msg += "\n"
        return msg
Пример #51
0
def _replaceWithApkg(mw, file, backup):
    mw.progress.start(immediate=True)

    z = zipfile.ZipFile(file)

    # v2 scheduler?
    colname = "collection.anki21"
    try:
        z.getinfo(colname)
    except KeyError:
        colname = "collection.anki2"

    try:
        with z.open(colname) as source, \
                open(mw.pm.collectionPath(), "wb") as target:
            shutil.copyfileobj(source, target)
    except:
        mw.progress.finish()
        showWarning(_("The provided file is not a valid .apkg file."))
        return
    # because users don't have a backup of media, it's safer to import new
    # data and rely on them running a media db check to get rid of any
    # unwanted media. in the future we might also want to deduplicate this
    # step
    d = os.path.join(mw.pm.profileFolder(), "collection.media")
    for n, (cStr, file) in enumerate(
            json.loads(z.read("media").decode("utf8")).items()):
        mw.progress.update(ngettext("Processed %d media file",
                                    "Processed %d media files", n) % n)
        size = z.getinfo(cStr).file_size
        dest = os.path.join(d, unicodedata.normalize("NFC", file))
        # if we have a matching file size
        if os.path.exists(dest) and size == os.stat(dest).st_size:
            continue
        data = z.read(cStr)
        open(dest, "wb").write(data)
    z.close()
    # reload
    if not mw.loadCollection():
        mw.progress.finish()
        return
    if backup:
        mw.col.modSchema(check=False)
    mw.progress.finish()
Пример #52
0
    def clockIsOff(self, diff):
        diffText = ngettext("%s second", "%s seconds", diff) % diff
        warn = _("""\
In order to ensure your collection works correctly when moved between \
devices, Anki requires your computer's internal clock to be set correctly. \
The internal clock can be wrong even if your system is showing the correct \
local time.

Please go to the time settings on your computer and check the following:

- AM/PM
- Clock drift
- Day, month and year
- Timezone
- Daylight savings

Difference to correct time: %s.""") % diffText
        showWarning(warn)
        self.app.closeAllWindows()
Пример #53
0
 def updateTemplates(self):
     if not self.handleCards:
         return
     # remove any shortcuts
     for s in self.cardShortcuts:
         s.setEnabled(False)
     self.cardShortcuts = []
     m = self.deck.currentModel()
     ts = m.templates
     active = [t['name'] for t in ts if t['actv']]
     txt = ngettext("%d card", "%d cards", len(active)) % len(active)
     self.cards.setText(txt)
     n = 1
     for t in ts:
         s = QShortcut(QKeySequence("Ctrl+%d" % n), self.widget)
         self.widget.connect(s, SIGNAL("activated()"),
                             lambda t=t: self.toggleTemplate(t))
         self.cardShortcuts.append(s)
         n += 1
Пример #54
0
def onRemove(self):
    """ Remove the current template, except if it would leave a note without card. Ask user for confirmation"""
    # only difference: remove current index from newTemplatesData.
    if len(self.model['tmpls']) < 2:
        return showInfo(_("At least one card type is required."))
    idx = self.ord
    cards = self.mm.tmplUseCount(self.model, idx)
    cards = ngettext("%d card", "%d cards", cards) % cards
    msg = (_("Delete the '%(a)s' card type, and its %(b)s?") %
        dict(a=self.model['tmpls'][idx]['name'], b=cards))
    if not askUser(msg):
        return
    if not self.mm.remTemplate(self.model, self.cards[idx].template()):
        return showWarning(_("""\
Removing this card type would cause one or more notes to be deleted. \
Please create a new card type first."""))

    del self.newTemplatesData[idx] # Only new line
    self.redraw()
Пример #55
0
 def onAddCard(self):
     cnt = self.mw.col.models.useCount(self.model)
     txt = (ngettext(
         "This will create %d card. Proceed?",
         "This will create %d cards. Proceed?",
         cnt,
     ) % cnt)
     if not askUser(txt):
         return
     if not self.change_tracker.mark_schema():
         return
     name = self._newCardName()
     t = self.mm.newTemplate(name)
     old = self.current_template()
     t["qfmt"] = old["qfmt"]
     t["afmt"] = old["afmt"]
     self.mm.add_template(self.model, t)
     self.ord = len(self.templates) - 1
     self.redraw_everything()
Пример #56
0
    def clockIsOff(self, diff):
        diffText = ngettext("%s second", "%s seconds", diff) % diff
        warn = _("""\
In order to ensure your collection works correctly when moved between \
devices, Anki requires your computer's internal clock to be set correctly. \
The internal clock can be wrong even if your system is showing the correct \
local time.

Please go to the time settings on your computer and check the following:

- AM/PM
- Clock drift
- Day, month and year
- Timezone
- Daylight savings

Difference to correct time: %s.""") % diffText
        showWarning(warn)
        self.app.closeAllWindows()
Пример #57
0
 def _delete(self, did):
     self.mw.checkpoint(_("Delete Deck"))
     deck = self.mw.col.decks.get(did)
     if not deck["dyn"]:
         dids = [did] + [r[1] for r in self.mw.col.decks.children(did)]
         cnt = self.mw.col.db.scalar(
             "select count() from cards where did in {0} or "
             "odid in {0}".format(ids2str(dids)))
         if cnt:
             extra = ngettext(" It has %d card.", " It has %d cards.",
                              cnt) % cnt
         else:
             extra = None
     if (deck["dyn"] or not extra
             or askUser((_("Are you sure you wish to delete %s?") %
                         deck["name"]) + extra)):
         self.mw.progress.start()
         self.mw.col.decks.rem(did, True)
         self.mw.progress.finish()
         self.show()
Пример #58
0
 def updateTemplates(self):
     if not self.handleCards:
         return
     # remove any shortcuts
     for s in self.cardShortcuts:
         s.setEnabled(False)
     self.cardShortcuts = []
     m = self.deck.currentModel()
     ts = m.templates
     active = [t['name'] for t in ts if t['actv']]
     txt = ngettext("%d card", "%d cards", len(active)) % len(active)
     self.cards.setText(txt)
     n = 1
     for t in ts:
         s = QShortcut(QKeySequence("Ctrl+%d" % n), self.widget)
         self.widget.connect(s,
                             SIGNAL("activated()"),
                             lambda t=t: self.toggleTemplate(t))
         self.cardShortcuts.append(s)
         n += 1
Пример #59
0
    def introductionGraph(self) -> str:
        start, days, chunk = self.get_start_end_chunk()
        data = self._added(days, chunk)
        if not data:
            return ""
        conf: Dict[str, Any] = dict(
            xaxis=dict(tickDecimals=0, max=0.5),
            yaxes=[dict(min=0), dict(position="right", min=0)],
        )
        if days is not None:
            # pylint: disable=invalid-unary-operand-type
            conf["xaxis"]["min"] = -days + 0.5

        def plot(id, data, ylabel, ylabel2):
            return self._graph(id,
                               data=data,
                               conf=conf,
                               xunit=chunk,
                               ylabel=ylabel,
                               ylabel2=ylabel2)

        # graph
        repdata, repsum = self._splitRepData(data, ((1, colLearn, ""), ))
        txt = self._title(_("Added"),
                          _("The number of new cards you have added."))
        txt += plot("intro",
                    repdata,
                    ylabel=_("Cards"),
                    ylabel2=_("Cumulative Cards"))
        # total and per day average
        tot = sum([i[1] for i in data])
        period = self._periodDays()
        if not period:
            # base off date of earliest added card
            period = self._deckAge("add")
        i: List[str] = []
        self._line(i, _("Total"), ngettext("%d card", "%d cards", tot) % tot)
        self._line(i, _("Average"), self._avgDay(tot, period, _("cards")))
        txt += self._lineTbl(i)

        return txt
Пример #60
0
 def _delete(self, did):
     if str(did) == '1':
         return showWarning(_("The default deck can't be deleted."))
     self.mw.checkpoint(_("Delete Deck"))
     deck = self.mw.col.decks.get(did)
     if not deck['dyn']:
         dids = [did] + [r[1] for r in self.mw.col.decks.children(did)]
         cnt = self.mw.col.db.scalar(
             "select count() from cards where did in {0} or "
             "odid in {0}".format(ids2str(dids)))
         if cnt:
             extra = ngettext(" It has %d card.", " It has %d cards.",
                              cnt) % cnt
         else:
             extra = None
     if deck['dyn'] or not extra or askUser(
         (_("Are you sure you wish to delete %s?") % deck['name']) + extra):
         self.mw.progress.start(immediate=True)
         self.mw.col.decks.rem(did, True)
         self.mw.progress.finish()
         self.show()