Salome HOME
Merge branch 'master' of ssh://git.salome-platform.org/modules/med
[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 <MEDCalcConstants.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(MEDModule* salomeModule)
57 {
58   STDLOG("Creating a DatasourceController");
59   _salomeModule = salomeModule;
60   _studyEditor = _salomeModule->getStudyEditor();
61 }
62
63 DatasourceController::~DatasourceController() {
64   STDLOG("Deleting the DatasourceController");
65 }
66
67 void DatasourceController::createActions() {
68   int toolbarId = _salomeModule->createTool("Datasource", "DatasourceToolbar");
69
70   //
71   // Main actions (toolbar and menubar)
72   //
73   QString label   = tr("LAB_ADD_DATA_SOURCE");
74   QString tooltip = tr("TIP_ADD_DATA_SOURCE");
75   QString icon    = tr("ICO_DATASOURCE_ADD");
76   int actionId;
77   actionId = _salomeModule->createStandardAction(label,this, SLOT(OnAddDatasource()),icon,tooltip);
78   _salomeModule->createTool(actionId, toolbarId);
79
80   // This action has to be placed in the general file menu with the label "Import MED file"
81   int menuId = _salomeModule->createMenu( tr( "MEN_FILE" ), -1,  1 );
82   _salomeModule->action(actionId)->setIconVisibleInMenu(true);
83   _salomeModule->createMenu(actionId, menuId, 10);
84
85   label   = tr("LAB_ADD_IMAGE_SOURCE");
86   tooltip = tr("TIP_ADD_IMAGE_SOURCE");
87   icon    = tr("ICO_IMAGE_ADD");
88   actionId = _salomeModule->createStandardAction(label,this, SLOT(OnAddImagesource()),icon,tooltip);
89   _salomeModule->createTool(actionId, toolbarId);
90   _salomeModule->action(actionId)->setIconVisibleInMenu(true);
91   _salomeModule->createMenu(actionId, menuId, 20);
92
93   //
94   // Actions for popup menu only
95   //
96   // Expand field timeseries
97   label = tr("LAB_EXPAND_FIELD");
98   icon  = tr("ICO_DATASOURCE_EXPAND_FIELD");
99   actionId = _salomeModule->createStandardAction(label,this,SLOT(OnExpandField()),icon);
100   _salomeModule->addActionInPopupMenu(actionId);
101
102   // Use in workspace
103   label = tr("LAB_USE_IN_WORKSPACE");
104   icon  = tr("ICO_DATASOURCE_USE");
105   actionId = _salomeModule->createStandardAction(label,this,SLOT(OnUseInWorkspace()),icon);
106   _salomeModule->addActionInPopupMenu(actionId);
107 }
108
109 /**
110  * This function adds the specified MED file as a datasource in the
111  * dataspace. Technically speaking, the engine loads the
112  * meta-information concerning med data from the file, gives this
113  * informations to the GUI, and the GUI creates a tree view of these
114  * data in the study object browser.
115  */
116 // This function emits a signal that will be caught by workspace to delegate command (datasource creation) to python console.
117 void
118 DatasourceController::addDatasource(const char* filename)
119 {
120   DatasourceEvent* event = new DatasourceEvent();
121   event->eventtype = DatasourceEvent::EVENT_ADD_DATASOURCE;
122   event->objectalias = filename;
123   emit datasourceSignal(event);
124 }
125 // After above data source creation, python console emits a signal, forwarded by workspace, to update the GUI
126 void
127 DatasourceController::updateTreeViewWithNewDatasource(const MEDCALC::DatasourceHandler* datasourceHandler)
128 {
129   if (!datasourceHandler) {
130     return;
131   }
132
133   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(_salomeModule->application()->activeStudy());
134   _PTR(Study) studyDS = study->studyDS();
135
136   _salomeModule->engine()->addDatasourceToStudy(_CAST(Study, studyDS)->GetStudy(), *datasourceHandler);
137
138   // update Object browser
139   _salomeModule->getApp()->updateObjectBrowser(true);
140 }
141
142 void DatasourceController::OnAddDatasource()
143 {
144   // Dialog to get the filename where the input data are read from
145   QStringList filter;
146   filter.append(tr("FILE_FILTER_MED"));
147
148   QString anInitialPath = "";
149   if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
150     anInitialPath = QDir::currentPath();
151
152   QStringList filenames = SUIT_FileDlg::getOpenFileNames( _salomeModule->getApp()->desktop(),
153                                                           anInitialPath,
154                                                           filter,
155                                                           tr("IMPORT_MED_FIELDS") );
156
157   if ( filenames.count() <= 0 ) return;
158   for ( QStringList::ConstIterator itFile = filenames.begin();
159         itFile != filenames.end(); ++itFile ) {
160     QString filename = *itFile;
161     this->addDatasource(QCHARSTAR(filename));
162     _salomeModule->updateObjBrowser(true);
163   }
164 }
165
166 #include "DlgImageToMed.hxx"
167 void DatasourceController::OnAddImagesource()
168 {
169
170   DlgImageToMed dialog;
171   dialog.setAutoLoaded(true);
172   int choice = dialog.exec();
173   if ( choice == QDialog::Rejected ) {
174     // The user decides to cancel the operation
175     return;
176   }
177
178   QString imageFilename = dialog.getImageFilepath();
179   /*
180   QString medFilename   = dialog.getMedFilepath();
181   bool autoLoad         = dialog.isAutoLoaded();
182
183   std::string ROOT_DIR(getenv("MED_ROOT_DIR"));
184   std::string command(ROOT_DIR+"/bin/salome/med/image2med.py");
185   command += " -i "+QS2S(imageFilename);
186   command += " -m "+QS2S(medFilename);
187   int error = system(command.c_str());
188   if ( error != 0 ) {
189     QMessageBox::critical(_salomeModule->getApp()->desktop(),
190            tr("Operation failed"),
191            tr("The creation of med data from the image file failed"));
192     return;
193   }
194
195   if ( autoLoad ) {
196     this->addDatasource(QCHARSTAR(medFilename));
197     _salomeModule->updateObjBrowser(true);
198   }
199   */
200
201   DatasourceEvent* event = new DatasourceEvent();
202   event->eventtype = DatasourceEvent::EVENT_ADD_IMAGE_AS_DATASOURCE;
203   event->objectalias = imageFilename;
204   emit datasourceSignal(event);
205 }
206
207 void DatasourceController::OnExpandField()
208 {
209   // We need a studyEditor updated on the active study
210   _studyEditor->updateActiveStudy();
211
212   // Get the selected objects in the study (SObject)
213   SALOME_StudyEditor::SObjectList* listOfSObject = _studyEditor->getSelectedObjects();
214   for (int i=0; i<listOfSObject->size(); i++) {
215     SALOMEDS::SObject_var soFieldseries = listOfSObject->at(i);
216
217     // First retrieve the fieldseries id associated to this study object
218     long fieldseriesId = _studyEditor->getParameterInt(soFieldseries,FIELD_SERIES_ID);
219     //long fieldseriesId = _studyEditor->getParameterInt(soFieldseries,FIELD_ID);
220     STDLOG("Expand the field timeseries "<<fieldseriesId);
221
222     // If fieldseriesId equals -1, then it means that it is not a
223     // fieldseries managed by the MED module, and we stop this
224     // function process.
225     if ( fieldseriesId < 0 )
226       continue;
227     // _GBO_ A better correction should be to no display the
228     // contextual menu if the selected object is not conform
229
230     // Then retrieve the list of fields in this timeseries
231     MEDCALC::FieldHandlerList* fieldHandlerList =
232       MEDFactoryClient::getDataManager()->getFieldListInFieldseries(fieldseriesId);
233
234     // Finally, create an entry for each of the field
235     for(CORBA::ULong iField=0; iField<fieldHandlerList->length(); iField++) {
236       MEDCALC::FieldHandler fieldHandler = (*fieldHandlerList)[iField];
237       SALOMEDS::SObject_var soField = _studyEditor->newObject(soFieldseries);
238       std::string label("it="); label += ToString(fieldHandler.iteration);
239       _studyEditor->setName(soField,label.c_str());
240       _studyEditor->setParameterInt(soField, FIELD_ID, fieldHandler.id);
241       _studyEditor->setParameterBool(soField,IS_IN_WORKSPACE,false);
242     }
243   }
244   _salomeModule->updateObjBrowser(true);
245 }
246
247 void DatasourceController::OnUseInWorkspace() {
248   // We need a studyEditor updated on the active study
249   _studyEditor->updateActiveStudy();
250
251   // Get the selected objects in the study (SObject)
252   SALOME_StudyEditor::SObjectList* listOfSObject = _studyEditor->getSelectedObjects();
253   if ( listOfSObject->size() == 1 ) {
254     // In this case we ask the name of the variable for the python
255     // console
256
257     // >>>
258     // _GBO_ Note that it works only for a single field but the
259     // XmedDataObject will be improved to deal with mesh, timeseries
260     // and single field in a futur version. We suppose here that a
261     // single field has been selected.
262     // <<<
263
264     SALOMEDS::SObject_var soField = listOfSObject->at(0);
265
266     bool isInWorkspace = _studyEditor->getParameterBool(soField,IS_IN_WORKSPACE);
267     if ( isInWorkspace ) {
268       QMessageBox::warning(_salomeModule->getApp()->desktop(),
269          tr("Operation not allowed"),
270          tr("This field is already defined in the workspace"));
271       return;
272     }
273
274     int fieldId = _studyEditor->getParameterInt(soField,FIELD_ID);
275
276     // If fieldId equals -1, then it means that it is not a field
277     // managed by the MED module, and we stop this function process.
278     if ( fieldId < 0 ) {
279       QMessageBox::warning(_salomeModule->getApp()->desktop(),
280          tr("Operation not allowed"),
281          tr("This element is not a field object"));
282       return;
283     }
284
285     MEDCALC::FieldHandler* fieldHandler =
286       MEDFactoryClient::getDataManager()->getFieldHandler(fieldId);
287
288     if (! fieldHandler) {
289       QMessageBox::warning(_salomeModule->getApp()->desktop(),
290          tr("Operation not allowed"),
291          tr("No field is defined"));
292       return;
293     }
294
295     QString alias(fieldHandler->fieldname);
296     DlgAlias dialog;
297     dialog.setAlias(alias);
298     int choice = dialog.exec();
299     if ( choice == QDialog::Rejected ) {
300       // The user decides to cancel the operation
301       return;
302     }
303     alias = dialog.getAlias();
304
305     DatasourceEvent* event = new DatasourceEvent();
306     event->eventtype = DatasourceEvent::EVENT_USE_OBJECT;
307     XmedDataObject* dataObject = new XmedDataObject();
308     dataObject->setFieldHandler(*fieldHandler);
309     event->objectdata  = dataObject;
310     event->objectalias = alias;
311     emit datasourceSignal(event);
312     // Tag the item to prevent double import
313     //    _studyEditor->setParameterBool(soField,IS_IN_WORKSPACE,true);
314     // Tag the field as persistent on the server. It means that a
315     // saving of the workspace will save at least this field (maybe it
316     // should be an option?)
317     MEDFactoryClient::getDataManager()->markAsPersistent(fieldId, true);
318   }
319   else {
320     // In this case, we don't ask the user to specify an alias for
321     // each item, we just import the whole set of items.
322     for (int i=0; i<listOfSObject->size(); i++) {
323       SALOMEDS::SObject_var soField = listOfSObject->at(i);
324
325       bool isInWorkspace = _studyEditor->getParameterBool(soField,IS_IN_WORKSPACE);
326       if ( !isInWorkspace ) {
327         int fieldId = _studyEditor->getParameterInt(soField,FIELD_ID);
328         MEDCALC::FieldHandler* fieldHandler =
329           MEDFactoryClient::getDataManager()->getFieldHandler(fieldId);
330         DatasourceEvent* event = new DatasourceEvent();
331         event->eventtype = DatasourceEvent::EVENT_IMPORT_OBJECT;
332         XmedDataObject* dataObject = new XmedDataObject();
333         dataObject->setFieldHandler(*fieldHandler);
334         event->objectdata  = dataObject;
335         emit datasourceSignal(event);
336         // Note that this signal is processed by the WorkspaceController
337
338         // Tag the item to prevent double import
339         //        _studyEditor->setParameterBool(soField,IS_IN_WORKSPACE,true);
340         // Tag the field as persistent on the server. It means that a
341         // saving of the workspace will save at least this field (maybe it
342         // should be an option?)
343         MEDFactoryClient::getDataManager()->markAsPersistent(fieldId, true);
344       }
345       else {
346         STDLOG("The field "<<_studyEditor->getName(soField)<<
347                " is already defined in the workspace");
348       }
349     }
350   }
351 }
352
353 void
354 DatasourceController::processWorkspaceEvent(const MEDCALC::MedEvent* event)
355 {
356   if ( event->type == MEDCALC::EVENT_ADD_DATASOURCE ) {
357     MEDCALC::DatasourceHandler* datasourceHandler = MEDFactoryClient::getDataManager()->getDatasourceHandler(event->filename);
358     this->updateTreeViewWithNewDatasource(datasourceHandler);
359   }
360 }