Example #1
0
 def file_save(self):
     stopwatch.pause()
     path = config()["path"]
     try:
         database().save(path)
     except MnemosyneError, e:
         self.widget.error_box(e)
Example #2
0
    def do_input(line):
        """ Input mode """
        print("=== Input mode ===")

        card = ui_controller_main()

        card_type_by_id = dict([(card_type.id, card_type) \
            for card_type in card_types()])

        category_names_by_id = dict([(i, name) for (i, name) in \
            enumerate(database().category_names())])

        while True:
            # Select Card Type by user:
            print "Select Card Type:"
            print '\n'.join(["%s %s" % \
                  (type_id, card_type_by_id[type_id].name)\
                    for type_id in sorted(card_type_by_id.keys())])
            while True:
                inp = \
                raw_input(_("Enter number of Card Type or 'q' to quit ... "))
                if inp in ("q", "Q"):
                    return
                if inp in card_type_by_id:
                    card_type = card_type_by_id[inp]
                    break
                print(_("Input error, try again"))

            # Select the exist or Add the new Category
            print '\n'.join(["%s %s" % (cat_id, category_names_by_id[cat_id]) \
                for cat_id in sorted(category_names_by_id.keys())])
            inp = raw_input(_("Enter number of Category or "\
                "enter new category or 'q' to quit ... "))
            if inp in ("q", "Q"):
                return
            category_name = inp
            if inp in category_names_by_id:
                category_name = category_names_by_id[inp]

            # Enter all fields for the current type
            fact = {}
            for key, name in card_type.fields:
                print _("Enter field"), name
                inp = raw_input()
                if inp:
                    fact[key] = inp

            # Check necesary fields and create new card
            for required in card_type.required_fields():
                if required not in fact:
                    print(_("Error.This card is not saved in a database !!!"))
                    print(_("You didn't enter all necesary field(s) !!!"))
                    break
            else:
                # Create new card
                card.create_new_cards(fact, card_type, 0, [category_name])
                database().save(config()['path'])

            if raw_input(_("Do you want to add a new record? y/n ")) != "y":
                break
Example #3
0
 def closeEvent(self, event):
     try:
         config().save()
         database().backup()
         database().unload()
     except MnemosyneError, e:
         self.error_box(e)
         event.ignore()
Example #4
0
 def file_open(self):
     stopwatch.pause()
     old_path = expand_path(config()["path"])
     out = self.widget.open_file_dialog(path=old_path,
                         filter=_("Mnemosyne databases (*.mem)"))
     if not out:
         stopwatch.unpause()
         return
     try:
         database().unload()
     except MnemosyneError, e:
         self.widget.error_box(e)
         stopwatch.unpause()
         return            
Example #5
0
 def file_save_as(self):
     stopwatch.pause()
     old_path = expand_path(config()["path"])
     out = self.widget.save_file_dialog(path=old_path,
                         filter=_("Mnemosyne databases (*.mem)"))
     if not out:
         stopwatch.unpause()
         return
     if not out.endswith(".mem"):
         out += ".mem"
     try:
         database().save(out)
     except MnemosyneError, e:
         self.widget.error_box(e)
         stopwatch.unpause()
         return
Example #6
0
File: card.py Project: wojas/pomni
    def reset_learning_data(self):

        """Used when creating a card for the first time, or when choosing
        'reset learning data' on import.

        Last_rep and next_rep are measured in days since the creation of
        the database. Note that these values should be stored as float in
        SQL to accomodate plugins doing minute-level scheduling.

        Note: self.unseen is needed on top of self.acq_reps, because the
        initial grading of a manually added card is counted as the first
        repetition. An imported card has no such initial grading, and
        therefore we do the initial grading the first time we see it during
        the interactive learning process. Because of this, determining if a
        card has been seen during the interactive learning process can not
        be decided on the basis of acq_reps, but still that information is
        needed when randomly selecting unseen cards to learn.

        """

        self.grade = 0
        self.easiness = database().average_easiness()
        self.acq_reps = 0
        self.ret_reps = 0
        self.lapses = 0
        self.acq_reps_since_lapse = 0
        self.ret_reps_since_lapse = 0
        self.last_rep = 0
        self.next_rep = 0
        self.unseen = True
