#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys, os
import sqlite3
import locale
import ntpath
import configparser

try:
    from gi.repository import Gtk as gtk, GdkPixbuf
except:
    print("GTK (PyGI) n'est pas installé")
    sys.exit(1)

__BDD__ = "bdd/main.db"
__CONFDIR__ = os.path.dirname(os.path.realpath("MesCigares.py"))
__CONFIGFILE__ = "conf/mescigares.conf"

class MesCigares:

    def on_window_main_destroy(self, widget, data=None):
        db.close()
        gtk.main_quit()

    def on_gtk_quit_activate(self, menuitem, data=None):
        db.close()
        gtk.main_quit()

    def on_gtk_about_activate(self, menuitem, data=None):
        self.aboutdialog.run()
        self.aboutdialog.hide()

    # Mise à jour de la quantité en fonction du cigare choisi dans la liste déroulante
    def on_cbchoixcigqte_changed(self,object,data=None):
        item = self.cbchoixcigqte.get_active()

        # Si aucune séléction, pas besoin de traitement.
        if item == -1:
            return

        model = self.cbchoixcigqte.get_model()
        idc = model[item]

        cursor = db.cursor()
        qte = cursor.execute("Select quantite from stocks where id_cigare = '{0}'".format(idc[0])).fetchone()[0]
        cursor.close()

        self.scaleqte.set_value(int(qte))

    # Permet d'alimenter la treeview avec la liste des cigares
    def loadtreeview(self):
        if len(self.table) != 0:
           self.table.clear()

        cursor = db.cursor()
        cursor.execute('Select c.designation, m.libelle, mo.module,m.provenance, s.quantite,c.id from cigares c inner join modules mo  on mo.id = c.module inner join marques m on m.id = c.marque inner join stocks s on s.id_cigare = c.id')
        rs = cursor.fetchall()

        cursor.execute("select avg(d.note), max(d.note),id_cigare from degustation d group by id_cigare")
        rs2 = cursor.fetchall()
        # top = 5 premier items de la liste par meilleure note [2] pour la note seulement
        top = sorted(rs2, reverse=True)[0:5]
        print (top)
        # top5 = juste les id
        top5  = list()
        for i in top:
            top5.append(i[2])

        cursor.execute("select min(prix),id_cigare from achats group by id_cigare")
        rs3 = cursor.fetchall()

        cursor.execute("select commentaires, id_cigare from degustation group by id_cigare")
        rs4 = cursor.fetchall()

        for item in rs:
            iter = self.table.append()
            # Si le nombre de cigares est = 0 on affiche la ligne en rouge clair
            if (item[4] == 0):
                color = '#F3B9B9' # rouge clair
            else:
                color = '#FFFFFF' # blanc

            # On regarde si l'enregistrement est dans le top 5
            try:
                index = top5.index(item[5])
            except:
                index = 9
            # Et on affecte la couleur (dégradé de vert)
            if(index == 0):
                topcolor = '#8FFF80'
            if(index == 1):
                topcolor = '#A4FF97'
            if(index == 2):
                topcolor = '#BFFFB7'
            if(index == 3):
                topcolor = '#CDFFC7'
            if(index == 4):
                topcolor = '#DBFFD7'
            if(index == 9):
                topcolor = color

            self.table.set(iter, 0, item[0], 1, item[1], 2, item[2].title(), 3, item[3].title(), 4, item[4], 5, item[5], 11, color, 12, topcolor)
        # Il n'y a pas de outer join en sqlite du coup je suis obligé d'alimenter les notes à part
        for item2 in rs2:
            itr = self.table.get_iter_first()
            while ( itr != None ):
                # itr, 5 = id de la table cigare (colonne 4 invisible), item2[2] = id_cigare table degustation
                if self.table.get_value (itr, 5) == item2[2]:
                    self.table.set(itr, 6, item2[1], 7, item2[0])
                itr= self.table.iter_next(itr)
        for item3 in rs3:
            itr = self.table.get_iter_first ()
            while ( itr != None ):
                # itr, 5 = id de la table cigare (colonne 4 invisible), item3[1] = id_cigare table achats
                if self.table.get_value (itr, 5) == item3[1]:
                    # .2f pour 2 decimales
                    it = '%.2f' % item3[0]
                    self.table.set(itr, 8, it + " €", 10, float(item3[0]))
                itr= self.table.iter_next(itr)
        for item4 in rs4:
            itr = self.table.get_iter_first ()
            while ( itr != None ):
                # itr, 4 = id de la table cigare (colonne 4 invisible), item4[1] = id_cigare table achats
                if self.table.get_value (itr, 5) == item4[1]:
                    self.table.set(itr, 9, item4[0])
                itr= self.table.iter_next(itr)

        # On calcule le nombre de cigares et le prix
        nbcigares = 0
        montant = 0
        itr = self.table.get_iter_first ()
        while ( itr != None ):
            nbcigares += int(self.table.get_value(itr, 4))
            if self.table.get_value(itr, 8) is not None:
                montant += float(self.table.get_value(itr, 10)) * int(self.table.get_value(itr, 4))
            itr= self.table.iter_next(itr)
        montant = '%.2f' % montant

        # On calcule le prix total
        montant_total = 0
        cursor.execute("select prix, quantite from achats")
        rs = cursor.fetchall()

        for item in rs:
            montant_total += (item[0] * item[1])
        montant_total = '%.2f' % montant_total

        cursor.close()
        # On affiche le nombre de résultats trouvés sur la barre de statut
        if nbcigares == 0:
            self.statusbar.push(self.context_id, "Aucun cigare dans la base")
        else:
            self.statusbar.push(self.context_id, str(nbcigares) + " cigares dans la base pour un montant de " + str(montant) + "€ - (" + str(montant_total) + "€ depuis le début)")

    # Permet l'affichage de la photo du cigare séléctionné dans la zone rétractable
    def affiche_preview(self):

        cursor = db.cursor()
        photo = cursor.execute("select photo from photos where id_cigare = '{0}'".format(self.treeview_selection[5]))

        try:
           photo = cursor.fetchone()[0]
        except TypeError:
            photo = None
        cursor.close()
        # Si aucune photo n'existe pour ce cigare
        if(photo is None):
            photo = __CONFDIR__ + "/images/no_photo.jpg"
            self.image_preview.set_from_file(photo)
        else:
            if os.path.exists(photo):
                pixbuf = GdkPixbuf.Pixbuf().new_from_file(photo)
                # Si l'image est plus grande que la fenêtre on re-dimensionne
                new_size = self.window.get_size()[0] - 20
                if(pixbuf.get_width() > new_size):
                    w, h = pixbuf.get_width(), pixbuf.get_height()
                    pixbuf = pixbuf.scale_simple( new_size, new_size * h / w, GdkPixbuf.InterpType.HYPER)
                # Si la largeur de l'image est plus petite que la hauteur on fait pivoter
                if(pixbuf.get_width() < pixbuf.get_height()):
                    pixbuf = pixbuf.rotate_simple(270)
                # Si la hauteur est dépasse la moitié de la fenêtre principale, on re-dimensionne
                if(pixbuf.get_height() > self.window.get_size()[1]/2):
                    w, h = pixbuf.get_width(), pixbuf.get_height()
                    pixbuf = pixbuf.scale_simple( (w * self.window.get_size()[1]/2)/h, self.window.get_size()[1]/2 , GdkPixbuf.InterpType.HYPER)
                self.image_preview.set_from_pixbuf(pixbuf)
            else:
                # Si la photo n'existe plus ou a été renommée
                photo = __CONFDIR__ + "/images/bad_photo.jpg"
                self.image_preview.set_from_file(photo)
        self.imgpath = photo

    # Si la fenêtre principale change de taille on re-dimensionne le preview aussi
    def on_window_main_check_resize(self, widget):
        #print(self.window.get_size()[1],self.window_last_h)
        if (( abs(self.window_last_h - self.window.get_size()[1]) > 40) | ( abs(self.window_last_w - self.window.get_size()[0]) > 5) ):
            self.window_last_h = self.window.get_size()[1]
            self.window_last_w = self.window.get_size()[0]

            if not os.path.exists(self.imgpath):
                return
            pixbuf = GdkPixbuf.Pixbuf().new_from_file(self.imgpath)
            # Si l'image est plus grande que la fenêtre on re-dimensionne
            new_size = self.window.get_size()[0] - 20
            if(pixbuf.get_width() > new_size):
                w, h = pixbuf.get_width(), pixbuf.get_height()
                pixbuf = pixbuf.scale_simple( new_size, new_size * h / w, GdkPixbuf.InterpType.HYPER)
            # Si la largeur de l'image est plus petite que la hauteur on fait pivoter
            if(pixbuf.get_width() < pixbuf.get_height()):
                pixbuf = pixbuf.rotate_simple(270)
            # Si la hauteur est dépasse la moitié de la fenêtre principale, on re-dimensionne
            if(pixbuf.get_height() > self.window.get_size()[1]/2):
                w, h = pixbuf.get_width(), pixbuf.get_height()
                pixbuf = pixbuf.scale_simple( (w * self.window.get_size()[1]/2)/h, self.window.get_size()[1]/2 , GdkPixbuf.InterpType.HYPER)
            self.image_preview.set_from_pixbuf(pixbuf)

    # Dès qu'une ligne est séléctionnée sur la treeview on enregistre les valeurs
    def on_treeview_cigares_row_activated(self, widget):
        selection = self.tree.get_selection()
        (model, iter) = selection.get_selected()
        if iter is not None:
            self.treeview_selection.clear()
            self.treeview_selection.append(model.get_value(iter, 0))
            self.treeview_selection.append(model.get_value(iter, 1))
            self.treeview_selection.append(model.get_value(iter, 2))
            self.treeview_selection.append(model.get_value(iter, 3))
            self.treeview_selection.append(model.get_value(iter, 4))
            self.treeview_selection.append(model.get_value(iter, 5))
            self.treeview_selection.append(model.get_value(iter, 6))
            self.treeview_selection.append(model.get_value(iter, 7))
            # for i in range(0,6):
            #     print(model.get_value(iter, i))
            # print("\n")
            # Et on met à jour l'affichage du preview
            self.affiche_preview()

    def get_libelle_quantite(self):
        selection = self.tree.get_selection()
        (model, iter) = selection.get_selected()
        if iter is not None:
            lib = model.get_value(iter, 0)
            qtee = model.get_value(iter,5)
            return(lib, qtee)

    # Changer de base de données
    def on_bdd_change_activate(self, widget):
        filter = gtk.FileFilter()
        filter.set_name("Bases sqlite")
        filter.add_mime_type("application/octet-stream")
        filter.add_pattern("*.db")
        self.filechooser_bdd.add_filter(filter)
        self.filechooser_bdd.set_current_folder(__CONFDIR__ + "/bdd/")
        self.filechooser_bdd.run()
        self.loadtreeview()
        self.filechooser_bdd.hide()

    # Double clic sur le sélécteur de fichiers pour choisir la bdd
    def on_filechooser_bdd_file_activated(self, widget):
        if not os.path.exists(self.filechooser_bdd.get_filename()):
            createdb(self.filechooser_bdd.get_filename())
        setconfig(self.filechooser_bdd.get_filename())
        global db
        db.close()
        db = sqlite3.connect(self.filechooser_bdd.get_filename())
        # On met à jour le titre de la fenêtre
        self.window.set_title("MesCigares - base : {0}".format(ntpath.basename(self.filechooser_bdd.get_filename().replace('.db',''))))
        self.loadtreeview()
        self.filechooser_bdd.hide()

    # Clic sur le bouton OK du sélécteur de fichiers pour choisir l'image
    def on_btchooseokbdd_clicked(self, widget):
        if not os.path.exists(self.filechooser_bdd.get_filename()):
            createdb(self.filechooser_bdd.get_filename())
        # changer la conf
        setconfig(self.filechooser_bdd.get_filename())
        global db
        db.close()
        db = sqlite3.connect(self.filechooser_bdd.get_filename())
        self.loadtreeview()

    # Ajouter une image pour un cigare
    def on_inserer_image_activate(self, widget):
        self.filechooser_image.run()
        self.filechooser_image.hide()

    # Modifier/Supprimer une note de degustation
    def on_modsupp_degustation_activate(self, widget):
        # On commence par vider la liststore_date_modif_degustation (2ème utilisation)
        if len(self.liststore_date_modif_degustation) != 0:
           self.liststore_date_modif_degustation.clear()

        cursor = db.cursor()
        # On regarde récupère le commentaire
        cursor.execute("select date, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12,  q13, id, commentaires from degustation where id_cigare = '{0}'".format(self.treeview_selection[5]))
        rs = cursor.fetchall()
        # si nb = 0 on insère sinon on update la table photos
        db.commit()
        cursor.close()

        if(len(rs) == 0):
            # Afficher un message d'infos pour alerter qu'il faut d'abord faire une dégustation
            self.msgdialog.format_secondary_text("Il n'y a aucune dégustation pour ce cigare")
            self.msgdialog.run()
            self.msgdialog.hide()
            return

        for item in rs:
            date = item[0]
            q1 = item[1]
            q2 = item[2]
            q3 = item[3]
            q4 = item[4]
            q5 = item[5]
            q6 = item[6]
            q7 = item[7]
            q8 = item[8]
            q9 = item[9]
            q10 = item[10]
            q11 = item[11]
            q12 = item[12]
            q13 = item[13]
            idcomm = item[14]
            commentaire = item[15]
            iter = self.liststore_date_modif_degustation.append()
            self.liststore_date_modif_degustation.set(iter, 0, date, 1, q1, 2, q2, 3, q3, 4, q4, 5, q5, 6, q6, 7, q7, 8, q8, 9, q9, 10, q10, 11, q11, 12, q12, 13, q13, 14, idcomm, 15, commentaire)

        # On affiche la fenêtre de modification du commentaire
        self.window_modif_degustation.run()
        self.window_modif_degustation.hide()
        # On recharge la treeview
        self.loadtreeview()

    # Changement sur la liste déroulante de choix de la not de dégustation à modifier/supprimer
    def on_cbchoix_date_modif_degustation_changed(self, widget):
        index = self.cbchoix_date_modif_degustation.get_active()
        q = list()
        try:
            for i in range(1, 14):
                q.append(self.liststore_date_modif_degustation[index][i])
            idcomm = self.liststore_date_modif_degustation[index][14]

        except IndexError:
            pass

        try:
            commentaire = self.liststore_date_modif_degustation[index][15]
            self.txtview_commentaire_modif.get_buffer().set_text(commentaire)
        except IndexError:
            self.txtview_commentaire_modif.get_buffer().set_text("")

        # On met la bonne valeur sur les scales
        try:
            self.scaleq1m.set_value(q[0])
            self.scaleq2m.set_value(q[1])
            self.scaleq3m.set_value(q[2])
            self.scaleq4m.set_value(q[3])
            self.scaleq5m.set_value(q[4])
            self.scaleq6m.set_value(q[5])
            self.scaleq7m.set_value(q[6])
            self.scaleq8m.set_value(q[7])
            self.scaleq9m.set_value(q[8])
            self.scaleq10m.set_value(q[9])
            self.scaleq11m.set_value(q[10])
            self.scaleq12m.set_value(q[11])
            self.scaleq13m.set_value(q[12])
        except IndexError:
            self.scaleq1m.set_value(1)
            self.scaleq2m.set_value(1)
            self.scaleq3m.set_value(1)
            self.scaleq4m.set_value(5)
            self.scaleq5m.set_value(2)
            self.scaleq6m.set_value(2)
            self.scaleq7m.set_value(2)
            self.scaleq8m.set_value(1)
            self.scaleq9m.set_value(1)
            self.scaleq10m.set_value(1)
            self.scaleq11m.set_value(1)
            self.scaleq12m.set_value(1)
            self.scaleq13m.set_value(1)


    # Calcul de la note globale pour modification d'une note de dégustation
    def on_scaleqm_change_value(self, scale, enum, new_value):
        # On récupère les notes
        q1=int(self.scaleq1m.get_value())
        q2=int(self.scaleq2m.get_value())
        q3=int(self.scaleq3m.get_value())
        q4=int(self.scaleq4m.get_value())
        q5=int(self.scaleq5m.get_value())
        q6=int(self.scaleq6m.get_value())
        q7=int(self.scaleq7m.get_value())
        q8=int(self.scaleq8m.get_value())
        q9=int(self.scaleq9m.get_value())
        q10=int(self.scaleq10m.get_value())
        q11=int(self.scaleq11m.get_value())
        q12=int(self.scaleq12m.get_value())
        q13=int(self.scaleq13m.get_value())

        note = q1 + q2 + q3 + q4 + q5 + q6 + q7 + q8 + q9 + q10 + q11 + q12 + q13
        # On affiche la note / 100 temporaire
        self.lbl_note_totale.set_text("Nouvelle note: {0}/100".format(note))

    # Validation de la modification d'une dégustation
    def on_btvalid_degustation_clicked(self, widget):
        # modifier
        index = self.cbchoix_date_modif_degustation.get_active()
        textbuffer = self.txtview_commentaire_modif.get_buffer()
        start = textbuffer.get_start_iter()
        end = textbuffer.get_end_iter()
        # On récupère le commentaire et on échape les quote pour l'insert SQL
        commentaire = textbuffer.get_text(start, end, include_hidden_chars=False).replace("'","''")
        # On récupère les notes
        q1=int(self.scaleq1m.get_value())
        q2=int(self.scaleq2m.get_value())
        q3=int(self.scaleq3m.get_value())
        q4=int(self.scaleq4m.get_value())
        q5=int(self.scaleq5m.get_value())
        q6=int(self.scaleq6m.get_value())
        q7=int(self.scaleq7m.get_value())
        q8=int(self.scaleq8m.get_value())
        q9=int(self.scaleq9m.get_value())
        q10=int(self.scaleq10m.get_value())
        q11=int(self.scaleq11m.get_value())
        q12=int(self.scaleq12m.get_value())
        q13=int(self.scaleq13m.get_value())

        note = q1 + q2 + q3 + q4 + q5 + q6 + q7 + q8 + q9 + q10 + q11 + q12 + q13
        # Le commentaire et l'id
        idcomm = self.liststore_date_modif_degustation[index][14]
        id_cigare = self.treeview_selection[5]

        # On met à jour la base de données
        cursor = db.cursor()
        sql = "update degustation set commentaires = '{0}', q1 = '{1}', q2 = '{2}', q3 = '{3}', q4 = '{4}', q5 = '{5}', q7 = '{7}', q8 = '{8}', q9 = '{9}', q10 = '{10}', q11 = '{11}', q12 = '{12}', q13 = '{13}', note = '{14}' where id_cigare = '{15}' and id = '{16}'".format(commentaire, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12, q13, note , id_cigare, idcomm)
        cursor.execute(sql)
        db.commit()
        cursor.close()
        # Afficher un message d'infos pour confirmer
        self.msgdialog.format_secondary_text("Modification de la dégustation pour {0}.\nNouvelle note: {1}".format(self.treeview_selection[1], note))
        self.msgdialog.run()
        self.msgdialog.hide()

        # On recharge la liste des cigares
        self.loadtreeview()

    # Double clic sur le sélécteur de fichiers pour choisir l'image
    def on_filechooser_image_file_activated(self, widget):
        self.addimage(self.filechooser_image.get_filename())
        self.filechooser_image.hide()

    # Clic sur le bouton OK du sélécteur de fichiers pour choisir l'image
    def on_btchooseok_clicked(self, widget):
        self.addimage(self.filechooser_image.get_filename())

    # Mettre à jour la BDD avec le chemin de l'image choisie
    def addimage(self, path):

        cursor = db.cursor()
        # On regarde s'il y a déjà une photo pour le cigare séléctionné
        nb = cursor.execute("select count(*)  from photos where id_cigare = '{0}'".format(self.treeview_selection[5])).fetchone()[0]
        # si nb = 0 on insère sinon on update la table photos
        if ( nb == 0):
            cursor.execute("insert into photos (id_cigare, photo) values('{0}','{1}')".format(self.treeview_selection[5], path))
        else:
            cursor.execute("update photos set photo = '{0}' where id_cigare='{1}'".format(path, self.treeview_selection[5]))
        db.commit()
        cursor.close()

    # Clic droit sur un cigare dans la treeview
    def on_treeview_cigares_button_press_event(self, treeview, event):
        x = int(event.x)
        y = int(event.y)
        if event.button == 3: # Clic droit
            pthinfo = self.tree.get_path_at_pos(x, y)
            if pthinfo is not None:
                path, col, cellx, celly = pthinfo
                self.tree.grab_focus()
                self.tree.set_cursor( path, col, 0)
            # On affiche le popup
            self.popup.show_all();
            self.popup.popup(None, None, None, None, event.button, event.time)


    def text_edited(self, widget, path, text):
        self.liststore[path][1] = text

    # Mise à jour du listestore si édition d'une cellule
    def cell_edited_callback(self, cellule, path, new_text, col, data=None):
        iter = self.table.get_iter(path)
        if col == 4:
            try:
                self.table.set_value(iter, col, int(new_text))
                self.update_db("id", new_text,tuple(self.treeview_selection)[5])
            except ValueError: # Si la quantité saisie n'est pas un entier
                pass
        else:
            self.table.set_value(iter, col, new_text)
            self.update_db("nom", new_text,tuple(self.treeview_selection)[5])

    # Mise à jour de la BDD si changement dans un cellule
    def update_db(self, operation, new_text, indice):
        cursor = db.cursor()
        # update cigares.designation
        if (operation == 'nom'):
            sql = "update cigares set designation = '{0}' where id = '{1}'".format(new_text.replace("'","''"),str(indice))
            #print(sql)
            cursor.execute(sql)
            db.commit()

        # update quantité dans table stock
        if (operation == 'id'):
            sql = "update stocks set quantite = '{0}' where id_cigare='{1}'".format(new_text, str(indice))
            #print(sql)
            cursor.execute(sql)
            db.commit()

        cursor.close()
        # recharger la treeview
        self.loadtreeview()

    # Affichage de la fenêtre d'ajout d'un cigare
    def on_gtk_new_activate(self, widget):
        # On commence par vider le liststore_marques (2è recherche)
        if len(self.tablemarques) != 0:
           self.tablemarques.clear()
        if len(self.tablemodules) != 0:
           self.tablemodules.clear()


        cursor = db.cursor()
        cursor.execute('Select id, libelle, provenance from marques order by lower(libelle)')
        rs = cursor.fetchall()
        # On alimente la combobox des marques
        for item in rs:
            iter = self.tablemarques.append()
            self.tablemarques.set(iter, 0, item[0], 1, item[1].title(), 2, item[2].title())

        cursor.execute('Select id, module, longueur, diametre, calibre from modules order by lower(module)')
        rs = cursor.fetchall()
        # Et celle des modules
        for item in rs:
            iter = self.tablemodules.append()
            self.tablemodules.set(iter, 0, item[0], 1, item[1].title(), 2, item[2], 3, item[3], 4, item[4])

        cursor.close()
        self.dialog_add_cigare.run()
        self.dialog_add_cigare.hide()

    # Changement dans la liste déroulante des marques
    def on_cbmarques_changed(self,widget):
        index = self.cbmarques.get_active()
        try:
            provenance = self.tablemarques[index][2].title()
            self.lbl_marque.set_text("Terroir: " + provenance)
        except IndexError:
            self.lbl_marque.set_text("")


    # Changement dans la liste déroulante des modules
    def on_cbmodules_changed(self,widget):
        try:
            index = self.cbmodules.get_active()
            longueur = self.tablemodules[index][2]
            diametre = self.tablemodules[index][3]
            calibre = self.tablemodules[index][4]
            self.lbl_module.set_text("{0} mm, diamètre {1}, calibre(cepo) {2}".format(longueur, diametre, calibre))
        except IndexError:
            self.lbl_module.set_text("")

    # Validation de l'ajout d'un nouveau cigare
    def on_btadd_clicked(self,widget):
        index = self.cbmarques.get_active()
        model = self.cbmarques.get_model()
        itemmarque = model[index]
        # item[0] = id à insérer dans champ marque de la table cigares
        #print (str(itemmarque[0]), str(itemmarque[1]))

        index = self.cbmodules.get_active()
        model = self.cbmodules.get_model()
        itemmodel = model[index]
        # item[0] = id à insérer dans champ marque de la table cigares
        #print (str(itemmodel[0]), str(itemmodel[1]))
        # Il faudra faire une requete sur cigares pour obtenir le dernier id et faire
        # + 1 : Select max(id) from cigares
        # table stocks : id_cigare = max id + 1
        #print (str(self.entry_nom_cigare.get_text()))


        cursor = db.cursor()
        cursor.execute('Select max(id) from cigares')
        try:
            maxid = cursor.fetchone()[0] + 1
        except TypeError:
            maxid = 1
        cursor.execute("insert into stocks (id_cigare, quantite) values ('{0}','{1}')".format(int(maxid),0))
        cursor.execute("insert into cigares (designation, marque, module) values ('{0}','{1}', '{2}')".format(str(self.entry_nom_cigare.get_text()), int(itemmarque[0]),int(itemmodel[0])))
        db.commit()
        cursor.close()

        # On recharge le treeview
        self.loadtreeview()

    # Affichage de la fenêtre de gestion des achats
    def on_gtk_achats_activate(self, widget):
        # On remet les selections à zero
        self.scale_qte_achats.set_value(1)
        self.scale_typeboite.set_value(25)
        self.entry_prix_achats.set_text("")
        self.entry_code_boite.set_text("")
        self.entry_prix_boite.set_text("")
        self.notebook_achats.set_current_page(0)
        # On vide le listestore_liste_cigares (2è recherche)
        if len(self.tablechoixcig) != 0:
           self.tablechoixcig.clear()


        cursor = db.cursor()
        cursor.execute('Select c.id, c.designation from cigares c order by c.designation asc')
        rs = cursor.fetchall()
        for item in rs:
            iter = self.tablechoixcig.append()
            self.tablechoixcig.set(iter, 0, item[0], 1, item[1])
        cursor.close()
        # On affiche la fenêtre de gestion des achats
        self.dialog_achats.run()

    # Cancel sur l'ajout d'un achat
    def on_bt_cancel_achats_clicked(self, widget):
        self.dialog_achats.hide()

    # Validation des achats
    def on_bt_valid_achats_clicked(self, widget):
        # On récupère le cigare choisi dans la liste déroulante
        # [0] id_cigare ~ [1] libelle
        index = self.cb_liste_cigares_achats.get_active()
        itemchoixcig = self.tablechoixcig[index]

        id_cigare = itemchoixcig[0]

        # On vérifie les saisies
        if(index == -1): # Aucun cigare choisi
            self.msgdialog.format_secondary_text("Vous devez d'abord choisir un cigare dans la liste")
            self.msgdialog.run()
            self.msgdialog.hide()
            return
        # Mauvais prix unité
        if(self.notebook_achats.get_current_page() == 0 and not is_number(self.entry_prix_achats.get_text())):
            self.msgdialog.format_secondary_text("Saisie erronée pour le prix du cigare.")
            self.msgdialog.run()
            self.msgdialog.hide()
            return
        # Mauvais prix boite
        if(self.notebook_achats.get_current_page() == 1 and not is_number(self.entry_prix_boite.get_text())):
            self.msgdialog.format_secondary_text("Saisie erronée pour le prix de la boite.")
            self.msgdialog.run()
            self.msgdialog.hide()
            return
        if(self.notebook_achats.get_current_page() == 0): # Choix à l'unité
            qte_achat = int(self.scale_qte_achats.get_value())
            prix_achat = self.entry_prix_achats.get_text().replace(",",".")
            prix_achat = '%.2f' % float(prix_achat)
            code_boite = ""
        else: # = 1 choix par boites
            qte_achat = int(self.scale_typeboite.get_value())
            prix_achat = float(self.entry_prix_boite.get_text()) / qte_achat
            prix_achat = '%.2f' % prix_achat
            code_boite = self.entry_code_boite.get_text()
        print(qte_achat)
        print(prix_achat)
        print(code_boite)

        # On formate la date (ajout d'un 0 si besoin)
        j = str(self.calendar_date_achats.get_date()[2])
        if(len(str(self.calendar_date_achats.get_date()[1] +1)) == 1):
            m = "0" + str(self.calendar_date_achats.get_date()[1] +1)
        else:
            m = str(self.calendar_date_achats.get_date()[1] +1)
        a = self.calendar_date_achats.get_date()[0]

        date_achat = "{0}/{1}/{2}".format(j, m, a)

        # Insert des achats en base de données
        cursor = db.cursor()
        cursor.execute("insert into achats (id_cigare, date, prix, quantite, code_boite) values ('{0}','{1}','{2}','{3}', '{4}')".format(id_cigare, date_achat, prix_achat, qte_achat, code_boite))
        # ajout dans le stock
        cursor.execute("update stocks set quantite = quantite + {1} where id = {0}".format(id_cigare, qte_achat))

        db.commit()
        cursor.close()

        # Afficher un message d'infos pour confirmer
        self.msgdialog.format_secondary_text("Achats ajoutés avec succés pour {0}".format(itemchoixcig[1]))
        self.msgdialog.run()
        self.msgdialog.hide()

        # On recharge la liste des cigares
        self.loadtreeview()

        self.dialog_achats.hide()

    # Affiche du prix d'un cigare pour les achats par boite
    def on_scale_typeboite_change_value(self, scale, enum, new_value):
        if(is_number(self.entry_prix_boite.get_text())):
            prix_unite = float(self.entry_prix_boite.get_text()) / int(self.scale_typeboite.get_value())
            prix_unite = '%.2f' % prix_unite
            # on met à jour le label
            self.lbl_prix_unite_boite.set_text(" Soit {0}€ le cigare".format(prix_unite))

    def on_entry_prix_boite_changed(self, widget):
        self.on_scale_typeboite_change_value(None, None, None)

    # Affichage de la fenêtre d'ajout d'une marque
    def on_gtk_add_marque_activate(self, menuitem, data=None):
        self.dialog_add_marque.run()
        self.dialog_add_marque.hide()

    # Validation de l'ajout d'une marque
    def on_bt_add_marque_clicked(self, widget):
        print("todo")
        e_marque = self.entry_marque.get_text().title()
        e_provenance = self.entry_provenance.get_text().title()

        # Insert de la nouvelle marque en base de données
        cursor = db.cursor()
        cursor.execute("insert into marques (libelle, provenance) values ('{0}','{1}')".format(e_marque, e_provenance))

        db.commit()
        cursor.close()

        # Afficher un message d'infos pour confirmer
        self.msgdialog.format_secondary_text("Marque {0} ajoutée.".format(e_marque))
        self.msgdialog.run()
        self.msgdialog.hide()

    # Affichage de la fenêtre de gestion des stocks
    def on_gtk_stocks_activate(self, menuitem, data=None):
        # On commence par vider le listestore_liste_cigares (2è recherche)
        if len(self.tablechoixcig) != 0:
           self.tablechoixcig.clear()

        cursor = db.cursor()
        cursor.execute('Select c.id, c.designation from cigares c order by c.designation asc')
        rs = cursor.fetchall()
        for item in rs:
            iter = self.tablechoixcig.append()
            self.tablechoixcig.set(iter, 0, item[0], 1, item[1])
        cursor.close()

        self.dialog_stocks.run()
        self.dialog_stocks.hide()

    # Validation des stocks
    def on_btstockvalid_clicked(self, value):
        item = self.cbchoixcigqte.get_active()
        model = self.cbchoixcigqte.get_model()
        idc = model[item]


        cursor = db.cursor()
        cursor.execute("Update stocks set quantite = '{0}' where id_cigare = '{1}'".format(int(self.scaleqte.get_value()), idc[0]))
        db.commit()
        cursor.close()
        # affichage message maj ok pour qte
        self.msgdialog.format_secondary_text("Quantité mise à jour pour {0}.\nVous avez maintenant {1} exemplaire(s)".format(idc[1], int(self.scaleqte.get_value())))
        self.msgdialog.run()
        self.msgdialog.hide()
        # On recharge la treeview principale
        self.loadtreeview()

    # Affichage de la fenêtre de dégustation
    def on_gtk_degustation_activate(self,menuitem, data=None):
        if len(self.tablechoixcigare) != 0:
           self.tablechoixcigare.clear()

        cursor = db.cursor()
        cursor.execute('Select c.id, c.designation from cigares c where c.id not in (select s.id_cigare from stocks s where s.quantite = 0) order by c.designation asc')
        rs = cursor.fetchall()
        for item in rs:
            iter = self.tablechoixcigare.append()
            self.tablechoixcigare.set(iter, 0, item[0], 1, item[1])

        cursor.close()
        self.window_degustation.run()
        self.window_degustation.hide()

    # Validation d'une dégusation
    def on_btvalid_clicked(self, widget):

        # On formate la date (ajout d'un 0 si besoin)
        j = str(self.DegustationDate.get_date()[2])
        if(len(str(self.DegustationDate.get_date()[1] +1)) == 1):
            m = "0" + str(self.DegustationDate.get_date()[1] +1)
        else:
            m = str(self.DegustationDate.get_date()[1] +1)
        a = self.DegustationDate.get_date()[0]

        # Formatage de la date du calendar au format %d/%m/%Y
        DateDegustation = "{0}/{1}/{2}".format(j, m, a)

        textbuffer = self.txtview_commentaire.get_buffer()
        start = textbuffer.get_start_iter()
        end = textbuffer.get_end_iter()
        # On récupère le commentaire et on échape les quote pour l'insert SQL
        textlines = textbuffer.get_text(start, end, include_hidden_chars=False).replace("'","''")

        index = self.cbchoixcigare.get_active()
        itemchoixcig = self.tablechoixcigare[index]

        note = int(self.scaleq1.get_value()) + int(self.scaleq2.get_value())+int(self.scaleq3.get_value())+int(self.scaleq4.get_value())+int(self.scaleq5.get_value())+int(self.scaleq6.get_value())+int(self.scaleq7.get_value())+int(self.scaleq8.get_value())+int(self.scaleq9.get_value())+int(self.scaleq10.get_value())+int(self.scaleq11.get_value())+int(self.scaleq12.get_value())+int(self.scaleq13.get_value())


        cursor = db.cursor()
        cursor.execute("insert into degustation (id_cigare,date,commentaires,q1,q2,q3,q4,q5,q6,q7,q8,q9,q10,q11,q12,q13,note) values ('{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}','{8}','{9}','{10}','{11}','{12}','{13}','{14}','{15}','{16}')".format(itemchoixcig[0],DateDegustation ,textlines,int(self.scaleq1.get_value()),int(self.scaleq2.get_value()),int(self.scaleq3.get_value()),int(self.scaleq4.get_value()),int(self.scaleq5.get_value()),int(self.scaleq6.get_value()),int(self.scaleq7.get_value()),int(self.scaleq8.get_value()),int(self.scaleq9.get_value()),int(self.scaleq10.get_value()),int(self.scaleq11.get_value()),int(self.scaleq12.get_value()),int(self.scaleq13.get_value()),note))
        # - 1 sur le stock
        cursor.execute("update stocks set quantite = quantite - 1 where id = {0}".format(itemchoixcig[0]))
        db.commit()
        cursor.close()

        # TODO ajouter une checkbox sur le formulaire pour choisir si retirer 1 du stock ou non
        self.msgdialog.format_secondary_text("Note de dégustation ajoutée avec succès pour : {0}.\n1 cigare retiré du stock.".format(itemchoixcig[1]))
        self.msgdialog.run()
        self.msgdialog.hide()

        # On recharge la treeview
        self.loadtreeview()

    # Affichage de la fenêtre des cigares à tester
    def on_gtk_wish_activate(self, menuitem, data=None):
        # On commence par vider le listestore_wishes (2è recherche)
        if len(self.liststore_wishes) != 0:
           self.liststore_wishes.clear()

        cursor = db.cursor()
        cursor.execute('select nom, provenance,raison,source,id from tester order by id')
        rs = cursor.fetchall()
        for item in rs:
            iter = self.liststore_wishes.append()
            self.liststore_wishes.set(iter, 0, item[0], 1, item[1], 2, item[2], 3, item[3], 4, item[4])
        cursor.close()

        self.window_wishes.resize(self.window.get_size()[0], self.window.get_size()[1])

        self.window_wishes.show()

    # Quitter la fenêtre des cigares à tester
    def on_window_wishes_delete_event(self, widget, data=None):
        self.window_wishes.hide()
        return True

    # Affichage de l'assistant d'aide pour la documentation
    def on_gtk_how_to_activate(self, widget):
        self.doc.show()
        #self.doc.hide()

    def on_lbl_intro_activate_link(self, widget):
        self.doc.set_forward_page_func(page_func=None, data=None)

    # Quitter la fenêtre d'assistant
    def on_assistant_delete_event(self, widget, data=None):
        self.doc.hide()
        return True

    # Affichage de la fenêtre d'ajout d'un cigare à tester
    def on_bt_add_wish_clicked(self, widget):
        self.dialog_add_wish.run()
        self.dialog_add_wish.hide()

    # Valider l'ajout d'un cigare à tester
    def on_bt_valid_add_wish_clicked(self, widget):
        textbuffer = self.txtview_test_raison.get_buffer()
        start = textbuffer.get_start_iter()
        end = textbuffer.get_end_iter()
        # On récupère le commentaire et on échape les quote pour l'insert SQL
        textlines = textbuffer.get_text(start, end, include_hidden_chars=False).replace("'","''")

        # On ajoute en base de données
        cursor = db.cursor()
        sql = "insert into tester (nom, provenance, source, raison) values ('{0}','{1}','{2}','{3}')".format(self.entry_test_nom.get_text(), self.entry_test_origine.get_text(), self.entry_test_source.get_text(), textlines)
        cursor.execute(sql)
        db.commit()
        cursor.close()

        # On recharge la treeview des cigares à tester
        self.on_gtk_wish_activate(self)

    # Clic droit sur un cigare à tester dans la treeview
    def on_treeview_wishes_button_press_event(self, treeview, event):
        x = int(event.x)
        y = int(event.y)
        if event.button == 3: # Clic droit
            pthinfo = self.treeview_wishes.get_path_at_pos(x, y)
            if pthinfo is not None:
                path, col, cellx, celly = pthinfo
                self.treeview_wishes.grab_focus()
                self.treeview_wishes.set_cursor( path, col, 0)
            # On affiche le popup
            self.popup_test.show_all();
            self.popup_test.popup(None, None, None, None, event.button, event.time)


    # Ouvrir l'url dans le navigateur au clic droit sur une ligne de la treeview des cigares à tester
    def on_gtk_copier_test_activate(self, widget):
        try:
            import webbrowser
            from urllib.parse import urlparse
        except:
            print('webbrowser not available')
            return False

        selection = self.treeview_wishes.get_selection()
        (model, iter) = selection.get_selected()
        if iter is not None:
            url = model.get_value(iter, 3)
            if not urlparse(url).scheme:
                url = "http://"+url
            # On copie dans le presse papier
            webbrowser.open(url)

    # Pour supprimer au clic droit
    def on_gtk_supprimer_activate(self,widget):
        id_supp = self.treeview_selection[5]
        cursor = db.cursor()
        sql = "delete from cigares where id = {0}".format(id_supp)
        cursor.execute(sql)
        sql = "delete from achats where id_cigare = {0}".format(id_supp)
        cursor.execute(sql)
        sql = "delete from stocks where id_cigare = {0}".format(id_supp)
        cursor.execute(sql)
        sql = "delete from degustation where id_cigare = {0}".format(id_supp)
        cursor.execute(sql)
        sql = "delete from photos where id_cigare = {0}".format(id_supp)
        cursor.execute(sql)

        db.commit()
        cursor.close()

        # On recharge la treeview
        self.loadtreeview()

    # Pour supprimer un cigare à tester au clic droit
    def on_gtk_supprimer_test_activate(self,widget):
        selection = self.treeview_wishes.get_selection()
        (model, iter) = selection.get_selected()
        if iter is not None:
            cursor = db.cursor()
            sql = "delete from tester where nom = '{0}' and provenance = '{1}' and raison = '{2}' and source = '{3}'".format(model.get_value(iter, 0), model.get_value(iter, 1), model.get_value(iter, 2), model.get_value(iter, 3))
            cursor.execute(sql)

            db.commit()
            cursor.close()

            # Afficher un message d'infos pour alerter que c'est bien supprimé
            self.msgdialog.format_secondary_text("Cigare à tester correctement supprimé")
            self.msgdialog.run()
            self.msgdialog.hide()

            # On recharge la treeview
            self.on_gtk_wish_activate(self)

    # Permet le filtrage de la treeview de cigares
    def filter_func(self, model, iterr, data=None):
        query = self.entry_search.get_buffer().get_text()
        value = self.table.get_value(iterr, 0)

        try:
            if query == "":
                return True
            elif query in value.lower():
                return True
        except AttributeError:
            pass
        return False
    # Filtrer au changement sur entry_search
    def  on_entry_search_changed(self, data=None):
        self.tree_filter.refilter()

    def __init__(self):
        self.gladefile = "ui/ui.glade"
        self.builder = gtk.Builder()
        self.builder.add_from_file(self.gladefile)
        self.builder.connect_signals(self)
        self.window = self.builder.get_object("window_main")
        self.aboutdialog = self.builder.get_object("aboutdialog")
        self.statusbar = self.builder.get_object("window_main_statusbar")
        self.context_id = self.statusbar.get_context_id("exemple")
        self.table = self.builder.get_object("liststore_treeview_cigares")
        self.dialog_add_cigare = self.builder.get_object("dialog_add_cigare")
        self.dialog_add_marque = self.builder.get_object("dialog_add_marque")
        self.dialog_add_module = self.builder.get_object("dialog_add_module")

        # Modification/Suppression d'une note de dégustation
        self.window_modif_degustation = self.builder.get_object("window_modif_degustation")
        self.liststore_date_modif_degustation = self.builder.get_object("liststore_date_modif_degustation")
        self.cbchoix_date_modif_degustation = self.builder.get_object("cbchoix_date_modif_degustation")
        self.scaleq1m = self.builder.get_object("scaleq1m")
        self.scaleq2m = self.builder.get_object("scaleq2m")
        self.scaleq3m = self.builder.get_object("scaleq3m")
        self.scaleq4m = self.builder.get_object("scaleq4m")
        self.scaleq5m = self.builder.get_object("scaleq5m")
        self.scaleq6m = self.builder.get_object("scaleq6m")
        self.scaleq7m = self.builder.get_object("scaleq7m")
        self.scaleq8m = self.builder.get_object("scaleq8m")
        self.scaleq9m = self.builder.get_object("scaleq9m")
        self.scaleq10m = self.builder.get_object("scaleq10m")
        self.scaleq11m = self.builder.get_object("scaleq11m")
        self.scaleq12m = self.builder.get_object("scaleq12m")
        self.scaleq13m = self.builder.get_object("scaleq13m")
        self.lbl_note_totale = self.builder.get_object("lbl_note_totale")
        self.txtview_commentaire_modif = self.builder.get_object("txtview_commentaire_modif")

        self.cbmarques = self.builder.get_object("cbmarques")
        self.cbchoixcigare = self.builder.get_object("cbchoixcigare")
        self.tablechoixcigare = self.builder.get_object("liststore_cigares_a_noter")
        self.scaleq1 = self.builder.get_object("scaleq1")
        self.scaleq2 = self.builder.get_object("scaleq2")
        self.scaleq3 = self.builder.get_object("scaleq3")
        self.scaleq4 = self.builder.get_object("scaleq4")
        self.scaleq5 = self.builder.get_object("scaleq5")
        self.scaleq6 = self.builder.get_object("scaleq6")
        self.scaleq7 = self.builder.get_object("scaleq7")
        self.scaleq8 = self.builder.get_object("scaleq8")
        self.scaleq9 = self.builder.get_object("scaleq9")
        self.scaleq10 = self.builder.get_object("scaleq10")
        self.scaleq11 = self.builder.get_object("scaleq11")
        self.scaleq12 = self.builder.get_object("scaleq12")
        self.scaleq13 = self.builder.get_object("scaleq13")
        self.tablemarques = self.builder.get_object("liststore_marques")
        self.cbmodules = self.builder.get_object("cbmodules")
        self.tablemodules = self.builder.get_object("liststore_modules")
        self.entry_nom_cigare = self.builder.get_object("entry_nom_cigare")
        self.window_degustation = self.builder.get_object("window_degustation")
        self.txtview_commentaire = self.builder.get_object("txtview_commentaire")
        self.popup = self.builder.get_object("popup")
        self.popup_test = self.builder.get_object("popup_test")
        self.filechooser_image = self.builder.get_object("filechooser_image")
        self.filechooser_bdd = self.builder.get_object("filechooser_bdd")


        # Fenêtre d'ajout d'une marque
        self.entry_marque = self.builder.get_object("entry_marque")
        self.entry_provenance = self.builder.get_object("entry_provenance")

        # Fenêtre des cigares à tester
        self.txtview_test_raison = self.builder.get_object("txtview_test_raison")
        self.entry_test_nom = self.builder.get_object("entry_test_nom")
        self.entry_test_source = self.builder.get_object("entry_test_source")
        self.entry_test_origine = self.builder.get_object("entry_test_origine")

        self.lbl_marque = self.builder.get_object("lbl_marque")
        self.lbl_module = self.builder.get_object("lbl_module")

        self.msgdialog = self.builder.get_object("msgdialog")

        self.tablechoixcig = self.builder.get_object("listestore_liste_cigares")
        self.cbchoixcigqte = self.builder.get_object("cbchoixcigqte")
        self.lblqte = self.builder.get_object("lblqte")
        self.dialog_stocks = self.builder.get_object("dialog_stocks")
        self.scaleqte = self.builder.get_object("scaleqte")
        self.adjqte = self.builder.get_object("adjqte")
        # Assistant pour la documentation de l'appli
        self.doc = self.builder.get_object("assistant")
        # Image pour afficher le preview dans la zone rétractable
        self.image_preview = self.builder.get_object("image_preview")
        # Date pour la dégustation
        self.DegustationDate = self.builder.get_object("calendar_degustation")

        # Fenêtre de gestion des achats
        self.dialog_achats = self.builder.get_object("dialog_achats")
        # Combo pour la liste des cigares (achats) - utilise aussi listestore_choix_cigare_qte
        self.cb_liste_cigares_achats = self.builder.get_object("cb_liste_cigares_achats")
        # Scale pour la quantité achetée
        self.scale_qte_achats = self.builder.get_object("scale_qte_achats")
        # Entry pour le prix d'achat
        self.entry_prix_achats = self.builder.get_object("entry_prix_achats")
        # Notebook (tabs) pour les achats
        self.notebook_achats = self.builder.get_object("notebook_achats")
        self.scale_typeboite = self.builder.get_object("scale_typeboite")
        self.entry_prix_boite = self.builder.get_object("entry_prix_boite")
        self.entry_code_boite = self.builder.get_object("entry_code_boite")
        self.lbl_prix_unite_boite = self.builder.get_object("lbl_prix_unite_boite")

        # Calendar pour la date d'achat
        self.calendar_date_achats = self.builder.get_object("calendar_date_achats")
        # Fenêtre pour la liste des cigares à tester
        self.window_wishes = self.builder.get_object("window_wishes")
        # Fenêtre d'ajout d'un cigare à tester
        self.dialog_add_wish = self.builder.get_object("dialog_add_wish")
        # Treeview wishes
        self.treeview_wishes = self.builder.get_object("treeview_wishes")
        # Liststore associé à treeview wishes
        self.liststore_wishes = self.builder.get_object("liststore_wishes")

        # Ligne séléctionnée au changement sur la treeview
        self.treeview_selection = []
        # Chemin de l'image preview
        self.imgpath = ""
        self.window_last_h = self.window.get_size()[1]
        self.window_last_w = self.window.get_size()[0]

        # Recherche et filrage d'un cigare
        self.entry_search = self.builder.get_object("entry_search")

        # Filter la treeview des cigares
        self.tree_filter = self.table.filter_new()
        self.tree_filter.set_visible_func(self.filter_func)
        self.filtered_model =  gtk.TreeModelSort(model=self.tree_filter)

        # Treeview de la liste des cigares
        self.tree = self.builder.get_object("treeview_cigares")

        # On défini le modèle pour la treeview qui permet le filtrage
        self.tree.set_model(self.filtered_model)

        # Constuire l'entête du treeview
        self.editable_cell_nom = gtk.CellRendererText()
        self.no_editable_cell = gtk.CellRendererText()
        self.editable_cell_qte = gtk.CellRendererText()
        self.invisible_cell = gtk.CellRendererText()

        self.editable_cell_nom.connect('edited', self.cell_edited_callback,0)
        self.editable_cell_nom.set_property('editable', True)

        self.col_nom = gtk.TreeViewColumn('Nom', self.editable_cell_nom, text=0, background=11)
        self.col_nom.set_sort_column_id(0)
        self.tree.append_column(self.col_nom)

        # Recherche d'un cigare
        self.tree.set_search_column(0)
        self.tree.set_search_entry(self.entry_search)

        self.no_editable_cell.set_property('editable', False)

        self.col_marque = gtk.TreeViewColumn('Marque', self.no_editable_cell, text=1, background=11)
        self.col_marque.set_sort_column_id(1)
        self.tree.append_column(self.col_marque)

        self.col_module= gtk.TreeViewColumn('Module', self.no_editable_cell, text=2, background=11)
        self.col_module.set_sort_column_id(2)
        self.tree.append_column(self.col_module)

        self.col_provenance= gtk.TreeViewColumn('Terroir', self.no_editable_cell, text=3, background=11)
        self.col_provenance.set_sort_column_id(3)
        self.tree.append_column(self.col_provenance)

        self.editable_cell_qte.connect('edited', self.cell_edited_callback,4)
        self.editable_cell_qte.set_property('editable', True)
        self.col_qte = gtk.TreeViewColumn('Quantité', self.editable_cell_qte, text=4, background=11)
        self.col_qte.set_sort_column_id(4)
        self.tree.append_column(self.col_qte)

        # colonne invisible pour l'id_cigare
        self.invisible_cell.set_property('visible',False)
        self.col_id = gtk.TreeViewColumn('id', self.invisible_cell, text=5, background=11)
        self.col_id.set_sort_column_id(5)

        self.col_best_note = gtk.TreeViewColumn('Meilleure note', self.no_editable_cell, text=6, background=11)
        self.col_best_note.set_sort_column_id(6)
        self.tree.append_column(self.col_best_note)

        self.col_mid_note = gtk.TreeViewColumn('Note moyenne', self.no_editable_cell, text=7, background=12)
        self.col_mid_note.set_sort_column_id(7)
        self.tree.append_column(self.col_mid_note)

        self.col_prix = gtk.TreeViewColumn('Prix', self.no_editable_cell, text=8, background=11)
        # On utilise l'id de la col_tri (id = 10) qui contient le prix en float pour le tri
        self.col_prix.set_sort_column_id(10)
        self.tree.append_column(self.col_prix)

        # colonne invisible pour le commentaire de dégustation
        self.col_comment = gtk.TreeViewColumn('commentaire', self.invisible_cell, text=9)
        self.col_comment.set_sort_column_id(9)
        # On défini cette colonne comme colonne d'infobulle
        self.tree.set_tooltip_column(9)

        # colonne invisible pour le tri des prix
        self.col_tri = gtk.TreeViewColumn('tri', self.invisible_cell, text=10)

        # colonne invisible pour la couleur d'une ligne
        self.col_couleur = gtk.TreeViewColumn('couleur', self.invisible_cell, text=11)

        # colonne invisible pour la couleur du top 5
        self.col_couleurtop5 = gtk.TreeViewColumn('couleurtop5', self.invisible_cell, text=12)

        # Utiliser gtkspellcheck dans la txtview des commentaires
        # http://koehlma.github.io/projects/pygtkspellcheck.html
        try:
            from gtkspellcheck import SpellChecker
            SpellChecker(self.txtview_commentaire, locale.getdefaultlocale()[0])
            SpellChecker(self.txtview_commentaire_modif, locale.getdefaultlocale()[0])
            SpellChecker(self.txtview_test_raison, locale.getdefaultlocale()[0])
        except:
            print("gtkspellcheck n'est pas installé")
            pass

        self.window.show_all()
        # On charge la liste des cigares
        self.loadtreeview()

