1 // Copyright (C) 2007-2016 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, or (at your option) any later version.
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 "MEDFactoryClient.hxx"
25 #include "MEDModule.hxx"
26 #include "XmedDataModel.hxx"
27 #include "DlgAlias.hxx"
29 #include <SALOMEconfig.h>
30 #include CORBA_CLIENT_HEADER(MEDEventListener)
32 #include <SalomeApp_Application.h>
33 #include <SALOME_LifeCycleCORBA.hxx>
34 #include <SUIT_FileDlg.h>
35 #include <SUIT_Desktop.h>
36 #include <SUIT_ResourceMgr.h>
39 * This class defines a DockWidget plugged in the SALOME application,
40 * and containing a tree view for rendering a hierarchical data
41 * model. This datamodel contains the objects used in the workspace.
43 WorkspaceController::WorkspaceController(MEDModule* salomeModule)
44 : TreeGuiManager(salomeModule->getApp(), "Workspace")
46 _salomeModule = salomeModule;
47 getDockWidgets()->getDockWidget()->setObjectName("medWorkspaceDock");
49 this->tabifyDockWidgets(false);
51 // -------------------------------------------------------------
52 // Setup the MEDEventListener to manage notification from the
55 // We create a MEDEventListener CORBA object inside this GUI class
56 // with the role of listening events coming from the python console
57 // (or even the components if needed). The events arising in the
58 // python console are send as CORBA request to this CORBA
59 // servant. Then this object can process the event by notifying the
60 // GUI of something to update for example (using signals and slots
62 _medEventListener = MEDEventListener_i::getInstance();
63 MEDCALC::MEDEventListener_ptr medEventListenerServant = _medEventListener->_this();
65 // We store the IOR inside the MEDDataManager to share this data
66 // with other parts of the application, in particular the python
67 // console that could retrieve this IOR using the
68 // getEventListenerIOR() function of the MEDDataManager.
69 SalomeApp_Application* salomeApp = salomeModule->getApp();
70 const char* medEventListenerIOR =
71 salomeApp->orb()->object_to_string(medEventListenerServant);
72 MEDFactoryClient::getDataManager()->setEventListenerIOR(medEventListenerIOR);
74 // Connect the signals emitted from the MEDEventListener to slot of
76 connect(_medEventListener, SIGNAL(medEventSignal(const MEDCALC::MedEvent*)),
77 this, SLOT(processMedEvent(const MEDCALC::MedEvent*)));
79 // Note that this class must be mocked (Q_OBJECT + moc file
80 // generated from header file) so that to be able to connect a
81 // signal to a slot of this class.
83 // -------------------------------------------------------------
84 // Customize the treeview rendering the datamodel with specific
85 // action for the popup menu
86 this->getDataTreeView()->clearActions();
87 _actionIds.display = this->getDataTreeView()->addAction(tr("VISUALIZE_SCALAR_MAP"));
88 _actionIds.useInTui = this->getDataTreeView()->addAction(tr("USE_IN_CONSOLE"));
89 _actionIds.exportToPv = this->getDataTreeView()->addAction(tr("EXPORT_TO_PARAVIS"));
90 _actionIds.save = this->getDataTreeView()->addAction(tr("SAVE_AS_MED"));
91 _actionIds.remove = this->getDataTreeView()->addAction(tr("REMOVE_FROM_WORKSPACE"));
93 // -------------------------------------------------------------
94 // Initialize the python console. Note that this must be done at
95 // last because the setup will try to initiate a connection to the
97 _consoleDriver = new XmedConsoleDriver(salomeModule);
98 _consoleDriver->setup();
101 WorkspaceController::~WorkspaceController() {
102 STDLOG("WorkspaceController::~WorkspaceController()");
103 MEDEventListener_i::release();
107 * This creates the GUI actions for driving the Workspace. The
108 * WorkspaceController creates itself this actions and implements the
111 void WorkspaceController::createActions() {
112 QWidget* dsk = _salomeModule->getApp()->desktop();
113 SUIT_ResourceMgr* resMgr = _salomeModule->getApp()->resourceMgr();
114 int toolbarId = _salomeModule->createTool("Workspace", "WorkspaceToolbar");
116 QString label = tr("LAB_SAVE_WORKSPACE");
117 QString tooltip = tr("TIP_SAVE_WORKSPACE");
118 QString icon = tr("ICO_WORKSPACE_SAVE");
119 int actionId = _salomeModule->createStandardAction(label,this,SLOT(OnSaveWorkspace()),icon,tooltip);
120 _salomeModule->createTool(actionId, toolbarId);
122 label = tr("LAB_CLEAN_WORKSPACE");
123 tooltip = tr("TIP_CLEAN_WORKSPACE");
124 icon = tr("ICO_WORKSPACE_CLEAN");
125 actionId = _salomeModule->createStandardAction(label,this,SLOT(OnCleanWorkspace()),icon,tooltip);
126 _salomeModule->createTool(actionId, toolbarId);
130 * Implementation of the slot processItemList inherited from TreeGuiManager
132 void WorkspaceController::processItemList(QStringList itemNameIdList, int actionId) {
133 if ( actionId == _actionIds.display ) {
134 STDLOG("WorkspaceController::processItemList: display");
135 this->_viewItemList(itemNameIdList);
137 else if ( actionId == _actionIds.useInTui ) {
138 STDLOG("WorkspaceController::processItemList: use");
139 this->_importItemList(itemNameIdList);
141 else if ( actionId == _actionIds.exportToPv ) {
142 STDLOG("WorkspaceController::processItemList: export");
143 this->_exportItemList(itemNameIdList);
145 else if ( actionId == _actionIds.save ) {
146 STDLOG("WorkspaceController::processItemList: save");
147 this->_saveItemList(itemNameIdList);
149 else if ( actionId == _actionIds.remove ) {
150 STDLOG("WorkspaceController::processItemList: remove");
151 this->_removeItemList(itemNameIdList);
154 STDLOG("WorkspaceController::processItemList: ERR : action unknown ");
159 * This function import in the console all the fields associated to
160 * the model items of the specified list. "Import a fields" means
161 * "define a field proxy variable in the python context to manipulate
162 * the real field in the database".
164 void WorkspaceController::_importItemList(QStringList itemNameIdList) {
165 LOG("WorkspaceController: signal received : display item list "<<itemNameIdList);
166 QStringList::const_iterator it;
167 for (it = itemNameIdList.constBegin(); it != itemNameIdList.constEnd(); ++it) {
168 QString itemNameId = *it;
169 this->_importItem(itemNameId);
174 * This function is the unit function used to import field in the
175 * console (see _importItemList).
177 void WorkspaceController::_importItem(QString itemNameId) {
178 XmedDataModel* dataModel = (XmedDataModel*)this->getDataModel();
179 if ( dataModel == NULL ) {
180 LOG("No data model associated to this tree view");
184 // We can request the dataModel to obtain the dataObject associated
185 // to this item (iteNameId is a TreeView id, Qt stuff only).
186 XmedDataObject* dataObject =
187 (XmedDataObject*)dataModel->getDataObject(QS2S(itemNameId));
189 if ( dataObject == NULL ) {
190 LOG("WorkspaceController: WARN! No data object associated to the item "<<itemNameId);
194 // Then, we can request this data object to obtain the associated
196 MEDCALC::FieldHandler* fieldHandler = dataObject->getFieldHandler();
197 STDLOG("Field: mesh="<<fieldHandler->meshname<<" name="<<fieldHandler->fieldname);
199 // Finally, we can import the field
200 bool askForOptions = true;
201 _importFieldIntoConsole(fieldHandler, askForOptions);
205 * This function import the specified field into the tui console. This
206 * means to define a field proxy variable in the python context to
207 * manipulate the field. We can raise a gui to specify some import
208 * options or simply specify the alias (i.e. the name of the python
211 void WorkspaceController::_importFieldIntoConsole(MEDCALC::FieldHandler* fieldHandler,
215 STDLOG("alias="<<alias);
217 // By default, the alias is the name of the field
218 QString*effectiveAlias;
219 if ( alias == NULL ) {
220 effectiveAlias = new QString(fieldHandler->fieldname);
223 effectiveAlias = new QString(alias);
226 // We can propose to the user to specify some additionnal
227 // informations concerning what must be imported.
229 // In this version, we just ask the alias the field will be
230 // manipulated with. The default alias is the field name. This alias
231 // should be asked to the user to get a short name to manipulate.
232 if ( askForOptions ) {
234 dialog.setAlias(*effectiveAlias);
235 int choice = dialog.exec();
236 if ( choice == QDialog::Rejected ) {
237 // The user decides to cancel the operation
240 *effectiveAlias = dialog.getAlias();
244 // Then, the list of python commands can be written and executed to
245 // define the field in the console
247 QStringList commands;
248 commands+=QString("%1=medcalc.newFieldProxy(fieldHandlerId=%2)")
249 .arg(*effectiveAlias)
250 .arg(fieldHandler->id);
252 _consoleDriver->exec(commands);
256 * This function is a Qt slot connected to the signal medEventSignal
257 * emitted from the MEDEventListener. It processes events coming from
258 * the python console.
260 void WorkspaceController::processMedEvent(const MEDCALC::MedEvent* event) {
261 STDLOG("WorkspaceController::processMedEvent");
262 STDLOG("dataId :"<<event->dataId);
264 XmedDataModel* dataModel = (XmedDataModel*)this->getDataModel();
265 if ( dataModel == NULL ) {
266 STDLOG("No data model associated to this tree view");
270 if ( event->type == MEDCALC::EVENT_UPDATE_FIELD ) {
271 std::cout << "WorkspaceController::processMedEvent[MEDCALC::EVENT_UPDATE_FIELD]: Not implemented yet";
273 else if ( event->type == MEDCALC::EVENT_PUT_IN_WORKSPACE ) {
274 STDLOG("add new field");
275 MEDCALC::FieldHandler* fieldHandler =
276 MEDFactoryClient::getDataManager()->getFieldHandler(event->dataId);
278 XmedDataObject* dataObject = (XmedDataObject*)dataModel->newDataObject();
279 dataObject->setFieldHandler(*fieldHandler);
280 this->getDataTreeModel()->addData(dataObject);
282 else if ( event->type == MEDCALC::EVENT_REMOVE_FROM_WORKSPACE ) {
283 STDLOG("remove field");
284 std::map<string, DataObject*>::iterator itr = dataModel->begin();
285 for ( ; itr != dataModel->end(); ++itr) {
286 XmedDataObject* obj = dynamic_cast<XmedDataObject*>(itr->second);
287 if (obj->getFieldHandler()->id == event->dataId) {
288 std::string itemNameId = obj->getNameId();
289 this->getDataTreeModel()->removeData(obj);
290 dataModel->removeDataObject(itemNameId);
295 else if ( event->type == MEDCALC::EVENT_CLEAN_WORKSPACE ) {
296 STDLOG("clean workspace");
297 std::map<string, DataObject*>::iterator itr = dataModel->begin();
298 for ( ; itr != dataModel->end(); ++itr) {
299 XmedDataObject* obj = dynamic_cast<XmedDataObject*>(itr->second);
300 std::string itemNameId = obj->getNameId();
301 this->getDataTreeModel()->removeData(obj);
302 dataModel->removeDataObject(itemNameId);
305 else if ( event->type == MEDCALC::EVENT_ADD_DATASOURCE ) {
306 emit workspaceSignal(event); // forward to DatasourceController
308 else if ( event->type == MEDCALC::EVENT_ADD_PRESENTATION ) {
309 emit workspaceSignal(event); // forward to DatasourceController
315 * This function save a list of fields in a med file. The med file
316 * name is requested to the user using a file chooser dialog box
318 void WorkspaceController::_saveItemList(QStringList itemNameIdList) {
319 XmedDataProcessor* dataProcessor = new XmedDataProcessor(this->getDataModel());
320 dataProcessor->process(itemNameIdList);
321 MEDCALC::FieldIdList_var fieldIdList = dataProcessor->getResultingFieldIdList();
322 delete dataProcessor;
325 filter.append(tr("FILE_FILTER_MED"));
326 QString filename = SUIT_FileDlg::getFileName(_salomeModule->getApp()->desktop(),
329 tr("SAVE_SELECTED_FIELDS"),
332 if ( filename.isEmpty() ) return;
334 MEDFactoryClient::getDataManager()->saveFields(QCHARSTAR(filename), fieldIdList);
338 * This function remove the selected item from workspace.
340 void WorkspaceController::_removeItemList(QStringList itemNameIdList) {
341 XmedDataModel* dataModel = (XmedDataModel*)this->getDataModel();
342 if ( dataModel == NULL ) {
343 LOG("No data model associated to this tree view");
347 // __GBO__: In this version, we consider only the first field in the selection
348 QString itemNameId = itemNameIdList[0];
350 // We can request the dataModel to obtain the dataObject associated
351 // to this item (iteNameId is a TreeView id, Qt stuff only).
352 XmedDataObject* dataObject =
353 (XmedDataObject*)dataModel->getDataObject(QS2S(itemNameId));
355 if ( dataObject == NULL ) {
356 LOG("WorkspaceController: WARN! No data object associated to the item "<<itemNameId);
360 // Then, we can request this data object to obtain the associated
362 MEDCALC::FieldHandler* fieldHandler = dataObject->getFieldHandler();
363 STDLOG("Field: mesh="<<fieldHandler->meshname<<" name="<<fieldHandler->fieldname);
365 // Remove the field variable from console
366 QStringList commands;
367 commands+=QString("removeFromWorkspace(accessField(%1))").arg(fieldHandler->id);
368 _consoleDriver->exec(commands);
370 // Finally, we can remove the field from tree data model and tree view
371 this->getDataTreeModel()->removeData(dataObject);
372 dataModel->removeDataObject(QS2S(itemNameId));
376 * This function export the list of specified field item to PARAVIS
377 * module. This consists in create a med file gathering the selected
378 * items, then to import this file in PARAVIS, and finally to create a
379 * scalar map of the first item to start the job.
381 void WorkspaceController::_exportItemList(QStringList itemNameIdList) {
382 XmedDataProcessor* dataProcessor = new XmedDataProcessor(this->getDataModel());
383 dataProcessor->process(itemNameIdList);
384 MEDCALC::FieldIdList_var fieldIdList = dataProcessor->getResultingFieldIdList();
385 delete dataProcessor;
387 // _GBO_ We use a temporary file to proceed with this export to
388 // paravis. I'm sure it could be better in a futur version or when I
389 // will get a better understanding of paravis API.
390 const char* tmpfilename = "/tmp/medcalc_export2paravis.med";
391 MEDFactoryClient::getDataManager()->saveFields(tmpfilename, fieldIdList);
393 // We import the whole file but create a scalar map for the first
394 // selected field only (it's just an export to continue the job in
396 XmedDataModel* dataModel = (XmedDataModel*)this->getDataModel();
397 if ( dataModel == NULL ) {
398 STDLOG("No data model associated to this tree view");
401 QString itemNameId = itemNameIdList[0];
402 XmedDataObject* dataObject = (XmedDataObject*)dataModel->getDataObject(QS2S(itemNameId));
403 if ( dataObject == NULL ) {
404 LOG("WorkspaceController: WARN! No data object associated to the item "<<itemNameId);
407 MEDCALC::FieldHandler* fieldHandler = dataObject->getFieldHandler();
408 QStringList commands;
410 commands+=QString("from xmed.driver_pvis import pvis_scalarmap");
411 commands+=QString("pvis_scalarmap('%1','%2','%3',%4,%5)")
413 .arg(QString(fieldHandler->meshname))
414 .arg(QString(fieldHandler->fieldname))
415 .arg(fieldHandler->type)
416 .arg(fieldHandler->iteration);
418 commands += "print 'Not implemented yet'";
419 _consoleDriver->exec(commands);
424 * This function sends a request to the SALOME data visualisation
425 * (module VISU or PARAVIS) for displaying a scalar map of the fields
426 * associated to the model items in the specified list.
429 void WorkspaceController::_viewItemList(QStringList itemNameIdList) {
431 // __GBO__: In this version, we consider only the first field in the selection
432 QString itemNameId = itemNameIdList[0];
434 XmedDataModel* dataModel = (XmedDataModel*)this->getDataModel();
435 if ( dataModel == NULL ) {
436 LOG("No data model associated to this tree view");
440 // We can request the dataModel to obtain the dataObject associated
441 // to this item (iteNameId is a TreeView id, Qt stuff only).
442 XmedDataObject* dataObject =
443 (XmedDataObject*)dataModel->getDataObject(QS2S(itemNameId));
444 if ( dataObject == NULL ) {
445 LOG("WorkspaceController: WARN! No data object associated to the item "<<itemNameId);
449 // Then, we can request this data object to obtain the associated
451 MEDCALC::FieldHandler* fieldHandler = dataObject->getFieldHandler();
453 // And finally, we can create the set of medcalc instructions to
454 // generate the scalar map on this field.
455 QStringList commands;
456 //commands+=QString("view(accessField(%1))").arg(fieldHandler->id);
457 commands += "print 'Not implemented yet'";
458 _consoleDriver->exec(commands);
462 WorkspaceController::_getViewMode() {
463 MEDCALC::MEDPresentationViewMode viewMode = _salomeModule->getSelectedViewMode();
465 case MEDCALC::VIEW_MODE_REPLACE: return "MEDCALC.VIEW_MODE_REPLACE";
466 case MEDCALC::VIEW_MODE_OVERLAP: return "MEDCALC.VIEW_MODE_OVERLAP";
467 case MEDCALC::VIEW_MODE_NEW_LAYOUT: return "MEDCALC.VIEW_MODE_NEW_LAYOUT";
468 case MEDCALC::VIEW_MODE_SPLIT_VIEW: return "MEDCALC.VIEW_MODE_SPLIT_VIEW";
473 * This slot can process the event coming from the
474 * DatasourceController. The connection between the datasource signal
475 * and this slot is realized by the main class MEDModule.
477 void WorkspaceController::processDatasourceEvent(const DatasourceEvent* event) {
478 XmedDataModel* dataModel = (XmedDataModel*)this->getDataModel();
479 if ( dataModel == NULL ) {
480 STDLOG("No data model associated to this tree view");
485 // __GBO__ To know what to do we should test the type, because the
486 // object could be a mesh, a timeseries or a single field. We test
487 // here the case of a single field. Moreover, there could have
488 // options such that "change the underlying mesh".
491 XmedDataObject* dataObject = event->objectdata;
493 if ( event->eventtype == DatasourceEvent::EVENT_IMPORT_OBJECT ) {
494 std::cout << "IMPORT object in workspace: " << dataObject->toString() << std::endl;
495 STDLOG("IMPORT object in workspace:\n"<<dataObject->toString());
496 // _GBO_ QUESTION: tag automatically the object as a peristant object ??
497 // We first add the data object to the internal data model
498 dataModel->addDataObject(dataObject);
499 // Then we request the tree view to consider this new object
500 this->getDataTreeModel()->addData(dataObject);
502 else if ( event->eventtype == DatasourceEvent::EVENT_USE_OBJECT ) {
503 STDLOG("USE object in workspace:\n"<<dataObject->toString());
504 // We first add the data object to the internal data model
505 dataModel->addDataObject(dataObject);
506 // Then we request the tree view to consider this new object
507 this->getDataTreeModel()->addData(dataObject);
509 // We define a proxy for this object in the tui console.
510 STDLOG("Define a proxy variable in the console with name : "<<QCHARSTAR(event->objectalias));
511 bool askForOptions = false;
512 _importFieldIntoConsole(dataObject->getFieldHandler(),
514 QCHARSTAR(event->objectalias));
516 else if ( event->eventtype == DatasourceEvent::EVENT_ADD_DATASOURCE ) {
517 QStringList commands;
518 commands += QString("medcalc.LoadDataSource('%1')").arg(event->objectalias);
519 _consoleDriver->exec(commands);
521 else if ( event->eventtype == DatasourceEvent::EVENT_ADD_IMAGE_AS_DATASOURCE ) {
522 QStringList commands;
523 commands += QString("medcalc.LoadImageAsDataSource('%1')").arg(event->objectalias);
524 _consoleDriver->exec(commands);
527 STDLOG("The event "<<event->eventtype<<" is not implemented yet");
531 * This slot can process the event coming from the
532 * DatasourceController. The connection between the datasource signal
533 * and this slot is realized by the main class MEDModule.
535 void WorkspaceController::processPresentationEvent(const PresentationEvent* event) {
536 XmedDataModel* dataModel = (XmedDataModel*)this->getDataModel();
537 if ( dataModel == NULL ) {
538 STDLOG("No data model associated to this tree view");
543 // __GBO__ To know what to do we should test the type, because the
544 // object could be a mesh, a timeseries or a single field. We test
545 // here the case of a single field. Moreover, there could have
546 // options such that "change the underlying mesh".
549 XmedDataObject* dataObject = event->objectdata;
551 // --> Send commands to SALOME Python console
552 if ( event->eventtype == PresentationEvent::EVENT_VIEW_OBJECT_SCALAR_MAP ) {
553 QString viewMode = _getViewMode();
554 //QString displayedInfo = ; // from PresentationController combobox
555 //QString scalarBarRange = ; // from PresentationController spinbox
556 //QString colorMap = ; // from PresentationController combobox
557 MEDCALC::FieldHandler* fieldHandler = dataObject->getFieldHandler();
558 QStringList commands;
559 commands += QString("medcalc.MakeScalarMap(accessField(%1), %2)").arg(fieldHandler->id).arg(viewMode);
560 _consoleDriver->exec(commands);
562 else if ( event->eventtype == PresentationEvent::EVENT_VIEW_OBJECT_CONTOUR ) {
563 QString viewMode = _getViewMode();
564 MEDCALC::FieldHandler* fieldHandler = dataObject->getFieldHandler();
565 QStringList commands;
566 commands += QString("medcalc.MakeContour(accessField(%1), %2)").arg(fieldHandler->id).arg(viewMode);
567 _consoleDriver->exec(commands);
569 else if ( event->eventtype == PresentationEvent::EVENT_VIEW_OBJECT_VECTOR_FIELD ) {
570 QString viewMode = _getViewMode();
571 MEDCALC::FieldHandler* fieldHandler = dataObject->getFieldHandler();
572 QStringList commands;
573 commands += QString("medcalc.MakeVectorField(accessField(%1), %2)").arg(fieldHandler->id).arg(viewMode);
574 _consoleDriver->exec(commands);
576 else if ( event->eventtype == PresentationEvent::EVENT_VIEW_OBJECT_SLICES ) {
577 QString viewMode = _getViewMode();
578 MEDCALC::FieldHandler* fieldHandler = dataObject->getFieldHandler();
579 QStringList commands;
580 commands += QString("medcalc.MakeSlices(accessField(%1), %2)").arg(fieldHandler->id).arg(viewMode);
581 _consoleDriver->exec(commands);
583 else if ( event->eventtype == PresentationEvent::EVENT_VIEW_OBJECT_DEFLECTION_SHAPE ) {
584 QString viewMode = _getViewMode();
585 MEDCALC::FieldHandler* fieldHandler = dataObject->getFieldHandler();
586 QStringList commands;
587 commands += QString("medcalc.MakeDeflectionShape(accessField(%1), %2)").arg(fieldHandler->id).arg(viewMode);
588 _consoleDriver->exec(commands);
590 else if ( event->eventtype == PresentationEvent::EVENT_VIEW_OBJECT_POINT_SPRITE ) {
591 QString viewMode = _getViewMode();
592 MEDCALC::FieldHandler* fieldHandler = dataObject->getFieldHandler();
593 QStringList commands;
594 commands += QString("medcalc.MakePointSprite(accessField(%1), %2)").arg(fieldHandler->id).arg(viewMode);
595 _consoleDriver->exec(commands);
598 STDLOG("The event "<<event->eventtype<<" is not implemented yet");
602 void WorkspaceController::OnSaveWorkspace() {
604 // Dialog to get the filename where the workspace must be saved into
606 filter.append(tr("FILE_FILTER_MED"));
608 QString filename = SUIT_FileDlg::getFileName(_salomeModule->getApp()->desktop(),
611 tr("SAVE_WORKSPACE_DATA"),
614 if ( filename.isEmpty() ) return;
616 STDLOG("OnWorkspaceSave: save the workspace in the file " << QCHARSTAR(filename));
617 QStringList commands;
618 commands+=QString("saveWorkspace('%1')").arg(filename);
619 _consoleDriver->exec(commands);
622 #include <QMessageBox>
623 void WorkspaceController::OnCleanWorkspace() {
624 // Remove field from console
625 QStringList commands;
626 commands += QString("cleanWorkspace()");
627 _consoleDriver->exec(commands);