From 8001ff4db171debb2a4e3d963af402e87e80b46e Mon Sep 17 00:00:00 2001 From: eficas <> Date: Wed, 6 Nov 2002 17:46:09 +0000 Subject: [PATCH] =?utf8?q?CCAR:=20Modified=20Files:=20CCAR:=20=09I=5FETAPE?= =?utf8?q?.py=20I=5FFORM=5FETAPE.py=20I=5FJDC.py=20I=5FMACRO=5FETAPE.py=20?= =?utf8?q?CCAR:=20=09I=5FMCCOMPO.py=20I=5FMCLIST.py=20I=5FMCSIMP.py=20I=5F?= =?utf8?q?PROC=5FETAPE.py=20CCAR:=20--------------------------------------?= =?utf8?q?--------------------------------=20CCAR=20:=20developpement=20po?= =?utf8?q?ur=20traiter=20correctement=20l'insertion=20et=20la=20destructio?= =?utf8?q?n=20des=20macros=20avec=20etapes=20et=20concepts=20inclus.=20Ces?= =?utf8?q?=20INCLUDEs=20sont=20evalu=C3=A9s=20dans=20un=20JDC=20auxiliaire?= =?utf8?q?=20avant=20d'etre=20ins=C3=A9r=C3=A9es=20d=C3=A9finitivement=20d?= =?utf8?q?ans=20la=20macro=20apres=20verification.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- Ihm/I_ETAPE.py | 61 ++++++-- Ihm/I_FORM_ETAPE.py | 13 +- Ihm/I_JDC.py | 220 ++++++++++++++++++++++----- Ihm/I_MACRO_ETAPE.py | 346 ++++++++++++++++++++++++++++++++++++------- Ihm/I_MCCOMPO.py | 12 ++ Ihm/I_MCLIST.py | 12 ++ Ihm/I_MCSIMP.py | 88 ++++++++++- Ihm/I_PROC_ETAPE.py | 15 +- 8 files changed, 655 insertions(+), 112 deletions(-) diff --git a/Ihm/I_ETAPE.py b/Ihm/I_ETAPE.py index 865f2378..5ccb189e 100644 --- a/Ihm/I_ETAPE.py +++ b/Ihm/I_ETAPE.py @@ -20,6 +20,7 @@ """ """ # Modules Python +import sys import string,types from copy import copy @@ -40,10 +41,11 @@ class ETAPE(I_MCCOMPO.MCCOMPO): def get_sdname(self): if CONTEXT.debug : print "SDNAME ",self.reuse,self.sd,self.sd.get_name() + sdname='' if self.reuse != None: sdname= self.reuse.get_name() else: - sdname=self.sd.get_name() + if self.sd:sdname=self.sd.get_name() if string.find(sdname,'sansnom') != -1 or string.find(sdname,'SD_') != -1: # dans le cas où la SD est 'sansnom' ou 'SD_' on retourne la chaîne vide return '' @@ -59,7 +61,6 @@ class ETAPE(I_MCCOMPO.MCCOMPO): """ Met l'état de l'étape à : modifié Propage la modification au parent - Si la fonction op_init existe, l'active """ # Une action # doit etre realisée apres init_modif et la validite reevaluée @@ -76,11 +77,10 @@ class ETAPE(I_MCCOMPO.MCCOMPO): ex : INCLUDE et POURSUITE """ if self.isvalid() : - if type(self.definition.op_init) == types.FunctionType : - # XXX Normalement en mode editeur g_context ne peut pas etre utilisé - apply(self.definition.op_init,(self,self.parent.g_context)) - self.state = 'modified' - + d=self.parent.get_contexte_apres(self) + if self.parent: + self.parent.fin_modif() + def nomme_sd(self,nom) : """ Cette méthode a pour fonction de donner un nom (nom) au concept @@ -190,9 +190,9 @@ class ETAPE(I_MCCOMPO.MCCOMPO): Il faut ajouter la sd si elle existe au contexte global du JDC et à la liste des sd """ + if self.actif:return self.actif = 1 if not self.sd : return - # XXX Pourquoi faut-il faire ce qui suit ??? par defaut les etapes sont actives try: self.jdc.append_sdprod(self.sd) except: @@ -209,6 +209,31 @@ class ETAPE(I_MCCOMPO.MCCOMPO): self.jdc.del_sdprod(self.sd) self.jdc.delete_concept_after_etape(self,self.sd) + def control_sdprods(self,d): + """ + Cette methode doit updater le contexte fournit par + l'appelant en argument (d) en fonction de sa definition + tout en verifiant que ses concepts produits ne sont pas + deja definis dans le contexte + """ + if type(self.definition.op_init) == types.FunctionType: + apply(self.definition.op_init,(self,d)) + if self.sd: + if d.has_key(self.sd.nom): + # Le concept est deja defini + if self.reuse and self.reuse is d[self.sd.nom]: + # Le concept est reutilise : situation normale + pass + else: + # Redefinition du concept, on l'annule + #XXX on pourrait simplement annuler son nom pour conserver les objets + # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??) + self.sd=self.reuse=self.sdnom=None + self.init_modif() + else: + # Le concept n'est pas defini, on peut updater d + d[self.sd.nom]=self.sd + def supprime_sdprods(self): """ Fonction: @@ -217,8 +242,6 @@ class ETAPE(I_MCCOMPO.MCCOMPO): Une procedure n'en a aucun Une macro en a en général plus d'un """ - # XXX pour les macros il faudrait peut etre aussi - # supprimer les concepts a droite du = ??? if not self.is_reentrant() : # l'étape n'est pas réentrante # le concept retourné par l'étape est à supprimer car il était @@ -244,6 +267,22 @@ class ETAPE(I_MCCOMPO.MCCOMPO): for child in self.mc_liste : child.delete_concept(sd) + def replace_concept(self,old_sd,sd): + """ + Inputs : + old_sd=concept remplace + sd = nouveau concept + Fonction : + Mettre a jour les mots cles de l etape et eventuellement + le concept produit si reuse + suite au remplacement du concept old_sd + """ + if self.reuse and self.reuse == old_sd: + self.sd=self.reuse=sd + self.init_modif() + for child in self.mc_liste : + child.replace_concept(old_sd,sd) + def make_register(self): """ Initialise les attributs jdc, id, niveau et réalise les @@ -392,8 +431,10 @@ class ETAPE(I_MCCOMPO.MCCOMPO): # En plus il faut rendre coherents sdnom et sd.nom self.sd=None self.sdnom=None + self.state="unchanged" self.valid=0 return self.sd + #raise AsException("Etape ",self.nom,'ligne : ',self.appel[0], # 'fichier : ',self.appel[1],e) except EOFError: diff --git a/Ihm/I_FORM_ETAPE.py b/Ihm/I_FORM_ETAPE.py index 80689be4..b76b4b5a 100644 --- a/Ihm/I_FORM_ETAPE.py +++ b/Ihm/I_FORM_ETAPE.py @@ -262,7 +262,7 @@ class FORM_ETAPE(MACRO_ETAPE): Inputs : sd=concept detruit Fonction : - Mettre a jour les mos cles de l etape et eventuellement le concept produit si reuse + Mettre a jour les mots cles de l etape et eventuellement le concept produit si reuse suite à la disparition du concept sd Seuls les mots cles simples MCSIMP font un traitement autre que de transmettre aux fils, sauf les objets FORM_ETAPE qui doivent vérifier que le concept détruit n'est pas @@ -270,3 +270,14 @@ class FORM_ETAPE(MACRO_ETAPE): """ self.init_modif() + def replace_concept(self,old_sd,sd): + """ + Inputs : + old_sd=concept remplace + sd = nouveau concept + Fonction : + Les objets FORM_ETAPE devraient vérifier que le concept remplacé n'est pas + utilisé dans le corps de la fonction + """ + self.init_modif() + diff --git a/Ihm/I_JDC.py b/Ihm/I_JDC.py index 125fb617..3b895351 100644 --- a/Ihm/I_JDC.py +++ b/Ihm/I_JDC.py @@ -216,6 +216,57 @@ class JDC(I_OBJECT.OBJECT): if sd:return sd return self.get_sd_apres_etape(nom_sd,etape,avec) + def get_contexte_avant(self,etape): + """ + Retourne le dictionnaire des concepts connus avant etape + On tient compte des commandes qui modifient le contexte + comme DETRUIRE ou les macros + Si etape == None, on retourne le contexte en fin de JDC + """ + # L'étape courante pour laquelle le contexte a été calculé est + # mémorisée dans self.index_etape_courante + # XXX on pourrait faire mieux dans le cas PAR_LOT="NON" : en + # mémorisant l'étape + # courante pendant le processus de construction des étapes. + # Si on insère des commandes (par ex, dans EFICAS), il faut préalablement + # remettre ce pointeur à 0 + if etape: + index_etape=self.etapes.index(etape) + else: + index_etape=len(self.etapes) + if index_etape >= self.index_etape_courante: + # On calcule le contexte en partant du contexte existant + d=self.current_context + if self.index_etape_courante==0 and self.context_ini: + d.update(self.context_ini) + liste_etapes=self.etapes[self.index_etape_courante:index_etape] + else: + d=self.current_context={} + if self.context_ini:d.update(self.context_ini) + liste_etapes=self.etapes + + for e in liste_etapes: + if e is etape: + break + if e.isactif(): + e.update_context(d) + self.index_etape_courante=index_etape + return d + + def get_contexte_apres(self,etape): + """ + Retourne le dictionnaire des concepts connus apres etape + On tient compte des commandes qui modifient le contexte + comme DETRUIRE ou les macros + Si etape == None, on retourne le contexte en fin de JDC + """ + if not etape: return self.get_contexte_avant(etape) + + d=self.get_contexte_avant(etape) + if etape.isactif():etape.update_context(d) + self.index_etape_courante=self.index_etape_courante+1 + return d + def active_etapes(self): """ Cette méthode a pour fonction de désactiver les étapes qui doivent @@ -245,6 +296,10 @@ class JDC(I_OBJECT.OBJECT): un jeu de commandes """ self.init_modif() + # On memorise le contexte avant l'etape a supprimer + d=self.get_contexte_avant(etape) + index_etape=self.etapes.index(etape) + self.etapes.remove(etape) if etape.niveau is not self: # Dans ce cas l'étape est enregistrée dans un niveau @@ -253,25 +308,13 @@ class JDC(I_OBJECT.OBJECT): etape.supprime_sdprods() self.active_etapes() - def del_sdprod(self,sd): - """ - Supprime la SD sd de la liste des sd et des dictionnaires de contexte - """ - if sd in self.sds : self.sds.remove(sd) - if self.g_context.has_key(sd.nom) : del self.g_context[sd.nom] - - def delete_concept(self,sd): - """ - Inputs : - sd=concept detruit - Fonction : - Mettre a jour les etapes du JDC suite à la disparition du - concept sd - Seuls les mots cles simples MCSIMP font un traitement autre - que de transmettre aux fils - """ - for etape in self.etapes : - etape.delete_concept(sd) + # Apres suppression de l'etape il faut controler que les etapes + # suivantes ne produisent pas des concepts DETRUITS dans op_init de etape + for e in self.etapes[index_etape:]: + e.control_sdprods(d) + + self.reset_context() + self.fin_modif() def analyse(self): self.compile() @@ -368,17 +411,6 @@ class JDC(I_OBJECT.OBJECT): if self.appli: self.appli.send_message(message) -#XXX ne semble pas servir pour JDC -# def reevalue_sd_jdc(self): - #""" - #Avec la liste des SD qui ont été supprimées, propage la disparition de ces - #SD dans toutes les étapes et descendants - #""" - #l_sd = self.diff_contextes() - #if len(l_sd) == 0 : return - #for sd in l_sd: - #self.jdc.delete_concept(sd) - def init_modif(self): """ Méthode appelée au moment où une modification va être faite afin de @@ -387,6 +419,7 @@ class JDC(I_OBJECT.OBJECT): self.state = 'modified' def fin_modif(self): + self.isvalid() pass def get_liste_mc_inconnus(self): @@ -423,6 +456,7 @@ class JDC(I_OBJECT.OBJECT): fproc=open(file,'r') text=fproc.read() fproc.close() + if file == None : return None,None text=string.replace(text,'\r\n','\n') linecache.cache[file]=0,0,string.split(text,'\n'),file return file,text @@ -435,30 +469,34 @@ class JDC(I_OBJECT.OBJECT): """ return [] - def NommerSdprod(self,sd,sdnom): + def NommerSdprod(self,sd,sdnom,restrict='non'): """ - Nomme la SD apres avoir verifie que le nommage est possible : nom - non utilise + Nomme la SD apres avoir verifie que le nommage est possible : + nom non utilise Si le nom est deja utilise, leve une exception Met le concept créé dans le concept global g_context """ # XXX En mode editeur dans EFICAS, le nommage doit etre géré différemment # Le dictionnaire g_context ne représente pas le contexte # effectif avant une étape. - # Il faut utiliser get_contexte_avant avec une indication de l'étape - # traitée. Pour le moment, il n'y a pas de moyen de le faire : ajouter - # un attribut dans le JDC ??? + # Il faut utiliser get_contexte_avant avec indication de l'étape + # traitée. + # Cette etape est indiquee par l'attribut _etape_context qui a ete + # positionné préalablement par un appel à set_etape_context + if CONTEXT.debug : print "JDC.NommerSdprod ",sd,sdnom + if self._etape_context: o=self.get_contexte_avant(self._etape_context).get(sdnom,None) else: - o=self.g_context.get(sdnom,None) + o=self.sds_dict.get(sdnom,None) + if isinstance(o,ASSD): raise AsException("Nom de concept deja defini : %s" % sdnom) # ATTENTION : Il ne faut pas ajouter sd dans sds car il s y trouve deja. # Ajoute a la creation (appel de reg_sd). - self.g_context[sdnom]=sd + self.sds_dict[sdnom]=sd sd.nom=sdnom def set_etape_context(self,etape): @@ -477,6 +515,14 @@ class JDC(I_OBJECT.OBJECT): self.current_context={} self.index_etape_courante=0 + def del_sdprod(self,sd): + """ + Supprime la SD sd de la liste des sd et des dictionnaires de contexte + """ + if sd in self.sds : self.sds.remove(sd) + if self.g_context.has_key(sd.nom) : del self.g_context[sd.nom] + if self.sds_dict.has_key(sd.nom) : del self.sds_dict[sd.nom] + def del_param(self,param): """ Supprime le paramètre param de la liste des paramètres @@ -493,3 +539,101 @@ class JDC(I_OBJECT.OBJECT): if fonction in self.fonctions : self.fonctions.remove(fonction) if self.g_context.has_key(fonction.nom) : del self.g_context[fonction.nom] + def append_sdprod(self,sd): + """ + Ajoute la SD sd à la liste des sd en vérifiant au préalable qu'une SD de + même nom n'existe pas déjà + """ + if sd == None or sd.nom == None:return + + o=self.sds_dict.get(sd.nom,None) + if isinstance(o,ASSD): + raise AsException("Nom de concept deja defini : %s" % sd.nom) + self.sds_dict[sd.nom]=sd + self.g_context[sd.nom] = sd + if sd not in self.sds : self.sds.append(sd) + + def append_param(self,param): + """ + Ajoute le paramètre param à la liste des params + et au contexte global + """ + # il faudrait vérifier qu'un paramètre de même nom n'existe pas déjà !!! + if param not in self.params : self.params.append(param) + self.g_context[param.nom]=param + + def append_fonction(self,fonction): + """ + Ajoute la fonction fonction à la liste des fonctions + et au contexte global + """ + # il faudrait vérifier qu'une fonction de même nom n'existe pas déjà !!! + if fonction not in self.fonctions : self.fonctions.append(fonction) + self.g_context[fonction.nom]=fonction + + def delete_concept_after_etape(self,etape,sd): + """ + Met à jour les étapes du JDC qui sont après etape en fonction + de la disparition du concept sd + """ + index = self.etapes.index(etape)+1 + if index == len(self.etapes) : + return # etape est la dernière étape du jdc ...on ne fait rien ! + for child in self.etapes[index:]: + child.delete_concept(sd) + + def delete_concept(self,sd): + """ + Inputs : + sd=concept detruit + Fonction : + Mettre a jour les etapes du JDC suite à la disparition du + concept sd + Seuls les mots cles simples MCSIMP font un traitement autre + que de transmettre aux fils + """ + for etape in self.etapes : + etape.delete_concept(sd) + + def replace_concept_after_etape(self,etape,old_sd,sd): + """ + Met à jour les étapes du JDC qui sont après etape en fonction + du remplacement du concept sd + """ + index = self.etapes.index(etape)+1 + if index == len(self.etapes) : + return # etape est la dernière étape du jdc ...on ne fait rien ! + for child in self.etapes[index:]: + child.replace_concept(old_sd,sd) + + def dump_state(self): + print "dump_state" + print "JDC.state: ",self.state + for etape in self.etapes : + print etape.nom+".state: ",etape.state + +#ATTENTION cette methode surcharge la methode du package Validation : a reintegrer + def isvalid(self,cr='non'): + """ + Méthode booléenne qui retourne 0 si le JDC est invalide, 1 sinon + """ + # FR : on prend en compte l'état du JDC ('unchanged','modified','undetermined') + # afin d'accélérer le test de validité du JDC + if self.state == 'unchanged': + return self.valid + else: + valid = 1 + texte,test = self.verif_regles() + if test == 0: + if cr == 'oui': self.cr.fatal(string.strip(texte)) + valid = 0 + if valid : + for e in self.etapes: + if not e.isactif() : continue + if not e.isvalid(): + valid = 0 + break + self.state="unchanged" + self.valid = valid + return self.valid + diff --git a/Ihm/I_MACRO_ETAPE.py b/Ihm/I_MACRO_ETAPE.py index 1fd95f5e..5c00db69 100644 --- a/Ihm/I_MACRO_ETAPE.py +++ b/Ihm/I_MACRO_ETAPE.py @@ -20,6 +20,7 @@ """ """ # Modules Python +import sys import traceback,types,string # Modules Eficas @@ -27,7 +28,7 @@ import I_ETAPE from Noyau.N_ASSD import ASSD # import rajoutés suite à l'ajout de Build_sd --> à résorber -import Noyau +import Noyau, Validation.V_MACRO_ETAPE from Noyau import N_Exception from Noyau.N_Exception import AsException # fin import à résorber @@ -35,8 +36,6 @@ from Noyau.N_Exception import AsException class MACRO_ETAPE(I_ETAPE.ETAPE): def __init__(self): - # XXX CCAR : ne suis pas certain que typret doive etre - # initialise à None (a verifier) self.typret=None def get_sdprods(self,nom_sd): @@ -44,73 +43,90 @@ class MACRO_ETAPE(I_ETAPE.ETAPE): Fonction : retourne le concept produit par l etape de nom nom_sd s il existe sinon None """ - if self.sd: - if self.sd.nom == nom_sd: - return self.sd + if self.sd and self.sd.nom == nom_sd :return self.sd for co in self.sdprods: - if co.nom==nom_sd:return co + if co.nom == nom_sd:return co + if type(self.definition.op_init) == types.FunctionType: + d={} + apply(self.definition.op_init,(self,d)) + return d.get(nom_sd,None) return None - def make_contexte(self,fichier,text): - """ - Cette méthode sert à créer un contexte en interprétant un texte source - Python - """ - # on récupère le contexte d'un nouveau jdc dans lequel on interprete text - contexte = self.get_contexte_jdc(fichier,text) - if contexte == None : - raise Exception("Impossible de relire le fichier") - else: - self.g_context = contexte - if hasattr(self,'contexte_fichier_init'): - self.old_contexte_fichier_init = self.contexte_fichier_init - self.contexte_fichier_init = contexte - # XXX la validité ne doit pas etre forcée à 1. Que faut-il faire exactement ??? - self.init_modif() - #self.valid = 1 - #self.state = 'unchanged' - def get_contexte_jdc(self,fichier,text): """ Interprète text comme un texte de jdc et retourne le contexte final cad le dictionnaire des sd disponibles à la dernière étape Si text n'est pas un texte de jdc valide, retourne None + ou leve une exception --> utilisée par ops.POURSUITE et INCLUDE """ try: - # on essaie de créer un objet JDC... + # on essaie de créer un objet JDC auxiliaire avec un contexte initial context_ini = self.parent.get_contexte_avant(self) + # Indispensable avant de creer un nouveau JDC CONTEXT.unset_current_step() - j=self.jdc.definition(procedure=text,cata=self.jdc.cata, - nom=fichier, - context_ini = context_ini, - appli=self.jdc.appli) + args=self.jdc.args + prefix_include=None + if hasattr(self,'prefix'): + prefix_include=self.prefix + + j=self.JdC_aux( procedure=text,cata=self.jdc.cata, + nom=fichier, + context_ini = context_ini, + appli=self.jdc.appli, + jdc_pere=self.jdc,etape_include=self, + prefix_include=prefix_include,**args) + j.analyse() - # XXX en passant par un jdc auxiliaire, on risque de rendre les etapes inactives - # on les force dans l'etat actif - for etape in j.etapes: - etape.active() except: traceback.print_exc() + # On force le contexte (etape courante) à self + CONTEXT.unset_current_step() + CONTEXT.set_current_step(self) return None - CONTEXT.set_current_step(self) + if not j.cr.estvide(): - raise Exception("Impossible de relire le fichier\n"+str(j.cr)) + # On force le contexte (etape courante) à self + CONTEXT.unset_current_step() + CONTEXT.set_current_step(self) + # Erreurs dans l'INCLUDE. On garde la memoire du fichier mais on n'insere pas les concepts + # et les etapes. Ce traitement doit etre fait par l'appelant qui recoit l'exception + raise Exception("Impossible de relire le fichier\n"+str(j.cr)) + + cr=j.report() + if not cr.estvide(): + # On force le contexte (etape courante) à self + CONTEXT.unset_current_step() + CONTEXT.set_current_step(self) + raise Exception("Le fichier include contient des erreurs\n"+str(j.cr)) + + # Cette verification n'est plus necessaire elle est integree dans le JDC_INCLUDE + #self.verif_contexte(j_context) - #XXX la validité d'un source inclus n'est pas identique à celle d'un JDC complet - # impossible de la tester en dehors du JDC d'accueil - #cr=j.report() - #if not cr.estvide(): - # raise Exception("Le fichier contient des erreurs\n"+str(j.cr)) + # On recupere le contexte apres la derniere etape j_context=j.get_contexte_avant(None) - # XXX j.g_context doit donner le meme résultat - # On retourne le contexte apres la derniere etape - # XXX j.supprime() ??? - self.verif_contexte(j_context) - # Le contexte est acceptable. On récupère les étapes internes (pour validation) + + # On remplit le dictionnaire des concepts produits inclus + # en retirant les concepts présents dans le contexte initial + self.g_context.clear() + for k,v in j_context.items(): + if not context_ini.has_key(k) or context_ini[k] != v: + self.g_context[k]=v + + # On récupère les étapes internes (pour validation) self.etapes=j.etapes + + # ainsi que le contexte courant + self.current_context=j.current_context + self.index_etape_courante=j.index_etape_courante + + # XXX j.supprime() ??? + # On force le contexte (etape courante) à self + CONTEXT.unset_current_step() + CONTEXT.set_current_step(self) + return j_context def verif_contexte(self,context): @@ -128,27 +144,71 @@ class MACRO_ETAPE(I_ETAPE.ETAPE): def reevalue_sd_jdc(self): """ Avec la liste des SD qui ont été supprimées, propage la - disparition de ces SD dans totues les étapes et descendants + disparition de ces SD dans toutes les étapes et descendants """ - l_sd = self.diff_contextes() - if len(l_sd) == 0 : return - for sd in l_sd: - self.jdc.delete_concept(sd) + l_sd_supp,l_sd_repl = self.diff_contextes() + for sd in l_sd_supp: + self.parent.delete_concept_after_etape(self,sd) + for old_sd,sd in l_sd_repl: + self.parent.replace_concept_after_etape(self,old_sd,sd) def diff_contextes(self): """ Réalise la différence entre les 2 contextes old_contexte_fichier_init et contexte_fichier_init - cad retourne la liste des sd qui ont disparu + cad retourne la liste des sd qui ont disparu ou ne derivent pas de la meme classe + et des sd qui ont ete remplacees """ - if not hasattr(self,'old_contexte_fichier_init'):return [] + if not hasattr(self,'old_contexte_fichier_init'):return [],[] l_sd_suppressed = [] + l_sd_replaced = [] for old_key in self.old_contexte_fichier_init.keys(): if not self.contexte_fichier_init.has_key(old_key): if isinstance(self.old_contexte_fichier_init[old_key],ASSD): l_sd_suppressed.append(self.old_contexte_fichier_init[old_key]) - return l_sd_suppressed + else: + if isinstance(self.old_contexte_fichier_init[old_key],ASSD): + # Un concept de meme nom existe + old_class=self.old_contexte_fichier_init[old_key].__class__ + if not isinstance(self.contexte_fichier_init[old_key],old_class): + # S'il n'est pas d'une classe derivee, on le supprime + l_sd_suppressed.append(self.old_contexte_fichier_init[old_key]) + else: + l_sd_replaced.append((self.old_contexte_fichier_init[old_key],self.contexte_fichier_init[old_key])) + return l_sd_suppressed,l_sd_replaced + def control_sdprods(self,d): + """ + Cette methode doit updater le contexte fournit par + l'appelant en argument (d) en fonction de sa definition + tout en verifiant que ses concepts produits ne sont pas + deja definis dans le contexte + """ + if type(self.definition.op_init) == types.FunctionType: + apply(self.definition.op_init,(self,d)) + if self.sd: + if d.has_key(self.sd.nom): + # Le concept est deja defini + if self.reuse and self.reuse is d[self.sd.nom]: + # Le concept est reutilise : situation normale + pass + else: + # Redefinition du concept, on l'annule + #XXX on pourrait simplement annuler son nom pour conserver les objets + # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??) + self.sd=self.reuse=self.sdnom=None + self.init_modif() + else: + # Le concept n'est pas defini, on peut updater d + d[self.sd.nom]=self.sd + # On verifie les concepts a droite du signe = + for co in self.sdprods: + if d.has_key(co.nom) and co is not d[co.nom] : + self.delete_concept(co) + else: + d[co.nom]=co + + def supprime_sdprods(self): """ Fonction: @@ -171,12 +231,12 @@ class MACRO_ETAPE(I_ETAPE.ETAPE): # Si la macro a des etapes et des concepts inclus, on les detruit for nom_sd,co in self.g_context.items(): if not isinstance(co,ASSD):continue - print "Delete: ",self.nom,co.nom self.parent.del_sdprod(co) self.parent.delete_concept(co) # On met g_context à blanc self.g_context={} +#ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro) def Build_sd(self,nom): """ Construit le concept produit de l'opérateur. Deux cas @@ -220,8 +280,10 @@ class MACRO_ETAPE(I_ETAPE.ETAPE): # 1. on annule la sd associée à self # 2. on la conserve mais il faut qu'elle soit correcte et la retourner # En plus il faut rendre coherents sdnom et sd.nom + # On choisit de retourner None et de mettre l'etape invalide self.sd=None self.sdnom=None + self.state="unchanged" self.valid=0 return self.sd #raise AsException("Etape ",self.nom,'ligne : ',self.appel[0], @@ -234,3 +296,175 @@ class MACRO_ETAPE(I_ETAPE.ETAPE): raise AsException("Etape ",self.nom,'ligne : ',self.appel[0], 'fichier : ',self.appel[1]+'\n', string.join(l)) + + def make_contexte_include(self,fichier,text): + """ + Cette méthode sert à créer un contexte en interprétant un texte source + Python + """ + # on récupère le contexte d'un nouveau jdc dans lequel on interprete text + contexte = self.get_contexte_jdc(fichier,text) + if contexte == None : + raise Exception("Impossible de construire le jeu de commandes correspondant au fichier") + else: + # Pour les macros de type include : INCLUDE, INCLUDE_MATERIAU et POURSUITE + # l'attribut g_context est un dictionnaire qui contient les concepts produits par inclusion + # l'attribut contexte_fichier_init est un dictionnaire qui contient les concepts produits + # en sortie de macro. g_context est obtenu en retirant de contexte_fichier_init les concepts + # existants en debut de macro contenus dans context_ini (dans get_contexte_jdc) + # g_context est utilisé pour avoir les concepts produits par la macro + # contexte_fichier_init est utilisé pour avoir les concepts supprimés par la macro + self.contexte_fichier_init = contexte + + def reevalue_fichier_init(self): + """Recalcule les concepts produits par le fichier enregistre""" + old_context=self.contexte_fichier_init + try: + self.make_contexte_include(self.fichier_ini ,self.fichier_text) + except: + l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1]) + self.fichier_err = string.join(l) + self.etapes=[] + self.g_context={} + + self.old_contexte_fichier_init=old_context + self.contexte_fichier_init={} + self.reevalue_sd_jdc() + return + + # L'evaluation s'est bien passee + self.fichier_err = None + self.old_contexte_fichier_init=old_context + self.reevalue_sd_jdc() + + def make_poursuite(self): + """ Cette methode est appelée par la fonction sd_prod de la macro POURSUITE + """ + if not hasattr(self,'fichier_ini') : + # Si le fichier n'est pas defini on le demande + f,text=self.get_file(fic_origine=self.parent.nom) + # On memorise le fichier retourne + self.fichier_ini = f + self.fichier_text = text + import Extensions.jdc_include + self.JdC_aux=Extensions.jdc_include.JdC_poursuite + self.contexte_fichier_init={} + if f is None: + self.fichier_err="Le fichier POURSUITE n'est pas defini" + else: + self.fichier_err=None + + if self.fichier_err is not None: raise Exception(self.fichier_err) + + try: + self.make_contexte_include(self.fichier_ini,self.fichier_text) + except: + l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1]) + if self.jdc.appli: + self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier poursuite", + message="Ce fichier ne sera pas pris en compte\n"+string.join(l) + ) + self.g_context={} + self.etapes=[] + self.fichier_err = string.join(l) + self.contexte_fichier_init={} + raise + + else: + # Si le fichier est deja defini on ne reevalue pas le fichier + # et on leve une exception si une erreur a été enregistrée + if self.fichier_err is not None: raise Exception(self.fichier_err) + + +#ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro) + def make_include(self,unite=None): + """ + Inclut un fichier dont l'unite logique est unite + Cette methode est appelee par la fonction sd_prod de la macro INCLUDE + Si l'INCLUDE est invalide, la methode doit produire une exception + Sinon on retourne None. Les concepts produits par l'INCLUDE sont + pris en compte par le JDC parent lors du calcul du contexte (appel de ???) + """ + + # On supprime l'attribut unite qui bloque l'evaluation du source de l'INCLUDE + # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini + del self.unite + # Si unite n'a pas de valeur, l'etape est forcement invalide. On peut retourner None + if not unite : return + + if not hasattr(self,'fichier_ini') : + # Si le fichier n'est pas defini on le demande + f,text=self.get_file(unite=unite,fic_origine=self.parent.nom) + # On memorise le fichier retourne + self.fichier_ini = f + self.fichier_text = text + self.contexte_fichier_init={} + if f is None: + self.fichier_err="Le fichier INCLUDE n est pas defini" + else: + self.fichier_err=None + import Extensions.jdc_include + self.JdC_aux=Extensions.jdc_include.JdC_include + + if self.fichier_err is not None: raise Exception(self.fichier_err) + + try: + self.make_contexte_include(self.fichier_ini ,self.fichier_text) + except: + l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1]) + if self.jdc.appli: + self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus", + message="Ce fichier ne sera pas pris en compte\n"+string.join(l) + ) + self.g_context={} + self.etapes=[] + self.fichier_err = string.join(l) + self.contexte_fichier_init={} + raise + + else: + # Si le fichier est deja defini on ne reevalue pas le fichier + # et on leve une exception si une erreur a été enregistrée + #self.reevalue_fichier_init() + if self.fichier_err is not None: raise Exception(self.fichier_err) + + +#ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro) + def make_contexte(self,fichier,text): + """ + Cette méthode sert à créer un contexte pour INCLUDE_MATERIAU + en interprétant un texte source Python + Elle est appelee par la fonction sd_prd d'INCLUDE_MATERIAU + """ + # On supprime l'attribut mat qui bloque l'evaluation du source de l'INCLUDE_MATERIAU + # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini + if hasattr(self,'mat'):del self.mat + self.fichier_ini =fichier + self.fichier_text=text + self.fichier_err=None + self.contexte_fichier_init={} + # On specifie la classe a utiliser pour le JDC auxiliaire + import Extensions.jdc_include + self.JdC_aux=Extensions.jdc_include.JdC_include + try: + self.make_contexte_include(self.fichier_ini ,self.fichier_text) + except: + l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1]) + self.g_context={} + self.etapes=[] + self.fichier_err = string.join(l) + self.contexte_fichier_init={} + raise + +#ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro) + def update_sdprod(self,cr='non'): + # Cette methode peut etre appelee dans EFICAS avec des mots cles de + # la commande modifies. Ceci peut conduire a la construction ou + # a la reconstruction d'etapes dans le cas d'INCLUDE ou d'INCLUDE_MATERIAU + # Il faut donc positionner le current_step avant l'appel + CONTEXT.unset_current_step() + CONTEXT.set_current_step(self) + valid=Validation.V_MACRO_ETAPE.MACRO_ETAPE.update_sdprod(self,cr=cr) + CONTEXT.unset_current_step() + return valid + diff --git a/Ihm/I_MCCOMPO.py b/Ihm/I_MCCOMPO.py index d7e828ff..fd773d94 100644 --- a/Ihm/I_MCCOMPO.py +++ b/Ihm/I_MCCOMPO.py @@ -309,6 +309,18 @@ class MCCOMPO(I_OBJECT.OBJECT): for child in self.mc_liste : child.delete_concept(sd) + def replace_concept(self,old_sd,sd): + """ + Inputs : + old_sd=concept remplace + sd = nouveau concept + Fonction : + Mettre a jour les fils de l objet suite au remplacement du + concept old_sd + """ + for child in self.mc_liste : + child.replace_concept(old_sd,sd) + def delete_mc_global(self,mc): """ Supprime le mot-clé mc de la liste des mots-clés globaux de l'étape diff --git a/Ihm/I_MCLIST.py b/Ihm/I_MCLIST.py index b9529e33..c201ed25 100644 --- a/Ihm/I_MCLIST.py +++ b/Ihm/I_MCLIST.py @@ -71,6 +71,18 @@ class MCList: for child in self.data : child.delete_concept(sd) + def replace_concept(self,old_sd,sd): + """ + Inputs : + old_sd=concept remplacé + sd=nouveau concept + Fonction : + Mettre a jour les fils de l objet suite au remplacement + du concept old_sd + """ + for child in self.data : + child.replace_concept(old_sd,sd) + def copy(self): """ Réalise la copie d'une MCList diff --git a/Ihm/I_MCSIMP.py b/Ihm/I_MCSIMP.py index ca1bafa3..cbe8d0c2 100644 --- a/Ihm/I_MCSIMP.py +++ b/Ihm/I_MCSIMP.py @@ -200,6 +200,7 @@ class MCSIMP(I_OBJECT.OBJECT): self.val = new_valeur self.valeur = valeur self.init_modif() + self.fin_modif() return 1 else: # On n'a pas trouve de concept ni réussi à évaluer la valeur @@ -214,27 +215,30 @@ class MCSIMP(I_OBJECT.OBJECT): except: traceback.print_exc() return 0 - self.val=self.valeur self.init_modif() + self.val=self.valeur + self.fin_modif() return 1 elif type(new_valeur)==types.StringType and self.wait_TXM(): + self.init_modif() self.val = new_valeur self.valeur = new_valeur - self.init_modif() + self.fin_modif() return 1 else: return 0 else : # on ne fait aucune vérification ... + self.init_modif() try: self.valeur = eval(new_valeur) self.val = eval(new_valeur) - self.init_modif() + self.fin_modif() return 1 except: self.valeur = new_valeur self.val = new_valeur - self.init_modif() + self.fin_modif() return 1 def eval_valeur(self,new_valeur): @@ -282,6 +286,32 @@ class MCSIMP(I_OBJECT.OBJECT): self.val=None self.init_modif() + def replace_concept(self,old_sd,sd): + """ + Inputs : + old_sd=concept remplacé + sd=nouveau concept + Fonction : + Met a jour la valeur du mot cle simple suite au remplacement + du concept old_sd + """ + if type(self.valeur) == types.TupleType : + if old_sd in self.valeur: + self.valeur=list(self.valeur) + i=self.valeur.index(old_sd) + self.valeur[i]=sd + self.init_modif() + elif type(self.valeur) == types.ListType: + if old_sd in self.valeur: + i=self.valeur.index(old_sd) + self.valeur[i]=sd + self.init_modif() + else: + if self.valeur == old_sd: + self.valeur=sd + self.val=sd + self.init_modif() + def copy(self): """ Retourne une copie de self """ objet = self.makeobjet() @@ -339,9 +369,10 @@ class MCSIMP(I_OBJECT.OBJECT): new_objet = CO(nom_co) CONTEXT.unset_current_step() CONTEXT.set_current_step(cs) + self.init_modif() self.valeur = new_objet self.val = new_objet - self.init_modif() + self.fin_modif() step.reset_context() # On force l'enregistrement de new_objet en tant que concept produit # de la macro en appelant get_type_produit avec force=1 @@ -371,13 +402,16 @@ class MCSIMP(I_OBJECT.OBJECT): else: l.append(sd) self.valeur=l + # Est ce init_modif ou init_modif_up + # Normalement init_modif va avec fin_modif self.init_modif() + self.fin_modif() else: if isinstance(self.valeur,ASSD) : if self.valeur not in l_sd_avant_etape : self.valeur = None self.init_modif() - + self.fin_modif() def get_min_max(self): """ @@ -392,6 +426,48 @@ class MCSIMP(I_OBJECT.OBJECT): """ return self.definition.type +#ATTENTION : toutes les methodes ci apres sont des surcharges du Noyau et de Validation +# Elles doivent etre reintegrees des que possible + + def isvalid(self,cr='non'): + """ + Cette méthode retourne un indicateur de validité de l'objet + de type MCSIMP + + - 0 si l'objet est invalide + + - 1 si l'objet est valide + + Le paramètre cr permet de paramétrer le traitement. + Si cr == 'oui' + la méthode construit également un comte-rendu de validation + dans self.cr qui doit avoir été créé préalablement. + """ + if self.state == 'unchanged': + return self.valid + else: + valid = 1 + if hasattr(self,'valid'): + old_valid = self.valid + else: + old_valid = None + v=self.valeur + # presence + if self.isoblig() and v == None : + if cr == 'oui' : + self.cr.fatal(string.join(("Mot-clé : ",self.nom," obligatoire non valorisé"))) + valid = 0 + # type,into ... + valid = self.verif_type(cr=cr)*self.verif_into(cr=cr)*self.verif_card(cr=cr) + self.valid = valid + self.state = 'unchanged' + # Si la validité du mot clé a changé, on le signale à l'objet parent + if not old_valid: + self.init_modif_up() + elif old_valid != self.valid : + self.init_modif_up() + return self.valid + diff --git a/Ihm/I_PROC_ETAPE.py b/Ihm/I_PROC_ETAPE.py index 81d6c810..b4ebb72d 100644 --- a/Ihm/I_PROC_ETAPE.py +++ b/Ihm/I_PROC_ETAPE.py @@ -21,7 +21,8 @@ import I_ETAPE # import rajoutés suite à l'ajout de Build_sd --> à résorber -import traceback,types +import sys +import traceback,types,string import Noyau from Noyau import N_Exception from Noyau.N_Exception import AsException @@ -52,6 +53,18 @@ class PROC_ETAPE(I_ETAPE.ETAPE): for child in self.mc_liste : child.delete_concept(sd) + def replace_concept(self,old_sd,sd): + """ + Inputs : + old_sd=concept remplacé + sd=nouveau concept + Fonction : + Mettre a jour les mots cles de l etape + suite au remplacement du concept old_sd + """ + for child in self.mc_liste : + child.replace_concept(old_sd,sd) + def Build_sd(self): """ Cette methode applique la fonction op_init au contexte du parent -- 2.39.2