1 // Copyright (C) 2007-2013 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.
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 "WorkspaceController.hxx"
23 #include "QtHelper.hxx"
24 #include "MEDOPFactoryClient.hxx"
25 #include "XmedDataModel.hxx"
26 #include "DlgAlias.hxx"
28 #include <SALOMEconfig.h>
29 #include CORBA_CLIENT_HEADER(MEDEventListener)
31 #include <SalomeApp_Application.h>
32 #include <SALOME_LifeCycleCORBA.hxx>
33 #include <SUIT_FileDlg.h>
34 #include <SUIT_Desktop.h>
37 * This class defines a DockWidget plugged in the SALOME application,
38 * and containing a tree view for rendering a hierarchical data
39 * model. This datamodel contains the objects used in the workspace.
41 WorkspaceController::WorkspaceController(StandardApp_Module * salomeModule)
42 : TreeGuiManager(salomeModule->getApp(), "Workspace")
44 _salomeModule = salomeModule;
46 this->tabifyDockWidgets(false);
48 // -------------------------------------------------------------
49 // Setup the MEDEventListener to manage notification from the
52 // We create a MEDEventListener CORBA object inside this GUI class
53 // with the role of listening events coming from the python console
54 // (or even the components if needed). The events arising in the
55 // python console are send as CORBA request to this CORBA
56 // servant. Then this object can process the event by notifying the
57 // GUI of something to update for example (using signals and slots
59 _medEventListener = MEDEventListener_i::getInstance();
60 MEDOP::MEDEventListener_ptr medEventListenerServant = _medEventListener->_this();
62 // We store the IOR inside the MEDDataManager to share this data
63 // with other parts of the application, in particular the python
64 // console that could retrieve this IOR using the
65 // getEventListenerIOR() function of the MEDDataManager.
66 SalomeApp_Application * salomeApp = salomeModule->getApp();
67 const char * medEventListenerIOR =
68 salomeApp->orb()->object_to_string(medEventListenerServant);
69 MEDOPFactoryClient::getDataManager()->setEventListenerIOR(medEventListenerIOR);
71 // Connect the signals emitted from the MEDEventListener to slot of
73 connect(_medEventListener, SIGNAL(medEventSignal(const MEDOP::MedEvent*)),
74 this, SLOT(processMedEvent(const MEDOP::MedEvent*)));
76 // Note that this class must be mocked (Q_OBJECT + moc file
77 // generated from header file) so that to be able to connect a
78 // signal to a slot of this class.
80 // -------------------------------------------------------------
81 // Customize the treeview rendering the datamodel with specific
82 // action for the popup menu
83 this->getDataTreeView()->clearActions();
84 _actionIds.display = this->getDataTreeView()->addAction(tr("VISUALIZE_SCALAR_MAP"));
85 _actionIds.useInTui = this->getDataTreeView()->addAction(tr("USE_IN_CONSOLE"));
86 _actionIds.exportToPv = this->getDataTreeView()->addAction(tr("EXPORT_TO_PARAVIS"));
87 _actionIds.save = this->getDataTreeView()->addAction(tr("SAVE_AS_MED"));
88 _actionIds.remove = this->getDataTreeView()->addAction(tr("REMOVE_FROM_WORKSPACE"));
90 // -------------------------------------------------------------
91 // Initialize the python console. Note that this must be done at
92 // last because the setup will try to initiate a connection to the
94 _consoleDriver = new XmedConsoleDriver(salomeApp);
95 _consoleDriver->setup();
98 WorkspaceController::~WorkspaceController() {
99 MEDEventListener_i::release();
103 * This creates the GUI actions for driving the Workspace. The
104 * WorkspaceController creates itself this actions and implements the
107 void WorkspaceController::createActions() {
109 QString label = tr("LAB_SAVE_WORKSPACE");
110 QString tooltip = tr("TIP_SAVE_WORKSPACE");
111 QString icon = tr("ICO_WORKSPACE_SAVE");
112 int actionId = _salomeModule->createStandardAction(label,this,SLOT(OnSaveWorkspace()),icon,tooltip);
113 _salomeModule->addActionInToolbar(actionId);
115 label = tr("LAB_CLEAN_WORKSPACE");
116 tooltip = tr("TIP_CLEAN_WORKSPACE");
117 icon = tr("ICO_WORKSPACE_CLEAN");
118 actionId = _salomeModule->createStandardAction(label,this,SLOT(OnCleanWorkspace()),icon,tooltip);
119 _salomeModule->addActionInToolbar(actionId);
123 * Implementation of the slot processItemList inherited from TreeGuiManager
125 void WorkspaceController::processItemList(QStringList itemNameIdList, int actionId) {
126 if ( actionId == _actionIds.display ) {
127 STDLOG("WorkspaceController::processItemList: display");
128 this->_viewItemList(itemNameIdList);
130 else if ( actionId == _actionIds.useInTui ) {
131 STDLOG("WorkspaceController::processItemList: use");
132 this->_importItemList(itemNameIdList);
134 else if ( actionId == _actionIds.exportToPv ) {
135 STDLOG("WorkspaceController::processItemList: export");
136 this->_exportItemList(itemNameIdList);
138 else if ( actionId == _actionIds.save ) {
139 STDLOG("WorkspaceController::processItemList: save");
140 this->_saveItemList(itemNameIdList);
142 else if ( actionId == _actionIds.remove ) {
143 STDLOG("WorkspaceController::processItemList: remove");
146 STDLOG("WorkspaceController::processItemList: ERR : action unknown ");
151 * This function import in the console all the fields associated to
152 * the model items of the specified list. "Import a fields" means
153 * "define a field proxy variable in the python context to manipulate
154 * the real field in the database".
156 void WorkspaceController::_importItemList(QStringList itemNameIdList) {
157 LOG("WorkspaceController: signal received : display item list "<<itemNameIdList);
158 QStringList::const_iterator it;
159 for (it = itemNameIdList.constBegin(); it != itemNameIdList.constEnd(); ++it) {
160 QString itemNameId = *it;
161 this->_importItem(itemNameId);
166 * This function is the unit function used to import field in the
167 * console (see _importItemList).
169 void WorkspaceController::_importItem(QString itemNameId) {
170 XmedDataModel * dataModel = (XmedDataModel *)this->getDataModel();
171 if ( dataModel == NULL ) {
172 LOG("No data model associated to this tree view");
176 // We can request the dataModel to obtain the dataObject associated
177 // to this item (iteNameId is a TreeView id, Qt stuff only).
178 XmedDataObject * dataObject =
179 (XmedDataObject *)dataModel->getDataObject(QS2S(itemNameId));
181 if ( dataObject == NULL ) {
182 LOG("WorkspaceController: WARN! No data object associated to the item "<<itemNameId);
186 // Then, we can request this data object to obtain the associated
188 MEDOP::FieldHandler * fieldHandler = dataObject->getFieldHandler();
189 STDLOG("Field: mesh="<<fieldHandler->meshname<<" name="<<fieldHandler->fieldname);
191 // Finally, we can import the field
192 bool askForOptions = true;
193 _importFieldIntoConsole(fieldHandler, askForOptions);
197 * This function import the specified field into the tui console. This
198 * means to define a field proxy variable in the python context to
199 * manipulate the field. We can raise a gui to specify some import
200 * options or simply specify the alias (i.e. the name of the python
203 void WorkspaceController::_importFieldIntoConsole(MEDOP::FieldHandler * fieldHandler,
207 STDLOG("alias="<<alias);
209 // By default, the alias is the name of the field
210 QString *effectiveAlias;
211 if ( alias == NULL ) {
212 effectiveAlias = new QString(fieldHandler->fieldname);
215 effectiveAlias = new QString(alias);
218 // We can propose to the user to specify some additionnal
219 // informations concerning what must be imported.
221 // In this version, we just ask the alias the field will be
222 // manipulated with. The default alias is the field name. This alias
223 // should be asked to the user to get a short name to manipulate.
224 if ( askForOptions ) {
226 dialog.setAlias(*effectiveAlias);
227 int choice = dialog.exec();
228 if ( choice == QDialog::Rejected ) {
229 // The user decides to cancel the operation
232 *effectiveAlias = dialog.getAlias();
236 // Then, the list of python commands can be written and executed to
237 // define the field in the console
239 QStringList commands;
240 commands+=QString("%1=xmed.fieldproxy.newFieldProxy(fieldHandlerId=%2)")
241 .arg(*effectiveAlias)
242 .arg(fieldHandler->id);
244 _consoleDriver->exec(commands);
248 * This function is a Qt slot connected to the signal medEventSignal
249 * emitted from the MEDEventListener. It processes events coming from
250 * the python console.
252 void WorkspaceController::processMedEvent(const MEDOP::MedEvent * event) {
253 STDLOG("WorkspaceController::processMedEvent");
254 STDLOG("fieldid :"<<event->fieldid);
256 XmedDataModel * dataModel = (XmedDataModel *)this->getDataModel();
257 if ( dataModel == NULL ) {
258 STDLOG("No data model associated to this tree view");
262 if ( event->type == MEDOP::EVENT_ADDNEW_FIELD ) {
263 STDLOG("add new field");
264 MEDOP::FieldHandler * fieldHandler =
265 MEDOPFactoryClient::getDataManager()->getFieldHandler(event->fieldid);
267 XmedDataObject * dataObject = (XmedDataObject *)dataModel->newDataObject();
268 dataObject->setFieldHandler(*fieldHandler);
269 this->getDataTreeModel()->addData(dataObject);
275 * This function save a list of fields in a med file. The med file
276 * name is requested to the user using a file chooser dialog box
278 void WorkspaceController::_saveItemList(QStringList itemNameIdList) {
279 XmedDataProcessor * dataProcessor = new XmedDataProcessor(this->getDataModel());
280 dataProcessor->process(itemNameIdList);
281 MEDOP::FieldIdList_var fieldIdList = dataProcessor->getResultingFieldIdList();
282 delete dataProcessor;
285 filter.append(tr("FILE_FILTER_MED"));
286 QString filename = SUIT_FileDlg::getFileName(_salomeModule->getApp()->desktop(),
289 tr("SAVE_SELECTED_FIELDS"),
292 if ( filename.isEmpty() ) return;
294 MEDOPFactoryClient::getDataManager()->saveFields(QCHARSTAR(filename), fieldIdList);
298 * This function export the list of specified field item to PARAVIS
299 * module. This consists in create a med file gathering the selected
300 * items, then to import this file in PARAVIS, and finally to create a
301 * scalar map of the first item to start the job.
303 void WorkspaceController::_exportItemList(QStringList itemNameIdList) {
304 XmedDataProcessor * dataProcessor = new XmedDataProcessor(this->getDataModel());
305 dataProcessor->process(itemNameIdList);
306 MEDOP::FieldIdList_var fieldIdList = dataProcessor->getResultingFieldIdList();
307 delete dataProcessor;
309 // _GBO_ We use a temporary file to proceed with this export to
310 // paravis. I'm sure it could be better in a futur version or when I
311 // will get a better understanding of paravis API.
312 const char * tmpfilename = "/tmp/medop_export2paravis.med";
313 MEDOPFactoryClient::getDataManager()->saveFields(tmpfilename, fieldIdList);
315 // We import the whole file but create a scalar map for the first
316 // selected field only (it's just an export to continue the job in
318 XmedDataModel * dataModel = (XmedDataModel *)this->getDataModel();
319 if ( dataModel == NULL ) {
320 STDLOG("No data model associated to this tree view");
323 QString itemNameId = itemNameIdList[0];
324 XmedDataObject * dataObject = (XmedDataObject *)dataModel->getDataObject(QS2S(itemNameId));
325 if ( dataObject == NULL ) {
326 LOG("WorkspaceController: WARN! No data object associated to the item "<<itemNameId);
329 MEDOP::FieldHandler * fieldHandler = dataObject->getFieldHandler();
330 QStringList commands;
331 commands+=QString("from xmed.driver_pvis import pvis_scalarmap");
332 commands+=QString("pvis_scalarmap('%1','%2','%3',%4,%5)")
334 .arg(QString(fieldHandler->meshname))
335 .arg(QString(fieldHandler->fieldname))
336 .arg(fieldHandler->type)
337 .arg(fieldHandler->iteration);
338 _consoleDriver->exec(commands);
344 * This function sends a request to the SALOME data visualisation
345 * (module VISU or PARAVIS) for displaying a scalar map of the fields
346 * associated to the model items in the specified list.
349 void WorkspaceController::_viewItemList(QStringList itemNameIdList) {
351 // __GBO__: In this version, we consider only the first field in the selection
352 QString itemNameId = itemNameIdList[0];
354 XmedDataModel * dataModel = (XmedDataModel *)this->getDataModel();
355 if ( dataModel == NULL ) {
356 LOG("No data model associated to this tree view");
360 // We can request the dataModel to obtain the dataObject associated
361 // to this item (iteNameId is a TreeView id, Qt stuff only).
362 XmedDataObject * dataObject =
363 (XmedDataObject *)dataModel->getDataObject(QS2S(itemNameId));
364 if ( dataObject == NULL ) {
365 LOG("WorkspaceController: WARN! No data object associated to the item "<<itemNameId);
369 // Then, we can request this data object to obtain the associated
371 MEDOP::FieldHandler * fieldHandler = dataObject->getFieldHandler();
373 // And finally, we can create the set of medop instructions to
374 // generate the scalar map on this field.
375 QStringList commands;
376 commands+=QString("view(get(%1))").arg(fieldHandler->id);
377 _consoleDriver->exec(commands);
381 * This slot can process the event coming from the
382 * DatasourceController. The connection between the datasource signal
383 * and this slot is realized by the main class MEDOPModule.
385 void WorkspaceController::processDatasourceEvent(const DatasourceEvent * event) {
386 XmedDataModel * dataModel = (XmedDataModel *)this->getDataModel();
387 if ( dataModel == NULL ) {
388 STDLOG("No data model associated to this tree view");
393 // __GBO__ To know what to do we should test the type, because the
394 // object could be a mesh, a timeseries or a single field. We test
395 // here the case of a single field. Moreover, there could have
396 // options such that "change the underlying mesh".
399 XmedDataObject * dataObject = event->objectdata;
401 if ( event->eventtype == DatasourceEvent::EVENT_IMPORT_OBJECT ) {
402 STDLOG("IMPORT object in workspace:\n"<<dataObject->toString());
403 // _GBO_ QUESTION: tag automatically the object as a peristant object ??
404 // We first add the data object to the internal data model
405 dataModel->addDataObject(dataObject);
406 // Then we request the tree view to consider this new object
407 this->getDataTreeModel()->addData(dataObject);
409 else if ( event->eventtype == DatasourceEvent::EVENT_USE_OBJECT ) {
410 STDLOG("USE object in workspace:\n"<<dataObject->toString());
411 // We first add the data object to the internal data model
412 dataModel->addDataObject(dataObject);
413 // Then we request the tree view to consider this new object
414 this->getDataTreeModel()->addData(dataObject);
416 // We define a proxy for this object in the tui console.
417 STDLOG("Define a proxy variable in the console with name : "<<QCHARSTAR(event->objectalias));
418 bool askForOptions = false;
419 _importFieldIntoConsole(dataObject->getFieldHandler(),
421 QCHARSTAR(event->objectalias));
423 else if ( event->eventtype == DatasourceEvent::EVENT_VIEW_OBJECT ) {
424 QStringList commands;
425 commands+=QString("view(get(%1))").arg(dataObject->getFieldHandler()->id);
426 _consoleDriver->exec(commands);
429 STDLOG("The event "<<event->eventtype<<" is not implemented yet");
434 void WorkspaceController::OnSaveWorkspace() {
436 // Dialog to get the filename where the workspace must be saved into
438 filter.append(tr("FILE_FILTER_MED"));
440 QString filename = SUIT_FileDlg::getFileName(_salomeModule->getApp()->desktop(),
443 tr("SAVE_WORKSPACE_DATA"),
446 if ( filename.isEmpty() ) return;
448 STDLOG("OnWorkspaceSave: save the workspace in the file " << QCHARSTAR(filename));
449 QStringList commands;
450 commands+=QString("save('%1')").arg(filename);
451 _consoleDriver->exec(commands);
454 #include <QMessageBox>
455 void WorkspaceController::OnCleanWorkspace() {
456 QMessageBox::warning(_salomeModule->getApp()->desktop(),
457 tr("NOT_IMPLEMENTED_YET"),
458 tr("FUNCTION_NOT_IMPLEMENTED"));