Salome HOME
6facd594ce16dc68f7f9ef8b49b111ab7e48f22b
[modules/hydrosolver.git] / src / HYDROGUI / HYDROSOLVERGUI.py
1 #  Copyright (C) 2012-2013 EDF
2 #
3 #  This file is part of SALOME HYDRO module.
4 #
5 #  SALOME HYDRO module 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 3 of the License, or
8 #  (at your option) any later version.
9 #
10 #  SALOME HYDRO module is distributed in the hope that it will be useful,
11 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 #  GNU General Public License for more details.
14 #
15 #  You should have received a copy of the GNU General Public License
16 #  along with SALOME HYDRO module.  If not, see <http://www.gnu.org/licenses/>.
17
18 import sys
19 import os
20 import traceback
21 import logging
22
23 from PyQt5.QtWidgets import QMessageBox, QApplication, QDialog
24
25 import salome
26 import SALOME
27 import SalomePyQt
28 sgPyQt = SalomePyQt.SalomePyQt()
29 from salome.kernel.studyedit import getStudyEditor
30 from salome.kernel.logger import Logger
31 from salome.kernel import termcolor
32 logger = Logger("HYDROGUI", color = termcolor.BLUE)
33 #logger.setLevel(logging.ERROR)
34
35 import HYDROSOLVER_ORB
36
37 from salome.hydro.interpolz_gui import InterpolzDlg
38 from salome.hydro.assignStrickler_gui import assignStricklerDlg
39 from salome.hydro.gui_utils import HSGUIException, wait_cursor, \
40                                    get_and_check_selected_file_path
41 import salome.hydro.study as hydro_study
42 from salome.hydro.run_study.eficas.appli import EficasForRunStudyAppli
43 from salome.hydro.param_study.eficas.appli import EficasForParamStudyAppli
44 from salome.hydro.telma.eficas.appli import EficasForTelmaAppli
45 from salome.hydro.run_study.gui import create_case_study, \
46                                    run_selected_case_study, \
47                                    edit_selected_case_study, \
48                                    generate_job_for_selected_case_study
49 from eficasSalome import runEficas
50
51 from BndConditionsDialog import BoundaryConditionsDialog
52 from LiquidBoundariesDialog import LiquidBoundariesDialog
53 from BreachesDialog import BreachesDialog
54 from InitialConditionsDialog import InitialConditionsDialog
55
56 ################################################
57 # GUI context class
58 # Used to store actions, menus, toolbars, etc...
59 ################################################
60
61 class GUIcontext:
62   
63     # --- menus/toolbars/actions IDs
64     
65     HYDRO_MENU_ID = 90
66     CREATE_STUDY_ID = 951
67     EDIT_STUDY_ID = 952
68     RUN_STUDY_ID = 953
69     GEN_STUDY_BATCH_ID = 954
70
71     CREATE_TELMA_CAS_ID = 955
72     EDIT_TELMA_CAS_ID = 956
73
74     GENERATE_INTERPOLZ_PY_ID = 957
75     GENERATE_ASSIGNSTRICKLER_PY_ID = 958
76
77     # TODO Add create and edit ?
78     EDIT_BOUNDARY_CONDITIONS_FILE_ID = 959
79     EDIT_LIQUID_BOUNDARY_FILE_ID = 960
80     EDIT_BREACHES_FILE_ID = 961
81     EDIT_INITIAL_CONDITIONS_FILE_ID = 962
82
83     CREATE_PARAM_STUDY_ID = 963
84     EDIT_PARAM_STUDY_ID = 964
85     GEN_PARAM_STUDY_PYTHON_ID = 965
86     GEN_PARAM_STUDY_YACS_ID = 966
87
88     def __init__(self):
89         # create top-level menu
90         mid = sgPyQt.createMenu("Hydro", -1, GUIcontext.HYDRO_MENU_ID,
91                                 sgPyQt.defaultMenuGroup())
92         # create toolbar
93         tid = sgPyQt.createTool("Hydro")
94         # create actions and fill menu and toolbar with actions
95         act = sgPyQt.createAction(\
96                 GUIcontext.GENERATE_INTERPOLZ_PY_ID,
97                 "Generate interpolz.py",
98                 "Generate interpolz.py",
99                 "Generate interpolation script for altitudes",
100                 "generate_interpolz_py.png")
101         sgPyQt.createMenu(act, mid)
102         sgPyQt.createTool(act, tid)
103
104         act = sgPyQt.createAction(\
105                 GUIcontext.GENERATE_ASSIGNSTRICKLER_PY_ID,
106                 "Generate assignStrickler.py",
107                 "Generate assignStrickler.py",
108                 "Generate assignation script for bottom friction coefficients",
109                  "generate_interpolz_py.png" )
110         sgPyQt.createMenu( act, mid )
111         sgPyQt.createTool( act, tid )
112         
113         act = sgPyQt.createSeparator()
114
115         act = sgPyQt.createAction(\
116                 GUIcontext.EDIT_BOUNDARY_CONDITIONS_FILE_ID,
117                 "Edit boundary conditions file",
118                 "Edit boundary conditions file",
119                 "Create/edit the boundary conditions file for Telemac",
120                 "edit_boundary_conditions_file.png")
121         sgPyQt.createMenu(act, mid)
122         sgPyQt.createTool(act, tid)
123
124         act = sgPyQt.createAction(\
125                 GUIcontext.EDIT_LIQUID_BOUNDARY_FILE_ID,
126                 "Edit liquid boundary conditions file",
127                 "Edit liquid boundary conditions file",
128                 "Create/edit the liquid boundary conditions file for Telemac",
129                 "edit_liquid_boundary_conditions_file.png")
130         sgPyQt.createMenu(act, mid)
131         sgPyQt.createTool(act, tid)
132
133         act = sgPyQt.createAction(\
134                 GUIcontext.EDIT_BREACHES_FILE_ID,
135                 "Edit breaches file",
136                 "Edit breaches file",
137                 "Create/edit the breaches file for Telemac",
138                 "edit_breaches_file.png")
139         sgPyQt.createMenu(act, mid)
140         sgPyQt.createTool(act, tid)
141         
142         act = sgPyQt.createAction(\
143                 GUIcontext.EDIT_INITIAL_CONDITIONS_FILE_ID,
144                 "Edit initial conditions file",
145                 "Edit initial conditions file",
146                 "Create/edit the initial conditions file for Telemac",
147                 "edit_boundary_conditions_file.png" )
148         sgPyQt.createMenu( act, mid )
149         sgPyQt.createTool( act, tid )
150
151         act = sgPyQt.createAction(\
152                 GUIcontext.CREATE_TELMA_CAS_ID,
153                 "Edit cas file (English)",
154                 "Edit cas file (English)",
155                 "Create/edit act .cas file for Telemac (English)",
156                 "create_telma_cas.png")
157         sgPyQt.createMenu(act, mid)
158         sgPyQt.createTool(act, tid)
159
160         act = sgPyQt.createAction(\
161                 GUIcontext.CREATE_STUDY_ID,
162                 "Execute a steering file",
163                 "Execute a steering file",
164                 "Fill formular for a normal execution",
165                 "create_study.png")
166
167         sgPyQt.createMenu(act, mid)
168         sgPyQt.createTool(act, tid)
169
170         act = sgPyQt.createAction(\
171                 GUIcontext.CREATE_PARAM_STUDY_ID,
172                 "Create Parameter Study",
173                 "Create Parameter Study",
174                 "Create act new Parameter Study",
175                 "create_param_study.png")
176         sgPyQt.createMenu(act, mid)
177         sgPyQt.createTool(act, tid)
178
179         act = sgPyQt.createSeparator()
180
181         # the following action are used in context popup
182
183         sgPyQt.createAction(\
184                 GUIcontext.EDIT_PARAM_STUDY_ID,
185                 "Edit param study",
186                 "Edit param study",
187                 "Edit study using python launcher")
188         sgPyQt.createAction(\
189                 GUIcontext.GEN_PARAM_STUDY_PYTHON_ID,
190                 "Generate Python script",
191                 "Generate Python script",
192                 "Generate act Python script from the eficas date")
193         sgPyQt.createAction(\
194                 GUIcontext.GEN_PARAM_STUDY_YACS_ID,
195                 "Generate YACS script",
196                 "Generate YACS script",
197                 "Generate act YACS script from the eficas date")
198
199         sgPyQt.createAction(\
200                 GUIcontext.RUN_STUDY_ID,
201                 "Compute study",
202                 "Compute study",
203                 "Compute study using python launcher")
204         sgPyQt.createAction(\
205                 GUIcontext.EDIT_STUDY_ID,
206                 "Edit study",
207                 "Edit study",
208                 "Edit the selected study")
209         sgPyQt.createAction(\
210                 GUIcontext.GEN_STUDY_BATCH_ID,
211                 "Generate batch job",
212                 "Generate batch job",
213                 "Generate a batch job to run the selected study")
214
215         sgPyQt.createAction(\
216                 GUIcontext.EDIT_TELMA_CAS_ID,
217                 "Edit Steering file",
218                 "Edit Steering file",
219                 "Edit a Telemac-Mascaret steering file")
220
221
222 ################################################
223 # Global variables
224 ################################################
225
226 # study-to-context map
227 __study2context__ = {}
228 # current context
229 __current_context__ = None
230 # object counter
231 __objectid__ = 0
232
233 ################################################
234 # Internal methods
235 ################################################
236
237 ###
238 # get active study ID
239 ###
240 #def _getStudyId():
241     #return sgPyQt.getStudyId()
242
243 ###
244 # get active study
245 ###
246 #def _getStudy():
247     #studyId = _getStudyId()
248     #study = getStudyManager().GetStudyByID(studyId)
249     #return study
250
251 ###
252 # returns True if object has children
253 ###
254 def _hasChildren(sobj):
255     if sobj:
256         study = salome.myStudy
257         iter  = study.NewChildIterator(sobj)
258         while iter.More():
259             name = iter.Value().GetName()
260             if name:
261                 return True
262             iter.Next()
263             pass
264         pass
265     return False
266
267 ###
268 # get current GUI context
269 ###
270 def _getContext():
271     global __current_context__
272     return __current_context__
273
274 ###
275 # set and return current GUI context
276 # study ID is passed as parameter
277 ###
278 def _setContext():
279     global __study2context__, __current_context__
280     #if studyID not in __study2context__:
281         #__study2context__[studyID] = GUIcontext()
282         #pass
283     #__current_context__ = __study2context__[studyID]
284     __current_context__ = GUIcontext()
285     return __current_context__
286
287 ###
288 # increment object counter in the map
289 ###
290 def _incObjToMap(m, id):
291     if id not in m: m[id] = 0
292     m[id] += 1
293     pass
294
295 ################################################
296 # Callback functions
297 ################################################
298
299 # called when module is activated
300 # returns True if activating is successfull and False otherwise
301 def activate():
302     ctx = _setContext()
303     return True
304
305 # called when module is deactivated
306 def deactivate():
307     pass
308
309 # called when active study is changed
310 # active study ID is passed as parameter
311 def activeStudyChanged():
312     ctx = _setContext()
313     pass
314
315 # called when popup menu is invoked
316 # popup menu and menu context are passed as parameters
317 def createPopupMenu(popup, context):
318     ed = getStudyEditor()
319     _setContext()
320     if salome.sg.SelectedCount() == 1:
321         # one object is selected
322         sobj = ed.study.FindObjectID(salome.sg.getSelected(0))
323         print("sobj: %s"%sobj) # strange bug with sobj is None when right clic on 3Dview in HYDROSOLVER used after HYDRO (generate AssignStrickler)
324         if sobj:
325             selectedType = ed.getTypeId(sobj)
326             if selectedType == hydro_study.TELMA_TYPE_ID:
327                 popup.addAction(sgPyQt.action(GUIcontext.EDIT_TELMA_CAS_ID))
328             elif selectedType == hydro_study.PARAM_STUDY_TYPE_ID:
329                 popup.addAction(sgPyQt.action(GUIcontext.EDIT_PARAM_STUDY_ID))
330                 popup.addAction(sgPyQt.action(GUIcontext.GEN_PARAM_STUDY_PYTHON_ID))
331                 popup.addAction(sgPyQt.action(GUIcontext.GEN_PARAM_STUDY_YACS_ID))
332             elif selectedType == hydro_study.STUDY_TYPE_ID:
333                 popup.addAction(sgPyQt.action(GUIcontext.EDIT_STUDY_ID))
334                 popup.addAction(sgPyQt.action(GUIcontext.RUN_STUDY_ID))
335                 popup.addAction(sgPyQt.action(GUIcontext.GEN_STUDY_BATCH_ID))
336
337 # called when GUI action is activated
338 # action ID is passed as parameter
339 def OnGUIEvent(commandID):
340     try:
341         dict_command[commandID]()
342     except HSGUIException as exc:
343         QMessageBox.critical(sgPyQt.getDesktop(),
344                                    QApplication.translate("OnGUIEvent", "Error"),
345                                    str(exc))
346     except:
347         logger.exception("Unhandled exception caught in HYDROSOLVER GUI")
348         msg = QApplication.translate("OnGUIEvent",
349             "Unhandled error happened in HYDROSOLVER module. Please report a bug on "
350             '<a href="https://forge-pleiade.der.edf.fr/projects/salome-rex/issues">SALOME bugtracker</a>, '
351             'category "HYDROSOLVER", describing how you got there and including the following traceback:')
352         msgBox = QMessageBox(QMessageBox.Critical,
353                                    QApplication.translate("OnGUIEvent", "Error"),
354                                    msg,
355                                    parent=sgPyQt.getDesktop())
356         msgBox.setDetailedText(traceback.format_exc())
357         msgBox.exec_()
358
359 ################################################
360 # GUI actions implementation
361 ################################################
362
363 ###
364 # Open Eficas for a new parametric study
365 ###
366 def create_param_study():
367     EficasForParamStudyAppli()
368 ###
369 # Open Eficas to edit a new parametric study
370 ###
371 def edit_param_study():
372     EficasForParamStudyAppli(get_and_check_selected_file_path())
373
374 ###
375 # Generate a python script from the eficas file
376 ###
377 def generate_param_study_python():
378     try:
379         with wait_cursor:
380             ed = hydro_study.HydroStudyEditor()
381             sobj = get_and_check_selected_file_path()
382             ed.generate_study_script(sobj)
383     except SALOME.SALOME_Exception as exc:
384         salome.sg.updateObjBrowser()
385         msg = str(QApplication.translate("generate_telemac2d_python",
386                       "An error happened while trying to generate telemac2d Python script:"))
387         msg += "\n" + exc.details.text
388         raise HSGUIException(msg)
389
390 ###
391 # Generate a python script from the eficas file
392 ###
393 def generate_param_study_yacs():
394     try:
395         with wait_cursor:
396             ed = hydro_study.HydroStudyEditor()
397             sobj = get_and_check_selected_file_path()
398             ed.generate_study_yacs(sobj)
399     except SALOME.SALOME_Exception as exc:
400         salome.sg.updateObjBrowser()
401         msg = str(QApplication.translate("generate_telemac2d_yacs",
402                       "An error happened while trying to generate telemac2d Python script:"))
403         msg += "\n" + exc.details.text
404         raise HSGUIException(msg)
405
406 def open_schema_in_yacs():
407     ed = getStudyEditor()
408     sobj = ed.study.FindObjectID(salome.sg.getSelected(0))
409     filename = sobj.GetComment()
410     if filename.endswith(".comm"):
411         filename = filename[:-5] + ".xml"
412     if not os.path.isfile(filename):
413         raise HSGUIException(QApplication.translate("open_schema_in_yacs",
414                                   "Schema file %1 does not exist").arg(filename))
415     yg = salome.ImportComponentGUI("YACS")
416     yg.loadSchema(filename)
417
418 ###
419 # Open dialog for boundary conditions edition
420 ###
421 def edit_boundary_conditions_file():
422     desktop = sgPyQt.getDesktop()
423     dlg = BoundaryConditionsDialog(desktop)
424     dlg.exec_()
425
426 ###
427 # Open dialog for liquid boundaries edition
428 ###
429 def edit_liquid_boundaries_file():
430     desktop = sgPyQt.getDesktop()
431     dlg = LiquidBoundariesDialog(desktop)
432     dlg.exec_()
433
434 ###
435 # Open dialog for breaches edition
436 ###
437 def edit_breaches_file():
438     desktop = sgPyQt.getDesktop()
439     dlg = BreachesDialog(desktop)
440     dlg.exec_()
441
442 ###
443 # Open dialog for initial conditions edition
444 ###
445 def edit_initial_conditions_file():
446     desktop = sgPyQt.getDesktop()
447     dlg = InitialConditionsDialog(desktop)
448     dlg.exec_()
449
450 ###
451 # Open dialog for liquid boundary conditions edition
452 ###
453 def edit_liquid_boundary_file():
454     # TODO: Implement gui
455     QMessageBox.warning(sgPyQt.getDesktop(),
456                         "",
457                         "Liquid boundary file handling not implemented yet")
458     return
459
460 ###
461 # Open dialog for breaches file edition
462 ###
463 def edit_breaches_file():
464     # TODO: Implement gui
465     QMessageBox.warning(sgPyQt.getDesktop(),
466                         "",
467                         "Breaches file handling not implemented yet")
468     return
469
470 ###
471 # Open dialog for interpolz.py script generation
472 ###
473 def generate_interpolz_py():
474     desktop = sgPyQt.getDesktop()
475     dlg = InterpolzDlg(desktop)
476     dlg.show()
477
478 ###
479 # Open dialog for assignStrickler.py script generation
480 ###
481 def generate_assignStrickler_py():
482     desktop = sgPyQt.getDesktop()
483     dlg = assignStricklerDlg(desktop)
484     dlg.show()
485
486 ###
487 # Open dialog for boundary conditions edition
488 ###
489 def generate_interpolks_py():
490     QMessageBox.warning(sgPyQt.getDesktop(),
491                         "",
492                         "Generation of interpolks.py not implemented yet")
493     return
494
495 ###
496 # Open dialog for creation of steering file
497 ###
498 def create_telma_cas():
499     EficasForTelmaAppli(code='TELEMAC', lang='en')
500
501 ###
502 # Open dialog for edition of steering file
503 ###
504 def edit_telma_cas():
505     # TODO: See how to detect module
506     EficasForTelmaAppli(fichier=get_and_check_selected_file_path(),
507                         code='TELEMAC', lang='en')
508
509 ###
510 # Commands dictionary
511 ###
512 dict_command = {
513     GUIcontext.CREATE_STUDY_ID: create_case_study,
514     GUIcontext.EDIT_STUDY_ID: edit_selected_case_study,
515     GUIcontext.RUN_STUDY_ID: run_selected_case_study,
516     GUIcontext.GEN_STUDY_BATCH_ID: generate_job_for_selected_case_study,
517     GUIcontext.CREATE_TELMA_CAS_ID: create_telma_cas,
518     GUIcontext.EDIT_TELMA_CAS_ID: edit_telma_cas,
519     GUIcontext.GENERATE_INTERPOLZ_PY_ID: generate_interpolz_py,
520     GUIcontext.GENERATE_ASSIGNSTRICKLER_PY_ID: generate_assignStrickler_py,
521     GUIcontext.EDIT_LIQUID_BOUNDARY_FILE_ID: edit_liquid_boundary_file,
522     GUIcontext.EDIT_BOUNDARY_CONDITIONS_FILE_ID: edit_boundary_conditions_file,
523     GUIcontext.EDIT_BREACHES_FILE_ID: edit_breaches_file,
524     GUIcontext.EDIT_INITIAL_CONDITIONS_FILE_ID: edit_initial_conditions_file,
525     GUIcontext.CREATE_PARAM_STUDY_ID: create_param_study,
526     GUIcontext.EDIT_PARAM_STUDY_ID: edit_param_study,
527     GUIcontext.GEN_PARAM_STUDY_PYTHON_ID: generate_param_study_python,
528     GUIcontext.GEN_PARAM_STUDY_YACS_ID: generate_param_study_yacs,
529     }