Example #1
0
def update_typer_html(typer, errors):
    '''Organizational function.

Given a Typer, updates its html based on settings (not including invisible mode)'''
    #dict : str -> str ; original and displacement strs in error region (for easier display)
    v = unicode(typer.toPlainText())
    v_err_replacements = {}
    if Settings.get('text_area_replace_spaces'):
        #if want to make replacements change spaces in text area as well (risky!)
        v_err_replacements.update(
            space_replacement_dict_from_setting(
                'text_area_mistakes_space_char'))

    if Settings.get('text_area_replace_return'):
        #want to make replacements change returns in text area as well (a little less risky since there's usually fewer)
        v_err_replacements["\n"] = Settings.get('text_area_return_replacement')

    error_colors = {}  #dict : int -> str, mapping errors to color
    v_replaced_list = list(
        v)  #list of strs, initially one char each, to operate on
    v_replaced_list = html_list_process_spaces(v_replaced_list)

    if Settings.get("show_text_area_mistakes"):
        error_colors = dict(
            map(lambda i: (i, Settings.get('text_area_mistakes_color')),
                errors))
        v_replaced_list = replace_at_locs(v_replaced_list, v_err_replacements,
                                          errors)

    v_colored_list = html_color_strs(v_replaced_list, error_colors)
    htmlized = "".join(v_colored_list).replace("\n", "<BR>")
    set_typer_html(typer, htmlized)
Example #2
0
def to_lessons(sentences):
    backlog = []
    backlen = 0
    min_chars = Settings.get('min_chars')
    max_chars = Settings.get('max_chars')
    sweet_size = 3*(min_chars + max_chars) // 4

    for s in sentences:
        ssplit = []
        while len(s) > sweet_size:
            idx = s.find(' ', sweet_size)
            if idx == -1:
                break
            if idx != -1:
                ssplid.append(s[:idx])
                s = s[idx+1:]
        ssplit.append(s)
        for xs in ssplit:
            backlog.append(xs)
            backlen += len(xs)
            if backlen >= min_chars:
                yield u' '.join(backlog)
                backlog = []
                backlen = 0
    if backlen > 0:
        yield u' '.join(backlog)
Example #3
0
    def cleanup(self):
        s_in_day = 24*60*60
        now = time.time()
        pending = []

        for idx, grp, lim in [
                (1, 30, Settings.get("group_month")),
                (2, 7, Settings.get("group_week")),
                (3, 1, Settings.get("group_day")),
            ]:

            minimum = now - s_in_day * lim
            binsize = s_in_day * grp

            pending.extend(DB.fetchall(f"""
                select avg(w), data, type, agg_mean(time, count), sum(count), sum(mistakes),
                    agg_median(viscosity)
                from statistic where w <= {minimum}
                group by data, type, cast(w/{binsize} as int)"""))
            self.progressbar.set_fraction(idx/5)

        DB.executemany("""insert into statistic (w, data, type, time, count, mistakes, viscosity)
            values (?,?,?,?,?,?,?)""", pending)
        self.progressbar.set_fraction(4/5)
        # FIXME vacuum not supported
        # DB.execute("vacuum")
        self.progressbar.set_fraction(5/5)
        DB.commit()
        self.progressbar.set_fraction(0)
Example #4
0
    def __init__(self):
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)

        self.result = Gtk.Label()
        self.typer = Typer()
        self.label = Gtk.Label(wrap=True, xalign=0, yalign=1)

        update_result_vis = lambda: self.result.set_visible(
            Settings.get("show_last"))
        update_result_vis()

        sync_font = lambda: self.label.override_font(
            Pango.FontDescription.from_string(Settings.get("typer_font")))
        sync_font()

        self.typer.connect("done", lambda *_: self.done())
        self.typer.connect("want-text", lambda *_: self.emit("want-text"))
        Settings.connect("change_typer_font", sync_font)
        Settings.connect("change_show_last", update_result_vis)

        self.text = ("", 0, "")

        self.pack_start(self.result, False, False, 0)
        body = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,
                       homogeneous=True,
                       spacing=24)
        body.add(self.label)
        body.add(self.typer)
        self.pack_start(body, True, True, 0)
Example #5
0
def to_lessons(sentences):
    backlog = []
    backlen = 0
    min_chars = Settings.get('min_chars')
    max_chars = Settings.get('max_chars')
    sweet_size = 3 * (min_chars + max_chars) // 4

    for s in sentences:
        ssplit = []
        while len(s) > sweet_size:
            idx = s.find(' ', sweet_size)
            if idx == -1:
                break
            if idx != -1:
                ssplid.append(s[:idx])
                s = s[idx + 1:]
        ssplit.append(s)
        for xs in ssplit:
            backlog.append(xs)
            backlen += len(xs)
            if backlen >= min_chars:
                yield ' '.join(backlog)
                backlog = []
                backlen = 0
    if backlen > 0:
        yield ' '.join(backlog)
Example #6
0
    def filter_words(self, words):
        num = Settings.get('str_extra')
        what = Settings.get('str_what')
        if what == 'r': # random
            pass
        else:
            control = self.get_list()
            if not control:
                return
            if what == 'e': # encompassing
                stream = [(sum([x.count(c) for c in control]), x) for x in words]
                #print "str:", list(stream)[0:10]
                preres = list(itertools.islice(filter(lambda x: x[0] > 0, stream), 4*num))
                #print "pre:", preres
                preres.sort(key=lambda x: x[0], reverse=True)
                words = [x[1] for x in preres]
            else: # similar
                words = filter(lambda x:
                               0 < min(
                                   editdist.distance(
                                       x.encode('latin1', 'replace'),
                                       y.encode('latin1', 'replace'))/max(len(y), len(x))
                                   for y in control) < .26, words)

        if Settings.get('str_clear') == 'r': # replace = clear
            GtkUtil.textbuf_clear(self.buf())

        self.add_list(itertools.islice(words, num))
Example #7
0
def to_lessons(sentences):
    backlog = []
    backlen = 0
    min_chars = Settings.get('min_chars')
    max_chars = Settings.get('max_chars')
    sweet_size = 3 * (min_chars + max_chars) // 4

    for sent in sentences:
        ssplit = []
        while len(sent) > sweet_size:
            idx = sent.find(' ', sweet_size)
            if idx == -1:
                break
            ssplit.append(sent[:idx])
            sent = sent[idx + 1:]

        ssplit.append(sent)
        for part in ssplit:
            backlog.append(part)
            backlen += len(part)
            if backlen >= min_chars:
                yield ' '.join(backlog)
                backlog = []
                backlen = 0

    if backlen:
        yield ' '.join(backlog)
def update_typer_html(typer,errors):
    '''Organizational function.

Given a Typer, updates its html based on settings (not including invisible mode)'''
    #dict : str -> str ; original and displacement strs in error region (for easier display)
    v = unicode(typer.toPlainText())
    v_err_replacements = {}
    if Settings.get('text_area_replace_spaces'):
        #if want to make replacements change spaces in text area as well (risky!)
        v_err_replacements.update(space_replacement_dict_from_setting('text_area_mistakes_space_char'))
        
    if Settings.get('text_area_replace_return'):
        #want to make replacements change returns in text area as well (a little less risky since there's usually fewer)
        v_err_replacements["\n"] = Settings.get('text_area_return_replacement')
    
    error_colors = {} #dict : int -> str, mapping errors to color
    v_replaced_list = list(v)  #list of strs, initially one char each, to operate on
    v_replaced_list = html_list_process_spaces(v_replaced_list)

    if Settings.get("show_text_area_mistakes"):
        error_colors = dict(map(lambda i : (i,Settings.get('text_area_mistakes_color')),errors))
        v_replaced_list = replace_at_locs(v_replaced_list,v_err_replacements,errors)

    v_colored_list = html_color_strs(v_replaced_list,error_colors)
    htmlized = "".join(v_colored_list).replace("\n","<BR>")
    set_typer_html(typer,htmlized)
