1 // Copyright (C) 2007-2015 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 = new SALOME_AppStudyEditor(_salomeModule->getApp());
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");
78 void DatasourceController::createActions() {
79 //QWidget* dsk = _salomeModule->getApp()->desktop();
80 //SUIT_ResourceMgr* resMgr = _salomeModule->getApp()->resourceMgr();
81 int toolbarId = _salomeModule->createTool("Datasource", "DatasourceToolbar");
84 // Main actions (toolbar and menubar)
86 QString label = tr("LAB_ADD_DATA_SOURCE");
87 QString tooltip = tr("TIP_ADD_DATA_SOURCE");
88 QString icon = tr("ICO_DATASOURCE_ADD");
90 actionId = _salomeModule->createStandardAction(label,this, SLOT(OnAddDatasource()),icon,tooltip);
91 //_salomeModule->addActionInToolbar(actionId);
92 _salomeModule->createTool(actionId, toolbarId);
94 // This action has to be placed in the general file menu with the label "Import MED file"
95 int menuId = _salomeModule->createMenu( tr( "MEN_FILE" ), -1, 1 );
96 //_salomeModule->addActionInMenubar(actionId, menuId);
97 _salomeModule->action(actionId)->setIconVisibleInMenu(true);
98 _salomeModule->createMenu(actionId, menuId, 10);
100 label = tr("LAB_ADD_IMAGE_SOURCE");
101 tooltip = tr("TIP_ADD_IMAGE_SOURCE");
102 icon = tr("ICO_IMAGE_ADD");
103 actionId = _salomeModule->createStandardAction(label,this, SLOT(OnAddImagesource()),icon,tooltip);
104 // _salomeModule->addActionInToolbar(actionId);
105 _salomeModule->createTool(actionId, toolbarId);
108 // Actions for popup menu only
110 // Expand field timeseries
111 label = tr("LAB_EXPAND_FIELD");
112 icon = tr("ICO_DATASOURCE_EXPAND_FIELD");
113 actionId = _salomeModule->createStandardAction(label,this,SLOT(OnExpandField()),icon);
114 _salomeModule->addActionInPopupMenu(actionId);
116 // Create a view submenu with usual visualization functions
117 label = tr("LAB_VISUALIZE_SCALARMAP");
118 icon = tr("ICO_DATASOURCE_VIEW");
119 actionId = _salomeModule->createStandardAction(label,this,SLOT(OnVisualizeScalarMap()),icon);
120 _salomeModule->addActionInPopupMenu(actionId, tr("LAB_VISUALIZE"));
123 label = tr("LAB_USE_IN_WORKSPACE");
124 icon = tr("ICO_DATASOURCE_USE");
125 actionId = _salomeModule->createStandardAction(label,this,SLOT(OnUseInWorkspace()),icon);
126 _salomeModule->addActionInPopupMenu(actionId);
128 // Change underlying mesh (note that this action creates a new field in
129 // the workspace that corresponds to a copy of the selected field
130 // modified by the change of the underlying mesh.
131 label = tr("LAB_CHANGE_MESH");
132 icon = tr("ICO_DATASOURCE_CHANGE_MESH");
133 actionId = _salomeModule->createStandardAction(label,this,SLOT(OnChangeUnderlyingMesh()),icon);
134 _salomeModule->addActionInPopupMenu(actionId);
136 label = tr("LAB_INTERPOLATE_FIELD");
137 icon = tr("ICO_DATASOURCE_INTERPOLATE_FIELD");
138 actionId = _salomeModule->createStandardAction(label,this,SLOT(OnInterpolateField()),icon);
139 _salomeModule->addActionInPopupMenu(actionId);
143 * This function adds the specified MED file as a datasource in the
144 * dataspace. Technically speaking, the engine loads the
145 * meta-information concerning med data from the file, gives this
146 * informations to the GUI, and the GUI creates a tree view of these
147 * data in the study object browser.
149 // This function emits a signal that will be caught by workspace to delegate command (datasource creation) to python console.
151 DatasourceController::addDatasource(const char* filename)
153 DatasourceEvent* event = new DatasourceEvent();
154 event->eventtype = DatasourceEvent::EVENT_ADD_DATASOURCE;
155 event->objectalias = filename;
156 emit datasourceSignal(event);
158 // After above data source creation, python console emits a signal, forwarded by workspace, to update the GUI
160 DatasourceController::updateTreeViewWithNewDatasource(const MEDCALC::DatasourceHandler* datasourceHandler)
162 if (!datasourceHandler) {
166 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(_salomeModule->application()->activeStudy());
167 _PTR(Study) studyDS = study->studyDS();
169 _salomeModule->engine()->addDatasourceToStudy(_CAST(Study, studyDS)->GetStudy(), *datasourceHandler);
171 // update Object browser
172 _salomeModule->getApp()->updateObjectBrowser(true);
176 DatasourceController::updateTreeViewWithNewPresentation(long fieldId, long presentationId)
178 if (presentationId < 0) {
179 std::cerr << "Unknown presentation\n";
183 std::string name = MEDFactoryClient::getPresentationManager()->getPresentationProperty(presentationId, "name");
184 name = tr(name.c_str()).toStdString();
185 std::string label = tr("ICO_MED_PRESENTATION").toStdString();
187 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(_salomeModule->application()->activeStudy());
188 _PTR(Study) studyDS = study->studyDS();
190 _salomeModule->engine()->registerPresentation(_CAST(Study, studyDS)->GetStudy(), fieldId, name.c_str(), label.c_str());
192 // update Object browser
193 _salomeModule->getApp()->updateObjectBrowser(true);
196 void DatasourceController::OnAddDatasource()
198 // Dialog to get the filename where the input data are read from
200 filter.append(tr("FILE_FILTER_MED"));
202 QString anInitialPath = "";
203 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
204 anInitialPath = QDir::currentPath();
206 QStringList filenames = SUIT_FileDlg::getOpenFileNames( _salomeModule->getApp()->desktop(),
209 tr("IMPORT_MED_FIELDS") );
211 if ( filenames.count() <= 0 ) return;
212 for ( QStringList::ConstIterator itFile = filenames.begin();
213 itFile != filenames.end(); ++itFile ) {
214 QString filename = *itFile;
215 this->addDatasource(QCHARSTAR(filename));
216 _salomeModule->updateObjBrowser(true);
220 #include "DlgImageToMed.hxx"
222 //#include <stdlib.h>
223 void DatasourceController::OnAddImagesource()
226 DlgImageToMed dialog;
227 dialog.setAutoLoaded(true);
228 int choice = dialog.exec();
229 if ( choice == QDialog::Rejected ) {
230 // The user decides to cancel the operation
234 QString imageFilename = dialog.getImageFilepath();
236 QString medFilename = dialog.getMedFilepath();
237 bool autoLoad = dialog.isAutoLoaded();
239 std::string ROOT_DIR(getenv("MED_ROOT_DIR"));
240 std::string command(ROOT_DIR+"/bin/salome/med/image2med.py");
241 command += " -i "+QS2S(imageFilename);
242 command += " -m "+QS2S(medFilename);
243 int error = system(command.c_str());
245 QMessageBox::critical(_salomeModule->getApp()->desktop(),
246 tr("Operation failed"),
247 tr("The creation of med data from the image file failed"));
252 this->addDatasource(QCHARSTAR(medFilename));
253 _salomeModule->updateObjBrowser(true);
257 DatasourceEvent* event = new DatasourceEvent();
258 event->eventtype = DatasourceEvent::EVENT_ADD_IMAGE_AS_DATASOURCE;
259 event->objectalias = imageFilename;
260 emit datasourceSignal(event);
263 void DatasourceController::OnExpandField()
265 // We need a studyEditor updated on the active study
266 _studyEditor->updateActiveStudy();
268 // Get the selected objects in the study (SObject)
269 SALOME_StudyEditor::SObjectList * listOfSObject = _studyEditor->getSelectedObjects();
270 for (int i=0; i<listOfSObject->size(); i++) {
271 SALOMEDS::SObject_var soFieldseries = listOfSObject->at(i);
273 // First retrieve the fieldseries id associated to this study object
274 long fieldseriesId = _studyEditor->getParameterInt(soFieldseries,OBJECT_ID);
275 STDLOG("Expand the field timeseries "<<fieldseriesId);
277 // If fieldseriesId equals -1, then it means that it is not a
278 // fieldseries managed by the MED module, and we stop this
280 if ( fieldseriesId < 0 )
282 // _GBO_ A better correction should be to no display the
283 // contextual menu if the selected object is not conform
285 // Then retrieve the list of fields in this timeseries
286 MEDCALC::FieldHandlerList * fieldHandlerList =
287 MEDFactoryClient::getDataManager()->getFieldListInFieldseries(fieldseriesId);
289 // Finally, create an entry for each of the field
290 for(CORBA::ULong iField=0; iField<fieldHandlerList->length(); iField++) {
291 MEDCALC::FieldHandler fieldHandler = (*fieldHandlerList)[iField];
292 SALOMEDS::SObject_var soField = _studyEditor->newObject(soFieldseries);
293 std::string label("it="); label += ToString(fieldHandler.iteration);
294 _studyEditor->setName(soField,label.c_str());
295 _studyEditor->setParameterInt(soField, OBJECT_ID, fieldHandler.id);
296 _studyEditor->setParameterBool(soField,OBJECT_IS_IN_WORKSPACE,false);
299 _salomeModule->updateObjBrowser(true);
302 void DatasourceController::visualize(DatasourceEvent::EventType eventType) {
303 // We need a _studyEditor updated on the active study
304 _studyEditor->updateActiveStudy();
306 // Get the selected objects in the study (SObject)
307 SALOME_StudyEditor::SObjectList * listOfSObject = _studyEditor->getSelectedObjects();
309 // For each object, emit a signal to the workspace to request a
310 // visualisation using the tui command (so that the user can see how
311 // to make a view of an object from the tui console).
312 for (int i=0; i<listOfSObject->size(); i++) {
313 SALOMEDS::SObject_var soField = listOfSObject->at(i);
314 int fieldId = _studyEditor->getParameterInt(soField,OBJECT_ID);
315 // If fieldId equals -1, then it means that it is not a field
316 // managed by the MED module, and we stop this function process.
320 MEDCALC::FieldHandler * fieldHandler = MEDFactoryClient::getDataManager()->getFieldHandler(fieldId);
321 if (! fieldHandler) {
322 QMessageBox::warning(_salomeModule->getApp()->desktop(),
323 tr("Operation not allowed"),
324 tr("No field is defined"));
328 DatasourceEvent * event = new DatasourceEvent();
329 event->eventtype = eventType;
330 XmedDataObject * dataObject = new XmedDataObject();
331 dataObject->setFieldHandler(*fieldHandler);
332 event->objectdata = dataObject;
333 emit datasourceSignal(event);
337 void DatasourceController::OnVisualizeScalarMap() {
338 this->visualize(DatasourceEvent::EVENT_VIEW_OBJECT_SCALAR_MAP);
341 void DatasourceController::OnUseInWorkspace() {
342 // We need a studyEditor updated on the active study
343 _studyEditor->updateActiveStudy();
345 // Get the selected objects in the study (SObject)
346 SALOME_StudyEditor::SObjectList * listOfSObject = _studyEditor->getSelectedObjects();
347 if ( listOfSObject->size() == 1 ) {
348 // In this case we ask the name of the variable for the python
352 // _GBO_ Note that it works only for a single field but the
353 // XmedDataObject will be improved to deal with mesh, timeseries
354 // and single field in a futur version. We suppose here that a
355 // single field has been selected.
358 SALOMEDS::SObject_var soField = listOfSObject->at(0);
360 bool isInWorkspace = _studyEditor->getParameterBool(soField,OBJECT_IS_IN_WORKSPACE);
361 if ( isInWorkspace ) {
362 QMessageBox::warning(_salomeModule->getApp()->desktop(),
363 tr("Operation not allowed"),
364 tr("This field is already defined in the workspace"));
368 int fieldId = _studyEditor->getParameterInt(soField,OBJECT_ID);
370 // If fieldId equals -1, then it means that it is not a field
371 // managed by the MED module, and we stop this function process.
373 QMessageBox::warning(_salomeModule->getApp()->desktop(),
374 tr("Operation not allowed"),
375 tr("This element is not a field object"));
379 MEDCALC::FieldHandler * fieldHandler =
380 MEDFactoryClient::getDataManager()->getFieldHandler(fieldId);
382 if (! fieldHandler) {
383 QMessageBox::warning(_salomeModule->getApp()->desktop(),
384 tr("Operation not allowed"),
385 tr("No field is defined"));
389 QString alias(fieldHandler->fieldname);
391 dialog.setAlias(alias);
392 int choice = dialog.exec();
393 if ( choice == QDialog::Rejected ) {
394 // The user decides to cancel the operation
397 alias = dialog.getAlias();
399 DatasourceEvent * event = new DatasourceEvent();
400 event->eventtype = DatasourceEvent::EVENT_USE_OBJECT;
401 XmedDataObject * dataObject = new XmedDataObject();
402 dataObject->setFieldHandler(*fieldHandler);
403 event->objectdata = dataObject;
404 event->objectalias = alias;
405 emit datasourceSignal(event);
406 // Tag the item to prevent double import
407 // _studyEditor->setParameterBool(soField,OBJECT_IS_IN_WORKSPACE,true);
408 // Tag the field as persistent on the server. It means that a
409 // saving of the workspace will save at least this field (maybe it
410 // should be an option?)
411 MEDFactoryClient::getDataManager()->markAsPersistent(fieldId, true);
414 // In this case, we don't ask the user to specify an alias for
415 // each item, we just import the whole set of items.
416 for (int i=0; i<listOfSObject->size(); i++) {
417 SALOMEDS::SObject_var soField = listOfSObject->at(i);
419 bool isInWorkspace = _studyEditor->getParameterBool(soField,OBJECT_IS_IN_WORKSPACE);
420 if ( !isInWorkspace ) {
421 int fieldId = _studyEditor->getParameterInt(soField,OBJECT_ID);
422 MEDCALC::FieldHandler * fieldHandler =
423 MEDFactoryClient::getDataManager()->getFieldHandler(fieldId);
424 DatasourceEvent * event = new DatasourceEvent();
425 event->eventtype = DatasourceEvent::EVENT_IMPORT_OBJECT;
426 XmedDataObject * dataObject = new XmedDataObject();
427 dataObject->setFieldHandler(*fieldHandler);
428 event->objectdata = dataObject;
429 emit datasourceSignal(event);
430 // Note that this signal is processed by the WorkspaceController
432 // Tag the item to prevent double import
433 // _studyEditor->setParameterBool(soField,OBJECT_IS_IN_WORKSPACE,true);
434 // Tag the field as persistent on the server. It means that a
435 // saving of the workspace will save at least this field (maybe it
436 // should be an option?)
437 MEDFactoryClient::getDataManager()->markAsPersistent(fieldId, true);
440 STDLOG("The field "<<_studyEditor->getName(soField)<<
441 " is already defined in the workspace");
447 void DatasourceController::OnChangeUnderlyingMesh() {
448 // We need a studyEditor updated on the active study
449 _studyEditor->updateActiveStudy();
451 // Get the selected objects in the study (SObject). In cas of a
452 // multiple selection, we consider only the first item. At least one
453 // item must be selected.
454 SALOME_StudyEditor::SObjectList * listOfSObject = _studyEditor->getSelectedObjects();
455 if ( listOfSObject->size() > 0 ) {
456 SALOMEDS::SObject_var soField = listOfSObject->at(0);
457 int fieldId = _studyEditor->getParameterInt(soField,OBJECT_ID);
458 // _GBO_ : the dialog should not be modal, so that we can choose a
459 // mesh in the browser. Then we have to emit a signal from the
460 // dialog.accept, connected to a slot of the DatasourceControler
461 _dlgChangeUnderlyingMesh->setFieldId(fieldId);
462 Qt::WindowFlags flags = _dlgChangeUnderlyingMesh->windowFlags();
463 _dlgChangeUnderlyingMesh->setWindowFlags(flags | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint);
464 _dlgChangeUnderlyingMesh->open();
468 void DatasourceController::OnChangeUnderlyingMeshInputValidated() {
469 int meshId = _dlgChangeUnderlyingMesh->getMeshId();
470 STDLOG("meshId = " << ToString(meshId));
471 int fieldId = _dlgChangeUnderlyingMesh->getFieldId();
472 MEDCALC::FieldHandler * fieldHandler =
473 MEDFactoryClient::getDataManager()->getFieldHandler(fieldId);
475 // We don't modify the original field but create first a duplicate
476 MEDCALC::FieldHandler * duplicate = MEDFactoryClient::getCalculator()->dup(*fieldHandler);
477 MEDFactoryClient::getDataManager()->changeUnderlyingMesh(duplicate->id, meshId);
479 // Request once more the duplicate to update the meta-data on this
481 duplicate = MEDFactoryClient::getDataManager()->getFieldHandler(duplicate->id);
484 // WARN: the following is a temporary code for test purpose
485 // Automatically add in ws
486 DatasourceEvent * event = new DatasourceEvent();
487 event->eventtype = DatasourceEvent::EVENT_IMPORT_OBJECT;
488 XmedDataObject * dataObject = new XmedDataObject();
489 dataObject->setFieldHandler(*duplicate);
490 event->objectdata = dataObject;
491 emit datasourceSignal(event);
492 // Note that this signal is processed by the WorkspaceController
494 // Tag the item to prevent double import
495 //_studyEditor->setParameterBool(soField,OBJECT_IS_IN_WORKSPACE,true);
498 void DatasourceController::OnInterpolateField() {
499 // We need a studyEditor updated on the active study
500 _studyEditor->updateActiveStudy();
502 // Get the selected objects in the study (SObject). In case of a
503 // multiple selection, we consider only the first item. At least one
504 // item must be selected.
505 SALOME_StudyEditor::SObjectList * listOfSObject = _studyEditor->getSelectedObjects();
506 if ( listOfSObject->size() > 0 ) {
507 SALOMEDS::SObject_var soField = listOfSObject->at(0);
508 int fieldId = _studyEditor->getParameterInt(soField,OBJECT_ID);
509 // _GBO_ : the dialog should not be modal, so that we can choose a
510 // mesh in the browser. Then we have to emit a signal from the
511 // dialog.accept, connected to a slot of the DatasourceControler
512 _dlgInterpolateField->setFieldId(fieldId);
513 Qt::WindowFlags flags = _dlgInterpolateField->windowFlags();
514 _dlgInterpolateField->setWindowFlags(flags | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint);
515 _dlgInterpolateField->open();
519 void DatasourceController::OnInterpolateFieldInputValidated() {
520 MEDCALC::InterpolationParameters params;
521 params.precision = _dlgInterpolateField->getPrecision();
522 STDLOG("precision = " << params.precision);
523 params.defaultValue = _dlgInterpolateField->getDefaultValue();
524 STDLOG("defaultValue = " << params.defaultValue);
525 params.reverse = _dlgInterpolateField->getReverse();
526 STDLOG("reverse = " << params.reverse);
527 params.intersectionType = _dlgInterpolateField->getIntersectionType().c_str();
528 STDLOG("intersectionType = " << params.intersectionType);
529 params.method = _dlgInterpolateField->getMethod().c_str();
530 STDLOG("method = " << params.method);
531 params.nature = _dlgInterpolateField->getFieldNature().c_str();
532 STDLOG("nature = " << params.nature);
534 int meshId = _dlgInterpolateField->getMeshId();
535 STDLOG("meshId = " << ToString(meshId));
536 int fieldId = _dlgInterpolateField->getFieldId();
537 MEDCALC::FieldHandler* fieldHandler = MEDFactoryClient::getDataManager()->getFieldHandler(fieldId);
539 // We don't modify the original field but create first a duplicate
540 // MEDCALC::FieldHandler* duplicate = MEDFactoryClient::getCalculator()->dup(*fieldHandler);
541 //MEDFactoryClient::getDataManager()->changeUnderlyingMesh(duplicate->id, meshId);
542 MEDCALC::FieldHandler* result = NULL;
544 result = MEDFactoryClient::getDataManager()->interpolateField(fieldId, meshId, params);
547 STDLOG("Unable to process field interpolation; please check interpolation parameters");
548 QMessageBox::critical(_salomeModule->getApp()->desktop(),
549 tr("Operation failed"),
550 tr("Unable to process field interpolation; please check interpolation parameters"));
554 // Request once more the duplicate to update the meta-data on this
556 // duplicate = MEDFactoryClient::getDataManager()->getFieldHandler(duplicate->id);
559 // WARN: the following is a temporary code for test purpose
560 // Automatically add in ws
561 DatasourceEvent * event = new DatasourceEvent();
562 event->eventtype = DatasourceEvent::EVENT_IMPORT_OBJECT;
563 XmedDataObject * dataObject = new XmedDataObject();
564 dataObject->setFieldHandler(*result);
565 event->objectdata = dataObject;
566 emit datasourceSignal(event);
567 // Note that this signal is processed by the WorkspaceController
569 // // Tag the item to prevent double import
570 // //_studyEditor->setParameterBool(soField,OBJECT_IS_IN_WORKSPACE,true);
574 DatasourceController::processWorkspaceEvent(const MEDCALC::MedEvent* event)
576 if ( event->type == MEDCALC::EVENT_ADD_DATASOURCE ) {
577 MEDCALC::DatasourceHandler* datasourceHandler = MEDFactoryClient::getDataManager()->getDatasourceHandler(event->filename);
578 this->updateTreeViewWithNewDatasource(datasourceHandler);
580 else if ( event->type == MEDCALC::EVENT_ADD_PRESENTATION ) {
581 this->updateTreeViewWithNewPresentation(event->dataId, event->presentationId);