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