Example #7
0
    def __init__(self, datadir=None, category=None, records=None):
        
        if datadir:
            datadir = os.path.abspath(datadir)
        elif os.path.exists(os.path.join(os.getcwdu(), ".mnemosyne")):
            datadir = os.path.abspath(os.path.join(os.getcwdu(), ".mnemosyne"))
        else:
            datadir = os.path.abspath(os.path.join(os.path.expanduser("~"), 
                        ".mnemosyne"))

        print 'datadir=', datadir

        libmnemosyne.initialise(datadir)

        self.card_type = FrontToBack()
        self.database = database()
        self.saved = False
        
        if records:
            self.records = records
        else:
            self.records = -1

        if not category:
            category = "English-Russian"
        
        self.category = category #Category(category)

        self.controller = ui_controller_main()
Example #8
0
    def new_cards(self, grade):

        """Note that we don't rebuild revision queue afterwards, as this can
        cause corruption for the current card.  The new cards will show up
        after the old queue is empty."""

        try:
            fact_data = self.card_widget.get_data()
        except ValueError:
            return # Let the user try again to fill out the missing data.
        cat_names = [c.strip() for c in \
                        unicode(self.categories.currentText()).split(',')]
        card_type_name = unicode(self.card_types.currentText())
        card_type = self.card_type_by_name[card_type_name]
        c = ui_controller_main()
        c.create_new_cards(fact_data, card_type, grade, cat_names)
        self.update_combobox(', '.join(cat_names))
        database().save(config()['path'])
        self.card_widget.clear()
Example #9
0
 def update_status_bar(self, message=None):
     db = database()
     self.sched.setText(_("Scheduled: ") + \
                        str(db.scheduled_count()) + " ")
     self.notmem.setText(_("Not memorised: ") + \
                         str(db.non_memorised_count()) + " ")
     self.all.setText(_("All: ") \
                      + str(db.active_count()) + " ")
     if message:
         self.statusBar().showMessage(message)
Example #10
0
 def new_question(self, learn_ahead=False):
     if database().card_count() == 0:
         self.state = "EMPTY"
         self.card = None
     else:
         self.card = scheduler().get_new_question(learn_ahead)
         if self.card != None:
             self.state = "SELECT SHOW"
         else:
             self.state = "SELECT AHEAD"
     self.update_dialog()
     stopwatch.start()
Example #11
0
 def update_combobox(self, current_cat_name):
     no_of_categories = self.categories.count()
     for i in range(no_of_categories-1,-1,-1):
         self.categories.removeItem(i)
     self.categories.addItem(_("<default>"))
     for name in database().category_names():
         if name != _("<default>"):
             self.categories.addItem(name)
     if ',' in current_cat_name:
         self.categories.addItem(current_cat_name)      
     for i in range(self.categories.count()):
         if self.categories.itemText(i) == current_cat_name:
             self.categories.setCurrentIndex(i)
             break
