#!/usr/bin/python
# -*- coding: Utf-8 -*-

import os, string, Image, glob, sets
import shutil
from PyQt4.QtCore import *
from PyQt4.QtGui import *

from gui_modules_image.image_base import Base
from gui_modules_lecture.affichage_image.afficheurImage import VisionneurImagePourEKD

class Image_Transitions_FondEnch(QWidget):
	# -----------------------------------
	# Cadre accueillant les widgets de :
	# Image >> Transitions >> Fondu enchaîné
	# -----------------------------------
	def __init__(self, parent):
        	QWidget.__init__(self)
		
		# ----------------------------
		# quelques paramètres de base
		# ----------------------------
		
		'''
		# création des répertoires temporaires pour les différentes traitements
		if os.path.isdir('/tmp/ekd/tampon/transitions/fondu_enchaine/fe_tempo_A') is False:
        		os.makedirs('/tmp/ekd/tampon/transitions/fondu_enchaine/fe_tempo_A')
		if os.path.isdir('/tmp/ekd/tampon/transitions/fondu_enchaine/pas_fe_tempo_A') is False:
        		os.makedirs('/tmp/ekd/tampon/transitions/fondu_enchaine/pas_fe_tempo_A')
			
		if os.path.isdir('/tmp/ekd/tampon/transitions/fondu_enchaine/final_fondu_tempo_A') is False:
        		os.makedirs('/tmp/ekd/tampon/transitions/fondu_enchaine/final_fondu_tempo_A')
			
		if os.path.isdir('/tmp/ekd/tampon/transitions/fondu_enchaine/fe_tempo_B') is False:
        		os.makedirs('/tmp/ekd/tampon/transitions/fondu_enchaine/fe_tempo_B')
		if os.path.isdir('/tmp/ekd/tampon/transitions/fondu_enchaine/pas_fe_tempo_B') is False:
        		os.makedirs('/tmp/ekd/tampon/transitions/fondu_enchaine/pas_fe_tempo_B')
			
		if os.path.isdir('/tmp/ekd/tampon/transitions/fondu_enchaine/final_fondu_tempo_B') is False:
        		os.makedirs('/tmp/ekd/tampon/transitions/fondu_enchaine/final_fondu_tempo_B')
		'''
		
		# Fonctions communes à plusieurs cadres du module Image
		self.base = Base()
		# Paramètres de configuration
		self.config = parent.config
		
		# liste de chemins de fichiers sequence A, sequence B  
		# et du dossier de sauvegarde
		self.listeChemSequenceA=[]
		self.listeChemSequenceB=[]
		self.chemDossierSauv=''
		
		# variable provisoire contenant le texte des infos de chargement et sauvegarde
		self.infosImgProv = ''
		
		# Boite d'alignement vertical
		vbox=QVBoxLayout(self)
		
		# --------------------------------------------------
		# widgets du haut : titre + bouton de sélection
		# --------------------------------------------------
		
		#=== Titre de la page ===#
		#txt1=_(u"Fondu enchaîné")
		#titre_du_cadre=QLabel('<H2><CENTER>%s</CENTER></H2>' %txt1, self)
		
		hbox = QHBoxLayout()
		#hbox.addWidget(titre_du_cadre,1) # étirement: centré
		
		# Ajout du titre de la page et de l'aperçu à la boite verticale
		vbox.addLayout(hbox, 0)
		
		#=== Bouton de sélection des images seq A et B ===#
		hbox = QHBoxLayout()
		self.boutOuvChargerTousTypesImages = QPushButton(_(u"Charger images séquence A et B"))
		self.boutOuvChargerTousTypesImages.setFocusPolicy(Qt.NoFocus)
		hbox.addWidget(self.boutOuvChargerTousTypesImages,1)
		vbox.addLayout(hbox)
		
		self.connect(self.boutOuvChargerTousTypesImages, SIGNAL("clicked()"), self.ouvrirImages)
		
		'''
		# -----------------------------------------------------------------------
		# Widgets de réglage contenus dans la page Réglage du TabWidget-- choix 
		# du nombre d'images pour le fondu
		# -----------------------------------------------------------------------
		# boite de spin
		self.choixNbreImagesFondu=QSpinBox()
		self.choixNbreImagesFondu.setMinimum(1)
		self.choixNbreImagesFondu.setMaximum(5000)
		self.choixNbreImagesFondu.setValue(2)
		
		self.connect(self.choixNbreImagesFondu,SIGNAL("valueChanged(int)"),self.reglag)
		
		# label d'info du choix par l'utilisateur du nombre d'images qui
		# devront constituer le fondu enchaîné entre les deux séquences d'images
		txt1, txt2=_(u"Choix du nombre d'images pour le fondu enchaîné -->"),_(u'Entre 1 et 5000')
		infoImagesFondu=QLabel('<font color="green">%s</font> <font color="red">%s</font>' %(txt1,txt2), self)
		
		widget=QWidget()
		layout=QGridLayout()
		layout.addWidget(self.choixNbreImagesFondu, 0, 0)
		layout.addWidget(infoImagesFondu, 0, 1)
		widget.setLayout(layout)
		'''
		
		# -----------------------------------------------------------------------
		# tabwidget qui affiche la 1ère image chargée par
		# les boîtes de dialogue, puis la 1ère image du résultat du fondu
		# -----------------------------------------------------------------------
		# widget QScrolledArea (avec un Qlabel à l'intérieur) pour l'affichage
		# des images (fichier -->
		# gui_modules_lecture/affichage_image/afficheurImage.py,
		# classe --> VisionneurImagePourEKD)
		self.afficheurImg_1=VisionneurImagePourEKD()
		self.afficheurImg_2=VisionneurImagePourEKD()
		self.afficheurImg_3=VisionneurImagePourEKD()
		
		# infos - logs
		self.zoneAffichInfosImg = QTextEdit("")
		self.zoneAffichInfosImg.setReadOnly(True)
		self.fram=QFrame()
		vboxInfIm=QVBoxLayout(self.fram)
		vboxInfIm.addWidget(self.zoneAffichInfosImg)
		self.fram.setEnabled(False)
		
		self.tabwidget=QTabWidget()
		
		self.tab_1 = self.tabwidget.addTab(self.afficheurImg_1, _(u'Séquence A'))
		self.tab_2 = self.tabwidget.addTab(self.afficheurImg_2, _(u'Séquence B'))
		self.tab_3 = self.tabwidget.addTab(self.afficheurImg_3, _(u'Résultat final'))
		#self.tab_4 = self.tabwidget.addTab(widget, _(u'Réglages'))
		self.tab_5 = self.tabwidget.addTab(self.fram, _(u'Infos'))
		
		# [bidouillage] Comme on n'arrive pas à afficher les images centrées
		# de façon 'propre', en attendant on bidouille pour y
		# arriver (le prbl concerne surtout les images d'acceuil)
		self.connect(self.tabwidget, SIGNAL("currentChanged(int)"), self.protheseCentrageImg)
		
		vbox.addWidget(self.tabwidget)
		
		# -------------------------------------------------------------------
		# widgets du bas : ligne + boutons
		# -------------------------------------------------------------------
		
		# boutons
		boutAide=QPushButton(_(u" Aide"))
		boutAide.setIcon(QIcon("Icones/icone_aide_128.png"))
		self.connect(boutAide, SIGNAL("clicked()"), self.afficherAide)
		
		self.boutAppliquer=QPushButton(_(u" Appliquer et sauver"))
		# Appliquer et sauver
		self.boutAppliquer.setIcon(QIcon("Icones/icone_appliquer_128.png"))
		# Bouton inactif au départ
		self.boutAppliquer.setEnabled(False)
		self.connect(self.boutAppliquer, SIGNAL("clicked()"), self.final_moteur)
		
		# ligne de séparation juste au dessus des boutons
		ligne = QFrame()
		ligne.setFrameShape(QFrame.HLine)
		ligne.setFrameShadow(QFrame.Sunken)
		vbox.addWidget(ligne)
		vbox.addSpacing(-5)	# la ligne doit être plus près des boutons
		
		hbox=QHBoxLayout()
		hbox.addWidget(boutAide)
		hbox.addStretch()	# espace entre les 2 boutons
		hbox.addWidget(self.boutAppliquer)
		vbox.addLayout(hbox)
		
		# affichage de la boîte principale
		self.setLayout(vbox)
	
	
	def protheseCentrageImg(self, i):
		"""Rafraichissemnt pour affichage de l'image au
		# milieu de la fenêtre. La fonction setTailleFenetre()
		# vient de la classe VisionneurImagePourEKD du fichier
		# gui_modules_lecture/affichage_image/afficheurImage.py
		self.afficheurImg_3.setTailleFenetre()"""
		self.afficheurImg_1.setTailleFenetre() ##

		if i==1: # 2ème onglet
			self.afficheurImg_2.setTailleFenetre()
		elif i==2: # 3ème onglet
			self.afficheurImg_3.setTailleFenetre()
			
	
	def ouvrirImages_1(self):
		""" Récupération du chemin des images séquence A sélectionnées """
		
		# Ouvrir images séquence A
		rep = self.base.getRepSource(self.listeChemSequenceA, self.config)
		chemin_sequence_A=QFileDialog.getOpenFileNames(None, _(u"Ouvrir images séquence A"), rep, ("JPEG (*.jpg *.JPG *.jpeg *.JPEG);;PNG (*.png *.PNG);;GIF (*.gif *.GIF);;BMP (*.bmp *.BMP);;SGI (*.sgi *.SGI);;TIF (*.tif *.TIF);;TARGA (*.tga *.TGA);;PNM (*.pnm *.PNM);;PPM (*.ppm *.PPM)"))
		
		# Si pas de fichier sélectionné -> sortir de la fonction
		if chemin_sequence_A.count()==0: return
		
		# Convertir les differents fichiers selectionnes
		# en une liste de chaines de caracteres .
		self.listeChemSequenceA=[str(chemin_sequence_A[i_seqA]) for i_seqA in range(chemin_sequence_A.count())]
		
		self.listeChemSequenceA.sort()
		
		self.base.setRepSource(self.listeChemSequenceA, self.config)
		
		# On implémente les chemins des fichiers dans une variable
		# pour préparer l'affichage des infos
		textSeqB=_(u"Image(s) séquence A chargée(s)")
		a='#'*36
		self.infosImgProv = a + '\n# ' + textSeqB + '\n' + a
			
		for chemin in self.listeChemSequenceA:
			self.infosImgProv=self.infosImgProv+'\n'+chemin
		self.infosImgProv = self.infosImgProv + '\n\n'
			
		# Affichage de l'image séquence A ------------------------------------
		# Affiche ici la dernière image chargée
		qImage1=QImage(self.listeChemSequenceA[len(self.listeChemSequenceA)-1])
		# Selon la valeur de la largeur ou de la hauteur, la taille de l'image affichée
		# varie dans tous les cas self.width_1 et self.height_1 doivent être définis 
		# (même s'ils ne servent pas ici)
		self.width_1=qImage1.width()
		self.height_1=qImage1.height()
		self.afficheurImg_1.setImage(self.listeChemSequenceA[len(self.listeChemSequenceA)-1])
		# --------------------------------------------------------------------

		# Activer le bouton 'appliquer' si les chemins ont été donnés
		if self.listeChemSequenceA!=[] and self.listeChemSequenceB!=[]:
			self.boutAppliquer.setEnabled(True)
			
		# tout s'est bien passé
		return 1
	
	
	def ouvrirImages_2(self):
		""" Récupération du chemin des images séquence B sélectionnées """
		
		# Ouvrir images séquence B
		rep = self.base.getRepSource(self.listeChemSequenceA, self.config)
		chemin_sequence_B=QFileDialog.getOpenFileNames(None, _(u"Ouvrir images séquence B"), rep,  ("JPEG (*.jpg *.JPG *.jpeg *.JPEG);;PNG (*.png *.PNG);;GIF (*.gif *.GIF);;BMP (*.bmp *.BMP);;SGI (*.sgi *.SGI);;TIF (*.tif *.TIF);;TARGA (*.tga *.TGA);;PNM (*.pnm *.PNM);;PPM (*.ppm *.PPM)"))
	
		# Si pas de fichier sélectionné -> sortir de la fonction
		if chemin_sequence_B.count()==0: return
	
		# Convertir les differents fichiers selectionnes
		# en une liste de chaines de caracteres .
		self.listeChemSequenceB=[str(chemin_sequence_B[i_seqB]) for i_seqB in range(chemin_sequence_B.count())]
		
		self.listeChemSequenceB.sort()
		
		# On implémente les chemins des fichiers dans une variable
		# pour préparer l'affichage des infos
		textSeqB=_(u"Image(s) séquence B chargée(s)")
		a='#'*36
		self.infosImgProv = self.infosImgProv + a + '\n# ' + textSeqB + '\n' + a
		
		for chemin in self.listeChemSequenceB:
			self.infosImgProv=self.infosImgProv+'\n'+chemin
		self.infosImgProv = self.infosImgProv + '\n\n'
		
		# Affichage de l'image séquence B ------------------------------------
		qImage2=QImage(self.listeChemSequenceB[0])
		# Selon la valeur de la largeur ou de la hauteur, la taille de l'image affichée varie
		# dans tous les cas self.width_2 et self.height_2 
		# doivent être définis (même s'ils ne servent pas ici)
		self.width_2=qImage2.width()
		self.height_2=qImage2.height()
		self.afficheurImg_2.setImage(self.listeChemSequenceB[0])
		# --------------------------------------------------------------------
		
		# Activer le bouton 'appliquer' si les chemins ont été donnés
		if self.listeChemSequenceA!=[] and self.listeChemSequenceB!=[]:
			self.boutAppliquer.setEnabled(True)
		
		# Pour ne pas risquer d'afficher un résultat contraire
		# aux seq A et B, on remet l'image d'accueil
		self.afficheurImg_3.setImage()
		
		# tout s'est bien passé
		return 1
	
	
	def ouvrirImages(self):
		""" Récupération du chemin des images sélectionnées """
		# S'il y a une erreur lors du chargement des images
		# seq A et B, pas la peine de continuer
		if not self.ouvrirImages_1(): return
		self.tabwidget.setCurrentIndex(self.tab_1)
		
		if not self.ouvrirImages_2(): return
		self.tabwidget.setCurrentIndex(self.tab_2)
		
	'''	
	def reglag(self):
		self.valChoixFondEnch=int(self.choixNbreImagesFondu.value())
	'''
	
	def stat_dim_img(self):
		"""Calcul statistique des dimensions des images les plus présentes dans les deux lots (seq A et seq B)."""
		
		# Ouverture et mise ds une liste des dimensions des images seq A. List
		# comprehension.
		listePrepaRedimA=[Image.open(aA).size for aA in self.listeChemSequenceA]
		
		# Merci beaucoup à Marc Keller de la liste: python at aful.org de m'avoir 
		# aidé pour cette partie (les 4 lignes en dessous) pour statistiquement 
		# découvrir les dimensions des images les plus présentes dans le lot 
		# chargé par l'utilisateur. J'avais trouvé une solution qui fonctionnait 
		# bien, mais celle de Marc est bien plus efficace car elle utilise un
		# dictionnaire (elle est donc plus rapide).
		dictSeqA={}.fromkeys(listePrepaRedimA, 0)
		for cleA in listePrepaRedimA: dictSeqA[cleA]+=1
		self.lStatDimSeqA=sorted(zip(dictSeqA.itervalues(), dictSeqA.iterkeys()), reverse=1)
		self.dimStatImgA=self.lStatDimSeqA[0][1]
		
		print "Toutes les dimensions des images seq A (avec le nbre d'images):", self.lStatDimSeqA
		print 'Dimension des images la plus presente dans la sequence A:', self.dimStatImgA
		
		# Ouverture et mise ds une liste des dimensions des images seq B. List
		# comprehension.
		listePrepaRedimB=[Image.open(bB).size for bB in self.listeChemSequenceB]
		
		dictSeqB={}.fromkeys(listePrepaRedimB, 0)
		for cleB in listePrepaRedimB: dictSeqB[cleB]+=1
		self.lStatDimSeqB=sorted(zip(dictSeqB.itervalues(), dictSeqB.iterkeys()), reverse=1)
		self.dimStatImgB=self.lStatDimSeqB[0][1]
	
		print "Toutes les dimensions des images seq B (avec le nbre d'images):", self.lStatDimSeqB
		print 'Dimension des images la plus presente dans la sequence B:', self.dimStatImgB
	
	
	def redim_img(self):
		"""Si l'utilisateur charge des images avec des tailles complètement différentes --> les images de la séquence A et B sont redimensionnées"""
		
		self.stat_dim_img()
		
		# ----- TRAVAIL PREPARATOIRE --- Redimensionnement 1 des images -----------
		# Ce redimensionnement ne gère que le lien entre la taille des images
		# séquence A, il ne gère pas le redimensionnement des images séquence B
    		# Recuperation du chemin + nom de la 1ere image chargee séquence A
    		recupImgSeqA=self.listeChemSequenceA[0]
		# Recup de l'extension de l'image séquence A
		fichA, extSeqA=os.path.splitext(recupImgSeqA)
	    	# Recup du chemin des images chargees de la séquence A
    		NomImgSeqA=os.path.dirname(recupImgSeqA)
    		# Boucle pour redimensionner les images chargees séquence A. Les images 
		# sont redimensionnees aux dimensions des images de la séquence A (aux 
		# dimensions des images les plus présentes dans le lot).
    		n1=0
    		while n1 < len(self.listeChemSequenceA):
        		for parcRedimA in self.listeChemSequenceA :
            			OuvrirImagA=Image.open(parcRedimA)
				# Redimensionnement des images
				sRedimA=OuvrirImagA.resize(self.dimStatImgA)
				# Recup du nom exact de l'image chargee
            			f1=string.split(parcRedimA, '/')[-1:]
            			sRedimA.save(NomImgSeqA+'/'+''.join(f1))
            			n1=n1+1
			print 'Chemin+nom des images de la sequence A (apres Redimensionnement):', NomImgSeqA
		
		# ----- TRAVAIL PREPARATOIRE --- Redimensionnement 2 des images -----------
		# Ce redimensionnement ne gère que le lien entre la taille des images
		# séquence B, il ne gère pas le redimensionnement des images séquence A
    		# Recuperation du chemin + nom de la 1ere image chargee séquence B
    		recupImgSeqB=self.listeChemSequenceB[0]
		# Recup de l'extension de l'image séquence B
		fichB, extSeqB=os.path.splitext(recupImgSeqB)
    		# Recup du chemin des images chargees de la séquence B
    		NomImgSeqB=os.path.dirname(recupImgSeqB)
    		# Boucle pour redimensionner les images chargees séquence B. Les images 
		# sont redimensionnees aux dimensions des images avec séquence A.
    		n2=0
		# Tant qu'on a pas atteint le nbre d'images séquence B
    		while n2 < len(self.listeChemSequenceB):
        		for parcRedimB in self.listeChemSequenceB :
            			OuvrirImagB=Image.open(parcRedimB)
            			# Redimensionnement des images
				sRedimB=OuvrirImagB.resize(self.dimStatImgA)
            			# Recup du nom exact de l'image chargee
            			f2=string.split(parcRedimB, '/')[-1:]
            			sRedimB.save(NomImgSeqB+'/'+''.join(f2))
            			n2=n2+1
			# Recup	du chemin+nom des images de la sequence B (apres
			# Redimensionnement)
			print 'Chemin+nom des images de la sequence B (apres Redimensionnement):', NomImgSeqB
	
	
	def etape_preparatoire(self):
		"""Etape préparatoire avant l'application de la transition fondu enchaîné"""
			
		self.stat_dim_img()
			
		if len(self.lStatDimSeqA)==1 and len(self.lStatDimSeqB)==1: pass
		else: 
			reply = QMessageBox.warning(self, 'Message',
			_(u"Vos images ne sont pas toutes de la même taille. Ceci dit la création de la transition fondu enchaîné peut quand même avoir lieu. Les images vont être redimensionnées à la résolution (statistiquement parlant) la plus présente dans vos images. Les opérations supplémentaires allongeront le processus. Voulez-vous quand même continuer ?."), QMessageBox.Yes, QMessageBox.No)
			if reply == QMessageBox.No:
				return
			# Redimensionnement des images
			self.redim_img()
			
		# Application (sans réglage possible de la part de l'utilisateur ...
		# pour éviter des erreurs du genre: l'utilisateur règle le taux d'images
		# comprises dans le fondu plus élevé que le nbre d'images chargées pour
		# la séquence A ou B) du taux d'images incluses dans le fondu enchaîné
		mini=min(len(self.listeChemSequenceA), len(self.listeChemSequenceB))
		
		if mini==1: self.valChoixFondEnch=1
		elif 1<mini<=5: self.valChoixFondEnch=2
		elif 5<mini<=10: self.valChoixFondEnch=4
		elif 10<mini<=25: self.valChoixFondEnch=8
		elif 25<mini<=50: self.valChoixFondEnch=13
		elif 50<mini<=100: self.valChoixFondEnch=20
		elif 100<mini<=250: self.valChoixFondEnch=27
		elif 250<mini<=1500: self.valChoixFondEnch=52
		elif mini<1500: self.valChoixFondEnch=52
		
		print "Nombre d'images servant au fondu: entre ", str(self.valChoixFondEnch-2), ' et ', str(self.valChoixFondEnch)

		#self.valChoixFondEnch=int(self.choixNbreImagesFondu.value())

		# -------------------------------------------------------------------------
		# Boîte de dialogue pour sauvegarder (nom du nouveau fichier)
		#--------------------------------------------------------------------------
		rep = self.base.getRepSource(self.listeChemSequenceA, self.config)
		self.chemDossierSauv=str(QFileDialog.getSaveFileName(None, _(u"Sauver"), rep, _(u"Tous les fichiers *.*")))
		
		if self.chemDossierSauv=='': return
		
		print 'Chemin+nom de sauvegarde:', self.chemDossierSauv
		
		# Barre de progression dans une fenêtre séparée . Attention la fenêtre
		# de la barre se ferme dès que la progression est terminée . En cas de
		# process très court, la fenêtre peut n'apparaître que très brièvement
		# (voire pas du tout si le temps est très très court) .
		self.progress=QProgressDialog(_(u"Progression ..."), _(u"Arrêter le processus"), 0, 100)
		self.progress.setWindowTitle(_(u'EnKoDeur-Mixeur. Fenêtre de progression'))
		# Attribution des nouvelles dimensions 
		self.progress.setMinimumWidth(500)
		self.progress.setMinimumHeight(100)
		
		# On implémente les chemins des fichiers dans une variable
		# pour préparer l'affichage des infos
		textSeqFinal=_(u"Résultat fondu enchaïné")
		a='#'*36
		self.infosImgProv = self.infosImgProv + a + '\n# ' + textSeqFinal + '\n' + a
		
		# -------- TRAITEMENT DE LA SEQUENCE A ----- IMAGES POUR LE FONDU ENCHAINE -
		# Recup du chemin et nom de la 1ere image chargee sequence A
		chNomChargSeqA=self.listeChemSequenceA[0]
	
		# Recup de l'extension des images sequence A chargees par l'utilisateur
		extImSeqA=string.split(chNomChargSeqA, '.')[-1:]	
	
		# Mise dans l'ordre croissant des images
		self.listeChemSequenceA.sort()
		# Inversion de l'ordre (ordre decroissant)
		self.listeChemSequenceA.reverse()
	
		# On ne selectionne (ds cette liste) que les images qui vont subir
		# le fondu enchaine et ce pour les images de la sequence A
		self.imgCoupeesSeqA=self.listeChemSequenceA[0:self.valChoixFondEnch]
		# On remet les images de la liste self.imgCoupeesSeqA ds l'orde croissant
		self.imgCoupeesSeqA.sort()
	
		# On fait ressortir les elements differents entre les images sequence A 
		# selectionnes par l'utilisateur (seq A fondu) et les images sequence A  
		# qui ont ete chargees par l'utilisateur .
		interChargUtilisSeqA=sets.Set(self.imgCoupeesSeqA) 
		interExisteSeqA=sets.Set(self.listeChemSequenceA) 
		interInterSeqA=interChargUtilisSeqA.symmetric_difference(interExisteSeqA)
		listeInterInterSeqA=[t1 for t1 in interInterSeqA]
		listeInterInterSeqA.sort()
	
		# Creation d'un repertoire tampon pour accueillir les images du dossier
		# contenant les images de la sequence A . Si le repertoire existe deja il 
		# est elimine (avec tout ce qu'il contient) et ensuite recree . Ce rep. 
		# n'est qu'un TAMPON 	
		if os.path.exists(os.path.dirname(self.chemDossierSauv)+'/'+'fonduEnchaineImg_tempo_A') :
			shutil.rmtree(os.path.dirname(self.chemDossierSauv)+'/'+'fonduEnchaineImg_tempo_A')
			os.mkdir(os.path.dirname(self.chemDossierSauv)+'/'+'fonduEnchaineImg_tempo_A')
		else :
			os.mkdir(os.path.dirname(self.chemDossierSauv)+'/'+'fonduEnchaineImg_tempo_A')
		
		# Copie des images de la sequence A qui doivent faire partie du fondu 
		# dans le rep. temporaire fonduEnchaineImg_tempo_A (fraichement cree) .
		for parcSeqB_Temp in self.imgCoupeesSeqA:
			shutil.copy("".join(parcSeqB_Temp), os.path.dirname(self.chemDossierSauv)+'/'+'fonduEnchaineImg_tempo_A')
		# -------------------------------------------------------------------------
	
		# ----- TRAITEMENT DE LA SEQUENCE A --- IMAGES AUTRES QUE POUR LE FONDU
		# ENCHAINE -
		# Creation d'un repertoire tampon pour accueillir les images ne servant 
		# pas au fondu enchaine, mais ces images sont tres utiles pour le montage
		# final ==> images_seq_A_pas_fondu + images_fondu_seq_A_et_B_melangees 
		if os.path.exists(os.path.dirname(self.chemDossierSauv)+'/'+'pas_fonduEnchaineImg_tempo_A') :
			shutil.rmtree(os.path.dirname(self.chemDossierSauv)+'/'+'pas_fonduEnchaineImg_tempo_A')
			os.mkdir(os.path.dirname(self.chemDossierSauv)+'/'+'pas_fonduEnchaineImg_tempo_A')
		else :
			os.mkdir(os.path.dirname(self.chemDossierSauv)+'/'+'pas_fonduEnchaineImg_tempo_A')

		# Copie des images de la sequence A qui ne servent pas au fondu enchaine 
		# dans le rep. pas_fonduEnchaineImg_tempo_A fraichement cree .
		for parcSeqA_PasFE in listeInterInterSeqA:
			shutil.copy("".join(parcSeqA_PasFE), os.path.dirname(self.chemDossierSauv)+'/'+'pas_fonduEnchaineImg_tempo_A')
		
		# Chemin complet vers le rep. de sauvegarde
		chemRepSauvSeqA_PasFE=os.path.dirname(self.chemDossierSauv)+'/'+'pas_fonduEnchaineImg_tempo_A'
	
		# Recup du chemin+nom des images sequence A copiees ds
		# pas_fonduEnchaineImg_tempo_A
		rChRepSauvSeqA_PasFE=glob.glob(chemRepSauvSeqA_PasFE+'/'+'*.'+"".join(extImSeqA))
		rChRepSauvSeqA_PasFE.sort()
	
		# Pour le renommage des images selectionnees pour le fondu enchaine . Les
		# images copiees ds le rep. fonduEnchaineImg_tempo_A vont ensuite etre
		# renommees et (recopiees) ds le rep. de sauvegarde choisi par l'utilisateur
		##### Exemple : Affiche '000039' ... '000058' (si choix : 20 img. pour le
		# fondu)
		# List comprehension. Je sais c'est moins lisible, mais c'est plus rapide !.
		self.liste_1_RISPFE=[string.zfill(int(parcRISPFE)+len(listeInterInterSeqA)+1, 6) for parcRISPFE in range(len(self.imgCoupeesSeqA))]
			
		# Pour le renommage des images se trouvant juste avant celles pour le fondu
		# Les images copiees ds le rep. pas_fonduEnchaineImg_tempo_A vont ensuite
		# etre renommees et (recopiees) ds le rep. de sauvegarde choisi par
		# l'utilisateur.
		##### Exemple : Affichage '000001' ... '000038'.
		liste_2_RITJACPFseqA=[string.zfill(parcRITJACPF_seqA+1, 6) for parcRITJACPF_seqA in range(len(listeInterInterSeqA))]

		print 'Pour le renommage des images séquence A se trouvant juste avant celles pour le fondu:', liste_2_RITJACPFseqA
		
		# Renommage des images sequence A de la liste liste_2_RITJACPFseqA . Ces
		# images sont renommees en fonction de la numerotation des images qui n'ont
		# pas ete selectionnes par le reglage des images faisant partie du fondu .
		listeSeqAaff=[] 
		
		aSeqA=0
		while aSeqA < len(rChRepSauvSeqA_PasFE):
			os.rename(rChRepSauvSeqA_PasFE[aSeqA], os.path.dirname(self.chemDossierSauv)+'/'+os.path.basename(self.chemDossierSauv)+'_'+"".join(liste_2_RITJACPFseqA[aSeqA])+'.jpg')
			
			# Liste Séquence B Affichage --> affichage des infos
			listeSeqAaff.append(os.path.dirname(self.chemDossierSauv)+'/'+os.path.basename(self.chemDossierSauv)+'_'+"".join(liste_2_RITJACPFseqA[aSeqA])+'.jpg')
			
			aSeqA=aSeqA+1
			
		# Affichage des infos de sauvegarde des images venant juste
		# avant le fondu enchaîné
		for chemin_1 in listeSeqAaff:
			self.infosImgProv=self.infosImgProv+'\n'+chemin_1
		# ---------------------------------------------------------------------------
	
	
		# -------- TRAITEMENT DE LA SEQUENCE B ----- IMAGES POUR LE FONDU ENCHAINE -
		# Recup du chemin et nom de la 1ere image chargee sequence B
		chNomChargSeqB=self.listeChemSequenceB[0]
	
		# Recup de l'extension des images sequence B chargees par l'utilisateur
		extImSeqB=string.split(chNomChargSeqB, '.')[-1:]	
	
		# Mise dans l'ordre croissant des images
		self.listeChemSequenceB.sort()
	
		# On ne selectionne (ds cette liste) que les images qui vont subir
		# le fondu enchaine et ce pour les images de la sequence B .
		self.imgCoupeesSeqB=self.listeChemSequenceB[0:self.valChoixFondEnch]
	
		# On fait ressortir les elements differents entre les images sequence B 
		# selectionnes par l'utilisateur (seq B fondu) et les images sequence B  
		# qui ont ete chargees par l'utilisateur .
		interChargUtilisSeqB=sets.Set(self.imgCoupeesSeqB) 
		interExisteSeqB=sets.Set(self.listeChemSequenceB) 
		interInterSeqB=interChargUtilisSeqB.symmetric_difference(interExisteSeqB)
		listeInterInterSeqB=[t2 for t2 in interInterSeqB]
		listeInterInterSeqB.sort()
	
		# Creation d'un repertoire tampon pour accueillir les images du dossier
		# contenant les images de la sequence B . Si le repertoire existe deja il 
		# est elimine (avec tout ce qu'il contient) et ensuite recree . Ce rep. 
		# n'est qu'un TAMPON 	
		if os.path.exists(os.path.dirname(self.chemDossierSauv)+'/'+'fonduEnchaineImg_tempo_B') :
			shutil.rmtree(os.path.dirname(self.chemDossierSauv)+'/'+'fonduEnchaineImg_tempo_B')
			os.mkdir(os.path.dirname(self.chemDossierSauv)+'/'+'fonduEnchaineImg_tempo_B')
		else :
			os.mkdir(os.path.dirname(self.chemDossierSauv)+'/'+'fonduEnchaineImg_tempo_B')
		
		# Copie des images de la sequence B qui doivent faire partie du fondu 
		# dans le rep. temporaire fonduEnchaineImg_tempo_B (fraichement cree) .
		for parcSeqB_Temp in self.imgCoupeesSeqB:
			copRepSeqB_Temp=shutil.copy("".join(parcSeqB_Temp), os.path.dirname(self.chemDossierSauv)+'/'+'fonduEnchaineImg_tempo_B')
		# ---------------------------------------------------------------------------
		
		# ----- TRAITEMENT DE LA SEQUENCE B --- IMAGES AUTRES QUE POUR LE FONDU
		# ENCHAINE -
		# Creation d'un repertoire tampon pour accueillir les images ne servant pas
		# au fondu enchaine, mais ces images sont tres utiles pour le montage final
		# ==> images_fondu_seq_A_et_B_melangees + images_seq_B_pas_fondu .
		if os.path.exists(os.path.dirname(self.chemDossierSauv)+'/'+'pas_fonduEnchaineImg_tempo_B'):
			shutil.rmtree(os.path.dirname(self.chemDossierSauv)+'/'+'pas_fonduEnchaineImg_tempo_B')
			os.mkdir(os.path.dirname(self.chemDossierSauv)+'/'+'pas_fonduEnchaineImg_tempo_B')
		else :
			os.mkdir(os.path.dirname(self.chemDossierSauv)+'/'+'pas_fonduEnchaineImg_tempo_B')

		# Copie des images de la sequence B qui ne servent pas au fondu enchaine 
		# dans le rep. pas_fonduEnchaineImg_tempo_A fraichement cree .
		for parcSeqB_PasFE in listeInterInterSeqB:
			shutil.copy("".join(parcSeqB_PasFE), os.path.dirname(self.chemDossierSauv)+'/'+'pas_fonduEnchaineImg_tempo_B') 
		
		# Chemin complet vers le rep. de sauvegarde
		chemRepSauvSeqB_PasFE=os.path.dirname(self.chemDossierSauv)+'/'+'pas_fonduEnchaineImg_tempo_B'
	
		# Recup du chemin+nom des images sequence B copiees ds
		# pas_fonduEnchaineImg_tempo_B
		rChRepSauvSeqB_PasFE=glob.glob(chemRepSauvSeqB_PasFE+'/'+'*.'+"".join(extImSeqB))
		rChRepSauvSeqB_PasFE.sort()
	
		# Pour le renommage des images se trouvant juste apres celles pour le fondu
		# Les images copiees ds le rep. pas_fonduEnchaineImg_tempo_B vont ensuite
		# etre renommees et (recopiees) ds le rep. de sauvegarde choisi par
		# l'utilisateur .
		##### Exemple : Affichage '000059' ... '000088' .
		liste_2_RITJACPFseqB=[string.zfill(parcRITJACPF_seqB+len(self.imgCoupeesSeqB)+len(listeInterInterSeqA)+1, 6) for parcRITJACPF_seqB in range(len(listeInterInterSeqB))]

		print 'Pour le renommage des images séquence B se trouvant juste après celles pour le fondu:', liste_2_RITJACPFseqB
		
		# Renommage des images sequence B de la liste liste_2_RITJACPFseqB .
		# Attention : le renommage s'effectue avec la numerotation suivante ====> 
		# indice parcRITJACPF_seqB sequence B (c'est a dire 0, 1, 2, 3, 4, 5, 6, 7
		# ...) + nbre d'images selectionnees pour la decoupe sequence B + nbre
		# d'images n'ayant pas ete selectionnees pour le fondu de la séquence A (ce
		# coup-ci ce sont des images de la sequence A !!! et pas sequence B) + 1.
		self.listeSeqBaff=[]
		
		aSeqB=0
		while aSeqB < len(rChRepSauvSeqB_PasFE):
			os.rename(rChRepSauvSeqB_PasFE[aSeqB], os.path.dirname(self.chemDossierSauv)+'/'+os.path.basename(self.chemDossierSauv)+'_'+"".join(liste_2_RITJACPFseqB[aSeqB])+'.jpg')
			
			# Liste Séquence B Affichage --> affichage des infos
			self.listeSeqBaff.append(os.path.dirname(self.chemDossierSauv)+'/'+os.path.basename(self.chemDossierSauv)+'_'+"".join(liste_2_RITJACPFseqB[aSeqB])+'.jpg')
			
			aSeqB=aSeqB+1
		# ---------------------------------------------------------------------------

		
	def final_moteur(self):
		"""appliquer la transition fondu enchaîné"""
		
		try:
			# FINAL MOTEUR (APPLICATION DU FONDU)
			self.etape_preparatoire()
		
			listeResultatChem=[]
		
			nbreElem=len(self.imgCoupeesSeqA)
		
			for parc in range(nbreElem):
			
				# Ouverture des images en cours dans la boucle .
				imgOpFE1=Image.open("".join(self.imgCoupeesSeqA[parc]))
				imgOpFE2=Image.open("".join(self.imgCoupeesSeqB[parc]))
			
				# Calcul du taux de blend (taux de melange de l'image 
				# sequence A et sequence B en cours) .
				#calcCHANGblend=round((float((parc+1)*100)/len(self.imgCoupeesSeqA))/100, 8)
				calcCHANGblend=round(float(parc+1)/len(self.imgCoupeesSeqA), 8)
		
				# Application du fondu enchaine et sauvegarde (aves numerotation 
				# des images) .
				imgFE=Image.blend(imgOpFE1, imgOpFE2, calcCHANGblend)
				imgFE.save(os.path.dirname(self.chemDossierSauv)+'/'+os.path.basename(self.chemDossierSauv)+'_'+"".join(self.liste_1_RISPFE[parc])+'.jpg')
		
				listeResultatChem.append(os.path.dirname(self.chemDossierSauv)+'/'+os.path.basename(self.chemDossierSauv)+'_'+"".join(self.liste_1_RISPFE[parc])+'.jpg')
		
				# --------------------------------------------
				# Affichage de la progression (avec
				# QProgressDialog) ds une fenêtre séparée .
				val_pourc=((parc+1)*100)/nbreElem

				# Bouton Cancel pour arrêter la progression donc le process
				if (self.progress.wasCanceled()):
					break

				self.progress.setValue(val_pourc)
			
				QApplication.processEvents()
				# --------------------------------------------
			
			# Affichage de l'image produit du fondu enchaîné ----------------------
			# Affiche ici l'image se trouvant à peu près au milieu de la liste
			# résultant du fondu enchaîné
			qImage3=QImage(listeResultatChem[(len(listeResultatChem)-1)/2])
			# Selon la valeur de la largeur ou de la hauteur, la taille de l'image
			# affichée
			# varie dans tous les cas self.width_3 et self.height_3 doivent être définis 
			# (même s'ils ne servent pas ici)
			self.width_3=qImage3.width()
			self.height_3=qImage3.height()
			self.afficheurImg_3.setImage(listeResultatChem[(len(listeResultatChem)-1)/2])
			# --------------------------------------------------------------------
			
			# Affichage des infos de sauvegarde des images du fondu enchaîné
			for chemin_3 in listeResultatChem:
				self.infosImgProv=self.infosImgProv+'\n'+chemin_3
		
			# Affichage des infos de sauvegarde des images venant juste 
			# après le fondu enchaîné	
			for chemin_2 in self.listeSeqBaff: 
				self.infosImgProv=self.infosImgProv+'\n'+chemin_2 
			self.infosImgProv = self.infosImgProv + '\n\n'
		
			# Affichage des infos du nbre d'images ayant servi dans le fondu
			textNbre=_(u"Nombre d'image(s) incluses dans le fondu: entre ")
			a_nbre='#'*46
			self.infosImgProv = self.infosImgProv+a_nbre+'\n# '+textNbre+str(self.valChoixFondEnch-2)+_(' et ')+str(self.valChoixFondEnch)+'\n'+a_nbre+'\n'
		
			# On fait apparaître le dernier onglet
			self.tabwidget.setCurrentIndex(self.tab_3)
		
			# Le bouton appliquer n'a plus besoin d'être valide
			# car sinon on referait exactement la même action
			self.boutAppliquer.setEnabled(False)
		
			# affichage des infos dans l'onglet
			self.zoneAffichInfosImg.setText(self.infosImgProv)
			self.fram.setEnabled(True)
		
			# remise à 0 de la variable provisoire de log
			self.infosImgProv = ''
		
			# Elimination de tous les repertoires temporaires et de toutes les images
			# contenues dans ces repertoires.	
			shutil.rmtree(os.path.dirname(self.chemDossierSauv)+'/'+'fonduEnchaineImg_tempo_A')
			shutil.rmtree(os.path.dirname(self.chemDossierSauv)+'/'+'fonduEnchaineImg_tempo_B')
			shutil.rmtree(os.path.dirname(self.chemDossierSauv)+'/'+'pas_fonduEnchaineImg_tempo_A')
			shutil.rmtree(os.path.dirname(self.chemDossierSauv)+'/'+'pas_fonduEnchaineImg_tempo_B')
			
		except:
			messageErreur2=QMessageBox(self)
			messageErreur2.setText(_(u"Une erreur s'est produite !, vous vous êtes certainement trompé en chargeant vos images. Recommencez et faites attention ce coup-ci."))
			messageErreur2.setWindowTitle(_(u"Erreur"))
			messageErreur2.setIcon(QMessageBox.Critical)
			messageErreur2.exec_()
			self.infosImgProv = '' # remise à 0 du log provisoire
			
	
	def afficherAide(self):
		"""Boîte de dialogue de l'aide"""

		messageAide=QMessageBox(self)
		messageAide.setText(_(u"Blablablabla ... blabla."))
		messageAide.setWindowTitle(_(u"Aide"))
		messageAide.setIcon(QMessageBox.Information)
		messageAide.exec_()