mescigares/MesCigares/MesCigares.py

1071 lines
48 KiB
Python
Executable File

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# pylint: disable-msg=C0103
import sys, os
import sqlite3
import locale
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, 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 max(d.note), avg(d.note),id_cigare from degustation d group by id_cigare")
rs2 = cursor.fetchall()
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()
self.table.set(iter, 0, item[0], 1, item[1], 2, item[2], 3, item[3], 4, item[4])
# 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, 4 = id de la table cigare (colonne 4 invisible), item2[2] = id_cigare table degustation
if self.table.get_value (itr, 4) == item2[2]:
#print(self.table.get_value (itr, 4))
self.table.set(itr, 5, item2[0], 6, item2[1])
itr= self.table.iter_next(itr)
for item3 in rs3:
itr = self.table.get_iter_first ()
while ( itr != None ):
# itr, 4 = id de la table cigare (colonne 4 invisible), item3[1] = id_cigare table achats
if self.table.get_value (itr, 4) == item3[1]:
# .2f pour 2 decimales
it = '%.2f' % item3[0]
self.table.set(itr, 7, it)
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, 4) == item4[1]:
self.table.set(itr, 8, 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, 3))
if self.table.get_value(itr, 7) is not None:
montant += float(self.table.get_value(itr, 7)) * int(self.table.get_value(itr, 3))
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[4]))
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))
# 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()
# 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())
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 le commentaire d'un cigare
def on_modifier_commentaire_activate(self, widget):
cursor = db.cursor()
# On regarde récupère le commentaire
commentaire = cursor.execute("select commentaires from degustation where id_cigare = '{0}'".format(self.treeview_selection[4])).fetchone()
# si nb = 0 on insère sinon on update la table photos
db.commit()
cursor.close()
try:
commentaire = commentaire[0]
except TypeError:
# Afficher un message d'infos pour alerter qu'il faut d'abord faire une dégustation
self.msgdialog.format_secondary_text("Vous devez d'abord ajouter une dégustation pour ce cigare pour pouvoir ajouter un commentaire")
self.msgdialog.run()
self.msgdialog.hide()
return
# On affiche le commentaire
self.txtview_commentaire_modif.get_buffer().set_text(commentaire)
# On affiche la fenêtre de modification du commentaire
self.dialog_commentaires.run()
self.dialog_commentaires.hide()
# On recharge la treeview
self.loadtreeview()
# Valider la modification du commentaire
def on_bt_commentaires_modif_clicked(self, widget):
# modifier
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
textlines = textbuffer.get_text(start, end, include_hidden_chars=False).replace("'","''")
# On met à jour la base de données
cursor = db.cursor()
sql = "update degustation set commentaires = '{0}' where id_cigare = '{1}'".format(textlines, self.treeview_selection[4])
print(sql)
cursor.execute(sql)
db.commit()
cursor.close()
# Afficher un message d'infos pour confirmer
self.msgdialog.format_secondary_text("Commentaire modifié pour {0}.".format(self.treeview_selection[1]))
self.msgdialog.run()
self.msgdialog.hide()
# 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[4])).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[4], path))
else:
cursor.execute("update photos set photo = '{0}' where id_cigare='{1}'".format(path, self.treeview_selection[4]))
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)
# 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 == 3:
self.table.set_value(iter, col, int(new_text))
else:
self.table.set_value(iter, col, new_text)
self.update_db(tuple(self.treeview_selection),tuple(self.table[path]))
# Mise à jour de la BDD si changement dans un cellule
def update_db(self, old_value, new_value):
cursor = db.cursor()
# update cigares.designation
if (new_value[0] != old_value[0]):
cursor.execute("update cigares set designation = '{0}' where id = '{1}'".format(new_value[0].replace('"','\"'),old_value[4]))
# update quantité dans table stock
if (new_value[3] != old_value[3]):
cursor.execute("update stocks set quantite = '{0}' where id_cigare='{1}'".format(new_value[3], old_value[4]))
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 from marques order by 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])
cursor.execute('Select id, module from modules order by calibre, id')
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])
cursor.close()
self.dialog_add_cigare.run()
self.dialog_add_cigare.hide()
# 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 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()
# On affiche la fenêtre de gestion des achats
self.dialog_achats.run()
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]
qte_achat = int(self.scale_qte_achats.get_value())
prix_achat = self.entry_prix_achats.get_text().replace(",",".")
date_achat = "{0}/{1}/{2}".format(self.calendar_date_achats.get_date()[2], self.calendar_date_achats.get_date()[1] ,self.calendar_date_achats.get_date()[0])
# Insert des achats en base de données
cursor = db.cursor()
cursor.execute("insert into achats (id_cigare, date, prix, quantite) values ('{0}','{1}','{2}','{3}')".format(id_cigare, date_achat, prix_achat, qte_achat))
# 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()
# 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ée 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):
# Formatage de la date du calendar au format %d/%m/%Y
DateDegustation = "{0}/{1}/{2}".format(self.DegustationDate.get_date()[2], self.DegustationDate.get_date()[1],self.DegustationDate.get_date()[0])
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):
print("toto")
# Copier l'url dans le presse papier au changement de ligne sur la treeview des cigares à tester
def on_treeview_wishes_cursor_changed(self, widget):
try:
from lib import pyperclip
except:
print('pyperclip not available')
return False
selection = self.treeview_wishes.get_selection()
(model, iter) = selection.get_selected()
if iter is not None:
# On copie dans le presse papier
pyperclip.copy(model.get_value(iter, 3))
# TODO: ajouter un popup pour supprimer au clic droit
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_commentaires = self.builder.get_object("dialog_commentaires")
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.filechooser_image = self.builder.get_object("filechooser_image")
self.filechooser_bdd = self.builder.get_object("filechooser_bdd")
self.msgdialog = self.builder.get_object("msgdialog")
self.msginfo = self.builder.get_object("lblmsginfo")
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")
# 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]
# Constuire l'entête du treeview
self.cell1 = gtk.CellRendererText()
self.cell2 = gtk.CellRendererText()
self.cell3 = gtk.CellRendererText()
self.cell4 = gtk.CellRendererText()
self.cell5 = gtk.CellRendererText()
self.cell6 = gtk.CellRendererText()
self.cell7 = gtk.CellRendererText()
self.cell8 = gtk.CellRendererText()
self.cell9 = gtk.CellRendererText()
self.cell1.connect('edited', self.cell_edited_callback,0)
self.cell1.set_property('editable', True)
self.tree = self.builder.get_object("treeview_cigares")
self.column1 = gtk.TreeViewColumn('Nom', self.cell1, text=0)
self.column1.set_sort_column_id(0)
self.tree.append_column(self.column1)
self.cell2.connect('edited', self.cell_edited_callback,1)
self.cell2.set_property('editable', False)
self.column2 = gtk.TreeViewColumn('Marque', self.cell2, text=1)
self.column2.set_sort_column_id(1)
self.tree.append_column(self.column2)
self.cell3.connect('edited', self.cell_edited_callback,2)
self.cell3.set_property('editable', False)
self.column3 = gtk.TreeViewColumn('Module', self.cell3, text=2)
self.column3.set_sort_column_id(2)
self.tree.append_column(self.column3)
self.cell4.connect('edited', self.cell_edited_callback,3)
self.cell4.set_property('editable', True)
self.column4 = gtk.TreeViewColumn('Quantitée', self.cell4, text=3)
self.column4.set_sort_column_id(3)
self.tree.append_column(self.column4)
# colonne invisible pour l'id_cigare
self.cell5.set_property('visible',False)
self.column5 = gtk.TreeViewColumn('id', self.cell5, text=4)
self.column5.set_sort_column_id(4)
self.cell6.set_property('visible',True)
self.column6 = gtk.TreeViewColumn('Meilleure note', self.cell6, text=5)
self.column6.set_sort_column_id(5)
self.tree.append_column(self.column6)
self.cell7.set_property('visible',True)
self.column7 = gtk.TreeViewColumn('Note moyenne', self.cell7, text=6)
self.column7.set_sort_column_id(6)
self.tree.append_column(self.column7)
self.cell8.set_property('visible',True)
#self.cell8.set_property('xalign',1.0)
self.column8 = gtk.TreeViewColumn('Prix (en €)', self.cell8, text=7)
self.column8.set_sort_column_id(7)
self.tree.append_column(self.column8)
# colonne invisible pour le commentaire de dégustation
self.cell9.set_property('visible',False)
self.column9 = gtk.TreeViewColumn('commentaire', self.cell5, text=8)
self.column9.set_sort_column_id(8)
# On défini cette colonne comme colonne d'infobulle
self.tree.set_tooltip_column(8)
# 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])
except:
print("gtkspellcheck n'est pas installé")
pass
self.window.show_all()
# On charge la liste des cigares
self.loadtreeview()
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, 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
# 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()
gtk.main()