Salome HOME
b043c48d6f86451f3851a5ea33dbff1e396e93aa
[tools/eficas.git] / Ihm / I_JDC.py
1 # -*- coding: utf-8 -*-
2 #            CONFIGURATION MANAGEMENT OF EDF VERSION
3 # ======================================================================
4 # COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
5 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
6 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
7 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
8 # (AT YOUR OPTION) ANY LATER VERSION.
9 #
10 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
11 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
12 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
13 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
14 #
15 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
16 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
17 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
18 #
19 #
20 # ======================================================================
21 """
22 """
23 # Modules Python
24 import types,traceback
25 import string,linecache
26
27 # Modules Eficas
28 import I_OBJECT
29 from Noyau.N_ASSD import ASSD
30 from Noyau.N_ETAPE import ETAPE
31 from Noyau.N_Exception import AsException
32 from Extensions import commentaire,parametre,parametre_eval
33 import CONNECTOR
34
35 class JDC(I_OBJECT.OBJECT):
36    """
37    """
38    def __init__(self):
39       self.editmode=0
40       self.etapes_niveaux=[]
41       self.niveau=self
42       self.params=[]
43       self.fonctions=[]
44       self._etape_context=None
45       self.recorded_units={}
46       self.old_recorded_units={}
47
48    def get_index(self,objet):
49       """
50         Retourne la position d'objet dans la liste self
51       """
52       return self.etapes.index(objet)
53
54    def get_sd_avant_du_bon_type(self,etape,types_permis):
55       """
56           Retourne la liste des concepts avant etape d'un type acceptable
57       """
58       d=self.get_contexte_avant(etape)
59       l=[]
60       for k,v in d.items():
61         if type(v) != types.InstanceType : continue
62         # On considère que seul assd indique un type quelconque pas CO
63         elif self.assd in types_permis :
64            l.append(k)
65         elif self.est_permis(v,types_permis):
66            l.append(k)
67       l.sort()
68       return l
69
70    def est_permis(self,v,types_permis):
71       for type_ok in types_permis:
72           if type_ok in ('R','I','C','TXM') and v in self.params : 
73              return 1
74           elif type_ok == 'R' and v.__class__.__name__ == 'reel' : 
75              return 1
76           elif type_ok == 'I' and v.__class__.__name__ == 'entier' : 
77              return 1
78           elif type_ok == 'C' and v.__class__.__name__ == 'complexe' : 
79              return 1
80           elif type_ok == 'TXM' and v.__class__.__name__ == 'chaine' : 
81              return 1
82           elif type(type_ok) != types.ClassType : 
83              continue
84           elif v.__class__ == type_ok or issubclass(v.__class__,type_ok):
85              return 1
86       return 0
87
88    def addentite(self,name,pos):
89       """
90           Ajoute une entite :
91           Si name est le nom d une commande ou un commentaire ajoute 
92           une etape au JDC
93           Sinon remonte une erreur
94       """
95       self.init_modif()
96       self.editmode=1
97       if name == "COMMENTAIRE" :
98         # ajout d'un commentaire
99         self.set_current_step()
100         ind = 1
101         for child in self.etapes :
102           if isinstance(child,commentaire.COMMENTAIRE):
103             ind = ind+1
104         objet = commentaire.COMMENTAIRE('',parent=self)
105         objet.nom = "_comm_"+`ind`
106         if pos == None : pos = 0
107         self.etapes.insert(pos,objet)
108         self.editmode=0
109         self.active_etapes()
110         CONNECTOR.Emit(self,"add",objet)
111         self.fin_modif()
112         return objet
113       elif name == "PARAMETRE":
114         # ajout d'un parametre
115         self.set_current_step()
116         nom_param = '_param_'+str(len(self.params)+1)
117         objet = parametre.PARAMETRE(nom=nom_param)
118         if pos == None : pos = 0
119         self.etapes.insert(pos,objet)
120         self.editmode=0
121         self.reset_context()
122         self.active_etapes()
123         CONNECTOR.Emit(self,"add",objet)
124         self.fin_modif()
125         return objet
126       elif name == "PARAMETRE_EVAL":
127         # ajout d'un parametre EVAL
128         self.set_current_step()
129         nom_param = '_param_'+str(len(self.params)+1)
130         objet = parametre_eval.PARAMETRE_EVAL(nom=nom_param)
131         if pos == None : pos = 0
132         self.etapes.insert(pos,objet)
133         self.editmode=0
134         self.reset_context()
135         self.active_etapes()
136         CONNECTOR.Emit(self,"add",objet)
137         self.fin_modif()
138         return objet
139       elif type(name)==types.InstanceType:
140         # on est dans le cas où on veut ajouter une commande déjà 
141         # existante (par copie donc)
142         # on est donc nécessairement en mode editeur ...
143         objet = name
144         # Il ne faut pas oublier de reaffecter le parent d'obj (si copie)
145         #if hasattr(objet,'sd'):print "addentite",objet.sd
146         objet.reparent(self)
147         #if hasattr(objet,'sd'):print "addentite",objet.sd
148         self.set_current_step()
149         if isinstance(objet,ETAPE):
150           if objet.nom_niveau_definition == 'JDC':
151             # l'objet dépend directement du JDC
152             objet.niveau = self
153           else:
154             # l'étape dépend d'un niveau et non directement du JDC :
155             # il faut l'enregistrer dans le niveau de parent
156             objet.parent.dict_niveaux[objet.nom_niveau_definition].register(objet)
157             objet.niveau = objet.parent.dict_niveaux[objet.nom_niveau_definition]
158         self.etapes.insert(pos,objet)
159         # il faut vérifier que les concepts utilisés par objet existent bien
160         # à ce niveau d'arborescence
161         #if hasattr(objet,'sd'):print "addentite",objet.sd
162         objet.verif_existence_sd()
163         self.active_etapes()
164         self.editmode=0
165         self.reset_context()
166         #print "addentite",self.etapes
167         CONNECTOR.Emit(self,"add",objet)
168         self.fin_modif()
169         return objet
170       else :
171         # On veut ajouter une nouvelle commande
172         try:
173           self.set_current_step()
174           cmd=self.get_cmd(name)
175           # L'appel a make_objet n'a pas pour effet d'enregistrer l'étape
176           # auprès du step courant car editmode vaut 1
177           # Par contre elle a le bon parent grace a set_current_step
178           e=cmd.make_objet()
179           if pos == None : pos = 0
180           self.etapes.insert(pos,e)
181           self.reset_current_step()
182           self.editmode=0
183           self.reset_context()
184           self.active_etapes()
185           #print "addentite",self.etapes
186           CONNECTOR.Emit(self,"add",e)
187           self.fin_modif()
188           return e
189         except AsException,e:
190           self.reset_current_step()
191           self.editmode=0
192           raise AsException("Impossible d ajouter la commande "+name + '\n' +str(e))
193         except:
194           traceback.print_exc()
195           self.reset_current_step()
196           self.editmode=0
197           raise AsException("Impossible d ajouter la commande "+name)
198
199    def close(self):
200       #print "JDC.close",self
201       for etape in self.etapes:
202           if hasattr(etape,"close"):etape.close()
203       CONNECTOR.Emit(self,"close")
204
205    def set_current_step(self):
206       CONTEXT.unset_current_step()
207       CONTEXT.set_current_step(self)
208
209    def reset_current_step(self):
210       CONTEXT.unset_current_step()
211
212    def liste_mc_presents(self):
213       return []
214
215    def get_sd_avant_etape(self,nom_sd,etape):
216       return self.get_contexte_avant(etape).get(nom_sd,None)
217
218    def get_sd_apres_etape_avec_detruire(self,nom_sd,sd,etape,avec='non'):
219       """ 
220            Cette méthode retourne la SD sd de nom nom_sd qui est éventuellement
221            définie apres etape en tenant compte des concepts detruits
222            Si avec vaut 'non' exclut etape de la recherche
223       """
224       #print "JDC.get_sd_apres_etape_avec_detruire",nom_sd,sd
225       ietap=self.etapes.index(etape)
226       if avec == 'non':ietap=ietap+1
227       d={nom_sd:sd}
228       for e in self.etapes[ietap:]:
229          if e.isactif():
230             e.update_context(d)
231             autre_sd=d.get(nom_sd,None)
232             if autre_sd is None:
233               # Le concept a ete detruit. On interrompt la recherche car il n'y a
234               # pas eu de redefinition du concept (il n'y a pas de conflit potentiel).
235               return None
236             if autre_sd is not sd :
237               # L'etape produit un concept different de meme nom. La situation n'est
238               # pas saine (sauf peut etre si reuse ???)
239               if hasattr(e,'reuse') and e.reuse == autre_sd:
240                  # Le concept etant reutilise, on interrompt la recherche. 
241                  # On considere qu'il n'y a pas de nouveau concept defini
242                  # meme si dans les etapes suivantes le concept est detruit
243                  # et un concept de meme nom créé.
244                  # AVERIFIER : avec reuse le concept devrait etre le meme
245                  # le passage par ici est tres improbable
246                  return None
247               else:
248                  # Le concept est produit par l'etape (Il y a conflit potentiel).
249                  # Le concept est redefini par une etape posterieure.
250                  return autre_sd
251       # Pas de destruction du concept ni de redefinition. On retourne le
252       # concept initial
253       return sd
254
255    def get_sd_apres_etape(self,nom_sd,etape,avec='non'):
256       """ 
257            Cette méthode retourne la SD de nom nom_sd qui est éventuellement
258            définie apres etape 
259            Si avec vaut 'non' exclut etape de la recherche
260       """
261       ietap=self.etapes.index(etape)
262       if avec == 'non':ietap=ietap+1
263       for e in self.etapes[ietap:]:
264         sd=e.get_sdprods(nom_sd)
265         if sd:
266           if hasattr(e,'reuse'):
267             if e.reuse != sd:
268               return sd
269       return None
270
271    def get_sd_autour_etape(self,nom_sd,etape,avec='non'):
272       """
273            Fonction: retourne la SD de nom nom_sd qui est éventuellement
274            définie avant ou apres etape
275            Permet de vérifier si un concept de meme nom existe dans le périmètre 
276            d'une étape
277            Si avec vaut 'non' exclut etape de la recherche
278       """
279       sd=self.get_sd_avant_etape(nom_sd,etape)
280       if sd:return sd
281       return self.get_sd_apres_etape(nom_sd,etape,avec)
282
283    def get_contexte_apres(self,etape):
284       """
285          Retourne le dictionnaire des concepts connus apres etape
286          On tient compte des commandes qui modifient le contexte
287          comme DETRUIRE ou les macros
288          Si etape == None, on retourne le contexte en fin de JDC
289       """
290       if not etape: return self.get_contexte_avant(etape)
291
292       d=self.get_contexte_avant(etape)
293       if etape.isactif():etape.update_context(d)
294       self.index_etape_courante=self.index_etape_courante+1
295       return d
296
297    def active_etapes(self):
298       """
299           Cette méthode a pour fonction de désactiver les étapes qui doivent
300           l'être cad, dans le cas d'ASTER, les étapes qui ne sont pas 
301           comprises entre le premier DEBUT/POURSUITE et le premier FIN 
302           et rendre actives les autres
303       """
304       if self.definition.code == 'ASTER' :
305          # Seulement pour ASTER :
306          # Avant DEBUT actif vaut 0
307          # Apres DEBUT et avant le 1er FIN actif vaut 1
308          # Apres le 1er FIN actif vaut -1
309          actif=0
310       else:
311          actif=1
312       for etape in self.etapes:
313         if actif == 0 and etape.nom in ['DEBUT','POURSUITE']:actif=1
314         if actif == 1:
315            etape.active()
316         else:
317            etape.inactive()
318         if etape.nom == 'FIN':actif=-1
319
320    def suppentite(self,etape) :
321       """  
322           Cette methode a pour fonction de supprimer une étape dans 
323           un jeu de commandes
324           Retourne 1 si la suppression a pu être effectuée,
325           Retourne 0 dans le cas contraire
326       """
327       #print "suppentite",self
328       self.init_modif()
329       # On memorise le contexte avant l'etape a supprimer
330       d=self.get_contexte_avant(etape)
331       index_etape=self.etapes.index(etape)
332       #print "suppentite",index_etape,d
333
334       self.etapes.remove(etape)
335       if etape.niveau is not self:
336         # Dans ce cas l'étape est enregistrée dans un niveau
337         # Il faut la désenregistrer
338         etape.niveau.unregister(etape)
339       etape.supprime_sdprods()
340       etape.close()
341       self.active_etapes()
342
343       # Apres suppression de l'etape il faut controler que les etapes
344       # suivantes ne produisent pas des concepts DETRUITS dans op_init de etape
345       for e in self.etapes[index_etape:]:
346          e.control_sdprods(d)
347       
348       self.reset_context()
349       CONNECTOR.Emit(self,"supp",etape)
350       self.fin_modif()
351       return 1
352
353    def analyse(self):
354       self.compile()
355       if not self.cr.estvide():return
356       self.exec_compile()
357       self.active_etapes()
358
359    def register_parametre(self,param):
360       """
361           Cette méthode sert à ajouter un paramètre dans la liste des paramètres
362       """
363       self.params.append(param)
364
365    def register_fonction(self,fonction):
366       """
367           Cette méthode sert à ajouter une fonction dans la liste des fonctions
368       """
369       self.fonctions.append(fonction)
370
371    def delete_param(self,param):
372       """
373           Supprime le paramètre param de la liste des paramètres
374           et du contexte gobal
375       """
376       if param in self.params : self.params.remove(param)
377       if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
378
379    def get_parametres_fonctions_avant_etape(self,etape):
380       """
381           Retourne deux éléments :
382           - une liste contenant les noms des paramètres (constantes ou EVAL) 
383             définis avant etape
384           - une liste contenant les formules définies avant etape
385       """
386       l_constantes = []
387       l_fonctions = []
388       # on récupère le contexte avant etape
389       # on ne peut mettre dans les deux listes que des éléments de ce contexte
390       d=self.get_contexte_avant(etape)
391       # construction de l_constantes
392       for param in self.params:
393         nom = param.nom
394         if not nom : continue
395         if d.has_key(nom): l_constantes.append(nom)
396       # construction de l_fonctions
397       for form in self.fonctions:
398         nom = form.nom
399         if not nom : continue
400         if d.has_key(nom): l_fonctions.append(form.get_formule())
401
402       # on ajoute les concepts produits par DEFI_VALEUR
403       # XXX On pourrait peut etre faire plutot le test sur le type
404       # de concept : entier, reel, complexe, etc.
405       for k,v in d.items():
406          if hasattr(v,'etape') and v.etape.nom in ('DEFI_VALEUR',):
407             l_constantes.append(k)
408
409       # on retourne les deux listes
410       return l_constantes,l_fonctions
411
412    def get_nb_etapes_avant(self,niveau):
413       """ 
414           Retourne le nombre d etapes avant le debut de niveau
415       """
416       nb=0
417       for niv in self.etapes_niveaux:
418         if niv == niveau:break
419         nb=nb+len(niv.etapes)
420       return nb
421
422    def send_message(self,message):
423       if self.appli:
424          self.appli.send_message(message)
425
426    def init_modif(self):
427       """
428       Méthode appelée au moment où une modification va être faite afin de 
429       déclencher d'éventuels traitements pré-modification
430       """
431       #print "init_modif",self
432       self.state = 'modified'
433
434    def fin_modif(self):
435       #print "fin_modif",self
436       CONNECTOR.Emit(self,"valid")
437       self.isvalid()
438       pass
439
440    def deep_update_condition_bloc(self):
441       # pour le moment, on ne fait rien
442       raise "Not implemented"
443
444    def update_condition_bloc(self):
445       # pour le moment, on ne fait rien
446       raise "Not implemented"
447
448    def get_liste_mc_inconnus(self):
449      """
450      Retourne une liste contenant les mots-clés inconnus à la relecture du JDC
451      """
452      # cette liste a le format suivant : [etape,(bloc,mcfact,...),nom_mc,valeur_mc]
453      l_mc = []
454      for etape in self.etapes :
455          if etape.isactif() :
456             if not etape.isvalid() :
457                l = etape.get_liste_mc_inconnus()
458                if l : l_mc.extend(l)
459      return l_mc    
460
461    def get_genealogie(self):
462       """
463           Retourne la liste des noms des ascendants de l'objet self
464           jusqu'à la première ETAPE parent.
465       """
466       return []
467
468    def get_liste_cmd(self):
469       """
470           Retourne la liste des commandes du catalogue
471       """
472       return self.niveau.definition.get_liste_cmd()
473
474    def get_groups(self):
475       """
476           Retourne la liste des groupes
477       """
478       return self.niveau.definition.liste_groupes,self.niveau.definition.dict_groupes
479
480    def set_etape_context(self,etape):
481       """
482           Positionne l'etape qui sera utilisee dans NommerSdProd pour
483           decider si le concept passé pourra etre  nommé
484       """
485       self._etape_context=etape
486
487    def reset_context(self):
488       """ 
489           Cette methode reinitialise le contexte glissant pour pouvoir
490           tenir compte des modifications de l'utilisateur : création
491           de commandes, nommage de concepts, etc.
492       """
493       self.current_context={}
494       self.index_etape_courante=0
495       for etape in self.etapes:
496           etape.reset_context()
497
498    def del_sdprod(self,sd):
499       """
500           Supprime la SD sd de la liste des sd et des dictionnaires de contexte
501       """
502       #print "del_sdprod",self,sd
503       #print "del_sdprod",self.sds
504       #print "del_sdprod",self.g_context
505       #print "del_sdprod",self.sds_dict
506       if sd in self.sds : self.sds.remove(sd)
507       if self.g_context.has_key(sd.nom) : del self.g_context[sd.nom]
508       if self.sds_dict.has_key(sd.nom) : del self.sds_dict[sd.nom]
509
510    def del_param(self,param):
511       """
512           Supprime le paramètre param de la liste des paramètres
513           et du contexte gobal
514       """
515       if param in self.params : self.params.remove(param)
516       if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
517
518    def del_fonction(self,fonction):
519       """
520           Supprime la fonction fonction de la liste des fonctions
521           et du contexte gobal
522       """
523       if fonction in self.fonctions : self.fonctions.remove(fonction)
524       if self.g_context.has_key(fonction.nom) : del self.g_context[fonction.nom]
525
526    def append_sdprod(self,sd):
527       """
528           Ajoute la SD sd à la liste des sd en vérifiant au préalable qu'une SD de
529           même nom n'existe pas déjà
530       """
531       if sd == None or sd.nom == None:return
532
533       o=self.sds_dict.get(sd.nom,None)
534       if isinstance(o,ASSD):
535          raise AsException("Nom de concept deja defini : %s" % sd.nom)
536       self.sds_dict[sd.nom]=sd
537       self.g_context[sd.nom] = sd
538       if sd not in self.sds : self.sds.append(sd)
539
540    def append_param(self,param):
541       """
542           Ajoute le paramètre param à la liste des params
543           et au contexte global
544       """
545       # il faudrait vérifier qu'un paramètre de même nom n'existe pas déjà !!!
546       if param not in self.params : self.params.append(param)
547       self.g_context[param.nom]=param
548
549    def append_fonction(self,fonction):
550       """
551           Ajoute la fonction fonction à la liste des fonctions
552           et au contexte global
553       """
554       # il faudrait vérifier qu'une fonction de même nom n'existe pas déjà !!!
555       if fonction not in self.fonctions : self.fonctions.append(fonction)
556       self.g_context[fonction.nom]=fonction
557
558    def delete_concept(self,sd):
559       """
560           Inputs :
561              - sd=concept detruit
562           Fonction :
563           Mettre a jour les etapes du JDC suite à la disparition du
564           concept sd
565           Seuls les mots cles simples MCSIMP font un traitement autre
566           que de transmettre aux fils
567       """
568       #print "delete_concept",self,sd
569       for etape in self.etapes :
570         etape.delete_concept(sd)
571
572    def replace_concept_after_etape(self,etape,old_sd,sd):
573       """
574           Met à jour les étapes du JDC qui sont après etape en fonction
575           du remplacement du concept sd
576       """
577       index = self.etapes.index(etape)+1
578       if index == len(self.etapes) :
579          return # etape est la dernière étape du jdc ...on ne fait rien !
580       for child in self.etapes[index:]:
581         child.replace_concept(old_sd,sd)
582
583    def dump_state(self):
584       print "dump_state"
585       print "JDC.state: ",self.state
586       for etape in self.etapes :
587          print etape.nom+".state: ",etape.state
588       
589    def change_unit(self,unit,etape,old_unit):
590       #print "change_unit",unit,etape,old_unit
591       #print id(self.recorded_units),self.recorded_units
592       #if self.recorded_units.has_key(old_unit):del self.recorded_units[old_unit]
593       self.record_unit(unit,etape)
594
595    def record_unit(self,unit,etape):
596       """Enregistre les unites logiques incluses et les infos relatives a l'etape"""
597       #print "record_unit",unit,etape
598       if unit is None:
599          # Cas de POURSUITE
600          self.recorded_units[None]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
601       else:
602          self.recorded_units[unit]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
603       #print id(self.recorded_units),self.recorded_units
604       #print self.recorded_units.get(None,(None,"",{}))[2]
605       #print self.recorded_units.get(None,(None,"",{}))[2].get(None,(None,"",{}))
606
607 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
608    def register(self,etape):
609       """
610            Cette méthode ajoute  etape dans la liste
611            des etapes self.etapes et retourne l identificateur d'étape
612            fourni par l appel a g_register
613
614            A quoi sert editmode ?
615               - Si editmode vaut 1, on est en mode edition de JDC. On cherche
616                 à enregistrer une étape que l'on a créée avec eficas (en passant
617                 par addentite) auquel cas on ne veut récupérer que son numéro
618                 d'enregistrement et c'est addentité qui l'enregistre dans
619                 self.etapes à la bonne place...
620               - Si editmode vaut 0, on est en mode relecture d'un fichier de
621                 commandes et on doit enregistrer l'étape à la fin de self.etapes
622                 (dans ce cas l'ordre des étapes est bien l'ordre chronologique
623                 de leur création   )
624       """
625       if not self.editmode:
626          self.etapes.append(etape)
627       else:
628          pass
629       return self.g_register(etape)
630
631 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
632    def NommerSdprod(self,sd,sdnom,restrict='non'):
633       """
634           Nomme la SD apres avoir verifie que le nommage est possible :
635           nom non utilise
636           Si le nom est deja utilise, leve une exception
637           Met le concept créé dans le concept global g_context
638       """
639       # XXX En mode editeur dans EFICAS, le nommage doit etre géré différemment
640       # Le dictionnaire g_context ne représente pas le contexte
641       # effectif avant une étape.
642       # Il faut utiliser get_contexte_avant avec indication de l'étape
643       # traitée.
644       # Cette etape est indiquee par l'attribut _etape_context qui a ete
645       # positionné préalablement par un appel à set_etape_context
646
647       if CONTEXT.debug : print "JDC.NommerSdprod ",sd,sdnom
648
649       if self._etape_context:
650          o=self.get_contexte_avant(self._etape_context).get(sdnom,None)
651       else:
652          o=self.sds_dict.get(sdnom,None)
653
654       if isinstance(o,ASSD):
655          raise AsException("Nom de concept deja defini : %s" % sdnom)
656
657       # ATTENTION : Il ne faut pas ajouter sd dans sds car il s y trouve deja.
658       # Ajoute a la creation (appel de reg_sd).
659       self.sds_dict[sdnom]=sd
660       sd.nom=sdnom
661
662       # En plus si restrict vaut 'non', on insere le concept dans le contexte du JDC
663       if restrict == 'non':
664          self.g_context[sdnom]=sd
665
666 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
667    def delete_concept_after_etape(self,etape,sd):
668       """
669           Met à jour les étapes du JDC qui sont après etape en fonction
670           de la disparition du concept sd
671       """
672       index = self.etapes.index(etape)+1
673       if index == len(self.etapes) :
674          return # etape est la dernière étape du jdc ...on ne fait rien !
675       for child in self.etapes[index:]:
676         child.delete_concept(sd)
677
678 #ATTENTION SURCHARGE : les methodes ci-dessous surchargent des methodes de Noyau et Validation : a reintegrer
679