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