Example #12
0
    def rebuild_queue(self, learn_ahead=False):

        self.queue = []
        datab = database()
        if not datab.is_loaded():
            return

        queue = CardQueue(limit=20)

        if learn_ahead:
            queue.mkgroup("learn ahead", limit=5)
            queue.add(datab.cards_learn_ahead(sort_key="next_rep"))

        else:
            queue.mkgroup("scheduled", limit=10, allow_dup=None)

            # limit amount of grade0 cards for the current group
            queue.setlimit(limit=config()["grade_0_items_at_once"], group="scheduled", grade=0)

            # add due_for_ret_rep generator
            queue.add(datab.cards_due_for_ret_rep(sort_key="interval"))

            # add final review generator, grade0
            queue.add(datab.cards_due_for_final_review(grade=0))

            # add final review generator, grade1
            queue.add(datab.cards_due_for_final_review(grade=1))

            # add new_memorizing generator, grade0
            new_mem = datab.cards_new_memorising(grade=0)
            queue.add(new_mem)

            # FIXME: HOW?
            # queue.add(iter(2*grade_0_selected))
            # queue.add(new_mem)
            # queue.add(new_mem)

            # The same for grade1
            new_mem = datab.cards_new_memorising(grade=1)
            queue.add(new_mem)

            # add cards_unseen generator
            queue.add(datab.cards_unseen(randomise=config()["randomise_new_cards"]))

            # FIXME: HOW???
            # grade_0_in_queue = sum(1 for i in self.queue if i.grade == 0)/2

        self.queue = [card for card in queue()]
Example #13
0
    def new_question(self, learn_ahead=False):
        """ Print new question """

        if database().card_count() == 0:
            raise CmdUiControllerException(_("Database is empty"))
        else:
            self.card = scheduler().get_new_question(learn_ahead)
            if self.card:
                print _("Question:"), self.card.question()
            else:
                value = raw_input(_("Learn ahead of schedule" + "? (y/N)"))
                if value in ("y", "Y"):
                    print("\n")
                    self.new_question(True)
                else:
                    raise CmdUiControllerException(_("Finished"))
Example #14
0
 def file_new(self):
     stopwatch.pause()
     out = self.widget.save_file_dialog(path=config().basedir,
                         filter=_("Mnemosyne databases (*.mem)"),
                         caption=_("New"))
     if not out:
         stopwatch.unpause()
         return
     if not out.endswith(".mem"):
         out += ".mem"
     db = database()
     db.unload()
     db.new(out)
     db.load(config()["path"])
     ui_controller_review().clear()
     ui_controller_review().update_dialog()
     stopwatch.unpause()
Example #15
0
    def update_related_cards(self, fact, new_fact_data, new_card_type, \
                             new_cat_names):
        # Allow this function to be overridden by a function hook.
        f = component_manager.get_current("function_hook", "update_related_cards")
        if f:
            return f.run()

        # Partial implementation. Still to do: change card type, duplicate checking.     
        db = database()
        new_cards, updated_cards = fact.card_type.update_related_cards(\
                                                new_fact_data, new_cat_names)
        db.update_fact(fact)
        for card in new_cards:
            db.add_card(card)
        for card in updated_cards:
            db.update_card(card)
        return
        
        if db.has_fact_with_data(fact_data):
            self.widget.information_box(\
              _("Card is already in database.\nDuplicate not added."), _("OK"))
            return
        fact = Fact(fact_data, card_type)
        duplicates = db.duplicates_for_fact(fact)
        if len(duplicates) != 0:
            answer = self.widget.question_box(\
              _("There is already data present for:\n\n") +
              "".join(fact[k] for k in card_type.required_fields()),
              _("&Merge and edit"), _("&Add as is"), _("&Do not add"))
            if answer == 0: # Merge and edit.
                merged_fact_data = copy.copy(fact.data)
                for duplicate in duplicates:
                    for key in fact_data:
                        if key not in card_type.required_fields():
                            merged_fact_data[key] += "/" + duplicate[key]
                    db.delete_fact_and_related_data(duplicate)
                print merged_fact_data
                # TODO: edit merged data.
                #dlg = EditItemDlg(new_item, self)
                #dlg.exec_loop()
                #get fact from that
            if answer == 2: # Don't add.
                return
        db.add_fact(fact)
        for card in card_type.create_related_cards(fact, grade):
            db.add_card(card)
Example #16
0
    def new_question(self, learn_ahead=False):
        """ Create new question """

        if not database().card_count():
            raise HildonUiControllerException(self.w_tree, \
                _("Database is empty"))

        card = scheduler().get_new_question(learn_ahead)

        if card:
            self.question.set_text(card.question())
        else:
            # FIXME value = raw_input(_("Learn ahead of schedule" + "? (y/N)"))
            self.new_question(True)
            #self.question.set_text(card.question())

        self.answer.set_text("")
        for widget in [getattr(self, "grade%i" % num) for num in range(6)]:
            widget.set_sensitive(False)
        self.get_answer.set_sensitive(True)
        self.card = card
