Salome HOME
Update copyrights 2014.
[modules/med.git] / src / MEDOP / gui / DatasourceController.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 "DatasourceController.hxx"
23 #include "DatasourceConstants.hxx"
24
25 #include "MEDOPFactoryClient.hxx"
26 #include "QtHelper.hxx"
27
28 #include CORBA_CLIENT_HEADER(SALOMEDS)
29 #include <SUIT_FileDlg.h>
30 #include <SUIT_Desktop.h>
31
32 #include <QStringList>
33 #include <QString>
34 #include <QMessageBox>
35
36 #include "DlgAlias.hxx"
37
38 //
39 // ==============================================================
40 // Datasource controller
41 // ==============================================================
42 //
43 DatasourceController::DatasourceController(StandardApp_Module * salomeModule) {
44   STDLOG("Creating a DatasourceController");
45   _salomeModule = salomeModule;
46   _studyEditor = new SALOME_AppStudyEditor(_salomeModule->getApp());
47   _dlgChangeUnderlyingMesh = new DlgChangeUnderlyingMesh(_studyEditor);
48
49   connect(_dlgChangeUnderlyingMesh,SIGNAL(inputValidated()),
50           this, SLOT(OnChangeUnderlyingMeshInputValidated()));
51
52 }
53
54 DatasourceController::~DatasourceController() {
55   STDLOG("Deleting the DatasourceController");
56   delete _studyEditor;
57 }
58
59 void DatasourceController::createActions() {
60   //
61   // Main actions (toolbar and menubar)
62   //
63   QString label   = tr("LAB_ADD_DATA_SOURCE");
64   QString tooltip = tr("TIP_ADD_DATA_SOURCE");
65   QString icon    = tr("ICO_DATASOURCE_ADD");
66   int actionId;
67   actionId = _salomeModule->createStandardAction(label,this, SLOT(OnAddDatasource()),icon,tooltip);
68   _salomeModule->addActionInToolbar(actionId);
69
70   // This action has to be placed in the general file menu with the label "Import MED file"
71   int menuId = _salomeModule->createMenu( tr( "MEN_FILE" ), -1,  1 );
72   _salomeModule->addActionInMenubar(actionId, menuId);
73
74   label   = tr("LAB_ADD_IMAGE_SOURCE");
75   tooltip = tr("TIP_ADD_IMAGE_SOURCE");
76   icon    = tr("ICO_IMAGE_ADD");
77   actionId = _salomeModule->createStandardAction(label,this, SLOT(OnAddImagesource()),icon,tooltip);
78   _salomeModule->addActionInToolbar(actionId);
79
80   //
81   // Actions for popup menu only
82   //
83   // Expand field timeseries
84   label = tr("LAB_EXPAND_FIELD");
85   icon  = tr("ICO_DATASOURCE_EXPAND_FIELD");
86   actionId = _salomeModule->createStandardAction(label,this,SLOT(OnExpandField()),icon);
87   _salomeModule->addActionInPopupMenu(actionId);
88
89   // Create a control view
90   label = tr("LAB_VISUALIZE");
91   icon  = tr("ICO_DATASOURCE_VIEW");
92   actionId = _salomeModule->createStandardAction(label,this,SLOT(OnVisualize()),icon);
93   _salomeModule->addActionInPopupMenu(actionId);
94
95   // Use in workspace
96   label = tr("LAB_USE_IN_WORKSPACE");
97   icon  = tr("ICO_DATASOURCE_USE");
98   actionId = _salomeModule->createStandardAction(label,this,SLOT(OnUseInWorkspace()),icon);
99   _salomeModule->addActionInPopupMenu(actionId);
100
101   // Change underlying mesh (note that this action creates a new field in
102   // the workspace that corresponds to a copy of the selected field
103   // modified by the change of the underlying mesh.
104   label = tr("LAB_CHANGE_MESH");
105   icon  = tr("ICO_DATASOURCE_CHANGE_MESH");
106   actionId = _salomeModule->createStandardAction(label,this,SLOT(OnChangeUnderlyingMesh()),icon);
107   _salomeModule->addActionInPopupMenu(actionId);
108
109 }
110
111 /**
112  * This function adds the specified MED file as a datasource in the
113  * dataspace. Technically speaking, the engine loads the
114  * meta-information concerning med data from the file, gives this
115  * informations to the GUI, and the GUI creates a tree view of these
116  * data in the study object browser.
117  */
118 MEDOP::DatasourceHandler * DatasourceController::addDatasource(const char * filename) {
119
120   MEDOP::DatasourceHandler * datasourceHandler =
121     MEDOPFactoryClient::getDataManager()->addDatasource(filename);
122
123   // We need a studyEditor updated on the active study
124   _studyEditor->updateActiveStudy();
125
126   // Create a datasource SObject as a father of the module root
127   SALOMEDS::SComponent_var root = _studyEditor->findRoot(QCHARSTAR(_salomeModule->moduleName()));
128   SALOMEDS::SObject_var soDatasource = _studyEditor->newObject(root);
129   _studyEditor->setName(soDatasource,datasourceHandler->name);
130   _studyEditor->setIcon(soDatasource,tr("ICO_DATASOURCE").toStdString().c_str());
131   _studyEditor->setParameterInt(soDatasource,OBJECT_ID,datasourceHandler->id);
132
133
134   // We can add the meshes as children of the datasource
135   MEDOP::MeshHandlerList * meshHandlerList =
136     MEDOPFactoryClient::getDataManager()->getMeshList(datasourceHandler->id);
137
138   for(CORBA::ULong iMesh=0; iMesh<meshHandlerList->length(); iMesh++) {
139     MEDOP::MeshHandler meshHandler = (*meshHandlerList)[iMesh];
140     SALOMEDS::SObject_var soMesh = _studyEditor->newObject(soDatasource);
141     _studyEditor->setName(soMesh,meshHandler.name);
142     _studyEditor->setIcon(soMesh,tr("ICO_DATASOURCE_MESH").toStdString().c_str());
143     _studyEditor->setParameterInt(soMesh,OBJECT_ID,meshHandler.id);
144     _studyEditor->setParameterBool(soMesh,OBJECT_IS_IN_WORKSPACE,false);
145
146
147     // We add the field timeseries defined on this mesh, as children
148     // of the mesh SObject
149     MEDOP::FieldseriesHandlerList * fieldseriesHandlerList =
150       MEDOPFactoryClient::getDataManager()->getFieldseriesListOnMesh(meshHandler.id);
151
152     for(CORBA::ULong iFieldseries=0; iFieldseries<fieldseriesHandlerList->length(); iFieldseries++) {
153       MEDOP::FieldseriesHandler fieldseriesHandler = (*fieldseriesHandlerList)[iFieldseries];
154       SALOMEDS::SObject_var soFieldseries = _studyEditor->newObject(soMesh);
155
156       std::string label(fieldseriesHandler.name);
157       label +=" ("+std::string(XmedDataObject::mapTypeOfFieldLabel[fieldseriesHandler.type])+")";
158       _studyEditor->setName(soFieldseries,label.c_str());
159
160       _studyEditor->setIcon(soFieldseries,tr("ICO_DATASOURCE_FIELD").toStdString().c_str());
161       _studyEditor->setParameterInt(soFieldseries,OBJECT_ID,fieldseriesHandler.id);
162       _studyEditor->setParameterBool(soFieldseries,OBJECT_IS_IN_WORKSPACE,false);
163     }
164   }
165
166   return datasourceHandler;
167 }
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   /*
181   QString filename = SUIT_FileDlg::getFileName(_salomeModule->getApp()->desktop(),
182                                                "",
183                                                filter,
184                                                tr("IMPORT_MED_FIELDS"),
185                                                true);
186   */
187
188   QStringList filenames = SUIT_FileDlg::getOpenFileNames( _salomeModule->getApp()->desktop(),
189                                                           anInitialPath,
190                                                           filter,
191                                                           tr("IMPORT_MED_FIELDS") );
192
193   if ( filenames.count() <= 0 ) return;
194   for ( QStringList::ConstIterator itFile = filenames.begin();
195         itFile != filenames.end(); ++itFile ) {
196     QString filename = *itFile;
197     this->addDatasource(QCHARSTAR(filename));
198     _salomeModule->updateObjBrowser(true);
199   }
200 }
201
202 #include "DlgImageToMed.hxx"
203 #include <stdio.h>
204 #include <stdlib.h>
205 void DatasourceController::OnAddImagesource()
206 {
207
208   DlgImageToMed dialog;
209   dialog.setAutoLoaded(true);
210   int choice = dialog.exec();
211   if ( choice == QDialog::Rejected ) {
212     // The user decides to cancel the operation
213     return;
214   }
215
216   QString imageFilename = dialog.getImageFilepath();
217   QString medFilename   = dialog.getMedFilepath();
218   bool autoLoad         = dialog.isAutoLoaded();
219
220   std::string ROOT_DIR(getenv("MED_ROOT_DIR"));
221   std::string command(ROOT_DIR+"/bin/salome/med/image2med.py");
222   command += " -i "+QS2S(imageFilename);
223   command += " -m "+QS2S(medFilename);
224   int error = system(command.c_str());
225   if ( error != 0 ) {
226     QMessageBox::critical(_salomeModule->getApp()->desktop(),
227            tr("Operation failed"),
228            tr("The creation of med data from the image file failed"));
229     return;
230   }
231
232   if ( autoLoad ) {
233     this->addDatasource(QCHARSTAR(medFilename));
234     _salomeModule->updateObjBrowser(true);
235   }
236
237 }
238
239 void DatasourceController::OnExpandField()
240 {
241   // We need a studyEditor updated on the active study
242   _studyEditor->updateActiveStudy();
243
244   // Get the selected objects in the study (SObject)
245   SALOME_StudyEditor::SObjectList * listOfSObject = _studyEditor->getSelectedObjects();
246   for (int i=0; i<listOfSObject->size(); i++) {
247     SALOMEDS::SObject_var soFieldseries = listOfSObject->at(i);
248
249     // First retrieve the fieldseries id associated to this study object
250     long fieldseriesId = _studyEditor->getParameterInt(soFieldseries,OBJECT_ID);
251     STDLOG("Expand the field timeseries "<<fieldseriesId);
252
253     // If fieldseriesId equals -1, then it means that it is not a
254     // fieldseries managed by the MED module, and we stop this
255     // function process.
256     if ( fieldseriesId < 0 )
257       continue;
258     // _GBO_ A better correction should be to no display the
259     // contextual menu if the selected object is not conform
260
261     // Then retrieve the list of fields in this timeseries
262     MEDOP::FieldHandlerList * fieldHandlerList =
263       MEDOPFactoryClient::getDataManager()->getFieldListInFieldseries(fieldseriesId);
264
265     // Finally, create an entry for each of the field
266     for(CORBA::ULong iField=0; iField<fieldHandlerList->length(); iField++) {
267       MEDOP::FieldHandler fieldHandler = (*fieldHandlerList)[iField];
268       SALOMEDS::SObject_var soField = _studyEditor->newObject(soFieldseries);
269       std::string label("it="); label += ToString(fieldHandler.iteration);
270       _studyEditor->setName(soField,label.c_str());
271       _studyEditor->setParameterInt(soField, OBJECT_ID, fieldHandler.id);
272       _studyEditor->setParameterBool(soField,OBJECT_IS_IN_WORKSPACE,false);
273     }
274   }
275   _salomeModule->updateObjBrowser(true);
276 }
277
278 void DatasourceController::OnVisualize() {
279   STDLOG("OnVisualize: To Be Implemented");
280
281   // We need a _studyEditor updated on the active study
282   _studyEditor->updateActiveStudy();
283
284   // Get the selected objects in the study (SObject)
285   SALOME_StudyEditor::SObjectList * listOfSObject = _studyEditor->getSelectedObjects();
286
287   // For each object, emit a signal to the workspace to request a
288   // visualisation using the tui command (so that the user can see how
289   // to make a view of an object from the tui console).
290   for (int i=0; i<listOfSObject->size(); i++) {
291     SALOMEDS::SObject_var soField = listOfSObject->at(i);
292     int fieldId = _studyEditor->getParameterInt(soField,OBJECT_ID);
293     // If fieldId equals -1, then it means that it is not a field
294     // managed by the MED module, and we stop this function process.
295     if ( fieldId < 0 )
296       continue;
297
298     MEDOP::FieldHandler * fieldHandler = MEDOPFactoryClient::getDataManager()->getFieldHandler(fieldId);
299
300     DatasourceEvent * event = new DatasourceEvent();
301     event->eventtype = DatasourceEvent::EVENT_VIEW_OBJECT;
302     XmedDataObject * dataObject = new XmedDataObject();
303     dataObject->setFieldHandler(*fieldHandler);
304     event->objectdata  = dataObject;
305     emit datasourceSignal(event);
306   }
307
308 }
309
310 void DatasourceController::OnUseInWorkspace() {
311   // We need a studyEditor updated on the active study
312   _studyEditor->updateActiveStudy();
313
314   // Get the selected objects in the study (SObject)
315   SALOME_StudyEditor::SObjectList * listOfSObject = _studyEditor->getSelectedObjects();
316   if ( listOfSObject->size() == 1 ) {
317     // In this case we ask the name of the variable for the python
318     // console
319
320     // >>>
321     // _GBO_ Note that it works only for a single field but the
322     // XmedDataObject will be improved to deal with mesh, timeseries
323     // and single field in a futur version. We suppose here that a
324     // single field has been selected.
325     // <<<
326
327     SALOMEDS::SObject_var soField = listOfSObject->at(0);
328
329     bool isInWorkspace = _studyEditor->getParameterBool(soField,OBJECT_IS_IN_WORKSPACE);
330     if ( isInWorkspace ) {
331       QMessageBox::warning(_salomeModule->getApp()->desktop(),
332          tr("Operation not allowed"),
333          tr("This field is already defined in the workspace"));
334       return;
335     }
336
337     int fieldId = _studyEditor->getParameterInt(soField,OBJECT_ID);
338
339     // If fieldId equals -1, then it means that it is not a field
340     // managed by the MED module, and we stop this function process.
341     if ( fieldId < 0 ) {
342       QMessageBox::warning(_salomeModule->getApp()->desktop(),
343          tr("Operation not allowed"),
344          tr("This element is not a field object"));
345       return;
346     }
347
348     MEDOP::FieldHandler * fieldHandler =
349       MEDOPFactoryClient::getDataManager()->getFieldHandler(fieldId);
350
351     QString alias(fieldHandler->fieldname);
352     DlgAlias dialog;
353     dialog.setAlias(alias);
354     int choice = dialog.exec();
355     if ( choice == QDialog::Rejected ) {
356       // The user decides to cancel the operation
357       return;
358     }
359     alias = dialog.getAlias();
360
361     DatasourceEvent * event = new DatasourceEvent();
362     event->eventtype = DatasourceEvent::EVENT_USE_OBJECT;
363     XmedDataObject * dataObject = new XmedDataObject();
364     dataObject->setFieldHandler(*fieldHandler);
365     event->objectdata  = dataObject;
366     event->objectalias = alias;
367     emit datasourceSignal(event);
368     // Tag the item to prevent double import
369     _studyEditor->setParameterBool(soField,OBJECT_IS_IN_WORKSPACE,true);
370     // Tag the field as persistent on the server. It means that a
371     // saving of the workspace will save at least this field (maybe it
372     // should be an option?)
373     MEDOPFactoryClient::getDataManager()->markAsPersistent(fieldId, true);
374   }
375   else {
376     // In this case, we don't ask the user to specify an alias for
377     // each item, we just import the whole set of items.
378     for (int i=0; i<listOfSObject->size(); i++) {
379       SALOMEDS::SObject_var soField = listOfSObject->at(i);
380
381       bool isInWorkspace = _studyEditor->getParameterBool(soField,OBJECT_IS_IN_WORKSPACE);
382       if ( !isInWorkspace ) {
383   int fieldId = _studyEditor->getParameterInt(soField,OBJECT_ID);
384   MEDOP::FieldHandler * fieldHandler =
385     MEDOPFactoryClient::getDataManager()->getFieldHandler(fieldId);
386   DatasourceEvent * event = new DatasourceEvent();
387   event->eventtype = DatasourceEvent::EVENT_IMPORT_OBJECT;
388   XmedDataObject * dataObject = new XmedDataObject();
389   dataObject->setFieldHandler(*fieldHandler);
390   event->objectdata  = dataObject;
391   emit datasourceSignal(event);
392   // Note that this signal is processed by the WorkspaceController
393
394   // Tag the item to prevent double import
395   _studyEditor->setParameterBool(soField,OBJECT_IS_IN_WORKSPACE,true);
396   // Tag the field as persistent on the server. It means that a
397   // saving of the workspace will save at least this field (maybe it
398   // should be an option?)
399   MEDOPFactoryClient::getDataManager()->markAsPersistent(fieldId, true);
400       }
401       else {
402   STDLOG("The field "<<_studyEditor->getName(soField)<<
403          " is already defined in the workspace");
404       }
405     }
406   }
407 }
408
409
410 void DatasourceController::OnChangeUnderlyingMesh() {
411   // We need a studyEditor updated on the active study
412   _studyEditor->updateActiveStudy();
413
414   // Get the selected objects in the study (SObject). In cas of a
415   // multiple selection, we consider only the first item. At least one
416   // item must be selected.
417   SALOME_StudyEditor::SObjectList * listOfSObject = _studyEditor->getSelectedObjects();
418   if ( listOfSObject->size() > 0 ) {
419     SALOMEDS::SObject_var soField = listOfSObject->at(0);
420     int fieldId = _studyEditor->getParameterInt(soField,OBJECT_ID);
421     // _GBO_ : the dialog should not be modal, so that we can choose a
422     // mesh in the browser. Then we have to emit a signal from the
423     // dialog.accept, connected to a slot of the DatasourceControler
424     _dlgChangeUnderlyingMesh->setFieldId(fieldId);
425     Qt::WindowFlags flags = _dlgChangeUnderlyingMesh->windowFlags();
426     _dlgChangeUnderlyingMesh->setWindowFlags(flags | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint);
427     _dlgChangeUnderlyingMesh->open();
428   }
429 }
430
431 void DatasourceController::OnChangeUnderlyingMeshInputValidated() {
432   int meshId = _dlgChangeUnderlyingMesh->getMeshId();
433   STDLOG("meshId = " << ToString(meshId));
434   int fieldId = _dlgChangeUnderlyingMesh->getFieldId();
435   MEDOP::FieldHandler * fieldHandler =
436     MEDOPFactoryClient::getDataManager()->getFieldHandler(fieldId);
437
438   // We don't modify the original field but create first a duplicate
439   MEDOP::FieldHandler * duplicate = MEDOPFactoryClient::getCalculator()->dup(*fieldHandler);
440   MEDOPFactoryClient::getDataManager()->changeUnderlyingMesh(duplicate->id, meshId);
441
442   // Request once more the duplicate to update the meta-data on this
443   // client side
444   duplicate = MEDOPFactoryClient::getDataManager()->getFieldHandler(duplicate->id);
445
446   // >>>
447   // WARN: the following is a temporary code for test purpose
448   // Automatically add in ws
449   DatasourceEvent * event = new DatasourceEvent();
450   event->eventtype = DatasourceEvent::EVENT_IMPORT_OBJECT;
451   XmedDataObject * dataObject = new XmedDataObject();
452   dataObject->setFieldHandler(*duplicate);
453   event->objectdata  = dataObject;
454   emit datasourceSignal(event);
455   // Note that this signal is processed by the WorkspaceController
456
457   // Tag the item to prevent double import
458   //_studyEditor->setParameterBool(soField,OBJECT_IS_IN_WORKSPACE,true);
459
460
461 }