Salome HOME
16a54666bbdb41734ee0f5339638cb86f984ad39
[samples/genericsolver.git] / src / GENERICSOLVERGUI / GENERICSOLVERGUI.py
1 #  Copyright (C) 2009-2014 EDF R&D
2 #
3 #  This library is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU Lesser General Public
5 #  License as published by the Free Software Foundation; either
6 #  version 2.1 of the License.
7 #
8 #  This library is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 #  Lesser General Public License for more details.
12 #
13 #  You should have received a copy of the GNU Lesser General Public
14 #  License along with this library; if not, write to the Free Software
15 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 #
17 #  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 #
19
20 # $Id$
21 #
22
23 import traceback
24 import os
25 import logging
26
27 from PyQt4 import QtCore, QtGui
28
29 import salome
30 import SALOME
31 import SALOME_TYPES
32 from salome.kernel.studyedit import getStudyEditor
33 from salome.kernel.parametric import study_exchange_vars
34
35 # Get SALOME PyQt interface
36 import SalomePyQt
37 sgPyQt = SalomePyQt.SalomePyQt()
38
39 from salome.kernel.logger import Logger
40 from salome.kernel import termcolor
41 logger = Logger("GENERICSOLVERGUI", color = termcolor.RED_FG)
42 logger.setLevel(logging.INFO)
43
44 salome.salome_init()
45
46 VARS_ICON = "icon_variables.png"
47 SOLVER_ENGINE_NAME = "DEVIATION"
48
49 ################################################
50 # GUI context class
51 # Used to store actions, menus, toolbars, etc...
52 ################################################
53
54 class GUIcontext:
55     # module name
56     MODULE_NAME            = "GENERICSOLVER"
57     # module icon
58     MODULE_PIXMAP          = "GENERICSOLVER_small.png"
59     # data objects IDs
60     MODULE_ID              = 1000
61     CASE_ID                = 1020
62     VARIABLE_ID            = 1030
63     # menus/toolbars/actions IDs
64     GENERICSOLVER_MENU_ID  = 90
65     SOLVER_ID              = 941
66     OPTIONS_ID             = 943
67     OPTION_1_ID            = 944
68     OPTION_2_ID            = 945
69     OPTION_3_ID            = 946
70     DELETE_ALL_ID          = 951
71     CREATE_CASE_ID         = 955
72     SET_VALUE_ID           = 956
73     # default object name
74     DEFAULT_CASE_NAME      = "Case"
75
76     # constructor
77     def __init__( self ):
78         # create top-level menu
79         mid = sgPyQt.createMenu( "Genericsolver", -1, GUIcontext.GENERICSOLVER_MENU_ID,
80                                  sgPyQt.defaultMenuGroup() )
81         # create toolbar
82         tid = sgPyQt.createTool( "Genericsolver" )
83         # create actions and fill menu and toolbar with actions
84         a = sgPyQt.createAction( GUIcontext.CREATE_CASE_ID, "Create case", "Create case",
85                                  "Create a new case", "CaseGENERICSOLVER.png" )
86         sgPyQt.createMenu( a, mid )
87         sgPyQt.createTool( a, tid )
88         a = sgPyQt.createSeparator()
89         sgPyQt.createMenu( a, mid )
90         ag = sgPyQt.createActionGroup( GUIcontext.OPTIONS_ID )
91         ag.setText( "Creation mode" )
92         ag.setUsesDropDown(True)
93         a = sgPyQt.createAction( GUIcontext.OPTION_1_ID, "Default name", "Default name",
94                                  "Use default name for the objects" )
95         a.setCheckable( True )
96         ag.add( a )
97         a = sgPyQt.createAction( GUIcontext.OPTION_2_ID, "Generate name", "Generate name",
98                                  "Generate name for the objects" )
99         a.setCheckable( True )
100         ag.add( a )
101         a = sgPyQt.createAction( GUIcontext.OPTION_3_ID, "Ask name", "Ask name",
102                                  "Request object name from the user" )
103         a.setCheckable( True )
104         ag.add( a )
105         sgPyQt.createMenu( ag, mid )
106         sgPyQt.createTool( ag, tid )
107         default_mode = sgPyQt.integerSetting( "GENERICSOLVER", "creation_mode", 0 )
108         sgPyQt.action( GUIcontext.OPTION_1_ID + default_mode ).setChecked( True )
109         # the following action are used in context popup
110         a = sgPyQt.createAction( GUIcontext.DELETE_ALL_ID, "Delete all", "Delete all",
111                                  "Delete all objects" )
112         a = sgPyQt.createAction( GUIcontext.SET_VALUE_ID,  "Set value",  "Set Value",
113                                  "Set a new value to variable" )
114         a = sgPyQt.createAction( GUIcontext.SOLVER_ID, "Run Solver", "Run Solver",
115                                  "Run Solver on selected case", "ExecGENERICSOLVER.png" )
116
117 ################################################
118 # Global variables
119 ################################################
120
121 # study-to-context map
122 __study2context__   = {}
123 # current context
124 __current_context__ = None
125 # object counter
126 __id__ = 0
127
128 ################################################
129 # Internal methods
130 ################################################
131
132 ###
133 # get active study ID
134 ###
135 def getStudyId():
136     return sgPyQt.getStudyId()
137
138 ###
139 # get active study
140 ###
141 def getStudy():
142     studyId = getStudyId()
143     study = salome.myStudyManager.GetStudyByID( studyId )
144     return study
145
146 ###
147 # returns True if object has children
148 ###
149 def hasChildren( sobj ):
150     if sobj:
151         study = getStudy()
152         iter  = study.NewChildIterator( sobj )
153         while iter.More():
154             name = iter.Value().GetName()
155             if name:
156                 return True
157             iter.Next()
158             pass
159         pass
160     return False
161
162 ###
163 # get current GUI context
164 ###
165 def getContext():
166     global __current_context__
167     return __current_context__
168
169 ###
170 # set and return current GUI context
171 # study ID is passed as parameter
172 ###
173 def setContext( studyID ):
174     global __study2context__, __current_context__
175     if not __study2context__.has_key(studyID):
176         __study2context__[studyID] = GUIcontext()
177         pass
178     __current_context__ = __study2context__[studyID]
179     return __current_context__
180
181 ################################################
182 # Callback functions
183 ################################################
184
185 # called when module is initialized
186 # perform initialization actions
187 def initialize():
188     logger.debug("GENERICSOLVERGUI.initialize() : study : %d" % getStudyId())
189     # set default preferences values
190     if not sgPyQt.hasSetting( "GENERICSOLVER", "def_case_name"):
191         sgPyQt.addSetting( "GENERICSOLVER", "def_case_name", GUIcontext.DEFAULT_CASE_NAME )
192     if not sgPyQt.hasSetting( "GENERICSOLVER", "creation_mode"):
193         sgPyQt.addSetting( "GENERICSOLVER", "creation_mode", 0 )
194     pass
195
196 # called when module is initialized
197 # return map of popup windows to be used by the module
198 def windows():
199     logger.debug("GENERICSOLVERGUI.windows() : study : %d" % getStudyId())
200     wm = {}
201     wm[SalomePyQt.WT_ObjectBrowser] = QtCore.Qt.LeftDockWidgetArea
202     wm[SalomePyQt.WT_PyConsole]     = QtCore.Qt.BottomDockWidgetArea
203     return wm
204
205 # called when module is initialized
206 # return list of 2d/3d views to be used ny the module
207 def views():
208     logger.debug("GENERICSOLVERGUI.views() : study : %d" % getStudyId())
209     return []
210
211 # called when module is initialized
212 # export module's preferences
213 def createPreferences():
214     logger.debug("GENERICSOLVERGUI.createPreferences() : study : %d" % getStudyId())
215     gid = sgPyQt.addPreference( "General" )
216     gid = sgPyQt.addPreference( "Object creation", gid )
217     pid = sgPyQt.addPreference( "Default case name",  gid, SalomePyQt.PT_String,
218                                 "GENERICSOLVER", "def_case_name" )
219     pid = sgPyQt.addPreference( "Default creation mode", gid, SalomePyQt.PT_Selector,
220                                 "GENERICSOLVER", "creation_mode" )
221     strings = QtCore.QStringList()
222     strings.append( "Default name" )
223     strings.append( "Generate name" )
224     strings.append( "Ask name" )
225     indexes = []
226     indexes.append( QtCore.QVariant(0) )
227     indexes.append( QtCore.QVariant(1) )
228     indexes.append( QtCore.QVariant(2) )
229     sgPyQt.setPreferenceProperty( pid, "strings", QtCore.QVariant( strings ) )
230     sgPyQt.setPreferenceProperty( pid, "indexes", QtCore.QVariant( indexes ) )
231     pass
232
233 # called when module is activated
234 # returns True if activating is successfull and False otherwise
235 def activate():
236     logger.debug("GENERICSOLVERGUI.activate() : study : %d" % getStudyId())
237     ctx = setContext( getStudyId() )
238     return True
239
240 # called when module is deactivated
241 def deactivate():
242     logger.debug("GENERICSOLVERGUI.deactivate() : study : %d" % getStudyId())
243     pass
244
245 # called when active study is changed
246 # active study ID is passed as parameter
247 def activeStudyChanged( studyID ):
248     logger.debug("GENERICSOLVERGUI.activeStudyChanged(): study : %d" % studyID)
249     ctx = setContext( getStudyId() )
250     pass
251
252 # called when popup menu is invoked
253 # popup menu and menu context are passed as parameters
254 def createPopupMenu( popup, context ):
255     logger.debug("GENERICSOLVERGUI.createPopupMenu(): context = %s" % context)
256     ed = getStudyEditor()
257     ctx = setContext(ed.studyId)
258     if salome.sg.SelectedCount() == 1:    # one object is selected
259         typeId = ed.getTypeId(ed.study.FindObjectID(salome.sg.getSelected(0)))
260         if typeId == GUIcontext.MODULE_ID:
261             # menu for component
262             popup.addAction( sgPyQt.action( GUIcontext.DELETE_ALL_ID ) )
263         elif typeId == GUIcontext.CASE_ID:
264             # menu for case
265             popup.addAction( sgPyQt.action( GUIcontext.SOLVER_ID ) )
266         elif typeId == GUIcontext.VARIABLE_ID:
267             # menu for case
268             popup.addAction( sgPyQt.action( GUIcontext.SET_VALUE_ID ) )
269
270 # called when GUI action is activated
271 # action ID is passed as parameter
272 def OnGUIEvent( commandID ):
273     logger.debug("GENERICSOLVERGUI.OnGUIEvent(): command = %d" % commandID)
274     if dict_command.has_key( commandID ):
275         try:
276             dict_command[commandID]()
277         except:
278             traceback.print_exc()
279     elif commandID in (GUIcontext.OPTION_1_ID, GUIcontext.OPTION_2_ID, GUIcontext.OPTION_3_ID):
280       pass  # Option selection does not trigger a method
281     else:
282         logger.error("The command is not implemented: %d" % commandID)
283     pass
284
285 # called when module's preferences are changed
286 # preference's resources section and setting name are passed as parameters
287 def preferenceChanged( section, setting ):
288     logger.debug("GENERICSOLVERGUI.preferenceChanged(): %s / %s" % ( section, setting ))
289     pass
290
291 # called when active view is changed
292 # view ID is passed as parameter
293 def activeViewChanged( viewID ):
294     logger.debug("GENERICSOLVERGUI.activeViewChanged(): %d" % viewID)
295     pass
296
297 # called when active view is cloned
298 # cloned view ID is passed as parameter
299 def viewCloned( viewID ):
300     logger.debug("GENERICSOLVERGUI.viewCloned(): %d" % viewID)
301     pass
302
303 # called when active view is viewClosed
304 # view ID is passed as parameter
305 def viewClosed( viewID ):
306     logger.debug("GENERICSOLVERGUI.viewClosed(): %d" % viewID)
307     pass
308
309 ################################################
310 # GUI actions implementation
311 ################################################
312
313 ###
314 # Create a deterministic case
315 ###
316 def CreateCase():
317     logger.debug("GENERICSOLVERGUI.CreateCase : enter")
318     default_case_name = str( sgPyQt.stringSetting( "GENERICSOLVER", "def_case_name",
319                                                    GUIcontext.DEFAULT_CASE_NAME ).trimmed() )
320     global __id__
321     try:
322         if sgPyQt.action( GUIcontext.OPTION_3_ID ).isChecked():
323             # request object name from the user
324             name, ok = QtGui.QInputDialog.getText(sgPyQt.getDesktop(),
325                                                   "Create case",
326                                                   "Enter case name:",
327                                                   QtGui.QLineEdit.Normal,
328                                                   default_case_name )
329             if not ok: return
330             name = str( name.trimmed() )
331         elif sgPyQt.action( GUIcontext.OPTION_2_ID ).isChecked():
332             # generate object name
333             __id__  = __id__ + 1
334             name = "%s %d" % ( default_case_name, __id__ )
335         else:
336             name = default_case_name
337             pass
338         pass
339     except:
340         # generate object name
341         __id__  = __id__ + 1
342         name = "%s %d" % ( default_case_name, __id__ )
343         pass
344     if not name: return
345     ed = getStudyEditor()
346     father = ed.findOrCreateComponent(GUIcontext.MODULE_NAME, icon = GUIcontext.MODULE_PIXMAP)
347     ed.setTypeId(father, GUIcontext.MODULE_ID)
348     case = ed.findItem(father, name)
349     if case is None:
350         case = ed.createItem(father, name, typeId = GUIcontext.CASE_ID)
351         varE = ed.createItem(case, "E", typeId = GUIcontext.VARIABLE_ID)
352         ed.setAttributeValue(varE, "AttributeReal", 210.e9)
353         varF = ed.createItem(case, "F", typeId = GUIcontext.VARIABLE_ID)
354         ed.setAttributeValue(varF, "AttributeReal", 1000.)
355         varL = ed.createItem(case, "L", typeId = GUIcontext.VARIABLE_ID)
356         ed.setAttributeValue(varL, "AttributeReal", 1.5)
357         varI = ed.createItem(case, "I", typeId = GUIcontext.VARIABLE_ID)
358         ed.setAttributeValue(varI, "AttributeReal", 2.e-6)
359         
360         inputVarList = [study_exchange_vars.Variable("E"),
361                         study_exchange_vars.Variable("F"),
362                         study_exchange_vars.Variable("L"),
363                         study_exchange_vars.Variable("I")]
364         outputVarList = [study_exchange_vars.Variable("dev")]
365         exchVars = study_exchange_vars.ExchangeVariables(inputVarList, outputVarList)
366         study_exchange_vars.createSObjectForExchangeVariables(case, exchVars, icon = VARS_ICON)
367
368     salome.sg.updateObjBrowser( True )
369     logger.debug("GENERICSOLVERGUI.CreateCase : exit")
370
371 ###
372 # Run the SOLVER
373 ###
374 def RunSOLVER():
375     ed = getStudyEditor()
376     # Get selected case
377     entry = salome.sg.getSelected(0)
378     assert entry is not None
379     sobj = ed.study.FindObjectID(entry)
380     assert sobj
381     assert ed.getTypeId(sobj) == GUIcontext.CASE_ID
382     assert hasChildren(sobj)
383
384     # Initialize and run the solver
385     solver_engine = salome.lcc.FindOrLoadComponent("FactoryServer", SOLVER_ENGINE_NAME)
386     solver_engine.Init(getStudyId(), entry)
387
388     param_input = SALOME_TYPES.ParametricInput(inputVarList = [],
389                                                outputVarList = ["dev"],
390                                                inputValues = [[[]]],
391                                                specificParameters = [])
392     error = None
393
394     try:
395         param_output = solver_engine.Exec(param_input)
396     except SALOME.SALOME_Exception, exc:
397         error = exc.details.text
398
399     solver_engine.Finalize()
400     
401     if error is not None:
402         QtGui.QMessageBox.critical(sgPyQt.getDesktop(), "Error", error)
403     elif param_output.returnCode != 0:
404         QtGui.QMessageBox.critical(sgPyQt.getDesktop(), "Error", param_output.errorMessage)
405     else:
406         # Add result to deterministic case in object browser
407         var = ed.findOrCreateItem(sobj, "Deviation")
408         ed.setAttributeValue(var, "AttributeReal", param_output.outputValues[0][0][0][0])
409         salome.sg.updateObjBrowser(0)
410
411 ###
412 # Delete all objects
413 ###
414 def DeleteAll():
415     study = getStudy()
416     father = study.FindComponent( GUIcontext.MODULE_NAME )
417     if father:
418         iter = study.NewChildIterator( father )
419         builder = study.NewBuilder()
420         while iter.More():
421             sobj = iter.Value()
422             iter.Next()
423             builder.RemoveObjectWithChildren( sobj )
424             pass
425         salome.sg.updateObjBrowser( True )
426         pass
427     pass
428
429 ###
430 # Set value to variable
431 ###
432 def SetValue():
433     ed = getStudyEditor()
434     entry = salome.sg.getSelected(0)
435     assert entry is not None
436     sobj = ed.study.FindObjectID(entry)
437     assert sobj
438     oldvalue = ed.getAttributeValue(sobj, "AttributeReal", 0.0)
439     name, ok = QtGui.QInputDialog.getText(sgPyQt.getDesktop(),
440                                           "Set a value",
441                                           "Enter new value:",
442                                           QtGui.QLineEdit.Normal,
443                                           str(oldvalue) )
444     value = float( name.trimmed() )
445     if not ok or not value: return
446     ed.setAttributeValue(sobj, "AttributeReal", value)
447     salome.sg.updateObjBrowser(0)
448
449 ###
450 # Commands dictionary
451 ###
452 dict_command = {
453     GUIcontext.SOLVER_ID        : RunSOLVER,
454     GUIcontext.CREATE_CASE_ID   : CreateCase,
455     GUIcontext.DELETE_ALL_ID    : DeleteAll,
456     GUIcontext.SET_VALUE_ID     : SetValue,
457     }