Example #17
0
File: main.py Project: wojas/pomni
def main(argv):
    """ Main """

    opts, argv = parse_commandline(argv)

    # FIXME: move this to config module
    if opts.datadir:
        basedir = os.path.abspath(opts.datadir)
    elif os.path.exists(os.path.join(os.getcwdu(), ".pomni")):
        basedir = os.path.abspath(os.path.join(os.getcwdu(), ".pomni"))
    else:
        basedir = os.path.join(os.environ['HOME'], ".pomni")

    initialise(basedir)

    cdatabase = database()
    db_name = os.path.join(basedir, config()['path'])
    if os.path.exists(db_name):
        cdatabase.load(db_name)

    return ui_factory(opts.ui).start(opts.mode)
Example #18
0
    def create_new_cards(self, fact_data, card_type, grade, cat_names):

        """Create a new set of related cards."""

        # Allow this function to be overridden by a function hook.
        f = component_manager.get_current("function_hook", "create_new_cards")
        if f:
            return f.run()
        
        db = database()
        if db.has_fact_with_data(fact_data):
            self.widget.information_box(\
              _("Card is already in database.\nDuplicate not added."), _("OK"))
            return
        fact = Fact(fact_data, card_type)
        for cat_name in cat_names:
            fact.cat.append(db.get_or_create_category_with_name(cat_name))
        duplicates = db.duplicates_for_fact(fact)
        if len(duplicates) != 0:
            answer = self.widget.question_box(\
              _("There is already data present for:\n\n") +
              "".join(fact[k] for k in card_type.required_fields()),
              _("&Merge and edit"), _("&Add as is"), _("&Do not add"))
            if answer == 0: # Merge and edit.
                merged_fact_data = copy.copy(fact.data)
                for duplicate in duplicates:
                    for key in fact_data:
                        if key not in card_type.required_fields():
                            merged_fact_data[key] += "/" + duplicate[key]
                    db.delete_fact_and_related_data(duplicate)
                print merged_fact_data
                # TODO: edit merged data.
                #dlg = EditItemDlg(new_item, self)
                #dlg.exec_loop()
                #get fact from that
            if answer == 2: # Don't add.
                return
        db.add_fact(fact)
        for card in card_type.create_related_cards(fact, grade):
            db.add_card(card)
Example #19
0
File: card.py Project: wojas/pomni
    def set_initial_grade(self, grade):

        """This is called after manually adding cards. This code is separated
        out from the constructor, as for imported for imported cards, there is
        no grading information available when there are created, and the
        initial grading is done the first time they are are seen in
        the interactive review process (by similar code in the scheduler).

        This initial grading is seen as the first repetition.

        """

        db = database()
        sch = scheduler()
        self.grade = grade
        self.easiness = db.average_easiness()
        self.acq_reps = 1
        self.acq_reps_since_lapse = 1
        self.last_rep = db.days_since_start()
        new_interval = sch.calculate_initial_interval(grade)
        new_interval += sch.calculate_interval_noise(new_interval)
        self.next_rep = db.days_since_start() + new_interval
Example #20
0
def initialise_new_empty_database():
    from mnemosyne.libmnemosyne.component_manager import database
    filename = config()["path"]
    if not os.path.exists(os.path.join(config().basedir, filename)):
        database().new(os.path.join(config().basedir, filename))
