Ejemplo n.º 1
0
class Core:
    def __init__(self):
        self.ruler = Ruler()
        for i in range(len(_rules)):
            self.ruler.append(_rules[i][0], _rules[i][1])

    def process(self, state):
        rules = self.ruler.getRules('')
        for i in range(len(rules)):
            rules[i](state)

    @property
    def State(self):
        return StateCore
Ejemplo n.º 2
0
    def __init__(self, app, presenter):
        gtk.Table.__init__(self)
        self.app = app
        self.presenter = presenter
        self.caption = presenter.doc_name

        self.tab_caption = TabCaption(self, self.caption)

        da_box = gtk.Table(3, 3, False)

        self.corner = RulerCorner(self)
        da_box.attach(self.corner, 0, 1, 0, 1, gtk.SHRINK, gtk.SHRINK)

        self.hruler = Ruler(self, 0)
        da_box.attach(self.hruler, 1, 3, 0, 1, gtk.EXPAND | gtk.FILL,
                      gtk.SHRINK)

        self.vruler = Ruler(self, 1)
        da_box.attach(self.vruler, 0, 1, 1, 3, gtk.SHRINK,
                      gtk.EXPAND | gtk.FILL)

        self.v_adj = gtk.Adjustment()
        self.vscroll = gtk.VScrollbar(self.v_adj)
        da_box.attach(self.vscroll, 2, 3, 1, 2, gtk.SHRINK,
                      gtk.EXPAND | gtk.FILL)

        self.h_adj = gtk.Adjustment()
        self.hscroll = gtk.HScrollbar(self.h_adj)
        da_box.attach(self.hscroll, 1, 2, 2, 3, gtk.EXPAND | gtk.FILL,
                      gtk.SHRINK)

        self.canvas = AppCanvas(self)
        da_box.attach(self.canvas, 1, 2, 1, 2, gtk.FILL | gtk.EXPAND,
                      gtk.FILL | gtk.EXPAND, 0, 0)

        if system.get_os_family() == system.WINDOWS:
            xpad = 2
            ypad = 0
        else:
            xpad = ypad = 3

        self.attach(da_box,
                    0,
                    1,
                    0,
                    1,
                    gtk.EXPAND | gtk.FILL,
                    gtk.EXPAND | gtk.FILL,
                    xpadding=xpad,
                    ypadding=ypad)
Ejemplo n.º 3
0
class ParserBlock:
    def __init__(self):
        self.ruler = Ruler()
        for i in range(len(_rules)):
            self.ruler.append(_rules[i][0], _rules[i][1], {'alt': list(_rules[i][2] or [])})

    def tokenize(self,state,startLine,endLine):
        pass # todo

    def parse(self,src,md,env,outTokens):
        pass

    @property
    def State(self):
        return StateBlock
Ejemplo n.º 4
0
def use_ruler(species, ruler=Ruler()):
    """
    THIS IS A DEMONSTRATION/VISUALIZATION OF THE RULER IN USE

    Loads species specified and measures the species with
    Ruler(). Plots and displays the dfferent leaf images.
    :param species:
    :param ruler:
    :return:
    """

    # state current leaf species and localize path
    tc.print(
        (species.bin_nom, species.load_locations, species.get_leaf_paths()[0]),
        4, _f)
    leaf_path = species.get_leaf_paths()[0]

    # load the leaf with the ruler
    ruler.load_new_image(leaf_path)

    # img, lines, lines2, lines3, length, center_range
    img = ruler.leaf
    hough_center = ruler.vein_measure['hough center']
    hough_above = ruler.vein_measure['hough above']
    hough_below = ruler.vein_measure['hough below']
    hough_range = ruler.vein_measure['center range']
    midrib_line = ruler.vein_measure['midrib lin approx']
    length = ruler.length

    print(hough_above)

    # displaying data with pyplot and matplotlib
    fig, axes = plt.subplots(2, 2, figsize=(5, 2))
    ax = axes.ravel()
    ax[0].imshow(img, cmap=plt.cm.gray)
    ax[0].set_title('{0}, {1}cm'.format(species.bin_nom, length))
    row, col = img.shape
    ax[1].axis((0, col, row, 0))
    ax[1].imshow(-img, cmap=plt.cm.gray)
    for line in hough_center:
        p0, p1 = line
        ax[1].plot((p0[0], p1[0]), (p0[1], p1[1]), 'b')
    for line in hough_above:
        p0, p1 = line
        ax[1].plot((p0[0], p1[0]), (p0[1], p1[1]), 'g')
    for line in hough_below:
        p0, p1 = line
        ax[1].plot((p0[0], p1[0]), (p0[1], p1[1]), 'r')
    ax[1].plot((0, img.shape[1]), (hough_range[0], hough_range[0]), 'b--')
    ax[1].plot((0, img.shape[1]), (hough_range[1], hough_range[1]), 'g--')
    ax[1].plot((0, img.shape[1]), (midrib_line(0), midrib_line(img.shape[1])))
    ax[2].imshow(ruler.leaf_bin, cmap=plt.cm.gray)
    ax[2].set_title('{0} binary'.format(species.bin_nom))
    ax[3].imshow(ruler.scale_bin, cmap=plt.cm.gray)
    ax[3].set_title('{0} scale'.format(species.bin_nom))

    plt.show()
