1 // Copyright (C) 2007-2016 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 // Author : Guillaume Boulant (EDF)
22 #include "DatasourceController.hxx"
23 #include "DatasourceConstants.hxx"
25 #include <SalomeApp_Application.h>
26 #include <SalomeApp_Study.h>
27 #include <SalomeApp_DataObject.h>
29 #include <SALOME_ListIO.hxx>
30 #include <LightApp_SelectionMgr.h>
32 #include <SALOME_LifeCycleCORBA.hxx>
33 #include <SALOMEDS_SObject.hxx>
34 #include <SALOMEDS_Study.hxx>
36 #include "MEDFactoryClient.hxx"
37 #include "MEDModule.hxx"
38 #include "QtHelper.hxx"
40 #include CORBA_CLIENT_HEADER(SALOMEDS)
41 #include CORBA_CLIENT_HEADER(SALOMEDS_Attributes)
42 #include <SUIT_FileDlg.h>
43 #include <SUIT_Desktop.h>
45 #include <QStringList>
47 #include <QMessageBox>
49 #include "DlgAlias.hxx"
52 // ==============================================================
53 // Datasource controller
54 // ==============================================================
56 //DatasourceController::DatasourceController(StandardApp_Module* salomeModule)
57 DatasourceController::DatasourceController(MEDModule* salomeModule)
59 STDLOG("Creating a DatasourceController");
60 _salomeModule = salomeModule;
61 _studyEditor = _salomeModule->getStudyEditor();
63 _dlgChangeUnderlyingMesh = new DlgChangeUnderlyingMesh(_studyEditor);
64 connect(_dlgChangeUnderlyingMesh,SIGNAL(inputValidated()),
65 this, SLOT(OnChangeUnderlyingMeshInputValidated()));
67 _dlgInterpolateField = new DlgInterpolateField(_studyEditor);
68 connect(_dlgInterpolateField,SIGNAL(inputValidated()),
69 this, SLOT(OnInterpolateFieldInputValidated()));
73 DatasourceController::~DatasourceController() {
74 STDLOG("Deleting the DatasourceController");
77 void DatasourceController::createActions() {
78 //QWidget* dsk = _salomeModule->getApp()->desktop();
79 //SUIT_ResourceMgr* resMgr = _salomeModule->getApp()->resourceMgr();
80 int toolbarId = _salomeModule->createTool("Datasource", "DatasourceToolbar");
83 // Main actions (toolbar and menubar)
85 QString label = tr("LAB_ADD_DATA_SOURCE");
86 QString tooltip = tr("TIP_ADD_DATA_SOURCE");
87 QString icon = tr("ICO_DATASOURCE_ADD");
89 actionId = _salomeModule->createStandardAction(label,this, SLOT(OnAddDatasource()),icon,tooltip);
90 //_salomeModule->addActionInToolbar(actionId);
91 _salomeModule->createTool(actionId, toolbarId);
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);
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);
109 // Actions for popup menu only
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);
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);
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);
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);
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.
144 // This function emits a signal that will be caught by workspace to delegate command (datasource creation) to python console.
146 DatasourceController::addDatasource(const char* filename)
148 DatasourceEvent* event = new DatasourceEvent();
149 event->eventtype = DatasourceEvent::EVENT_ADD_DATASOURCE;
150 event->objectalias = filename;
151 emit datasourceSignal(event);
153 // After above data source creation, python console emits a signal, forwarded by workspace, to update the GUI
155 DatasourceController::updateTreeViewWithNewDatasource(const MEDCALC::DatasourceHandler* datasourceHandler)
157 if (!datasourceHandler) {
161 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(_salomeModule->application()->activeStudy());
162 _PTR(Study) studyDS = study->studyDS();
164 _salomeModule->engine()->addDatasourceToStudy(_CAST(Study, studyDS)->GetStudy(), *datasourceHandler);
166 // update Object browser
167 _salomeModule->getApp()->updateObjectBrowser(true);
170 void DatasourceController::OnAddDatasource()
172 // Dialog to get the filename where the input data are read from
174 filter.append(tr("FILE_FILTER_MED"));
176 QString anInitialPath = "";
177 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
178 anInitialPath = QDir::currentPath();
180 QStringList filenames = SUIT_FileDlg::getOpenFileNames( _salomeModule->getApp()->desktop(),
183 tr("IMPORT_MED_FIELDS") );
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);
194 #include "DlgImageToMed.hxx"
196 //#include <stdlib.h>
197 void DatasourceController::OnAddImagesource()
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
208 QString imageFilename = dialog.getImageFilepath();
210 QString medFilename = dialog.getMedFilepath();
211 bool autoLoad = dialog.isAutoLoaded();
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());
219 QMessageBox::critical(_salomeModule->getApp()->desktop(),
220 tr("Operation failed"),
221 tr("The creation of med data from the image file failed"));
226 this->addDatasource(QCHARSTAR(medFilename));
227 _salomeModule->updateObjBrowser(true);
231 DatasourceEvent* event = new DatasourceEvent();
232 event->eventtype = DatasourceEvent::EVENT_ADD_IMAGE_AS_DATASOURCE;
233 event->objectalias = imageFilename;
234 emit datasourceSignal(event);
237 void DatasourceController::OnExpandField()
239 // We need a studyEditor updated on the active study
240 _studyEditor->updateActiveStudy();
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);
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);
251 // If fieldseriesId equals -1, then it means that it is not a
252 // fieldseries managed by the MED module, and we stop this
254 if ( fieldseriesId < 0 )
256 // _GBO_ A better correction should be to no display the
257 // contextual menu if the selected object is not conform
259 // Then retrieve the list of fields in this timeseries
260 MEDCALC::FieldHandlerList* fieldHandlerList =
261 MEDFactoryClient::getDataManager()->getFieldListInFieldseries(fieldseriesId);
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);
273 _salomeModule->updateObjBrowser(true);
276 void DatasourceController::OnUseInWorkspace() {
277 // We need a studyEditor updated on the active study
278 _studyEditor->updateActiveStudy();
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
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.
293 SALOMEDS::SObject_var soField = listOfSObject->at(0);
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"));
303 int fieldId = _studyEditor->getParameterInt(soField,OBJECT_ID);
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.
308 QMessageBox::warning(_salomeModule->getApp()->desktop(),
309 tr("Operation not allowed"),
310 tr("This element is not a field object"));
314 MEDCALC::FieldHandler* fieldHandler =
315 MEDFactoryClient::getDataManager()->getFieldHandler(fieldId);
317 if (! fieldHandler) {
318 QMessageBox::warning(_salomeModule->getApp()->desktop(),
319 tr("Operation not allowed"),
320 tr("No field is defined"));
324 QString alias(fieldHandler->fieldname);
326 dialog.setAlias(alias);
327 int choice = dialog.exec();
328 if ( choice == QDialog::Rejected ) {
329 // The user decides to cancel the operation
332 alias = dialog.getAlias();
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);
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);
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
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);
375 STDLOG("The field "<<_studyEditor->getName(soField)<<
376 " is already defined in the workspace");
382 void DatasourceController::OnChangeUnderlyingMesh() {
383 // We need a studyEditor updated on the active study
384 _studyEditor->updateActiveStudy();
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();
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);
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);
414 // Request once more the duplicate to update the meta-data on this
416 duplicate = MEDFactoryClient::getDataManager()->getFieldHandler(duplicate->id);
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
429 // Tag the item to prevent double import
430 //_studyEditor->setParameterBool(soField,OBJECT_IS_IN_WORKSPACE,true);
433 void DatasourceController::OnInterpolateField() {
434 // We need a studyEditor updated on the active study
435 _studyEditor->updateActiveStudy();
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();
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);
469 int meshId = _dlgInterpolateField->getMeshId();
470 STDLOG("meshId = " << ToString(meshId));
471 int fieldId = _dlgInterpolateField->getFieldId();
472 MEDCALC::FieldHandler* fieldHandler = MEDFactoryClient::getDataManager()->getFieldHandler(fieldId);
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;
479 result = MEDFactoryClient::getDataManager()->interpolateField(fieldId, meshId, params);
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"));
489 // Request once more the duplicate to update the meta-data on this
491 // duplicate = MEDFactoryClient::getDataManager()->getFieldHandler(duplicate->id);
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
504 // // Tag the item to prevent double import
505 // //_studyEditor->setParameterBool(soField,OBJECT_IS_IN_WORKSPACE,true);
509 DatasourceController::processWorkspaceEvent(const MEDCALC::MedEvent* event)
511 if ( event->type == MEDCALC::EVENT_ADD_DATASOURCE ) {
512 MEDCALC::DatasourceHandler* datasourceHandler = MEDFactoryClient::getDataManager()->getDatasourceHandler(event->filename);
513 this->updateTreeViewWithNewDatasource(datasourceHandler);