Example #21
0
 def update_dialog(self, redraw_all=False):
     w = self.widget
     # Update title.
     database_name = os.path.basename(config()["path"])[:-4]
     title = _("Mnemosyne") + " - " + database_name
     w.set_window_title(title)
     # Update menu bar.
     if config()["only_editable_when_answer_shown"] == True:
         if self.card != None and self.state == "SELECT GRADE":
             w.enable_edit_current_card(True)
         else:
             w.enable_edit_current_card(False)
     else:
         if self.card != None:
             w.enable_edit_current_card(True)
         else:
             w.enable_edit_current_card(False)
     w.enable_delete_current_card(self.card != None)
     w.enable_edit_deck(database().card_count() > 0)
     # Hide/show the question and answer boxes.
     if self.state == "SELECT SHOW":
         w.question_box_visible(True)
         if self.card.fact_view.a_on_top_of_q:
             w.answer_box_visible(False)
     elif self.state == "SELECT GRADE":
         w.answer_box_visible(True)
         if self.card.fact_view.a_on_top_of_q:
             w.question_box_visible(False)
     else:
         w.question_box_visible(True)
         w.answer_box_visible(True)
     # Update question label.
     question_label_text = _("Question:")
     if self.card != None and self.card.fact.cat[0].name != _("<default>"):
         for c in self.card.fact.cat:
             question_label_text += " " + c.name
     w.set_question_label(question_label_text)
     # Update question content.
     if self.card == None:
         w.clear_question()
     elif self.state == "SELECT SHOW" or redraw_all == True:
         w.set_question(self.card.question())
     # Update answer content.
     if self.card == None or self.state == "SELECT SHOW":
         w.clear_answer()
     else:
         w.set_answer(self.card.answer())
     # Update 'Show answer' button.
     if self.state == "EMPTY":
         show_enabled, default, text = False, True, _("Show answer")
         grades_enabled = False
     elif self.state == "SELECT SHOW":
         show_enabled, default, text = True,  True, _("Show answer")
         grades_enabled = False
     elif self.state == "SELECT GRADE":
         show_enabled, default, text = False, True, _("Show answer")
         grades_enabled = True
     elif self.state == "SELECT AHEAD":
         show_enabled, default, text = True,  False, \
                                  _("Learn ahead of schedule")
         grades_enabled = False
     w.update_show_button(text, default, show_enabled)
     # Update grade buttons.
     if self.card != None and self.card.grade in [0,1]:
         i = 0 # Acquisition phase.
         default_4 = False
     else:
         i = 1 # Retention phase.
         default_4 = True
     w.enable_grades(grades_enabled)
     if grades_enabled:
         w.grade_4_default(default_4)            
     # Tooltips and texts for the grade buttons.
     for grade in range(0,6):
         # Tooltip.
         if self.state == "SELECT GRADE" and \
            config()["show_intervals"] == "tooltips":
             w.set_grade_tooltip(grade, tooltip[i][grade] +\
                 self.next_rep_string(scheduler().process_answer(self.card, \
                                     grade, dry_run=True)))
         else:
             w.set_grade_tooltip(grade, tooltip[i][grade])
         # Button text.
         if self.state == "SELECT GRADE" and \
            config()["show_intervals"] == "buttons":
             w.set_grade_text(grade, str(scheduler().process_answer(\
                                         self.card, grade, dry_run=True)))
             w.set_grades_title(_("Pick days until next repetition:"))
         else:
             w.set_grade_text(grade, str(grade))
             w.set_grades_title(_("Grade your answer:"))
         # TODO: accelerator update needed?
         #self.grade_buttons[grade].setAccel(QKeySequence(str(grade)))
     # Update status bar.
     ui_controller_main().widget.update_status_bar()
     # Run possible update code that independent of the controller state.
     # TODO: remove when migration is complete.
     w.update_dialog()
