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