# Vérifier qu'il s'agit d'un nombre
def is_number(s):
    try:
        float(s)
        return True
    except ValueError:
        return False

def createdb(new_bdd):
    db = sqlite3.connect(new_bdd)
    cursor = db.cursor()
    sql = 'create table achats' + \
          '(id INTEGER PRIMARY KEY, id_cigare INTEGER, date TEXT, code_boite TEXT, prix FLOAT, quantite INTEGER)'
    cursor.execute(sql)
    sql = 'create table cigares' + \
          '(id INTEGER PRIMARY KEY, designation TEXT, marque INTEGER, module INTEGER)'
    cursor.execute(sql)
    sql = 'create table degustation' + \
          '(id INTEGER PRIMARY KEY, id_cigare INTEGER, date TEXT, note NUMERIC, commentaires TEXT, q1 INTEGER, q2 INTEGER, q3 INTEGER, q4 INTEGER, q5 INTEGER, q6 INTEGER, q7 INTEGER, q8 INTEGER, q9 INTEGER, q10 INTEGER, q11 INTEGER, q12 INTEGER, q13 INTEGER)'
    cursor.execute(sql)
    sql = 'create table marques' + \
          '(id INTEGER PRIMARY KEY, libelle TEXT, provenance TEXT)'
    cursor.execute(sql)
    sql = 'create table modules' + \
          '(id INTEGER PRIMARY KEY, module TEXT, calibre TEXT, diametre TEXT, longueur TEXT)'
    cursor.execute(sql)
    sql = 'create table photos' + \
          '(id INTEGER PRIMARY KEY, id_cigare INTEGER, photo TEXT)'
    cursor.execute(sql)
    sql = 'create table stocks' + \
          '(id INTEGER PRIMARY KEY, id_cigare INTEGER, quantite INTEGER)'
    cursor.execute(sql)
    sql = 'create table tester' + \
          '(id INTEGER PRIMARY KEY, nom TEXT, provenance TEXT, raison TEXT, source TEXT)'
    cursor.execute(sql)

    # INSERT à mettre dans un fichier à part
    sql = "INSERT INTO modules VALUES(1, 'Laguito N °3', '26', '10.32', '115')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(2, 'Carolina', '26', '10.32', '121')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(3, 'Panetela Larga', '28', '11.11', '175')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(4, 'Chico', '29', '11.51', '106')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(5, 'Entreacto', '30', '11.91', '100')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(6, 'Palmita', '32', '12.70', '152')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(7, 'Delicioso', '33', '13.10', '159')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(8, 'Palma', '33', '13.10', '170')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(9, 'Ninfa', '33', '13.10', '178')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(10, 'Panetela', '34', '13.49', '117')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(11, 'Placera', '34', '13.49', '125')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(12, 'Epicure', '35', '13.89', '110')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(13, 'Sport', '35', '13.89', '117')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(14, 'Conchita', '35', '13.89', '127')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(15, 'Carlota', '35', '13.89', '143')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(16, 'Cadete', '36', '14.29', '115')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(17, 'Seoane', '36', '14.29', '125')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(18, 'Veguerito', '36', '14.29', '127')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(19, 'Delicado Extra', '36', '14.29', '185')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(20, 'Trabuco', '38', '15.08', '110')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(21, 'Laguito N ° 2', '38', '15.08', '152')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(22, 'Parejo', '38', '15.08', '166')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(23, 'Delicado', '38', '15.08', '192')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(24, 'Laguito N ° 1', '38', '15.08', '192')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(25, 'Belvedere', '39', '15.48', '125')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(26, 'Perla', '40', '15.87', '102')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(27, 'Franciscano', '40', '15.87', '116')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(28, 'Coronita', '40', '15.87', '117')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(29, 'Standard', '40', '15.87', '123')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(30, 'Londres', '40', '15.87', '126')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(31, 'Petit Cetro', '40', '15.87', '129')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(32, 'Almuerzo', '40', '15.87', '130')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(33, 'Crema', '40', '15.87', '140')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(34, 'Laguito No.1', '40', '15.87', '192')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(35, 'Minuto', '42', '16.67', '110')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(36, 'Mareva', '42', '16.67', '129')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(37, 'Petit Corona', '42', '16.67', '127')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(38, 'Eminente', '42', '16.67', '132')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(39, 'Nacional', '42', '15.87', '134')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(40, 'Cosaco', '42', '16.67', '135')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(41, 'Corona', '42', '16.67', '140')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(42, 'Corona Grande', '42', '16.67', '155')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(43, 'Cervante', '42', '16.67', '165')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(44, 'Conserva', '43', '17.07', '145')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(45, 'Cazadore', '43', '17.07', '162')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(46, 'Dalia', '43', '17.07', '170')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(47, 'Francisco', '44', '17.46', '143')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(48, 'Corona Gorda', '46', '18.26', '143')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(49, 'Taco', '47', '18.65', '158')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(50, 'Julieta / Churchill', '47', '18.65', '178')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(51, 'Gran Corona', '47', '18.65', '235')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(52, 'Hermoso N ° 4', '49', '19.05', '127')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(53, 'Paco', '49', '19.45', '180')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(54, 'Double corona', '49', '19.45', '194')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(55, 'Robusto', '50', '19.84', '127')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(56, 'Gordito', '50', '19.84', '141')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(57, 'Campana', '52', '20.64', '140')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(58, 'Panetelas Extra', '37', '13.49', '127')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(59, 'Oficios (Corona)', '43', '17.07', '135')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(60, 'Majestic (Petit Corona)', '39', '15.87', '140')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(61, 'Figurados', '60', '20+', '150+')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(62, 'Torpedo', '52', '20.8', '125')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(63, 'short robusto', '60', '24', '102')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(64, 'Mini Panetella', '20', '8', '125')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(65, 'Indéfini', '0', '0', '0')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(66, 'Très  petit corona', '40', '15.88', '102')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(67, 'Toro', '52', '20.8', '152')"
    cursor.execute(sql)
    sql = "INSERT INTO modules VALUES(68, 'Prominente', '49', '19.45', '194')"
    cursor.execute(sql)

    # MARQUES
    sql = "INSERT INTO marques VALUES(1, 'Cohiba', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(2, 'Trinidad', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(3, 'Vegas Robaina', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(4, 'Montecristo', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(5, 'Cuaba', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(6, 'Romeo y Julieta', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(7, 'Partagas', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(8, 'San Cristobal de la Habana', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(9, 'Punch', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(10, 'Hoyo de Monterrey', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(11, 'Bolivar', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(12, 'La Gloria Cubana', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(13, 'H.Upmann', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(14, 'Fonseca', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(15, 'La Flor de Cano', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(16, 'Troya', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(17, 'Quintero', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(18, 'Los Statos de Luxe', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(19, 'Caney', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(20, 'Belinda', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(21, 'Cabanas', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(22, 'La Corona', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(23, 'José L.Piedra', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(24, 'Cumpay', 'Nicaragua')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(25, 'CAO', 'Nicaragua')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(26, 'Dunhill', 'Nicaragua')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(27, 'Nicarao', 'Nicaragua')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(28, 'Oliva', 'Nicaragua')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(29, 'Padron', 'Nicaragua')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(30, 'Flor de Copan', 'Honduras')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(31, 'Flor de Selva', 'Honduras')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(32, 'J. Cortès', 'Honduras')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(33, 'Zino', 'Honduras')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(34, 'Villa Zamorano', 'Honduras')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(35, 'Flor de Rafaël Gonzáles Márquez', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(36, 'Macanudo', 'République Dominicaine')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(37, 'Pléiades', 'Nicaragua')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(38, 'Toscano', 'Italie')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(39, 'Davidoff', 'cuba')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(40, 'Avo Uvezian', 'République Dominicaine')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(41, 'Don Pepin Garcia', 'Nicaragua')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(42, 'O Line', 'Nicaragua')"
    cursor.execute(sql)
    sql = "INSERT INTO marques VALUES(43, 'Plasencia', 'Nicaragua')"
    cursor.execute(sql)

    db.commit()