Example #22
0
 def process_answer(self, card, new_grade, dry_run=False):
     db = database()
     days_since_start = db.days_since_start()
     # When doing a dry run, make a copy to operate on. Note that this
     # leaves the original in cards and the reference in the GUI intact.
     if dry_run:
         card = copy.copy(card)
     # Calculate scheduled and actual interval, taking care of corner
     # case when learning ahead on the same day.
     scheduled_interval = card.next_rep - card.last_rep
     actual_interval = days_since_start - card.last_rep
     if actual_interval == 0:
         actual_interval = 1 # Otherwise new interval can become zero.
     if  (card.acq_reps == 0) and (card.ret_reps == 0):
         # The card has not yet been given its initial grade, because it
         # was imported.
         card.easiness = db.average_easiness()
         card.acq_reps = 1
         card.acq_reps_since_lapse = 1
         new_interval = calculate_initial_interval(new_grade)
         # Make sure the second copy of a grade 0 card doesn't show
         # up again.
         if not dry_run and card.grade == 0 and new_grade in [2,3,4,5]:
             for i in self.queue:
                 if i.id == card.id:
                     self.queue.remove(i)
                     break
     elif card.grade in [0,1] and new_grade in [0,1]:
         # In the acquisition phase and staying there.
         card.acq_reps += 1
         card.acq_reps_since_lapse += 1
         new_interval = 0
     elif card.grade in [0,1] and new_grade in [2,3,4,5]:
          # In the acquisition phase and moving to the retention phase.
          card.acq_reps += 1
          card.acq_reps_since_lapse += 1
          new_interval = 1
          # Make sure the second copy of a grade 0 card doesn't show
          # up again.
          if not dry_run and card.grade == 0:
              for i in self.queue:
                  if i.id == card.id:
                      self.queue.remove(i)
                      break
     elif card.grade in [2,3,4,5] and new_grade in [0,1]:
          # In the retention phase and dropping back to the
          # acquisition phase.
          card.ret_reps += 1
          card.lapses += 1
          card.acq_reps_since_lapse = 0
          card.ret_reps_since_lapse = 0
          new_interval = 0
     elif card.grade in [2,3,4,5] and new_grade in [2,3,4,5]:
         # In the retention phase and staying there.
         card.ret_reps += 1
         card.ret_reps_since_lapse += 1
         if actual_interval >= scheduled_interval:
             if new_grade == 2:
                 card.easiness -= 0.16
             if new_grade == 3:
                 card.easiness -= 0.14
             if new_grade == 5:
                 card.easiness += 0.10
             if card.easiness < 1.3:
                 card.easiness = 1.3
         new_interval = 0
         if card.ret_reps_since_lapse == 1:
             new_interval = 6
         else:
             if new_grade == 2 or new_grade == 3:
                 if actual_interval <= scheduled_interval:
                     new_interval = actual_interval * card.easiness
                 else:
                     new_interval = scheduled_interval
             if new_grade == 4:
                 new_interval = actual_interval * card.easiness
             if new_grade == 5:
                 if actual_interval < scheduled_interval:
                     new_interval = scheduled_interval # Avoid spacing.
                 else:
                     new_interval = actual_interval * card.easiness
         # Shouldn't happen, but build in a safeguard.
         if new_interval == 0:
             print "Internal error: new interval was zero."
             new_interval = scheduled_interval
         new_interval = int(new_interval)
     # When doing a dry run, stop here and return the scheduled interval.
     if dry_run:
         return new_interval
     # Add some randomness to interval.
     noise = self.calculate_interval_noise(new_interval)
     # Update grade and interval.
     card.grade = new_grade
     card.last_rep = days_since_start
     card.next_rep = days_since_start + new_interval + noise
     card.unseen = False
     # Don't schedule related cards on the same day.
     for c in db.cards_from_fact(card.fact):
         if c != card and c.next_rep == card.next_rep and card.grade >= 2:
             card.next_rep += 1
             noise += 1
     db.update_card(card)
     # Create log entry.
     log().revision(card, scheduled_interval, actual_interval,
                    new_interval, noise)
     return new_interval + noise
Example #23
0
 def new_card(self, card):
     new_interval = database().days_since_start() - card.next_rep
     self.logger.info("New item %s %d %d", card.id, card.grade, new_interval)