Example #9
0
 def __init__(self, fname):
     super(LessonMiner, self).__init__()
     with codecs.open(fname, "r", "utf_8_sig") as f:
         self.text = f.read()
     self.lessons = None
     self.min_chars = Settings.get('min_chars')
     self.split_regex = Settings.get('sentence_regex')
     self.split = re.compile(self.split_regex).split(self.text)
Example #10
0
 def __init__(self, fname):
     super(LessonMiner, self).__init__()
     with codecs.open(fname, "r", "utf_8_sig") as f:
         self.text = f.read()
     self.lessons = None
     self.min_chars = Settings.get('min_chars')
     self.split_regex = Settings.get('sentence_regex')
     self.split = re.compile(self.split_regex).split(self.text)
Example #11
0
    def paras(self, f):
        p = []
        ps = []
        previous_line_empty = True
        for l in f:
            #designated replacements for unicode text
            if Settings.get('transliteration_manual_unicode'):
                for orig, repl in unicode_replacements:
                    l = l.replace(orig, repl)

            ascii_line = l
            if unidecode_imported and Settings.get(
                    'transliteration_method'
            ) == INDEX_TRANSLITERATION_UNIDECODE:
                #tries to use unidecode if it exists
                ascii_line = unidecode.unidecode(ascii_line)
            elif Settings.get(
                    'transliteration_method') == INDEX_TRANSLITERATION_DELETE:
                #deletes all remaining non-ascii chars
                try:
                    ascii_line = ascii_line.decode('ascii')
                except UnicodeEncodeError:
                    ascii_line = ''
                    for c in l:
                        if ord(c) < 128:
                            ascii_line += c
                        else:
                            ascii_line += ""

            #replaces any 1+ adjacent whitespace chars (spaces, tabs, newlines, etc) with one ascii space
            if Settings.get('single_space_only'):
                ascii_line = re.sub("\s+", " ", ascii_line)

            #designated replacements for ascii text
            if Settings.get('transliteration_manual_ascii'):
                for orig, repl in ascii_replacements:
                    ascii_line = ascii_line.replace(orig, repl)

            l = ascii_line.strip()
            current_line_empty = not l

            #the current line is empty: insert empty line
            #or the current line and previous line both nonempty: need to insert empty line between them
            if (current_line_empty or not previous_line_empty) and len(p) > 0:
                ps.append(SentenceSplitter(u" ".join(p)))
                p = []

            if not current_line_empty:
                p.append(l)

            previous_line_empty = current_line_empty
        if len(p) > 0:
            ps.append(SentenceSplitter(u" ".join(p)))
        return ps
Example #12
0
    def update_data(self):
        if self.editflag:
            return
        where = []
        where_query = ""
        selected = self.cb_source.get_active_id()
        if selected == "last text":
            where.append(
                "r.text_id = (select text_id from result order by w desc limit 1)"
            )
        elif selected == "all texts":
            where.append("s.discount is null")
        elif selected == "all lessons":
            where.append("s.discount is not null")
        elif selected and selected.isdigit():
            rowid = int(selected)
            where.append(f"r.source = {rowid}")

        if where:
            where_query = "where " + " and ".join(where)

        sql_template = """select agg_first(text_id),avg(r.w) as w,count(r.rowid)
                || ' result(s)',agg_median(r.wpm),
                100.0*agg_median(r.accuracy),agg_median(r.viscosity)
            from result as r left join source as s on (r.source = s.rowid)
            %s %s
            order by w desc limit %d"""

        groupby = Settings.get("perf_group_by")
        group = ""
        print(groupby)
        if groupby == 1:  # by def_group_by
            DB.reset_counter()
            group = "group by cast(counter()/%d as int)" % max(
                Settings.get("def_group_by"), 1)
        elif groupby == 2:  # by sitting
            mis = Settings.get("minutes_in_sitting") * 60.0
            DB.reset_time_group()
            group = "group by time_group(%f, r.w)" % mis
        elif groupby == 3:  # by day
            group = "group by cast((r.w+4*3600)/86400 as int)"
        elif not groupby:  # no grouping
            sql_template = """select text_id,w,s.name,wpm,100.0*accuracy,viscosity
                from result as r left join source as s on (r.source = s.rowid)
                %s %s
                order by w desc limit %d"""

        items = Settings.get("perf_items")

        sql = sql_template % (where_query, group, items)
        self.model.set_stats([list(r) for r in DB.fetchall(sql)])
        self.update_graph()
Example #13
0
def generate_automatic_insertion_regex():
    '''From settings info, returns the regex for which to re.match the automatically inserted chars

Or None if no chars are to be automatically inserted.'''
    #the str of characters (in regex-escaped form, but not regex) to automatically insert
    automatically_inserted_chars = ""
    if Settings.get('use_automatic_other_insertion'):
        automatically_inserted_chars += re.escape(Settings.get('automatic_other_insertion'))
    for s,c in ('automatic_space_insertion',u" "),('automatic_return_insertion',u"\n"):
        if Settings.get(s):
            automatically_inserted_chars += re.escape(c)

    return "[{0}]+".format(automatically_inserted_chars) if automatically_inserted_chars else None
Example #14
0
        def color_position(settings_color_var, use_space_var, space_var):
            '''Colors position with the color stored in settings_color_var.
            
strs use_space_var and space_var are settings variables to look up.
If [setting] use_space_var, space at position is replaced with [setting] space_var

Returns the new text_strs list (for assignment).'''
            colors[position] = Settings.get(settings_color_var)

            if Settings.get(use_space_var):
                return replace_at_locs(text_strs,space_replacement_dict_from_setting(space_var),[position])
            else:
                return text_strs
Example #15
0
    def paras(self, f):
        p = []
        ps = []
        previous_line_empty = True
        for l in f:
            #designated replacements for unicode text
            if Settings.get('transliteration_manual_unicode'):
                for orig, repl in unicode_replacements:
                    l = l.replace(orig, repl)
                    
            ascii_line = l
            if unidecode_imported and Settings.get('transliteration_method') == INDEX_TRANSLITERATION_UNIDECODE:
                #tries to use unidecode if it exists
                ascii_line = unidecode.unidecode(ascii_line)
            elif Settings.get('transliteration_method') == INDEX_TRANSLITERATION_DELETE:
                #deletes all remaining non-ascii chars
                try:
                    ascii_line = ascii_line.decode('ascii')
                except UnicodeEncodeError:
                    ascii_line = ''
                    for c in l:
                        if ord(c) < 128:
                            ascii_line += c
                        else:
                            ascii_line += ""

            #replaces any 1+ adjacent whitespace chars (spaces, tabs, newlines, etc) with one ascii space
            if Settings.get('single_space_only'): 
                ascii_line = re.sub("\s+"," ",ascii_line)               

            #designated replacements for ascii text
            if Settings.get('transliteration_manual_ascii'):
                for orig, repl in ascii_replacements:
                    ascii_line = ascii_line.replace(orig, repl) 

            l = ascii_line.strip()
            current_line_empty = not l
           
            #the current line is empty: insert empty line 
            #or the current line and previous line both nonempty: need to insert empty line between them
            if (current_line_empty or not previous_line_empty) and len(p) > 0:
                ps.append(SentenceSplitter(u" ".join(p)))
                p = []

            if not current_line_empty:
                p.append(l)
                
            previous_line_empty = current_line_empty
        if len(p) > 0:
            ps.append(SentenceSplitter(u" ".join(p)))
        return ps
Example #16
0
    def generate_lesson(self, words):
        copies = Settings.get('gen_copies')
        take = Settings.get('gen_take')
        mix = Settings.get('gen_mix')

        sentences = []
        while words:
            sen = words[:take] * copies
            words[:take] = []

            if mix == 'm': # mingle
                random.shuffle(sen)
            sentences.append(' '.join(sen))
        return sentences
