Beispiel #1
0
 def load(self, path):
     path = expand_path(path, config().basedir)
     if self.is_loaded():
         unload_database()
     if not os.path.exists(path):
         self.load_failed = True
         raise LoadError
     try:
         infile = file(path, 'rb')
         db = cPickle.load(infile)
         self.start_date = db[0]
         self.categories = db[1]
         self.facts = db[2]
         self.fact_views = db[3]           
         self.cards = db[4]
         infile.close()
         self.load_failed = False
     except:
         self.load_failed = True
         raise InvalidFormatError(stack_trace=True)
     # Work around a sip bug: don't store card types, but their ids.
     for f in self.facts:
         f.card_type = card_type_by_id(f.card_type)
     # TODO: This was to remove database inconsistencies. Still needed?
     #for c in self.categories:
     #    self.remove_category_if_unused(c)
     config()["path"] = contract_path(path, config().basedir)
     log().loaded_database()
     for f in component_manager.get_all("function_hook", "after_load"):
         f.run()
Beispiel #2
0
def contract_path(p, prefix=None):

    """Make absolute path relative and normalise slashes."""

    # By default, make paths relative to the database location.
    if prefix == None:
        prefix = os.path.dirname(config()["path"])
    # If there was no dirname in the last statement, it was a relative
    # path and we set the prefix to the basedir.
    if prefix == '':
        prefix = config().basedir
    # Normalise paths and convert everything to lowercase on Windows.
    p = os.path.normpath(p)
    prefix = os.path.normpath(prefix)
    if ( (len(p) > 2) and p[1] == ":"):
        p = p.lower()
        prefix = prefix.lower()
    # Do the actual detection.
    if (    ( (len(p) > 1) and p[0] == "/") \
         or ( (len(p) > 2) and p[1] == ":") ): # Unix or Windows absolute path.
        try:
            return p.split(prefix)[1][1:]
        except:
            return p            
    else:
        return p
Beispiel #3
0
 def new(self, path):
     if self.is_loaded():
         self.unload()
     self.load_failed = False
     self.start_date = StartDate()
     config()["path"] = path
     log().new_database()
     self.save(contract_path(path, config().basedir))
Beispiel #4
0
 def closeEvent(self, event):
     try:
         config().save()
         database().backup()
         database().unload()
     except MnemosyneError, e:
         self.error_box(e)
         event.ignore()
Beispiel #5
0
    def update_dialog(self):
        # Update question and answer font.

        if config()["QA_font"] != None:
            font = QFont()
            font.fromString(config()["QA_font"])
        else:
            font = self.show_button.font()
Beispiel #6
0
 def insert_sound(self):
     path = expand_path(config()["import_sound_dir"])
     fname = unicode(QFileDialog.getOpenFileName(self, _("Insert sound"),
                     path, _("Sound files") + \
                     " (*.wav *.mp3 *.ogg *.WAV *.MP3 *.OGG)"))
     if fname:
         self.insertPlainText("<sound src=\""+contract_path(fname)+"\">")
         config()["import_sound_dir"] = \
                    contract_path(os.path.dirname(fname))
Beispiel #7
0
 def insert_img(self):
     path = expand_path(config()["import_img_dir"])
     fname = unicode(QFileDialog.getOpenFileName(self, _("Insert image"),
                     path, _("Image files") + \
                     " (*.png *.gif *.jpg *.bmp *.jpeg" + \
                     " *.PNG *.GIF *.jpg *.BMP *.JPEG)"))
     if fname:
         self.insertPlainText("<img src=\""+contract_path(fname)+"\">")
         config()["import_img_dir"] = \
                    contract_path(os.path.dirname(fname))
Beispiel #8
0
def initialise(basedir):
    
    """Note: running user plugins is best done after the GUI has been created,
    in order to be able to provide feedback about errors to the user."""

    initialise_system_components()
    config().initialise(basedir)
    initialise_logging()
    initialise_lockfile()
    initialise_new_empty_database()
    initialise_error_handling()
