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