Example #17
0
        def color_position(settings_color_var, use_space_var, space_var):
            '''Colors position with the color stored in settings_color_var.
            
strs use_space_var and space_var are settings variables to look up.
If [setting] use_space_var, space at position is replaced with [setting] space_var

Returns the new text_strs list (for assignment).'''
            colors[position] = Settings.get(settings_color_var)

            if Settings.get(use_space_var):
                return replace_at_locs(
                    text_strs, space_replacement_dict_from_setting(space_var),
                    [position])
            else:
                return text_strs
Example #18
0
    def __init__(self, *args):
        super(Quizzer, self).__init__(*args)

        self.result = QLabel()
        self.typer = Typer()
        self.label = WWLabel()
        self.result.setVisible(Settings.get("show_last"))
        #self.label.setFrameStyle(QFrame.Raised | QFrame.StyledPanel)
        #self.typer.setBuddy(self.label)
        #self.info = QLabel()
        self.connect(self.typer,  SIGNAL("done"), self.done)
        self.connect(self.typer,  SIGNAL("textChanged"), self.checkText)
        self.connect(self.typer,  SIGNAL("cancel"), SIGNAL("wantText"))
        self.connect(Settings, SIGNAL("change_typer_font"), self.readjust)
        self.connect(Settings, SIGNAL("change_show_last"), self.result.setVisible)

        self.text = ('','', 0, None)

        layout = QVBoxLayout()
        #layout.addWidget(self.info)
        #layout.addSpacing(20)
        layout.addWidget(self.result, 0, Qt.AlignRight)
        layout.addWidget(self.label, 1, Qt.AlignBottom)
        layout.addWidget(self.typer, 1)
        self.setLayout(layout)
        self.readjust()
Example #19
0
    def next_text(self):
        kind = Settings.get("select_method")
        if kind != 1:
            # Not in order
            targets = DB.execute(
                f"""select id,source,text from text where disabled is null
                order by random() limit {Settings.get("num_rand")}"""
            ).fetchall()
            if not targets:
                target = None
            elif kind == 2:
                target = min(targets, key=self.diff_eval)
            elif kind == 3:
                target = max(targets, key=self.diff_eval)
            else:
                target = targets[0]  # random, just pick the first
        else:
            # Fetch in order
            prev = (0, )
            result = DB.fetchone(
                """select r.text_id
                from result as r left join source as s on (r.source = s.rowid)
                where (s.discount is null) or (s.discount = 1) order by r.w desc limit 1""",
                None)
            if result is not None:
                prev = DB.fetchone("select rowid from text where id = ?", prev,
                                   result)
            target = DB.fetchone(
                """select id,source,text from text
                where rowid > ? and disabled is null order by rowid asc limit 1""",
                None, prev)
        if target is None:
            target = self.default_text

        self.emit("set-text", *target)
Example #20
0
def generate_automatic_insertion_regex():
    '''From settings info, returns the regex for which to re.match the automatically inserted chars

Or None if no chars are to be automatically inserted.'''
    #the str of characters (in regex-escaped form, but not regex) to automatically insert
    automatically_inserted_chars = ""
    if Settings.get('use_automatic_other_insertion'):
        automatically_inserted_chars += re.escape(
            Settings.get('automatic_other_insertion'))
    for s, c in ('automatic_space_insertion',
                 u" "), ('automatic_return_insertion', u"\n"):
        if Settings.get(s):
            automatically_inserted_chars += re.escape(c)

    return "[{0}]+".format(
        automatically_inserted_chars) if automatically_inserted_chars else None
Example #21
0
    def update_graph(self):
        what = Settings.get("graph_what")
        y_coords = [row[what] for row in iter(self.model)]

        if Settings.get("chrono_x"):
            x_coords = [row[0] for row in iter(self.model)]
        else:
            x_coords = list(range(len(y_coords) - 1, 0 - 1, -1))

        if Settings.get("dampen_graph"):
            window = Settings.get("dampen_average")
            y_coords = list(dampen(y_coords, window))
            x_coords = list(dampen(x_coords, window))

        plot = Plotters.Plot(x_coords, y_coords)
        self.plot.set_data(plot)
Example #22
0
 def __init__(self, fname):
     super(LessonMiner, self).__init__()
     #print time.clock()
     with codecs.open(fname, "r", "utf_8_sig") as f:
         self.paras = self.paras(f)
     self.lessons = None
     self.min_chars = Settings.get('min_chars')
Example #23
0
    def __init__(self, *args):
        super(Quizzer, self).__init__(*args)

        self.result = QLabel()
        self.typer = Typer()
        self.label = WWLabel()
        self.result.setVisible(Settings.get("show_last"))
        #self.label.setFrameStyle(QFrame.Raised | QFrame.StyledPanel)
        #self.typer.setBuddy(self.label)
        #self.info = QLabel()
        self.connect(self.typer, SIGNAL("done"), self.done)
        self.connect(self.typer, SIGNAL("textChanged"), self.checkText)
        self.connect(self.typer, SIGNAL("cancel"), SIGNAL("wantText"))
        self.connect(Settings, SIGNAL("change_typer_font"), self.readjust)
        self.connect(Settings, SIGNAL("change_show_last"),
                     self.result.setVisible)

        self.text = ('', '', 0, None)

        layout = QVBoxLayout()
        #layout.addWidget(self.info)
        #layout.addSpacing(20)
        layout.addWidget(self.result, 0, Qt.AlignRight)
        layout.addWidget(self.label, 1, Qt.AlignBottom)
        layout.addWidget(self.typer, 1)
        self.setLayout(layout)
        self.readjust()
Example #24
0
 def __init__(self, fname):
     super(LessonMiner, self).__init__()
     #print time.clock()
     with codecs.open(fname, "r", "utf_8_sig") as f:
         self.paras = self.paras(f)
     self.lessons = None
     self.min_chars = Settings.get('min_chars')
Example #25
0
    def __init__(self, x, y, *args):
        super(Plot, self).__init__(*args)

        # self.connect(self, SIGNAL("sceneRectChanged(QRectF)"), self.setSceneRect)

        if len(x) < 2:
            return

        min_x, max_x = min(x), max(x)
        min_y, max_y = min(y), max(y)

        p = QPen(Qt.blue)
        p.setCosmetic(True)
        p.setWidthF(2.0)
        p.setCapStyle(Qt.RoundCap)
        for i in range(0, len(x) - 1):
            self.addLine(x[i], -y[i], x[i + 1], -y[i + 1], p)

        # Add axes
        if Settings.get("show_xaxis"):
            if min_y > 0:
                min_y = 0
            elif max_y < 0:
                max_y = 0
        if min_y <= 0 <= min_y:
            self.addLine(min_x, 0, max_x, 0)
        if min_x <= 0 <= max_x:
            self.addLine(0, -min_y, 0, -max_y)

        w, h = max_x - min_x, max_y - min_y

        if h <= 0 or w <= 0:
            return

        # Add background lines
        spc = math.pow(10.0, math.ceil(math.log10(h) - 1))
        while h / spc < 5:
            spc /= 2

        ns = int(min_y / spc) * spc
        start = ns

        qp = QPen(QColor(Qt.lightGray))
        qp.setStyle(Qt.DotLine)

        while start < max_y + spc:
            lin = self.addLine(min_x, -start, max_x, -start, qp)
            lin.setZValue(-1.0)

            lbl = QGraphicsSimpleTextItem("%g" % start)
            th, tw = lbl.boundingRect().height(), lbl.boundingRect().width()
            lbl.scale(0.026 * w / tw, spc / th)
            lbl.setPos(QPointF(min_x - 0.03 * w, -start - spc / 2))
            self.addItem(lbl)

            start += spc

        qr = QRectF(min_x - 0.03 * w, -start + spc / 2, 1.03 * w, start - ns)
        self.setSceneRect(qr)
Example #26
0
 def getWaitText(self):
     if Settings.get("req_space"):
         return (
             "Press SPACE and then immediately start typing the text\n"
             + "Press ESCAPE to restart with a new text at any time"
         )
     else:
         return "Press ESCAPE to restart with a new text at any time"
