Salome HOME
test simple
[tools/eficas.git] / Editeur / treewidget.py
1 #            CONFIGURATION MANAGEMENT OF EDF VERSION
2 # ======================================================================
3 # COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
4 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
5 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
6 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
7 # (AT YOUR OPTION) ANY LATER VERSION.
8 #
9 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
10 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
11 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
12 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
13 #
14 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
15 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
16 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
17 #
18 #
19 # ======================================================================
20 import os,sys,string,re,types,traceback
21 from Tkinter import *
22
23
24 import fontes
25 import images
26
27 #
28 __version__="$Name:  $"
29 __Id__="$Id: treewidget.py,v 1.9 2002/11/06 17:25:57 eficas Exp $"
30 #
31
32 Fonte_Standard = fontes.standard
33
34 class Tree :
35     def __init__(self,appli,jdc_item,scrolledcanvas,command = None,rmenu=None):
36         self.item = jdc_item
37         self.scrolledcanvas = scrolledcanvas
38         self.canvas = self.scrolledcanvas.component('canvas')
39         self.canvas.bind("<Key-Prior>", self.page_up)
40         self.canvas.bind("<Key-Next>", self.page_down)
41         self.canvas.bind("<Key-Up>", self.unit_up)
42         self.canvas.bind("<Key-Down>", self.unit_down)             
43         self.canvas.bind("<1>", self.canvas_select)             
44         self.tree = self
45         self.command = command
46         self.rmenu=rmenu
47         self.appli = appli
48         self.parent = None
49         self.racine = self
50         self.node_selected = None
51         self.build_children()
52
53     def canvas_select(self,event):
54         self.canvas.focus_set()
55
56     def page_up(self,event):
57         event.widget.yview_scroll(-1, "page")
58     def page_down(self,event):
59         event.widget.yview_scroll(1, "page")
60     def unit_up(self,event):
61         event.widget.yview_scroll(-1, "unit")
62     def unit_down(self,event):
63         event.widget.yview_scroll(1, "unit")              
64
65     def build_children(self):
66         """ Construit la liste des enfants de self """
67         self.children = []
68         child = Node(self,self.item,self.command,self.rmenu)
69         self.children.append(child)
70         child.state='expanded'
71
72     def draw(self):
73         """ Dessine l'arbre """
74         lasty = 8
75         x = 5
76         for child in self.children:
77             child.draw(x,lasty)
78             lasty = child.lasty + 15
79         self.children[0].select()
80         self.resizescrollregion()
81
82     def deselectall(self):
83         """ déselectionne tous les éléments de l'arbre """
84         if self.node_selected :
85             self.node_selected.deselect()
86             
87     def update(self):
88         """ Update tous les éléments de l'arbre """
89         for child in self.children:
90             child.update()
91
92     def resizescrollregion(self):
93         x0,y0,x1,y1=self.canvas.bbox(ALL)
94         y1=y1+(self.canvas.winfo_height()/20-1)*20
95         self.canvas.configure(scrollregion = (x0,y0,x1,y1))
96         #self.scrolledcanvas.resizescrollregion()
97
98     def select_next(self,event):
99         self.node_selected.select_next()
100
101     def select_previous(self,event):
102         self.node_selected.select_previous()
103
104     def full_creation(self,name,index):
105         # A changer lorsqu'il y aura plusieurs jdc ouverts en même temps
106         self.children[0].full_creation(name,index)
107
108     def verif_all(self):
109         for child in self.children :
110             self.verif_all_children()
111
112     def see(self,items):
113         x1, y1, x2, y2=apply(self.canvas.bbox, items)
114         while x2 > self.canvas.canvasx(0)+self.canvas.winfo_width():
115             old=self.canvas.canvasx(0)
116             self.canvas.xview_scroll( 1, 'units')
117             # avoid endless loop if we can't scroll
118             if old == self.canvas.canvasx(0):
119                 break
120         while y2 > self.canvas.canvasy(0)+self.canvas.winfo_height():
121             old=self.canvas.canvasy(0)
122             self.canvas.yview_scroll( 1, 'units')
123             if old == self.canvas.canvasy(0):
124                 break
125         # done in this order to ensure upper-left of object is visible
126         while x1 < self.canvas.canvasx(0):
127             old=self.canvas.canvasx(0)
128             self.canvas.xview_scroll( -1, 'units')
129             if old == self.canvas.canvasx(0):
130                 break
131         while y1 < self.canvas.canvasy(0):
132             old=self.canvas.canvasy(0)
133             self.canvas.yview_scroll( -1, 'units')
134             if old == self.canvas.canvasy(0):
135                 break
136             
137 class Node :
138     def __init__(self,parent,item,command=None,rmenu=None):
139         self.parent = parent
140         self.item = item
141         self.command = command
142         self.rmenu=rmenu
143         self.tree = self.parent.tree
144         self.appli = self.parent.appli
145         self.canvas = self.parent.canvas
146         self.init()
147
148     def init(self):
149         self.state='collapsed'
150         self.displayed = 0
151         self.selected = 0
152         self.x = self.y  =None
153         self.lasty = 0
154         self.children = None
155         self.id = []
156         # etape = noeud d'étape auquel appartient self
157         # = self si c'est lui-même
158         if isinstance(self.parent,Tree) :
159             # on est  sur un noeud de JDC
160             self.racine=self
161             self.etape=None
162             self.nature='JDC'
163         elif isinstance(self.parent.parent,Tree) :
164             # on est sur un noeud d'étape
165             self.racine = self.parent
166             self.etape=self
167             self.nature = 'ETAPE'
168         else :
169             # on est sur un noeud de mot-clé
170             self.racine = self.parent.racine
171             self.etape=self.parent.etape
172             self.nature = 'MOTCLE'
173
174     def build_children(self):
175         """ Construit la liste des enfants de self """
176         self.children = []
177         sublist = self.item._GetSubList()
178         if not sublist : return
179         for item in sublist :
180             child = Node(self,item,self.command,self.rmenu)
181             self.children.append(child)
182             
183     #-----------------------------------------------
184     # Méthodes de sélection/déselection d'un noeud
185     #-----------------------------------------------
186     
187     def select(self, event=None):
188         """
189         Rend le noeud courant (self) sélectionné et déselectionne
190         tous les autres
191         """
192         if not self.children : self.build_children()
193         self.tree.deselectall()
194         self.selected = 1
195         self.tree.node_selected = self
196         if self.command:apply(self.command,(self,))
197         self.highlight()
198         self.make_visible()
199
200     def deselect(self, event=None):
201         """ Déselectionne self """
202         self.selected = 0
203         if self.displayed == 1 : self.dehighlight()
204             
205     def make_visible(self):
206         """ Rend l'objet self visible cad déplace le scroll pour que self soit dans
207             la fenêtre de visu
208         """
209         lchild=self.last_child()
210         self.tree.see((self.image_id,lchild.image_id))
211         
212     def select_next(self,ind=0):
213         """ on doit chercher à sélectionner dans l'ordre:
214                 - son premier fils s'il est affiché
215                 - son frère cadet s'il existe
216                 - son oncle (benjamin de son père)
217                 - ... appel récursif ...
218         """
219         if self.state=='expanded' and len(self.children) > ind:
220             self.children[ind].select()
221         else :
222             index = self.parent.children.index(self) + 1
223             if isinstance(self.parent,TREE) :
224                 try:
225                     self.children[ind].select()
226                 except:
227                     self.children[0].select()
228             else :                
229                 self.parent.select_next(index)
230
231     def select_previous(self):
232         """ on doit d'abord sélectionner(dans l'ordre) :
233              - son frère aîné
234              - son père
235         """
236         index = self.parent.children.index(self) + 1
237         try :
238             self.parent.children[index].select()
239         except:
240             self.parent.select()
241
242     def popup(self,event=None):
243         """
244             Declenche le traitement associé au clic droit de la souris
245             sur l'icone du Node
246         """
247         if not self.rmenu:return
248         apply(self.rmenu,(self,event))
249
250     #-----------------------------------------------
251     # Méthodes de recherche d'informations
252     #-----------------------------------------------
253     def geticonimage(self,name=None):
254         """
255         Retourne l'image qui doit être associée à self
256         """
257         if not name :
258             name = self.item.GetIconName()
259         if not name or name == 'aucune' :
260             return None
261         return images.get_image(name)
262
263     def get_nb_children(self):
264         """ Retourne le nombre d'enfants affichés de self """
265         nb = 0
266         if self.state =='collapsed' :  return nb
267         for child in self.children :
268             nb = nb + 1 + child.get_nb_children()
269         return nb
270
271     def get_liste_id(self):
272         """ Retourne la liste de tous les id (filiation comprise) de self """
273         liste = self.id
274         for child in self.children:
275             liste.extend(child.get_liste_id())
276         return liste
277
278     def get_node_fils(self,name) :
279         """ Retourne le fils de self de nom name s'il existe"""
280         for child in self.children:
281             if child.item.get_nom() == name: return child
282         return None
283     #-----------------------------------------------
284     # Méthodes d'affichage d'un noeud
285     #-----------------------------------------------
286     def draw(self,x,y):
287         """ Permet de tracer le noeud self """
288         # le début du noeud est en x,y
289         self.x = x
290         self.y = y
291         self.lasty = y
292         self.displayed = 1
293         self.id=[]
294         # choix de l'icone à afficher : + ou -
295         if self.item.IsExpandable():
296             if self.state == 'expanded':
297                 iconname = "minusnode"
298                 callback = self.collapse
299             else:
300                 iconname = "plusnode"
301                 callback = self.expand
302             image = self.geticonimage(name=iconname)
303             self.icone_id = self.canvas.create_image(self.x, self.y, image=image)
304             self.canvas.tag_bind(self.icone_id, "<1>", callback)
305             self.id.append(self.icone_id)
306         # création de la ligne horizontale
307         self.ligne_id = self.canvas.create_line(self.x,self.y,self.x+10,self.y)
308         self.id.append(self.ligne_id)
309         self.canvas.tag_lower(self.ligne_id)
310         # affichage de l'icone (carre ,rond, ovale ...) de couleur
311         image = self.geticonimage()
312         if image != None :
313             self.image_id = self.canvas.create_image(self.x+15,self.y,image = image)
314             self.canvas.tag_bind(self.image_id,"<1>",self.select)
315             self.canvas.tag_bind(self.image_id,"<3>",self.popup)
316             self.id.append(self.image_id)
317         else:
318             self.image_id = None
319         # affichage du texte : nom de l'objet (ETAPE ou MOT-CLE) et sa valeur
320         self.drawtext()
321         if self.state == 'expanded' :
322             if not self.children : self.build_children()
323             if len(self.children) > 0:
324                 self.drawchildren()
325                 self.lasty = self.children[-1].lasty
326    
327     def drawchildren(self):
328         """ Dessine les enfants de self """
329         y = self.y + 20
330         x = self.x + 15
331         for child in self.children:
332             child.draw(x,y)
333             nb = child.get_nb_children()
334             y = y + 20*(nb+1)
335         self.trace_ligne()
336
337     def drawtext(self):
338         """ Affiche les deux zones de texte après l'icône de couleur de l'objet """
339         if self.image_id != None :
340             textx = self.x + 30
341         else:
342             textx = self.x + 15
343         texty = self.y
344         # nom,fonte et couleur de l'objet du noeud à afficher
345         labeltext,fonte,couleur = self.item.GetLabelText()
346         if labeltext    == ''   : labeltext = '   '
347         if fonte        == None : fonte = Fonte_Standard
348         if couleur      == None : couleur = 'black'
349         # création du widget label
350         self.label = Label(self.canvas,
351                            text = labeltext,
352                            fg = couleur,
353                            bg = 'gray95',
354                            font=fonte)
355         self.label_id = self.canvas.create_window(textx,texty,window=self.label,anchor='w')
356         self.id.append(self.label_id)
357         # bindings sur le widget label
358         self.label.bind("<1>", self.select)
359         self.label.bind("<3>", self.popup)
360         self.label.bind("<Enter>",self.enter)
361         self.label.bind("<Leave>",self.leave)
362         # valeur de cet objet à afficher
363         x0, y0, x1, y1 = self.canvas.bbox(self.label_id)
364         textx = max(x1, 200) + 10
365         text = self.item.GetText() or " "
366         self.text = Label(self.canvas, text=text,
367                             bd=0, padx=2, pady=2,background='gray95',
368                             font=fonte)
369         if self.selected:
370             self.highlight()
371         else:
372             self.dehighlight()
373         self.text_id = self.canvas.create_window(textx, texty,anchor="w", window=self.text)
374         self.id.append(self.text_id)
375         
376     def highlight(self,event=None):
377         """ Met en surbrillance self"""
378         if hasattr(self,'label'):
379             self.label.configure(fg='white',bg='#00008b')
380             
381     def dehighlight(self,event=None):
382         """ Rétablit l'affichage normal de self"""
383         if hasattr(self,'label'):
384             self.label.configure(fg='black',bg='gray95')
385
386     def enter(self,event=None):
387         """ Met en surbrillance self et affiche le fr de l'objet """
388         self.highlight()
389         fr = self.item.get_fr()
390         self.appli.affiche_infos(fr)
391         
392     def leave(self,event=None):
393         """ Rétablit l'affichage normal de self et efface le fr de l'objet """
394         if not self.selected :
395             self.dehighlight()
396         self.appli.affiche_infos('')
397
398     def collapse_children(self):
399         """ Collapse récursivement tous les descendants de self """
400         if not self.children : return
401         for child in self.children:
402             child.state='collapsed'
403             child.displayed = 0
404             child.collapse_children()
405             
406     def collapse(self,event = None):
407         """ Collapse self et descendants et retrace self """
408         nb = self.get_nb_children()
409         self.state = 'collapsed'
410         self.collapse_children()
411         self.redraw(-nb)
412         self.select()
413    
414     def expand(self,event = None):
415         """ Expanse self et le retrace """
416         if not self.item.isactif() : return
417         if not self.children : self.build_children()
418         self.state = 'expanded'
419         nb = self.get_nb_children()
420         self.redraw(nb)
421         self.select()
422
423     def redraw(self,nb):
424         """ Redessine self :  nb est le décalage à introduire
425             en dessous de self pour le redessiner """
426         # nb = nombre d'items de décalage
427         self.move(20*nb)
428         # on efface self et on le redessine
429         self.efface()
430         self.draw(self.x,self.y)
431         # Il n'est pas nécessaire d'appeler update
432         # il suffit d'updater les coordonnees et de retracer les lignes
433         self.racine.update_coords()
434         self.racine.trace_ligne()
435         self.tree.resizescrollregion()
436         
437     def update_coords(self):
438         """ Permet d'updater les coordonnes de self et de tous ses enfants"""
439         if self.displayed == 0 : return
440         if self.image_id != None :
441             coords = self.canvas.coords(self.image_id)
442             self.x = coords[0]-15
443         else:
444             coords = self.canvas.coords(self.label_id)
445             self.x = coords[0]-15
446         self.y = coords[1]
447         if self.state == 'expanded' :
448             for child in self.children:
449                 if child.displayed != 0:
450                     child.update_coords()
451
452     def update_icone(self):
453         """ Met à jour les icônes de tous les noeuds : teste la validité de l'objet
454         Cette méthode est très lente, trop !!"""
455         if self.image_id != None :
456             image = self.geticonimage()
457             self.canvas.itemconfig(self.image_id,image=image)
458         if self.state == 'expanded':
459             for child in self.children:
460                 if child.displayed != 0:
461                     child.update_icone()
462
463     def update_texte(self):
464         """ Met à jour les noms des SD et valeurs des mots-clés """
465         text = self.item.GetText()
466         if text == None : text = ''
467         self.text.configure(text=text)
468         if self.state == 'expanded' :
469             for child in self.children:
470                 if child.displayed != 0 : child.update_texte()
471         
472     def update(self,event=None) :
473         """ Classe Node :
474             Cette méthode est appelée pour demander l update d un noeud 
475              d'un jeu de commandes
476              Cette demande est transmise au noeud racine (le JDC) qui update
477              tout l arbre représentant le jeu de commandes
478              Pendant cette mise à jour, on appelle la méthode isvalid qui
479              fera l update de tous les objets déclarés modifiés lors des
480              actions précédentes
481              La métode isvalid est en général appelée par l intermédiaire de
482              update_icone -> geticonimage -> GetIconName
483         """
484         self.racine.update_coords()
485         self.racine.trace_ligne()
486         self.racine.update_icone()
487         self.racine.update_texte()
488         self.tree.resizescrollregion()
489
490     def efface(self):
491         """ Efface du canvas les id associés à self : cad les siens et ceux
492             de ses enfants """
493         for id in self.id :
494             self.canvas.delete(id)
495         if not self.children : return
496         for child in self.children:
497             child.efface()
498
499     def move(self,dy):
500         """ Déplace de l'incrément dy tous les id en dessous de self """
501         # il faut marquer tous les suivants de self
502         bbox1 = self.canvas.bbox(ALL)
503         self.canvas.dtag(ALL,'move')
504         self.canvas.delete('line')
505         try:
506             self.canvas.addtag_overlapping('move',bbox1[0],self.y +10,bbox1[2],bbox1[3])
507         except:
508             print "Erreur dans move :"
509             print self
510             print self.item
511             print self.item.object
512             print self.item.object.definition.label
513             print 'y=',self.y
514             print 'dy=',dy
515         # on déplace tous les items de dy
516         self.canvas.move('move',0,dy)
517
518     def trace_ligne(self):
519         """ Dessine les lignes verticales entre frères et entre père et premier fils"""
520         if self.state=='collapsed' : return
521         #if self.displayed == 0 : return
522         if len(self.children)==0 : return
523         # on est bien dans le cas d'un noeud expansé avec enfants ...
524         # il faut rechercher l'ordonnée du dernier fils de self
525         y_end = self.children[-1].y
526         ligne = self.canvas.create_line(self.x+15,self.y,self.x+15,y_end,tags='line')
527         self.canvas.tag_lower(ligne)
528         for child in self.children :
529             try:
530                 child.trace_ligne()
531             except:
532                 print "Erreur dans trace_ligne :"
533                 print child
534                 print child.item.object
535
536     def last_child(self):
537         lchild=self
538         if self.state == 'expanded' and self.children:
539            lchild= self.children[-1].last_child()
540         return lchild
541
542     #------------------------------------------------------------------
543     # Méthodes de création et destruction de noeuds
544     # Certaines de ces méthodes peuvent être appelées depuis l'externe
545     #------------------------------------------------------------------
546     def replace_node(self,node1,node2):
547         """ Remplace le noeud 1 par le noeud 2 dans la liste des enfants de self"""
548         index= self.children.index(node1)
549         self.delete_node_child(node1)
550         self.children.insert(index,node2)
551         
552     def full_creation(self,name,pos=None):
553         """
554             Interface avec ACCAS : création de l'objet de nom name et
555             du noeud associé. Retourne le noeud fils ainsi créé
556         """
557         item = self.item.additem(name,pos)
558         if item == None or item == 0:
559             # impossible d'ajouter le noeud de nom : name
560             return 0
561         nature = item.get_nature()
562         if nature in ("COMMANDE","OPERATEUR","PROCEDURE","COMMENTAIRE",
563                       "PARAMETRE","COMMANDE_COMMENTARISEE","PARAMETRE_EVAL"):
564             # on veut ajouter une commande ou un commentaire ou un paramètre
565             # il ne faut pas rechercher un même objet déjà existant
566             # à modifier : il faut tester l'attribut 'repetable' 
567             enfant = None
568         elif self.item.object.isMCList():
569             # Dans ce cas on ne fait pas de remplacement. On ne cherche pas un objet de meme nom
570             enfant=None
571         else :
572             enfant = self.get_node_fils(item.get_nom())
573         if enfant :
574             # un fils de même nom existe déjà : on remplace
575             # un MCFACT (ou une MCList) par une (autre) MCList
576             child = Node(self,item,self.command,self.rmenu)
577             self.replace_node(enfant,child)
578         else :            
579             child = Node(self, item,self.command,self.rmenu)
580             if pos is None:
581                 self.children.append(child)
582             else :
583                 self.children.insert(pos,child)
584         return child
585
586     def append_brother(self,name,pos='after',retour='non'):
587         """
588         Permet d'ajouter un frère à self
589         par défaut on l'ajoute après self
590         Méthode externe
591         """
592         # on veut ajouter le frère de nom name directement avant ou après self
593         index = self.parent.children.index(self)
594         if pos == 'before':
595             index = index
596         elif pos == 'after':
597             index = index +1
598         else:
599             print str(pos)," n'est pas un index valide pour append_brother"
600             return
601         return self.parent.append_child(name,pos=index,retour=retour)
602     
603     def append_node_child(self,fils,pos=None,verif='oui'):
604         """
605         Fait appel à la création complète de fils et à la vérification
606         des conditions en fonction du contexte
607         Attention : fils peut être un nom ou déjà un object (cas d'une copie)
608         """
609         if not self.children : self.build_children()
610         if pos == None :
611             if type(fils) == types.InstanceType:
612                 pos = self.item.get_index_child(fils.nom)
613             else:
614                 pos = self.item.get_index_child(fils)
615         child = self.full_creation(fils,pos)
616         if child == 0 :
617             # on n'a pas pu créer le noeud fils
618             return 0
619         self.state = 'expanded'
620         child.displayed = 1
621         if child.item.isactif():
622            child.state = 'expanded'
623         if not child.children : child.build_children()
624         if verif == 'oui':
625             test = child.item.isMCList()
626             if test :
627                 child.children[-1].verif_condition()
628             else :
629                 child.verif_condition()
630             self.verif_condition()
631         return child
632             
633     def append_child(self,name,pos=None,verif='oui',retour='non'):
634         """
635         Permet d'ajouter un fils à self
636         on peut l'ajouter en fin de liste (défaut) ou en début
637         Méthode externe
638         """
639         if pos == 'first':
640             index = 0
641         elif pos == 'last':
642             index = len(self.children)
643         elif pos != None and type(pos) == types.IntType :
644             # on donne la position depuis l'extérieur
645             # (appel de append_child par append_brother par exemple)
646             index = pos
647         elif type(pos) == types.InstanceType:
648             # pos est un item. Il faut inserer name apres pos
649             index = self.item.get_index(pos) +1
650         else :
651             if type(name) == types.InstanceType:
652                 index = self.item.get_index_child(name.nom)
653             else:
654                 index = self.item.get_index_child(name)
655         nbold = self.get_nb_children()
656         self.state='expanded'
657         child = self.append_node_child(name,pos=index)
658         if child == 0 :
659             # on n'a pas pu créer le fils
660             return 0
661         nbnew = self.get_nb_children()
662         self.redraw(nbnew-nbold)
663         child.select()
664         if retour == 'oui': return child
665
666     def delete_node_child(self,child):
667         """ Supprime child des enfants de self et les id associés """
668         child.efface()
669         child.displayed = 0
670         self.children.remove(child)
671         self.canvas.update()
672         
673     def delete_child(self,child):
674         """ 
675             Supprime child des enfants de self, tous les id associés
676             ET l'objet associé 
677         """
678         if self.item.suppitem(child.item):
679             self.delete_node_child(child)
680             return 1
681         else :
682             return 0
683                     
684     def delete(self):
685         """ Méthode externe pour la destruction du noeud ET de l'objet
686             Gère l'update du canvas"""
687         if self.parent.item.isMCList():
688             pere = self.parent.parent
689             nbold = pere.get_nb_children()
690             if self.parent.delete_child(self):
691                 self.parent.traite_mclist()
692             if self.item.get_position() == 'global':
693                 self.etape.verif_all()
694             elif self.item.get_position() == 'global_jdc':
695                 self.racine.verif_all()
696             else:
697                 self.parent.verif_condition()
698             nbnew = pere.get_nb_children()
699         else:
700             pere = self.parent
701             nbold = pere.get_nb_children()
702             if self.parent.delete_child(self):
703                 if self.item.get_position() == 'global':
704                     self.etape.verif_all()
705                 elif self.item.get_position() == 'global_jdc':
706                     self.racine.verif_all()
707                 else:
708                     self.parent.verif_condition()
709             else :
710                 print 'Erreur dans la destruction de ',self.item.get_nom(),' dans delete'
711             nbnew = pere.get_nb_children()
712         pere.redraw(nbnew-nbold)
713         pere.select()
714
715     def copynode(self,node,pos) :
716         """ node est le noeud à copier à la position pos de self ( = parent de node) """
717         objet_copie = node.item.get_copie_objet()
718         child = self.full_creation(node.item,pos)
719         child.displayed = node.displayed
720         #child.image_id = node.image_id
721         #child.label_id = node.label_id
722         if child.item.get_nature() == "MCList":
723             child.item.object[-1].mc_liste = objet_copie.mc_liste
724         else :
725             try :
726                 child.item.object.mc_liste = objet_copie.mc_liste
727             except:
728                 traceback.print_exc()
729
730     #--------------------------------------------------------------
731     # Méthodes de vérification du contexte et de validité du noeud
732     #--------------------------------------------------------------
733     def traite_mclist_OLD(self):
734         """ Dans le cas d'une MCList il faut vérifier qu'elle n'est pas vide
735             ou réduite à un seul élément suite à une destruction
736         """
737         # self représente une MCList
738         print "on passe par traite_mclist ",len(self.item)
739         if len(self.item) == 0 :
740             # la liste est vide : il faut la supprimer
741             self.delete()
742         elif len(self.item) == 1:
743             # il ne reste plus qu'un élément dans la liste
744             # il faut supprimer la liste et créer directement l'objet
745             index = self.parent.children.index(self)
746             noeud = self.children[0]
747             if self.parent.delete_child(self):
748                 self.parent.append_node_child(noeud.item,pos=index,verif='non')
749             else:
750                 print "destruction de self impossible !"
751             #if self.parent.delete_child(self):
752             #    self.parent.copynode(self.children[0],index)
753             #else :
754             #    print 'erreur dans la destruction de :',self.item.get_nom(),' dans traite_mclist'
755         else :
756             return
757
758     def traite_mclist(self):
759         """ Dans le cas d'une MCList il faut vérifier qu'elle n'est pas vide
760             ou réduite à un seul élément suite à une destruction
761         """
762         # self représente une MCList
763         if len(self.item) == 0 :
764             # la liste est vide : il faut la supprimer
765             self.delete()
766         elif len(self.item) == 1:
767             # il ne reste plus qu'un élément dans la liste
768             # il faut supprimer la liste et créer directement l'objet
769             index = self.parent.children.index(self)
770             noeud = self.children[0]
771             noeud.parent = self.parent
772             self.parent.delete_node_child(self)
773             self.parent.item.replace_child(self.item,noeud.item)
774             self.parent.children.insert(index,noeud)
775         else :
776             return
777             
778     def verif_all(self):
779         self.verif_all_children()
780             
781     def verif_all_children(self):
782         if not self.children : self.build_children()
783         if self.nature != 'JDC' :
784             self.verif()
785         for child in self.children :
786             child.verif_all_children()
787
788     def verif(self) :
789         """ 
790             Lance la vérification des conditions des blocs de self et le cas
791             échéant redessine self 
792         """
793         nbold = self.get_nb_children()
794         test = self.verif_condition()
795         nbnew = self.get_nb_children()
796         if test != 0 :
797             self.redraw(nbnew-nbold)
798
799     def verif_condition(self):
800         """
801         on lance la vérification des conditions de chaque bloc de self
802         on crée ou supprime les noeuds concernés
803         (self est d'un niveau inférieur ou égal à l'ETAPE)
804         """
805         if self.item.object.__class__.__name__ == 'ETAPE_NIVEAU': return 0
806         test = 0
807         l_bloc_arajouter,l_bloc_aenlever = self.verif_condition_bloc()
808         if len(l_bloc_arajouter) > 0:
809             test = 1
810             for mc in l_bloc_arajouter:
811                 self.append_node_child(mc,verif='non')
812         if len(l_bloc_aenlever) > 0:
813             test = 1
814             for mc in l_bloc_aenlever:
815                 mocle = self.get_node_fils(mc)
816                 self.delete_child(mocle)
817         l_mc_presents = self.item.get_liste_mc_presents()
818         l_mc_arajouter= self.verif_condition_regles(l_mc_presents)
819         if len(l_mc_arajouter) > 0:
820             test = 1
821             for mc in l_mc_arajouter:
822                 self.append_node_child(mc,verif='non')
823         if len(l_mc_arajouter)+len(l_bloc_arajouter)+len(l_bloc_aenlever) != 0 :
824             self.verif_condition()
825         return test
826         
827     def verif_condition_bloc(self):
828         return self.item.verif_condition_bloc()
829
830     def verif_condition_regles(self,l_mc_presents):
831         return self.item.verif_condition_regles(l_mc_presents)
832     
833