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