Beispiel #9
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()]
Beispiel #10
0
def ui_factory(interface=None):
    """ Create UI(View in terms of MVC) """

    if interface == 'cmd':
        from pomni.cmd_ui import CmdUiControllerReview, CommandlineUI

        component_manager.register("ui_controller_review",
                                   CmdUiControllerReview())
        component_manager.register("renderer", TextRenderer())
        return CommandlineUI()

    if not interface or interface == "hildon":
        try:
            theme = config()["theme_path"].split("/")[-1]
        except KeyError:
            theme = "eternal"

        from pomni import hildon_ui
        from hildon_ui import HildonUI

        review_class = getattr(hildon_ui,
            theme.capitalize() + 'ControllerReview')
        input_class = getattr(hildon_ui,
            theme.capitalize() + 'ControllerInput')
        main_class = getattr(hildon_ui,
            theme.capitalize() + 'ControllerMain')

        component_manager.register("ui_controller_main", main_class())
        component_manager.register("ui_controller_review", review_class())
        component_manager.register("ui_controller_input", input_class())
        component_manager.register("renderer", TextRenderer())
        return HildonUI()

    # add next gui here
    raise ValueError("No idea how to create %s UI" % interface)
Beispiel #11
0
 def run(self):
     basedir = config().basedir
     join = os.path.join
     # Find out which files haven't been uploaded yet.
     dir = os.listdir(unicode(join(basedir, "history")))
     history_files = [x for x in dir if x[-4:] == ".bz2"]
     uploaded = None
     try:
         upload_log = file(join(basedir, "history", "uploaded"))
         uploaded = [x.strip() for x in upload_log]
         upload_log.close()
     except:
         uploaded = []
     to_upload = sets.Set(history_files) - sets.Set(uploaded)
     if len(to_upload) == 0:
         return
     # Upload them to our server.
     upload_log = file(join(basedir, "history", "uploaded"), 'a')
     try:
         for f in to_upload:
             print "Uploading", f, "...",
             filename = join(basedir, "history", f)
             self.upload(filename)
             print >> upload_log, f
             log().uploaded(filename)
             print "done!"           
     except:
         log().uploading_failed()
         traceback.print_exc()
     upload_log.close()
Beispiel #12
0
def expand_path(p, prefix=None):

    """Make relative path absolute and normalise slashes."""
    
    # By default, make paths relative to the database location.
    if prefix == None:
        prefix = os.path.dirname(config()["path"])
    # If there was no dirname in the last statement, it was a relative
    # path and we set the prefix to the basedir.
    if prefix == '':
        prefix = config().basedir
    if (    ( (len(p) > 1) and p[0] == "/") \
         or ( (len(p) > 2) and p[1] == ":") ): # Unix or Windows absolute path.
        return os.path.normpath(p)
    else:  
        return os.path.normpath(os.path.join(prefix, p))
Beispiel #13
0
    def __init__(self):
        """ Initialization items of review window """

        HildonBaseUi.__init__(self, signals=[])

        self.title = _("Mnemosyne") + " - " + \
            splitext(basename(config()["path"]))[0]
Beispiel #14
0
 def __init__(self, parent=None):
     QDialog.__init__(self, parent)
     # TODO: modal, Qt.WStyle_MinMax | Qt.WStyle_SysMenu))?
     self.setupUi(self)
     # We calculate card_type_by_name here rather than in the component
     # manager, because these names can change if the user chooses another
     # translation. TODO: test.
     self.card_type_by_name = {}
     for card_type in card_types():
         self.card_types.addItem(card_type.name)
         self.card_type_by_name[card_type.name] = card_type
     # TODO: sort card types by id.
     # TODO: remember last type.
     
     self.card_widget = None
     self.update_card_widget()
     
     self.update_combobox(config()["last_add_category"])
     self.grades = QButtonGroup()
     self.grades.addButton(self.grade_0_button, 0)
     self.grades.addButton(self.grade_1_button, 1)
     self.grades.addButton(self.grade_2_button, 2)
     self.grades.addButton(self.grade_3_button, 3)
     self.grades.addButton(self.grade_4_button, 4)
     self.grades.addButton(self.grade_5_button, 5)
     self.connect(self.grades, SIGNAL("buttonClicked(int)"),
                  self.new_cards)
Beispiel #15
0
    def __init__(self):

        UiControllerReview.__init__(self, name="Command line UI Controller")
        self.title = _("Mnemosyne") + " - " + \
            os.path.basename(config()["path"])[:-4]
        self.grade = 0
        self.card = None
Beispiel #16
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
Beispiel #17
0
 def file_save(self):
     stopwatch.pause()
     path = config()["path"]
     try:
         database().save(path)
     except MnemosyneError, e:
         self.widget.error_box(e)
Beispiel #18
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()
Beispiel #19
0
 def start_logging(self):
     basedir = config().basedir
     log_name = os.path.join(basedir, "log.txt")
     self.logger.setLevel(logging.INFO)
     fh = logging.FileHandler(log_name)
     formatter = logging.Formatter("%(asctime)s %(message)s",
                               "%Y-%m-%d %H:%M:%S :")
     fh.setFormatter(formatter)
     self.logger.addHandler(fh)