Example #24
0
 def rebuild_queue(self, learn_ahead=False):
     self.queue = []
     db = database()
     if not db.is_loaded():
         return
     # Do the cards that are scheduled for today (or are overdue), but
     # first do those that have the shortest interval, as being a day
     # late on an interval of 2 could be much worse than being a day late
     # on an interval of 50.
     self.queue = list(db.cards_due_for_ret_rep(sort_key="interval"))
     if len(self.queue) != 0:
         return
     # Now rememorise the cards that we got wrong during the last stage.
     # Concentrate on only a limited number of grade 0 cards, in order to
     # avoid too long intervals between revisions. If there are too few
     # cards in left in the queue, append more new cards to keep some
     # spread between these last cards. Also limit the queue size to 10
     # in order not to have too large a spread.
     limit = config()["grade_0_items_at_once"]
     grade_0 = db.cards_due_for_final_review(grade=0)
     grade_0_selected = []
     if limit != 0:
         for i in grade_0:
             for j in grade_0_selected:
                 if i.fact == j.fact:
                     break
             else:
                 grade_0_selected.append(i)
             if len(grade_0_selected) == limit:
                 break
     grade_1 = list(db.cards_due_for_final_review(grade=1))
     self.queue += 2*grade_0_selected + grade_1
     random.shuffle(self.queue)
     if len(grade_0_selected) == limit or len(self.queue) >= 10:
         return
     # Now do the cards which have never been committed to long-term
     # memory, but which we have seen before. Also limit the queue size
     # to 10 in order not to have too large a spread.
     grade_0 = db.cards_new_memorising(grade=0)
     grade_0_in_queue = len(grade_0_selected)
     grade_0_selected = []
     if limit != 0:
         for i in grade_0:
             for j in grade_0_selected:
                 if i.fact == j.fact:
                     break
             else:
                 grade_0_selected.append(i)
             if len(grade_0_selected) + grade_0_in_queue == limit:
                 break
     grade_1 = list(db.cards_new_memorising(grade=1))
     self.queue += 2*grade_0_selected + grade_1
     random.shuffle(self.queue)
     if len(grade_0_selected) + grade_0_in_queue == limit or \
        len(self.queue) >= 10:
         return
     # Now add some new cards. This is a bit inefficient at the moment as
     # 'unseen' is wastefully created as opposed to being a generator
     # expression. However, in order to use random.choice, there doesn't
     # seem to be another option.
     unseen = list(db.cards_unseen())
     grade_0_in_queue = sum(1 for i in self.queue if i.grade == 0)/2
     grade_0_selected = []
     if limit != 0 and len(unseen) != 0:
         while True:
             if config()["randomise_new_cards"] == False:
                 new_card = unseen[0]
             else:
                 new_card = random.choice(unseen)
             unseen.remove(new_card)
             for i in grade_0_selected:
                 if new_card.fact == i.fact:
                     break
             else:
                 grade_0_selected.append(new_card)
             if len(unseen) == 0 or \
                    len(grade_0_selected) + grade_0_in_queue == limit:
                 self.queue += grade_0_selected
                 return
     # If we get to here, there are no more scheduled cards or new cards
     # to learn. The user can signal that he wants to learn ahead by
     # calling rebuild_revision_queue with 'learn_ahead' set to True.
     # Don't shuffle this queue, as it's more useful to review the
     # earliest scheduled cards first. We only put 5 cards at the same
     # time into the queue, in order to save memory.
     # TODO: this requires the user to click 'learn ahead of schedule'
     # again after 5 cards. If it's possible to make this algorithm
     # stateless and return 1 card at the time, this will be solved
     # automatically.
     if learn_ahead == False:
         return
     else:
         for card in db.cards_learn_ahead(sort_key="next_rep"):
             self.queue.append(card)
             if len(self.queue) >= 5:
                 return
Example #25
0
 def saved_database(self):
     self.logger.info("Saved database %d %d %d", \
                      database().scheduled_count(), \
                      database().non_memorised_count(), \
                      database().card_count())