Example #27
0
    def paras(self, f):
        p = []
        ps = []
        previous_line_empty = True
        for l in f:
            #designated replacements for unicode text
            if Settings.get('transliteration_manual_unicode'):
                for orig, repl in unicode_replacements:
                    l = l.replace(orig, repl)
                    
            ascii_line = l
            if unidecode_imported and Settings.get('transliteration_method') == INDEX_TRANSLITERATION_UNIDECODE:
                #tries to use unidecode if it exists
                ascii_line = unidecode.unidecode(ascii_line)
            elif Settings.get('transliteration_method') == INDEX_TRANSLITERATION_DELETE:
                #deletes all remaining non-ascii chars
                try:
                    ascii_line = ascii_line.decode('ascii')
                except UnicodeEncodeError:
                    ascii_line = filter(lambda c : ord(c) < 128, ascii_line) 

            #replaces any 1+ adjacent whitespace chars (spaces, tabs, newlines, etc) with one ascii space
            if Settings.get('single_space_only'): 
                ascii_line = re.sub("\s+"," ",ascii_line)               

            #TODO: newlines doesn't work since all this is done line-by-line
            #replaces multiple adjacent instances (possibly including spaces, newlines) of those characters 
            #in list multiple_replacements (e.g. "start ! !!!!! ! ! !!\n !\nend" might get replaced with
            #"start !\nend")
            if Settings.get('multiple_replacement_enabled'): 
                additional_chars = (" " if Settings.get('multiple_replacement_allow_spaces') else "") + ("\n" if Settings.get('multiple_replacement_allow_newlines') else "")
                for m in Settings.get('multiple_replacement_chars'): 
                    ascii_line = re.sub("{0}[{0}{1}]*{0}".format(re.escape(m),additional_chars), m, ascii_line)               

            #designated replacements for ascii text
            if Settings.get('transliteration_manual_ascii'):
                for orig, repl in ascii_replacements:
                    ascii_line = ascii_line.replace(orig, repl) 

            l = ascii_line.strip()
            current_line_empty = not l
           
            #the current line is empty: insert empty line 
            #or the current line and previous line both nonempty: need to insert empty line between them
            if (current_line_empty or not previous_line_empty) and len(p) > 0:
                ps.append(SentenceSplitter(u" ".join(p)))
                p = []

            if not current_line_empty:
                p.append(l)
                
            previous_line_empty = current_line_empty
        if len(p) > 0:
            ps.append(SentenceSplitter(u" ".join(p)))
        return ps
Example #28
0
    def check_text(self):
        if not self.target or self.edit_flag:
            return

        text = GtkUtil.textbuf_get_text(self.get_buffer())
        if self.when[0] == 0:  # We're just starting
            space = text and text[-1] == " "

            self.edit_flag = True
            if space:
                self.when[0] = timer()
                self.get_buffer().set_text("", -1)
                self.update_palette("right")
            elif Settings.get("req_space"):  # reset
                self.get_buffer().set_text(get_wait_text(), -1)
                self.get_buffer().select_range(*self.get_buffer().get_bounds())

            self.edit_flag = False

            if space or Settings.get("req_space"):
                return
            self.when[0] = -1

        # find first difference
        for upto in range(min(len(text), len(self.target))):
            if text[upto] != self.target[upto]:
                break
        else:
            upto = min(len(text), len(self.target))
        self.where = upto

        if self.when[upto] == 0 and upto == len(text):
            self.when[upto] = timer()
            if upto:
                self.times[upto - 1] = self.when[upto] - self.when[upto - 1]

        if upto == len(self.target):
            self.emit("done")
            return

        if upto < len(text) and upto < len(self.target):
            self.mistake[upto] = True
            self.mistakes[upto] = self.target[upto] + text[upto]

        self.update_palette("right" if upto == len(text) else "wrong")
Example #29
0
    def update(self):
        which = Settings.get("ana_which")
        what = Settings.get("ana_what")
        limit = Settings.get("ana_many")
        least = Settings.get("ana_count")
        hist = time.time() - Settings.get("history") * 86400.0

        sql = f"""select data,12.0/time as wpm,
            100.0-100.0*misses/cast(total as real) as accuracy,
            viscosity,total,misses,
            total*time*time*(1.0+misses/total) as damage
                from
                    (select data,agg_median(time) as time,agg_median(viscosity) as viscosity,
                    sum(count) as total,sum(mistakes) as misses
                    from statistic where w >= ? and type = ? group by data)
                where total >= ?
                order by {which} limit {limit}"""

        self.model.set_stats(DB.fetchall(sql, (hist, what, least)))
