#!/usr/bin/env python # -*- coding: utf-8 -*- """ Application de gestion de cave à cigares WTFPL @ Jérôme LAUNAY """ import os import sys import locale import ntpath import sqlite3 import configparser import gi gi.require_version('Gtk', '3.0') try: from gi.repository import Gtk as gtk, GdkPixbuf except ImportError: 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 """ class MesCigares(object): @classmethod def on_window_main_destroy(cls, widget, data=None): db.close() gtk.main_quit() @classmethod def on_gtk_quit_activate(cls, 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, objt, 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: itr = 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 Exception: 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(itr, 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 is not 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 is not 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 is not 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 is not 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 = str('%.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 = str('%.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, itr) = selection.get_selected() if itr is not None: self.treeview_selection.clear() self.treeview_selection.append(model.get_value(itr, 0)) self.treeview_selection.append(model.get_value(itr, 1)) self.treeview_selection.append(model.get_value(itr, 2)) self.treeview_selection.append(model.get_value(itr, 3)) self.treeview_selection.append(model.get_value(itr, 4)) self.treeview_selection.append(model.get_value(itr, 5)) self.treeview_selection.append(model.get_value(itr, 6)) self.treeview_selection.append(model.get_value(itr, 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, itr) = selection.get_selected() if itr is not None: lib = model.get_value(itr, 0) qtee = model.get_value(itr, 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.lstore_dmodif_degust) != 0: self.lstore_dmodif_degust.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] itr = self.lstore_dmodif_degust.append() self.lstore_dmodif_degust.set( itr, 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 note 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.lstore_dmodif_degust[index][i]) # idcomm = self.lstore_dmodif_degust[index][14] except IndexError: pass try: commentaire = self.lstore_dmodif_degust[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 note = [] note.append(int(self.scaleq1m.get_value())) note.append(int(self.scaleq2m.get_value())) note.append(int(self.scaleq3m.get_value())) note.append(int(self.scaleq4m.get_value())) note.append(int(self.scaleq5m.get_value())) note.append(int(self.scaleq6m.get_value())) note.append(int(self.scaleq7m.get_value())) note.append(int(self.scaleq8m.get_value())) note.append(int(self.scaleq9m.get_value())) note.append(int(self.scaleq10m.get_value())) note.append(int(self.scaleq11m.get_value())) note.append(int(self.scaleq12m.get_value())) note.append(int(self.scaleq13m.get_value())) # On affiche la note / 100 temporaire self.lbl_note_totale.set_text( "Nouvelle note: {0}/100".format(sum(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 note = [] note.append(int(self.scaleq1m.get_value())) note.append(int(self.scaleq2m.get_value())) note.append(int(self.scaleq3m.get_value())) note.append(int(self.scaleq4m.get_value())) note.append(int(self.scaleq5m.get_value())) note.append(int(self.scaleq6m.get_value())) note.append(int(self.scaleq7m.get_value())) note.append(int(self.scaleq8m.get_value())) note.append(int(self.scaleq9m.get_value())) note.append(int(self.scaleq10m.get_value())) note.append(int(self.scaleq11m.get_value())) note.append(int(self.scaleq12m.get_value())) note.append(int(self.scaleq13m.get_value())) # Le commentaire et l'id idcomm = self.lstore_dmodif_degust[index][14] id_cigare = self.treeview_selection[5] # On met à jour la base de données cursor = db.cursor() req = ("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}'") sql = (req.format(commentaire, note[0], note[1], note[2], note[3], note[4], note[5], note[6], note[7], note[8], note[9], note[10], note[11], note[12], sum(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], sum(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é req = ("select count(*) from photos where id_cigare ='{0}'" .format(self.treeview_selection[5])) nb = cursor.execute(req).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() sql = ('Select id,libelle,provenance ' 'from marques order by lower(libelle)') cursor.execute(sql) 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()) sql = ('Select id, module, longueur, diametre, calibre ' 'from modules order by lower(module)') cursor.execute(sql) rs = cursor.fetchall() # Et celle des modules for item in rs: itr = self.tablemodules.append() self.tablemodules.set(itr, 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() sql = ('Select c.id, c.designation ' 'from cigares c order by c.designation asc') cursor.execute(sql) 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() req = ("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}')") cursor.execute(req.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(jlaunay) 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 ImportError: 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.lstore_dmodif_degust = 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 Exception: print("gtkspellcheck n'est pas installé " + "http://koehlma.github.io/projects/" + "pygtkspellcheck.html") 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 Exception: 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()