Salome HOME
[MEDCalc] add icons and menu for presentations
[modules/med.git] / src / MEDCalc / gui / DatasourceController.cxx
1 // Copyright (C) 2007-2016  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 "DatasourceController.hxx"
23 #include "DatasourceConstants.hxx"
24
25 #include <SalomeApp_Application.h>
26 #include <SalomeApp_Study.h>
27 #include <SalomeApp_DataObject.h>
28
29 #include <SALOME_ListIO.hxx>
30 #include <LightApp_SelectionMgr.h>
31
32 #include <SALOME_LifeCycleCORBA.hxx>
33 #include <SALOMEDS_SObject.hxx>
34 #include <SALOMEDS_Study.hxx>
35
36 #include "MEDFactoryClient.hxx"
37 #include "MEDModule.hxx"
38 #include "QtHelper.hxx"
39
40 #include CORBA_CLIENT_HEADER(SALOMEDS)
41 #include CORBA_CLIENT_HEADER(SALOMEDS_Attributes)
42 #include <SUIT_FileDlg.h>
43 #include <SUIT_Desktop.h>
44
45 #include <QStringList>
46 #include <QString>
47 #include <QMessageBox>
48
49 #include "DlgAlias.hxx"
50
51 //
52 // ==============================================================
53 // Datasource controller
54 // ==============================================================
55 //
56 //DatasourceController::DatasourceController(StandardApp_Module* salomeModule)
57 DatasourceController::DatasourceController(MEDModule* salomeModule)
58 {
59   STDLOG("Creating a DatasourceController");
60   _salomeModule = salomeModule;
61   _studyEditor = _salomeModule->getStudyEditor();
62
63   _dlgChangeUnderlyingMesh = new DlgChangeUnderlyingMesh(_studyEditor);
64   connect(_dlgChangeUnderlyingMesh,SIGNAL(inputValidated()),
65           this, SLOT(OnChangeUnderlyingMeshInputValidated()));
66
67   _dlgInterpolateField = new DlgInterpolateField(_studyEditor);
68   connect(_dlgInterpolateField,SIGNAL(inputValidated()),
69           this, SLOT(OnInterpolateFieldInputValidated()));
70
71 }
72
73 DatasourceController::~DatasourceController() {
74   STDLOG("Deleting the DatasourceController");
75 }
76
77 void DatasourceController::createActions() {
78   //QWidget* dsk = _salomeModule->getApp()->desktop();
79   //SUIT_ResourceMgr* resMgr = _salomeModule->getApp()->resourceMgr();
80   int toolbarId = _salomeModule->createTool("Datasource", "DatasourceToolbar");
81
82   //
83   // Main actions (toolbar and menubar)
84   //
85   QString label   = tr("LAB_ADD_DATA_SOURCE");
86   QString tooltip = tr("TIP_ADD_DATA_SOURCE");
87   QString icon    = tr("ICO_DATASOURCE_ADD");
88   int actionId;
89   actionId = _salomeModule->createStandardAction(label,this, SLOT(OnAddDatasource()),icon,tooltip);
90   //_salomeModule->addActionInToolbar(actionId);
91   _salomeModule->createTool(actionId, toolbarId);
92
93   // This action has to be placed in the general file menu with the label "Import MED file"
94   int menuId = _salomeModule->createMenu( tr( "MEN_FILE" ), -1,  1 );
95   //_salomeModule->addActionInMenubar(actionId, menuId);
96   _salomeModule->action(actionId)->setIconVisibleInMenu(true);
97   _salomeModule->createMenu(actionId, menuId, 10);
98
99   label   = tr("LAB_ADD_IMAGE_SOURCE");
100   tooltip = tr("TIP_ADD_IMAGE_SOURCE");
101   icon    = tr("ICO_IMAGE_ADD");
102   actionId = _salomeModule->createStandardAction(label,this, SLOT(OnAddImagesource()),icon,tooltip);
103   // _salomeModule->addActionInToolbar(actionId);
104   _salomeModule->createTool(actionId, toolbarId);
105   _salomeModule->action(actionId)->setIconVisibleInMenu(true);
106   _salomeModule->createMenu(actionId, menuId, 20);
107
108   //
109   // Actions for popup menu only
110   //
111   // Expand field timeseries
112   label = tr("LAB_EXPAND_FIELD");
113   icon  = tr("ICO_DATASOURCE_EXPAND_FIELD");
114   actionId = _salomeModule->createStandardAction(label,this,SLOT(OnExpandField()),icon);
115   _salomeModule->addActionInPopupMenu(actionId);
116
117   // Use in workspace
118   label = tr("LAB_USE_IN_WORKSPACE");
119   icon  = tr("ICO_DATASOURCE_USE");
120   actionId = _salomeModule->createStandardAction(label,this,SLOT(OnUseInWorkspace()),icon);
121   _salomeModule->addActionInPopupMenu(actionId);
122
123   // Change underlying mesh (note that this action creates a new field in
124   // the workspace that corresponds to a copy of the selected field
125   // modified by the change of the underlying mesh.
126   label = tr("LAB_CHANGE_MESH");
127   icon  = tr("ICO_DATASOURCE_CHANGE_MESH");
128   actionId = _salomeModule->createStandardAction(label,this,SLOT(OnChangeUnderlyingMesh()),icon);
129   _salomeModule->addActionInPopupMenu(actionId);
130
131   label = tr("LAB_INTERPOLATE_FIELD");
132   icon  = tr("ICO_DATASOURCE_INTERPOLATE_FIELD");
133   actionId = _salomeModule->createStandardAction(label,this,SLOT(OnInterpolateField()),icon);
134   _salomeModule->addActionInPopupMenu(actionId);
135 }
136
137 /**
138  * This function adds the specified MED file as a datasource in the
139  * dataspace. Technically speaking, the engine loads the
140  * meta-information concerning med data from the file, gives this
141  * informations to the GUI, and the GUI creates a tree view of these
142  * data in the study object browser.
143  */
144 // This function emits a signal that will be caught by workspace to delegate command (datasource creation) to python console.
145 void
146 DatasourceController::addDatasource(const char* filename)
147 {
148   DatasourceEvent* event = new DatasourceEvent();
149   event->eventtype = DatasourceEvent::EVENT_ADD_DATASOURCE;
150   event->objectalias = filename;
151   emit datasourceSignal(event);
152 }
153 // After above data source creation, python console emits a signal, forwarded by workspace, to update the GUI
154 void
155 DatasourceController::updateTreeViewWithNewDatasource(const MEDCALC::DatasourceHandler* datasourceHandler)
156 {
157   if (!datasourceHandler) {
158     return;
159   }
160
161   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(_salomeModule->application()->activeStudy());
162   _PTR(Study) studyDS = study->studyDS();
163
164   _salomeModule->engine()->addDatasourceToStudy(_CAST(Study, studyDS)->GetStudy(), *datasourceHandler);
165
166   // update Object browser
167   _salomeModule->getApp()->updateObjectBrowser(true);
168 }
169
170 void DatasourceController::OnAddDatasource()
171 {
172   // Dialog to get the filename where the input data are read from
173   QStringList filter;
174   filter.append(tr("FILE_FILTER_MED"));
175
176   QString anInitialPath = "";
177   if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
178     anInitialPath = QDir::currentPath();
179
180   QStringList filenames = SUIT_FileDlg::getOpenFileNames( _salomeModule->getApp()->desktop(),
181                                                           anInitialPath,
182                                                           filter,
183                                                           tr("IMPORT_MED_FIELDS") );
184
185   if ( filenames.count() <= 0 ) return;
186   for ( QStringList::ConstIterator itFile = filenames.begin();
187         itFile != filenames.end(); ++itFile ) {
188     QString filename = *itFile;
189     this->addDatasource(QCHARSTAR(filename));
190     _salomeModule->updateObjBrowser(true);
191   }
192 }
193
194 #include "DlgImageToMed.hxx"
195 //#include <stdio.h>
196 //#include <stdlib.h>
197 void DatasourceController::OnAddImagesource()
198 {
199
200   DlgImageToMed dialog;
201   dialog.setAutoLoaded(true);
202   int choice = dialog.exec();
203   if ( choice == QDialog::Rejected ) {
204     // The user decides to cancel the operation
205     return;
206   }
207
208   QString imageFilename = dialog.getImageFilepath();
209   /*
210   QString medFilename   = dialog.getMedFilepath();
211   bool autoLoad         = dialog.isAutoLoaded();
212
213   std::string ROOT_DIR(getenv("MED_ROOT_DIR"));
214   std::string command(ROOT_DIR+"/bin/salome/med/image2med.py");
215   command += " -i "+QS2S(imageFilename);
216   command += " -m "+QS2S(medFilename);
217   int error = system(command.c_str());
218   if ( error != 0 ) {
219     QMessageBox::critical(_salomeModule->getApp()->desktop(),
220            tr("Operation failed"),
221            tr("The creation of med data from the image file failed"));
222     return;
223   }
224
225   if ( autoLoad ) {
226     this->addDatasource(QCHARSTAR(medFilename));
227     _salomeModule->updateObjBrowser(true);
228   }
229   */
230
231   DatasourceEvent* event = new DatasourceEvent();
232   event->eventtype = DatasourceEvent::EVENT_ADD_IMAGE_AS_DATASOURCE;
233   event->objectalias = imageFilename;
234   emit datasourceSignal(event);
235 }
236
237 void DatasourceController::OnExpandField()
238 {
239   // We need a studyEditor updated on the active study
240   _studyEditor->updateActiveStudy();
241
242   // Get the selected objects in the study (SObject)
243   SALOME_StudyEditor::SObjectList* listOfSObject = _studyEditor->getSelectedObjects();
244   for (int i=0; i<listOfSObject->size(); i++) {
245     SALOMEDS::SObject_var soFieldseries = listOfSObject->at(i);
246
247     // First retrieve the fieldseries id associated to this study object
248     long fieldseriesId = _studyEditor->getParameterInt(soFieldseries,OBJECT_ID);
249     STDLOG("Expand the field timeseries "<<fieldseriesId);
250
251     // If fieldseriesId equals -1, then it means that it is not a
252     // fieldseries managed by the MED module, and we stop this
253     // function process.
254     if ( fieldseriesId < 0 )
255       continue;
256     // _GBO_ A better correction should be to no display the
257     // contextual menu if the selected object is not conform
258
259     // Then retrieve the list of fields in this timeseries
260     MEDCALC::FieldHandlerList* fieldHandlerList =
261       MEDFactoryClient::getDataManager()->getFieldListInFieldseries(fieldseriesId);
262
263     // Finally, create an entry for each of the field
264     for(CORBA::ULong iField=0; iField<fieldHandlerList->length(); iField++) {
265       MEDCALC::FieldHandler fieldHandler = (*fieldHandlerList)[iField];
266       SALOMEDS::SObject_var soField = _studyEditor->newObject(soFieldseries);
267       std::string label("it="); label += ToString(fieldHandler.iteration);
268       _studyEditor->setName(soField,label.c_str());
269       _studyEditor->setParameterInt(soField, OBJECT_ID, fieldHandler.id);
270       _studyEditor->setParameterBool(soField,OBJECT_IS_IN_WORKSPACE,false);
271     }
272   }
273   _salomeModule->updateObjBrowser(true);
274 }
275
276 void DatasourceController::OnUseInWorkspace() {
277   // We need a studyEditor updated on the active study
278   _studyEditor->updateActiveStudy();
279
280   // Get the selected objects in the study (SObject)
281   SALOME_StudyEditor::SObjectList* listOfSObject = _studyEditor->getSelectedObjects();
282   if ( listOfSObject->size() == 1 ) {
283     // In this case we ask the name of the variable for the python
284     // console
285
286     // >>>
287     // _GBO_ Note that it works only for a single field but the
288     // XmedDataObject will be improved to deal with mesh, timeseries
289     // and single field in a futur version. We suppose here that a
290     // single field has been selected.
291     // <<<
292
293     SALOMEDS::SObject_var soField = listOfSObject->at(0);
294
295     bool isInWorkspace = _studyEditor->getParameterBool(soField,OBJECT_IS_IN_WORKSPACE);
296     if ( isInWorkspace ) {
297       QMessageBox::warning(_salomeModule->getApp()->desktop(),
298          tr("Operation not allowed"),
299          tr("This field is already defined in the workspace"));
300       return;
301     }
302
303     int fieldId = _studyEditor->getParameterInt(soField,OBJECT_ID);
304
305     // If fieldId equals -1, then it means that it is not a field
306     // managed by the MED module, and we stop this function process.
307     if ( fieldId < 0 ) {
308       QMessageBox::warning(_salomeModule->getApp()->desktop(),
309          tr("Operation not allowed"),
310          tr("This element is not a field object"));
311       return;
312     }
313
314     MEDCALC::FieldHandler* fieldHandler =
315       MEDFactoryClient::getDataManager()->getFieldHandler(fieldId);
316
317     if (! fieldHandler) {
318       QMessageBox::warning(_salomeModule->getApp()->desktop(),
319          tr("Operation not allowed"),
320          tr("No field is defined"));
321       return;
322     }
323
324     QString alias(fieldHandler->fieldname);
325     DlgAlias dialog;
326     dialog.setAlias(alias);
327     int choice = dialog.exec();
328     if ( choice == QDialog::Rejected ) {
329       // The user decides to cancel the operation
330       return;
331     }
332     alias = dialog.getAlias();
333
334     DatasourceEvent* event = new DatasourceEvent();
335     event->eventtype = DatasourceEvent::EVENT_USE_OBJECT;
336     XmedDataObject* dataObject = new XmedDataObject();
337     dataObject->setFieldHandler(*fieldHandler);
338     event->objectdata  = dataObject;
339     event->objectalias = alias;
340     emit datasourceSignal(event);
341     // Tag the item to prevent double import
342     //    _studyEditor->setParameterBool(soField,OBJECT_IS_IN_WORKSPACE,true);
343     // Tag the field as persistent on the server. It means that a
344     // saving of the workspace will save at least this field (maybe it
345     // should be an option?)
346     MEDFactoryClient::getDataManager()->markAsPersistent(fieldId, true);
347   }
348   else {
349     // In this case, we don't ask the user to specify an alias for
350     // each item, we just import the whole set of items.
351     for (int i=0; i<listOfSObject->size(); i++) {
352       SALOMEDS::SObject_var soField = listOfSObject->at(i);
353
354       bool isInWorkspace = _studyEditor->getParameterBool(soField,OBJECT_IS_IN_WORKSPACE);
355       if ( !isInWorkspace ) {
356         int fieldId = _studyEditor->getParameterInt(soField,OBJECT_ID);
357         MEDCALC::FieldHandler* fieldHandler =
358           MEDFactoryClient::getDataManager()->getFieldHandler(fieldId);
359         DatasourceEvent* event = new DatasourceEvent();
360         event->eventtype = DatasourceEvent::EVENT_IMPORT_OBJECT;
361         XmedDataObject* dataObject = new XmedDataObject();
362         dataObject->setFieldHandler(*fieldHandler);
363         event->objectdata  = dataObject;
364         emit datasourceSignal(event);
365         // Note that this signal is processed by the WorkspaceController
366
367         // Tag the item to prevent double import
368         //        _studyEditor->setParameterBool(soField,OBJECT_IS_IN_WORKSPACE,true);
369         // Tag the field as persistent on the server. It means that a
370         // saving of the workspace will save at least this field (maybe it
371         // should be an option?)
372         MEDFactoryClient::getDataManager()->markAsPersistent(fieldId, true);
373       }
374       else {
375         STDLOG("The field "<<_studyEditor->getName(soField)<<
376                " is already defined in the workspace");
377       }
378     }
379   }
380 }
381
382 void DatasourceController::OnChangeUnderlyingMesh() {
383   // We need a studyEditor updated on the active study
384   _studyEditor->updateActiveStudy();
385
386   // Get the selected objects in the study (SObject). In cas of a
387   // multiple selection, we consider only the first item. At least one
388   // item must be selected.
389   SALOME_StudyEditor::SObjectList* listOfSObject = _studyEditor->getSelectedObjects();
390   if ( listOfSObject->size() > 0 ) {
391     SALOMEDS::SObject_var soField = listOfSObject->at(0);
392     int fieldId = _studyEditor->getParameterInt(soField,OBJECT_ID);
393     // _GBO_ : the dialog should not be modal, so that we can choose a
394     // mesh in the browser. Then we have to emit a signal from the
395     // dialog.accept, connected to a slot of the DatasourceControler
396     _dlgChangeUnderlyingMesh->setFieldId(fieldId);
397     Qt::WindowFlags flags = _dlgChangeUnderlyingMesh->windowFlags();
398     _dlgChangeUnderlyingMesh->setWindowFlags(flags | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint);
399     _dlgChangeUnderlyingMesh->open();
400   }
401 }
402
403 void DatasourceController::OnChangeUnderlyingMeshInputValidated() {
404   int meshId = _dlgChangeUnderlyingMesh->getMeshId();
405   STDLOG("meshId = " << ToString(meshId));
406   int fieldId = _dlgChangeUnderlyingMesh->getFieldId();
407   MEDCALC::FieldHandler* fieldHandler =
408     MEDFactoryClient::getDataManager()->getFieldHandler(fieldId);
409
410   // We don't modify the original field but create first a duplicate
411   MEDCALC::FieldHandler* duplicate = MEDFactoryClient::getCalculator()->dup(*fieldHandler);
412   MEDFactoryClient::getDataManager()->changeUnderlyingMesh(duplicate->id, meshId);
413
414   // Request once more the duplicate to update the meta-data on this
415   // client side
416   duplicate = MEDFactoryClient::getDataManager()->getFieldHandler(duplicate->id);
417
418   // >>>
419   // WARN: the following is a temporary code for test purpose
420   // Automatically add in ws
421   DatasourceEvent* event = new DatasourceEvent();
422   event->eventtype = DatasourceEvent::EVENT_IMPORT_OBJECT;
423   XmedDataObject* dataObject = new XmedDataObject();
424   dataObject->setFieldHandler(*duplicate);
425   event->objectdata = dataObject;
426   emit datasourceSignal(event);
427   // Note that this signal is processed by the WorkspaceController
428
429   // Tag the item to prevent double import
430   //_studyEditor->setParameterBool(soField,OBJECT_IS_IN_WORKSPACE,true);
431 }
432
433 void DatasourceController::OnInterpolateField() {
434   // We need a studyEditor updated on the active study
435   _studyEditor->updateActiveStudy();
436
437   // Get the selected objects in the study (SObject). In case of a
438   // multiple selection, we consider only the first item. At least one
439   // item must be selected.
440   SALOME_StudyEditor::SObjectList* listOfSObject = _studyEditor->getSelectedObjects();
441   if ( listOfSObject->size() > 0 ) {
442     SALOMEDS::SObject_var soField = listOfSObject->at(0);
443     int fieldId = _studyEditor->getParameterInt(soField,OBJECT_ID);
444     // _GBO_ : the dialog should not be modal, so that we can choose a
445     // mesh in the browser. Then we have to emit a signal from the
446     // dialog.accept, connected to a slot of the DatasourceControler
447     _dlgInterpolateField->setFieldId(fieldId);
448     Qt::WindowFlags flags = _dlgInterpolateField->windowFlags();
449     _dlgInterpolateField->setWindowFlags(flags | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint);
450     _dlgInterpolateField->open();
451   }
452 }
453
454 void DatasourceController::OnInterpolateFieldInputValidated() {
455   MEDCALC::InterpolationParameters params;
456   params.precision = _dlgInterpolateField->getPrecision();
457   STDLOG("precision = " << params.precision);
458   params.defaultValue = _dlgInterpolateField->getDefaultValue();
459   STDLOG("defaultValue = " << params.defaultValue);
460   params.reverse = _dlgInterpolateField->getReverse();
461   STDLOG("reverse = " << params.reverse);
462   params.intersectionType = _dlgInterpolateField->getIntersectionType().c_str();
463   STDLOG("intersectionType = " << params.intersectionType);
464   params.method = _dlgInterpolateField->getMethod().c_str();
465   STDLOG("method = " << params.method);
466   params.nature = _dlgInterpolateField->getFieldNature().c_str();
467   STDLOG("nature = " << params.nature);
468
469   int meshId = _dlgInterpolateField->getMeshId();
470   STDLOG("meshId = " << ToString(meshId));
471   int fieldId = _dlgInterpolateField->getFieldId();
472   MEDCALC::FieldHandler* fieldHandler = MEDFactoryClient::getDataManager()->getFieldHandler(fieldId);
473
474   // We don't modify the original field but create first a duplicate
475   // MEDCALC::FieldHandler* duplicate = MEDFactoryClient::getCalculator()->dup(*fieldHandler);
476   //MEDFactoryClient::getDataManager()->changeUnderlyingMesh(duplicate->id, meshId);
477   MEDCALC::FieldHandler* result = NULL;
478   try {
479     result = MEDFactoryClient::getDataManager()->interpolateField(fieldId, meshId, params);
480   }
481   catch(...) {
482     STDLOG("Unable to process field interpolation; please check interpolation parameters");
483     QMessageBox::critical(_salomeModule->getApp()->desktop(),
484                           tr("Operation failed"),
485                           tr("Unable to process field interpolation; please check interpolation parameters"));
486     return;
487   }
488
489   // Request once more the duplicate to update the meta-data on this
490   // client side
491   // duplicate = MEDFactoryClient::getDataManager()->getFieldHandler(duplicate->id);
492
493   // >>>
494   // WARN: the following is a temporary code for test purpose
495   // Automatically add in ws
496   DatasourceEvent* event = new DatasourceEvent();
497   event->eventtype = DatasourceEvent::EVENT_IMPORT_OBJECT;
498   XmedDataObject* dataObject = new XmedDataObject();
499   dataObject->setFieldHandler(*result);
500   event->objectdata = dataObject;
501   emit datasourceSignal(event);
502   // Note that this signal is processed by the WorkspaceController
503
504   // // Tag the item to prevent double import
505   // //_studyEditor->setParameterBool(soField,OBJECT_IS_IN_WORKSPACE,true);
506 }
507
508 void
509 DatasourceController::processWorkspaceEvent(const MEDCALC::MedEvent* event)
510 {
511   if ( event->type == MEDCALC::EVENT_ADD_DATASOURCE ) {
512     MEDCALC::DatasourceHandler* datasourceHandler = MEDFactoryClient::getDataManager()->getDatasourceHandler(event->filename);
513     this->updateTreeViewWithNewDatasource(datasourceHandler);
514   }
515 }