Salome HOME
Revert "Synchronize adm files"
[modules/med.git] / src / MEDOP / gui / WorkspaceController.cxx
1 // Copyright (C) 2007-2014  CEA/DEN, 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, or (at your option) any later version.
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 // Author : Guillaume Boulant (EDF)
21
22 #include "WorkspaceController.hxx"
23 #include "QtHelper.hxx"
24 #include "MEDOPFactoryClient.hxx"
25 #include "XmedDataModel.hxx"
26 #include "DlgAlias.hxx"
27
28 #include <SALOMEconfig.h>
29 #include CORBA_CLIENT_HEADER(MEDEventListener)
30
31 #include <SalomeApp_Application.h>
32 #include <SALOME_LifeCycleCORBA.hxx>
33 #include <SUIT_FileDlg.h>
34 #include <SUIT_Desktop.h>
35
36 /*!
37  * This class defines a DockWidget plugged in the SALOME application,
38  * and containing a tree view for rendering a hierarchical data
39  * model. This datamodel contains the objects used in the workspace.
40  */
41 WorkspaceController::WorkspaceController(StandardApp_Module * salomeModule)
42   : TreeGuiManager(salomeModule->getApp(), "Workspace")
43 {
44   _salomeModule = salomeModule;
45
46   this->tabifyDockWidgets(false);
47
48   // -------------------------------------------------------------
49   // Setup the MEDEventListener to manage notification from the
50   // python console.
51
52   // We create a MEDEventListener CORBA object inside this GUI class
53   // with the role of listening events coming from the python console
54   // (or even the components if needed). The events arising in the
55   // python console are send as CORBA request to this CORBA
56   // servant. Then this object can process the event by notifying the
57   // GUI of something to update for example (using signals and slots
58   // of course).
59   _medEventListener = MEDEventListener_i::getInstance();
60   MEDOP::MEDEventListener_ptr medEventListenerServant = _medEventListener->_this();
61
62   // We store the IOR inside the MEDDataManager to share this data
63   // with other parts of the application, in particular the python
64   // console that could retrieve this IOR using the
65   // getEventListenerIOR() function of the MEDDataManager.
66   SalomeApp_Application * salomeApp = salomeModule->getApp();
67   const char * medEventListenerIOR =
68     salomeApp->orb()->object_to_string(medEventListenerServant);
69   MEDOPFactoryClient::getDataManager()->setEventListenerIOR(medEventListenerIOR);
70
71   // Connect the signals emitted from the MEDEventListener to slot of
72   // this class.
73   connect(_medEventListener, SIGNAL(medEventSignal(const MEDOP::MedEvent*)),
74     this, SLOT(processMedEvent(const MEDOP::MedEvent*)));
75   // >>> WARN:
76   // Note that this class must be mocked (Q_OBJECT + moc file
77   // generated from header file) so that to be able to connect a
78   // signal to a slot of this class.
79
80   // -------------------------------------------------------------
81   // Customize the treeview rendering the datamodel with specific
82   // action for the popup menu
83   this->getDataTreeView()->clearActions();
84   _actionIds.display    = this->getDataTreeView()->addAction(tr("VISUALIZE_SCALAR_MAP"));
85   _actionIds.useInTui   = this->getDataTreeView()->addAction(tr("USE_IN_CONSOLE"));
86   _actionIds.exportToPv = this->getDataTreeView()->addAction(tr("EXPORT_TO_PARAVIS"));
87   _actionIds.save       = this->getDataTreeView()->addAction(tr("SAVE_AS_MED"));
88   _actionIds.remove     = this->getDataTreeView()->addAction(tr("REMOVE_FROM_WORKSPACE"));
89
90   // -------------------------------------------------------------
91   // Initialize the python console. Note that this must be done at
92   // last because the setup will try to initiate a connection to the
93   // event listener.
94   _consoleDriver = new XmedConsoleDriver(salomeApp);
95   _consoleDriver->setup();
96 }
97
98 WorkspaceController::~WorkspaceController() {
99   MEDEventListener_i::release();
100 }
101
102 /**
103  * This creates the GUI actions for driving the Workspace. The
104  * WorkspaceController creates itself this actions and implements the
105  * connected slots.
106  */
107 void WorkspaceController::createActions() {
108
109   QString label   = tr("LAB_SAVE_WORKSPACE");
110   QString tooltip = tr("TIP_SAVE_WORKSPACE");
111   QString icon    = tr("ICO_WORKSPACE_SAVE");
112   int actionId = _salomeModule->createStandardAction(label,this,SLOT(OnSaveWorkspace()),icon,tooltip);
113   _salomeModule->addActionInToolbar(actionId);
114
115   label   = tr("LAB_CLEAN_WORKSPACE");
116   tooltip = tr("TIP_CLEAN_WORKSPACE");
117   icon    = tr("ICO_WORKSPACE_CLEAN");
118   actionId = _salomeModule->createStandardAction(label,this,SLOT(OnCleanWorkspace()),icon,tooltip);
119   _salomeModule->addActionInToolbar(actionId);
120 }
121
122 /*!
123  * Implementation of the slot processItemList inherited from TreeGuiManager
124  */
125 void WorkspaceController::processItemList(QStringList itemNameIdList, int actionId) {
126   if ( actionId == _actionIds.display ) {
127     STDLOG("WorkspaceController::processItemList: display");
128     this->_viewItemList(itemNameIdList);
129   }
130   else if ( actionId == _actionIds.useInTui ) {
131     STDLOG("WorkspaceController::processItemList: use");
132     this->_importItemList(itemNameIdList);
133   }
134   else if ( actionId == _actionIds.exportToPv ) {
135     STDLOG("WorkspaceController::processItemList: export");
136     this->_exportItemList(itemNameIdList);
137   }
138   else if ( actionId == _actionIds.save ) {
139     STDLOG("WorkspaceController::processItemList: save");
140     this->_saveItemList(itemNameIdList);
141   }
142   else if ( actionId == _actionIds.remove ) {
143     STDLOG("WorkspaceController::processItemList: remove");
144   }
145   else {
146     STDLOG("WorkspaceController::processItemList: ERR : action unknown ");
147   }
148 }
149
150 /*!
151  * This function import in the console all the fields associated to
152  * the model items of the specified list. "Import a fields" means
153  * "define a field proxy variable in the python context to manipulate
154  * the real field in the database".
155  */
156 void WorkspaceController::_importItemList(QStringList itemNameIdList) {
157   LOG("WorkspaceController: signal received : display item list "<<itemNameIdList);
158   QStringList::const_iterator it;
159   for (it = itemNameIdList.constBegin(); it != itemNameIdList.constEnd(); ++it) {
160     QString itemNameId = *it;
161     this->_importItem(itemNameId);
162   }
163 }
164
165 /*!
166  * This function is the unit function used to import field in the
167  * console (see _importItemList).
168  */
169 void WorkspaceController::_importItem(QString itemNameId) {
170   XmedDataModel * dataModel = (XmedDataModel *)this->getDataModel();
171   if ( dataModel == NULL ) {
172     LOG("No data model associated to this tree view");
173     return;
174   }
175
176   // We can request the dataModel to obtain the dataObject associated
177   // to this item (iteNameId is a TreeView id, Qt stuff only).
178   XmedDataObject * dataObject =
179     (XmedDataObject *)dataModel->getDataObject(QS2S(itemNameId));
180
181   if ( dataObject == NULL ) {
182     LOG("WorkspaceController: WARN! No data object associated to the item "<<itemNameId);
183     return;
184   }
185
186   // Then, we can request this data object to obtain the associated
187   // FieldHandler.
188   MEDOP::FieldHandler * fieldHandler = dataObject->getFieldHandler();
189   STDLOG("Field: mesh="<<fieldHandler->meshname<<" name="<<fieldHandler->fieldname);
190
191   // Finally, we can import the field
192   bool askForOptions = true;
193   _importFieldIntoConsole(fieldHandler, askForOptions);
194 }
195
196 /**
197  * This function import the specified field into the tui console. This
198  * means to define a field proxy variable in the python context to
199  * manipulate the field. We can raise a gui to specify some import
200  * options or simply specify the alias (i.e. the name of the python
201  * variable).
202  */
203 void WorkspaceController::_importFieldIntoConsole(MEDOP::FieldHandler * fieldHandler,
204               bool askForOptions,
205               const char * alias)
206 {
207   STDLOG("alias="<<alias);
208
209   // By default, the alias is the name of the field
210   QString *effectiveAlias;
211   if ( alias == NULL ) {
212     effectiveAlias = new QString(fieldHandler->fieldname);
213   }
214   else {
215     effectiveAlias = new QString(alias);
216   }
217
218   // We can propose to the user to specify some additionnal
219   // informations concerning what must be imported.
220   //
221   // In this version, we just ask the alias the field will be
222   // manipulated with. The default alias is the field name. This alias
223   // should be asked to the user to get a short name to manipulate.
224   if ( askForOptions ) {
225     DlgAlias dialog;
226     dialog.setAlias(*effectiveAlias);
227     int choice = dialog.exec();
228     if ( choice == QDialog::Rejected ) {
229       // The user decides to cancel the operation
230       return;
231     }
232     *effectiveAlias = dialog.getAlias();
233   }
234
235   //
236   // Then, the list of python commands can be written and executed to
237   // define the field in the console
238   //
239   QStringList commands;
240   commands+=QString("%1=xmed.fieldproxy.newFieldProxy(fieldHandlerId=%2)")
241     .arg(*effectiveAlias)
242     .arg(fieldHandler->id);
243
244   _consoleDriver->exec(commands);
245 }
246
247 /*!
248  * This function is a Qt slot connected to the signal medEventSignal
249  * emitted from the MEDEventListener. It processes events coming from
250  * the python console.
251  */
252 void WorkspaceController::processMedEvent(const MEDOP::MedEvent * event) {
253   STDLOG("WorkspaceController::processMedEvent");
254   STDLOG("fieldid  :"<<event->fieldid);
255
256   XmedDataModel * dataModel = (XmedDataModel *)this->getDataModel();
257   if ( dataModel == NULL ) {
258     STDLOG("No data model associated to this tree view");
259     return;
260   }
261
262   if ( event->type == MEDOP::EVENT_ADDNEW_FIELD ) {
263     STDLOG("add new field");
264     MEDOP::FieldHandler * fieldHandler =
265       MEDOPFactoryClient::getDataManager()->getFieldHandler(event->fieldid);
266
267     XmedDataObject * dataObject = (XmedDataObject *)dataModel->newDataObject();
268     dataObject->setFieldHandler(*fieldHandler);
269     this->getDataTreeModel()->addData(dataObject);
270   }
271
272 }
273
274 /*!
275  * This function save a list of fields in a med file. The med file
276  * name is requested to the user using a file chooser dialog box
277  */
278 void WorkspaceController::_saveItemList(QStringList itemNameIdList) {
279   XmedDataProcessor * dataProcessor = new XmedDataProcessor(this->getDataModel());
280   dataProcessor->process(itemNameIdList);
281   MEDOP::FieldIdList_var fieldIdList = dataProcessor->getResultingFieldIdList();
282   delete dataProcessor;
283
284   QStringList filter;
285   filter.append(tr("FILE_FILTER_MED"));
286   QString filename = SUIT_FileDlg::getFileName(_salomeModule->getApp()->desktop(),
287                                                "",
288                                                filter,
289                                                tr("SAVE_SELECTED_FIELDS"),
290                                                false);
291
292   if ( filename.isEmpty() ) return;
293
294   MEDOPFactoryClient::getDataManager()->saveFields(QCHARSTAR(filename), fieldIdList);
295 }
296
297 /**
298  * This function export the list of specified field item to PARAVIS
299  * module. This consists in create a med file gathering the selected
300  * items, then to import this file in PARAVIS, and finally to create a
301  * scalar map of the first item to start the job.
302  */
303 void WorkspaceController::_exportItemList(QStringList itemNameIdList) {
304   XmedDataProcessor * dataProcessor = new XmedDataProcessor(this->getDataModel());
305   dataProcessor->process(itemNameIdList);
306   MEDOP::FieldIdList_var fieldIdList = dataProcessor->getResultingFieldIdList();
307   delete dataProcessor;
308
309   // _GBO_ We use a temporary file to proceed with this export to
310   // paravis. I'm sure it could be better in a futur version or when I
311   // will get a better understanding of paravis API.
312   const char * tmpfilename = "/tmp/medop_export2paravis.med";
313   MEDOPFactoryClient::getDataManager()->saveFields(tmpfilename, fieldIdList);
314
315   // We import the whole file but create a scalar map for the first
316   // selected field only (it's just an export to continue the job in
317   // paravis)
318   XmedDataModel * dataModel = (XmedDataModel *)this->getDataModel();
319   if ( dataModel == NULL ) {
320     STDLOG("No data model associated to this tree view");
321     return;
322   }
323   QString itemNameId = itemNameIdList[0];
324   XmedDataObject * dataObject = (XmedDataObject *)dataModel->getDataObject(QS2S(itemNameId));
325   if ( dataObject == NULL ) {
326     LOG("WorkspaceController: WARN! No data object associated to the item "<<itemNameId);
327     return;
328   }
329   MEDOP::FieldHandler * fieldHandler = dataObject->getFieldHandler();
330   QStringList commands;
331   commands+=QString("from xmed.driver_pvis import pvis_scalarmap");
332   commands+=QString("pvis_scalarmap('%1','%2','%3',%4,%5)")
333     .arg(tmpfilename)
334     .arg(QString(fieldHandler->meshname))
335     .arg(QString(fieldHandler->fieldname))
336     .arg(fieldHandler->type)
337     .arg(fieldHandler->iteration);
338   _consoleDriver->exec(commands);
339
340 }
341
342
343 /*!
344  * This function sends a request to the SALOME data visualisation
345  * (module VISU or PARAVIS) for displaying a scalar map of the fields
346  * associated to the model items in the specified list.
347  *
348  */
349 void WorkspaceController::_viewItemList(QStringList itemNameIdList) {
350
351   // __GBO__: In this version, we consider only the first field in the selection
352   QString itemNameId = itemNameIdList[0];
353
354   XmedDataModel * dataModel = (XmedDataModel *)this->getDataModel();
355   if ( dataModel == NULL ) {
356     LOG("No data model associated to this tree view");
357     return;
358   }
359
360   // We can request the dataModel to obtain the dataObject associated
361   // to this item (iteNameId is a TreeView id, Qt stuff only).
362   XmedDataObject * dataObject =
363     (XmedDataObject *)dataModel->getDataObject(QS2S(itemNameId));
364   if ( dataObject == NULL ) {
365     LOG("WorkspaceController: WARN! No data object associated to the item "<<itemNameId);
366     return;
367   }
368
369   // Then, we can request this data object to obtain the associated
370   // FieldHandler.
371   MEDOP::FieldHandler * fieldHandler = dataObject->getFieldHandler();
372
373   // And finally, we can create the set of medop instructions to
374   // generate the scalar map on this field.
375   QStringList commands;
376   commands+=QString("view(get(%1))").arg(fieldHandler->id);
377   _consoleDriver->exec(commands);
378 }
379
380 /**
381  * This slot can process the event coming from the
382  * DatasourceController. The connection between the datasource signal
383  * and this slot is realized by the main class MEDOPModule.
384  */
385 void WorkspaceController::processDatasourceEvent(const DatasourceEvent * event) {
386   XmedDataModel * dataModel = (XmedDataModel *)this->getDataModel();
387   if ( dataModel == NULL ) {
388     STDLOG("No data model associated to this tree view");
389     return;
390   }
391
392   // >>>
393   // __GBO__ To know what to do we should test the type, because the
394   // object could be a mesh, a timeseries or a single field. We test
395   // here the case of a single field. Moreover, there could have
396   // options such that "change the underlying mesh".
397   // <<<
398
399   XmedDataObject * dataObject = event->objectdata;
400
401   if ( event->eventtype == DatasourceEvent::EVENT_IMPORT_OBJECT ) {
402     STDLOG("IMPORT object in workspace:\n"<<dataObject->toString());
403     // _GBO_ QUESTION: tag automatically the object as a peristant object ??
404     // We first add the data object to the internal data model
405     dataModel->addDataObject(dataObject);
406     // Then we request the tree view to consider this new object
407     this->getDataTreeModel()->addData(dataObject);
408   }
409   else if ( event->eventtype == DatasourceEvent::EVENT_USE_OBJECT ) {
410     STDLOG("USE object in workspace:\n"<<dataObject->toString());
411     // We first add the data object to the internal data model
412     dataModel->addDataObject(dataObject);
413     // Then we request the tree view to consider this new object
414     this->getDataTreeModel()->addData(dataObject);
415
416     // We define a proxy for this object in the tui console.
417     STDLOG("Define a proxy variable in the console with name : "<<QCHARSTAR(event->objectalias));
418     bool askForOptions = false;
419     _importFieldIntoConsole(dataObject->getFieldHandler(),
420           askForOptions,
421           QCHARSTAR(event->objectalias));
422   }
423   else if ( event->eventtype == DatasourceEvent::EVENT_VIEW_OBJECT ) {
424     QStringList commands;
425     commands+=QString("view(get(%1))").arg(dataObject->getFieldHandler()->id);
426     _consoleDriver->exec(commands);
427   }
428   else {
429     STDLOG("The event "<<event->eventtype<<" is not implemented yet");
430   }
431
432 }
433
434 void WorkspaceController::OnSaveWorkspace() {
435
436   // Dialog to get the filename where the workspace must be saved into
437   QStringList filter;
438   filter.append(tr("FILE_FILTER_MED"));
439
440   QString filename = SUIT_FileDlg::getFileName(_salomeModule->getApp()->desktop(),
441                                                "",
442                                                filter,
443                                                tr("SAVE_WORKSPACE_DATA"),
444                                                false);
445
446   if ( filename.isEmpty() ) return;
447
448   STDLOG("OnWorkspaceSave: save the workspace in the file " << QCHARSTAR(filename));
449   QStringList commands;
450   commands+=QString("save('%1')").arg(filename);
451   _consoleDriver->exec(commands);
452 }
453
454 #include <QMessageBox>
455 void WorkspaceController::OnCleanWorkspace() {
456   QMessageBox::warning(_salomeModule->getApp()->desktop(),
457            tr("NOT_IMPLEMENTED_YET"),
458            tr("FUNCTION_NOT_IMPLEMENTED"));
459 }