Beispiel #20
0
def initialise_logging():
    global upload_thread
    from mnemosyne.libmnemosyne.log_uploader import LogUploader
    log().archive_old_log()
    log().start_logging()
    log().program_started()
    if config()["upload_logs"]:
        upload_thread = LogUploader()
        upload_thread.start()
Beispiel #21
0
 def unload(self):
     self.save(config()["path"])
     log().saved_database()
     self.start_date = None
     self.categories = []
     self.facts = []
     self.fact_views = []
     self.cards = []
     scheduler().clear_queue()
     return True
Beispiel #22
0
def initialise_user_plugins():
    basedir = config().basedir
    plugindir = unicode(os.path.join(basedir, "plugins"))
    sys.path.insert(0, plugindir)
    for plugin in os.listdir(plugindir):
        if plugin.endswith(".py"):
            try:
                __import__(plugin[:-3])
            except:
                raise PluginError(stack_trace=True)
Beispiel #23
0
    def __init__(self):
        """ Load theme's glade file """

        theme_path = config()["theme_path"]
        gtk.rc_parse(os.path.join(theme_path, "rcfile"))
        self.w_tree = gtk.glade.XML(os.path.join(theme_path, "window.glade"))

        # Set unvisible tabs of switcher
        switcher = self.w_tree.get_widget("switcher")
        switcher.set_property('show_tabs', False)
Beispiel #24
0
 def archive_old_log(self):
     
     """Archive log to history folder if it's large enough."""
     
     basedir = config().basedir
     log_name = os.path.join(basedir, "log.txt")
     try:
         log_size = os.stat(log_name).st_size
     except:
         log_size = 0
     if log_size > 64000:
         user  = config()["user_id"]
         index = config()["log_index"]
         archive_name = "%s_%05d.bz2" % (user, index)
         f = bz2.BZ2File(os.path.join(basedir, "history", archive_name), 'w')
         for l in file(log_name):
             f.write(l)
         f.close()
         os.remove(log_name)
         config()["log_index"] = index + 1
Beispiel #25
0
    def days_since_start(self):

        """Note that this should be cached as much as possible for
        efficiency reasons.

        """

        h = config()["day_starts_at"]
        adjusted_start = self.start.replace(hour=h, minute=0, second=0)
        dt = datetime.datetime.now() - adjusted_start
        return dt.days
Beispiel #26
0
    def __init__(self):
        """ Initialization items of review window """

        HildonBaseUi.__init__(self, signals=["get_answer", "grade"])
        UiControllerReview.__init__(self, name="Hildon UI Review Controller")

        self.title = _("Mnemosyne") + " - " + \
            splitext(basename(config()["path"]))[0]

        self.grade = 0
        self.card = None
Beispiel #27
0
def finalise():
    global upload_thread
    if upload_thread:
        print "Waiting for uploader thread to stop..."
        upload_thread.join()
        print "done!"
    log().program_stopped()
    try:
        os.remove(os.path.join(config().basedir,"MNEMOSYNE_LOCK"))
    except OSError:
        print "Failed to remove lock file."
        print traceback_string()
Beispiel #28
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            
Beispiel #29
0
 def save(self, path):
     path = expand_path(path, config().basedir)
     # Work around a sip bug: don't store card types, but their ids.
     for f in self.facts:
         f.card_type = f.card_type.id
     # Don't erase a database which failed to load.
     if self.load_failed == True:
         return
     try:
         # Write to a backup file first, as shutting down Windows can
         # interrupt the dump command and corrupt the database.
         outfile = file(path + "~", 'wb')
         db = [self.start_date, self.categories, self.facts, self.fact_views,
               self.cards]
         cPickle.dump(db, outfile)
         outfile.close()
         shutil.move(path + "~", path) # Should be atomic.
     except:
         print traceback_string()
         raise SaveError()
     config()["path"] = contract_path(path, config().basedir)
     # Work around sip bug again.
     for f in self.facts:
         f.card_type = card_type_by_id(f.card_type)
Beispiel #30
0
    def load(self, fname):
        """Load database from file."""

        # Unload opened database if exists
        self.unload()

        self.path = expand_path(fname, config().basedir)
        try:
            res = self.conn.execute("select value from meta where key=?",
                ("start_date", )).fetchone()
            self.load_failed = False
            self.set_start_date(StartDate(datetime.strptime(res["value"],
                "%Y-%m-%d %H:%M:%S")))
            self.load_failed = False
        except sqlite.OperationalError:
            self.load_failed = True