Salome HOME
Merge from V6_main 01/04/2013
[modules/med.git] / src / MEDOP / gui / DatasourceController.cxx
1 // Copyright (C) 2007-2013  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.
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   = QString("Add Data Source");
64   QString tooltip = QString("Add a file data source (file providing med data)");
65   QString icon    = QString("datasource_add.png");
66   int actionId;
67   actionId = _salomeModule->createStandardAction(label,this, SLOT(OnAddDatasource()),icon,tooltip);
68   _salomeModule->addActionInToolbar(actionId);
69
70   label   = QString("Add Image Source");
71   tooltip = QString("Create a Data Source from an image file");
72   icon    = QString("image_add.png");
73   actionId = _salomeModule->createStandardAction(label,this, SLOT(OnAddImagesource()),icon,tooltip);
74   _salomeModule->addActionInToolbar(actionId);
75     
76   //
77   // Actions for popup menu only
78   //
79   // Expand field timeseries
80   label = QString("Expand field timeseries");
81   icon  = QString("datasource_expandfield.png");
82   actionId = _salomeModule->createStandardAction(label,this,SLOT(OnExpandField()),icon);
83   _salomeModule->addActionInPopupMenu(actionId);
84   
85   // Create a control view
86   label = QString("Visualize");
87   icon  = QString("datasource_view.png");
88   actionId = _salomeModule->createStandardAction(label,this,SLOT(OnVisualize()),icon);
89   _salomeModule->addActionInPopupMenu(actionId);
90
91   // Use in workspace
92   label = QString("Use in workspace");
93   icon  = QString("datasource_use.png");
94   actionId = _salomeModule->createStandardAction(label,this,SLOT(OnUseInWorkspace()),icon);
95   _salomeModule->addActionInPopupMenu(actionId);
96
97   // Change underlying mesh (note that this action creates a new field in
98   // the workspace that corresponds to a copy of the selected field
99   // modified by the change of the underlying mesh.
100   label = QString("Change underlying mesh");
101   icon  = QString("datasource_changeUnderlyingMesh.png");
102   actionId = _salomeModule->createStandardAction(label,this,SLOT(OnChangeUnderlyingMesh()),icon);
103   _salomeModule->addActionInPopupMenu(actionId);
104 }
105
106 /**
107  * This function adds the specified MED file as a datasource in the
108  * dataspace. Technically speaking, the engine loads the
109  * meta-information concerning med data from the file, gives this
110  * informations to the GUI, and the GUI creates a tree view of these
111  * data in the study object browser.
112  */
113 MEDOP::DatasourceHandler * DatasourceController::addDatasource(const char * filename) {
114
115   MEDOP::DatasourceHandler * datasourceHandler =
116     MEDOPFactoryClient::getDataManager()->addDatasource(filename);
117
118   // We need a studyEditor updated on the active study
119   _studyEditor->updateActiveStudy();
120
121   // Create a datasource SObject as a father of the module root
122   SALOMEDS::SComponent_var root = _studyEditor->findRoot(QCHARSTAR(_salomeModule->moduleName()));
123   SALOMEDS::SObject_var soDatasource = _studyEditor->newObject(root);
124   _studyEditor->setName(soDatasource,datasourceHandler->name);
125   _studyEditor->setIcon(soDatasource,"datasource.png");
126   _studyEditor->setParameterInt(soDatasource,OBJECT_ID,datasourceHandler->id);
127   
128
129   // We can add the meshes as children of the datasource
130   MEDOP::MeshHandlerList * meshHandlerList = 
131     MEDOPFactoryClient::getDataManager()->getMeshList(datasourceHandler->id);
132   
133   for(CORBA::ULong iMesh=0; iMesh<meshHandlerList->length(); iMesh++) {
134     MEDOP::MeshHandler meshHandler = (*meshHandlerList)[iMesh];
135     SALOMEDS::SObject_var soMesh = _studyEditor->newObject(soDatasource);
136     _studyEditor->setName(soMesh,meshHandler.name);
137     _studyEditor->setIcon(soMesh,"datasource_mesh.png");
138     _studyEditor->setParameterInt(soMesh,OBJECT_ID,meshHandler.id);
139     _studyEditor->setParameterBool(soMesh,OBJECT_IS_IN_WORKSPACE,false);
140     
141
142     // We add the field timeseries defined on this mesh, as children
143     // of the mesh SObject
144     MEDOP::FieldseriesHandlerList * fieldseriesHandlerList =
145       MEDOPFactoryClient::getDataManager()->getFieldseriesListOnMesh(meshHandler.id);
146     
147     for(CORBA::ULong iFieldseries=0; iFieldseries<fieldseriesHandlerList->length(); iFieldseries++) {
148       MEDOP::FieldseriesHandler fieldseriesHandler = (*fieldseriesHandlerList)[iFieldseries];
149       SALOMEDS::SObject_var soFieldseries = _studyEditor->newObject(soMesh);
150
151       std::string label(fieldseriesHandler.name);
152       label +=" ("+std::string(XmedDataObject::mapTypeOfFieldLabel[fieldseriesHandler.type])+")";
153       _studyEditor->setName(soFieldseries,label.c_str());
154
155       _studyEditor->setIcon(soFieldseries,"datasource_field.png");
156       _studyEditor->setParameterInt(soFieldseries,OBJECT_ID,fieldseriesHandler.id);
157       _studyEditor->setParameterBool(soFieldseries,OBJECT_IS_IN_WORKSPACE,false);
158     }
159   }
160
161   return datasourceHandler;
162 }
163
164
165 void DatasourceController::OnAddDatasource()
166 {
167   // Dialog to get the filename where the input data are read from
168   QStringList filter;
169   filter.append(QObject::tr("MED files (*.med)"));
170
171   QString filename = SUIT_FileDlg::getFileName(_salomeModule->getApp()->desktop(),
172                                                "",
173                                                filter,
174                                                QObject::tr("Import MED fields"),
175                                                true);
176
177   if ( filename.isEmpty() ) return;
178
179   this->addDatasource(QCHARSTAR(filename));
180   _salomeModule->updateObjBrowser(true);
181 }
182
183 #include "DlgImageToMed.hxx"
184 #include <stdio.h>
185 #include <stdlib.h>
186 void DatasourceController::OnAddImagesource()
187 {
188
189   DlgImageToMed dialog;
190   dialog.setAutoLoaded(true);
191   int choice = dialog.exec();
192   if ( choice == QDialog::Rejected ) {
193     // The user decides to cancel the operation
194     return;
195   }
196
197   QString imageFilename = dialog.getImageFilepath();
198   QString medFilename   = dialog.getMedFilepath();
199   bool autoLoad         = dialog.isAutoLoaded();
200   
201   std::string ROOT_DIR(getenv("MED_ROOT_DIR"));
202   std::string command(ROOT_DIR+"/bin/salome/med/image2med.py");
203   command += " -i "+QS2S(imageFilename);
204   command += " -m "+QS2S(medFilename);
205   int error = system(command.c_str());
206   if ( error != 0 ) {
207     QMessageBox::critical(_salomeModule->getApp()->desktop(),
208            tr("Operation failed"),
209            tr("The creation of med data from the image file failed"));
210     return;
211   }
212
213   if ( autoLoad ) {
214     this->addDatasource(QCHARSTAR(medFilename));
215     _salomeModule->updateObjBrowser(true);
216   }
217
218 }
219
220 void DatasourceController::OnExpandField()
221 {
222   // We need a studyEditor updated on the active study
223   _studyEditor->updateActiveStudy();
224
225   // Get the selected objects in the study (SObject)
226   SALOME_StudyEditor::SObjectList * listOfSObject = _studyEditor->getSelectedObjects();
227   for (int i=0; i<listOfSObject->size(); i++) {  
228     SALOMEDS::SObject_var soFieldseries = listOfSObject->at(i);
229
230     // First retrieve the fieldseries id associated to this study object 
231     long fieldseriesId = _studyEditor->getParameterInt(soFieldseries,OBJECT_ID);
232     STDLOG("Expand the field timeseries "<<fieldseriesId);
233
234     // Then retrieve the list of fields in this timeseries
235     MEDOP::FieldHandlerList * fieldHandlerList =
236       MEDOPFactoryClient::getDataManager()->getFieldListInFieldseries(fieldseriesId);
237
238     // Finally, create an entry for each of the field
239     for(CORBA::ULong iField=0; iField<fieldHandlerList->length(); iField++) {
240       MEDOP::FieldHandler fieldHandler = (*fieldHandlerList)[iField];
241       SALOMEDS::SObject_var soField = _studyEditor->newObject(soFieldseries);
242       std::string label("it="); label += ToString(fieldHandler.iteration);
243       _studyEditor->setName(soField,label.c_str());
244       _studyEditor->setParameterInt(soField, OBJECT_ID, fieldHandler.id);
245       _studyEditor->setParameterBool(soField,OBJECT_IS_IN_WORKSPACE,false);
246     }
247   }
248   _salomeModule->updateObjBrowser(true);
249 }
250
251 void DatasourceController::OnVisualize() {
252   STDLOG("OnVisualize: To Be Implemented");
253
254   // We need a _studyEditor updated on the active study
255   _studyEditor->updateActiveStudy();
256
257   // Get the selected objects in the study (SObject)
258   SALOME_StudyEditor::SObjectList * listOfSObject = _studyEditor->getSelectedObjects();
259
260   // For each object, emit a signal to the workspace to request a
261   // visualisation using the tui command (so that the user can see how
262   // to make a view of an object from the tui console).
263   for (int i=0; i<listOfSObject->size(); i++) {
264     SALOMEDS::SObject_var soField = listOfSObject->at(i);
265     int fieldId = _studyEditor->getParameterInt(soField,OBJECT_ID);
266     MEDOP::FieldHandler * fieldHandler = MEDOPFactoryClient::getDataManager()->getFieldHandler(fieldId);
267
268     DatasourceEvent * event = new DatasourceEvent();
269     event->eventtype = DatasourceEvent::EVENT_VIEW_OBJECT;
270     XmedDataObject * dataObject = new XmedDataObject();
271     dataObject->setFieldHandler(*fieldHandler);
272     event->objectdata  = dataObject;
273     emit datasourceSignal(event);    
274   }
275
276 }
277
278 void DatasourceController::OnUseInWorkspace() {
279   // We need a studyEditor updated on the active study
280   _studyEditor->updateActiveStudy();
281
282   // Get the selected objects in the study (SObject)
283   SALOME_StudyEditor::SObjectList * listOfSObject = _studyEditor->getSelectedObjects();
284   if ( listOfSObject->size() == 1 ) {
285     // In this case we ask the name of the variable for the python
286     // console
287
288     // >>>
289     // _GBO_ Note that it works only for a single field but the
290     // XmedDataObject will be improved to deal with mesh, timeseries
291     // and single field in a futur version. We suppose here that a
292     // single field has been selected. 
293     // <<<
294
295     SALOMEDS::SObject_var soField = listOfSObject->at(0);
296
297     bool isInWorkspace = _studyEditor->getParameterBool(soField,OBJECT_IS_IN_WORKSPACE);
298     if ( isInWorkspace ) {
299       QMessageBox::warning(_salomeModule->getApp()->desktop(),
300          tr("Operation not allowed"),
301          tr("This field is already defined in the workspace"));
302       return;
303     }
304
305     int fieldId = _studyEditor->getParameterInt(soField,OBJECT_ID);
306     MEDOP::FieldHandler * fieldHandler =
307       MEDOPFactoryClient::getDataManager()->getFieldHandler(fieldId);
308
309     QString alias(fieldHandler->fieldname);
310     DlgAlias dialog;
311     dialog.setAlias(alias);
312     int choice = dialog.exec();
313     if ( choice == QDialog::Rejected ) {
314       // The user decides to cancel the operation
315       return;
316     }
317     alias = dialog.getAlias();
318
319     DatasourceEvent * event = new DatasourceEvent();
320     event->eventtype = DatasourceEvent::EVENT_USE_OBJECT;
321     XmedDataObject * dataObject = new XmedDataObject();
322     dataObject->setFieldHandler(*fieldHandler);
323     event->objectdata  = dataObject;
324     event->objectalias = alias;
325     emit datasourceSignal(event);
326     // Tag the item to prevent double import
327     _studyEditor->setParameterBool(soField,OBJECT_IS_IN_WORKSPACE,true);
328     // Tag the field as persistent on the server. It means that a
329     // saving of the workspace will save at least this field (maybe it
330     // should be an option?)
331     MEDOPFactoryClient::getDataManager()->markAsPersistent(fieldId, true);
332   }
333   else {
334     // In this case, we don't ask the user to specify an alias for
335     // each item, we just import the whole set of items.
336     for (int i=0; i<listOfSObject->size(); i++) {
337       SALOMEDS::SObject_var soField = listOfSObject->at(i);
338
339       bool isInWorkspace = _studyEditor->getParameterBool(soField,OBJECT_IS_IN_WORKSPACE);
340       if ( !isInWorkspace ) {
341   int fieldId = _studyEditor->getParameterInt(soField,OBJECT_ID);
342   MEDOP::FieldHandler * fieldHandler =
343     MEDOPFactoryClient::getDataManager()->getFieldHandler(fieldId);
344   DatasourceEvent * event = new DatasourceEvent();
345   event->eventtype = DatasourceEvent::EVENT_IMPORT_OBJECT;
346   XmedDataObject * dataObject = new XmedDataObject();
347   dataObject->setFieldHandler(*fieldHandler);
348   event->objectdata  = dataObject;
349   emit datasourceSignal(event);
350   // Note that this signal is processed by the WorkspaceController
351
352   // Tag the item to prevent double import
353   _studyEditor->setParameterBool(soField,OBJECT_IS_IN_WORKSPACE,true);
354   // Tag the field as persistent on the server. It means that a
355   // saving of the workspace will save at least this field (maybe it
356   // should be an option?)
357   MEDOPFactoryClient::getDataManager()->markAsPersistent(fieldId, true);
358       }
359       else {
360   STDLOG("The field "<<_studyEditor->getName(soField)<<
361          " is already defined in the workspace");
362       }
363     }
364   }
365 }
366
367
368 void DatasourceController::OnChangeUnderlyingMesh() {
369   // We need a studyEditor updated on the active study
370   _studyEditor->updateActiveStudy();
371
372   // Get the selected objects in the study (SObject). In cas of a
373   // multiple selection, we consider only the first item. At least one
374   // item must be selected.
375   SALOME_StudyEditor::SObjectList * listOfSObject = _studyEditor->getSelectedObjects();
376   if ( listOfSObject->size() > 0 ) {
377     SALOMEDS::SObject_var soField = listOfSObject->at(0);
378     int fieldId = _studyEditor->getParameterInt(soField,OBJECT_ID);    
379     // _GBO_ : the dialog should not be modal, so that we can choose a
380     // mesh in the browser. Then we have to emit a signal from the
381     // dialog.accept, connected to a slot of the DatasourceControler
382     _dlgChangeUnderlyingMesh->setFieldId(fieldId);
383     Qt::WindowFlags flags = _dlgChangeUnderlyingMesh->windowFlags();
384     _dlgChangeUnderlyingMesh->setWindowFlags(flags | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint);
385     _dlgChangeUnderlyingMesh->open();
386   }
387 }
388
389 void DatasourceController::OnChangeUnderlyingMeshInputValidated() {
390   int meshId = _dlgChangeUnderlyingMesh->getMeshId();
391   STDLOG("meshId = " << ToString(meshId));
392   int fieldId = _dlgChangeUnderlyingMesh->getFieldId();
393   MEDOP::FieldHandler * fieldHandler =
394     MEDOPFactoryClient::getDataManager()->getFieldHandler(fieldId);
395   
396   // We don't modify the original field but create first a duplicate
397   MEDOP::FieldHandler * duplicate = MEDOPFactoryClient::getCalculator()->dup(*fieldHandler);
398   MEDOPFactoryClient::getDataManager()->changeUnderlyingMesh(duplicate->id, meshId);
399
400   // Request once more the duplicate to update the meta-data on this
401   // client side
402   duplicate = MEDOPFactoryClient::getDataManager()->getFieldHandler(duplicate->id);
403
404   // >>>
405   // WARN: the following is a temporary code for test purpose
406   // Automatically add in ws
407   DatasourceEvent * event = new DatasourceEvent();
408   event->eventtype = DatasourceEvent::EVENT_IMPORT_OBJECT;
409   XmedDataObject * dataObject = new XmedDataObject();
410   dataObject->setFieldHandler(*duplicate);
411   event->objectdata  = dataObject;
412   emit datasourceSignal(event);
413   // Note that this signal is processed by the WorkspaceController
414   
415   // Tag the item to prevent double import
416   //_studyEditor->setParameterBool(soField,OBJECT_IS_IN_WORKSPACE,true);
417   
418   
419 }