1 // Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // File: SalomeApp_Application.cxx
24 // Created: 10/22/2004 3:23:45 PM
25 // Author: Sergey LITONIN
28 // E.A. : On windows with python 2.6, there is a conflict
29 // E.A. : between pymath.h and Standard_math.h which define
30 // E.A. : some same symbols : acosh, asinh, ...
31 #include <Standard_math.hxx>
32 #ifndef DISABLE_PYCONSOLE
37 #ifndef DISABLE_PYCONSOLE
38 #include "SalomeApp_PyInterp.h"
39 #include "SalomeApp_NoteBook.h"
40 #include "LightApp_PyEditor.h"
41 #include "PyConsole_Console.h"
43 #include "SalomeApp_Application.h"
44 #include "SalomeApp_Study.h"
45 #include "SalomeApp_DataModel.h"
46 #include "SalomeApp_DataObject.h"
47 #include "SalomeApp_VisualState.h"
48 #include "SalomeApp_StudyPropertiesDlg.h"
49 #include "SalomeApp_LoadStudiesDlg.h"
50 #include "SalomeApp_ExitDlg.h"
52 #include <LightApp_Application.h>
53 #include <LightApp_FileValidator.h>
54 #include <LightApp_Module.h>
55 #include <LightApp_Preferences.h>
56 #include <LightApp_SelectionMgr.h>
57 #include <LightApp_NameDlg.h>
58 #include <LightApp_DataOwner.h>
60 #include <CAM_Module.h>
62 #include <SUIT_Tools.h>
63 #include <SUIT_Session.h>
64 #include <SUIT_Desktop.h>
65 #include <SUIT_DataBrowser.h>
66 #include <SUIT_FileDlg.h>
67 #include <SUIT_MessageBox.h>
68 #include <SUIT_ResourceMgr.h>
69 #include <SUIT_TreeModel.h>
70 #include <SUIT_ViewWindow.h>
71 #include <SUIT_ViewManager.h>
72 #include <SUIT_ViewModel.h>
73 #include <SUIT_OverrideCursor.h>
75 #include <QtxTreeView.h>
77 #include <SALOME_EventFilter.h>
79 // temporary commented
80 //#include <OB_ListItem.h>
83 #include <Utils_ORB_INIT.hxx>
84 #include <Utils_SINGLETON.hxx>
85 #include <SALOME_LifeCycleCORBA.hxx>
87 #include <QApplication>
92 #include <QPushButton>
94 #include <QListWidget>
95 #include <QGridLayout>
99 #include <SALOMEDSClient_ClientFactory.hxx>
100 #include <Basics_Utils.hxx>
102 #include <SALOME_ListIO.hxx>
103 #include <SALOME_Prs.h>
106 #include <ToolsGUI_CatalogGeneratorDlg.h>
107 #include <ToolsGUI_RegWidget.h>
111 #include <SALOMEDS_Tool.hxx>
113 std::unique_ptr<SALOME_NamingService_Abstract> SalomeApp_Application::_ns;
115 /*!Internal class that updates object browser item properties */
116 // temporary commented
117 /*class SalomeApp_Updater : public OB_Updater
120 SalomeApp_Updater() : OB_Updater(){};
121 virtual ~SalomeApp_Updater(){};
122 virtual void update( SUIT_DataObject* theObj, OB_ListItem* theItem );
125 void SalomeApp_Updater::update( SUIT_DataObject* theObj, OB_ListItem* theItem )
127 if( !theObj || !theItem )
130 SalomeApp_DataObject* SAObj = dynamic_cast<SalomeApp_DataObject*>( theObj );
134 _PTR(SObject) SObj = SAObj->object();
137 _PTR( GenericAttribute ) anAttr;
140 if ( SObj->FindAttribute( anAttr, "AttributeSelectable" ) )
142 _PTR(AttributeSelectable) aAttrSel = anAttr;
143 theItem->setSelectable( aAttrSel->IsSelectable() );
146 if ( SObj->FindAttribute(anAttr, "AttributeExpandable") )
148 _PTR(AttributeExpandable) aAttrExpand = anAttr;
149 theItem->setExpandable( aAttrExpand->IsExpandable() );
152 //this attribute is not supported in the version of SALOME 3.x
153 //if ( SObj->FindAttribute(anAttr, "AttributeOpened") )
155 // _PTR(AttributeOpened) aAttrOpen = anAttr;
156 // theItem->setOpen( aAttrOpen->IsOpened() );
168 //! Constructor. Sets passed boolean flag to \c true.
169 MessageLocker( bool& Lock ) : myPrevState( Lock ), myLock( Lock ) { myLock = true; }
170 //! Destructor. Clear external boolean flag passed as parameter to the constructor to \c false.
171 ~MessageLocker() { myLock = myPrevState; }
174 bool& myLock; //! External 'Lock state' boolean flag
179 SalomeApp_Application::SalomeApp_Application(SALOME_NamingService_Abstract *ns):myIsCloseFromExit( false ),myToIgnoreMessages( false )
182 _ns.reset(new SALOME_NamingService(orb()));
188 *\li Destroy event filter.
190 SalomeApp_Application::~SalomeApp_Application()
192 // Do not destroy. It's a singleton !
193 //SALOME_EventFilter::Destroy();
196 QStringList __getArgsList(QString argsString)
198 // Special process if some items of 'args:' list are themselves lists
199 // Note that an item can be a list, but not a list of lists...
200 // So we can have something like this:
201 // myscript.py args:['file1','file2'],val1,"done",[1,2,3],[True,False],"ok"
202 // With such a call, argsString variable contains the string representing "[file1,file2]", "val1", "done", "[1,2,3]", "[True,False]", "ok"
203 // We have to split argsString to obtain: [[file1,file2],val1,done,[1,2,3],[True,False],ok]
204 argsString.replace("\\\"", "'"); // replace escaped double quotes by simple quotes
205 bool containsList = (QRegExp("(\\[[^\\]]*\\])").indexIn(argsString) >= 0);
207 QStringList sl = argsString.split("\"", QString::SkipEmptyParts);
212 return argsString.split(",", QString::SkipEmptyParts);
215 /*!Start application.*/
216 void SalomeApp_Application::start()
218 // process the command line options before start: to createActions in accordance to the options
219 static bool isFirst = true;
226 QStringList args = QApplication::arguments();
227 for (int i = 1; i < args.count(); i++) {
228 QRegExp rxs ("--study-hdf=(.+)");
229 if ( rxs.indexIn( args[i] ) >= 0 && rxs.capturedTexts().count() > 1 ) {
230 QString file = rxs.capturedTexts()[1];
231 QFileInfo fi ( file );
232 QString extension = fi.suffix().toLower();
233 if ( extension == "hdf" && fi.exists() )
234 hdffile = fi.absoluteFilePath();
237 QRegExp rxp ("--pyscript=\\[(.+)\\]");
238 if ( rxp.indexIn( args[i] ) >= 0 && rxp.capturedTexts().count() > 1 ) {
240 QStringList dictList = rxp.capturedTexts()[1].split("},", QString::SkipEmptyParts);
241 for (int k = 0; k < dictList.count(); ++k) {
242 QRegExp rxd ("[\\s]*\\{?([^\\{\\}]+)\\}?[\\s]*");
243 if ( rxd.indexIn( dictList[k] ) >= 0 && rxd.capturedTexts().count() > 1 ) {
244 for (int m = 1; m < rxd.capturedTexts().count(); ++m) {
245 pyfiles += rxd.capturedTexts()[m];
252 // Here pyfiles elements are: "script_name": [list_of_"arg"s]
253 // For example: "/absolute/path/to/my_script.py": ["1", "2"]
255 LightApp_Application::start();
256 SALOME_EventFilter::Init();
258 setProperty("open_study_from_command_line", true);
259 if ( !hdffile.isEmpty() ) // open hdf file given as parameter
260 onOpenDoc( hdffile );
261 setProperty("open_study_from_command_line", QVariant());
263 #ifndef DISABLE_PYCONSOLE
264 // import/execute python scripts
265 if ( pyfiles.count() > 0 && activeStudy() ) {
266 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
267 PyConsole_Console* pyConsole = pythonConsole();
268 if ( appStudy && pyConsole ) {
269 if ( !getStudy()->GetProperties()->IsLocked() ) {
270 // pyfiles[j] is a dictionary: {"/absolute/path/to/script.py": [script_args]}
271 // Path is absolute, script has .py extension
272 for (int j = 0; j < pyfiles.count(); j++ ) {
273 // Extract scripts and their arguments, if any
274 QRegExp rxp ("\"(.+)\":[\\s]*\\[(.*)\\]");
275 if ( rxp.indexIn( pyfiles[j] ) >= 0 && rxp.capturedTexts().count() == 3 ) {
276 QString script = rxp.capturedTexts()[1];
278 QStringList argList = __getArgsList(rxp.capturedTexts()[2]);
279 for (int k = 0; k < argList.count(); k++ ) {
280 QString arg = argList[k].trimmed();
281 arg.remove( QRegExp("^[\"]") );
282 arg.remove( QRegExp("[\"]$") );
283 args << QString("\"%1\"").arg(arg);
285 if (args.count() == 1)
288 script.remove( QRegExp("^python.*[\\s]+") );
289 QString command = QString( "exec(open(\"%1\", \"rb\").read(), args=(%2))" ).arg(script).arg(args.join(","));
290 pyConsole->exec(command);
292 } // end for loop on pyfiles QStringList
298 LightApp_Application::start();
299 SALOME_EventFilter::Init();
304 void SalomeApp_Application::createActions()
306 LightApp_Application::createActions();
308 SUIT_Desktop* desk = desktop();
311 // "Save GUI State" command is moved to VISU module
312 // createAction( SaveGUIStateId, tr( "TOT_DESK_FILE_SAVE_GUI_STATE" ), QIcon(),
313 // tr( "MEN_DESK_FILE_SAVE_GUI_STATE" ), tr( "PRP_DESK_FILE_SAVE_GUI_STATE" ),
314 // 0, desk, false, this, SLOT( onSaveGUIState() ) );
317 createAction( DumpStudyId, tr( "TOT_DESK_FILE_DUMP_STUDY" ), QIcon(),
318 tr( "MEN_DESK_FILE_DUMP_STUDY" ), tr( "PRP_DESK_FILE_DUMP_STUDY" ),
319 Qt::CTRL+Qt::Key_D, desk, false, this, SLOT( onDumpStudy() ) );
322 createAction( LoadScriptId, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), QIcon(),
323 tr( "MEN_DESK_FILE_LOAD_SCRIPT" ), tr( "PRP_DESK_FILE_LOAD_SCRIPT" ),
324 Qt::CTRL+Qt::Key_T, desk, false, this, SLOT( onLoadScript() ) );
327 createAction( PropertiesId, tr( "TOT_DESK_PROPERTIES" ), QIcon(),
328 tr( "MEN_DESK_PROPERTIES" ), tr( "PRP_DESK_PROPERTIES" ),
329 0, desk, false, this, SLOT( onProperties() ) );
331 //! Catalog Generator
332 createAction( CatalogGenId, tr( "TOT_DESK_CATALOG_GENERATOR" ), QIcon(),
333 tr( "MEN_DESK_CATALOG_GENERATOR" ), tr( "PRP_DESK_CATALOG_GENERATOR" ),
334 Qt::ALT+Qt::SHIFT+Qt::Key_G, desk, false, this, SLOT( onCatalogGen() ) );
337 createAction( RegDisplayId, tr( "TOT_DESK_REGISTRY_DISPLAY" ), QIcon(),
338 tr( "MEN_DESK_REGISTRY_DISPLAY" ), tr( "PRP_DESK_REGISTRY_DISPLAY" ),
339 /*Qt::SHIFT+Qt::Key_D*/0, desk, false, this, SLOT( onRegDisplay() ) );
341 createAction( ConnectId, tr( "TOT_DESK_CONNECT_STUDY" ), QIcon(),
342 tr( "MEN_DESK_CONNECT" ), tr( "PRP_DESK_CONNECT" ),
343 Qt::CTRL+Qt::Key_L, desk, false, this, SLOT( onLoadDoc() ) );
344 //no need at this action for mono-study application because study is always exists
345 action( ConnectId )->setVisible( false );
347 createAction( DisconnectId, tr( "TOT_DESK_DISCONNECT_STUDY" ), QIcon(),
348 tr( "MEN_DESK_DISCONNECT" ), tr( "PRP_DESK_DISCONNECT" ),
349 Qt::CTRL+Qt::Key_U, desk, false, this, SLOT( onUnloadDoc() ) );
350 //no need at this action for mono-study application because study is always exists
351 action( DisconnectId )->setVisible( false );
354 int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1 );
356 // "Save GUI State" command is renamed to "Save VISU State" and
357 // creation of menu item is moved to VISU
358 // createMenu( SaveGUIStateId, fileMenu, 10, -1 );
360 createMenu( ConnectId, fileMenu, 5 );
361 createMenu( DisconnectId, fileMenu, 5 );
362 createMenu( separator(), fileMenu, -1, 5 );
364 createMenu( DumpStudyId, fileMenu, 10, -1 );
365 createMenu( LoadScriptId, fileMenu, 10, -1 );
366 createMenu( separator(), fileMenu, -1, 10, -1 );
367 createMenu( PropertiesId, fileMenu, 10, -1 );
368 createMenu( separator(), fileMenu, -1, 10, -1 );
370 int toolsMenu = createMenu( tr( "MEN_DESK_TOOLS" ), -1, MenuToolsId, 50 );
371 createMenu( CatalogGenId, toolsMenu, 10, -1 );
372 createMenu( RegDisplayId, toolsMenu, 10, -1 );
373 createMenu( separator(), toolsMenu, -1, 15, -1 );
375 createExtraActions();
377 #ifndef DISABLE_PYCONSOLE
378 #ifndef DISABLE_SALOMEOBJECT
379 // import Python module that manages SALOME plugins
381 PyLockWrapper lck; // acquire GIL
382 PyObjWrapper pluginsmanager = PyImport_ImportModule((char*)"salome_pluginsmanager");
383 PyObjWrapper res = PyObject_CallMethod( pluginsmanager, (char*)"initialize", (char*)"isss",0,"salome",tr("MEN_DESK_TOOLS").toUtf8().data(),tr("MEN_DESK_PLUGINS").toUtf8().data());
387 // end of SALOME plugins loading
394 \brief Close application.
396 void SalomeApp_Application::onExit()
398 //MessageLocker ml( myToIgnoreMessages );
400 bool killServers = false;
403 if ( exitConfirmation() ) {
404 SalomeApp_ExitDlg dlg( desktop() );
405 result = dlg.exec() == QDialog::Accepted;
406 killServers = dlg.isServersShutdown();
410 if ( !killServers ) myIsCloseFromExit = true;
411 SUIT_Session::session()->closeSession( SUIT_Session::ASK, killServers );
412 if ( SUIT_Session::session()->applications().count() > 0 ) myIsCloseFromExit = false;
416 /*!SLOT. Create a document.*/
417 void SalomeApp_Application::onNewDoc()
419 MessageLocker ml( myToIgnoreMessages );
421 LightApp_Application::onNewDoc();
424 /*!SLOT. Load document.*/
425 void SalomeApp_Application::onLoadDoc()
427 MessageLocker ml( myToIgnoreMessages );
431 // rnv: According to the single-study approach on the server side
432 // can be only one study. So if it is exists connect to them,
433 // overwise show warning message: "No active study on the server"
436 SUIT_Session* aSession = SUIT_Session::session();
437 QList<SUIT_Application*> aAppList = aSession->applications();
439 QStringList unloadedStudies;
441 for ( unsigned int ind = 0; ind < List.size(); ind++ ) {
442 studyName = List[ind].c_str();
443 // Add to list only unloaded studies
444 bool isAlreadyOpen = false;
445 QListIterator<SUIT_Application*> it( aAppList );
446 while ( it.hasNext() && !isAlreadyOpen ) {
447 SUIT_Application* aApp = it.next();
448 if( !aApp || !aApp->activeStudy() )
450 if ( aApp->activeStudy()->studyName() == studyName )
451 isAlreadyOpen = true;
454 if ( !isAlreadyOpen )
455 unloadedStudies << studyName;
457 studyName = SalomeApp_LoadStudiesDlg::selectStudy( desktop(), unloadedStudies );
458 if ( studyName.isEmpty() )
463 SUIT_MessageBox::warning( desktop(),
464 QObject::tr("WRN_WARNING"),
465 QObject::tr("WRN_NO_STUDY_ON SERV") );
469 studyName = activeStudy()->studyName();
472 // this code replaces marker of windows drive and path become invalid therefore
473 // defines placed there
474 studyName.replace( QRegExp(":"), "/" );
477 if ( onLoadDoc( studyName ) ) {
479 updateViewManagers();
480 updateObjectBrowser( true );
484 /*!SLOT. Unload document.*/
485 void SalomeApp_Application::onUnloadDoc( bool ask )
488 activeStudy()->abortAllOperations();
489 if ( activeStudy()->isModified() ) {
490 QString docName = activeStudy()->studyName().trimmed();
491 int answer = SUIT_MessageBox::question( desktop(), tr( "DISCONNECT_CAPTION" ),
492 tr( "DISCONNECT_DESCRIPTION" ),
493 tr( "DISCONNECT_SAVE" ),
494 tr( "DISCONNECT_WO_SAVE" ),
495 tr( "APPCLOSE_CANCEL" ), 0 );
496 if ( answer == 0 ) { // save before unload
497 if ( activeStudy()->isSaved() )
499 else if ( !onSaveAsDoc() )
502 else if ( answer == 2 ) // Cancel
506 closeActiveDoc( false );
509 /*!SLOT. Create new study and load script*/
510 void SalomeApp_Application::onNewWithScript()
512 QStringList filtersList;
513 filtersList.append(tr("PYTHON_FILES_FILTER"));
514 filtersList.append(tr("ALL_FILES_FILTER"));
516 QString anInitialPath = "";
517 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
518 anInitialPath = QDir::currentPath();
520 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
522 if ( !aFile.isEmpty() )
526 QString command = QString("exec(open(\"%1\", \"rb\").read())").arg(aFile);
528 #ifndef DISABLE_PYCONSOLE
529 PyConsole_Console* pyConsole = pythonConsole();
532 pyConsole->exec( command );
538 /*!SLOT. Load document with \a aName.*/
539 bool SalomeApp_Application::onLoadDoc( const QString& aName )
541 if ( !LightApp_Application::closeDoc() )
545 if ( !activeStudy() ) {
546 // if no study - load in current desktop
547 res = useStudy( aName );
550 // if study exists - load in new desktop. Check: is the same file is loaded?
551 SUIT_Session* aSession = SUIT_Session::session();
552 QList<SUIT_Application*> aAppList = aSession->applications();
553 bool isAlreadyOpen = false;
554 SalomeApp_Application* aApp = 0;
555 for ( QList<SUIT_Application*>::iterator it = aAppList.begin();
556 it != aAppList.end() && !isAlreadyOpen; ++it ) {
557 aApp = dynamic_cast<SalomeApp_Application*>( *it );
558 if ( aApp && aApp->activeStudy()->studyName() == aName )
559 isAlreadyOpen = true;
561 if ( !isAlreadyOpen ) {
562 aApp = dynamic_cast<SalomeApp_Application*>( startApplication( 0, 0 ) );
564 res = aApp->useStudy( aName );
567 aApp->desktop()->activateWindow();
574 /*!SLOT. Parse message for desktop.*/
575 void SalomeApp_Application::onDesktopMessage( const QString& message )
577 if ( myToIgnoreMessages )
578 return; // a message from SALOMEDS is caused by GUI action
580 MessageLocker ml( myToIgnoreMessages );
582 if (message.indexOf("studyCreated") == 0) {
583 if (!activeStudy()) {
585 updateCommandsStatus();
588 if (message.indexOf("studyCleared") == 0) {
589 // Disconnect GUI from active study, because it was closed on DS side.
591 closeActiveDoc( false );
592 // Disable 'Connect' action
593 QAction* a = action( ConnectId );
595 a->setEnabled( false );
598 else if ( message.toLower() == "connect_to_study" ) {
600 useStudy( activeStudy()->studyName() );
602 if (message.indexOf("studyNameChanged") == 0) {
603 updateDesktopTitle();
605 LightApp_Application::onDesktopMessage( message );
608 /*!On module activation action.*/
609 void SalomeApp_Application::onModuleActivation( const QString& modName )
611 if (!activeStudy() && !modName.isEmpty())
614 LightApp_Application::onModuleActivation( modName );
617 /*!SLOT. Copy objects to study maneger from selection maneger..*/
618 void SalomeApp_Application::onCopy()
620 LightApp_Application::onCopy();
623 LightApp_SelectionMgr* mgr = selectionMgr();
624 mgr->selectedObjects(list);
626 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
627 if(study == NULL) return;
629 _PTR(Study) stdDS = getStudy();
632 SALOME_ListIteratorOfListIO it( list );
635 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
640 onSelectionChanged();
648 /*!SLOT. Paste objects to study maneger from selection manager.*/
649 void SalomeApp_Application::onPaste()
651 LightApp_Application::onPaste();
654 LightApp_SelectionMgr* mgr = selectionMgr();
655 mgr->selectedObjects(list);
657 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
658 if(study == NULL) return;
660 _PTR(Study) stdDS = getStudy();
663 if ( stdDS->GetProperties()->IsLocked() ) {
664 SUIT_MessageBox::warning( desktop(),
665 QObject::tr("WRN_WARNING"),
666 QObject::tr("WRN_STUDY_LOCKED") );
670 SALOME_ListIteratorOfListIO it( list );
673 _PTR(SObject) so = stdDS->FindObjectID(it.Value()->getEntry());
678 updateObjectBrowser( true );
679 updateActions(); //SRN: BugID IPAL9377, case 3
687 /*!Check the application on closing.
688 * \retval true if possible, else false
690 bool SalomeApp_Application::isPossibleToClose( bool& closePermanently )
692 return LightApp_Application::isPossibleToClose( closePermanently );
695 /*! Check if the study is locked */
696 void SalomeApp_Application::onCloseDoc( bool ask )
698 if(getStudy()->IsStudyLocked()) {
699 if ( SUIT_MessageBox::question( desktop(),
700 QObject::tr( "WRN_WARNING" ),
701 QObject::tr( "CLOSE_LOCKED_STUDY" ),
702 SUIT_MessageBox::Yes | SUIT_MessageBox::No,
703 SUIT_MessageBox::No) == SUIT_MessageBox::No ) return;
706 MessageLocker ml( myToIgnoreMessages );
708 LightApp_Application::onCloseDoc( ask );
710 // reinitialize study to have empty data
711 //getStudy()->Init();
714 /*!SLOT. Reload document from the file.*/
715 bool SalomeApp_Application::onReopenDoc()
717 MessageLocker ml( myToIgnoreMessages );
719 return LightApp_Application::onReopenDoc();
723 /*!SLOT. Load document.*/
724 void SalomeApp_Application::onOpenDoc()
726 MessageLocker ml( myToIgnoreMessages );
728 LightApp_Application::onOpenDoc();
731 /*!SLOT. Load document.*/
732 bool SalomeApp_Application::onOpenDoc(const QString& name)
734 MessageLocker ml( myToIgnoreMessages );
736 return LightApp_Application::onOpenDoc(name);
739 /*!Sets enable or disable some actions on selection changed.*/
740 void SalomeApp_Application::onSelectionChanged()
743 LightApp_SelectionMgr* mgr = selectionMgr();
744 mgr->selectedObjects(list);
746 bool canCopy = false;
747 bool canPaste = false;
749 LightApp_Module* m = dynamic_cast<LightApp_Module*>( activeModule() );
752 canCopy = m->canCopy();
753 canPaste = m->canPaste();
756 SALOME_ListIteratorOfListIO it ( list );
758 if (it.More() && list.Extent() == 1) {
759 _PTR(SObject) so = getStudy()->FindObjectID(it.Value()->getEntry());
762 canCopy = canCopy || getStudy()->CanCopy(so);
763 canPaste = canPaste || getStudy()->CanPaste(so);
767 action(EditCopyId)->setEnabled(canCopy);
768 action(EditPasteId)->setEnabled(canPaste);
771 /*!Delete references.*/
772 void SalomeApp_Application::onDeleteInvalidReferences()
775 LightApp_SelectionMgr* mgr = selectionMgr();
776 mgr->selectedObjects( aList, QString(), false );
778 if( aList.IsEmpty() )
781 _PTR(Study) aStudyDS = getStudy();
782 _PTR(StudyBuilder) aStudyBuilder = aStudyDS->NewBuilder();
785 for( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
786 if ( it.Value()->hasEntry() )
788 _PTR(SObject) aSObject = aStudyDS->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
789 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
792 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
793 aStudyBuilder->RemoveReference( aSObject );
795 updateObjectBrowser();
799 void SalomeApp_Application::onOpenWith()
801 QApplication::setOverrideCursor( Qt::WaitCursor );
803 LightApp_SelectionMgr* mgr = selectionMgr();
804 mgr->selectedObjects(aList);
805 if (aList.Extent() != 1)
807 QApplication::restoreOverrideCursor();
810 Handle(SALOME_InteractiveObject) aIObj = aList.First();
811 QString aModuleName(aIObj->getComponentDataType());
812 QString aModuleTitle = moduleTitle(aModuleName);
813 activateModule(aModuleTitle);
814 QApplication::restoreOverrideCursor();
820 SUIT_Study* SalomeApp_Application::createNewStudy()
822 SalomeApp_Study* aStudy = new SalomeApp_Study( this );
824 // Set up processing of major study-related events
825 connect( aStudy, SIGNAL( created( SUIT_Study* ) ), this, SLOT( onStudyCreated( SUIT_Study* ) ) );
826 connect( aStudy, SIGNAL( opened ( SUIT_Study* ) ), this, SLOT( onStudyOpened ( SUIT_Study* ) ) );
827 connect( aStudy, SIGNAL( saved ( SUIT_Study* ) ), this, SLOT( onStudySaved ( SUIT_Study* ) ) );
828 connect( aStudy, SIGNAL( closed ( SUIT_Study* ) ), this, SLOT( onStudyClosed ( SUIT_Study* ) ) );
830 #ifndef DISABLE_PYCONSOLE
831 //to receive signal in application that NoteBook's variable was modified
832 connect( aStudy, SIGNAL(notebookVarUpdated(QString)),
833 this, SIGNAL(notebookVarUpdated(QString)) );
842 Enable/Disable menu items and toolbar buttons. Rebuild menu
844 void SalomeApp_Application::updateCommandsStatus()
846 LightApp_Application::updateCommandsStatus();
849 QAction* a = action( DumpStudyId );
851 a->setEnabled( activeStudy() );
853 #ifndef DISABLE_PYCONSOLE
855 a = action( LoadScriptId );
857 a->setEnabled( pythonConsole() );
861 a = action( PropertiesId );
863 a->setEnabled( activeStudy() );
865 // Save GUI state menu
866 a = action( SaveGUIStateId );
868 a->setEnabled( activeStudy() );
870 // Connect study menu
871 a = action( ConnectId );
873 a->setEnabled( !activeStudy() );
875 // Disconnect study menu
876 a = action( DisconnectId );
878 a->setEnabled( activeStudy() );
880 // update state of Copy/Paste menu items
881 onSelectionChanged();
885 \class DumpStudyFileDlg
886 Private class used in Dump Study operation. Consists 2 check boxes:
887 "Publish in study" and "Save GUI parameters"
889 class DumpStudyFileDlg : public SUIT_FileDlg
892 DumpStudyFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
894 QGridLayout* grid = ::qobject_cast<QGridLayout*>( layout() );
897 QWidget *hB = new QWidget( this );
898 myPublishChk = new QCheckBox( tr("PUBLISH_IN_STUDY") );
899 myMultiFileChk = new QCheckBox( tr("MULTI_FILE_DUMP") );
900 mySaveGUIChk = new QCheckBox( tr("SAVE_GUI_STATE") );
902 QHBoxLayout *layout = new QHBoxLayout;
903 layout->addWidget(myPublishChk);
904 layout->addWidget(myMultiFileChk);
905 layout->addWidget(mySaveGUIChk);
906 hB->setLayout(layout);
908 QPushButton* pb = new QPushButton(this);
910 int row = grid->rowCount();
911 grid->addWidget( new QLabel("", this), row, 0 );
912 grid->addWidget( hB, row, 1, 1, 3 );
913 grid->addWidget( pb, row, 5 );
918 QCheckBox* myPublishChk;
919 QCheckBox* myMultiFileChk;
920 QCheckBox* mySaveGUIChk;
923 /*!Private SLOT. On dump study.*/
924 void SalomeApp_Application::onDumpStudy( )
926 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
927 if ( !appStudy ) return;
929 QStringList aFilters;
930 aFilters.append( tr( "PYTHON_FILES_FILTER" ) );
932 bool anIsPublish = true;
933 bool anIsMultiFile = false;
934 bool anIsSaveGUI = true;
936 if ( SUIT_ResourceMgr* aResourceMgr = resourceMgr() ) {
937 anIsPublish = aResourceMgr->booleanValue( "Study", "pydump_publish", anIsPublish );
938 anIsMultiFile = aResourceMgr->booleanValue( "Study", "multi_file_dump", anIsMultiFile );
939 anIsSaveGUI = aResourceMgr->booleanValue( "Study", "pydump_save_gui", anIsSaveGUI );
942 DumpStudyFileDlg fd( desktop() );
943 fd.setValidator( new LightApp_PyFileValidator( &fd ) );
944 fd.setWindowTitle( tr( "TOT_DESK_FILE_DUMP_STUDY" ) );
945 fd.setNameFilters( aFilters );
946 fd.myPublishChk->setChecked( anIsPublish );
947 fd.myMultiFileChk->setChecked( anIsMultiFile );
948 fd.mySaveGUIChk->setChecked( anIsSaveGUI );
949 if ( fd.exec() == QDialog::Accepted )
951 QString aFileName = fd.selectedFile();
953 bool toPublish = fd.myPublishChk->isChecked();
954 bool isMultiFile = fd.myMultiFileChk->isChecked();
955 bool toSaveGUI = fd.mySaveGUIChk->isChecked();
957 if ( !aFileName.isEmpty() ) {
958 QFileInfo aFileInfo(aFileName);
959 if( aFileInfo.isDir() ) // IPAL19257
962 // Issue 21377 - dump study implementation moved to SalomeApp_Study class
965 SUIT_OverrideCursor wc;
966 ensureShaperIsActivated();
967 res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI );
970 SUIT_MessageBox::warning( desktop(),
971 QObject::tr("WRN_WARNING"),
972 tr("WRN_DUMP_STUDY_FAILED") );
977 /*!Private SLOT. On load script.*/
978 void SalomeApp_Application::onLoadScript( )
980 if ( getStudy()->GetProperties()->IsLocked() ) {
981 SUIT_MessageBox::warning( desktop(),
982 QObject::tr("WRN_WARNING"),
983 QObject::tr("WRN_STUDY_LOCKED") );
987 QStringList filtersList;
988 filtersList.append(tr("PYTHON_FILES_FILTER"));
989 filtersList.append(tr("ALL_FILES_FILTER"));
991 QString anInitialPath = "";
992 if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() )
993 anInitialPath = QDir::currentPath();
995 QString aFile = SUIT_FileDlg::getFileName( desktop(), anInitialPath, filtersList, tr( "TOT_DESK_FILE_LOAD_SCRIPT" ), true, true );
997 if ( !aFile.isEmpty() )
1000 QString command = QString("exec(compile(open('%1', 'rb').read(), '%1', 'exec'))").arg(aFile);
1002 #ifndef DISABLE_PYCONSOLE
1003 PyConsole_Console* pyConsole = pythonConsole();
1006 pyConsole->exec( command );
1011 /*!Private SLOT. On save GUI state.*/
1012 void SalomeApp_Application::onSaveGUIState()
1014 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1016 SalomeApp_VisualState( this ).storeState();
1017 updateSavePointDataObjects( study );
1018 updateObjectBrowser();
1023 /*!Public SLOT. Performs some actions when dockable windows are triggered.*/
1024 void SalomeApp_Application::onDockWindowVisibilityChanged( bool theIsVisible )
1026 LightApp_Application::onDockWindowVisibilityChanged( theIsVisible );
1027 QAction* send = ::qobject_cast<QAction*>( sender() );
1030 QString aWinName = send->data().toString();
1031 if ( theIsVisible && aWinName == "objectBrowser" )
1032 objectBrowserColumnsVisibility();
1036 QWidget* SalomeApp_Application::createWindow( const int flag )
1039 #ifndef DISABLE_PYCONSOLE
1040 if ( flag != WT_PyConsole ) wid = LightApp_Application::createWindow(flag);
1042 wid = LightApp_Application::createWindow(flag);
1045 SUIT_ResourceMgr* resMgr = resourceMgr();
1047 if ( flag == WT_ObjectBrowser )
1049 SUIT_DataBrowser* ob = qobject_cast<SUIT_DataBrowser*>( wid );
1051 // temporary commented
1052 //ob->setUpdater( new SalomeApp_Updater() );
1054 #ifdef WITH_SALOMEDS_OBSERVER
1055 //do not activate the automatic update of Qt tree through signal/slot
1056 ob->setAutoUpdate(false);
1057 //activate update of modified objects only
1058 ob->setUpdateModified(true);
1061 connect( ob, SIGNAL( doubleClicked( SUIT_DataObject* ) ), this, SLOT( onDblClick( SUIT_DataObject* ) ) );
1064 ValueCol = QObject::tr( "VALUE_COLUMN" ),
1065 IORCol = QObject::tr( "IOR_COLUMN" ),
1066 RefCol = QObject::tr( "REFENTRY_COLUMN" ),
1067 EntryCol = QObject::tr( "ENTRY_COLUMN" );
1069 SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( ob->model() );
1070 treeModel->registerColumn( 0, EntryCol, SalomeApp_DataObject::EntryId );
1071 treeModel->registerColumn( 0, ValueCol, SalomeApp_DataObject::ValueId );
1072 treeModel->registerColumn( 0, IORCol, SalomeApp_DataObject::IORId );
1073 treeModel->registerColumn( 0, RefCol, SalomeApp_DataObject::RefEntryId );
1074 treeModel->setAppropriate( EntryCol, Qtx::Toggled );
1075 treeModel->setAppropriate( ValueCol, Qtx::Toggled );
1076 treeModel->setAppropriate( IORCol, Qtx::Toggled );
1077 treeModel->setAppropriate( RefCol, Qtx::Toggled );
1079 bool autoSize = resMgr->booleanValue( "ObjectBrowser", "auto_size", false );
1080 bool autoSizeFirst = resMgr->booleanValue( "ObjectBrowser", "auto_size_first", true );
1081 bool resizeOnExpandItem = resMgr->booleanValue( "ObjectBrowser", "resize_on_expand_item", true );
1083 ob->setAutoSizeFirstColumn(autoSizeFirst);
1084 ob->setAutoSizeColumns(autoSize);
1085 ob->setResizeOnExpandItem(resizeOnExpandItem);
1086 ob->setProperty( "shortcut", QKeySequence( "Alt+Shift+O" ) );
1088 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1090 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1091 ob->treeView()->setColumnHidden( i, !shown );
1094 // temporary commented
1096 for ( int i = SalomeApp_DataObject::ValueIdx; i <= SalomeApp_DataObject::RefEntryIdx; i++ )
1098 ob->addColumn( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i ) ), i );
1099 ob->setColumnShown( i, resMgr->booleanValue( "ObjectBrowser",
1100 QString().sprintf( "visibility_column_%d", i ), true ) );
1104 // temporary commented
1106 ob->setWidthMode( autoSize ? QListView::Maximum : QListView::Manual );
1107 ob->listView()->setColumnWidthMode( 0, autoSizeFirst ? QListView::Maximum : QListView::Manual );
1108 ob->resize( desktop()->width()/3, ob->height() );
1112 #ifndef DISABLE_PYCONSOLE
1113 else if ( flag == WT_PyConsole )
1115 PyConsole_Console* pyCons = new PyConsole_Console( desktop(), new LightApp_PyEditor( getPyInterp() ) );
1116 pyCons->setObjectName( "pythonConsole" );
1117 pyCons->setWindowTitle( tr( "PYTHON_CONSOLE" ) );
1118 pyCons->setFont(resourceMgr()->fontValue( "PyConsole", "font" ));
1119 pyCons->setIsShowBanner(resourceMgr()->booleanValue( "PyConsole", "show_banner", true ));
1120 pyCons->setAutoCompletion( resMgr->booleanValue( "PyConsole", "auto_completion", true ) );
1121 pyCons->setProperty( "shortcut", QKeySequence( "Alt+Shift+P" ) );
1124 else if ( flag == WT_NoteBook )
1126 setNoteBook( new SalomeApp_NoteBook( desktop() ) );
1127 //to receive signal in NoteBook that it's variable was modified
1128 connect( this, SIGNAL( notebookVarUpdated( QString ) ),
1129 getNoteBook(), SLOT( onVarUpdate( QString ) ) );
1131 wid = getNoteBook();
1132 wid->setObjectName( "noteBook" );
1138 /*!Create preferences.*/
1139 void SalomeApp_Application::createPreferences( LightApp_Preferences* pref )
1141 LightApp_Application::createPreferences(pref);
1146 int salomeCat = pref->addPreference( tr( "PREF_CATEGORY_SALOME" ) );
1147 int obTab = pref->addPreference( tr( "PREF_TAB_OBJBROWSER" ), salomeCat );
1148 int defCols = pref->addPreference( tr( "PREF_GROUP_DEF_COLUMNS" ), obTab );
1149 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1151 pref->addPreference( tr( QString().sprintf( "OBJ_BROWSER_COLUMN_%d", i-SalomeApp_DataObject::EntryId ).toLatin1() ), defCols,
1152 LightApp_Preferences::Bool, "ObjectBrowser", QString().sprintf( "visibility_column_id_%d", i-1 ) );
1154 pref->setItemProperty( "orientation", Qt::Vertical, defCols );
1156 // adding preference to LightApp_Application handled preferences.. a bit of hacking with resources..
1157 int genTab = pref->addPreference( LightApp_Application::tr( "PREF_TAB_GENERAL" ), salomeCat );
1158 int studyGroup = pref->addPreference( LightApp_Application::tr( "PREF_GROUP_STUDY" ), genTab );
1159 pref->addPreference( tr( "PREF_STORE_VISUAL_STATE" ), studyGroup, LightApp_Preferences::Bool, "Study", "store_visual_state" );
1160 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1161 pref->addPreference( tr( "PREF_PYDUMP_PUBLISH" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_publish" );
1162 pref->addPreference( tr( "PREF_PYDUMP_MULTI_FILE" ), studyGroup, LightApp_Preferences::Bool, "Study", "multi_file_dump" );
1163 pref->addPreference( tr( "PREF_PYDUMP_SAVE_GUI" ), studyGroup, LightApp_Preferences::Bool, "Study", "pydump_save_gui" );
1164 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1165 pref->addPreference( "", studyGroup, LightApp_Preferences::Space );
1168 /*!Update desktop title.*/
1169 void SalomeApp_Application::updateDesktopTitle() {
1170 QString aTitle = applicationName();
1171 QString aVer = applicationVersion();
1172 if ( !aVer.isEmpty() )
1173 aTitle += QString( " " ) + aVer;
1175 if ( activeStudy() )
1177 QString sName = SUIT_Tools::file( activeStudy()->studyName().trimmed(), false );
1178 if ( !sName.isEmpty() ) {
1179 if ( getStudy()->GetProperties()->IsLocked() ) {
1180 aTitle += QString( " - [%1 (%2)]").arg( sName ).arg( tr( "STUDY_LOCKED" ) );
1182 aTitle += QString( " - [%1]" ).arg( sName );
1187 desktop()->setWindowTitle( aTitle );
1190 int SalomeApp_Application::closeChoice( const QString& /*docName*/ )
1192 QStringList buttons;
1193 QMap<int, int> choices;
1195 buttons << tr ("APPCLOSE_SAVE"); // Save & Clear
1196 choices.insert( idx++, CloseSave ); // ...
1197 buttons << tr ("APPCLOSE_CLOSE"); // Clear w/o saving
1198 choices.insert( idx++, CloseDiscard ); // ...
1199 if ( myIsCloseFromExit ) {
1200 buttons << tr ("APPCLOSE_UNLOAD_SAVE"); // Save & Disconnect
1201 choices.insert( idx++, CloseDisconnectSave ); // ...
1202 buttons << tr ("APPCLOSE_UNLOAD"); // Disconnect
1203 choices.insert( idx++, CloseDisconnect ); // ...
1205 buttons << tr ("APPCLOSE_CANCEL"); // Cancel
1206 choices.insert( idx++, CloseCancel ); // ...
1208 if( !activeStudy()->isModified() )
1210 int answer = SUIT_MessageBox::question( desktop(), tr( "APPCLOSE_CAPTION" ),
1211 tr( "APPCLOSE_DESCRIPTION" ), buttons, 0 );
1212 return choices[answer];
1215 bool SalomeApp_Application::closeAction( const int choice, bool& closePermanently )
1221 if ( activeStudy()->isSaved() )
1223 else if ( !onSaveAsDoc() )
1228 case CloseDisconnectSave:
1229 if ( activeStudy()->isSaved() )
1231 else if ( !onSaveAsDoc() )
1234 case CloseDisconnect:
1235 closeActiveDoc( false );
1236 closePermanently = false;
1245 int SalomeApp_Application::openChoice( const QString& aName )
1247 int choice = LightApp_Application::openChoice( aName );
1249 if ( QFileInfo( aName ).exists() ) {
1250 if ( choice == OpenNew ) { // The document isn't already open.
1252 if ( aName == getStudy()->Name().c_str() )
1254 // The document already exists in the study.
1255 // Do you want to reload it?
1257 int answer = SUIT_MessageBox::question( desktop(), tr( "WRN_WARNING" ), tr( "QUE_DOC_ALREADYEXIST" ).arg( aName ),
1258 SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No );
1259 if ( answer == SUIT_MessageBox::Yes )
1260 choice = OpenRefresh;
1262 choice = OpenCancel;
1265 } else { // file is not exist on disk
1266 SUIT_MessageBox::warning( desktop(),
1267 QObject::tr("WRN_WARNING"),
1268 QObject::tr("WRN_FILE_NOT_EXIST").arg(aName.toUtf8().data()));
1275 bool SalomeApp_Application::openAction( const int aChoice, const QString& aName )
1278 int choice = aChoice;
1285 res = LightApp_Application::openAction( choice, aName );
1293 \brief Get map of the operations which can be performed
1294 on the module activation.
1296 The method should return the map of the kind \c {<id>:<name>}
1297 where \c <id> is an integer identifier of the operation and
1298 \c <name> is a title for the button to be added to the
1299 dialog box. After user selects the required operation by the
1300 clicking the corresponding button in the dialog box, its identifier
1301 is passed to the moduleActionSelected() method to process
1304 \return map of the operations
1305 \sa moduleActionSelected()
1307 QMap<int, QString> SalomeApp_Application::activateModuleActions() const
1309 QMap<int, QString> opmap = LightApp_Application::activateModuleActions();
1311 opmap.insert( LoadStudyId, tr( "ACTIVATE_MODULE_OP_LOAD" ) );
1313 opmap.insert( NewAndScriptId, tr( "ACTIVATE_MODULE_OP_SCRIPT" ) );
1318 \brief Called when the used selectes required operation chosen
1319 from "Activate module" dialog box.
1321 Performs the required operation according to the user choice.
1323 \param id operation identifier
1324 \sa activateModuleActions()
1326 void SalomeApp_Application::moduleActionSelected( const int id )
1332 case NewAndScriptId:
1336 LightApp_Application::moduleActionSelected( id );
1341 /*!Gets CORBA::ORB_var*/
1342 CORBA::ORB_var SalomeApp_Application::orb()
1344 static CORBA::ORB_var _orb;
1346 if ( CORBA::is_nil( _orb ) ) {
1347 Qtx::CmdLineArgs args;
1348 ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
1349 _orb = init( args.argc(), args.argv() );
1355 /*!Create and return SALOMEDS_Study.*/
1356 _PTR(Study) SalomeApp_Application::getStudy()
1358 static _PTR(Study) _study;
1360 CORBA::Object_var aSObject = namingService()->Resolve("/Study");
1361 SALOMEDS::Study_var aStudy = SALOMEDS::Study::_narrow(aSObject);
1362 _study = ClientFactory::Study(aStudy);
1367 /*!Create and return SALOME_NamingService.*/
1368 SALOME_NamingService_Abstract *SalomeApp_Application::namingService()
1373 /*!Create and return SALOME_LifeCycleCORBA.*/
1374 SALOME_LifeCycleCORBA* SalomeApp_Application::lcc()
1376 static SALOME_LifeCycleCORBA _lcc( namingService() );
1380 /*!Private SLOT. On preferences.*/
1381 void SalomeApp_Application::onProperties()
1383 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1387 _PTR(StudyBuilder) SB = study->studyDS()->NewBuilder();
1390 SalomeApp_StudyPropertiesDlg aDlg( desktop() );
1391 int res = aDlg.exec();
1392 if( res==QDialog::Accepted && aDlg.isChanged() )
1393 SB->CommitCommand();
1397 //study->updateCaptions();
1398 updateDesktopTitle();
1402 /*!Insert items in popup, which necessary for current application*/
1403 void SalomeApp_Application::contextMenuPopup( const QString& type, QMenu* thePopup, QString& title )
1405 LightApp_SelectionMgr* mgr = selectionMgr();
1406 bool cacheIsOn = mgr->isSelectionCacheEnabled();
1407 mgr->setSelectionCacheEnabled( true );
1409 LightApp_Application::contextMenuPopup( type, thePopup, title );
1411 // temporary commented
1412 /*OB_Browser* ob = objectBrowser();
1413 if ( !ob || type != ob->popupClientType() )
1416 // Get selected objects
1417 SALOME_ListIO aList;
1418 mgr->selectedObjects( aList, QString(), false );
1420 // add GUI state commands: restore, rename
1421 if ( aList.Extent() == 1 && aList.First()->hasEntry() &&
1422 QString( aList.First()->getEntry() ).startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1423 thePopup->addSeparator();
1424 thePopup->addAction( tr( "MEN_RESTORE_VS" ), this, SLOT( onRestoreGUIState() ) );
1425 thePopup->addAction( tr( "MEN_RENAME_VS" ), objectBrowser(),
1426 SLOT( onStartEditing() ), objectBrowser()->shortcutKey(SUIT_DataBrowser::RenameShortcut) );
1427 thePopup->addAction( tr( "MEN_DELETE_VS" ), this, SLOT( onDeleteGUIState() ) );
1430 // "Delete reference" item should appear only for invalid references
1432 // isInvalidRefs will be true, if at least one of selected objects is invalid reference
1433 bool isInvalidRefs = false;
1435 _PTR(SObject) anObj;
1436 for( SALOME_ListIteratorOfListIO it( aList ); it.More() && !isInvalidRefs; it.Next() )
1438 if( it.Value()->hasEntry() )
1440 _PTR(SObject) aSObject = getStudy()->FindObjectID( it.Value()->getEntry() ), aRefObj = aSObject;
1441 while( aRefObj && aRefObj->ReferencedObject( anObj ) )
1444 if( aRefObj && aRefObj!=aSObject && QString( aRefObj->GetName().c_str() ).isEmpty() )
1445 isInvalidRefs = true;
1449 // Add "Delete reference" item to popup
1450 if ( isInvalidRefs )
1452 thePopup->addSeparator();
1453 thePopup->addAction( tr( "MEN_DELETE_INVALID_REFERENCE" ), this, SLOT( onDeleteInvalidReferences() ) );
1457 // "Activate module" item should appear only if it's necessary
1458 if ( aList.Extent() == 1 ) {
1460 mgr->selectedObjects( aList );
1462 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1464 // add extra popup menu (defined in XML)
1465 if ( myExtActions.size() > 0 ) {
1466 // Use only first selected object
1467 _PTR(SObject) aSO = getStudy()->FindObjectID( aIObj->getEntry() );
1469 _PTR( GenericAttribute ) anAttr;
1470 std::string auid = "AttributeUserID";
1471 auid += Kernel_Utils::GetGUID(Kernel_Utils::ObjectdID);
1472 if ( aSO->FindAttribute( anAttr, auid ) ) {
1473 _PTR(AttributeUserID) aAttrID = anAttr;
1474 QString aId = aAttrID->Value().c_str();
1475 if ( myExtActions.contains( aId ) ) {
1476 thePopup->addAction(myExtActions[aId]);
1482 // check if item is a "GUI state" item (also a first level object)
1483 QString entry( aIObj->getEntry() );
1484 if ( !entry.startsWith( tr( "SAVE_POINT_DEF_NAME" ) ) ) {
1485 QString aModuleName( aIObj->getComponentDataType() );
1486 QString aModuleTitle = moduleTitle( aModuleName );
1487 CAM_Module* currentModule = activeModule();
1488 if ( ( !currentModule || currentModule->moduleName() != aModuleTitle ) && !aModuleTitle.isEmpty() )
1489 thePopup->addAction( tr( "MEN_OPENWITH" ).arg( aModuleTitle ), this, SLOT( onOpenWith() ) );
1493 mgr->setSelectionCacheEnabled( cacheIsOn );
1496 /*!Update obect browser:
1497 1.if 'updateModels' true, update existing data models;
1498 2. update "non-existing" (not loaded yet) data models;
1499 3. update object browser if it exists */
1500 void SalomeApp_Application::updateObjectBrowser( const bool updateModels )
1502 // update "non-existing" (not loaded yet) data models
1503 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
1506 for ( _PTR(SComponentIterator) it ( getStudy()->NewComponentIterator() ); it->More(); it->Next() )
1508 _PTR(SComponent) aComponent ( it->Value() );
1510 #ifndef WITH_SALOMEDS_OBSERVER
1511 // with GUI observers this check is not needed anymore
1512 if ( aComponent->ComponentDataType() == study->getVisualComponentName().toLatin1().constData() )
1513 continue; // skip the magic "Interface Applicative" component
1515 if ( !objectBrowser() )
1516 getWindow( WT_ObjectBrowser );
1517 const bool isAutoUpdate = objectBrowser()->autoUpdate();
1518 objectBrowser()->setAutoUpdate( false );
1519 SalomeApp_DataModel::synchronize( aComponent, study );
1520 objectBrowser()->setAutoUpdate( isAutoUpdate );
1524 // create data objects that correspond to GUI state save points
1525 if ( study ) updateSavePointDataObjects( study );
1527 // update existing data models (already loaded SComponents)
1528 LightApp_Application::updateObjectBrowser( updateModels );
1531 /*!Display Catalog Genenerator dialog */
1532 void SalomeApp_Application::onCatalogGen()
1534 ToolsGUI_CatalogGeneratorDlg aDlg( desktop() );
1538 /*!Display Registry Display dialog */
1539 void SalomeApp_Application::onRegDisplay()
1541 CORBA::ORB_var anOrb = orb();
1542 ToolsGUI_RegWidget* regWnd = ToolsGUI_RegWidget::GetRegWidget( anOrb, desktop() );
1545 regWnd->activateWindow();
1548 /*!find original object by double click on item */
1549 void SalomeApp_Application::onDblClick( SUIT_DataObject* theObj )
1551 // Issue 21379: References are supported at LightApp_DataObject level
1552 LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( theObj );
1554 if( obj && obj->isReference() )
1556 QString entry = obj->refEntry();
1558 SUIT_DataOwnerPtrList aList;
1559 aList.append( new LightApp_DataOwner( entry ) );
1560 selectionMgr()->setSelected( aList, false );
1562 SUIT_DataBrowser* ob = objectBrowser();
1564 QModelIndexList aSelectedIndexes = ob->selectedIndexes();
1565 if ( !aSelectedIndexes.isEmpty() )
1566 ob->treeView()->scrollTo( aSelectedIndexes.first() );
1568 emit objectDoubleClicked( theObj );
1572 Creates new view manager
1573 \param type - type of view manager
1575 SUIT_ViewManager* SalomeApp_Application::newViewManager(const QString& type)
1577 return createViewManager(type);
1581 /*!Global utility function, returns selected GUI Save point object's ID */
1582 int getSelectedSavePoint( const LightApp_SelectionMgr* selMgr )
1584 SALOME_ListIO aList;
1585 selMgr->selectedObjects( aList );
1586 if( aList.Extent() > 0 ) {
1587 Handle(SALOME_InteractiveObject) aIObj = aList.First();
1588 QString entry( aIObj->getEntry() );
1589 QString startStr = QObject::tr( "SAVE_POINT_DEF_NAME" );
1590 if ( !entry.startsWith( startStr ) ) // it's a "GUI state" object
1592 bool ok; // conversion to integer is ok?
1593 int savePoint = entry.right( entry.length() - startStr.length() ).toInt( &ok );
1594 return ok ? savePoint : -1;
1599 /*!Called on Restore GUI State popup command*/
1600 void SalomeApp_Application::onRestoreGUIState()
1602 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1603 if ( savePoint == -1 )
1605 SalomeApp_VisualState( this ).restoreState( savePoint );
1608 /*!Called on Delete GUI State popup command*/
1609 void SalomeApp_Application::onDeleteGUIState()
1611 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1612 if ( savePoint == -1 )
1614 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1618 study->removeSavePoint( savePoint );
1619 updateSavePointDataObjects( study );
1622 /*!Called on New study operation*/
1623 void SalomeApp_Application::onStudyCreated( SUIT_Study* study )
1625 LightApp_Application::onStudyCreated( study );
1627 //#ifndef DISABLE_PYCONSOLE
1628 // desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1629 // windowDock( getWindow( WT_ObjectBrowser ) ) );
1632 loadDockWindowsState();
1634 objectBrowserColumnsVisibility();
1637 /*!Called on Open study operation*/
1638 void SalomeApp_Application::onStudyOpened( SUIT_Study* study )
1640 LightApp_Application::onStudyOpened( study );
1642 //#ifndef DISABLE_PYCONSOLE
1643 // desktop()->tabifyDockWidget( windowDock( getWindow( WT_NoteBook ) ),
1644 // windowDock( getWindow( WT_ObjectBrowser ) ) );
1647 loadDockWindowsState();
1649 objectBrowserColumnsVisibility();
1651 // temporary commented
1652 /*if ( objectBrowser() ) {
1653 updateSavePointDataObjects( dynamic_cast<SalomeApp_Study*>( study ) );
1654 objectBrowser()->updateTree( study->root() );
1658 /*! updateSavePointDataObjects: syncronize data objects that correspond to save points (gui states)*/
1659 void SalomeApp_Application::updateSavePointDataObjects( SalomeApp_Study* study )
1662 SUIT_DataBrowser* ob = objectBrowser();
1663 LightApp_SelectionMgr* selMgr = selectionMgr();
1665 if ( !study || !ob || !selMgr )
1668 // find GUI states root object
1669 SUIT_DataObject* guiRootObj = 0;
1671 study->root()->children( ch );
1672 DataObjectList::const_iterator it = ch.begin(), last = ch.end();
1673 for ( ; it != last ; ++it ) {
1674 if ( dynamic_cast<SalomeApp_SavePointRootObject*>( *it ) ) {
1679 std::vector<int> savePoints = study->getSavePoints();
1680 // case 1: no more save points but they existed in study's tree
1681 if ( savePoints.empty() && guiRootObj ) {
1682 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1683 // : set auto update to true for removing SalomeApp_SavePointRootObject from the SUIT_TreeModel
1684 const bool isAutoUpdate = ob->autoUpdate();
1685 selMgr->clearSelected();
1686 ob->setAutoUpdate(true);
1687 DataObjectList ch = guiRootObj->children();
1688 for( int i = 0; i < ch.size(); i++ )
1691 ob->setAutoUpdate(isAutoUpdate);
1694 // case 2: no more save points but root does not exist either
1695 if ( savePoints.empty() && !guiRootObj )
1697 // case 3: save points but no root for them - create it
1698 if ( !savePoints.empty() && !guiRootObj )
1699 guiRootObj = new SalomeApp_SavePointRootObject( study->root() );
1700 // case 4: everything already exists.. here may be a problem: we want "GUI states" root object
1701 // to be always the last one in the tree. Here we check - if it is not the last one - remove and
1703 if ( guiRootObj->nextBrother() ) {
1704 study->root()->removeChild(guiRootObj);
1705 study->root()->appendChild(guiRootObj);
1706 //study->root()->dump();
1709 // store data objects in a map id-to-DataObject
1710 QMap<int,SalomeApp_SavePointObject*> mapDO;
1712 guiRootObj->children( ch );
1713 for( it = ch.begin(), last = ch.end(); it != last ; ++it ) {
1714 SalomeApp_SavePointObject* dobj = dynamic_cast<SalomeApp_SavePointObject*>( *it );
1716 mapDO[dobj->getId()] = dobj;
1719 // iterate new save points. if DataObject with such ID not found in map - create DataObject
1720 // if in the map - remove it from map.
1721 for ( size_t i = 0; i < savePoints.size(); i++ )
1722 if ( !mapDO.contains( savePoints[i] ) )
1723 new SalomeApp_SavePointObject( guiRootObj, savePoints[i], study );
1725 mapDO.remove( savePoints[i] );
1727 // delete DataObjects that are still in the map -- their IDs were not found in data model
1728 if( mapDO.size() > 0) {
1729 //rnv : to fix bug "IPAL22450 TC6.3.0: sigsegv loop deleting the GUI state"
1730 // : set auto update to true for removing SalomeApp_SavePointObject from the SUIT_TreeModel
1731 selMgr->clearSelected();
1732 const bool isAutoUpdate = ob->autoUpdate();
1733 ob->setAutoUpdate(true);
1734 for ( QMap<int,SalomeApp_SavePointObject*>::Iterator it = mapDO.begin(); it != mapDO.end(); ++it )
1736 ob->setAutoUpdate(isAutoUpdate);
1740 /*! Check data object */
1741 bool SalomeApp_Application::checkDataObject(LightApp_DataObject* theObj)
1750 Opens other study into active Study. If Study is empty - creates it.
1751 \param theName - name of study
1753 bool SalomeApp_Application::useStudy( const QString& theName )
1756 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1759 res = aStudy->loadDocument( theName );
1760 updateDesktopTitle();
1761 updateCommandsStatus();
1765 /*! Show/hide object browser colums according to preferences */
1766 void SalomeApp_Application::objectBrowserColumnsVisibility()
1768 if ( objectBrowser() )
1769 for ( int i = SalomeApp_DataObject::EntryId; i < SalomeApp_DataObject::LastId; i++ )
1771 bool shown = resourceMgr()->booleanValue( "ObjectBrowser", QString( "visibility_column_id_%1" ).arg( i-1 ), true );
1772 objectBrowser()->treeView()->setColumnHidden( i, !shown );
1776 #ifndef DISABLE_PYCONSOLE
1777 /*! Set SalomeApp_NoteBook pointer */
1778 void SalomeApp_Application::setNoteBook( SalomeApp_NoteBook* theNoteBook )
1780 myNoteBook = theNoteBook;
1783 /*! Return SalomeApp_NoteBook pointer */
1784 SalomeApp_NoteBook* SalomeApp_Application::getNoteBook() const
1791 * Define extra actions defined in module definition XML file.
1792 * Additional popup items sections can be defined by parameter "popupitems".
1793 * Supported attributes:
1794 * title - title of menu item,
1795 * attributelocalid - AttributeLocalId defined for selected data item where menu command has to be applied,
1796 * method - method which has to be called when menu item is selected
1798 * <section name="MODULENAME">
1799 * <parameter name="popupitems" value="menuitem1:menuitem2:..."/>
1801 * <section name="importmed">
1802 * <parameter name="title" value="My menu"/>
1803 * <parameter name="objectid" value="VISU.Result"/>
1804 * <parameter name="method" value="nameOfModuleMethod"/>
1807 void SalomeApp_Application::createExtraActions()
1809 myExtActions.clear();
1810 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
1812 QStringList aModules;
1813 modules(aModules, false);
1814 foreach(QString aModile, aModules) {
1815 QString aModName = moduleName(aModile);
1816 QString aSectionStr = resMgr->stringValue(aModName, "popupitems", QString());
1817 if (!aSectionStr.isNull()) {
1818 QStringList aSections = aSectionStr.split(':');
1819 foreach(QString aSection, aSections) {
1820 QString aTitle = resMgr->stringValue(aSection, "title", QString());
1821 QString aId = resMgr->stringValue(aSection, "objectid", QString());
1822 QString aSlot = resMgr->stringValue(aSection, "method", QString());
1823 if (aTitle.isEmpty() || aSlot.isEmpty() || aId.isEmpty())
1826 QString aModuleName = resMgr->stringValue(aSection, "module", QString());
1827 if (aModuleName.isNull())
1828 aModuleName = aModName;
1830 QAction* aAction = new QAction(aTitle, this);
1832 aData<<aModuleName<<aSlot;
1833 aAction->setData(aData);
1834 connect(aAction, SIGNAL(triggered()), this, SLOT(onExtAction()));
1835 myExtActions[aId] = aAction;
1842 * Called when extra action is selected
1844 void SalomeApp_Application::onExtAction()
1846 QAction* aAction = ::qobject_cast<QAction*>(sender());
1850 QVariant aData = aAction->data();
1851 QStringList aDataList = aData.value<QStringList>();
1852 if (aDataList.size() != 2)
1855 LightApp_SelectionMgr* aSelectionMgr = selectionMgr();
1856 SALOME_ListIO aListIO;
1857 aSelectionMgr->selectedObjects(aListIO);
1858 const Handle(SALOME_InteractiveObject)& anIO = aListIO.First();
1859 if (aListIO.Extent() < 1)
1861 if (!anIO->hasEntry())
1864 QString aEntry(anIO->getEntry());
1866 QApplication::setOverrideCursor( Qt::WaitCursor );
1867 QString aModuleTitle = moduleTitle(aDataList[0]);
1868 activateModule(aModuleTitle);
1869 QApplication::restoreOverrideCursor();
1871 QCoreApplication::processEvents();
1873 CAM_Module* aModule = activeModule();
1877 if (!QMetaObject::invokeMethod(aModule, qPrintable(aDataList[1]), Q_ARG(QString, aEntry)))
1878 printf("Error: Can't Invoke method %s\n", qPrintable(aDataList[1]));
1882 Checks that an object can be renamed.
1883 \param entry entry of the object
1884 \brief Return \c true if object can be renamed
1886 bool SalomeApp_Application::renameAllowed( const QString& entry) const
1888 return entry.startsWith( tr( "SAVE_POINT_DEF_NAME") );
1892 Rename object by entry.
1893 \param entry entry of the object
1894 \param name new name of the object
1895 \brief Return \c true if rename operation finished successfully, \c false otherwise.
1897 bool SalomeApp_Application::renameObject( const QString& /*entry*/, const QString& name )
1899 SalomeApp_Study* aStudy = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1901 int savePoint = ::getSelectedSavePoint( selectionMgr() );
1903 if(!aStudy || savePoint == -1)
1906 if ( !name.isNull() && !name.isEmpty() ) {
1907 aStudy->setNameOfSavePoint( savePoint, name );
1908 updateSavePointDataObjects( aStudy );
1910 //Mark study as modified
1917 #ifndef DISABLE_PYCONSOLE
1918 //============================================================================
1919 /*! Function : onUpdateStudy
1920 * Purpose : Slot to update the study.
1922 //============================================================================
1923 void SalomeApp_Application::onUpdateStudy()
1925 QApplication::setOverrideCursor( Qt::WaitCursor );
1927 if( !updateStudy() )
1928 SUIT_MessageBox::warning( desktop(), tr( "ERROR" ), tr( "ERR_UPDATE_STUDY_FAILED" ) );
1930 QApplication::restoreOverrideCursor();
1933 //============================================================================
1934 /*! Function : updateStudy
1935 * Purpose : Update study by dumping the study to Python script and loading it.
1936 * It is used to apply variable modifications done in NoteBook to created objects.
1938 //============================================================================
1939 bool SalomeApp_Application::updateStudy()
1941 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( activeStudy() );
1942 if ( !study || !myNoteBook )
1945 myNoteBook->setIsDumpedStudySaved( study->isSaved() );
1946 myNoteBook->setDumpedStudyName( study->studyName() );
1948 // get unique temporary directory name
1949 QString aTmpDir = QString::fromStdString( SALOMEDS_Tool::GetTmpDir() );
1951 if( aTmpDir.isEmpty() )
1954 if( aTmpDir.right( 1 ).compare( QDir::separator() ) == 0 )
1955 aTmpDir.remove( aTmpDir.length() - 1, 1 );
1957 // dump study to the temporary directory
1958 QString aScriptName( "notebook" );
1959 bool toPublish = true;
1960 bool isMultiFile = false;
1961 bool toSaveGUI = true;
1964 _PTR(AttributeParameter) ap;
1965 _PTR(IParameters) ip = ClientFactory::getIParameters(ap);
1966 if(ip->isDumpPython()) ip->setDumpPython(); //Unset DumpPython flag.
1967 if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method
1968 ip->setDumpPython();
1969 savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point
1971 bool ok = getStudy()->DumpStudy( aTmpDir.toStdString(), aScriptName.toStdString(), toPublish, isMultiFile );
1973 study->removeSavePoint(savePoint); //SRN: remove the created temporary save point.
1976 myNoteBook->setDumpedStudyScript( aTmpDir + QDir::separator() + aScriptName + ".py" );
1980 QList<SUIT_Application*> aList = SUIT_Session::session()->applications();
1981 int anIndex = aList.indexOf( this );
1983 // Disconnect dialog from application desktop in case if:
1984 // 1) Application is not the first application in the session
1985 // 2) Application is the first application in session but not the only.
1986 bool changeDesktop = ((anIndex > 0) || (anIndex == 0 && aList.count() > 1));
1987 if( changeDesktop ) {
1989 SalomeApp_Application* app = this;
1990 if( anIndex > 0 && anIndex < aList.count() )
1991 app = dynamic_cast<SalomeApp_Application*>( aList[ anIndex - 1 ] );
1992 else if(anIndex == 0 && aList.count() > 1)
1993 app = dynamic_cast<SalomeApp_Application*>( aList[ 1 ] );
1998 // creation a new study and restoring will be done in another application
1999 connect( this, SIGNAL( dumpedStudyClosed( const QString&, const QString&, bool ) ),
2000 app, SLOT( onRestoreStudy( const QString&, const QString&, bool ) ), Qt::UniqueConnection );
2003 QString aDumpScript = myNoteBook->getDumpedStudyScript();
2004 QString aStudyName = myNoteBook->getDumpedStudyName();
2005 bool isStudySaved = myNoteBook->isDumpedStudySaved();
2006 // clear a study (delete all objects)
2007 onCloseDoc( false );
2009 if( !changeDesktop ) {
2010 ok = onRestoreStudy( aDumpScript,
2019 //============================================================================
2020 /*! Function : onRestoreStudy
2021 * Purpose : Load the dumped study from Python script
2023 //============================================================================
2024 bool SalomeApp_Application::onRestoreStudy( const QString& theDumpScript,
2025 const QString& theStudyName,
2026 bool theIsStudySaved )
2030 // create a new study
2033 // get active application
2034 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
2036 // load study from the temporary directory
2037 QFileInfo aScriptInfo = QFileInfo(theDumpScript);
2038 QString command = QString( "exec(open(\"%1\" ,\"rb\").read())" ).arg(aScriptInfo.canonicalFilePath());
2040 #ifndef DISABLE_PYCONSOLE
2041 PyConsole_Console* pyConsole = app->pythonConsole();
2043 pyConsole->execAndWait( command );
2046 // remove temporary directory
2047 QString aStudyName = aScriptInfo.baseName();
2048 QDir aDir = aScriptInfo.absoluteDir();
2049 QStringList aFiles = aDir.entryList( QStringList( "*.py*" ) );
2050 for( QStringList::iterator it = aFiles.begin(), itEnd = aFiles.end(); it != itEnd; ++it )
2051 ok = aDir.remove( *it ) && ok;
2053 ok = aDir.rmdir( aDir.absolutePath() );
2055 if( SalomeApp_Study* newStudy = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
2057 #ifndef DISABLE_PYCONSOLE
2058 if ( app->getNoteBook() )
2059 app->getNoteBook()->Init();
2060 newStudy->updateFromNotebook(theStudyName, theIsStudySaved);
2061 newStudy->Modified();
2062 updateDesktopTitle();
2073 Close the Application
2075 void SalomeApp_Application::afterCloseDoc()
2077 #ifndef DISABLE_PYCONSOLE
2078 // emit signal to restore study from Python script
2080 emit dumpedStudyClosed( myNoteBook->getDumpedStudyScript(),
2081 myNoteBook->getDumpedStudyName(),
2082 myNoteBook->isDumpedStudySaved() );
2085 LightApp_Application::afterCloseDoc();
2088 bool SalomeApp_Application::canOpenDoc( const QString& url )
2090 _PTR(Study) aStudyDS = getStudy();
2092 return aStudyDS->CanOpen( url.toUtf8().data() );
2097 Asks to close existing document.
2099 bool SalomeApp_Application::checkExistingDoc()
2101 return LightApp_Application::checkExistingDoc();
2105 #ifndef DISABLE_PYCONSOLE
2107 PyConsole_Interp* SalomeApp_Application::createPyInterp()
2109 return new SalomeApp_PyInterp;
2112 #endif // DISABLE_PYCONSOLE
2114 void SalomeApp_Application::ensureShaperIsActivated()
2116 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>(activeStudy());
2117 _PTR(Study) studyDS = getStudy();
2118 if ( study && studyDS )
2120 _PTR(SObject) shaper = studyDS->FindObjectByPath("/Shaper"); // non null result if shaper data is present in the study
2121 bool shaperIsActive = false;
2122 QList<CAM_DataModel*> models;
2123 study->dataModels( models );
2124 for( int i = 0; i < models.count() && !shaperIsActive; i++ )
2125 shaperIsActive = models[i]->module()->moduleName() == "Shaper";
2127 if (shaper && !shaperIsActive)
2128 onDesktopMessage("register_module_in_study/Shaper");