2 // Author : Guillaume Boulant (EDF)
4 #include "WorkspaceController.hxx"
5 #include "QtHelper.hxx"
6 #include "MEDOPFactoryClient.hxx"
7 #include "XmedDataModel.hxx"
8 #include "DlgAlias.hxx"
10 #include <SALOMEconfig.h>
11 #include CORBA_CLIENT_HEADER(MEDEventListener)
13 #include <SalomeApp_Application.h>
14 #include <SALOME_LifeCycleCORBA.hxx>
15 #include <SUIT_FileDlg.h>
16 #include <SUIT_Desktop.h>
19 * This class defines a DockWidget plugged in the SALOME application,
20 * and containing a tree view for rendering a hierarchical data
21 * model. This datamodel contains the objects used in the workspace.
23 WorkspaceController::WorkspaceController(StandardApp_Module * salomeModule)
24 : TreeGuiManager(salomeModule->getApp(), "Workspace")
26 _salomeModule = salomeModule;
28 this->tabifyDockWidgets(false);
30 // -------------------------------------------------------------
31 // Setup the MEDEventListener to manage notification from the
34 // We create a MEDEventListener CORBA object inside this GUI class
35 // with the role of listening events coming from the python console
36 // (or even the components if needed). The events arising in the
37 // python console are send as CORBA request to this CORBA
38 // servant. Then this object can process the event by notifying the
39 // GUI of something to update for example (using signals and slots
41 _medEventListener = MEDEventListener_i::getInstance();
42 MEDOP::MEDEventListener_ptr medEventListenerServant = _medEventListener->_this();
44 // We store the IOR inside the MEDDataManager to share this data
45 // with other parts of the application, in particular the python
46 // console that could retrieve this IOR using the
47 // getEventListenerIOR() function of the MEDDataManager.
48 SalomeApp_Application * salomeApp = salomeModule->getApp();
49 const char * medEventListenerIOR =
50 salomeApp->orb()->object_to_string(medEventListenerServant);
51 MEDOPFactoryClient::getDataManager()->setEventListenerIOR(medEventListenerIOR);
53 // Connect the signals emitted from the MEDEventListener to slot of
55 connect(_medEventListener, SIGNAL(medEventSignal(const MEDOP::MedEvent*)),
56 this, SLOT(processMedEvent(const MEDOP::MedEvent*)));
58 // Note that this class must be mocked (Q_OBJECT + moc file
59 // generated from header file) so that to be able to connect a
60 // signal to a slot of this class.
62 // -------------------------------------------------------------
63 // Customize the treeview rendering the datamodel with specific
64 // action for the popup menu
65 this->getDataTreeView()->clearActions();
66 _actionIds.display = this->getDataTreeView()->addAction(QObject::tr("Visualiser (une carte scalaire)"));
67 _actionIds.useInTui = this->getDataTreeView()->addAction(QObject::tr("Utiliser (dans la console)"));
68 _actionIds.exportToPv = this->getDataTreeView()->addAction(QObject::tr("Exporter (vers PARAVIS)"));
69 _actionIds.save = this->getDataTreeView()->addAction(QObject::tr("Sauvegarder (dans un fichier med)"));
70 _actionIds.remove = this->getDataTreeView()->addAction(QObject::tr("Supprimer (de lespace de travail)"));
72 // -------------------------------------------------------------
73 // Initialize the python console. Note that this must be done at
74 // last because the setup will try to initiate a connection to the
76 _consoleDriver = new XmedConsoleDriver(salomeApp);
77 _consoleDriver->setup();
80 WorkspaceController::~WorkspaceController() {
81 MEDEventListener_i::release();
85 * This creates the GUI actions for driving the Workspace. The
86 * WorkspaceController creates itself this actions and implements the
89 void WorkspaceController::createActions() {
91 QString label = QString("Save workspace");
92 QString tooltip = QString("Save the workspace (fields and meshes) in a med file");
93 QString icon = QString("workspace_save.png");
94 int actionId = _salomeModule->createStandardAction(label,this,SLOT(OnSaveWorkspace()),icon,tooltip);
95 _salomeModule->addActionInToolbar(actionId);
97 label = QString("Clean workspace");
98 tooltip = QString("Clean all data in the workspace");
99 icon = QString("workspace_clean.png");
100 actionId = _salomeModule->createStandardAction(label,this,SLOT(OnCleanWorkspace()),icon,tooltip);
101 _salomeModule->addActionInToolbar(actionId);
105 * Implementation of the slot processItemList inherited from TreeGuiManager
107 void WorkspaceController::processItemList(QStringList itemNameIdList, int actionId) {
108 if ( actionId == _actionIds.display ) {
109 STDLOG("WorkspaceController::processItemList: display");
110 this->_viewItemList(itemNameIdList);
112 else if ( actionId == _actionIds.useInTui ) {
113 STDLOG("WorkspaceController::processItemList: use");
114 this->_importItemList(itemNameIdList);
116 else if ( actionId == _actionIds.exportToPv ) {
117 STDLOG("WorkspaceController::processItemList: export");
118 this->_exportItemList(itemNameIdList);
120 else if ( actionId == _actionIds.save ) {
121 STDLOG("WorkspaceController::processItemList: save");
122 this->_saveItemList(itemNameIdList);
124 else if ( actionId == _actionIds.remove ) {
125 STDLOG("WorkspaceController::processItemList: remove");
128 STDLOG("WorkspaceController::processItemList: ERR : action unknown ");
133 * This function import in the console all the fields associated to
134 * the model items of the specified list. "Import a fields" means
135 * "define a field proxy variable in the python context to manipulate
136 * the real field in the database".
138 void WorkspaceController::_importItemList(QStringList itemNameIdList) {
139 LOG("WorkspaceController: signal received : display item list "<<itemNameIdList);
140 QStringList::const_iterator it;
141 for (it = itemNameIdList.constBegin(); it != itemNameIdList.constEnd(); ++it) {
142 QString itemNameId = *it;
143 this->_importItem(itemNameId);
148 * This function is the unit function used to import field in the
149 * console (see _importItemList).
151 void WorkspaceController::_importItem(QString itemNameId) {
152 XmedDataModel * dataModel = (XmedDataModel *)this->getDataModel();
153 if ( dataModel == NULL ) {
154 LOG("No data model associated to this tree view");
158 // We can request the dataModel to obtain the dataObject associated
159 // to this item (iteNameId is a TreeView id, Qt stuff only).
160 XmedDataObject * dataObject =
161 (XmedDataObject *)dataModel->getDataObject(QS2S(itemNameId));
163 if ( dataObject == NULL ) {
164 LOG("WorkspaceController: WARN! No data object associated to the item "<<itemNameId);
168 // Then, we can request this data object to obtain the associated
170 MEDOP::FieldHandler * fieldHandler = dataObject->getFieldHandler();
171 STDLOG("Field: mesh="<<fieldHandler->meshname<<" name="<<fieldHandler->fieldname);
173 // Finally, we can import the field
174 bool askForOptions = true;
175 _importFieldIntoConsole(fieldHandler, askForOptions);
179 * This function import the specified field into the tui console. This
180 * means to define a field proxy variable in the python context to
181 * manipulate the field. We can raise a gui to specify some import
182 * options or simply specify the alias (i.e. the name of the python
185 void WorkspaceController::_importFieldIntoConsole(MEDOP::FieldHandler * fieldHandler,
189 STDLOG("alias="<<alias);
191 // By default, the alias is the name of the field
192 QString *effectiveAlias;
193 if ( alias == NULL ) {
194 effectiveAlias = new QString(fieldHandler->fieldname);
197 effectiveAlias = new QString(alias);
200 // We can propose to the user to specify some additionnal
201 // informations concerning what must be imported.
203 // In this version, we just ask the alias the field will be
204 // manipulated with. The default alias is the field name. This alias
205 // should be asked to the user to get a short name to manipulate.
206 if ( askForOptions ) {
208 dialog.setAlias(*effectiveAlias);
209 int choice = dialog.exec();
210 if ( choice == QDialog::Rejected ) {
211 // The user decides to cancel the operation
214 *effectiveAlias = dialog.getAlias();
218 // Then, the list of python commands can be written and executed to
219 // define the field in the console
221 QStringList commands;
222 commands+=QString("%1=xmed.fieldproxy.newFieldProxy(fieldHandlerId=%2)")
223 .arg(*effectiveAlias)
224 .arg(fieldHandler->id);
226 _consoleDriver->exec(commands);
230 * This function is a Qt slot connected to the signal medEventSignal
231 * emitted from the MEDEventListener. It processes events coming from
232 * the python console.
234 void WorkspaceController::processMedEvent(const MEDOP::MedEvent * event) {
235 STDLOG("WorkspaceController::processMedEvent");
236 STDLOG("fieldid :"<<event->fieldid);
238 XmedDataModel * dataModel = (XmedDataModel *)this->getDataModel();
239 if ( dataModel == NULL ) {
240 STDLOG("No data model associated to this tree view");
244 if ( event->type == MEDOP::EVENT_ADDNEW_FIELD ) {
245 STDLOG("add new field");
246 MEDOP::FieldHandler * fieldHandler =
247 MEDOPFactoryClient::getDataManager()->getFieldHandler(event->fieldid);
249 XmedDataObject * dataObject = (XmedDataObject *)dataModel->newDataObject();
250 dataObject->setFieldHandler(*fieldHandler);
251 this->getDataTreeModel()->addData(dataObject);
257 * This function save a list of fields in a med file. The med file
258 * name is requested to the user using a file chooser dialog box
260 void WorkspaceController::_saveItemList(QStringList itemNameIdList) {
261 XmedDataProcessor * dataProcessor = new XmedDataProcessor(this->getDataModel());
262 dataProcessor->process(itemNameIdList);
263 MEDOP::FieldIdList_var fieldIdList = dataProcessor->getResultingFieldIdList();
264 delete dataProcessor;
267 filter.append(QObject::tr("MED files (*.med)"));
268 QString filename = SUIT_FileDlg::getFileName(_salomeModule->getApp()->desktop(),
271 QObject::tr("Save selected fields"),
274 if ( filename.isEmpty() ) return;
276 MEDOPFactoryClient::getDataManager()->saveFields(QCHARSTAR(filename), fieldIdList);
280 * This function export the list of specified field item to PARAVIS
281 * module. This consists in create a med file gathering the selected
282 * items, then to import this file in PARAVIS, and finally to create a
283 * scalar map of the first item to start the job.
285 void WorkspaceController::_exportItemList(QStringList itemNameIdList) {
286 XmedDataProcessor * dataProcessor = new XmedDataProcessor(this->getDataModel());
287 dataProcessor->process(itemNameIdList);
288 MEDOP::FieldIdList_var fieldIdList = dataProcessor->getResultingFieldIdList();
289 delete dataProcessor;
291 // _GBO_ We use a temporary file to proceed with this export to
292 // paravis. I'm sure it could be better in a futur version or when I
293 // will get a better understanding of paravis API.
294 const char * tmpfilename = "/tmp/medop_export2paravis.med";
295 MEDOPFactoryClient::getDataManager()->saveFields(tmpfilename, fieldIdList);
297 // We import the whole file but create a scalar map for the first
298 // selected field only (it's just an export to continue the job in
300 XmedDataModel * dataModel = (XmedDataModel *)this->getDataModel();
301 if ( dataModel == NULL ) {
302 STDLOG("No data model associated to this tree view");
305 QString itemNameId = itemNameIdList[0];
306 XmedDataObject * dataObject = (XmedDataObject *)dataModel->getDataObject(QS2S(itemNameId));
307 if ( dataObject == NULL ) {
308 LOG("WorkspaceController: WARN! No data object associated to the item "<<itemNameId);
311 MEDOP::FieldHandler * fieldHandler = dataObject->getFieldHandler();
312 QStringList commands;
313 commands+=QString("from xmed.driver_pvis import pvis_scalarmap");
314 commands+=QString("pvis_scalarmap('%1','%2','%3',%4,%5)")
316 .arg(QString(fieldHandler->meshname))
317 .arg(QString(fieldHandler->fieldname))
318 .arg(fieldHandler->type)
319 .arg(fieldHandler->iteration);
320 _consoleDriver->exec(commands);
326 * This function sends a request to the SALOME data visualisation
327 * (module VISU or PARAVIS) for displaying a scalar map of the fields
328 * associated to the model items in the specified list.
331 void WorkspaceController::_viewItemList(QStringList itemNameIdList) {
333 // __GBO__: In this version, we consider only the first field in the selection
334 QString itemNameId = itemNameIdList[0];
336 XmedDataModel * dataModel = (XmedDataModel *)this->getDataModel();
337 if ( dataModel == NULL ) {
338 LOG("No data model associated to this tree view");
342 // We can request the dataModel to obtain the dataObject associated
343 // to this item (iteNameId is a TreeView id, Qt stuff only).
344 XmedDataObject * dataObject =
345 (XmedDataObject *)dataModel->getDataObject(QS2S(itemNameId));
346 if ( dataObject == NULL ) {
347 LOG("WorkspaceController: WARN! No data object associated to the item "<<itemNameId);
351 // Then, we can request this data object to obtain the associated
353 MEDOP::FieldHandler * fieldHandler = dataObject->getFieldHandler();
355 // And finally, we can create the set of medop instructions to
356 // generate the scalar map on this field.
357 QStringList commands;
358 commands+=QString("view(get(%1))").arg(fieldHandler->id);
359 _consoleDriver->exec(commands);
363 * This slot can process the event coming from the
364 * DatasourceController. The connection between the datasource signal
365 * and this slot is realized by the main class MEDOPModule.
367 void WorkspaceController::processDatasourceEvent(const DatasourceEvent * event) {
368 XmedDataModel * dataModel = (XmedDataModel *)this->getDataModel();
369 if ( dataModel == NULL ) {
370 STDLOG("No data model associated to this tree view");
375 // __GBO__ To know what to do we should test the type, because the
376 // object could be a mesh, a timeseries or a single field. We test
377 // here the case of a single field. Moreover, there could have
378 // options such that "change the underlying mesh".
381 XmedDataObject * dataObject = event->objectdata;
383 if ( event->eventtype == DatasourceEvent::EVENT_IMPORT_OBJECT ) {
384 STDLOG("IMPORT object in workspace:\n"<<dataObject->toString());
385 // _GBO_ QUESTION: tag automatically the object as a peristant object ??
386 // We first add the data object to the internal data model
387 dataModel->addDataObject(dataObject);
388 // Then we request the tree view to consider this new object
389 this->getDataTreeModel()->addData(dataObject);
391 else if ( event->eventtype == DatasourceEvent::EVENT_USE_OBJECT ) {
392 STDLOG("USE object in workspace:\n"<<dataObject->toString());
393 // We first add the data object to the internal data model
394 dataModel->addDataObject(dataObject);
395 // Then we request the tree view to consider this new object
396 this->getDataTreeModel()->addData(dataObject);
398 // We define a proxy for this object in the tui console.
399 STDLOG("Define a proxy variable in the console with name : "<<QCHARSTAR(event->objectalias));
400 bool askForOptions = false;
401 _importFieldIntoConsole(dataObject->getFieldHandler(),
403 QCHARSTAR(event->objectalias));
405 else if ( event->eventtype == DatasourceEvent::EVENT_VIEW_OBJECT ) {
406 QStringList commands;
407 commands+=QString("view(get(%1))").arg(dataObject->getFieldHandler()->id);
408 _consoleDriver->exec(commands);
411 STDLOG("The event "<<event->eventtype<<" is not implemented yet");
416 void WorkspaceController::OnSaveWorkspace() {
418 // Dialog to get the filename where the workspace must be saved into
420 filter.append(QObject::tr("MED files (*.med)"));
422 QString filename = SUIT_FileDlg::getFileName(_salomeModule->getApp()->desktop(),
425 QObject::tr("Save workspace data"),
428 if ( filename.isEmpty() ) return;
430 STDLOG("OnWorkspaceSave: save the workspace in the file " << QCHARSTAR(filename));
431 QStringList commands;
432 commands+=QString("save('%1')").arg(filename);
433 _consoleDriver->exec(commands);
436 #include <QMessageBox>
437 void WorkspaceController::OnCleanWorkspace() {
438 QMessageBox::warning(_salomeModule->getApp()->desktop(),
439 tr("Not implemented yet"),
440 tr("This function is not implemented yet"));