Example #30
0
    def set_select(self):
        method = Settings.get("select_method")
        if method in (0, 1):
            self.diff_eval = lambda x: 1
            self.next_text()
            return

        hist = time.time() - 86400 * Settings.get("history")
        tri = dict(
            DB.execute(
                """
            select data,agg_median(time) as wpm from statistic
            where w >= ? and type = 1
            group by data""", (hist, )).fetchall())

        vals = list(tri.values())
        if not vals:
            self.diff_eval = lambda x: 1
            self.next_text()
            return
        vals.sort(reverse=True)
        expect = vals[len(vals) // 4]

        def func(target):
            text = target[2]
            # FIXME what does v do here?
            # v = 0
            total = 0.0
            for i in range(0, len(text) - 2):
                trigram = text[i:i + 3]
                if trigram in tri:
                    total += tri[trigram]
                else:
                    total += expect
                    # v += 1
            avg = total / (len(text) - 2)
            return 12.0 / avg

        self.diff_eval = func
        self.next_text()
Example #31
0
    def updateLabel(self,position,errors):
        '''Populates the label with colors depending on current position and errors.'''
        #dict : str -> str ; original and displacement strs in error region (for easier display)
        err_replacements = {"\n":u"{0}<BR>".format(Settings.get('label_return_symbol'))}

        colors = {}  #dict : int -> str, mapping errors to color
        
        if Settings.get('show_label_mistakes'):
            #showing mistakes; need to populate color
            colors = dict([(i,Settings.get('label_mistakes_color')) for i in errors])

            if Settings.get('label_replace_spaces_in_mistakes'):
                err_replacements.update(space_replacement_dict_from_setting('label_mistakes_space_char'))

        text_strs = list(self.text[2]) #list of strs, initially one char each, to operate on
        text_strs = html_list_process_spaces(text_strs)
        text_strs = replace_at_locs(text_strs,err_replacements,errors)

        def color_position(settings_color_var, use_space_var, space_var):
            '''Colors position with the color stored in settings_color_var.
            
strs use_space_var and space_var are settings variables to look up.
If [setting] use_space_var, space at position is replaced with [setting] space_var

Returns the new text_strs list (for assignment).'''
            colors[position] = Settings.get(settings_color_var)

            if Settings.get(use_space_var):
                return replace_at_locs(text_strs,space_replacement_dict_from_setting(space_var),[position])
            else:
                return text_strs
            
        #designates colors and replacements of position
        if Settings.get('show_label_position_with_prior_mistake') and position - 1 in errors:
            text_strs = color_position('label_position_with_prior_mistake_color',
                                       'label_replace_spaces_in_position_with_prior_mistake',
                                       'label_position_with_prior_mistake_space_char')
        elif Settings.get('show_label_position_with_mistakes') and errors:
            text_strs = color_position('label_position_with_mistakes_color',
                                       'label_replace_spaces_in_position_with_mistakes',
                                       'label_position_with_mistakes_space_char')
        elif Settings.get('show_label_position'): 
            text_strs = color_position('label_position_color',
                                       'label_replace_spaces_in_position',
                                       'label_position_space_char') 

        htmlized = "".join(html_color_strs(text_strs,colors))
        htmlized = htmlized.replace(u"\n", u"{0}<BR>".format(Settings.get('label_return_symbol')))
        
        self.label.setText(htmlized) 
Example #32
0
    def checkText(self):
        if self.target is None or self.editflag:
            return

        v = unicode(self.toPlainText())
        if self.when[0] == 0:
            space = len(v) > 0 and v[-1] == u" "
            req = Settings.get('req_space')

            self.editflag = True
            if space:
                self.when[0] = timer()
                self.clear()
                self.setPalette(self.palettes['right'])
            elif req:
                self.setText(self.getWaitText())
                self.selectAll()
            self.editflag = False

            if req or space:
                return
            else:
                self.when[0] = -1

        y = 0
        for y in xrange(min(len(v), len(self.target)), -1, -1):
            if v[0:y] == self.target[0:y]:
                break
        lcd = v[0:y]
        self.where = y

        if self.when[y] == 0 and y == len(v):
            self.when[y] = timer()
            if y > 0:
                self.times[y-1] = self.when[y] - self.when[y-1]

        if lcd == self.target:
            self.emit(SIGNAL("done"))
            return

        if y < len(v) and y < len(self.target):
            self.mistake[y] = True
            self.mistakes[y] = self.target[y] + v[y]

        if v == lcd:
            self.setPalette(self.palettes['right'])
        else:
            self.setPalette(self.palettes['wrong'])
Example #33
0
    def checkText(self):
        if self.target is None or self.editflag:
            return

        v = unicode(self.toPlainText())
        if self.when[0] == 0:
            space = len(v) > 0 and v[-1] == u" "
            req = Settings.get('req_space')

            self.editflag = True
            if space:
                self.when[0] = timer()
                self.clear()
                self.setPalette(self.palettes['right'])
            elif req:
                self.setText(self.getWaitText())
                self.selectAll()
            self.editflag = False

            if req or space:
                return
            else:
                self.when[0] = -1

        y = 0
        for y in xrange(min(len(v), len(self.target)), -1, -1):
            if v[0:y] == self.target[0:y]:
                break
        lcd = v[0:y]
        self.where = y

        if self.when[y] == 0 and y == len(v):
            self.when[y] = timer()
            if y > 0:
                self.times[y-1] = self.when[y] - self.when[y-1]

        if lcd == self.target:
            self.emit(SIGNAL("done"))
            return

        if y < len(v) and y < len(self.target):
            self.mistake[y] = True
            self.mistakes[y] = self.target[y] + v[y]

        if v == lcd:
            self.setPalette(self.palettes['right'])
        else:
            self.setPalette(self.palettes['wrong'])
Example #34
0
    def __init__(self):
        GtkUtil.AmphBoxLayout.__init__(self)

        self.plotcol = 3
        self.plot = Plotters.Plotter()

        self.editflag = False
        self.model = ResultModel()

        self.cb_source = Gtk.ComboBoxText()
        self.refresh_sources()
        self.cb_source.set_active_id("all")
        self.cb_source.connect("changed", lambda _: self.update_data())

        tree = GtkUtil.AmphTreeView(self.model)
        tree.treeview.connect("row-activated", self.double_clicked)
        Settings.on_any_change(
            ["graph_what", "show_xaxis", "chrono_x", "dampen_graph"],
            self.update_graph)
        Settings.on_any_change(["perf_items", "perf_group_by", "lesson_stats"],
                               self.update_data)

        self.append_layout([
            [
                "Show",
                SettingsEdit("perf_items"), "items from", self.cb_source,
                "and group by",
                SettingsCombo("perf_group_by", [
                    "<no grouping>",
                    "%d sessions" % Settings.get("def_group_by"), "sitting",
                    "day"
                ]), None,
                GtkUtil.new_button("Update", self.update_data)
            ],
            (tree, ),
            [
                "Plot",
                SettingsCombo("graph_what",
                              ((3, "WPM"), (4, "accuracy"), (5, "viscosity"))),
                SettingsCheckBox("show_xaxis", "Show X-axis"),
                SettingsCheckBox("chrono_x", "Use time-scaled X-axis"),
                SettingsCheckBox("dampen_graph", "Dampen graph values")
            ],
            (self.plot, ),
        ])

        self.update_data()
Example #35
0
    def __init__(self):
        Gtk.TextView.__init__(self, wrap_mode=Gtk.WrapMode.WORD)

        sync_font = lambda: self.override_font(
            Pango.FontDescription.from_string(Settings.get("typer_font")))
        sync_font()

        self.connect("key-press-event", lambda _, key: self.key_press(key))
        self.get_buffer().connect("end-user-action",
                                  lambda _: self.check_text())
        Settings.on_any_change([
            "quiz_wrong_fg",
            "quiz_wrong_bg",
            "quiz_right_fg",
            "quiz_right_bg",
        ], self.update_palette)
        Settings.on_any_change(["typer_font"], sync_font)

        self.set_target("")  # clear input
Example #36
0
    def __init__(self, *args):
        super(Quizzer, self).__init__(*args)

        self.result = QLabel()
        self.typer = Typer()
        self.label = WWLabel()
        self.tryout_label = QLabel()
        self.tryout_label.setText("Tryout layout: ")
        self.tryout_layout = QComboBox()
        self.result.setVisible(Settings.get("show_last"))
        #self.label.setFrameStyle(QFrame.Raised | QFrame.StyledPanel)
        #self.typer.setBuddy(self.label)
        #self.info = QLabel()
        self.connect(self.typer,  SIGNAL("done"), self.done)
        self.connect(self.typer,  SIGNAL("cancel"), SIGNAL("wantText"))
        self.connect(Settings, SIGNAL("change_typer_font"), self.readjust)
        self.connect(Settings, SIGNAL("change_show_last"), self.result.setVisible)
        self.connect(self.tryout_layout, SIGNAL("currentIndexChanged(int)"), self.changeTryoutLayout)

        self.text = ('','', '', None)
        self.originalText = ('','', '', None)
        self.keyboardLayouts = []

        layout = QVBoxLayout()
        #layout.addWidget(self.info)
        #layout.addSpacing(20)
        hlayout = QHBoxLayout()
        hlayout.addWidget(self.tryout_label, 0, Qt.AlignLeft)
        hlayout.addWidget(self.tryout_layout, 0, Qt.AlignLeft)
        hlayout.addStretch()
        hlayout.addWidget(self.result, 0, Qt.AlignRight)
        layout.addLayout(hlayout)
        layout.addWidget(self.label, 1, Qt.AlignBottom)
        layout.addWidget(self.typer, 1)
        self.setLayout(layout)
        self.readjust()
        self.addLayouts()
Example #37
0
 def __iter__(self):
     p = [0]
     sen = re.compile(Settings.get('sentence_regex'))
     return ifilter(None, imap(lambda x: self.pars(p, x), sen.finditer(self.string)))
Example #38
0
def new_error(position,errors):
    '''Given list of error positions and current position, 
returns whether or there's a new error at position'''
    #considers adjacent errors to be part of the same error if the setting is toggled
    return position in errors and not (Settings.get('adjacent_errors_not_counted') and position - 1 in errors)
Example #39
0
    def checkText(self, automatically_inserted = False):
        if self.typer.target is None or self.typer.editflag:
            return

        v = unicode(self.typer.toPlainText())
        
        if Settings.get('allow_mistakes') and len(v) >= len(self.typer.target):
            v = self.typer.target
 
        if self.typer.start_time == None and Settings.get('req_space'):
            #space is required before beginning the passage proper
            if v == u" ":
                #the first char typed was space
                #the first space only starts the session; clear the typer
                set_typer_text(self.typer,"",cursor_position=0)
                self.typer.start_time = 0
                return
            else:
                #reset the wait text
                set_typer_text(self.typer,self.typer.getWaitText())
                self.typer.selectAll()
                return
                
        if not self.typer.start_time:
            self.typer.start_time = timer()
            if 1 < len(v) < len(self.typer.target): 
                #checks whether wait text was accidentally left in
                diff = list(difflib.Differ().compare(list(self.typer.getWaitText()),list(v)))

                #the vast majority of the wait text is still there
                wait_text_present = len(filter(lambda line : line[0] == "-", diff)) <= 1

                if wait_text_present:
                    #leave only the additional typed text
                    new_str = "".join(line[2:] for line in diff if line[0] == "+")
                    set_typer_text(self.typer,new_str,cursor_position=len(new_str))
                    v = new_str 

        old_cursor = self.typer.textCursor()
        old_position = old_cursor.position()
        old_str_position = old_position - 1  #the position that has (presumably, unless delete was used) just been typed
     
        #colors text in typer depending on errors
        errors = disagreements(v,self.typer.target,case_sensitive=Settings.get('case_sensitive'))
        first_error = errors[0] if errors else None

        #records time that any char was hit
        #except that if we've already been correct farther, we don't record
        if self.typer.farthest_correct < old_str_position < len(self.typer.target):
            if old_str_position not in errors:
                self.typer.farthest_correct = old_str_position

            #invalidates all farther-out times that might have previously been written
            if old_str_position < self.typer.farthest_data:
                for i in xrange(old_str_position+1, self.typer.farthest_data + 1):
                    self.typer.data[i].when = None

            self.typer.farthest_data = old_str_position
            self.typer.data[old_str_position] = Letter(char=self.typer.target[old_str_position],
                                                       when=timer(),
                                                       automatically_inserted=automatically_inserted)

        automatic_insertion_regex = generate_automatic_insertion_regex()
        #TODO: refactor so this doesn't rely on text setting then re-calling gimmick
        #TODO: change statistics to account for this
        #Automatically insert characters into the text area
        if automatic_insertion_regex and old_position == len(v): #only works if cursor is at the end
            automatic_insertion = re.match(automatic_insertion_regex,self.typer.target[old_position:])
            if automatic_insertion:
                new_end = old_position + automatic_insertion.end()
                set_typer_text(self.typer, v[:old_position] + self.typer.target[old_position:new_end], cursor_position = new_end)
                self.checkText(automatically_inserted=True)  #recovers the formatting
                return

        #TODO: refactor so this doesn't rely on text setting then re-calling gimmick
        #Prevent advancement until user correctly types space
        if Settings.get('ignore_until_correct_space') and self.typer.target[old_str_position] == u" " and old_str_position in errors:
            #gets rid of new character (sets as plaintext)
            set_typer_text(self.typer,v[:old_str_position] + v[old_str_position+1:],cursor_position = old_position - 1) 
            self.checkText()    #recovers the formatting 
            return

        if len(v) >= len(self.typer.target) and (not first_error or first_error >= len(self.typer.target)):
            self.done()
            return
       
        if new_error(old_str_position,errors): 
            self.typer.mistake[old_str_position] = True
            self.typer.mistakes[old_str_position] = self.typer.target[old_str_position] + v[old_str_position]

        if Settings.get('quiz_invisible'):
            self.typer.activate_invisibility()
        else:
            if Settings.get("quiz_use_wrong_palette") and errors:
                self.typer.setPalette(self.typer.palettes['wrong'])
            else:
                self.typer.setPalette(self.typer.palettes['right'])
            update_typer_html(self.typer,errors)
        
        #updates the label depending on errors
        self.updateLabel(old_position,errors)
Example #40
0
    def checkText(self):
        if self.typer.target is None or self.typer.editflag:
            return

        v = unicode(self.typer.toPlainText())

        if Settings.get('allow_mistakes') and len(v) >= len(self.typer.target):
            v = self.typer.target

        if not self.typer.started:
            if Settings.get('req_space'):
                #space is required before beginning the passage proper
                if v == u" ":
                    #the first char typed was space
                    #the first space only starts the session; clear the typer
                    set_typer_text(self.typer, "", cursor_position=0)
                    self.typer.when[0] = timer()
                    self.typer.started = True
                    return
                else:
                    #reset the wait text
                    set_typer_text(self.typer, self.typer.getWaitText())
                    self.typer.selectAll()
                    return
            else:
                self.typer.when[0] = -1
                self.typer.when[1] = timer(
                )  #have to set starting time regardless of correctness
                self.typer.started = True

        old_cursor = self.typer.textCursor()
        old_position = old_cursor.position()
        old_str_position = old_position - 1  #the position that has (presumably) just been typed

        #colors text in typer depending on errors
        errors = disagreements(v,
                               self.typer.target,
                               case_sensitive=Settings.get('case_sensitive'))
        first_error = errors[0] if errors else None

        #records time that any char was correctly hit
        #except that if we've already been correct farther, we don't record
        if self.typer.farthest_correct < old_str_position < len(
                self.typer.target) and not old_str_position in errors:
            self.typer.when[old_str_position +
                            1] = timer()  #zeroth position is original space
            self.typer.farthest_correct = old_str_position

        automatic_insertion_regex = generate_automatic_insertion_regex()
        #TODO: refactor so this doesn't rely on text setting then re-calling gimmick
        #TODO: change statistics to account for this
        #Automatically insert characters into the text area
        if automatic_insertion_regex and old_position == len(
                v):  #only works if cursor is at the end
            automatic_insertion = re.match(automatic_insertion_regex,
                                           self.typer.target[old_position:])
            if automatic_insertion:
                new_end = old_position + automatic_insertion.end()
                set_typer_text(self.typer,
                               v[:old_position] +
                               self.typer.target[old_position:new_end],
                               cursor_position=new_end)
                self.checkText()  #recovers the formatting
                return

        #TODO: refactor so this doesn't rely on text setting then re-calling gimmick
        #Prevent advancement until user correctly types space
        if Settings.get('ignore_until_correct_space') and self.typer.target[
                old_str_position] == u" " and old_str_position in errors:
            #gets rid of new character (sets as plaintext)
            set_typer_text(self.typer,
                           v[:old_str_position] + v[old_str_position + 1:],
                           cursor_position=old_position - 1)
            self.checkText()  #recovers the formatting
            return

        if len(v) >= len(self.typer.target) and (
                not first_error or first_error >= len(self.typer.target)):
            self.done()
            return

        if new_error(old_str_position, errors):
            self.typer.mistake[old_str_position] = True
            self.typer.mistakes[old_str_position] = self.typer.target[
                old_str_position] + v[old_str_position]

        if Settings.get('quiz_invisible'):
            self.typer.activate_invisibility()
        else:
            if Settings.get("quiz_use_wrong_palette") and errors:
                self.typer.setPalette(self.typer.palettes['wrong'])
            else:
                self.typer.setPalette(self.typer.palettes['right'])
            update_typer_html(self.typer, errors)

        #updates the label depending on errors
        self.updateLabel(old_position, errors)
Example #41
0
    def done(self):
        now = time.time()
        elapsed, chars, times, mis, mistakes = self.typer.getStats()

        assert chars == len(self.text[2])

        accuracy = 1.0 - len(filter(None, mis)) / chars
        spc = elapsed / chars

        viscosity = sum(map(lambda x: ((x - spc) / spc)**2, times)) / chars

        DB.execute(
            'insert into result (w,text_id,source,wpm,accuracy,viscosity) values (?,?,?,?,?,?)',
            (now, self.text[0], self.text[1], 12.0 / spc, accuracy, viscosity))

        v2 = DB.fetchone(
            """select agg_median(wpm),agg_median(acc) from
            (select wpm,100.0*accuracy as acc from result order by w desc limit %d)"""
            % Settings.get('def_group_by'), (0.0, 100.0))
        self.result.setText(
            "Last: %.1fwpm (%.1f%%), last 10 average: %.1fwpm (%.1f%%)" %
            ((12.0 / spc, 100.0 * accuracy) + v2))

        self.emit(SIGNAL("statsChanged"))

        stats = collections.defaultdict(Statistic)
        visc = collections.defaultdict(Statistic)
        text = self.text[2]

        for c, t, m in zip(text, times, mis):
            stats[c].append(t, m)
            visc[c].append(((t - spc) / spc)**2)

        def gen_tup(s, e):
            perch = sum(times[s:e]) / (e - s)
            visc = sum(map(lambda x:
                           ((x - perch) / perch)**2, times[s:e])) / (e - s)
            return (text[s:e], perch, len(filter(None, mis[s:e])), visc)

        for tri, t, m, v in [gen_tup(i, i + 3) for i in xrange(0, chars - 2)]:
            stats[tri].append(t, m > 0)
            visc[tri].append(v)

        regex = re.compile(r"(\w|'(?![A-Z]))+(-\w(\w|')*)*")

        for w, t, m, v in [
                gen_tup(*x.span()) for x in regex.finditer(text)
                if x.end() - x.start() > 3
        ]:
            stats[w].append(t, m > 0)
            visc[w].append(v)

        def type(k):
            if len(k) == 1:
                return 0
            elif len(k) == 3:
                return 1
            return 2

        vals = []
        for k, s in stats.iteritems():
            v = visc[k].median()
            vals.append(
                (s.median(), v * 100.0, now, len(s), s.flawed(), type(k), k))

        is_lesson = DB.fetchone("select discount from source where rowid=?",
                                (None, ), (self.text[1], ))[0]

        if Settings.get('use_lesson_stats') or not is_lesson:
            DB.executemany_(
                '''insert into statistic
                (time,viscosity,w,count,mistakes,type,data) values (?,?,?,?,?,?,?)''',
                vals)
            DB.executemany_(
                'insert into mistake (w,target,mistake,count) values (?,?,?,?)',
                [(now, k[0], k[1], v) for k, v in mistakes.iteritems()])

        if is_lesson:
            mins = (Settings.get("min_lesson_wpm"),
                    Settings.get("min_lesson_acc"))
        else:
            mins = (Settings.get("min_wpm"), Settings.get("min_acc"))

        if 12.0 / spc < mins[0] or accuracy < mins[1] / 100.0:
            self.setText(self.text)
        elif not is_lesson and Settings.get('auto_review'):
            ws = filter(lambda x: x[5] == 2, vals)
            if len(ws) == 0:
                self.emit(SIGNAL("wantText"))
                return
            ws.sort(key=lambda x: (x[4], x[0]), reverse=True)
            i = 0
            while ws[i][4] != 0:
                i += 1
            i += (len(ws) - i) // 4

            self.emit(SIGNAL("wantReview"), map(lambda x: x[6], ws[0:i]))
        else:
            self.emit(SIGNAL("wantText"))
Example #42
0
 def setText(self, text):
     self.text = text
     self.label.setText(self.text[2].replace(
         u"\n", u"{0}\n".format(Settings.get('label_return_symbol'))))
     self.typer.setTarget(self.text[2])
     self.typer.setFocus()
Example #43
0
 def setText(self, text):
     self.text = text 
     self.label.setText(self.text[2].replace(u"\n", u"{0}\n".format(Settings.get('label_return_symbol')))) 
     self.typer.setTarget(self.text[2])
     self.typer.setFocus()
Example #44
0
    def done(self):
        now = time.time()
        elapsed, chars, times, mis, mistakes = self.typer.getStats()

        assert chars == len(self.text[2])

        accuracy = 1.0 - len(filter(None, mis)) / chars
        spc = elapsed / chars
        
        viscosity = sum(map(lambda x: ((x-spc)/spc)**2, times)) / chars

        DB.execute('insert into result (w,text_id,source,wpm,accuracy,viscosity) values (?,?,?,?,?,?)',
                   (now, self.text[0], self.text[1], 12.0/spc, accuracy, viscosity))

        v2 = DB.fetchone("""select agg_median(wpm),agg_median(acc) from
            (select wpm,100.0*accuracy as acc from result order by w desc limit %d)""" % Settings.get('def_group_by'), (0.0, 100.0))
        self.result.setText("Last: %.1fwpm (%.1f%%), last 10 average: %.1fwpm (%.1f%%)"
            % ((12.0/spc, 100.0*accuracy) + v2))

        self.emit(SIGNAL("statsChanged"))

        stats = collections.defaultdict(Statistic)
        visc = collections.defaultdict(Statistic)
        text = self.text[2]

        for c, t, m in zip(text, times, mis):
            stats[c].append(t, m)
            visc[c].append(((t-spc)/spc)**2)

        def gen_tup(s, e):
            perch = sum(times[s:e])/(e-s)
            visc = sum(map(lambda x: ((x-perch)/perch)**2, times[s:e]))/(e-s)
            return (text[s:e], perch, len(filter(None, mis[s:e])), visc)

        for tri, t, m, v in [gen_tup(i, i+3) for i in xrange(0, chars-2)]:
            stats[tri].append(t, m > 0)
            visc[tri].append(v)

        regex = re.compile(r"(\w|'(?![A-Z]))+(-\w(\w|')*)*")

        for w, t, m, v in [gen_tup(*x.span()) for x in regex.finditer(text) if x.end()-x.start() > 3]:
            stats[w].append(t, m > 0)
            visc[w].append(v)

        def type(k):
            if len(k) == 1:
                return 0
            elif len(k) == 3:
                return 1
            return 2

        vals = []
        for k, s in stats.iteritems():
            v = visc[k].median()
            vals.append( (s.median(), v*100.0, now, len(s), s.flawed(), type(k), k) )

        is_lesson = DB.fetchone("select discount from source where rowid=?", (None,), (self.text[1], ))[0]

        if Settings.get('use_lesson_stats') or not is_lesson:
            DB.executemany_('''insert into statistic
                (time,viscosity,w,count,mistakes,type,data) values (?,?,?,?,?,?,?)''', vals)
            DB.executemany_('insert into mistake (w,target,mistake,count) values (?,?,?,?)',
                    [(now, k[0], k[1], v) for k, v in mistakes.iteritems()])

        if is_lesson:
            mins = (Settings.get("min_lesson_wpm"), Settings.get("min_lesson_acc"))
        else:
            mins = (Settings.get("min_wpm"), Settings.get("min_acc"))

        if 12.0/spc < mins[0] or accuracy < mins[1]/100.0:
            self.setText(self.text)
        elif not is_lesson and Settings.get('auto_review'):
            ws = filter(lambda x: x[5] == 2, vals)
            if len(ws) == 0:
                self.emit(SIGNAL("wantText"))
                return
            ws.sort(key=lambda x: (x[4],x[0]), reverse=True)
            i = 0
            while ws[i][4] != 0:
                i += 1
            i += (len(ws) - i) // 4

            self.emit(SIGNAL("wantReview"), map(lambda x:x[6], ws[0:i]))
        else:
            self.emit(SIGNAL("wantText"))
Example #45
0
def get_wait_text():
    if Settings.get("req_space"):
        return ("Press SPACE and then immediately start typing the text\n"
                "Press ESCAPE to restart with a new text at any time")
    return "Press ESCAPE to restart with a new text at any time"
Example #46
0
    def checkText(self):
        if self.typer.target is None or self.typer.editflag:
            return

        v = unicode(self.typer.toPlainText())
        
        if Settings.get('allow_mistakes') and len(v) >= len(self.typer.target):
            v = self.typer.target

        if not self.typer.started:
            if Settings.get('req_space'):
            #space is required before beginning the passage proper
                if v == u" ":
                    #the first char typed was space
                    #the first space only starts the session; clear the typer
                    set_typer_text(self.typer,"",cursor_position=0)
                    self.typer.when[0] = timer()
                    self.typer.started = True
                    return
                else:
                    #reset the wait text
                    set_typer_text(self.typer,self.typer.getWaitText())
                    self.typer.selectAll()
                    return
            else:
                self.typer.when[0] = -1
                self.typer.when[1] = timer()  #have to set starting time regardless of correctness
                self.typer.started = True

        old_cursor = self.typer.textCursor()
        old_position = old_cursor.position()
        old_str_position = old_position - 1  #the position that has (presumably) just been typed
     
        #colors text in typer depending on errors
        errors = disagreements(v,self.typer.target,case_sensitive=Settings.get('case_sensitive'))
        first_error = errors[0] if errors else None

        #records time that any char was correctly hit
        #except that if we've already been correct farther, we don't record
        if self.typer.farthest_correct < old_str_position < len(self.typer.target) and not old_str_position in errors:
            self.typer.when[old_str_position+1] = timer() #zeroth position is original space
            self.typer.farthest_correct = old_str_position

        automatic_insertion_regex = generate_automatic_insertion_regex()
        #TODO: refactor so this doesn't rely on text setting then re-calling gimmick
        #TODO: change statistics to account for this
        #Automatically insert characters into the text area
        if automatic_insertion_regex and old_position == len(v): #only works if cursor is at the end
            automatic_insertion = re.match(automatic_insertion_regex,self.typer.target[old_position:])
            if automatic_insertion:
                new_end = old_position + automatic_insertion.end()
                set_typer_text(self.typer, v[:old_position] + self.typer.target[old_position:new_end], cursor_position = new_end)
                self.checkText()  #recovers the formatting
                return

        #TODO: refactor so this doesn't rely on text setting then re-calling gimmick
        #Prevent advancement until user correctly types space
        if Settings.get('ignore_until_correct_space') and self.typer.target[old_str_position] == u" " and old_str_position in errors:
            #gets rid of new character (sets as plaintext)
            set_typer_text(self.typer,v[:old_str_position] + v[old_str_position+1:],cursor_position = old_position - 1) 
            self.checkText()    #recovers the formatting 
            return

        if len(v) >= len(self.typer.target) and (not first_error or first_error >= len(self.typer.target)):
            self.done()
            return
       
        if new_error(old_str_position,errors): 
            self.typer.mistake[old_str_position] = True
            self.typer.mistakes[old_str_position] = self.typer.target[old_str_position] + v[old_str_position]

        if Settings.get('quiz_invisible'):
            self.typer.activate_invisibility()
        else:
            if Settings.get("quiz_use_wrong_palette") and errors:
                self.typer.setPalette(self.typer.palettes['wrong'])
            else:
                self.typer.setPalette(self.typer.palettes['right'])
            update_typer_html(self.typer,errors)
        
        #updates the label depending on errors
        self.updateLabel(old_position,errors)
Example #47
0
    def done(self):
        print("DONE")
        # TODO split into smaller bits
        now = timer()
        elapsed, chars, times, mis, mistakes = self.typer.get_stats()
        text = self.text[2]

        assert chars == len(text)

        accuracy = 1.0 - sum(1 for f in mis if f) / chars
        spc = elapsed / chars
        viscosity = sum((t / spc - 1)**2 for t in times) / chars

        DB.execute(
            """insert into result (w, text_id, source, wpm, accuracy, viscosity)
                   values (?,?,?,?,?,?)""",
            (now, self.text[0], self.text[1], 12.0 / spc, accuracy, viscosity))

        wpm_median, acc_median = DB.fetchone(
            f"""select agg_median(wpm),agg_median(acc) from
            (select wpm,100.0*accuracy as acc from result order by w desc limit
             {Settings.get("def_group_by")})""", (0.0, 100.0))

        self.result.set_text(
            "Last: {:.1f}wpm ({:.1f}%), last 10 average: {:.1f}wpm ({:.1f}%)".
            format(12.0 / spc, 100.0 * accuracy, wpm_median, acc_median))

        self.emit("stats-changed")

        stats = collections.defaultdict(Statistic)
        viscs = collections.defaultdict(Statistic)

        for char, time, mistake in zip(text, times, mis):
            stats[char].append(time, mistake)
            viscs[char].append((time / spc - 1)**2)

        def gen_tup(start, end):
            span = end - start
            char_avg = sum(times[start:end]) / span
            visc = sum((t / char_avg - 1)**2 for t in times[start:end]) / span
            return (text[start:end], char_avg,
                    sum(1 for f in mis[start:end] if f), visc)

        for trigraph, time, mist, visc in [
                gen_tup(i, i + 3) for i in range(0, chars - 2)
        ]:
            stats[trigraph].append(time, mist > 0)
            viscs[trigraph].append(visc)

        regex = re.compile(r"(\w|'(?![A-Z]))+(-\w(\w|')*)*")
        for word, time, mist, visc in [
                gen_tup(*m.span()) for m in regex.finditer(text)
                if m.end() - m.start() > 3
        ]:
            stats[word].append(time, mist > 0)
            viscs[word].append(visc)

        def kind(key):
            if len(key) == 1:
                return 0
            if len(key) == 3:
                return 1
            return 2

        vals = []
        for key, stat in stats.items():
            visc = viscs[key].median()
            vals.append((stat.median(), visc * 100.0, now, len(stat),
                         stat.flawed(), kind(key), key))

        is_lesson = DB.fetchone("select discount from source where rowid=?",
                                (None, ), (self.text[1], ))[0]

        if Settings.get("use_lesson_stats") or not is_lesson:
            DB.executemany(
                """insert into statistic (time,viscosity,w,count,mistakes,type,data)
                    values (?,?,?,?,?,?,?)""", vals)
            DB.executemany(
                "insert into mistake (w,target,mistake,count) values (?,?,?,?)",
                [(now, k[0], k[1], v) for k, v in mistakes.items()])

        if is_lesson:
            mins = (Settings.get("min_lesson_wpm"),
                    Settings.get("min_lesson_acc"))
        else:
            mins = (Settings.get("min_wpm"), Settings.get("min_acc"))

        if 12.0 / spc < mins[0] or accuracy < mins[1] / 100.0:
            self.set_target(self.text)
        elif not is_lesson and Settings.get('auto_review'):
            words = [x for x in vals if x[5] == 2]
            if not words:
                self.emit("want-text")
                return
            words.sort(key=lambda x: (x[4], x[0]), reverse=True)
            i = 0
            while words[i][4] != 0:
                i += 1
            i += (len(words) - i) // 4

            # TODO support want-review
            # self.emit("want-review", [x[6] for x in words[0:i]])
        else:
            self.emit("want-text")
Example #48
0
    def executemany_(self, *args):
        sqlite3.Connection.executemany(self, *args)
    def executemany(self, *args):
        sqlite3.Connection.executemany(self, *args)
        #self.commit()

    def fetchall(self, *args):
        return sqlite3.Connection.execute(self, *args).fetchall()

    def fetchone(self, sql, default, *args):
        x = sqlite3.Connection.execute(self, sql, *args)
        g = x.fetchone()
        if g is None:
            return default
        return g

    def getSource(self, source, lesson=None):
        v = self.fetchall('select rowid from source where name = ? limit 1', (source, ))
        if len(v) > 0:
            sqlite3.Connection.execute(self, 'update source set disabled = NULL where rowid = ?', v[0])
            sqlite3.Connection.commit(self)
            return v[0][0]
        sqlite3.Connection.execute(self, 'insert into source (name, discount) values (?, ?)', (source, lesson))
        return self.getSource(source)

dbname = Settings.get("db_name")

# GLOBAL
DB = sqlite3.connect(dbname, 5, 0, "DEFERRED", False, AmphDatabase)
Example #49
0
 def activate_invisibility(self):
     '''Turns on invisible mode'''
     self.setPalette(self.palettes['invisible'])
     set_colored_typer_text(self,Settings.get('quiz_invisible_color'))  #flushes out html with plaintext
Example #50
0
    def fetchall(self, *args):
        return sqlite3.Connection.execute(self, *args).fetchall()

    def fetchone(self, sql, default, *args):
        x = sqlite3.Connection.execute(self, sql, *args)
        g = x.fetchone()
        if g is None:
            return default
        return g

    def getSource(self, source, lesson=None):
        v = self.fetchall('select rowid from source where name = ? limit 1',
                          (source, ))
        if len(v) > 0:
            sqlite3.Connection.execute(
                self, 'update source set disabled = NULL where rowid = ?',
                v[0])
            sqlite3.Connection.commit(self)
            return v[0][0]
        sqlite3.Connection.execute(
            self, 'insert into source (name, discount) values (?, ?)',
            (source, lesson))
        return self.getSource(source)


dbname = Settings.get("db_name")

# GLOBAL
DB = sqlite3.connect(dbname, 5, 0, "DEFERRED", False, AmphDatabase)
Example #51
0
def space_replacement_dict_from_setting(replacement_var):
    '''Returns a dict that assigns to html spaces the value in the setting replacement_var'''
    return space_replacement_dict(Settings.get(replacement_var))