Ejemplo n.º 5
0
def main(file_name):
    """Fonction qui s'effectuera lorsque l'on lance ce script"""
    f = open(file_name, "r")
    content = f.read()
    tab_lines0 = content.split('\n') #Sépare selon les lignes
    tab_lines = []
    for line in tab_lines0:
        if line != "":
            tab_lines.append(line) #On retire les lignes vides
    for i in range(0, len(tab_lines) - 1, 2):
        ruler = Ruler(tab_lines[i], tab_lines[i+1])
        ruler.compute()
        d = ruler.distance
        top, bottom = ruler.report()
        print("====== Comparaison # " + str(i//2 + 1) +" - distance = " + str(d))
        print(top)
        print(bottom)
    f.close()
Ejemplo n.º 6
0
    def __init__(self, scene):
        super(SceneView, self).__init__(scene)
        self.setMouseTracking(True)
        self.setViewportMargins(20, 20, 0, 0)
        gridLayout = QGridLayout()
        gridLayout.setSpacing(0)

        self.horizontalRuler = Ruler(Ruler.Horizontal)
        self.verticalRuler = Ruler(Ruler.Vertical)

        self.corner = QWidget()
        self.corner.setBackgroundRole(QPalette.Window)
        self.corner.setFixedSize(20, 20)
        gridLayout.addWidget(self.corner, 0, 0)
        gridLayout.addWidget(self.horizontalRuler, 0, 1)
        gridLayout.addWidget(self.verticalRuler, 1, 0)
        gridLayout.addWidget(self.viewport(), 1, 1)

        self.setLayout(gridLayout)
Ejemplo n.º 7
0
def iter_rule(datfile: '.txt'):
    """
    itérateur qui parcoure le fichier texte et 
    effectue la comparaison de chaine sur les deux premières lignes qu'il trouve
    """
    with open(datfile, 'r') as f:
        string1 = ""
        string2 = ""
        for line in f:
            if line == '' or line == ' ' or line == '\n':  # on passe si la liste est vide
                pass
            elif string1 == '':  # on stocke la première ligne
                string1 = line
            elif string2 == '':  # on stocke la seconde ligne
                string2 = line

                ruler = Ruler(string1, string2)
                string1, string2 = '', ''  # on vide le stockage
                ruler.compute()
                top, bottom = ruler.report()

                yield ruler.distance, top, bottom
Ejemplo n.º 8
0
    def __init__(self, config={}):
        QAbstractScrollArea.__init__(self)
        self.setFocusPolicy(Qt.NoFocus)

        self._ui_model = None
        self._updater = None

        # Widgets
        self.setViewport(View())

        self._corner = QWidget()
        self._corner.setStyleSheet('QWidget { background-color: #000 }')

        self._ruler = Ruler()
        self._header = Header()

        # Config
        self._config = None
        self._set_config(config)

        # Layout
        g = QGridLayout()
        g.setSpacing(0)
        g.setMargin(0)
        g.addWidget(self._corner, 0, 0)
        g.addWidget(self._ruler, 1, 0)
        g.addWidget(self._header, 0, 1)
        g.addWidget(self.viewport(), 1, 1)
        self.setLayout(g)

        self.viewport().setFocusProxy(None)

        self.setVerticalScrollBar(LongScrollBar())
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)

        QObject.connect(
                self.viewport(),
                SIGNAL('heightChanged()'),
                self._update_scrollbars)
        QObject.connect(
                self.viewport(),
                SIGNAL('followCursor(QString, int)'),
                self._follow_cursor)
Ejemplo n.º 9
0
class Controller:
    def __init__(self, texture, capacity):

        self.rules = Ruler()
        self.texture = Texture(texture)
        self.capacity = Capacity(capacity)

    def writeData(self, data):
        f = open("output.txt", "a")
        f.write(data)
        f.write(" ")
        f.close()

    def solve(self):

        result = self.rules.evaluate(self.texture, self.capacity)

        #print(result)
        #print(sorted(list(result.items()), key = lambda x: x[1])[-1][0])
        data = sorted(list(result.items()), key=lambda x: x[1])[-1][0]
        self.writeData(data)
        print(data)
Ejemplo n.º 10
0
__author__ = "Patrick Thomas"
__credits__ = ["Patrick Thomas", "Rick Fisher"]
__version__ = "1.0.0"
__date__ = "11/30/16"
__maintainer__ = "Patrick Thomas"
__email__ = "*****@*****.**"
__status__ = "Development"

# global variables
IMAGE_DIR = join(getcwd(), 'input-images')  # master image directory

# start main
if __name__ == '__main__':
    # create ruler
    ruler = Ruler()

    # use_ruler(Liriodendron_tulipifera, r)
    # print("saving data to ruler")
    # r.save_data(Liriodendron_tulipifera.bin_nom)

    # load the leaves from the harddrive
    leaves_list = load_species_structured(IMAGE_DIR)

    # get a leaf
    selected_leaf = [species for species in leaves_list if species.bin_nom == 'Acer pensylvanicum'][0]

    leaf_path = selected_leaf.get_leaf_paths()[3]

    # load the leaf with the ruler
    ruler.load_new_image(leaf_path)
Ejemplo n.º 11
0
from ruler import Ruler
import sys

dataset = sys.argv[1]
"""On ouvre le fichier contenant les chaines à comparer.
    On parcourt le fichier et on remplit une liste avec les lignes non vides du texte.
    On compare les lignes deux à deux en utilisant la classe Ruler. puis on 
    renvoie sous le format demandé les informations voulues
    """

with open(dataset, 'r') as fichier:  #ouvre le fichier dataset
    liste = []

    for ligne in fichier.readlines():
        if ligne != '\n':  #la ligne est non vide

            if ligne[-1] == '\n':
                ligne = ligne[:-1]

            liste.append(ligne)
            i = 1
            if len(liste) > 1:
                ruler = Ruler(liste[0], liste[1])
                ruler.compute()
                print(f'====== example # {i} - distance = {ruler.distance}')
                print(ruler.top)
                print(ruler.bottom)
                i = i + 1
                liste = []
Ejemplo n.º 12
0
 def __init__(self):
     self.ruler = Ruler()
     for i in range(len(_rules)):
         self.ruler.append(_rules[i][0], _rules[i][1])
import sys
from ruler import Ruler

DATASET = sys.argv[1]

with open(DATASET, "r") as data:
    lines = data.readlines()
    l = len(lines) // 2
    for i in range(l):
        line1 = lines[2 * i]
        line2 = lines[2 * i + 1]
    if line1[-1] == '\n':
        line1 = line1[0:len(line1) - 1]
    if line2[-1] == '\n':
        line2 = line1[0:len(line2) - 1]

    R = Ruler(line1, line2)
    R.compute()
    print(f'=========== comparaison n° {i} -- distance = {R.distance}')
    top, bot = R.report()
    print(top)
    print(bot)
Ejemplo n.º 14
0
import sys
from ruler import Ruler

filename = sys.argv[1]
fichier = open(filename, "r")

lines = fichier.readlines()

for line in lines:
    if line == "":
        del line

if len(lines) % 2 != 0:
    lines.pop()

for i in range(len(lines) // 2):
    ruler = Ruler(lines[2 * i], lines[2 * i + 1])
    ruler.compute()
    top, bottom = ruler.report()
    print(f"====== exemple # {i} - distance = {ruler.distance}")
    print(top)
    print(bottom)

fichier.close()
Ejemplo n.º 15
0
##Exercice 1

from ruler import Ruler

# on crée un objet pour mesurer
# la distance entre deux chaines
ruler = Ruler("abcdefghi", "abcdfghi")

# on impose à l'utilisateur de la classe
# de lancer explicitement le calcul
ruler.compute()

# on obtient la distance
print(ruler.distance)

# et pour afficher les différences
top, bottom = ruler.report()
print(top)
print(bottom)
Ejemplo n.º 16
0
liste = []
with open(argument2) as txtfile:
    data = txtfile.read()
    data = data.split("\n")
    i, j = 0, 1
    while i < len(data):
        while i < len(data) and data[i] == "":
            i += 1  #On cherche une chaine non vide pour la première chaîne
        j = i + 1
        while j < len(data) and data[
                j] == "":  #On cherche une chaîne non vide pour la deuxième chaîne
            j += 1

        if j <= len(data) - 1 and data[
                j] != "":  #Cette condition permet de verifier que deux chaînes non vide ont été trouvées
            liste.append([data[i], data[j]])
        i = j + 1  #On recommence juste après la dernière chaîne trouvée non vide

if liste == []:  #Si le fichier ne contenait pas deux chaines de caractère au moins:
    print("Moins de deux chaînes présentes")
    exit()

for index, k in enumerate(liste):
    ruler = Ruler(k[0], k[1])
    ruler.compute()
    print(f"________Exemple {index+1}________\n")
    top, bottom = ruler.report()
    print(top + "\n")
    print(bottom)
Ejemplo n.º 17
0
import sys
from ruler import Ruler

file_name = sys.argv[
    1]  #sys.argv permet de créer une liste avec les arguments rentrés dans cmd
f = open(file_name, 'r')
a = f.readlines()
k = 0
b = []
for i in range(len(a)):
    b.append(a[i].replace('\n', ''))

for i in range(0, len(b) - 1, 2):
    ruler = Ruler(b[i], b[i + 1])
    top, bottom = ruler.report()
    k += 1
    print(f"===== example #{k} - distance {ruler.distance}\n{top}\n{bottom}\n")
Ejemplo n.º 18
0
import sys
from ruler import Ruler  #on importe notre classe

file_name = sys.argv[
    1]  #sys.argv permet de créer une liste avec les arguments rentrés dans cmd
fichier1 = open(file_name, "r")  #on met en deuxième le nom du fichier à lire

L = []  #L est une liste contenant les strings contenu dans le fichier texte

for ligne in fichier1:
    l = ligne.replace('\n', "")  #on enlève les \n dans chaque string

    if l != "":  #si jamais on a une ligne vide, on passe à la ligne suivante
        L.append(l)

i = 0

while i < len(L) - 1:  #on s'arrête à l'avant-avant-dernier
    ruler = Ruler(L[i], L[i + 1])  #on applique la classe Ruler
    ruler.compute()
    top, bottom = ruler.report()
    print(f'''-----------------example #{i//2 + 1} distance = {ruler.distance}
    {top}
    {bottom}''')
    i += 2
Ejemplo n.º 19
0
# file = open('DATASET.txt')
from ruler import Ruler
import sys

filename = sys.argv[1]
file = open(filename)

i = 1
while True:
    try:
        l1 = next(file)
        l2 = next(file)
        ruler = Ruler(l1, l2)
        ruler.compute()
        print(f"====== example # {i} - distance = {ruler.distance}")
        top, bottom = ruler.report()
        print(top)
        print(bottom)
        i += 1
    except StopIteration:
        break
Ejemplo n.º 20
0
from ruler import Ruler

ruler = Ruler('abcdfgh', 'abcdefg')

#On lance le calcul de la comparaison des deux séquences
ruler.compute()

#Expression de la distance entre les deux séquences
print(ruler.distance)

#Impression des deux séquences avec éléments de comparaison en couleur
top, bottom = ruler.report()
print(top)
print(bottom)
Ejemplo n.º 21
0
import sys
from ruler import Ruler

DATASET = sys.argv[1]

with open(DATASET, "r") as dataset:
    lignes = dataset.readlines()
    # on prend les lignes 2 par 2:
    l = len(lignes) // 2

for i in range(l):
    A = str(lignes[2 * i])
    B = str(lignes[2 * i + 1])
    ruler = Ruler(A, B)
    ruler.compute()
    d = ruler.distance
    top, bottom = ruler.report()
    print(f"====== example # {i} - distance = {d}")
    print(top)
    print(bottom)
Ejemplo n.º 22
0
# -*- coding: utf-8 -*-

"""
Created on Wed Jan 15 14:43:36 2020
@author: Perrotin
"""

from ruler import Ruler
import sys

DATASET = sys.argv[1]

with open(DATASET, 'r') as dataset:

    ligne = dataset.readlines()
    nombre_lignes = len(ligne)

    for i in range(nombre_lignes//2):
        # On lance Ruler sur deux lignes successives

        ruler = Ruler(ligne[2*i].strip(), ligne[2*i+1].strip())
        ruler.compute()
        top, bottom = ruler.report()

        # On affiche le résultat

        print('====== example # {} - distance = {}'.format(i+1, ruler.distance))
        print(top)
        print(bottom)
Ejemplo n.º 23
0
parser.add_argument("dataset", help="Couples de fragments", type=str)

args = parser.parse_args()

texte = args.dataset

with open(texte, 'r') as fichier:
    """
    On extrait les chaînes à comparer d'un dataset au format txt.
    Cette méthode permet d'éviter la dernière ligne si en nombre impair.
    On groupe les chaînes à comparer par paires.
    """
    liste = []
    swap = []
    for ligne in fichier:
        if len(ligne) != 0:
            if len(swap) == 0:
                swap.append(ligne)
            else:
                liste.append((swap[0], ligne))
                swap = []

for k in range(len(liste)):
    ruler = Ruler(*liste[k])
    ruler.compute()
    d = ruler.distance
    top, bottom = ruler.report()
    print(f"====== example # {k} - distance = {d}")
    print(top)
    print(bottom)
Ejemplo n.º 24
0
__author__ = "Patrick Thomas"
__credits__ = ["Patrick Thomas", "Rick Fisher"]
__version__ = "1.0.0"
__date__ = "11/30/16"
__maintainer__ = "Patrick Thomas"
__email__ = "*****@*****.**"
__status__ = "Development"

# global variables
IMAGE_DIR = join(getcwd(), 'input-images')  # master image directory

# start main
if __name__ == '__main__':
    # create ruler
    ruler = Ruler()

    # use_ruler(Liriodendron_tulipifera, r)
    # print("saving data to ruler")
    # r.save_data(Liriodendron_tulipifera.bin_nom)

    # load the leaves from the harddrive
    leaves_list = load_species_structured(IMAGE_DIR)

    # get a leaf
    sugar_maple = [
        species for species in leaves_list
        if species.bin_nom == 'Acer pensylvanicum'
    ][0]

    leaf_path = sugar_maple.get_leaf_paths()[3]
Ejemplo n.º 25
0
import sys
from ruler import Ruler

DATASET = sys.argv[1]
# L'argument envoyé par le sytème est [bundle.py, fichier.txt]

with open(DATASET, "r") as dataset:
    lignes = dataset.readlines()
    l = len(lignes) // 2  # On enlève éventuellement la dernière ligne
    for i in range(l):
        bringauche = str(lignes[2 * i])
        brindroit = str(lignes[2 * i + 1])
        if bringauche[-1] == '\n':  # on enlève les newlignes
            bringauche = bringauche[:-1]
        if brindroit[-1] == '\n':
            brindroit = brindroit[:-1]
        ruler = Ruler(bringauche, brindroit)
        ruler.compute()
        print(f'===== example {i} - distance = {ruler.distance}')
        (a, b) = ruler.report()
        print(a)
        print(b)
Ejemplo n.º 26
0
__author__ = "Patrick Thomas"
__credits__ = ["Patrick Thomas", "Rick Fisher"]
__version__ = "1.0.0"
__date__ = "11/29/16"
__maintainer__ = "Patrick Thomas"
__email__ = "*****@*****.**"
__status__ = "Development"

# global variables
IMAGE_DIR = join(getcwd(), 'input-images')  # master image directory

# start main
if __name__ == '__main__':
    # create ruler
    ruler = Ruler()

    # use_ruler(Liriodendron_tulipifera, r)
    # print("saving data to ruler")
    # r.save_data(Liriodendron_tulipifera.bin_nom)

    # load the leaves from the harddrive
    leaves_list = load_species_structured(IMAGE_DIR)

    # get a leaf
    sugar_maple = [species for species in leaves_list if species.bin_nom == 'Acer saccharum'][0]

    leaf_path = sugar_maple.get_leaf_paths()[3]

    # load the leaf with the ruler
    ruler.load_new_image(leaf_path)
Ejemplo n.º 27
0
#Program to compare strings from a file which the path is given in argument

from ruler import Ruler
import sys

if __name__ == "__main__":
    file_path = sys.argv[1]
    with open(file_path, 'r') as file:
        args = list()
        i = 1
        for line in file.readlines():
            if line != '\n' and line != '':
                if line[-1] == '\n':
                    line = line[:-1]
                args.append(line)
                if len(args) == 2:
                    ruler = Ruler(args[0], args[1])
                    args = []
                    ruler.compute()
                    print("===== Exemple # {} - distance = {}".format(
                        i, ruler.distance))
                    print(ruler.top)
                    print(ruler.bottom)
                    i += 1
                    del ruler
Ejemplo n.º 28
0
import numpy as np
from colorama import Fore, Style
import os
os.chdir("C:/Users/Lenovo/Documents/GitHub/python-eval/needleman_wunsch")
mon_fichier = open("DATASET.txt", "r")
#on le lit avec read.
import ruler
from ruler import Ruler


contenu = mon_fichier.read()
contenu = contenu.split()
print(contenu)
i=0
while i < len(contenu) : 
    ruler = Ruler(contenu[i], contenu[i+1])
    print(ruler.distance(contenu[i], contenu[i+1],ruler.compute(contenu[i], contenu[i+1])))
    i +=2


#python3 bundle.py DATASET

Ejemplo n.º 29
0
from ruler import Ruler

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("nom_fichier",
                    type=str,
                    help="fichier contenant des chaines à tester")
args = parser.parse_args()
nom = args.nom_fichier

with open('DATASET.csv', "r") as fichier:
    L = []
    for e in fichier:
        L.append(e)
    for i in range(0, len(L) - 1, 2):
        a = Ruler(L[i], L[i + 1])
        a.compute()
        top, bottom = a.report()
        print(f'''Example # {(i+1)//2 + 1} - distance = {a.distance}
        {top}
        {bottom}''')

# LE CODE MARCHE EN TAPANT python bundle.py DATASET.csv DANS ANACONDA PROMPT
Ejemplo n.º 30
0
 def __init__(self):
     self.ruler = Ruler()
     for i in range(len(_rules)):
         self.ruler.append(_rules[i][0], _rules[i][1], {'alt': list(_rules[i][2] or [])})
Ejemplo n.º 31
0
import argparse


# Pour récupérer le nom du fichier
parser = argparse.ArgumentParser()
parser.add_argument("nom_fichier", type=str, help='')
args = parser.parse_args()
nom = args.nom_fichier

# Construction de la dataframe
df = pd.read_csv(nom, sep='\t', header=None)
df.head(10)

# On remplace les lignes vides par des NaN pour implémenter dropna()
# Attention, le skip empty lines est implémenté dans le read_csv donc ces deux lignes risquent d'être redondante
df[0].replace('', np.nan, inplace=True)
df.dropna(inplace=True)

# On enlève la dernière ligne si le nombre de lignes n'est pas pair
if len(df) % 2 != 0:
    df = df.drop(len(df.index)-1)

for i in range(len(df)//2):
    ruler = Ruler(df[0][2*i], df[0][2*i+1])
    ruler.compute()
    a = ruler.distance
    top, bottom = ruler.report()
    print(f'====== example # {i+1} - distance = {a} ')
    print(top)
    print(bottom)
Ejemplo n.º 32
0
class SheetArea(QAbstractScrollArea):

    def __init__(self, config={}):
        QAbstractScrollArea.__init__(self)
        self.setFocusPolicy(Qt.NoFocus)

        self._ui_model = None
        self._updater = None

        # Widgets
        self.setViewport(View())

        self._corner = QWidget()
        self._corner.setStyleSheet('QWidget { background-color: #000 }')

        self._ruler = Ruler()
        self._header = Header()

        # Config
        self._config = None
        self._set_config(config)

        # Layout
        g = QGridLayout()
        g.setSpacing(0)
        g.setMargin(0)
        g.addWidget(self._corner, 0, 0)
        g.addWidget(self._ruler, 1, 0)
        g.addWidget(self._header, 0, 1)
        g.addWidget(self.viewport(), 1, 1)
        self.setLayout(g)

        self.viewport().setFocusProxy(None)

        self.setVerticalScrollBar(LongScrollBar())
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)

        QObject.connect(
                self.viewport(),
                SIGNAL('heightChanged()'),
                self._update_scrollbars)
        QObject.connect(
                self.viewport(),
                SIGNAL('followCursor(QString, int)'),
                self._follow_cursor)

    def set_ui_model(self, ui_model):
        self._ui_model = ui_model
        self._updater = ui_model.get_updater()
        self._updater.register_updater(self._perform_updates)
        self._sheet_manager = ui_model.get_sheet_manager()

        # Default zoom level
        px_per_beat = self._config['trs_per_beat'] * self._config['tr_height']
        self._zoom_levels = self._get_zoom_levels(1, px_per_beat, tstamp.BEAT)
        self._default_zoom_index = self._zoom_levels.index(px_per_beat)
        self._sheet_manager.set_zoom_range(
                -self._default_zoom_index,
                len(self._zoom_levels) - self._default_zoom_index - 1)

        # Default column width
        fm = self._config['font_metrics']
        em_px = int(math.ceil(fm.tightBoundingRect('m').width()))
        em_range = list(range(3, 41))
        self._col_width_levels = [em_px * width for width in em_range]
        self._default_col_width_index = em_range.index(self._config['col_width'])
        self._sheet_manager.set_column_width_range(
                -self._default_col_width_index,
                len(self._col_width_levels) - self._default_col_width_index - 1)

        self._set_px_per_beat(self._zoom_levels[self._default_zoom_index])
        self._set_column_width(self._col_width_levels[self._default_col_width_index])

        # Child widgets
        self._ruler.set_ui_model(ui_model)
        self.viewport().set_ui_model(ui_model)

    def unregister_updaters(self):
        self._updater.unregister_updater(self._perform_updates)
        self._ruler.unregister_updaters()
        self.viewport().unregister_updaters()

    def _perform_updates(self, signals):
        if 'signal_sheet_zoom' in signals:
            self._update_zoom()
        if 'signal_sheet_column_width' in signals:
            self._update_column_width()

    def _set_config(self, config):
        self._config = DEFAULT_CONFIG.copy()
        self._config.update(config)

        for subcfg in ('ruler', 'header', 'trigger', 'edit_cursor'):
            self._config[subcfg] = DEFAULT_CONFIG[subcfg].copy()
            if subcfg in config:
                self._config[subcfg].update(config[subcfg])

        self._header.set_config(self._config)
        self._ruler.set_config(self._config['ruler'])

        header_height = self._header.minimumSizeHint().height()
        ruler_width = self._ruler.sizeHint().width()

        self.setViewportMargins(
                ruler_width,
                header_height,
                0, 0)

        self._corner.setFixedSize(
                ruler_width,
                header_height)
        self._header.setFixedHeight(header_height)
        self._ruler.setFixedWidth(ruler_width)

        fm = QFontMetrics(self._config['font'], self)
        self._config['font_metrics'] = fm
        self._config['tr_height'] = fm.tightBoundingRect('Ag').height() + 1

        self.viewport().set_config(self._config)

    def _get_zoom_levels(self, min_val, default_val, max_val):
        zoom_levels = [default_val]

        # Fill zoom out levels until minimum
        prev_val = zoom_levels[-1]
        next_val = prev_val / self._config['zoom_factor']
        while int(next_val) > min_val:
            actual_val = int(next_val)
            assert actual_val < prev_val
            zoom_levels.append(actual_val)
            prev_val = actual_val
            next_val = prev_val / self._config['zoom_factor']
        zoom_levels.append(min_val)
        zoom_levels = list(reversed(zoom_levels))

        # Fill zoom in levels until maximum
        prev_val = zoom_levels[-1]
        next_val = prev_val * self._config['zoom_factor']
        while math.ceil(next_val) < tstamp.BEAT:
            actual_val = int(math.ceil(next_val))
            assert actual_val > prev_val
            zoom_levels.append(actual_val)
            prev_val = actual_val
            next_val = prev_val * self._config['zoom_factor']
        zoom_levels.append(tstamp.BEAT)

        return zoom_levels

    def _set_px_per_beat(self, px_per_beat):
        self._ruler.set_px_per_beat(px_per_beat)
        self.viewport().set_px_per_beat(px_per_beat)

    def _set_column_width(self, width):
        self._header.set_column_width(width)
        self.viewport().set_column_width(width)

    def _update_scrollbars(self):
        if not self._ui_model:
            return

        self._total_height_px = (
                self.viewport().get_total_height() + self._config['tr_height'])

        vp_height = self.viewport().height()
        vscrollbar = self.verticalScrollBar()
        vscrollbar.setPageStep(vp_height)
        vscrollbar.set_actual_range(0, self._total_height_px - vp_height)

        vp_width = self.viewport().width()
        cur_col_width_index = self._sheet_manager.get_column_width() + self._default_col_width_index
        max_visible_cols = vp_width // self._col_width_levels[cur_col_width_index]
        hscrollbar = self.horizontalScrollBar()
        hscrollbar.setPageStep(max_visible_cols)
        hscrollbar.setRange(0, COLUMN_COUNT - max_visible_cols)

    def _follow_cursor(self, new_y_offset_str, new_first_col):
        new_y_offset = long(new_y_offset_str)
        vscrollbar = self.verticalScrollBar()
        hscrollbar = self.horizontalScrollBar()
        old_y_offset = vscrollbar.get_actual_value()
        old_scaled_y_offset = vscrollbar.value()
        old_first_col = hscrollbar.value()

        self._update_scrollbars()
        vscrollbar.set_actual_value(new_y_offset)
        hscrollbar.setValue(new_first_col)

        if (old_scaled_y_offset == vscrollbar.value() and
                old_first_col == hscrollbar.value()):
            if old_y_offset != vscrollbar.get_actual_value():
                # Position changed slightly, but the QScrollBar doesn't know this
                self.scrollContentsBy(0, 0)
            else:
                # Position not changed, so just update our viewport
                self.viewport().update()

    def _update_zoom(self):
        zoom_level = self._sheet_manager.get_zoom()
        cur_zoom_index = zoom_level + self._default_zoom_index
        self._set_px_per_beat(self._zoom_levels[cur_zoom_index])

    def _update_column_width(self):
        column_width_level = self._sheet_manager.get_column_width()
        cur_col_width_index = column_width_level + self._default_col_width_index
        self._set_column_width(self._col_width_levels[cur_col_width_index])

    def paintEvent(self, ev):
        self.viewport().paintEvent(ev)

    def resizeEvent(self, ev):
        self._update_scrollbars()

    def scrollContentsBy(self, dx, dy):
        hvalue = self.horizontalScrollBar().value()
        vvalue = self.verticalScrollBar().get_actual_value()

        self._header.set_first_column(hvalue)
        self._ruler.set_px_offset(vvalue)

        vp = self.viewport()
        vp.set_first_column(hvalue)
        vp.set_px_offset(vvalue)

    def mousePressEvent(self, event):
        self.viewport().mousePressEvent(event)