Salome HOME
F.R: -bulle d'aide des panneaux de composimp retaillées
[tools/eficas.git] / Editeur / bureau.py
1 """
2    Ce module contient la classe BUREAU qui gere les JDC ouverts
3 """
4 # Modules Python
5 import os,string
6 import traceback
7 import Pmw
8 from tkFileDialog import askopenfilename,asksaveasfilename
9 from tkMessageBox import showinfo,askyesno,showerror
10
11 # Modules Eficas
12 import splash
13 import prefs
14 import convert
15 import generator
16 from jdcdisplay import JDCDISPLAY
17 from utils import extension,stripPath,save_in_file
18 from widgets import Fenetre,Ask_Format_Fichier
19 from fenetre_mc_inconnus import fenetre_mc_inconnus
20
21 class BUREAU:
22    menu_defs=[
23               ('Fichier',[
24                            ('Nouveau','newJDC'),
25                            ('Ouvrir','openJDC'),
26                            ('Enregistrer','saveJDC'),
27                            ('Enregistrer sous','saveasJDC'),
28                            None,
29                            ('Fermer','closeJDC'),
30                            ('Quitter','exitEFICAS'),
31                          ]
32               ),
33               ('Edition',[
34                            ('Copier','copy'),
35                            ('Couper','cut'),
36                            ('Coller','paste'),
37                          ]
38               ),
39               ('Jeu de commandes',[
40                                    ('Rapport de validation','visuCRJDC'),
41                                    ('Fichier à plat','visu_a_plat'),
42                                    ('Fichier .py','visuJDC_py'),
43                                    ('Fichier source','visu_txt_brut_JDC'),
44                                    ('Paramètres Eficas','affichage_fichier_ini'),
45                                    ('Mots-clés inconnus','mc_inconnus'),
46                                   ]
47               ),
48              ]
49
50    button_defs  =      (('New24',"newJDC","Création d'un nouveau fichier",'always'),
51                         ('Open24',"openJDC","Ouverture d'un fichier existant",'always'),
52                         ('Save24',"saveJDC","Sauvegarde du fichier courant",'always'),
53                         ('Zoom24',"visuJDC","Visualisation du fichier de commandes",'always'),
54                         None,
55                         ('Copy24',"copy","Copie l'objet courant",'jdc'),
56                         ('Cut24',"cut","Coupe l'objet courant",'jdc'),
57                         ('Paste24',"paste","Colle l'objet copié après l'objet courant",'jdc'),
58                         None,
59                         ('Delete24',"delete","Supprime l'objet courant",'jdc'),
60                         ('Help24',"view_doc","Documentation de l'objet courant",'jdc')
61                        )
62    try:
63       menu_defs=prefs.menu_defs['bureau']
64    except:
65       pass
66    try:
67       button_defs=prefs.button_defs['bureau']
68    except:
69       pass
70
71    def __init__(self,appli,parent):
72       self.parent=parent
73       self.appli=appli
74       splash._splash.configure(text = "Création du bureau")
75       self.nb = Pmw.NoteBook(self.parent,raisecommand=self.selectJDC)
76       self.nb.pack(fill='both',expand=1)
77       self.JDCDisplay_courant=None
78       self.fileName=None
79       self.liste_JDCDisplay=[]
80       self.cree_cataitem()
81
82    def cree_cataitem(self):
83       """
84           On récupère dans l'extension readercata les variables 
85           qui servent par la suite pour la création des JDC
86       """
87       self.cataitem=self.appli.readercata.cataitem
88       self.cata=self.appli.readercata.cata
89       self.cata_ordonne_dico=self.appli.readercata.cata_ordonne_dico
90       self.code=self.appli.readercata.code
91       self.version_code=self.appli.readercata.version_code
92       self.fic_cata=self.appli.readercata.fic_cata
93
94    def selectJDC(self,event=None):
95       """
96           Cette méthode est appelée chaque fois que l'on sélectionne 
97           l'onglet d'un JDC dans le NoteBook des JDC.
98           Elle permet de stocker dans les variable self.JDC et 
99           self.JDCDisplay_courant les valeurs concernant le JDC courant
100       """
101       if len(self.liste_JDCDisplay) == 0 : return
102       #if self.JDCDisplay_courant : self.JDCDisplay_courant.jdc.unset_context()
103       numero_jdc = self.nb.index(self.nb.getcurselection())
104       self.JDCDisplay_courant = self.liste_JDCDisplay[numero_jdc]
105       self.JDC = self.JDCDisplay_courant.jdc
106       #self.JDC.set_context()
107       self.JDCName = self.JDC.nom
108
109    def newJDC(self):
110       """
111           Initialise un nouveau JDC vierge
112       """
113       self.appli.statusbar.reset_affichage_infos()
114
115       CONTEXT.unset_current_step()
116       J=self.cata[0].JdC(cata=self.cata,
117                          cata_ord_dico=self.cata_ordonne_dico,
118                          appli=self.appli)
119       self.JDCName=J.nom
120       self.fileName=None
121       self.ShowJDC(J,self.JDCName)
122       self.appli.toolbar.active_boutons()
123
124    def ShowJDC(self,JDC,nom,label_onglet=None):
125       """
126           Lance l'affichage du JDC cad création du JDCDisplay
127           Rajoute le JDCDisplay à la liste des JDCDisplay si label_onglet == None cad si on crée
128           bien un nouveau JDCDisplay et non si on remplace (renommage de l'onglet)
129       """
130       self.JDC=JDC
131       self.JDCName = self.JDC.nom = nom
132       #XXX CCAR: pour le moment mis en commentaire
133       #self.JDC.set_context()
134       if label_onglet == None :
135           label_onglet = self.GetLabelJDC()
136           self.nb.add(label_onglet,tab_text = nom,tab_width=20)
137           new = 'oui'
138       else :
139           new = 'non'
140       self.JDCDisplay_courant=JDCDISPLAY(self.JDC,nom,appli=self.appli,parent=self.nb.page(label_onglet))
141       if new == 'oui':
142           self.liste_JDCDisplay.append(self.JDCDisplay_courant)
143       self.JDCDisplay_courant.modified='n'
144       self.JDCDisplay_courant.fichier=self.fileName
145       self.nb.selectpage(label_onglet)
146       self.nb.setnaturalsize()
147       texte = "Jeu de commandes :" + self.JDCName+" ouvert"
148       self.appli.affiche_infos(texte)
149
150    def closeJDC (self) :
151       """
152       Ferme le JDC courant et détruit l'onglet associé dans le notebook self.nb
153       """
154       if self.JDCDisplay_courant.modified == 'o' :
155           message = "Voulez-vous sauvegarder le jeu de commandes "+self.JDC.nom+" courant ?"
156           reponse = askyesno(title="Sauvegarde du jdc courant",
157                              message=message)
158           if reponse :
159               test = self.saveJDC()
160               if test == 0 :
161                   self.appli.affiche_infos("Sauvegarde impossible")
162                   return
163       self.JDCDisplay_courant.jdc.supprime()
164       self.liste_JDCDisplay.remove(self.JDCDisplay_courant)
165       self.nb.delete(self.nb.getcurselection())
166       #XXX CCAR: pour le moment mis en commentaire
167       #self.JDC.unset_context()
168       self.JDC = None
169       try:
170           index = self.nb.index(self.nb.getcurselection())
171           self.JDCDisplay_courant = self.liste_JDCDisplay[index]
172           self.JDC = self.JDCDisplay_courant.jdc
173       except:
174           self.JDCDisplay_courant = None
175           self.appli.toolbar.inactive_boutons()
176
177    def visuCRJDC(self):
178       return self.visuCR(mode='JDC')
179
180    def visuCR(self,mode):
181       """
182       Méthode permettant l'affichage du rapport de validation
183       """
184       if mode == 'JDC':
185           if not hasattr(self,'JDC') : return
186           titre="rapport de validation du jeu de commandes courant"
187           cr = self.JDC.report()
188       elif mode == 'CATA':
189           from Noyau.N_CR import CR
190           cr = CR()
191           cr.debut = "Début rapport de validation du catalogue"
192           cr.fin = "Fin rapport de validation du catalogue"
193           titre="rapport de validation du catalogue"
194           if hasattr(self,'cata_ordonne_cr') :
195               cr.add(self.cata_ordonne_cr)
196           if hasattr(self,'cata_dev_ordonne_cr') :
197               cr.add(self.cata_dev_ordonne_cr)
198           for cata in self.cata:
199               if hasattr(cata,'JdC'):
200                   cr.add(cata.JdC.report())
201       texte_cr = str(cr)
202       self.visu_texte_cr = Fenetre(self.appli,titre=titre,texte=texte_cr)
203
204    def openJDC(self,file=None):
205       """
206           Demande à l'utilisateur quel JDC existant il veut ouvrir
207       """
208       if self.code == 'ASTER':
209           filetypes = ( ("format "+self.appli.format_fichier.get(), ".comm"),("Tous",'*'))
210       else:
211           filetypes = ( ("format "+self.appli.format_fichier.get(), ".py"),)
212       if not hasattr(self,'initialdir'):
213          self.initialdir = self.appli.CONFIGURATION.rep_user
214       if not file :
215           file = askopenfilename(title="Ouverture d'un fichier de commandes Aster",
216                                  defaultextension=".comm",
217                                  filetypes = filetypes,
218                                  initialdir = self.initialdir)
219       if file != '':
220           self.fileName = file
221           e=extension(file)
222           self.JDCName=stripPath(file)
223           self.initialdir = os.path.dirname(file)
224       else :
225           return
226       #XXX CCAR: pour le moment mis en commentaire
227       #if self.JDCDisplay_courant:self.JDCDisplay_courant.jdc.unset_context()
228
229       format=self.appli.format_fichier.get()
230       # Il faut convertir le contenu du fichier en fonction du format
231       if convert.plugins.has_key(format):
232          # Le convertisseur existe on l'utilise
233          p=convert.plugins[format]()
234          p.readfile(file)
235          text=p.convert('exec')
236          if not p.cr.estvide(): 
237             self.appli.affiche_infos("Erreur à la conversion")
238             Fenetre(self.appli,
239                     titre="compte-rendu d'erreurs, EFICAS ne sait pas convertir ce fichier",
240                     texte = str(p.cr)).wait()
241             return
242       else:
243          # Il n'existe pas c'est une erreur
244          self.appli.affiche_infos("Type de fichier non reconnu")
245          showerror("Type de fichier non reconnu","EFICAS ne sait pas ouvrir ce type de fichier")
246          return
247
248       # On se met dans le repertoire ou se trouve le fichier de commandes
249       # pour trouver les eventuels fichiers include ou autres
250       # localises a cote du fichier de commandes
251       os.chdir(self.initialdir)
252       CONTEXT.unset_current_step()
253       J=self.cata[0].JdC(procedure=text,appli=self.appli,
254                          cata=self.cata,cata_ord_dico=self.cata_ordonne_dico,
255                          nom = self.JDCName)
256       J.analyse()
257       txt_exception = J.cr.get_mess_exception()
258       if txt_exception :
259           # des exceptions ont été levées à la création du JDC 
260           # --> on affiche les erreurs mais pas le JDC
261           self.appli.affiche_infos("Erreur fatale au chargement de %s" %file)
262           showerror("Erreur fatale au chargement d'un fichier",txt_exception)
263       else:
264           self.ShowJDC(J,self.JDCName)
265           self.appli.toolbar.active_boutons()
266           # si le JDC ne contient rien (vide), on retourne ici
267           if len(self.JDC.etapes) == 0 : return
268           # dans le cas où le JDC est invalide, on affiche son CR
269           cr = self.JDC.report()
270           if not cr.estvide() : 
271              self.appli.top.update()
272              self.visuCR(mode='JDC')
273
274
275    def GetLabelJDC(self,nb_jdc = 'absent'):
276       """
277       Retourne le label de l'onglet du NoteBook associé au JDC à afficher
278       """
279       if nb_jdc == 'absent':
280           nb_jdc = len(self.nb.pagenames())
281       nb_jdc = nb_jdc+1
282       label_onglet = 'JDC'+`nb_jdc`
283       if label_onglet not in self.nb.pagenames() :
284           return label_onglet
285       else :
286           return self.GetLabelJDC(nb_jdc)
287
288    def saveasJDC(self):
289       """ 
290            Sauvegarde le JDC courant en demandant impérativement à l'utilisateur de
291            donner le nom du fichier de sauvegarde 
292       """
293       self.saveJDC(echo='oui')
294
295    def saveJDC(self,echo='non'):
296       """ 
297           Sauvegarde le JDC courant.
298           Retourne 1 si la sauvegarde s'est bien faite, 0 sinon.
299           Si echo = 'oui' : interactif (l'utilisateur donne le nom sous lequel il 
300                             veut sauver le JDC
301           Si echo = 'non' : muet (sauvegarde le JDC dans JDC.procedure)
302       """
303       if not hasattr(self,'JDC') : return 0
304       format=self.appli.format_fichier.get()
305       if generator.plugins.has_key(format):
306          # Le generateur existe on l'utilise
307          g=generator.plugins[format]()
308          jdc_formate=g.gener(self.JDC,format='beautifie')
309          if not g.cr.estvide():
310             print g.cr
311             self.appli.affiche_infos("Erreur à la generation")
312             showerror("Erreur à la generation","EFICAS ne sait pas convertir ce JDC")
313             return
314       else:
315          # Il n'existe pas c'est une erreur
316          self.appli.affiche_infos("Format %s non reconnu" % format)
317          showerror("Format %s non reconnu" % format,"EFICAS ne sait pas convertir le JDC")
318          return
319       self.jdc_fini = string.replace(jdc_formate,'\r\n','\n')
320
321       if echo =='oui' or self.JDCDisplay_courant.fichier == None:
322           return self.asknomsauvegardeJDC()
323       elif self.JDCDisplay_courant.fichier != None :
324           # le JDC a déjà un nom : on sauvegarde directement sans demander
325           # un autre nom au développeur
326           if not save_in_file(self.JDCDisplay_courant.fichier,self.jdc_fini) :
327               showinfo("Erreur","Problème à la sauvegarde du fichier :" + `self.JDCDisplay_courant.fichier`)
328               return 0
329           else :
330               self.JDCDisplay_courant.stop_modif()
331               self.appli.affiche_infos("sauvegarde de "+`self.JDCDisplay_courant.fichier`+" effectuée")
332               return 1
333
334    def asknomsauvegardeJDC(self):
335       """ Demande à l'utilsateur le nom sous lequel il veut sauvegarder le JDC courant """
336       titre = "Sauvegarde d'un fichier de commandes "+self.code
337       if self.code == 'ASTER':
338           defext = ".comm"
339           filtyp = ( ("ASTER", ".comm"),)
340       else :
341           defext = ".py"
342           filtyp = ( (self.code, ".py"),)
343       sauvegarde = asksaveasfilename(title=titre,
344                                      defaultextension=defext,
345                                      filetypes = filtyp,
346                                      initialdir = self.appli.CONFIGURATION.rep_user)
347       if sauvegarde != '':
348           if not save_in_file(sauvegarde,self.jdc_fini) :
349               showinfo("Erreur","Problème à la sauvegarde du fichier "+`sauvegarde`)
350               return 0
351           else :
352               self.JDCDisplay_courant.stop_modif()
353               self.appli.affiche_infos("Sauvegarde effectuée")
354               if sauvegarde != self.JDCDisplay_courant.fichier :
355                   # l'utilisateur a sauvegardé le JDC sous un autre nom
356                   self.JDCDisplay_courant.fichier = sauvegarde
357                   self.JDCName = self.JDC.nom = stripPath(sauvegarde)
358                   self.changeNomPage()
359               return 1
360       else :
361           return 0
362
363    def changeNomPage(self):
364       """ Change le nom de l'onglet contenant le JDC courant : en fait détruit l'actuel
365           et recrée un autre onglet à la même place avec le bon nom 
366       """
367       nom = self.JDCName
368       self.JDCDisplay_courant.jdc.nom = nom
369       nom_page = self.nb.getcurselection()
370       num_page = self.nb.index(nom_page)
371       tab = self.nb.tab(num_page)
372       tab.configure(text = nom)
373
374    def exitEFICAS(self):
375       """
376           Permet de sortir d'EFICAS en demandant à l'utilisateur
377           s'il veut sauvegarder les modifications en cours
378       """
379       liste = self.GetListeJDCaSauvegarder()
380       if liste != [] :
381           # Certains fichiers n'ont pas été sauvegardés ...
382           if askyesno("Enregistrer modifications","Enregister les modifications ?") :
383               test = self.saveall(liste)
384               if test != 1 :
385                   return
386       if askyesno ("Quitter","Voulez-vous vraiment quitter l'application ?") :
387           for JDCDisplay in self.liste_JDCDisplay:
388               JDCDisplay.jdc.supprime()
389           self.appli.quit()
390           return
391
392    def GetListeJDCaSauvegarder(self) :
393       """ Retourne parmi la liste de tous les JDC ouverts la liste de ceux qui ont été modifiés """
394       if not self.JDCDisplay_courant : return []
395       if len(self.liste_JDCDisplay) == 0 : return l
396       l = []
397       for JDCDisplay in self.liste_JDCDisplay:
398           if JDCDisplay.modified == 'o' :
399               l.append(JDCDisplay)
400       return l
401
402    def copy(self):
403       """
404           Lance la copie sur le JDC courant
405       """
406       if self.JDCDisplay_courant : self.JDCDisplay_courant.doCopy()
407
408    def paste(self):
409       """
410            Lance le collage sur le JDC courant
411       """
412       if self.JDCDisplay_courant : self.JDCDisplay_courant.doPaste()
413
414    def cut(self):
415       """
416          Lance le cut sur le JDC courant
417       """
418       if self.JDCDisplay_courant: self.JDCDisplay_courant.doCut()
419
420    def delete(self):
421       """
422           Lance la suppression du noeud courant
423       """
424       if not self.JDCDisplay_courant : return
425       try:
426           if self.JDCDisplay_courant.modified == 'n' : 
427              self.JDCDisplay_courant.init_modif()
428           pere = self.JDCDisplay_courant.node_selected.parent
429           self.JDCDisplay_courant.node_selected.delete()
430           pere.select()
431       except AttributeError:
432           pass
433
434    def visuJDC_py(self):
435       """ 
436           Méthode permettant d'afficher dans une fenêtre à part l'écho au 
437             format python du jdc courant 
438       """
439       if not hasattr(self,'JDC') : return
440       jdc_fini = self.get_text_JDC('python')
441       if jdc_fini == None : return
442       Fenetre(self.appli,
443               titre = 'fichier '+ self.JDCName + ' à la syntaxe Python',
444               texte = jdc_fini)
445
446    def visuJDC(self):
447       """ 
448           Méthode permettant d'afficher dans une fenêtre à part l'écho au 
449             format .comm ou .py du jdc courant 
450       """
451       if not hasattr(self,'JDC') : return
452       titre = 'fichier '+ self.JDCName + ' à la syntaxe '+ self.code
453       format=self.appli.format_fichier.get()
454       self.jdc_fini = self.get_text_JDC(format)
455       if self.jdc_fini == None : return
456       self.visu_fichier_cmd = Fenetre(self.appli,titre=titre,texte = self.jdc_fini)
457
458    def get_text_JDC(self,format):
459       if generator.plugins.has_key(format):
460          # Le generateur existe on l'utilise
461          g=generator.plugins[format]()
462          jdc_formate=g.gener(self.JDC,format='beautifie')
463          if not g.cr.estvide():
464             print g.cr
465             self.appli.affiche_infos("Erreur à la generation")
466             showerror("Erreur à la generation","EFICAS ne sait pas convertir ce JDC")
467             return
468          else:
469             return jdc_formate
470       else:
471          # Il n'existe pas c'est une erreur
472          self.appli.affiche_infos("Format %s non reconnu" % format)
473          showerror("Format %s non reconnu" % format,"EFICAS ne sait pas convertir le JDC en format %s "% format)
474          return
475
476    def view_doc(self):
477       """
478           Permet d'ouvrir le fichier doc U de la commande au format pdf avec Acrobat Reader
479           - Ne fonctionne pas sous UNIX (chemin d'accès Acrobat Reader)
480           - indication du chemin d'accès aux fichiers pdf à revoir : trop statique
481       """
482       if not self.JDCDisplay_courant : return
483       try:
484           cle_doc = self.JDCDisplay_courant.node_selected.item.get_docu()
485           if cle_doc == None : return
486           cle_doc = string.replace(cle_doc,'.','')
487           cle_doc = string.replace(cle_doc,'-','')
488           commande = self.appli.CONFIGURATION.exec_acrobat
489           nom_fichier = cle_doc+".pdf"
490           rep_fichier = cle_doc[0:2]
491           fichier = os.path.abspath(os.path.join(self.appli.CONFIGURATION.path_doc,rep_fichier,nom_fichier))
492           if os.name == 'nt':
493               os.spawnv(os.P_NOWAIT,commande,(commande,fichier,))
494           elif os.name == 'posix':
495               script ="#!/usr/bin/sh \n%s %s&" %(commande,fichier)
496               pid = os.system(script)
497       except AttributeError:
498           traceback.print_exc()
499           pass
500
501    def visu_a_plat(self):
502       """ 
503           Méthode permettant d'afficher dans une fenêtre à part l'écho 'à plat' du jdc courant 
504       """
505       if not hasattr(self,'JDC') : return
506       titre = 'fichier '+ self.JDCName + ' à plat '
507       self.jdc_fini = self.get_text_JDC('aplat')
508       if self.jdc_fini == None : return
509       self.visu_fichier_cmd = Fenetre(self.appli,titre=titre,texte = self.jdc_fini)
510
511    def visu_txt_brut_JDC(self):
512       """
513            Méthode permettant d'afficher le jeu de commandes tel qu'il a été passé au JDC
514       """
515       if not hasattr(self,'JDC') : return
516       titre = "fichier de commandes utilisateur"
517       #texte = self.JDC.procedure
518       #if texte == None:
519       if self.JDCDisplay_courant.fichier == None:
520             self.appli.affiche_infos("Pas de fichier initial")
521             showerror("Impossible de visualiser le fichier initial",
522                       "EFICAS ne peut visualiser le fichier initial.\nIl s'agit d'un nouveau JDC")
523             return
524       f=open(self.JDCDisplay_courant.fichier,'r')
525       texte=f.read()
526       f.close()
527       self.visu_texte_JDC = Fenetre(self.appli,titre=titre,texte=texte)
528
529    def affichage_fichier_ini(self):
530       """
531            Affichage des valeurs des paramètres relus par Eficas
532       """
533       self.appli.CONFIGURATION.affichage_fichier_ini()
534
535    def saveall(self,liste):
536       """ 
537            Sauvegarde tous les JDC contenus dans liste 
538       """
539       test = 1
540       for JDCDisplay in liste :
541           self.JDC = JDCDisplay.jdc
542           test = test * self.saveJDC(echo = 'non')
543       return test
544
545
546 # ---------------------------------------------------------------------------
547 #                       Méthodes liées aux mots-clés inconnus
548 # ---------------------------------------------------------------------------
549
550    def mc_inconnus(self):
551       l_mc = self.JDCDisplay_courant.jdc.get_liste_mc_inconnus()
552       o = fenetre_mc_inconnus(l_mc)
553       l = o.wait_new_list()
554