def checkconfig():
    """Récupérer la configuration ou la créer"""
    # Fichier de configuration
    #configfile = os.path.expanduser("~/.config/cltwit.conf")
    # On ouvre le fichier de conf
    config = configparser.RawConfigParser()
    try:
        config.read(__CONFIGFILE__)
        if config.has_option('MesCigares','bdd'):
            bdd = config.get('MesCigares','bdd')
    except:
        pass

    if  not os.path.exists(bdd):
        createdb(bdd)

    # Si aucune conf
    if not(config.has_option('MesCigares','bdd')):
        bdd = __CONFDIR__ + "/bdd/main.db"
        # écrire le fichier de conf avec les informations par defaut
        try:
            cfgfile = open(__CONFIGFILE__,'w')
            if not(config.has_section('MesCigares')):
                config.add_section('MesCigares')
            config.set('MesCigares','bdd',bdd)
            config.write(cfgfile)
        except IOError:
            pass
        finally:
            cfgfile.close
        createdb(bdd)
    return(bdd)

def setconfig(new_bdd):
    """Mettre à jour la configuration"""
    config = configparser.RawConfigParser()
    try:
        cfgfile = open(__CONFIGFILE__,'w')
        if not(config.has_section('MesCigares')):
            config.add_section('MesCigares')
        config.set('MesCigares','bdd',new_bdd)
        config.write(cfgfile)
    except IOError:
        pass
    finally:
        cfgfile.close

if __name__ == "__main__":
    dbconf = checkconfig()
    db = sqlite3.connect(dbconf)
    main = MesCigares()
    main.window.set_title("MesCigares - base : {0}".format(ntpath.basename(dbconf)).replace('.db',''))
    gtk.main()
